WILDFLY - Loading jar dynamically java.lang.ClassNotFoundException - java

I have an EAR deployed in wildfly and I'm loading a jar from source with this code:
File file = new File("C:\\XXXX\\XXXX\\ProcessTest.jar");
String lcStr = "com.package.test.TestProcess";
URLClassLoader cl = URLClassLoader.newInstance(new URL[]{file.toURL()});
Class<?> loadedClass;
try {
loadedClass = cl.loadClass(lcStr);
IProcess data = (IProcess)loadedClass.newInstance();
data.start();
} catch (Exception e) {
e.printStackTrace();
}
The TestProcess class implements IProcess that is loaded in another jar with the EAR.
When I run the server code and the class is being casted I receive:
java.lang.NoClassDefFoundError: com/package/test/process/IProcess
If I added the interface in the JAR that I'm loading the problem is a CastException because com/package/test/process/IProcess loaded by wildfly is different of the loaded with the JAR.
I need receive the IProcess (casting the object), because a solution is call directly the method with Mehtod.invoke but it's not solution for my problem.
Thanks in advanced.

With this tip works perfectly:
URLClassLoader.newInstance(new URL[]{file.toURL()}, IProcess.class.getClassLoader())
Thanks to Steve C!

Related

How can I read the MANIFEST.MF file during the test execution?

I am trying to automate acceptance test using TestLink, Cucumber, Jenkins and Maven. To do that, I am asking to read the MANIFEST.MF file created by Maven. I have to do it during the test execution.
I found out this example of code :
`public static String readVersion() throws IOException {
InputStream in = VersionUtil.class.getResourceAsStream("/META-INF/MANIFEST.MF");
Manifest manifest = new Manifest(in);
// Lire la propriété "Implementation-Version" du Manifest
String version = manifest.getMainAttributes().getValue(Attributes.Name.IMPLEMENTATION_VERSION);
return version;
}`
But I am getting a NullPointerException when trying to execute it... Do you have any idea why ?
I am launching Maven with the simple command : mvn package test.
I think the problem comes from the moment when this code is launching, I should launch it after the package phase, is there any way to do that ?
Thank you !
I think you can try the code below, since most classloader can be cast to URLClassLoader
URLClassLoader cl = (URLClassLoader) getClass().getClassLoader();
try {
URL url = cl.findResource("META-INF/MANIFEST.MF");
Manifest manifest = new Manifest(url.openStream());
...
} catch (IOException E) {
// handle
}

Load jar dynamically at runtime?

My current java project is using methods and variables from another project (same package). Right now the other project's jar has to be in the classpath to work correctly. My problem here is that the name of the jar can and will change because of increasing versions, and because you cannot use wildcards in the manifest classpath, it's impossible to add it to the classpath. So currently the only option of starting my application is using the -cp argument from the command line, manually adding the other jar my project depends on.
To improve this, I wanted to load the jar dynamically and read about using the ClassLoader. I read a lot of examples for it, however I still don't understand how to use it in my case.
What I want is it to load a jar file, lets say, myDependency-2.4.1-SNAPSHOT.jar, but it should be able to just search for a jar file starting with myDependency- because as I already said the version number can change at anytime. Then I should just be able to use it's methods and variables in my Code just like I do now (like ClassInMyDependency.exampleMethod()).
Can anyone help me with this, as I've been searching the web for a few hours now and still don't get how to use the ClassLoader to do what I just explained.
Many thanks in advance
(Applies to Java version 8 and earlier).
Indeed this is occasionally necessary. This is how I do this in production. It uses reflection to circumvent the encapsulation of addURL in the system class loader.
/*
* Adds the supplied Java Archive library to java.class.path. This is benign
* if the library is already loaded.
*/
public static synchronized void loadLibrary(java.io.File jar) throws MyException
{
try {
/*We are using reflection here to circumvent encapsulation; addURL is not public*/
java.net.URLClassLoader loader = (java.net.URLClassLoader)ClassLoader.getSystemClassLoader();
java.net.URL url = jar.toURI().toURL();
/*Disallow if already loaded*/
for (java.net.URL it : java.util.Arrays.asList(loader.getURLs())){
if (it.equals(url)){
return;
}
}
java.lang.reflect.Method method = java.net.URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{java.net.URL.class});
method.setAccessible(true); /*promote the method to public access*/
method.invoke(loader, new Object[]{url});
} catch (final java.lang.NoSuchMethodException |
java.lang.IllegalAccessException |
java.net.MalformedURLException |
java.lang.reflect.InvocationTargetException e){
throw new MyException(e);
}
}
I needed to load a jar file at runtime for both java 8 and java 9+. Here is the method to do it (using Spring Boot 1.5.2 if it may relate).
public static synchronized void loadLibrary(java.io.File jar) {
try {
java.net.URL url = jar.toURI().toURL();
java.lang.reflect.Method method = java.net.URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{java.net.URL.class});
method.setAccessible(true); /*promote the method to public access*/
method.invoke(Thread.currentThread().getContextClassLoader(), new Object[]{url});
} catch (Exception ex) {
throw new RuntimeException("Cannot load library from jar file '" + jar.getAbsolutePath() + "'. Reason: " + ex.getMessage());
}
}

