I have a program that generates classes using JCodemodel and a dynamic class loader. I parse a yaml file, generate the required classes and map the structure of the file . Everything is fine so far.
Snakeyaml handles the parse and write nicely, so the definition of classes if fine.
Then I try to access a method properties() which is redefined in the yaml.
I first load the file into a "Tree", load its root element as a "Compute" and print its class and methods ; then I call the overridden method.
The computeb class is dynamicaly generated, as well as the computeb$Properties.
here is the code (I replaced my packages by shorter ones):
Tree tree = Parser.load(new FileInputStream("src/test/resources/tree.yaml"));
mypackage.Compute c = (mypackage.Compute) tree.root();
System.err.println("class : " + c.getClass());
for (Method m : c.getClass().getMethods()) {
System.err.println(" method : " + m);
}
System.err.println("properties() class is " + c.properties().getClass().getName());
The result is :
class : class computeb
method : public computeb$Property computeb.properties()
method : public mypackage.Compute$Property mypackage.Compute.properties()
(...)
properties() class is mypackage.Compute$Property
As you notice, the class has the two methods present, however the properties() method called is the second one. I would want to call the first one (which is defined in the classloader) . Why does it happen this way ? What should I do ?
OK I got it, I had an issue while statically generating the classes on a specific folder.
Since I had to resolve existing classes to avoid creating them twice, I only resolved classes that were starting with my package prefix.
This worked well in static generation, but in dynamic generation I had previously generated classes I could not load, while they already were present. Basically that means that my class generator was creating another class with same name, so sometimes the classloader could refer to one class, sometimes to another.
I'm working on correcting this dirty mess.
Related
I have a Java based RMI Server in which one of the interface method is like this :
public Properties process(String operation, Properties params) {
Class nodecls = Class.forName("com.example.commands." + operation);
}
This method runs fine all the time but sometimes (say once in a million RMI calls) throws ClassNotFoundException. What could be the reason for this? I am sure that the name passed is correct.
From XYZWS - What does Class forname method do?:
A call to Class.forName("X") causes the class named X to be dynamically loaded (at runtime). A call to forName("X") causes the class named X to be initialized (i.e., JVM executes all its static block after class loading). Class.forName("X") returns the Class object associated with the "X" class. The returned Class object is not an instance of the "x" class itself.
Class.forName("X") loads the class if it not already loaded. The JVM keeps track of all the classes that have been previously loaded. This method uses the classloader of the class that invokes it. The "X" is the fully qualified name of the desired class.
The tag wiki for classnotfoundexception has a simpler description:
The Java exception thrown when an application tries to load a class by name. Usually raised by one of:
the forName method in class Class [...]
when no definition for the class with the specified name could be found in the classpath.
Therefore, there can only be two causes for this:
The class named "com.example.commands." + operation is not present on the Class Path.
The ClassLoader of the Class which your method is in cannot find the "com.example.commands." + operation class. Maybe some reflection trick broke it.
However, you should never have to bother with this, as your method wouldn't even compile - it's of a non-void return type, while you never included a proper return statement.
What should be done if a lookup returns null? I am using Lookup.getDefault().lookup() of org.openide.util.Lookup which is used for finding instances of objects. The general pattern is to pass a Class object and get back an instance of that class or null.
I am using it in the code below:
StreamingServer server = Lookup.getDefault().lookup(StreamingServer.class);
ServerControllerFactory controllerFactory = Lookup.getDefault().lookup(ServerControllerFactory.class);
StreamingController controller = Lookup.getDefault().lookup(StreamingController.class);
Since no istances are found, null is returned for each of these, 'server', 'controllerFactory', 'controller'. I need to handle this situation so I can use these objects to access methods, as in :
controllerFactory.createServerController(graph)
server.register(serverController, context)
How can I accomplish this?
You need to create a META-INF/services folder in your Eclipse source folder. Then, for each class, create a text file in the META-INF/services folder. The name of the text file is the full name (includes the package location) of the class type, and the contents of the text file is the full name (includes the package location) of the implementing class (which is not necessarily the same name of the class).
For example, for the ServerControllerFactory class, you will create a text file named org.gephi.streaming.server.ServerControllerFactory and the text this file will contain is org.gephi.streaming.server.impl.ServerControllerFactory
For me, the class that I was trying to call lookup on just needed the #ServiceProvider decoration like this:
#ServiceProvider(service = MyClassHere.class)
public final class MyClassHere ....
I have not yet used Constants interface in GWT and I am having problem to run the example CellTable. The deferred binding fails and the central error message is: "No resource found for contactDataBaseCategories". contactDataBaseCategories is a method defined in the interface DataBaseConstants and returns an array of Strings. I suspect I must create a properties (txt?) file and to define the categories, but I am not sure, since I come across this case for the first time. How can I do it properly to make the example of the CellTable run?
Update: I have created the ContactDatabase.DatabaseConstants.properties file in the same package in which the interface is declared, I have added the line in the file:
contactDataBaseCategories = friends, coWorkers, other
but it still does not work. The error is again : "No resource found for contactDataBaseCategories" and then
"Deferred Binding failed for com.al.celltablöeexample.ContactDatabase.DatabaseConstants".
What going wrong?
This is how i do it
Constant interface
public interface DataBaseConstants extends Constants
{
#Key("contact-database-categories")
String contactDataBaseCategories();
}
property file. DataBaseConstants.properties
contact-database-categories = "Your String"
You can use it
public DataBaseConstants dbConstant= GWT.create( DataBaseConstants .class );
dbConstant.contactDataBaseCategories();
Edited
If you want to pass string array then you can do it like this
#DefaultStringArrayValue({"cat1", "cat2", "cat3", "cat4", "cat5"})
String[] contactDataBaseCategories();
More about Constants
I have finally managed it. The problem was that it could not find the resource/file: ContactDatabase.DatabaseConstants.properties. I have changed it to DatabaseConstants.properties and I removed the inner interface to its own file. The same I did in the class CwCellTable on the interface CwConstants. In the example page moreover, the instantiation of the CwConstants interface is missed, and one must do also this (in the constructor), like in the ContactDatabase class.
Just to add to Dilantha's answer you can then set
contact-database-categories = Family, Friends, Coworkers, Businesses, Contacts
in order to comply with the example.
Tip : In order to make the example work create a costructor in CwCellList and add the following :
initWidget(onInitialize());
Well, not sure if the question sounds a little weird but let me try to put forth the clarification :
I have a JSP page. On this JSP page, I am calling a java class defined in one of my packages under my projects. This class connects to database and access a table which has got fields namely - functionname, function class. Now I am able to retrieve in my JSP the two strings, lets say -
String funName = "ComFunctions";
String className = "funLog");
Now, I want to invoke this function using this class name i.e. basically something like - className.funName
Is it possible in Java? Actually, these functions and class names will be retrieved in a for loop, so I can't directly call using real classname but have to use strings.
Kindly suggest if there is a way or worl around or if the question is still unclear.
I tried the following approach so far but no luck -
Class c = Class.forName(className);
Object o = c.newInstance();
Method m = c.getMethod(funName, String.class); // Not sure what is supposed to be second parameter here i.e. after funName
Error - the above code gives " No class found error". And i made sure that class is there under the package. Even adding package name i.e. packge.classname didnt help and it says "Symbol not found" for package name.
Any pointers please?
Example class that I am trying to invoke -
package mypackage;
public class ComFunctions extends WDriverInitialize{
public static void main(String[] args){
}
public static void funLog(String username){
System.out.println(userName);
}
}
You need to make sure the compiled class is in the webapp's classpath (ie, WEB-INF/classes) and use the FQN (ie, add the package name). You could also make a JAR file of your classes and add that to the WEB-INF/lib folder.
Also, the extra parameter in getMethod is to fetch a method with the matching parameters (ie, in your example, one that takes a String
You're missing one piece of the puzzle, and that's the method arguments. Without it, you can't really be sure what method funName is referring to, and what arguments to pass to it.
And of course, the class needs to be in the classpath.
I've got a library that allows clients to provide a list of text files, each of which contains groovy code for a class that extends java class Z. For instance file 'A.groovy' contains
package com.mypkg;
public class A extends Z {
#Override
public void someMethod() {
// do something A-ish
}
}
etc.
The library compiles each of these and (in this case) would return to the clients an instance of type Z.
My issue comes when a client needs something like this:
package com.mypkg;
public class B extends A { // extends A!
#Override
public void someMethod() {
// do something B-ish instead of A-ish
}
}
where B extends A, and class A was parsed before class B.
The issue is that the GroovyClassLoader can't seem to find class A, even though it just parsed A. Here's the code that compiles the scripts and creates the instances:
for (String fileName : listOfScriptFiles) {
InputStream in = getInputStreamFromFile(fileName);
CompilerConfiguration compConfig = new CompilerConfiguration();
GroovyClassLoader classLoader = new GroovyClassLoader(Thread.currentThread()
.getContextClassLoader(), compConfig);
Z service = null;
Class clazz = classLoader.parseClass(in);
service = (Z) clazz.newInstance();
return service;
}
Is there a way to 'register' class A with the runtime so that when Groovy tries to compile class B it will not complain that class A doesn't exist?
UPDATE
I was actually able to solve this by instantiating the GroovyClassLoader outside the loop that iterates through the client's code list, so the classloader that parses A is the same that parses B.
The question still stands, though, because I could envision a case where in one part of someone's code they parse A, and then in a completely different part, where the same classloader is unavailable, they parse B.
In my experience with the Groovy classloader (which is similar in behavior with Ant and beanshell's classloader in this respect) , you have to decide up front whether you are going to use the default system classloader, in which case you would build the classpath into the command that launches the Groovy script, OR on the other hand, you specify ONLY the groovy jar on the command line classpath and then you dynamically add classes at the beginning of your Groovy script on the custom classloader.
You aren't providing much information in your question, but my guess is that you put class "A" on the classpath before you launched the script and then your trying to load class "B" dynamically. That wouldn't work as far as I know.
NOTE: I myself have been trying to figure out how to do this kind of thing. It seems it would be possible but I still haven't figured it out.