Sto cercando di associare XML e JSON usando le stesse annotazioni JAXB (usando il JaxbAnnotationModule).
XML <--> JAXB <--> Jackson <--> JSON
Devo usare l'annotazione JAXB e non posso modificarli. Il mio problema è che alcuni XML vengono convertiti nella classe generica JAXBElement<T>
invece di una classe T
direttamente. Ciò porta all'output JSON:
{
"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
}
}
Mentre io invece voglio:
{
"Capabilities":{
"ProcessOfferings":{ },
"Languages":{ },
"ServiceIdentification":{ },
"ServiceProvider":{ },
"OperationsMetadata":{ },
"version":"1.0.0",
"updateSequence":"1",
"service":"WPS",
"lang":"en-US"
}
}
Il vero oggetto del tipo T
è avvolto da un JAXBElement. Ciò può accadere per alcuni elementi di root e nidificato ovunque nella struttura ad albero degli oggetti. Se chiamo getValue()
su quello otterrò il vero oggetto, ma non posso farlo quando il JAXBElement<T>
non è l'elemento radice dal momento che Jackson è l'unico interprete tra JAXB e JSON e non posso né modificare il JAXB-Binding né gli oggetti creati (anche altre parti del codice li usano).
Quindi quello che ho trovato che cosa potrebbe risolvere il problema sono 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);
Ciò risolve il problema degli elementi aggiuntivi ma causa il nome dell'oggetto JAXBElement
invece di T
(nel mio caso 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"
}
}
Le domande:
Qualche idea su cosa posso fare (forse annotare JAXBElementMixin<T>
) per ottenere il tipo corretto Capabilities
come nome oggetto (ci sono altre classi invece di Capabilities
che può essere posizionato come T
, pure)?
Qualche altra idea su come saltare la serializzazione di qualsiasi JAXBElement<T>
in qualsiasi punto dell'albero degli oggetti e continuare con la serializzazione dell'oggetto dietro di esso getValue()
metodo?
risposte:
0 per risposta № 1Questa non è direttamente una risposta alla tua domanda, ma forse una ricetta per raggiungere il tuo obiettivo.
Se vuoi solo liberarti del più alto JAXBElement
, perché non personalizzi semplicemente XJC per generare una classe aggiuntiva per il tuo Capabilities
elemento?
Qualcosa di simile a:
<jaxb:bindings node="xs:element[@name="Capabilities"]">
<jaxb:class name="Capabilities"/>
</jaxb:bindings>
Questo dovrebbe generare una classe Capabilities
annotato con "@XmlRootElement". Così ti libererai di JAXBElement
.
0 per risposta № 2
Jackson non supporta JAXBElement
, poiché è molto specifico per XML e lo èdifficile lavorare con altri formati: il supporto di Jackson JAXB è focalizzato sull'uso delle informazioni dalle annotazioni per far funzionare le cose, ma l'obiettivo non è quello di essere un'implementazione completa di JAXB.
Pertanto, la soluzione migliore è fare ciò che @lexicore suggerisce e cercare di evitare JAXBElement
.