I have really tricky problem. I have kinda container which can run custom JAR with the method which has a class ComponentContext as a parameter. After loading I want to invoke this method with the reflection but there is a problem - I must use the same class loader (JCL in this case) to create ComponentContext. See the code:
JclObjectFactory factory = JclObjectFactory.getInstance();
Object context = factory.create(jcl, "org.hive.lib.component.ComponentContextImpl");
Method setConfigDirMethod = context.getClass().getMethod("initialize", File.class, File.class);
setConfigDirMethod.invoke(context, configDir, workspace);
Method method = instance.getClass().getMethod("initialize", context.getClass());
method.invoke(instance, context);
And when I'm trying to pass context created in container like this
ComponentContextImpl c = new ComponentContext();
It fails with java.lang.IllegalArgumentException because of another classloader.
It means that my container depends on class from the JAR, it drives me crazy. It there a way to pass my own ComponentContext (not instantiated from the JAR) to the method initialize?
PS - JAR was assembled with assembly:single
Solved as marking shared library as provided
Related
This question is slightly different from the previous error reported via Unable to invoke method by java reflection: NoSuchMethodException
Signature of overloading methods follow as below in target class, my objective is to invoke public List run(FileInput,StreamOutput)dynamically.
public List run(String, String);
public List run(FileInput,StreamOutput);
Case 1: When dynamically loading a method using reflection api when target class(jar) is present in CLASS_PATH - method is accessible.
Class mapClass = loader.loadClass("com.sample.test.TrackingService");
FileInput input = new FileInput(inputFileFullPath);
StreamOutput output = new StreamOutput(new java.io.ByteArrayOutputStream());
Object mapObj = mapClass.newInstance();
Class params[]={ FileInput.class,StreamOutput.class};
Method m = mapClass.getDeclaredMethod("run", params);
outputList = (List) m.invoke(mapObj, input,output);`
Case 2: On top of the same code in Case 1, instead of placing jar in CLASS_PATH, but loaded via URLClassLoader then it throws NoSuchMethodException
Code block
URL urls[] = {new URL("file:/opt/jars/Tracking.jar")};
URLClassLoader loader = new URLClassLoader(urls);
Class mapClass = loader.loadClass("com.sample.test.TrackingService",true,loader);
FileInput input = new FileInput(inputFileFullPath);
StreamOutput output = new StreamOutput(new java.io.ByteArrayOutputStream());
Object mapObj = mapClass.newInstance();
Class params[]={ FileInput.class,StreamOutput.class};
Method m = mapClass.getDeclaredMethod("run", params);
outputList = (List) m.invoke(mapObj, input,output);
Exception is thrown at line Method m = mapClass.getDeclaredMethod("run", params);
Question 1: Is something missing here when loading class via URLClassLoader ?
Question 2: Any recommendation on loading class definition into JVM via custom class. I mean, achieving same level as jar file present in CLASS_PATH ? Part of our requirement and limitation we can't place jar under CLASS_PATH or add jar path to CLASS_PATH
All that should change between the two code(One using ClassLoader and other using URLClassLoader), is the instantiation, i.e.
This:
ClassLoader loader = getClass().getClassLoader();
Class<?> myLib = loader.loadClass("com.chetan.loader.MyLib");
Should be replaced by:
URL url[] = {new URL("file:C:\\Chetan\\mylib-0.0.1-SNAPSHOT.jar")};
URLClassLoader loader = new URLClassLoader(url);
Class<?> myLib = loader.loadClass("com.chetan.loader.MyLib");
Here is what I recommend, though you might have tried these things, but in case you haven't:
Unpack the Jar /opt/jars/Tracking.jar (You can open it via Winzip or other similar utility), and then decompile the class TrackingService - Check if it does contain the method you are trying to call?
Give you code a fresh look / Simulate - I will suggest create a small class with the two method variants. Pack it in a jar. create a test loader class and try out using URLClassLoader - This will give you the confidence that the code you have written works. You can then look for other aspects of the problem.
In any case, let me know if above suggestions worked. In case you are not able to make the test class work as well, do share the code so that fellow members here can better understand what you are trying to do.
It worked when the class loader changed as shown below.
URLClassLoader loader = new URLClassLoader(new URL[] { new URL("file:/opt/jars/Tracking.jar") }, this.getClass().getClassLoader());
Rest everything same... as I said, with-out adding the current class loader also worked when run in eclipse.
I am creating a game where characters can have modules attached to them which provide extra functionality, for example there could be a 'banker' module which listens for a click event and opens a menu for banking. Modules are user creatable by extending the Module class and registering an instance with a ModuleFactory. Modules are able to serialize themselves and load themselves from a serialized form (saving to XML) when is passed in the constructor.
The problem I am having is that when loading the modules I have the name and an instance of every module but I cannot make a new instance of each module.
Is it acceptable to make a newInstance() method inside of each module which returns an instance of the module?
I know it is possible to use reflection for this but most of the time I find reflection to be more trouble than the benefits I get from it.
It is possible to do something like this, since you said you already know the names of each Module (hopefully in some sort of list).
Class<?> temp = Class.forName("ModuleName");
Object obj = temp.newInstance();
This is actually reflection.
Originally I had this, but my above code is superior, because this will require you to have a method that creates a new instances inside each Module. It works, but it is messy. Think of it as this, an object that creates a clone of itself, that is just weird.
public static Module createInstance()
{
return new ThisModule();
}
If you want a new instance as a copy of the existing instance, you can use the clone method,
Otherwise create a factory method which creates instances for you,
public static Module createInstance(){
return new Module();
}
I m not sure if I completely understood what you want
Create a static method in each module to instantiate. This is static factory method. Effective java book says it is indeed good practice to create objects through static factory methods.
I think we can call static methods on objects( though not a good practice).
If i understand you right, you want to extend the behavior of an object and be able to send/serialize it via XML to a client and back (frontend <-> backend communication).
I think what you are looking for is something like a decoration for your Modules and Submodules. Maybe you should build them decoratable to each other, like an InputStream.
something like this:
MyBaseModule base = new MyBaseModule();
BankerModule banker = new BankerModule(base);
ExtendedBankerModuler extBanker = new ExtendedBankerModule(banker);
Maybe call extBanker.toXML() to get the XML to send it to the frontend.
You can wrap each module with the tags of the decorations ones...
<serialized>
<module>
<type>ExtendedBankerModule</type>
<description>extended banker module</description>
<decorates>
<module>
<type>BankerModule</type>
<description>banker module</description>
<decorates>
<module>
<type>MyBaseModule</type>
<description>basic module</description>
<decorates></decorates>
</module>
</decorates>
</module>
<decorates>
</module>
</serialized>
I have an Spring-powered app and want to integrate groovy. Specifically, I have one abstract java class with a set of abstract method definitions and one repository inyected with autowired.
This class must be implemented by several final groovy external classes (one for each client).
At this moment, I am calling the Groovy class in java this way:
final Class parsedClass = groovyClassLoader.parseClass(groovyFile);
final GroovyObject groovyObject = (GroovyObject) parsedClass.newInstance();
final Object response = groovyObject.invokeMethod(methodName, methodParameters);
The problem is that I need to autowired the repository variable in each Groovy external class but currently are null.
How can I notify the Groovy class to get the inyected repository variable when I create it at runtime?
Thanks!
Edit
Y have solved it using the setProperty method from groovyObjectObject this way:
groovyObject.setProperty("myRepository", myRepositoryImpl);
The instance here is not created by spring, hence I don't think spring can automagically set the instance of repository in the groovyObject that you have.
However, if you can can autowire the repository into the class thats generating the groovyObject then you can manually inject the repo in the newInstance call.
parsedClass.newInstance(repository:your_autowired_repo_ref)
I have solved it using the setProperty method from groovyObjectObject this way:
groovyObject.setProperty("myRepository", myRepositoryImpl);
I'm attempting to:
1) Load an interface and implementation class from a given file location
2) Create a Proxy object with reflection that matches the interface, and directs all calls to the implementation class
This is later used for testing purposes using JUnit.
The Problem:
However, I seem to be having problems when I try to create the proxy object. I get the exception:
java.lang.IllegalArgumentException: interface Testing.Testable is not visible from class loader
...at Core.ProxyFactory.createProxy(ProxyFactory.java:26)
The line in question is as follows:
Object obj = Proxy.newProxyInstance(implementationClass.getClassLoader(), new Class[]{interfaceClass}, forwarder);
Class loading the right way?
I am loading the classes that I need using a URLClassLoader. The snippet for this is as follows:
URL url = new File(path).toURI().toURL();
URL[] urlList = {url};
// Create loader and load
ClassLoader classLoader = new URLClassLoader(urlList);
Class loadedClass = classLoader.loadClass (classname);
return loadedClass;
However, is this correct? This snippet gets repeated for each class file, and so I believe each time a new class loader is created. Could this be causing my problem? How can I resolve this?
Thanks in advance for any help you can give
Solved...
I was correct in my concerns that I was loading the classes in the wrong way. Because the classes depend on each other (e.g. one class uses another), they need to belong to the same classloader, or a child therefore of.
This problem can be solved by replacing use of the URLClassLoader with:
ClassLoader classLoader = new URLClassLoader(urlList);
Class[] classes = new Class[classNames.length];
for (int i = 0; i<classNames.length; i++) {
classes[i] = classLoader.loadClass(classNames[i]);
}
This allows you to load multiple classes using the same classloader, and seems to solve the problem!
I am developing a web application.
The web application generates java classes on the fly. For example it generates class com.people.Customer.java
In my code, I dynamically compile this to get com.people.Customer.class and store in some directory say repository/com/people/Customer.class which is not on the classpath of my application server.My application server(I am using WebSphere Application Server/Apache Tomcat etc) picks up the classes from the WEB-INF/classes directory. The Classloader would use this to load the classes.
After compilation I need to load this class so that it becomes accessible to other classes using it after its creation.
When I use Thread.currentThread().getContextClassLoader().loadClass(com.people.Customer) obviously the Classloader is not able to load the class, since its not on the classpath(not in WEB-INF/classes). Due to similar reasons, getResource(..) or getResourceAsStream(..) also does not work.
I need a way to :
Read the class Customer.class maybe as a stream (or any other way would do) and then load it. Following are the constraints:
I cannot add the repository folder to the WEB-INF/classes folder.
I cannot create a new Custom ClassLoader. If I create a new ClassLoader and this loads the class, it will not be accessible to its parent ClassLoader.
Is there any way of achieving this?
If not this, in the worse case, is there a way of overriding the default class loader with a custom class loader for web applications the same classloader should be used to load applications throughout entire lifecycle of my web application.
Appreciate any solution :)
You need a custom class loader to do this, and in this classloader you need to re-define a method findClass(String name)
An example:
public class CustomClassLoader extends ClassLoader {
final String basePath = "/your/base/path/to/directory/named/repository/";
#Override
protected Class<?> findClass(final String name) throws ClassNotFoundException {
String fullName = name.replace('.', '/');
fullName += ".class";
String path = basePath + fullName ;
try {
FileInputStream fis = new FileInputStream(path);
byte[] data = new byte[fis.available()];
fis.read(data);
Class<?> res = defineClass(name, data, 0, data.length);
fis.close();
return res;
} catch(Exception e) {
return super.findClass(name);
}
}
}
Then, you'll be load classes from custom location. For example:
Class<?> clazz = Class.forName("my.pretty.Clazz", true, new CustomClassLoader());
Object obj = clazz.newInstance();
Doing this, you tell JVM that class named my.pretty.Clazz should be loaded by your custom class loader, which knows how and where from to load your custom class.
It resolves full class name (like my.pretty.Clazz) to file name (in our case: /your/base/path/to/directory/named/repository/my/pretty/Clazz.class), then loads obtained resource as a byte array, and finally converts this array to a Class instance.
This example is very simple and demonstrates a general technique about how to load custom classes as in your case.
I suggest you to read some articles about class loading, for example this one.
Short answer: No
Without a custom ClassLoader, you cannot dynamically load classes.
However, your assumption that you cannot use a custom ClassLoader because your other objects loaded by the WebApp ClassLoader would be unable to use these newly loaded classes is incorrect. All you need is a generic way to use these newly created classes - like a common interface or a meta-description (Beans Introspector for accessing bean properties).
But if you are using third-party libraries like Hibernate and you are dynamically loading entities at runtime which are to be persisted, then you will have a hard time, but imho it is possible.
Sure you can do this. Just get the web classloader and call the defineClass() method using reflection (it is protected, so be sure to call setAccessible(true) on the method. defineClass() takes a byte array, so it doesn't make any difference where you class is from. Make sure that the class name is unique and you're loading it only once, or you'll have complicated classloading problems.