Facing NoClassDefFoundError despite jar being in classpath (dynamic compilation) - java

In a tomcat server, at run time, I am reading java class files and compiling them dynamically using the InMemoryJavaCompiler library which internally uses JavaCompiler .
Code Sample -
InMemoryJavaCompiler.newInstance()
.useOptions("-parameters",
"-classpath", sb.toString(),
"-Xlint:unchecked")
.compile(sourceCodeClassName,
sourceCode.toString());
Here sb (Stringbuilder) indicates the jars read from WEB-INF/lib directory separated by a colon.
The code works in the following scenarios :
If the above compilation code is kept in a standalone class file & the relevant libraries are set in the classpath. The compilation was successful.
I printed the jar files i.e. I printed sb value separately & took a copy of it. I manually ran javac -classpath <sourceCode.java> in the terminal. The compilation was successful.
The code is not working in the following scenarios :
a. When the above code snippet is added as a stand alone program in eclipse, I faced NoClassDefFound error for the interface which the sourceCode was implementing.
b. In Tomcat, the relevant jar is present in contextName/WEB-INF/lib/ and in addition to that the jar is added in -useOptions classpath. Even then, I am facing NoClassDefFound error for the the interface the sourceCode was implementing.
Note : There are no duplicate copies of the jar or multiple versions of the jar present in the lib directory or the classpath value. The interface is ContractInterface present in hyperledger-fabric-shim

The issue was that System classloader was being used. Once I set the classloader using the -useParentClassLoader option with the current thread's classloader, the compilation was successful.

Related

Error: Could not find or load main class fileReader.Main Caused by: java.lang.ClassNotFoundException: fileReader.Main (individual case) [duplicate]

