javassist throws ClassNotFoundException when loading external classes from jar - java

I'm trying load an external jar file with javassist & call its main method at runtime, however when i try to do this with the below code:
File file = new File("C:\\Users\\MainPC\\Desktop\\test.jar");
ClassPool cp = ClassPool.getDefault();
cp.insertClassPath(file.getAbsolutePath());
Class<?> MainClass = cp.get("TestPackage.MainClass").toClass();
MainClass.getMethod("main", String[].class).invoke(null, new Object[] {args});
It throws the following exception:
Exception in thread "main" java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at ReflectionTests.main(ReflectionTests.java:99)
Caused by: java.lang.NoClassDefFoundError: TestPackage/OtherClass
at TestPackage.MainClass.main(Unknown Source)
... 5 more
Caused by: java.lang.ClassNotFoundException: TestPackage.OtherClass
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:602)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
... 6 more
When i attempt the same thing only using the built in java reflection api it works with no problems:
File file = new File("C:\\Users\\MainPC\\Desktop\\test.jar");
URLClassLoader cl = new URLClassLoader(new URL[] {new URL("jar:file:"+file.getAbsoluteFile()+"!/")});
Class<?> clazz = cl.loadClass("TestPackage.MainClass");
clazz.getMethod("main", String[].class).invoke(null, new Object[] {args});
(the above throws no exceptions & calls the main method of the jar file as expected)
This leaves me to believe i'm doing something wrong in javassist (specifically with the loading of the jar file classes). Can someone explain to me what it is?
I should mention the jar file only contains 2 classes: MainClass.class & OtherClass.Class. Both reside in a package called TestPackage. It seems the error has something to do with the MainClass class not being able to find the OtherClass class, when javassist loads it.

The problem was that when i call ct.toClass() it only exposes the class itself to my runtimes classloader (not the entire classpool's classpath). When i then later attempt to invoke the main method of this class, my runtimes classloader tries to execute the part that loads the other class which it obviously doesn't know about and so throws a ClassNotFoundException.
The solution is to use the javassist provided classloader (javassist.Loader) which takes a classpool as argument in the constructor and then is able to load & resolve classes from the classpools classpath properly.
Here's a working code example of what i was trying to achieve:
File file = new File("C:\\Users\\MainPC\\Desktop\\test.jar");
ClassPool cp = ClassPool.getDefault();
cp.insertClassPath(file.getAbsolutePath());
Loader loader = new Loader(cp);
Class<?> MainClass = loader.loadClass("TestPackage.MainClass");
MainClass.getMethod("main", String[].class).invoke(null, new Object[] {args});

Related

java.lang.NoClassDefFoundError when trying to load class from JAR

I am working on a project that is supposed to parse texts from PDF files.
Having multiple dependencies I have decided to build a combined JAR with all the dependencies and the classes.
However, when I build JAR including dependencies via Intellij IDEA even though the JAR file is added properly and I can import the class the program throws NoClassDefFoundError (Please refer to the screenshot).
Firstly, I thought the jar wasn't in the classpath. However, even if I add -cp TessaractPDF.jar through VM Options the class still get undetected.
I think it is worth to mention that, everything works smoothly if I build JAR without dependencies and add the dependencies manually.
What should I do?
Exception in thread "main" java.lang.NoClassDefFoundError: me/afifaniks/parsers/TessPDFParser
at Test.main(Test.java:20)
Caused by: java.lang.ClassNotFoundException: me.afifaniks.parsers.TessPDFParser
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:355)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
... 1 more
Code Snippet:
import me.afifaniks.parsers.TessPDFParser;
import java.io.IOException;
import java.util.HashMap;
public class Test {
public static void main(String[] args) throws IOException {
System.out.println(System.getProperty("java.classpath"));
HashMap<String, Object> arguments = new HashMap<>();
arguments.put("imageMode", "binary");
arguments.put("toFile", false);
arguments.put("tessDataPath", "/home/afif/Desktop/PDFParser/tessdata");
TessPDFParser pdfParser = new TessPDFParser("hiers15.pdf", arguments);
String text = (String) pdfParser.convert();
System.out.println(text);
}
}

dynamic loading class error NoClassDefFoundError

I'm writing program witch loads .class files in run time and calls main method. Code below.
File classDir = new File(pathToClass);
URL pathTo = classDir.toURL();
URL[] urls = new URL[]{pathTo};
URLClassLoader cl = new URLClassLoader(urls);
_class = cl.loadClass(className);
Method m = _class.getMethod("main", String[].class);
It builds and in execution I get this error :
java.lang.NoClassDefFoundError: [LComplex;
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2693)
at java.lang.Class.privateGetMethodRecursive(Class.java:3040)
at java.lang.Class.getMethod0(Class.java:3010)
at java.lang.Class.getMethod(Class.java:1776)
What I'm doing wrong
Files are placed in this pattern:
C:/dir/a/ccc.class
C:/dir/a/ccc.java
C:/dir/b/ccc.class
C:/dir/b/ccc.java
Like isnot2bad told, Complex class was missing. After loading it error vanished

How to run a java class from a jar file dynamically

