Hi,
I was encountering a problem this week that I luckily managed to solve.
However, I thought it might be useful to share my knowledge about this
on the mailing list. The problem involves an AxisFault in my web
service, which was apparently caused by a NoClassDefFoundError.
For the impatient: the short solution is, to always define "private
static final long serialVersionUID" to a meaningful value.
For anyone who's interested, this is what happened:
System:
- axis2 1.4 (also used 1.3)
- Java JDK 1.6 update 6
- tomcat 6.0.16, with axis2.war running as a web application
- linux (some old fedora version with kernel 2.4.20-31.9)
I am testing axis2 for a scenario where clients pass TV metadata via
SOAP to a web server, which collates it and hopefully does interesting
things with it. On the server side I need to convert from the
databinding classes to our own custom Java classes, because further
encoding steps depend on them. The converter class ADBBean2TVAnytimeAPI
was put into a larger converter library, which had to be linked against
some of the axis2 jars and some of the code that was generated from the
WSDL. A colleague had started this project and written the WSDL and also
decided to generate and compile client-side and server-side code
independently into different directories (autogen/client and
autogen/service). Both directories would contain certain common files
that were needed on both sides (most importantly, the ADBBeans). The
client-side JAR file was used by the converter library.
I implemented the additional server-side code that would contain the
actual application logic (for which the new converter class was needed).
Then I deployed the compiled code as an axis2 service into tomcat. When
I tried to send data from the client to the server, it would fail on the
server side with the following error:
[ERROR] tva/cri/ResultType
java.lang.NoClassDefFoundError: tva/cri/ResultType
at
bbc.rd.tvadb.converter.ADBBean2TVAnytimeAPI.convert(ADBBean2TVAnytimeAPI.java:90)
at
bbc.rd.tvadb.converter.ADBBean2TVAnytimeAPI.convert(ADBBean2TVAnytimeAPI.java:55)
at bbc.rd.tvadb.server.database.TimedResult.<init>(TimedResult.java:72)
at
bbc.rd.tvadb.server.database.ServerCRIDatabase.add(ServerCRIDatabase.java:161)
at
bbc.rd.tvadb.server.database.ServerCRIDatabase.update(ServerCRIDatabase.java:134)
at
uk.co.bbc.rd.metadataInterchangeService.MetadataInterchangeServiceSkeleton.CRI_Resolutions_Operation(MetadataInterchangeServiceSkeleton.java:765)
at
uk.co.bbc.rd.metadataInterchangeService.MetadataInterchangeServiceMessageReceiverInOut.invokeBusinessLogic(MetadataInterchangeServiceMessageReceiverInOut.java:84)
at
org.apache.axis2.receivers.AbstractInOutMessageReceiver.invokeBusinessLogic(AbstractInOutMessageReceiver.java:40)
at
org.apache.axis2.receivers.AbstractMessageReceiver.receive(AbstractMessageReceiver.java:100)
at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:176)
at
org.apache.axis2.transport.http.HTTPTransportUtils.processHTTPPostRequest(HTTPTransportUtils.java:275)
at
org.apache.axis2.transport.http.AxisServlet.doPost(AxisServlet.java:131)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:710)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
at
org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:856)
at
org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:565)
at
org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1509)
at java.lang.Thread.run(Thread.java:619)
Caused by: java.lang.ClassNotFoundException: tva.cri.ResultType
at
org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1360)
at
org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1206)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)
... 26 more
I wasn't sure what to make of this first, as the server-side code that
was packaged in the axis2.war DID contain all the necessary classes.
Also, it had worked before. I was sure that it wasn't a classpath issue
(although the error sounds like it was).
The only change was, that I now used the converter mentioned above. It
became clear to me, that the classes (ResultType and others) used by the
converter (it was built using the client-side JAR file!) and those used
on the server side were incompatible. Which is strange, as they were not
only created using the very same WSDL file, the source files (they are
stored in different directories) were also identical. The only possible
difference was, that, because these automatically generated classes both
didn't define the serialVersionUID, it would be generated differently by
the compiler.
I had a look on this mailing list and found that there had been a
discussion about the serialVersionUID before:
http://marc.info/?l=axis-user&m=112180252016164&w=2
There it was suggested that setting it explicitly was not necessary, as
Java would create it automatically based on the class content. Changes
in class members would automatically cause a different version number.
Note, that I compiled everything on the same machine, some java, ant,
axi2, etc... version. The java code was identical. So in theory, the
auto-generated serialVersionUID should be the same, too. At least that's
what I thought.
To test this assumption, I added the following, respectively, to my ant
targets generate.client and generate.service in the common build.xml:
<replace dir="${build.service.dir}/src"
token="implements org.apache.axis2.databinding.ADBBean{"
value="implements org.apache.axis2.databinding.ADBBean{
${serialVersionUID}">
<include name="**/*.java"/>
</replace>
...
<replace dir="${build.client.dir}/src"
token="implements org.apache.axis2.databinding.ADBBean{"
value="implements org.apache.axis2.databinding.ADBBean{
private static final long serialVersionUID=${version.serialVersionUID}L;">
<include name="**/*.java"/>
</replace>
The serial version number was derived from our version number for the
web service itself (the date of the last modification to the WSDL file
is used). The code above effectively sets the serialVersionUID in all
classes that are derived from ADBBean. It's not nice, maybe, but after
compiling everything my web service worked again as expected.
Lessons learned:
- Java seems to be inconsistent with its automatic generation of
serialVersionUIDs. So don't rely on any assumptions!
- Java errors are sometimes a bit misleading. Why did it not say that
the class definitions were incompatible?
- maybe adding an option to wsdl2java, that creates a serialVersionUID,
should be considered?
- don't use duplicate copies of your code!
I hope that this helps anyone who has similar problems. Although I have
to admit that, looking at it now, my problem looks like a very rare and
unlikely situation...
Peter
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]