I am trying to run a Java application, but getting this error:
java.lang.ClassNotFoundException:
After the colon comes the location of the class that is missing. However, I know that that location does not exist since the class is located elsewhere. How can I update the path of that class? Does it have something to do with the class path?
A classpath is a list of locations to load classes from.
These 'locations' can either be directories, or jar files.
For directories, the JVM will follow an expected pattern for loading a class. If I have the directory C:/myproject/classes in my classpath, and I attempt to load a class com.mycompany.Foo, it will look under the classes directory for a directory called com, then under that a directory called mycompany, and finally it will look for a file called Foo.class in that directory.
In the second instance, for jar files, it will search the jar file for that class. A jar file is in reality just a zipped collection of directories like the above. If you unzip a jar file, you'll get a bunch of directories and class files following the pattern above.
So the JVM traverses a classpath from start to finish looking for the definition of the class when it attempts to load the class definition. For example, in the classpath :
C:/myproject/classes;C:/myproject/lib/stuff.jar;C:/myproject/lib/otherstuff.jar
The JVM will attempt to look in the directory classes first, then in stuff.jar and finally in otherstuff.jar.
When you get a ClassNotFoundException, it means the JVM has traversed the entire classpath and not found the class you've attempted to reference. The solution, as so often in the Java world, is to check your classpath.
You define a classpath on the command line by saying java -cp and then your classpath. In an IDE such as Eclipse, you'll have a menu option to specify your classpath.
Your classpath is broken (which is a very common problem in the Java world).
Depending on how you start your application, you need to revise the argument to -cp, your Class-Path entry in MANIFEST.MF or your disk layout.
This is the best solution I found so far.
Suppose we have a package called org.mypackage containing the classes:
HelloWorld (main class)
SupportClass
UtilClass
and the files defining this package are stored physically under the directory D:\myprogram (on Windows) or /home/user/myprogram (on Linux).
The file structure will look like this:
When we invoke Java, we specify the name of the application to run: org.mypackage.HelloWorld. However we must also tell Java where to look for the files and directories defining our package. So to launch the program, we have to use the following command:
NOTE: You have to execute the above java command no matter what your current location is. But this is not the case for javac. For
compiling you can even directly go into the directory where you have
your .java files and directly execute javac ClassName.java.
If you know the path of the class or the jar containing the class then add it to your classpath while running it. You can use the classpath as mentioned here:
on Windows
java -classpath .;yourjar.jar YourMainClass
on UNIX/Linux
java -classpath .:yourjar.jar YourMainClass
I had the same error and it took me a whole day to realize it's a dependency conflict issue:
I imported two libraries, A and B;
Both A and B depends on another library C, but different versions of C. Let's say A depends on C 1.0 and B depends on C 2.0;
B makes use of a class that only exists in C 2.0;
However, A is "closer" in the dependency tree, so Maven uses C 1.0 for both A and B and doesn't even warn you about this (it's quite astounding to me);
As a result, when B tries to use the class that only exists in C 2.0, a ClassNotFoundException is thrown;
Now the weird thing is: if you navigate the code of B in your IDE and try to jump to the class that only exists in C 2.0, it works correctly. C 2.0 is indeed installed and your IDE knows about it, but it's just ignored when running the application.
This really drove me mad...
I ended up having to add C 2.0 to my pom.xml so that it can be chosen over C 1.0.
Please refer to this post for how Maven chooses the closest dependency: https://stackoverflow.com/a/63815140/7438905
You can use mvn dependency:tree to visualize the dependency tree.
Try these if you use maven. I use maven for my project and when I do mvn clean install and try to run a program it throws the exception. So, I clean the project and run it again and it works for me.
I use eclipse IDE.
For Class Not Found Exception when running Junit test, try running mvn clean test once. It will compile all the test classes.
Basic Generic Question - Simplest Generic Answer ;)
Given the information I will make the assumption that you might be trying a basic approach to coding, building/compiling and running a simple console app like "Hello World", using some simple text editor and some Command Shell.
This error occurs in the fallowing scenario:
..\SomePath>javac HelloWorld.java
..\SomePath>java HelloWorld.class
In other words, use:
..\SomePath>java HelloWorld
P.S. The adding the file extension .class produces the same mistake.
Also be sure to have the Java's (JDK/JRE) bin folder in the operating system's Environment Variables's PATH.(Lookup for more details other posts on this)
P.P.S Was I correct in my assumption/s?
If you use maven, check that you have this plugin in your pom.xml:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.0</version>
<executions>
<!-- Attach the shade goal into the package phase -->
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
It will put your dependency (the exception reason) to your jar.
FYI:
this will include all dependencies inflated in the final jar
To add the location of a class to your classpath via command line simply add -cp or -classpath and the location of the class while running it. I.E.
java -cp "c:/location/of/file" YourProgram
Or if you're running an IDE such as eclipse you can right click on the project -> build path -> configure build path
and add the external JAR containing your class to the build path then it should work fine.
Use ';' as the separator. If your environment variables are set correctly, you should see your settings. If your PATH and CLASSPATH is correct, windows should recognize those commands. You do NOT need to restart your computer when installing Java.
Add the full path of jar file to the CLASSPATH.
In linux use: export CLASSPATH=".:/full/path/to/file.jar:$CLASSPATH". Other way worked (without editing the CLASSPATH) was unzipping the jar in the current project folder.
Ways didn't work for me:
1) Using -cp option with full path of jar file.
2) Using -cpwith only the name of jar when located in the current folder
3) Copying the jar to the current project folder
4) Copying the jar to standard location of java jars (/usr/share/java)
This solution is reported for class com.mysql.jdbc.Driver in mysql-connector-java.5-*.jar, working on linux with OpenJDK version 1.7
This can happen on Windows after a java update where the old version of the java SDK is missing and a new one is present. I would check if your IDE is using the installed java SDK version (IntelliJ: CTRL + SHIFT + ALT + S)
Go up to the top and remove the import statement if there is one, and re import the class. But if that isn't the case do a clean then build. Are you using Netbeans or Eclipse?
I ran into this as well and tried all of the other solutions. I did not have the .class file in my HTML folder, I only had the .java file. Once I added the .class file the program worked fine.
It could happen if your classpath is not correct
Let us posit a serializable class and deserializable class under same projectname. You run the serializable class, creating a serializable object in specific folder. Now you need the desearialized data. In the meantime, if you change the name of the project it will not work. You have to run the serializable class first and then deserialize the file.
If you are using maven
try to maven update all projects and force for snapshots.
It will clean as well and rebuilt all classpath..
It solved my problem..
I just did
1.Invalidate caches and restart
2.Rebuilt my project which solved the problem
It's worth noting that sometimes Java lies about the Class that is causing the problem.
You can get this error if java tries to load class A which depends on class B and class B can't be loaded.
In some circumstances java reports that class A can't be loaded when the problem is B.
From recollection the last time this occurred was when class A includes a static field or a static initializer that loaded class B.
So after checking your class path is correct (I actually dump the full classpath on startup) I then do a binary chop on class A.
By this I mean, I remove half of the code in A.
If it still fails I remove another half and so on until the problem (hopefully goes away).
I was trying to run .jar from C# code using Process class. The java code ran successfully from eclipse but it doesn't from C# visual studio and even clicking directly on the jar file, it always stopped with ClassNotFoundException: exception. Solution for my, was export the java program as "Runnable JAR file" instead of "JAR File". Hope it can help someone.
If you have added multiple (Third-Party)**libraries and Extends **Application class
Then it might occur.
For that, you have to set multiDexEnabled true and replace your extended Application class with MultiDexApplication.
It will be solved.
In my case the class thrown as class not found exception has properties related to ssl certificates. Close the eclipse and open with as “Run as Administrator” then issue got resolved. As eclipse have issue related permission it will throw such kind of exception.
I started having this issue after upgrading the "Java Language Support" plugin from Visual Studio Code from version 0.66.0 to 0.67.0.
Downgrading back allowed me to run the same code without any issue.
If you have moved your project to new machine or importing it from git, then try this.
Right Click on class > Run as > Run Configuration
remove main class reference
Apply > Close
Now again right click on class > run as java application.
It worked for me.
I ran the Java code at the Terminal and adding Class Path was solution like this:
> java -cp <JAR file> <JAVA Class file>
for example,
c:\code\prototype-app\target\classes>java -cp ..\prototype-app-1.0-SNAPSHOT.jar com_stree.app.DetectLabels
My runtime environment:
  OS: Windows 10
  JAVA: 15.0.1
  Maven: 3.8.1