I'm working on a java project that needs a third-party java program running as a server to work.
Normally, I'd do:
java -cp jarfile1.jar:jarfile2.jar className arg1 arg2
And then I'd run my java code. This way it works.
I'd like to know if there is any way to, including the two .jars required into my project, run the class directly from my code instead of having to manually start it.
I've tried to use URLClassLoader as I saw in some examples, but either I'm doing it wrong or none cover this specific use case.
URLClassLoader classLoader = URLClassLoader.newInstance(new URL[]{new URL("file:///tmp/jarfile1.jar"),new URL("file:///tmp/jarfile2.jar")});
Class<?> cls = classLoader.loadClass("className");
Method method = cls.getDeclaredMethod ("main");
Object instance = cls.newInstance();
Object result = method.invoke (instance);
yields
Exception in thread "main" java.lang.NoClassDefFoundError: alice/tuprolog/lib/InvalidObjectIdException
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2615)
at java.lang.Class.getDeclaredMethod(Class.java:2007)
at pkg1.MainClass.main(MainClass.java:54)
Caused by: java.lang.ClassNotFoundException: alice.tuprolog.lib.InvalidObjectIdException
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
... 4 more
Please note that I copied the .jars to /tmp to isolate the failure cause. The files exist and are accessible.
How can I make that run the class as specified above within java code?
Thanks!
If the class exists in a different ClassLoader, you need to use reflection to get to it:
ClassLoader classLoader = new URLClassLoader(
new URL[] { firstJarURL, secondJarURL });
String[] args = { arg1, arg2 };
try {
Class<?> mainClass = classLoader.loadClass("com.somepackage.ClassName");
mainClass.getMethod("main", String[].class).invoke(null, args);
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
I finally fixed it! Things done:
I forgot to add the second jar to the classpath of the project (duh!)
Since everything was on the project classpath, I just reused the current classloader
Final working code:
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Class<?> cls = classLoader.loadClass("className");
Method method = cls.getDeclaredMethod("main", String[].class);
Object instance = cls.newInstance();
Object result = method.invoke(null, (Object)args);
Thanks everyone and specially to VGR and Joop Eggen in the comments for pointing out the error with the second jar!
EDIT: As JB Nizet pointed out in the comments, calling the class's main() method directly is simpler:
className.main(args);
And you're done

Java class is not found when loading jar file

I am working on a API system for a program. This system goes to a 'plugin' folder and loads every jar there. I am trying to load the main class of the jar file that is in the 'plugin' folder, but while doing so, I get a ClassNotFoundException.
Here is my code:
private static void loadClassFromJar(String PluginJar) throws MalformedURLException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
logger.debug("jar:file:" + "./debug/plugins/DiamondCorePlugin.jar!/");
URL[] urls = { new URL("jar:file:" + FileList.PluginFolder.getAbsolutePath() + PluginJar +"!/") };
URLClassLoader ClassLoader = URLClassLoader.newInstance(urls);
Class<?> Class = ClassLoader.loadClass("net.trenterprises.diamondcore.plugin.Main");
Object Object = Class.newInstance();
Method EventMethod = Object.getClass().getMethod("onEnable");
EventMethod.invoke(Object);
}
If the question is vague or unclear, please let me know (I am new around here, so I try my best to word any question I ask).
EDIT:
Forgot to include the stack trace. Here it is!
java.lang.ClassNotFoundException: net.trenterprises.diamondcore.plugin.Main
at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.net.FactoryURLClassLoader.loadClass(URLClassLoader.java:798)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at net.trenterprises.diamondcore.cross.api.PluginLoader.loadClassFromJar(PluginLoader.java:53)
at net.trenterprises.diamondcore.cross.api.PluginLoader.loadAllPlugins(PluginLoader.java:25)
at net.trenterprises.diamondcore.DiamondCoreServer.<init>(DiamondCoreServer.java:47)
at net.trenterprises.diamondcore.run.main(run.java:15)
Either the jar does not contain the requested class (check with a zip-tool or jar -tf DiamondCorePlugin.jar, or the jar-URL is not correct (it seems to point to a resource inside the jar, not the jar itself). You can create it a little easier like:
File file = new File("debug/plugins/DiamondCorePlugin.jar");
URL[] urls = { file.getAbsoluteFile().toURI().toURL() };

Error in creating owl file

I want to create ontology whit this code:
public static void main(String[] args) throws FileNotFoundException {
// TODO code application logic here
OntModel my_model= ModelFactory.createOntologyModel();
ObjectProperty op = my_model.createObjectProperty("b");
OntClass my_class = my_model.createClass("student");
DatatypeProperty dtp = my_model.createDatatypeProperty("name");
dtp.addDomain(my_class);
FileOutputStream univer= new FileOutputStream("c:/uni.owl");
my_model.write(univer,"RDF/XML-ABBREV","ns");
}
But it gives this error:
java.lang.NoClassDefFoundError: com/hp/hpl/jena/rdf/model/Resource
Caused by: java.lang.ClassNotFoundException: com.hp.hpl.jena.rdf.model.Resource
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
Could not find the main class: javaapplication6.Main. Program will exit.
Exception in thread "main" Java Result: 1
I cannot understand what is the problem.Thanks for any Help.
NoClassDefFoundError means the Java Virtual Machine or a ClassLoader instance tries to load in the definition of a class (as part of a normal method call or as part of creating a new instance using the new expression) and no definition of the class could be found.
Try to download Apache Jena library from here and put it in your classpath

Categories