NoClassDefFoundError using JAR from other project - java

There seem to be a number of questions on SO in this area, but I haven't been able to find one with exactly my scenario:
I have two projects in Eclipse: Core and Interface.
In the Core project I have 5 .jar files that contain useful classes and so on. Let's say that one of the jars is called DAO.
In the Interface project I have gone into the Build Path (via Right-Click > Build Path > Configure Build Path...) and gone to the Projects section, then added the Core project.
At first the Interface project still couldn't see the classes within the DAO.jar, which confused me, but I found that by going into the Core project's build path and checking the box next to DAO.jar (for export) the compiler stopped complaining and I was able to use classes from DAO.jar.
(Just to be specific, I'm making a Java webapp with Servlets and JSPs and so on, running on a local Tomcat server.)
I build the project, but when I navigate to a Servlet where the Get method involves a class from DAO.jar, I get a NoClassDefFoundError. Here's the stack trace:
java.lang.ClassNotFoundException: dao.DirectSqlVisitorImpl
org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1702)
org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1547)
java.lang.ClassLoader.defineClass1(Native Method)
java.lang.ClassLoader.defineClass(ClassLoader.java:792)
java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:2928)
org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:1174)
org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1669)
org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1547)
interface.DonationsServletController.doGet(DonationsServletController.java:79)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
What I've gathered is that the JRE can't find the definition of the DirectSqlVisitorImpl class at runtime, even though the Eclipse error-checking lets it fly now that I've configured my Build Path in the (seemingly) correct fashion.
So what do I need to do to make sure that the jar gets pulled into the Interface project via the Core project?
As a note, I'd prefer not to do something like adding the jars directly to the Interface project, as the Core project could be used by other projects, and I'd like to have modifications to the Core project cascade to all dependent projects.
Thanks!

Your issue is the difference between the classpath used by eclipse as it compiles your code, and the classpath used at runtime by tomcat. I have dealt with this in an OSGi-based desktop application, though I haven't, yet, learned how to package a JavaEE application as separate components. However, I can tell you that the path to the answer is to learn how to build the WAR and/or EAR files so that the libraries in one are exported by the bundle and the other can import them.

One solution may be to add the dependent jars to the tomcat lib folder. i.e /lib.

Although the other answers here may be useful in some respect, overall they are incomplete.
I did find a way to resolve my problem and get rid of this error, though it does not quite accomplish the cascading system that I had hoped for.
It seems that dsh was right in that my issue is the difference between the classpath used by eclipse as it compiles my code, and the classpath used at runtime by tomcat. Or more specifically, the DAO jar file exists within my project, but doesn't get deployed to the tomcat server.
To solve this, I went to my Project's Properties > Web Deployment Assembly > Add... > Archives from Workspace > Add...
I then selected the DAO jar and added it in. The project then built and ran fine, without the NoClassDefFoundError. So my problem was solved, essentially.
However, I'm not sure what would happen if I changed/updated the jar files in the Core project.

Related

JBoss classloading IncompatibleClassChangeError

I'm migrating a project from JBoss 5 to 6.4. In the process I've updated several jar files in my build. I had several ClassCastExceptions which I resolved by taking the version of the specific classes from a jar in the JBoss system modules and using that in my app build. I've done so with two jars, jbossweb-7.5.26.Final-redhat-1.jar and jboss-servlet-api_3.0_spec-1.0.2.Final-redhat-2.jar which contain the classes org.apache.catalina.connector.Request and javax.servlet.http.HttpServletRequest respectively. I'm using both of those jars as libs in my app build and all is compiling without error or warning. I've confirmed that when I remove those libs the app fails to compile as it can't find the included refernced classes, so I know I'm not actually referencing some other copy of those classes in my build. The app is deploying fine, but when I try hitting it I get an exception
JBWEB001018: An exception or error occurred in the container during
the request processing: java.lang.IncompatibleClassChangeError: Class
org.apache.catalina.connector.Request does not implement the requested
interface javax.servlet.http.HttpServletRequest
When I look at the class definitions from the jars in my editor (JDeveloper 12c) I can see that org.apache.catalina.connector.Request as defined in jbossweb-7.5.26.Final-redhat-1 does in fact implement javax.servlet.http.HttpServletRequest as defined in jboss-servlet-api_3.0_spec-1.0.2.Final-redhat-2.jar.
I turned on verbose logging of classloading (JAVA_OPT -verbose:class), and confirmed that as JBoss is loading those two classes they are in fact being loaded from those two jar files, not some other one I didn't know about. I can see in my developer tool that the .class files I'm including in my project are from those same two jar files.
Possibly relevant, the classloading logs say JBoss is loading org.apache.catalina.connector.Request from RedHat/JBoss/EAP-6.4.0/modules/system/layers/base/.overlays/layer-base-jboss-eap-6.4.18.CP/org/jboss/as/web/main/. I'm not sure why it's using that copy/location rather than RedHat\JBoss\EAP-6.4.0\modules\system\layers\base\org\jboss\as\web\main.
So what gives? What I read on the error would suggest to me that jboss-servlet-api_3.0_spec-1.0.2.Final-redhat-2.jar was compiled against a different version of HttpServletRequest than jbossweb-7.5.26.Final-redhat-1 includes.
Is that interpretation or the error correct? Does JBoss 6.4 really ship with incompatible jar files in its system modules? If so what versions of these jars do I need and how to I check compatibility? And can I safely switch to a different jar file without introducing more incompatibilities with other jars? What other causes might I be missing? Any help much appreciated here.
1/ You shouldn't depend on servlet API implementation
2/ You shouldn't include those implementation classes in your application are they are provided by the server itself
3/ You shouldn't put API jars or their implementation in your application or if you do this you need to exclude those modules from your application using a jboss-deployment.xml
Looks like the issue was that I was not using the modules.xml correctly. I needed to add dependencies for the two packages in my module.xml file
<dependencies>
<module name="org.jboss.as.web"/>
<module name="javax.servlet.api"/>
</dependencies>
I had previously added those modules to my war file's jboss-deployment-structure.xml and that did not do the trick and left me with ClassNotFoundExceptions. My Jboss-deployment-structure.xml now just references my own custom module as a dependency, which in turn has dependencies of its own.
I still don't understand what was causing the previous error, as it's all the same versions of the jar files in question so I don't know where a conflict was, but this got the error to go away and no more ClassNotFoundExceptions.

