I developer a web application using Java. When I deploy it to my application server (Jetty, Tomcat, JBoss, GlassFish, etc.) throws an error. I can see this error message in the stacktrace:
java.lang.ClassNotFoundException
Or
java.lang.NoClassDefFoundError
What does this mean and how can I fix it?
What does this mean?
First, let's see the meaning of java.lang.ClassNotFoundException:
Thrown when an application tries to load in a class through its string name using:
The forName method in class Class.
The findSystemClass method in class ClassLoader.
The loadClass method in class ClassLoader.
but no definition for the class with the specified name could be found.
Usually, this happens when trying to open a connection manually in this form:
String jdbcDriver = "...'; //name of your driver
Class.forName(jdbcDriver);
Or when you refer to a class that belongs to an external library and strangely this class cannot be loaded when the application server tries to deploy the application.
Let's see the meaning of java.lang.NoClassDefFoundError (emphasis mine):
Thrown if 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.
The searched-for class definition existed when the currently executing class was compiled, but the definition can no longer be found.
The last part says it all: the class existed at compile time i.e. when I compiled the application through my IDE, but it is not available at runtime i.e. when the application is deployed.
how can I fix it?
In Java web applications, all third party libraries used by your application must go in WEB-INF/lib folder. Make sure that all the necessary libraries (jars) are placed there. You can check this easily:
- <webapp folder>
- WEB-INF
- lib
+ jar1
+ jar2
+ ...
- META-INF
- <rest of your folders>
This problem usually arises for JDBC connectivity jars (MySQL, Derby, MSSQL, Oracle, etc.) or web MVC frameworks libraries like JSF or Spring MVC.
Take into account that some third party libraries rely on other third party libraries, so you have to add all of them in WEB-INF/lib in order to make the application work. A good example of this is RichFaces 4 libraries, where you have to download and add the external libraries manually.
Note for Maven users: you should not experience these problems unless you have set the libraries as provided, test or system. If set to provided, you're responsible to add the libraries somewhere in the classpath. You can find more info about the dependency scopes here: Introduction to the Dependency Mechanism
In case the library must be shared among several applications that will be deployed on your application server e.g. MySQL connector for two applications, there's another alternative. Instead of deploying two war files each with their own MySQL connector library, place this library in the common library folder of the server application, this will enable the library to be in the classpath of all the deployed applications.
This folder vary from application server.
Tomcat 7/8: <tomcat_home>/lib
JBoss 7/Wildfly: <jboss_home>/standalone/lib
The class must exist under WEB-INF/classes or be inside a .jar file under WEB-INF/lib. Make sure it does.
Same problem happen with me.
Might be possible one of your libraries are using some classes internal which is not available
in your lib or maven dependency pom.xml.
Thats means you have analyze your error logs and identify these classes and then import all dependencies in maven or lib folder.
I have fixed this error by the same way.
because some of my libraries are using activation.jar and json.jar internally.
Related
Problem - I have an issue with two jars in my web application which I am developing using Eclipse IDE of Mars version and hosting it on apache tomcat 7.0 web server -
hibernate-jpa-2.1-api-1.0.0.final
com.ibm.ws.webservices.thinclient_7.0.0
Both of them have same package structure and and same class -
javax.persistence.CascadeType
This package and class is a ENUM type declaration which was being used from first jar. And I have recently added the second jar which is also mandatory as a dependency for a third party jar for authentication and authorization for my application. Once the second jar is added, I have got this issue where the package intended to be used from first jar is being picked up from the second jar.
The Enumeration value CascadeType.DETACH was being used from first jar file in the application and this ENUM value is not defined in its counterpart in the second jar. Hence this issue is being faced.
Things I have already tried and no result -
Tried to remove the above conflicting package from the second jar and added to the library. Then this jar was not being picked up at run time and I was getting noclassdeffound error for the class - com.ibm.ws.webservices.multiprotocol.GeneratedService even after this class is visible inside the second jar itself in classpath.
Instead of CascadeType.DETACH, I tried to use some other ENUM value of the second jar itself and let the compiler ignore first jar. Then was getting the noclassdeffound error for the class - com.ibm.ws.webservices.multiprotocol.GeneratedService which is still inside the second jar.
Out of suggestions I got from stack overflow itself, traversed to Right click on project -> build path -> configure build path -> Order and export to set priority for jars. But at this option, only priority can be set within library sets like WEBAPP libraries, JDK libraries or externally configured libraries but not within individual jars inside a set of libraries. But my both libraries were inside WEBAPP libraries set itself and hence could not set the priority of those jars using this option. As another trial, I removed the second jar from the WEBAPP libraries and configured as an external library instead and set its priority lower than WEBAPP libraries which contained my first jar. Still was getting the same issue- noclassdeffound error for the class - com.ibm.ws.webservices.multiprotocol.GeneratedService which is still inside the second jar.
Some suggestions from stack overflow were setting dependencies in maven pom xml. This will not be applicable to my application as I am not running it through maven but just running it on tomcat web server.
Please suggest a way forward to resolve this issue. Please note that this application is targeted for Websphere server at environment level. Tomcat server is being used at the local setup itself. Please suggest keeping this in mind. I also tried installing websphere server for local setup as well but could not do it as commercial servers are not allowed to be installed inside our organization.
We have started using our new in-house built authorization library from this version. It internally loads a native file .so and then does whatever it has to (Before it used to do based on regex).
Now in our application, we have 2 different war files that are deployed on the same tomcat in production. Both of them use this authorization library and hence both of those class loaders try loading the native file twice. Which of-course the jvm does not allow as you can only load it once.
java.lang.UnsatisfiedLinkError: Native Library /usr/lib64/xxxx-0.1.0.so already loaded in another classloader
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1903)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1855)
at java.lang.Runtime.loadLibrary0(Runtime.java:870)
at java.lang.System.loadLibrary(System.java:1122)
....
One solution to this problem is that, we put this authorization jar in the tomcat/lib. So that because the tomcat common class loader loads it, they are automatically available to child class-loaders (so the war files) and everyone can access it. But this solution needs special maintenance. And I dont like this tweaking. I might as well do some config if possible in my maven pom.
Is there any other simpler solution to this kind of problem? Its a pure spring application, maven based.
I developer a web application using Java. When I deploy it to my application server (Jetty, Tomcat, JBoss, GlassFish, etc.) throws an error. I can see this error message in the stacktrace:
java.lang.ClassNotFoundException
Or
java.lang.NoClassDefFoundError
What does this mean and how can I fix it?
What does this mean?
First, let's see the meaning of java.lang.ClassNotFoundException:
Thrown when an application tries to load in a class through its string name using:
The forName method in class Class.
The findSystemClass method in class ClassLoader.
The loadClass method in class ClassLoader.
but no definition for the class with the specified name could be found.
Usually, this happens when trying to open a connection manually in this form:
String jdbcDriver = "...'; //name of your driver
Class.forName(jdbcDriver);
Or when you refer to a class that belongs to an external library and strangely this class cannot be loaded when the application server tries to deploy the application.
Let's see the meaning of java.lang.NoClassDefFoundError (emphasis mine):
Thrown if 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.
The searched-for class definition existed when the currently executing class was compiled, but the definition can no longer be found.
The last part says it all: the class existed at compile time i.e. when I compiled the application through my IDE, but it is not available at runtime i.e. when the application is deployed.
how can I fix it?
In Java web applications, all third party libraries used by your application must go in WEB-INF/lib folder. Make sure that all the necessary libraries (jars) are placed there. You can check this easily:
- <webapp folder>
- WEB-INF
- lib
+ jar1
+ jar2
+ ...
- META-INF
- <rest of your folders>
This problem usually arises for JDBC connectivity jars (MySQL, Derby, MSSQL, Oracle, etc.) or web MVC frameworks libraries like JSF or Spring MVC.
Take into account that some third party libraries rely on other third party libraries, so you have to add all of them in WEB-INF/lib in order to make the application work. A good example of this is RichFaces 4 libraries, where you have to download and add the external libraries manually.
Note for Maven users: you should not experience these problems unless you have set the libraries as provided, test or system. If set to provided, you're responsible to add the libraries somewhere in the classpath. You can find more info about the dependency scopes here: Introduction to the Dependency Mechanism
In case the library must be shared among several applications that will be deployed on your application server e.g. MySQL connector for two applications, there's another alternative. Instead of deploying two war files each with their own MySQL connector library, place this library in the common library folder of the server application, this will enable the library to be in the classpath of all the deployed applications.
This folder vary from application server.
Tomcat 7/8: <tomcat_home>/lib
JBoss 7/Wildfly: <jboss_home>/standalone/lib
The class must exist under WEB-INF/classes or be inside a .jar file under WEB-INF/lib. Make sure it does.
Same problem happen with me.
Might be possible one of your libraries are using some classes internal which is not available
in your lib or maven dependency pom.xml.
Thats means you have analyze your error logs and identify these classes and then import all dependencies in maven or lib folder.
I have fixed this error by the same way.
because some of my libraries are using activation.jar and json.jar internally.
I am getting ClassNotFound exception even though the class existed in my project.On further investigation,I found that another file with same file name (Constants.java) was present in another project and both these projects were present in my classpath(although with a different name).
So is there any way I can prevent that ClassNotFoundException at runtime because of someone including creating a similar file in a different project??
com.util.Constants.java - business-common.jar
com.util.Constants.java - reader.jar
My projects in classpath are:-
1) business-common.jar
2)reader.jar
The technical solution would be class loader separation, using something like OSGi to completely separate the classpath of your application's modules. OSGi is integrated in some Java EE Application Servers (e.g. Glassfish) for separating the classpath of different EAR/WAR modules deployed on the same server.
If you don't want to introduce this extra complexity, you can easily solve it by using a dedicated package namespace for each module, e.g. com.reader.util.Constants vs com.business.util.Constants.
If there are two different classes with the same name in the same package, you are inviting trouble.
If there is a common utility package, there needs to be a package maintainer as well.
Are the two versions of the class really necessary, or is an accident that they are both included? Is it a Java EE application (WAR, EAR), which container is being used?
Often this situation is an accident, check this classpath troubleshooting tool JHades to know how many similar classpath duplicates exist in the project.
A standalone jar is available for generating command line reports, if there are problems starting the server there is support for runtime analysis.
This talk is great for further understanding the Java classpath and why these type of errors occur.
ClassNotFoundException means that one of the classloaders of your application cannot 'see' a class file for class Constants.
This does not mean that the class is not deployed on the server, only that a class loaded by a certain classloader needs this class but cannot find it.
JHades can be used to print the classloaders chain and query the classpath to better understand what is going on in these cases.
In our application(applet) I want to enable export functionality if one of the required jars is found. I do not want to add this jar applet references to avoid download size.
I am using Class.forName with one of the classed to check whether particular is available. In local machine Class.forName call retruns an instance although the jar is not in any of the class paths.
Can anybody explain tomcat class discovery mechanism.
Applets run at the client side(inside the browser of the user) not on the Tomcat web server, so this is unrelated to Tomcat.
You'd want to investigate how Applet classloaders work.
Usually they will try to downloading the classes from the web server under the same Url as the applet was fetched from. So if the applet is at http://www.example.com/Hello/HelloApplet
and needs the class foo.bar.MyClass it will try to download http://www.example.com/Hello/foo/bar/MyClass.class if it isn't found locally.
Based on your description of having an Applet I don't see any option but to include the jar file in the applet tag as the applet runs on the client side.
You could set HTTP cache headers for the jar files to allow the client browser to cache them, therefore, you only pay the download cost only once.
For frequently changing jar files include the a version number in the jar file name to avoid client side caching issues with same named but contentually different jars.
Edit: Although the question is about the way tomcat discovers the jars I think the root cause of the problem is elsewhere.
In Tomcat 6 on the server side Tomcat searches the $TOMCAT_HOME/lib and WEB-INF/lib directories for your jar files. If you add or remove files there you usually need to restart the entire Tomcat instance.
Edit2:
Your experience about locating the jar file might be because you run the HTML page from the same directory where your webapp resides or you have the JAR file in a common place or common classpath location (for example in the JRE/lib/ext directory).
I am having a hard time following your question. Are you trying to download classes into an applet if a particular runtime condition is met? From 6u10 I believe you could dynamically download extensions with DownloadService. Going back to 1.2, you can use URLCLassLoader.newInstance, although that wont be so good on the cache side of things.
This question isn't very clear. Tomcat and Applets are completely different in terms of class loading. Applets have a security manager that prevents certain things, such as loading arbitrary classes. They have to download the classes from the web server. The web server doesn't have to be tomcat or even Java; the applet files are just files served over plain HTTP.
As for Tomcat, this article explains version 6's classloading. In particular, Tomcat uses a heirarchy of classloaders to find classes. There are several well-known locations where jars are automatically loaded, such as $CATALINA_HOME/lib or $CATALINA_HOME/shared/lib. It also loads the web-app's own jars and classes. The classloaders work as follows:
The bootstrap class loader looks in the core Java classes folders.
The system class loader looks in the $CATALINA_HOME/bin/bootstrap.jar and
$CATALINA_HOME/bin/tomcat-juli.jar
The WebAppX class loader looks in WEB-INF/classes and then WEB-INF/lib
The common class loader looks in $CATALINA_HOME/lib folder.
The shared class loader looks in $CATALINA_HOME/shared/classes and $CATALINA_HOME/shared/lib if the shared.loader property is set in conf/catalina.properties file.
Reason: One of the other libraries(jars) referenced earlier had the class I was looking for.