1

I have a piece of JAXB unmarshalling code that looks like this:

Foo foo = null;
try {
    logger.debug(methodNamePrefix + "xmlString is \n" + xmlString);
    JAXBContext jaxbContext = JAXBContext
                                .newInstance(Foo.class);
    Unmarshaller u = jaxbContext.createUnmarshaller();
    u.setEventHandler(new DefaultValidationEventHandler()); 
    StreamSource streamsource = new StreamSource(new StringReader(xmlString));
    foo = (Foo) u.unmarshal(streamsource);
    sanityCheckDbpAfterUnmarshalling(xmlString, foo);

}catch(Exception e){
    throw new AnalysisNotPossibleException();
}
if (foo==null){
    throw new AnalysisNotPossibleException();
}

This code has been working for months, until recently, on one machine, it started failing. When it failed, it spit out a seemingly legit complaint -- except that the same piece of code, with same input xmlString, when run on another machine, or even on the very same machine but in unit test, would not complain:

javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"entry"). Expected elements are (none)
        at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:642)
        at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:254)
        at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:249)
        at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportUnexpectedChildElement(Loader.java:116)
        at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.childElement(Loader.java:101)
        at com.sun.xml.bind.v2.runtime.unmarshaller.StructureLoader.childElement(StructureLoader.java:243)
        at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:478)
        at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:459)
        at com.sun.xml.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:148)

I am quite sure that this is due to some local environment of that machine, but I could not figure out what that is. I have tried cleaning all my binary in my Eclipse.

I know this needs debugging, and I do not expect a full answer. But I would appreciate any ideas for some more things that I can check. Thanks!

Updated

The class Foo looks like this:

@XmlRootElement
public class Foo  implements Serializable{
    private static final long serialVersionUID = -4550266352252980254L;

    @XmlElement
    private HashMap<String, SomeProperty> mapAllPortletProperty =
            new HashMap<String, SomeProperty>();
    ...

And the XML string looks like this

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<foo>
    <mapAllPortletProperty>
        <entry>
            <key>Portlet 6262</key>
            <value>
                <apIdStrAtBirth>4536</apIdStrAtBirth>               
                ...

2nd Update

Thanks for all the help so far. That has helped me to think about these two aspects:

  1. Resource leak? StreamSource and StringReader are holding onto some resources after they are done with unmarshalling?
  2. Thread safety? c.f. This SO post about "JAXB creating context and marshallers cost"

For #1, I have checked that there does not appear to have resource leak. I also have a stress-test program and it does a lot of unmarshalling. I did not observe the program has ever growing memory footprint.

For #2, I have rewritten my code so that for each class that needs to be unmarshalling, my code instantiate an JAXBContext only once.

Unfortunately, with the above new insight, I still have not been able to find the root cause of the problem. Any more insight are welcome!

Community
  • 1
  • 1
leeyuiwah
  • 6,562
  • 8
  • 41
  • 71
  • The class Foo and the .xml might help – k5_ Dec 23 '16 at 22:43
  • Thanks! Added the info – leeyuiwah Dec 23 '16 at 22:54
  • Are all the machines running the *same* version of Java? – Andreas Dec 23 '16 at 23:09
  • No. But on the failing machine, the same piece of code was tested with two drivers. One is the actual integrated environment (which failed), and the other is an unit test (which did not fail). But you have a good point. I can see if I can sync the JDK on both machines. – leeyuiwah Dec 23 '16 at 23:11
  • Could it be due to resource leak? The integrate environment did a lot of unmarshalling and the unit test did it once only. Do I need to close the StreamSource? However, StreamSource does not have a close() method. Should I close the StringReader instead? Will that release the resource (if any) held by StreamSource? – leeyuiwah Dec 23 '16 at 23:46
  • Thanks for your help so far. I have also considered thread safety and added some update to the question. Any more ideas are welcome. – leeyuiwah Dec 24 '16 at 14:48
  • Thanks for all your help. I've found the answer, and have just posted it. – leeyuiwah Dec 25 '16 at 17:52

1 Answers1

1

After much debugging, I found the cause of the problem.

In one of my folders there were two JAXB related JAR files sitting there:

$ find . -name "jaxb*" -exec ls -l {} \;
-rwx------+ 1 leecy None 89967 Mar 19  2014 ./war/WEB-INF/lib/jaxb-api-2.1.jar
-rwx------+ 1 leecy None 876610 Mar 19  2014 ./war/WEB-INF/lib/jaxb-impl-2.1.13.jar

I think there is already an reference implementation of JAXB that comes with the JVM (I am using Oracle/Sun's JDK 1.7.0_51) and we do NOT need these extra JAR files, do we? And their presence actually could confuse my program and cause a different JAXBContextImpl to be loaded. For some reason such an implementation could not unmarshall the XML file.

Inspired by this blog post, I have my program print out the exact class name of the implementation after instantiation, and I got these results:

If I removed the extra JAR files, my program printed this line out, and the unmarshalling would work:

getJcMap(): Just instantiated an JAXBContext: class com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl

If I left them in, my program print this instead, and the unmarshalling would fail:

getJcMap(): Just instantiated an JAXBContext: class com.sun.xml.bind.v2.runtime.JAXBContextImpl

That explained why the problem happened only with that particular machine with that particular project folder, but not with other environment.

So I removed those extra JAR files and the problem was solved!

Thanks everyone! Happy Holidays!

leeyuiwah
  • 6,562
  • 8
  • 41
  • 71