I have a RESTful web service that I am deploying on Tomcat 6 with Java 1.6 that I'm seeing some strange behavior with. I'm deploying this particular war file with about 5 other war files. The web app in question also periodically sends a status message to remote server in xml format, all the XML binding is done with JAXB 2.1.13. The JAXB binding does not appear to be working properly after initial deployment. That is to say, if I start tomcat and wait for the status message to be sent I get the following error:
javax.xml.bind.JAXBException: class StatusMessage nor any of its super class is known to this context.
(I left out the fully qualified classname for brevity) Also any incoming requests to the RESTful service throw the same exception.
I don't see this problem if I package ALL the libraries in each war, but I'm trying not to do that because my WAR files were getting extremely bloated.The JAX libraries are packaged in this war, but things like the Spring, commons-*, hibernate, are in tomcat/lib. Does anyone have any ideas what could be causing this strange deployment order sensitivity?
Here's a little more code detail, every time the status message is triggered the following happens:
JAXBElement<StatusMessage> el = ( new ObjectFactory() ).createHeartbeat( statusMessage );
ApiUtils apiUtil = new ApiUtils();
NamespaceFilter outFilter = new NamespaceFilter("http://middleware/status", true);
String xml = apiUtil.makeXml( el, "com.package.path.status", ApiUtils.getFormatXMLSetting(), ApiUtils.getValidateXMLSetting(), outFilter);
The makeXML call looks like this:
public String makeXml(JAXBElement el, String packageName, Boolean formatXml, Boolean validateXml, NamespaceFilter outFilter) throws JAXBException,
SAXException, UnsupportedEncodingException, IOException{
// Marshal XML
JAXBContext jaxbContext = JAXBContext.newInstance( packageName );
Marshaller marshaller = jaxbContext.createMarshaller();
OutputFormat format = new OutputFormat();;
if (formatXml){
format.setIndent(true);
format.setNewlines(true);
}
//Create a filter that will remove the xmlns attribute
if(outFilter == null)
outFilter = new NamespaceFilter(null, false);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
if ( validateXml ) {
SchemaFactory schemaFactory = SchemaFactory.newInstance( "http://www.w3.org/2001/XMLSchema" );
InputStream is = this.getClass().getClassLoader().getResourceAsStream( packageName.replaceAll( "\\.", "/" ) + "/schema.xsd" );
Source source = new StreamSource( is );
Schema schema = schemaFactory.newSchema( source );
// This line enforces schema validation
marshaller.setSchema( schema );
}
XMLWriter writer = new XMLWriter(baos, format);
outFilter.setContentHandler(writer);
marshaller.marshal( el, outFilter );
return baos.toString( "UTF-8" );
}
The marshall line is where the exception is thrown. It seems like the JAXB context should be created every time this gets executed.
Update, undeploying/redeploying doesn't always fix this issue, however packaging all the libs with it does. Is there a static object somewhere I need to be aware of?
Somewhere in your code, you are creating a JAXBContext
object which lists all of the Java classes that can be marshalled and/or unmarhsalled. It's pretty common to pass a package name or an ObjectFactory to it so that it knows about a lot of classes. The error message makes it sound like those classes in the context aren't in the classpath at the time the JAXBContext
is being constructed.
Trace through the code and find where this JAXBContext
instance is constructed and check out what Java classes are being set. The fact that it works after redploying make me think that it's a classpath issue; maybe some of the classes aren't being loaded into the classpath before the rest of the code is.
Your load-on-startup
values in your web.xml
might also provide some hints.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With