load class from another class within same jar in java web start fails

I've a javafx application which is run by web start. In my fx application, I try to load the classes using ClassLoader as in below code. The parameter passed is a package name like "com.example.project.abcd"
public final static List<Class<?>> find(final String scannedPackage)
{
final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
final String scannedPath = scannedPackage.replace(DOT, SLASH);
final Enumeration<URL> resources;
try {
resources = classLoader.getResources(scannedPath);
} catch (IOException e) {
throw new IllegalArgumentException(String.format(BAD_PACKAGE_ERROR, scannedPath, scannedPackage), e);
}
final List<Class<?>> classes = new LinkedList<Class<?>>();
while (resources.hasMoreElements()) {
final File file = new File(resources.nextElement().getFile());
classes.addAll(find(file, scannedPackage));
}
return classes;
}
Now I'm not able to get all the classes present inside "com.example.project.abcd" package when I run it thru java web start but through IDE it is working fine.
I'm using JDK 7, JavaFX 2.
As per http://docs.oracle.com/javase/7/docs/technotes/guides/javaws/developersguide/faq.html#s211 Thread.currentThread().getContextClassLoader() should work fine but it is not!.
Tried searching on net/googling but in vain. Checked http://lopica.sourceforge.net/faq.html#customcl as well and tried using URLClassLoader as suggested. But that didn't work as well (Though did not know what should be passed to the parameter 'urls')
Any help is much apreciated.
I think this works in IDE because your BIN/classes directory is used to get all the files.
In Webstart-Mode, all your classes are inside JARs.

Class not found exception when trying to create web service client

