Reputation: 55
I have a problem with the "JavaClassLoader" library. I want to program a launcher for a application. At the end it should be possible to shutdown the program, to update and to start again. Now, I always get an NoSuchMethodEx when I try to invoke methods with arguments.
The main class that I want to start, implemented following (part of apache Daemon):
package org.apache.commons.daemon;
public interface Daemon {
public void init(DaemonContext context) throws DaemonInitException, Exception;
public void start() throws Exception;
public void stop() throws Exception;
public void destroy();
}
In my Launcher following happens:
// set cglib proxy
ProxyProviderFactory.setDefaultProxyProvider(new CglibProxyProvider());
// load instance
JarClassLoader jcl = new JarClassLoader();
jcl.add("application.jar");
JclObjectFactory factory = JclObjectFactory.getInstance(true);
this.application = (Daemon) factory.create(jcl, "de.FabiUnne.Application");
Now if I try to invoke a method with no argument (e.g. #start()), everything works. I get an error when I try to invoke the #init(DaemonContext) method.
The stacktrace:
Exception in thread "main" java.lang.NoSuchMethodException: de.FabiUnne.Application.init(org.apache.commons.daemon.DaemonContext)
at java.lang.Class.getMethod(Class.java:1670)
at org.xeustechnologies.jcl.proxy.CglibProxyProvider$CglibProxyHandler.intercept(CglibProxyProvider.java:52)
at org.apache.commons.daemon.Daemon$$EnhancerByCGLIB$$b9db6482.init(<generated>)
and 2 more...
The funny thing is that the method is indeed present in any case.
<- this.application.getClass().getMethods()
-> [ ...
public final void org.apache.commons.daemon.Daemon$$EnhancerByCGLIB$$b9db6482.init(org.apache.commons.daemon.DaemonContext) throws org.apache.commons.daemon.DaemonInitException,java.lang.Exception,
public final void org.apache.commons.daemon.Daemon$$EnhancerByCGLIB$$b9db6482.start() throws java.lang.Exception,
public final void org.apache.commons.daemon.Daemon$$EnhancerByCGLIB$$b9db6482.destroy(),
public final void org.apache.commons.daemon.Daemon$$EnhancerByCGLIB$$b9db6482.stop() throws java.lang.Exception,
... ]
Why can not I call the #init() method anyway?
Upvotes: 0
Views: 325
Reputation: 55
jcl: manipulating-class-loading-order
@ChristianFrommeyer gave me the solution. I want to explain it, so it's own answer.
The launcher is still loaded by the "normal" class loader. All objects that are loaded in this class will be loaded by the same class loader as the Launcher. I load now from the other ClasLoader of (github.com/kamranzafar/JCL). The class that's stored in the application as dependency is loaded on the second loader. This class is different, as the above loaded.
public final void org.apache.commons.daemon.Daemon.init( ... ),
are not the same as
public final void org.apache.commons.daemon.Daemon$$EnhancerByCGLIB$$b9db6482.init( ... ),
So I tell the JCL, that he should not override loaded objects. Here, the following Loader achieve the same effect.
jcl.getCurrentLoader().setOrder(1); // or
jcl.getParentLoader().setOrder(1); // or
jcl.getSystemLoader().setOrder(1);
The objects that are present in both classloaders, are now identical, because they both come from the local Loader.
Upvotes: 0
Reputation: 1420
I'm not familiar with the framework you're using. But if I got it right than the new Class loader you create is the reason of the exception. If you would obtain the Instance of the DaemonContext from your jcl you should be able to invoke the method. You could also create the new Class loader as child of the application class loader. The way it currently is there are two different classes of type DaemonContext one from each distinct class loader.
Upvotes: 1