in eclipse how do I get tomcat run two connected projects when all three require servlet-api.jar?

In eclipse, I have two projects, each populated with servlets. Project A contains Project B in its build path.
The problem is each of these projects requires servlet-api.jar in order to compile, and matters are made worse when Tomcat ALSO needs servlet-api.jar in its library to run Project A.
When I have servlet-api.jar in the WEB-INF/lib folder of both Project A and Project B as well as Tomcat, I get a ClassNotFoundException on javax.servlet.Servlet because the multiple instances of servlet-api.jar conflict. If I delete servlet-api.jar from either of the projects, they can no longer recognize the HTTPWebRequest class, even if I leave servlet-api.jar in Project B and leave Project B in the build path of Project A, the servlets in Project A still won't recognize the HTTPWebRequest class.
If I remove servlet-api.jar from Tomcat, Tomcat can no longer run, and throws a NoClassDefFoundError on javax/servlet/http/HttpServletRequest. It doesn't seem like there's any way I can get all three to work together since they each need servlet-api.jar to work, and yet if more than one has it there is a conflict.
Thank you in advance!
In 'servers' view configure a tomcat server (if you haven't already done so). In project A and B go to java build path -> Libraries. Click on add library -> server runtime and then select tomcat runtime (which you configured via 'servers' view). Following links give you further information.
adding tomcat as a server in eclipse.
http://www.eclipse.org/webtools/jst/components/ws/M4/tutorials/InstallTomcat.html
As it turns out, the errors were caused by the init methods in two of the classes in Project B. After spending multiple days trying everything possible, the solution in the end was to merge the two projects.
Things that did not work include:
deleting servlet-api.jar from either of the projects, both of the projects, or from Tomcat
adding or removing project B from project A's build path (though this was necessary to compile A)
adding project B under Tomcat's build path (though it did seem to help)
removing startup calls from web.xml to keep the init() method from being called (this allowed Tomcat to start without any errors, but then the project didn't work
We may have tried a few other things, but in the end, removing project B and merging the files with A was what allowed it to work.

java.lang.ClassNotFoundException: com.ibm.broker.config.proxy.BarFile

Added 2 jar files for IBM integration in Java. Getting this exception:
error at :: BarFile b = BarFile.loadBarFile("C:\\Users\\Uni\\Desktop\\outputt\\Dev_BAR.bar");
root cause:::::::::
java.lang.ClassNotFoundException: com.ibm.broker.config.proxy.BarFile
org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1714)
org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1559)
com.cts.XmlExtract.extract(XmlExtract.java:25)
com.cts.BrokerServlet.doGet(BrokerServlet.java:30)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
When developing a java project using an IDE (perhaps IBM's RAD or Eclipse) it is important to remember that there are two classpath that you care about:
The classpath when you are writing the code. This is the Compile Classpath.
The classpath when you are running the code on a server. This is the Runtime Classpath.
The error you are receiving is happening because the Runtime Classpath does not contain one (or both) of the jars that you are attempting to add to your project.
You can add a jar to the Runtime Classpath using one of the following techniques:
Add the jar to the WEB-INF/libs directory in your web app project. This technique guarantees that the jar will be distributed with your WAR file, but also guarantees that the jar will not be shared by other projects that may want to use the jar.
If you are building an EAR, add the jar to the EAR file. It's been a while since I built an ear, so I dont remember the exact directory name (I think you just at it to the root of the EAR). This allows WAR files that are in the EAR to share the jar.
Add the jar to a shared location in your tomcat. $CATALINA_HOME/lib seems like a good spot. This allows all web apps in that instance of tomcat to share the jar.
Other. Other servers provide other means to share a jar.

Adding an external JAR to Eclipse Application debug configuration

The issue is as follows:
I have a 3rd party Eclipse plug-in installed and running
The above Eclipse plug-in provides an "extension point" of sorts - a source for a class I can extend/rewrite and replace in the plug-in lib directory (I am not saying it's a great idea, but necessity makes us do things we are not proud of - in-house development has its quirks)
The idea here is to envelop any such change in an external JAR (created by us) so that any change in code wouldn't require us to restart Eclipse to "refresh" the "extension point" class during development.
Eventually, a plugin/bundle will be created and placed as a dependency on the original plugin - so that installing and using that plug-in would actually, you know, work.
Question is - can I somehow add what is basically an external JAR file to Eclipse Application debug/run configuration?
Normally, adding JAR to classpath tab would work for regular Java application debugging/running. Eclipse Application however, doesn't have that tab.
So far the efforts (failed, perhaps due to some stupid syntax error or whatnot) included:
Adding the JAR as a dependency to Bundle-ClassPath: of the plug-in as C:\test.jar
Adding the JAR to the system's CLASSPATH variable
None of that made any difference - the code in the "extension point" that refers to a class in the JAR file fails - exception that boils down to:
Caused by: java.lang.ClassNotFoundException: test.Test
at org.eclipse.osgi.internal.loader.BundleLoader.
findClassInternal(BundleLoader.java:506)
Any pointer/help/criticism would be greatly appreciated.
Update
Apparently putting the JAR in the lib directory of the plug-in and updating the MANIFEST file doesn't work (not that it would help me - since such a solution would require a "refresh", which I am trying to avoid in the first place), so I must be doing something fundamentally wrong.
Does that make any sense or did I miss something in one of those attempts?
I have included an external JAR file to my Eclipse application.....not to the debug/run configurations but to the application itself.
What we did was to wrap the plugin into it's own java project. We are using maven for our build, so the pom.xml lists the dependency as the .jar file (which we put into a lib directory in the project). The manifest.mf file exports the needed classes. My application plugins have a dependency on this project. When I debug/run the application in the workbench I just make sure that this library project is included.
I'm not sure this answers your question completely or not....but I hope it helps.
A first guess based on some assumptions:
You are developing an extension to an 3rd party extension point 'foo'. Your application is a Eclipse Application, that you start via a run configuration. You need to create a new plugin 'foo-extension' which implements the extension point. You have to add the new plugin as a plugin dependency to your application. This way it will be available in the project class path, as well as in the 'Plugin-Ins' tab of your run configuration. Select the new project and when you start your application the extension will be available with the latest change.

Eclipse debug-time classpath problem: How do you include a dependent project's output into a web project's runtime classpath?

So I started with a web services project (just a dynamic web project) that builds and debugs correctly from eclipse. We've pulled a chunk of common code out that we want to put into a shared library so now those classes are going into a separate jar project that the web project references.
On the web project, I did Project->Properties->Java Build Path->Projects->Add and added the jar project. And this correctly solved all the compile-time classpath problems and everything builds fine. But at runtime, when the tomcat server fires up, spring attempts to inject some of the classes contained in the jar file and I get a NoClassDefFoundError.
My .class and properties files and the contents of my META-INF directory are showing up in the ./build directory, but my WEB-INF/lib directory seems to be referenced in-place, and the jar dependency doesn't get copied in to it to show up as part of the Web App Library.
What is the magical incantation to tell eclipse that the other jar project needs to be available to tomcat at runtime? From our ant build script, we first just build the other project into WEB-INF/lib and everything works fine, but not for eclipse debugging.
I figured this out after spending some time on it. If you are in Eclipse Helios , go to properties > deployment assembly > add > project and select the dependent project you wish to add.
Java EE module dependencies would solve this problem.
You have already done the task of extracting your common classes into its own project, possibly because other projects depend on these classes. Either way, you'll have to ensure that this is a Utility project (appears under Java EE in the project wizards), and not just a plain Java project.
One that is done, you can proceed to add the Utility project to your build path (compile-time path) as you have figured out.
The additional (final) step is to establish a Java EE module dependency between your Dynamic Web project and the shared library, which causes the utility's classes to be placed in WEB-INF\lib during deployment, and even during export of the WAR. To do so, visit the dynamic web project's properties, and browse to the Java EE module dependencies. Ensure that your utility project is selected here. Redeploy/publish your application and you should be good to go.

Categories

Resources