Jackson MixIn will replace the generic JAXBElement <T> with its own T for getValue ()
I am trying to bind XML and JSON using the same JAXB annotations (using JaxbAnnotationModule ).
XML <--> JAXB <--> Jackson <--> JSON
I have to use JAXB annotation and cannot change them. My problem is that some XML files are directly converted to a generic class JAXBElement<T>
instead of a class T
. This results in JSON output:
{
"JAXBElement":{
"name":"{http://www.opengis.net/wps/1.0.0}Capabilities",
"declaredType":"net.opengis.wps.v_1_0_0.WPSCapabilitiesType",
"scope":"javax.xml.bind.JAXBElement$GlobalScope",
"value":{
"ProcessOfferings":{ },
"Languages":{ },
"ServiceIdentification":{ },
"ServiceProvider":{ },
"OperationsMetadata":{ },
"version":"1.0.0",
"updateSequence":"1",
"service":"WPS",
"lang":"en-US"
},
"nil":false,
"globalScope":true,
"typeSubstituted":false
}
}
As long as I want:
{
"Capabilities":{
"ProcessOfferings":{ },
"Languages":{ },
"ServiceIdentification":{ },
"ServiceProvider":{ },
"OperationsMetadata":{ },
"version":"1.0.0",
"updateSequence":"1",
"service":"WPS",
"lang":"en-US"
}
}
The real object of the type is T
wrapped in JAXBElement. This can happen for some root elements, as well as objects nested in the tree. If I call getValue()
, I get a real object. But I cannot do this when JAXBElement<T>
not the root element, since Jackson is the only interpreter between JAXB and JSON, and I can neither modify the JAXB-Binding nor the created objects (some other parts of the code use them, too).
So what I found that can solve the problem is MixIns :
// a mixin annotation that overrides the handling for the JAXBElement
public static interface JAXBElementMixin<T> {
@JsonValue
Object getValue();
}
ObjectMapper mapper = new ObjectMapper();
JaxbAnnotationModule module = new JaxbAnnotationModule();
mapper.registerModule(module);
mapper.addMixInAnnotations(JAXBElement.class, JAXBElementMixin.class);
This solves the extra items problem, but results in the object name JAXBElement
instead of T
(in my case Capabilities
):
{
"JAXBElement":{ // <------ Should be 'Capabilities' because of type JAXBElement<Capabilities>
"ProcessOfferings":{ },
"Languages":{ },
"ServiceIdentification":{ },
"ServiceProvider":{ },
"OperationsMetadata":{ },
"version":"1.0.0",
"updateSequence":"1",
"service":"WPS",
"lang":"en-US"
}
}
Questions:
Any idea what I can do (possibly annotate JAXBElementMixin<T>
) to get the correct type Capabilities
as the object name (there are other classes instead of Capabilities
which could also be put like T
)?
Any other idea how to skip serializing any anywhere JAXBElement<T>
in the object tree and continue serializing the object by its method getValue()
?
source to share
This is not a direct answer to your question, but perhaps a recipe for achieving your goal.
If you just want to get rid of the topmost one JAXBElement
, why not just tweak XJC to create an additional class for your element Capabilities
?
Something like:
<jaxb:bindings node="xs:element[@name='Capabilities']">
<jaxb:class name="Capabilities"/>
</jaxb:bindings>
This should generate a class Capabilities
annotated with "@XmlRootElement". This way you get rid of JAXBElement
.
source to share
Jackson does not support JAXBElement
it as it is very XML specific and difficult to work with other formats: Jackson's JAXB support focuses on using information from annotations to make things work, but the goal should not be a complete JAXB implementation.
Thus, it is best to do what @lexicore suggests and try to avoid using JAXBElement
.
source to share