Reusing unmarshaller results in an unexpected result · Issue #450 · javaee/jaxb-v2 (original) (raw)
If you use an unmarshaller once for decoding an XML document of which root
element is not a registered root element in the JAXB context but xsi:type
attribute signifies the content's type, next time you use it again for decoding
another XML document of which root element is a registered one, you will see
that the result is not an instance of the registered class but a wrapper
JAXBElement object. Of course, if you use a 'fresh' unmarshaller for the latter
document, you will get an instance of the registered class as expected.
The cause of this seems to reside in UnmarshallingContext$DefaultRootLoader
class. Here I quote the part.
private static final class DefaultRootLoader extends Loader implements
Receiver {
public void childElement(UnmarshallingContext.State state, TagName ea)
throws SAXException {
Loader loader = jaxbContext.selectRootLoader(state,ea);
if(loader!=null)
{ state.loader = loader; // <----- (1) state.receiver = this; return; }
// the registry doesn't know about this element.
// try its xsi:type
...
state.prev.backup = new JAXBElement(...); // <----- (2)
...
}
...
public void receive(State state, Object o) {
if(state.backup!=null)
{ // <---- (3) ((JAXBElement)state.backup).setValue(o); o = state.backup; }
state.getContext().result = o;
}
}
First time its childElemnt() method is called, it cannot find the root element's
definition in the context, so the control reaches to the line marked (2). Next
time the method is called again while it is decoding another XML document, it
finds registered class information in the context and the control reaches the
line marked (1). Note that this 'state' object is reused from the previous run
and its 'backup' field still holds an instance of JAXBElement.
And the control finally reaches to the line marked (3), since 'state.backup'
field is set, the result becomes a wrapping JAXBElement, not a registered
class's instance. If the first run had not occurred, 'state.backup' field would
have stayed null and the results would have been, as expected, a registered
class's instance.
I believe 'state.backup' field should be cleared somewhere between two runs,
however, I am not clear about where the appropriate location is.
Environment
Operating System: All
Platform: All
Affected Versions
[2.0.5]