10

The environment is WAS 6.1 on Linux, deploying a webapp that uses classes from xercesImpl.jar.

Due to company policy restrictions, the app must be deployed with settings:

Class Loader Order
    Classes loaded with parent class loader first
->  Classes loaded with application class loader first

WAR class loader policy
    Class loader for each WAR file in application
->  Single class loader for application

The WAR file contains a copy of xercesImpl.jar, the same one that was in the classpath when the app was compiled.

When launching the webapp, when Spring tries to parse its configs, it throws:

java.lang.VerifyError: class loading constraint violated 
    (class: org/apache/xerces/jaxp/DocumentBuilderImpl 
    method: parse(Lorg/xml/sax/InputSource;)Lorg/w3c/dom/Document;)

ANALYSIS SO FAR

It appears that WAS provides an implementation of org.apache.xerces.jaxp.DocumentBuilderImpl, because we can remove xercesImpl.jar from the WAR file and still get the same error (not ClassNotFoundException). Thus WAS seems to be resolving the references using its own copy that is incompatible with the references in our compiled class files. However, the only other instance of 'xercesImpl.jar' I can find (other than the copy deployed with our app) is in directory deploytool, which seems to be outside the app server.

I scanned all the jars in WAS (all 1300 of them) with

for i in `find . -name \*.jar`; do jar tvf $i|grep -qi xerces && echo $i ; done

and found that ./java/jre/lib/xml.jar contains all the classes in org.apache.xerces.*, so this is likely where the classloader is resolving the reference.

HERE'S THE WEIRD PART:

If we change to "parent class loader first" we do not see the exception. This goes counter to the expected behavior. We would expect that with "application classloader first" it would use the xercesImpl.jar that we provided, and use WAS's version only if we set "parent classloader first". This appears to be backwards from what we actually see.

THE QUESTION:

How is the classloader delegation setting interacting with the above information to result in the observed behavior?

Brett Kail
  • 33,593
  • 2
  • 85
  • 90
Jim Garrison
  • 85,615
  • 20
  • 155
  • 190
  • This sounds good. If I understand you, the problem is not DocumentBuilderImpl, but the fact that it is being resolved from the JDK while one of the classes it references is being found in the WAR. This does not explain why, when we INCLUDE xercesImpl.jar in the WAR, we still get the exact same error, quoting the same method and classnames. Are you saying that the method and classnames quoted in the message are irrelevant to the problem? – Jim Garrison May 19 '10 at 14:30

6 Answers6

14

Your WAR is also including either org.xml.sax or org.w3c.dom classes, and then you're referencing a class that is outside your application that also references these classes. This sets up a scenario where your application class loader has visibility to two instances of the same class, which is a linkage error.

For example, if your application uses javax.xml.bind.Unmarshaller.unmarshal(InputSource), then Unmarshaller would be loaded from the JDK, and the Unmarshaller class only has visibility to the JDK InputSource. When your application creates its InputSource, it will load the class from the WAR (because "app first" policy), and then your application would attempt to pass an instance of the WAR InputSource to the JDK Unmarshaller, which can only accept an instance of the JDK InputSource.

There are two solutions:

  1. Remove all API jars from your application, and use the ones from the JDK. For example, remove the jar containing org.xml.sax or org.w3c.dom.
  2. Include all libraries in your WAR that reference the classes you want to reference. For example, include a copy of the JAXB library in your WAR.

In my experience, linkage errors are quite difficult to track down because JVMs give lousy information about what causes linkages to be added. I usually enable class loader trace, reproduce the problem, and then walk backwards until I find a class loaded from outside the application that "sounds like" it might reference a class that is known to exist inside the application.

Brett Kail
  • 33,593
  • 2
  • 85
  • 90
  • This sounds good. If I understand you, the problem is not DocumentBuilderImpl, but the fact that it is being resolved from the JDK while one of the classes it references is being found in the WAR. This does not explain why, when we INCLUDE xercesImpl.jar in the WAR, we still get the exact same error, quoting the same method and classnames. Are you saying that the method and classnames quoted in the message are irrelevant to the problem? – Jim Garrison May 19 '10 at 14:42
  • Thanks. With a little research I was able to resolve the problem by removing several unnecessary jars from our app that were left over from before the JDK included org.xml.sax and org.w3c.dom. I also found a conflicting DataSource definition as well. – Jim Garrison May 19 '10 at 16:37
  • Yes, DocumentBuilderImpl is unrelated to the problem. The parse method just happens to reference types that have linkage problems. Like I said, the JVM gives lousy information; I should have been bolder and said "and sometimes misleading" :-). – Brett Kail May 19 '10 at 19:03
  • Fix for my case: add provides to maven dependency jaxb-api. – childno͡.de Jun 13 '12 at 19:10
0

Our issue was deploying on WAS 8.5.

In our web application we have a web service client generated by cxf. No issues.