Check the .jar or .class file permissions. I had the jar on a project library with permission of -rw-r--r-- and I changed it to -rw-rw-r-- using on Linux:
chmod 664 <.jar>
One library was calling ClassLoader.loadClass which started the error when loading the class in the jar with wrong permission.
I deleted some unused imports and it fixed the problem for me. You can't not find a Class if you never look for it in the first place.
sorry i am late to the question, but i will explain it to you in the simplest layman language.
When you type 'javac <programname.java>
The compiler checks the program and finds errors, first of all make sure your program is in the same directory as you have executed in the command prompt. Then it creates a. Class file of your program. For ex. If the name of my program was Test.java then the class file created should be Test.class which will be executed in the next line.
Sometimes java takes some other name for your .class, use that name and voila you'll get the output.
Put all the code in try block then catch exception in a catch block
try
{
// code
}
catch(ClassNotFoundException e1)
{
e1.getmessage();
}

jdeprscan throws cannot find class error

I'm trying jdeprscan on my CentOS system. Here are the commands that I'm executing:
export classpath=<PATH/*>:<ANOTHER/PATH/*>:<SOME/OTHER/PATH/*>
jdeprscan --for-removal --verbose --class-path $classpath --release 9 <ANOTHER/PATH>/MyProject.jar
In spite of providing the classpath, I'm getting multiple errors of this sort
Processing class <some/class/in/MyProject.jar>...
error: cannot find class <some/class/in/a/different/jar>
error: cannot resolve Methodref <some/class/in/a/different/jar>.<method>:()Ljava/lang/String;
I've verified that the class mentioned in the error message are pretty much among one of the jars provided in the classpath.
Strangely, it's not the case that I'm getting this error for every other classes referred in the jar that I'm scanning.
Few points for your consideration:
The are 50+ jars in the paths provided in the classpath
The jar that I'm trying to scan is residing in one of the paths mentioned in the classpath
I've tried jdeprscan available in JDK 9 & JDK 10 and getting the same errors
I've tried replacing the * in classpath with *.jar, doesn't help!
Is there anything wrong in the syntax that I'm following or is this a known bug in jdeprscan?
Some preliminary notes on jdeprscsan from Oracle JDK 11 under Windows (I know the question related to JDK 9 on CentOS, but maybe the following applies as well...):
use wildcard "path/to/lib/*.jar" (it will not work without the ".jar" extension)
having a wildcard with more than one path is not supported (i.e. --class-path dir1/;dir2/*.jar throws a parse exception on the wildcard)
JARs in the directory specified by --class-path are added to the classpath and analyzed in alphabetical order, which may cause some error : cannot find class X messages because a JAR a.jar may depend on a JAR b.jar which is not yet loaded.
Based on the above, I found the 3 solutions below. Note that I did the same experiment with jdeprscan from the Oracle JDK 12.0.2 without any improvement.
Solution 1: all classes on the classpath
unzip all JARs in a specific directory (ignore overwritted files such as META-INF/maven/pom.xml), e.g. mylib (note that at this stage, the mylibs directory contains only classes organized by directory packages, and no JARs).
run the following command:
jdeprscan --for-removal --class-path /path/to/mylib /path/to/my-application.jar
Advantage: fast (very manual operations)
Drawback: only analyses the JAR file that has been specified on the command line (my-application.jar)
Solution 2: all JARs + a fat JAR on the classpath
copy all JARs libs into a single mylib directory
extract all files from JARs of mylib (ignore duplicate files) and repack them into a big JAR mylib/00lib.jar (a simple ZIP file renamed to .jar makes the trick)
copy the mylib/00lib.jar to mylib/01lib.jar to ensure that it will be analysed
run the following command:
jdeprscan --for-removal --verbose --class-path path/to/mylib/*.jar path/to/my-application.jar
Advantage: fast (only a few manual operations) + analyses the JARs from mylib
Drawback: some of the jdeprscan messages will be related to the fat JAR 00lib.jar so you will not be able to determine immediately which library uses classes that are deprecated or removed from Java 9 or 11, but you can do it indirectly by looking at the class name, e.g. (a class from the com.atomikos library requires the missing class javax.jms.JMSException):
Processing class com/atomikos/datasource/xa/jms/JmsTransactionalResource...
error: cannot find class javax/jms/JMSException
Solution 3: reorder the JAR files on the classpath
copy all JARs libs into a single mylib directory
run the following command:
jdeprscan --for-removal --class-path path/to/mylib/*.jar path/to/my-application.jar
inspect the log to see error: cannot find class messages that are not supposed to be raised because the JAR exists in the lib directory. For each such library, copy the library with a name that is before the library name which reference it alphabetically speaking. For example, I have a JAR in the lib dir alpha.jar which depends on commons-lang-3.0.jar (which is not yet loaded in the classpath), so I copy commons-lang-3.0.jar to a0commons-lang-3.0.jar so that it will be loaded before alpha.jar. It is important to copy the JAR and not to rename it otherwise it may not be analyzed by jdeprscan (does not occur on every JAR). Once done, go back to step 2 until no error messages produced by library dependencies occurs.
Advantage: gives a clear view of which JAR uses deprecated/removed classes.
Drawback: takes a lot time (manual copy of each individual JARs which cause a classloading issue).
Conclusion
I use jdeprscan with Solution 2. This should be considered as a workaround (is it an incomplete tool documentation or a bug, I don't know...).
If you happen to have a folder in PATH which has classes and JARs, it won't work. You'd have to specify the JARs individually (or get rid of the classes).

JSP compilation fails when using dynamic classpath generated by IntelliJ IDEA on Windows

I have a Spring/MVC/Tomcat website project that I am attempting to run with IntelliJ IDEA. Because I am running on Windows, there is a command-line size limit, which is exceeded by the large classpath. I use IntelliJ's dynamic classpath feature which puts the classpath in a jar file to shorten the command line. Java runs with -classpath <classpath.jar>.
When I try to view a page, the JSP compilation fails with an error to this effect:
org.apache.jasper.JasperException: Unable to compile class for JSP:
An error occurred at line: [-1] in the generated java file: [<removed>.java]
[javac] <removed>.java:11: error: package javax.servlet does not exist
[javac] import javax.servlet.*;
[javac] ^
I ran it in debug and stepped into where the java compilation was being done and found the javac command line used. It was put together in org.apache.tools.ant.taskdefs.compilers.JavacExternal. I ran the javac command myself, with -verbose, and noticed that the dependency path from the search path for class files: log line shows up like:
C:\Users\<removed>\AppData\Local\Temp\file:\C:\Users\<removed>\lib\servlet-api-3.0.jar
Note that it seems like the absolute URI path is being treated as a relative path, resulting in an invalid path. I believe this is why it's not compiling properly.
Intellij's generated pathing jar's MANIFEST.MF lists the classpath with entries that are absolute paths that look like:
file:/C:/Program%20Files/Java/jdk1.8.0_121/jre/lib/charsets.jar file:/C:/Program%20Files/Java/jdk1.8.0_121/jre/lib/deploy.jar [...]
This problem doesn't happen on Mac, using dynamic classpath jar (even though it's not necessary because the command line too long error does not happen) so I believe something about the Windows path or the way that IntelliJ generates the classpath jar on Windows is messing up the JSP compilation.
Also, using an Ant build task that generates a pathing jar with relative paths works too, but I am interested in avoiding the use of Ant here.
How can I get this working, or what else do I need to investigate to get to the root cause?
This is a known bug in JDK.
Javac incorrectly handles absolute paths in manifest classpath headers. It has been fixed in JDK9.
When I investigated this problem, assuming Java8, I found a different root cause in my case.
In short:
The "/org/apache/jasper/servlet/TldScanner.java" on Line 102, attempts to scan locations for potential JARs.
It uses the "/org/apache/tomcat/util/scan/StandardJarScanner.java" to actually search.
Put a breakpoint on Line 221 URL[] urls = ((URLClassLoader) classLoader).getURLs();
You will see this ClassLoader has the "classpath.jar" as a potential JAR to scan (i.e. process).
But it cannot further find JARs referenced by a (classpath.jar) JAR's manifest file. Meaning, the real JAR(s) you need are not going to be checked.
A short fix, a for this is to:
Add "standard-1.1.2.jar" to your web/WEB-INF/lib/ dir.
If you look inside this jar, you will see *.tld files.
Test:
You can put a breakpoint on TldScanner.java Line 311 found = true;.
When it is not working, you will never hit this line.
When it works, with this (or any) fix, it will hit this line.

Diagnose "incorrect classpath" indicated by java compiler

Out of desperation of lack of ideas I'm currently working on a way to compile a single file from inside an eclipse plugin.
So far, I've successfully made code that compiles a single .java file that has no external .class (without being inside .jar) dependencies.
For the compilation process, I know where all the dependency .class files are and I give that information to the compiler using -classpath option.
Currently, I'm calling the compiler like this:
String[] params = new String[]{
"-properties", propertiesFile,
"-g", "-preserveAllLocals",
"-classpath", classPath,
fileToCompile,
"-d", outputPath,
"-proc:none",
"-proceedOnError",
};
boolean result = BatchCompiler.compile(
params, new PrintWriter(outWriter), new PrintWriter(errWriter), null);
The variables:
propertiesFile: exists and it contains the merge of the workspace + project's settings without repetition (in that order).
classPath: contains multiple paths separated by ";" (this one has problems, see below)
fileToCompile contains the absolute path of the file I want to compile. Do note that this file is not in the sources directory.
outputPath: The directory where the "bin" of the project is. It gets it from the IProject object itself.
You may find the meaning of the other options here.
classPath is giving me an error. Two classes exist in this test project:
This is its content (after reducing the size by removing most .jar includes from native java:
"C:/Program Files (x86)/java/jre1.8.0_66/lib/resources.jar";"C:/Program Files (x86)/Java/jre1.8.0_66/lib/rt.jar";D:/Users/user/runtime-EclipseApplication/Tests/bin"
I've tried using these as the last "include" in the classpath:
"D:/Users/user/runtime-EclipseApplication/Tests/bin"
"D\:\Users\user\runtime-EclipseApplication\Tests\bin"
"D\\:/Users/user/runtime-EclipseApplication/Tests/bin"
"D\\:\\Users\\user\\runtime-EclipseApplication\\Tests\\bin"
Here's the output it gives in stderr:
incorrect classpath: "D:/Users/user/runtime-EclipseApplication/Tests/bin"
----------
1. ERROR in D:\Users\user\runtime-EclipseApplication\.metadata\.plugins\myplugin\tmp\sources\Test2.java (at line 3)
public class Test2 extends Test{
^^^^^^^^
Test cannot be resolved to a type
I can assert in my own code that, just before the compiler is called:
That classpath directory exists
That Test.class is in that directory
I'm using the default package at the time that code executes
What am I doing wrong here? Why is it classifying it at an incorrect classpath?
I'm using org.eclipse.jdt.core(v.3.10.2) dependency and I'm compiling in eclipse Luna (4.4) which is the minimum version I want my plugin to support.
After days around this, somehow...
"C:/Program Files (x86)/java/jre1.8.0_66/lib/resources.jar";"C:/Program Files (x86)/Java/jre1.8.0_66/lib/rt.jar";D:/Users/user/runtime-EclipseApplication/Tests/bin <- No ending quote
That worked. I don't remember anymore if I did anything else but it works like that regardless if it has spaces or not.
I'm still wondering what is causing the inconsistency between the first elements using quotes but my element mustn't use any quotes.

How to import commons-io.jar jsp/java

I am getting an exception:
Cannot find symbol: FileUploadException;
I have a piece of code which uses
FileUploadException
The library that needs importing is:
org.apache.commons.fileupload.FileUploadException
The path to my project is :
D:\Projects\website
In the project folder I have each in its folder:
Tomcat, Derby, Website
I have copied:
commons-fileupload.jar and commons-io.jar
into both:
Tomcat/lib and Website/Web-INF/lib
---------------I tried this--------------
just importing the library on its own
import org.apache.commons.fileupload.FileUploadException;
adding the jars to the class path upon build:
javac -cp .;D:Projects\website\Tomcat\lib\commons-fileupload.jar;D:\Projects\website\Tomcat\lib\commons-io.jar com/otrocol/app/*.java
adding them to the Environment variables CLASSPATH
D:Projects\website\Tomcat\lib\commons-fileupload.jar;D:\Projects\website\Tomcat\lib\commons-io.jar
I also tried adding the jars where my .java files are as #Scot Ship suggested
----mentions---
I am not using any IDE
The code contains more unrecognized symbols, but I'm trying to solve one at a time
First time using apache, tomcat, jsp.. please be gentle
Vlad, the web container will automatically look for JARs inside
/WEB-INF/lib
even without any developer intervention. Take note that it's all caps WEB-INF. As long as your JAR is there, it will be in your web application's classpath.
Try to display this in one of your servlets or JSP:
System.getProperty("java.class.path")
and you'll get a better view of what classes and JARs were actually loaded.
Update: After reviewing your question, it appears you're facing issues in compiling the files to begin with and you're doing it outside an IDE.
Take note that when you use -cp in javac like this:
javac -cp .;D:Projects\website\Tomcat\lib\commons-fileupload.jar;D:\Projects\website\Tomcat\lib\commons-io.jar com/otrocol/app/*.java
Whatever value you have set in the CLASSPATH environment variable becomes ignored.
Be absolutely sure that the class FileUploadException is indeed inside one of the JARs you're trying to import: you can view the JAR directly using an unarchiving tool.
Also, change the com/otrocol/app/*.java to com\otrocol\app*.java - you should be using your system delimiter (not that this may affect your problem).
Create a simple HelloWorld in the same location as the file you're compiling, add the SystemOut mentioned above, and compile it the same way you're doing for the concerned file.
Read this http://commons.apache.org/proper/commons-fileupload/faq.html#class-not-found. Probably you have the fileupload jar but you also need commons-io.jar in your classpath as well.

Categories

Resources