Is there a chance to get an information about libraries used in my java application?
Example: If I deploy my application on glassfish, the glassfish has it's own libraries and my application has own. If I use a newer version of a lib as the glassfish has, I want to test/log that my lib is used.
The reflection API lets you find some information about classes loaded into the application. For example assuming the library that includes SomeClass is loaded from a .jar file that includes version information you can use:
Package libPackage = SomeClass.class.getPackage();
String libVersion = libPackage.getSpecificationVersion();
If the .jar file does not include version information you can still find out its name with:
URL classLocation = SomeClass.class.getProtectionDomain().getCodeSource().getLocation();
Related
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.
My target platform is a WebLogic 12c application server.
I have an ear-project, which on startup requires e.g. org.apache.commons.logging.LogFactory.
I know that this class - an related classes - can be found in <WL_HOME>/modules/com.bea.core.apache.commons.logging.api_1.1.1.jar, but it is not by default available on the classspath.
In such cases - am I supposed to somehow make the jar file in <WL_HOME>/modulesavailable on the classpath - or should I provide whatever jar file I find suitable - either bundled in the application, or placed in <WL_HOME>/user_projects/domains/<mydomain>/lib?
If I am to use the one in the <WL_HOME>/modules folder - how do I configure my domain to make it available?
To me it seems reasonable that the jar files in the modules folder should be considered provided dependencies, but so far I have been unable to find the right way to enable them as such - I have been browsing for an answer for hours:-)
UPDATE:
I know I can simply add them to the CLASSPATH variable in the server startup script - my question is more like - should I? Is there a better way - or should I completely forget about <WL_HOME>/modules?
That's a short-sighted approach.
you need to reboot the server to upgrade libraries
every app on the server must be okay with those libraries in their claspath
Weblogic has the concept of Shared JEE Libraries (example). In short, you add extra lines to MANIFEST.MF and configure the jar differently, then you can reference it in other apps using weblogic-application.xml or whatever.
The point is that you can upgrade the library without restarting the server (provided you gave it a version like 1.1 (there were bugs last time I named it 1.1.1 - it needed to be able to cast it to a floating-point number to seamlessly upgrade)).
If you just want to include some libraries but not share them outside the app, then just specify the correct <prefer-application-packages> or < prefer-web-inf-classes> element, depending on whether you have an EAR or a WAR.
Background:
I have the following problem: I have several WAR files I need to have deployed on same Websphere server. The WAR files use libraries that depend on having a specific version of XMLSec regisered as the XML Signature Provider (with the Java Security class). Currently I bundle this library with each WAR file (since the WAR files also need to work standalone and on Tomcat's without any special shared library configuration etc.). Each WAR files registers the provider with Security.addProvider() in a ServerContextListener. But this causes problems in the multi-WAR setup, because if one WAR file does the registration with Security.addProvider) and another WAR files tries to fetch it using the XMLSignatureFactory class (which is actually a javax.* class contained inside the XMLSec JAR itself, but which ultimately calls back to the global provider list configured with Security.addProvider), then it causes a ClassCastException inside XMLSignatureFactory, because this class does a cast of what it gets from Security into to its own version of the provider classes, which doesn't work. The exact stack trace is as follows:
Caused by: java.lang.ClassCastException:
org.apache.jcp.xml.dsig.internal.dom.DOMXMLSignatureFactory
incompatible with javax.xml.crypto.dsig.XMLSignatureFactory at
javax.xml.crypto.dsig.XMLSignatureFactory.findInstance(XMLSignatureFactory.java:202)
at
javax.xml.crypto.dsig.XMLSignatureFactory.getInstance(XMLSignatureFactory.java:292)
By the way this is not a case of conflict with different versions of XMLSec being in play or conflicts with Websphere's own version. There is only one version albeit it is loaded from different WAR's.
Of course the solution is to have the xmlsec library loaded with a common classloader so that there is only one version of the classes loaded that all WAR files see, which would avoid ClassCastExceptions etc.. But here is the rub: I also need to have each application loaded with the "parent last" policy - or rather, I need the JAR files inside each application to take precedence over Websphere's built-in version of the libraries (for instance Axis2 that I also include in the WAR filesetc.). Furter, I would prefer that I can keep the xmlsec library in each WAR files' WEB-INF/lib folder, so that the WAR files can still work stand-alone (i.e. in other environments which might not have the shared library configured etc.).
So basically I want to have a common class loader loading the XMLSec library, say, somewhere from disk. Let's denote that [SHARED XMLSEC]. Then I want each application classpath to ultimately appear like this:
App1: [SHARED XMLSEC][App1 WEB-inf/lib][Websphere libraries][JDK libraries]
App2: [SHARED XMLSEC][App2 WEB-inf/lib][Websphere libraries][JDK libraries]
etc.
In such a configuration it doesn't matter if App1+App2 themselves contain the XMLSec library since the shared one will take precedence so they will use the common one. At the same time, App1+App2 are still free to override other built-in Websphere libraries (Axis2).
Is it possible to realize this configuration and what options do I need to set? Do you see alternative ways to achieve the same objective?
Since you have a conflict between classes here, I would suggest going for isolated class loaders for each application. On the server side, setting the class loader policy to 'Multiple' should provide isolation between applications.
Once you have this set, configure class loading at the application level to the 'Parent last' configuration for both the applications.
The following Knowledge Center link has the relevant instructions [Steps 2,3 & 4 under the 'Procedure' section] :
http://www.ibm.com/support/knowledgecenter/en/SSAW57_8.5.5/com.ibm.websphere.nd.multiplatform.doc/ae/trun_classload.html
[Note: The version of WAS in use is not specified in the question. The Knowledge Center link refers to version 8.5.5.]
I have a Java EE application where you can define variables of a certain type. To validate that the value expression is valid for it's type, I create a string containing a small class:
public class CompilableExpression {
private <type> expression = <expression>;
}
.. and try to compile it using JavaCompiler:
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
Iterable<? extends JavaFileObject> compilationUnits =
Arrays.asList(stringContainingCompilableExpression);
CompilationTask task = compiler.getTask(
null, null, diagnostics, options, null, compilationUnits
);
task.call();
This works fine if you are using type: String and expression: "my string", or type: Integer and expression: 10.
I also want to validate types using the #Entity annotation.
When I try to do so I get an error:
Cannot find annotation method name() in type javax.persistence.Table: class file for javax.persistence.Table not found
So, I need to add a JAR containing javax.persistence classes to the class path somehow. Is there a generic way to find this JAR? I'm using GlassFish, and don't want to build a GlassFish only solution.
Or is adding it to my project as a normal (non provided) dependency the way to go?
Update
I'm trying to at least find the location in GlassFish (at ~/glassfish-4.1/glassfish):
find ./ -name '*ee*.jar'
./lib/javaee.jar
./modules/security-ee.jar
./modules/amx-javaee.jar
./modules/javaee-kernel.jar
./modules/autostart/osgi-javaee-base.jar
./modules/autostart/osgi-ee-resources.jar
./modules/deployment-javaee-full.jar
./modules/deployment-javaee-core.jar
./modules/glassfish-ee-api.jar
./modules/javax.management.j2ee-api.jar
My best guess is to use ./lib/javaee.jar, but when I check the contents it's almost empty:
$JAVA_HOME/bin/jar tf ./lib/javaee.jar
META-INF/
META-INF/MANIFEST.MF
META-INF/maven/
META-INF/maven/org.glassfish.main.extras/
META-INF/maven/org.glassfish.main.extras/javaee/
META-INF/maven/org.glassfish.main.extras/javaee/pom.xml
META-INF/maven/org.glassfish.main.extras/javaee/pom.properties
Does anyone know where (in the GlassFish installation) to get the JAR including the javax.persistence classes?
The JAR you are looking for is in $GLASSFISH_HOME/glassfish/modules/javax.persistence.jar
If you are deploying to a JavaEE App Server, the JAR with the #Entity annotation will already be in your application's runtime classpath. You shouldn't have to load any JAR files in code (as you described in your comment).
During development you typically configure your App Server in your IDE and that process should include the JAR with the annotation into your compilation classpath.
You might need to manually include it in the project compile classpath / application server libraries classpath depending on how your IDE handles this. For Glassfish all the API JARs are where you were looking in the modules directory.
Even though this ties your project to finding the JAR for compilation in a specific location relative to the app server install I find it's still a better approach then copying JARs into you project for compilation. This ensures you are compiling against the correct JARs that are deployed to the app server and so long as these are JavaEE APIs your application will deploy fine into any app server.
You could also set up your project to use Maven, include the required deps for the persistence APIs and it will find the compile time deps in your maven cache.
Also you might want to check out Jar Explorer which lets you search for classes etc inside JARs, folders of JARs etc. Its pretty convenient for finding these things.
I'm having a hard time figuring out where the problem is coming from, so I'm posting this in the hopes that others might have found something similar to this elsewhere and are kind enough to share their insight.
I'm using a JBoss 5.0.1.GA application server running on top of a Sun Java 1.6.0-13 JDK. For the WAR file in the generated Web Service, I use a Axis2 1.4 WS engine whose JAR files are inserted by Eclipse Galileo into the project's WEB-INF/lib directory when creating the Webservice from the given "worker" class in the Dynamic Web Project. The relevant code snippet follows:
String sUrl = "http://example.com/datafile.xml";
String sPath = "/some/xpath/string";
InputStream input = new URL(sUrl).openStream();
InputSource source = new InputSource(input);
DocumentBuilderFactory docFact = DocumentBuilderFactory.newInstance();
docFact.setNamespaceAware(false);
DocumentBuilder parser = docFact.newDocumentBuilder();
Document doc = parser.parse(source);
XPath xpath = XPathFactory.newInstance().newXPath();
// error occurs here:
String result = (String) xpath.evaluate(path,doc,XPathConstants.STRING);
input.close();
This is the error I'm getting from the JBoss log:
java.lang.LinkageError: loader constraint violation: when resolving field "STRING" the class loader (instance of org/jboss/classloader/spi/base/BaseClassLoader) of the referring class, javax/xml/xpath/XPathConstants, and the class loader (instance of <bootloader>) for the field's resolved type, javax/xml/namespace/QName, have different Class objects for that type
I could use the XPath.evaluate(String,Document) — however there are occasions where I need to get (for example) a XPathConstants.NODESET instead, so it's a no-go. I have also tried to fumble a little by littering some jboss-web.xml files here and there in the WAR file, but with no effect.
What I'm trying to understand is:
Where could the error be coming from? The JBoss class loader? Some weird interaction between JBoss and the Sun JDK? Some weirdness introduced by Eclipse when creating the Web Service? Maybe some confusion introduced by the Axis2 libraries deployed within the WAR?
I've found instances of compiled class files in what looks like a triple-whammie:
Sun JDK (file rt.jar);
JBoss libraries ($JBOSS_HOME/lib/endorsed/stax-api.jar); and
Axis2-deployed libraries ($JBOSS_HOME/server/deploy/MyProject.ear/MyProject.war/WEB-INF/lib/axis2-saaj-api-1.4.jar and woden-impl-dom-1.0M8.jar).
How exactly am I supposed to configure JBoss to tell it which classes it's OK to load from "other" libraries from? Specifically, the jaxax.xml.namespace.QName is is causing the grief.
Thank you in advance.
JBoss will throw a LinkageError when the application's classpath contains classes which JBoss considers "protected", i.e. it does not permit the application to contain its own copies of certain key APIs.
In this case, it looks like your appcontains its own copies of the javax.xml.xpath API, and possibly some others as well, as you mentioned.
You need to remove anything from your EAR/WAR's lib directories that clashes with JBoss's own libraries (e.g. axis2-saaj-api-1.4.jar).
It seems that the problem was solved by removing the javax.xml.namespace.* package and respective classes from the deployed Axis2 JAR files. Namely, using Axis2 1.4.1 (instead of 1.4), I repackaged these JAR files:
axis2-saaj-api-1.4.1.jar, by removing javax.xml.namespace
woden-impl-dom-1.0M8.jar, by removing javax
Also, Eclipse is extremely picky at the project configuration. So far, I've found that the Project Facet for the Dynamic Web Project has to be created with a Dynamic Web Module of version 2.4 (and not 2.5 as it suggests by default), but with a Java version 6 (same as the branch of the used JDK). I don't know why this happens, I suppose the Dynamic Web Module version 2.4 tying up by default with Java 1.4 in Eclipse is where all the confusion comes from. Some googling led me to believe that package javax.xml didn't become incorporated into the JDK until Java 5 or Java 6 -- hence the possible mixup! However, I'm not knowledgeable enough to investigate if the problem comes from how Eclipse packages the archive files for deployment so this is just a suspicion I have so far.