When we added in tika-parser for mime type detection, then we got this issue.

We excluded three dependencies:

<dependency>
            <groupId>org.apache.tika</groupId>
            <artifactId>tika-parsers</artifactId>
            <version>${apache.tika.version}</version>
            <exclusions>
                <exclusion>
                    <artifactId>geronimo-stax-api_1.0_spec</artifactId>
                    <groupId>org.apache.geronimo.specs</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>xercesImpl</artifactId>
                    <groupId>xerces</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>xmlbeans</artifactId>
                    <groupId>org.apache.xmlbeans</groupId>
                </exclusion>
            </exclusions>
        </dependency>

Once they were excluded, our application started successfully.

shane lee
  • 1,290
  • 15
  • 17
0

May be it's too late but, we solved this problem, removing this line in server.xml:

jaxb-2.1

0

Here is what is going on:

The same libraries are defined in both the pom.xml file for the applications AND the server.xml file on WAS. So, after WAS loads the class from the war file created from the pom.xml file for the application, it then attempts to load the same class from the library in shared libraries on WAS that is specified in the server.xml file.

The server.xml file will defined for the application in a folder defined by a path like this if your application was named corrservo65-01:

/usr/WebSphere905/AppServer/profiles/node01/config/cells/dwauslwasapp06Cell01/nodes/dwauslwasapp06Node01/servers/corrservo65-01

You can see which libraries are also being loaded from shared libraries by searching for the classloaders element in the server.xml file. Inside of the classloaders element there are libraries elements. Each one defines a library that is ALSO being loaded from the shared libraries on WAS as well as the library defined in the pom.xml file of the application.

For example, wsdl4j-1.6.2 is defined as a dependency in the pom.xml file:

 <dependency>
    <groupId>wsdl4j</groupId>
    <artifactId>wsdl4j</artifactId>
    <version>1.6.2</version>
</dependency>

Here is the same library being loaded from the shared libraries by WAS:

<classloaders xmi:id="Classloader_1629835928681" mode="PARENT_LAST">
   <libraries xmi:id="LibraryRef_1629835942246" libraryName="wsdl4j-1.6.2"/>
</classloaders>

When you set an application to parent_last in WAS then you have to also remove the references to libraries found in shared libraries from it as well. You then need to include those libraries in the pom.xml file of the application. This will cause ONLY the libraries to be loaded based on the pom.xml file.

However, there is another possible source and that is the WAS JDK. If the library is in the WAS JDK, then it will always load from there. In those cases, you must either remove the dependency from the pom.xml file or set the scope to "provided". Setting the scope to "provided" will use the dependency when the application is compiled locally, but not when it is deployed to WAS.

Lastly, there is a class loader for WAS and one for the JDK. If both contain the same class, say javax.server.ServletContext, then they will still the exception - even if the class does not exist in the ear file.

In our particular case, we had to set up WAS like this: Class loaders to use parent_last and Managed Modules to use parent_first.

Danny Remington - OMS
  • 5,244
  • 4
  • 32
  • 21
-1

Disable the Bytecode Verification

java.lang.VerifyError - Runtime Unchecked Exception once class file is loaded in Websphere JVM, then byte code varification is the next process.during byte code verification if our class in violating the JVM constraints ,then this error appears.

disable bytecode verification. Go to

admin console->server1->java and process management->process definition->JVM arguments`

And in JVM arguments pass the following string

 -Xverify:none 

and in workspace open the ApplicationDeploymentDescriptor xml file, go to deployment tab, select PARENT_LAST for war, as well as for first option. this stops the xml validations errors.

Community
  • 1
  • 1
-2

If we change to "parent class loader first" we do not see the exception. This goes counter to the expected behavior.

Yes, that's correct, it's the only way you can see such behaviour. I can suggest you yo take a look at the "Do you really get class loaders?" talk, as there is no single or short answer to your question.

http://www.slideshare.net/guestd56374/do-you-really-get-class-loaders http://www.parleys.com/#sl=2&st=5&id=1585

Jevgeni Kabanov
  • 2,632
  • 24
  • 23
  • This is really more of a sales-pitch for your product, no? – Jim Garrison May 19 '10 at 15:25
  • Yes, the answer is correct, "parent last" is the only way to see this problem. Unfortunately, the link is not helpful and has several inaccuraces. Slide 8: JavaEE specs mandate neither parent last nor separate CLs. Slide 11: ClassNoDefFoundException is not a real exception type; the method is "getURLs". I stopped looking after that. Fix and I'll remove downvote. – Brett Kail May 19 '10 at 19:09
  • @Jim Huh? There are two slides about that in the intro. The talk is specifically about solving similar problems. @bkail Not that I care about how you vote, but see Servlet spec SRV.9.7.2. Thanks for the typos, I usually do a lot of demos, so slides are not terribly important. – Jevgeni Kabanov Jun 24 '10 at 21:09