I am trying to consume a web service from a Java client.
I generated the classes using wsimport:
wsimport -keep -verbose http://localhost:5382/Service1.svc?wsdl
Code looks something like:
private String CreateSalesforceIssue() {
IssueService service = new IssueService();
IIssueService binding = service.getBasicHttpBindingIIssueService();
String issueID = binding.createIssue(type, description, steps,
expected, workaround, storage,
docType, actions, tools, external,
repeatability, workaroundType, severity,
pmSeverity, products, extensions, versions,
os, status, project, resolution, fixversions);
return issueID;
}
When it hits this line:
IssueService service = new IssueService();
Stepping into the code far enough and it gets to javax.xml.ws.spi.Provider and fails there.
On
public static Provider provider() {
try {
Object provider =
FactoryFinder.find(JAXWSPROVIDER_PROPERTY,
DEFAULT_JAXWSPROVIDER);
if (!(provider instanceof Provider)) {
Class pClass = Provider.class;
String classnameAsResource = pClass.getName().replace('.', '/') + ".class";
ClassLoader loader = pClass.getClassLoader();
if(loader == null) {
loader = ClassLoader.getSystemClassLoader();
}
URL targetTypeURL = loader.getResource(classnameAsResource);
throw new LinkageError("ClassCastException: attempting to cast" +
provider.getClass().getClassLoader().getResource(classnameAsResource) +
"to" + targetTypeURL.toString() );
}
return (Provider) provider;
} catch (WebServiceException ex) {
throw ex;
} catch (Exception ex) {
throw new WebServiceException("Unable to createEndpointReference Provider", ex);
}
}
on this line:
if (!(provider instanceof Provider)) {
with a ClassNotFoundException: Provider com.sun.xml.ws.spi.ProviderImpl
I feel like I am missing something, unfortunately I am not sure what... Do I need to initialize the provider anywhere?
You should add Provider class into your classpath.
If you use IDE you can add the library easily by right click on library and choose "add Jar file" (or something like that!). But if you try to compile and run your application via terminal use the following commands:
javac -d [bin folder] -cp [jar files] [java source files]
java -classpath [jar files] [Main class]
you should split the jar files using : in Linux and MAC OS and ; in MS Windows. As you said this is a web service, I think you are using IDE and first solution may help you.
P.S. If you also added this jar file into class path and this exception occurs again, please add this jar file into your web server/container library directory. (for example lib folder in tomcat.

How to load a jar file at runtime [duplicate]

This question already has answers here:
How to load JAR files dynamically at Runtime?
(20 answers)
Closed 7 years ago.
I was asked to build a java system that will have the ability to load new code (expansions) while running.
How do I re-load a jar file while my code is running? or how do I load a new jar?
Obviously, since constant up-time is important, I'd like to add the ability to re-load existing classes while at it (if it does not complicate things too much).
What are the things I should look out for?
(think of it as two different questions - one regarding reloading classes at runtime, the other regarding adding new classes).
Reloading existing classes with existing data is likely to break things.
You can load new code into new class loaders relatively easily:
ClassLoader loader = URLClassLoader.newInstance(
new URL[] { yourURL },
getClass().getClassLoader()
);
Class<?> clazz = Class.forName("mypackage.MyClass", true, loader);
Class<? extends Runnable> runClass = clazz.asSubclass(Runnable.class);
// Avoid Class.newInstance, for it is evil.
Constructor<? extends Runnable> ctor = runClass.getConstructor();
Runnable doRun = ctor.newInstance();
doRun.run();
Class loaders no longer used can be garbage collected (unless there is a memory leak, as is often the case with using ThreadLocal, JDBC drivers, java.beans, etc).
If you want to keep the object data, then I suggest a persistence mechanism such as Serialisation, or whatever you are used to.
Of course debugging systems can do fancier things, but are more hacky and less reliable.
It is possible to add new classes into a class loader. For instance, using URLClassLoader.addURL. However, if a class fails to load (because, say, you haven't added it), then it will never load in that class loader instance.
This works for me:
File file = new File("c:\\myjar.jar");
URL url = file.toURL();
URL[] urls = new URL[]{url};
ClassLoader cl = new URLClassLoader(urls);
Class cls = cl.loadClass("com.mypackage.myclass");
I was asked to build a java system that will have the ability to load new code while running
You might want to base your system on OSGi (or at least take a lot at it), which was made for exactly this situation.
Messing with classloaders is really tricky business, mostly because of how class visibility works, and you do not want to run into hard-to-debug problems later on. For example, Class.forName(), which is widely used in many libraries does not work too well on a fragmented classloader space.
I googled a bit, and found this code here:
File file = getJarFileToLoadFrom();
String lcStr = getNameOfClassToLoad();
URL jarfile = new URL("jar", "","file:" + file.getAbsolutePath()+"!/");
URLClassLoader cl = URLClassLoader.newInstance(new URL[] {jarfile });
Class loadedClass = cl.loadClass(lcStr);
Can anyone share opinions/comments/answers regarding this approach?
Use org.openide.util.Lookup and ClassLoader to dynamically load the Jar plugin, as shown here.
public LoadEngine() {
Lookup ocrengineLookup;
Collection<OCREngine> ocrengines;
Template ocrengineTemplate;
Result ocrengineResults;
try {
//ocrengineLookup = Lookup.getDefault(); this only load OCREngine in classpath of application
ocrengineLookup = Lookups.metaInfServices(getClassLoaderForExtraModule());//this load the OCREngine in the extra module as well
ocrengineTemplate = new Template(OCREngine.class);
ocrengineResults = ocrengineLookup.lookup(ocrengineTemplate);
ocrengines = ocrengineResults.allInstances();//all OCREngines must implement the defined interface in OCREngine. Reference to guideline of implement org.openide.util.Lookup for more information
} catch (Exception ex) {
}
}
public ClassLoader getClassLoaderForExtraModule() throws IOException {
List<URL> urls = new ArrayList<URL>(5);
//foreach( filepath: external file *.JAR) with each external file *.JAR, do as follows
File jar = new File(filepath);
JarFile jf = new JarFile(jar);
urls.add(jar.toURI().toURL());
Manifest mf = jf.getManifest(); // If the jar has a class-path in it's manifest add it's entries
if (mf
!= null) {
String cp =
mf.getMainAttributes().getValue("class-path");
if (cp
!= null) {
for (String cpe : cp.split("\\s+")) {
File lib =
new File(jar.getParentFile(), cpe);
urls.add(lib.toURI().toURL());
}
}
}
ClassLoader cl = ClassLoader.getSystemClassLoader();
if (urls.size() > 0) {
cl = new URLClassLoader(urls.toArray(new URL[urls.size()]), ClassLoader.getSystemClassLoader());
}
return cl;
}

Categories