/ / Jackson MixIn per sostituire la classe generica JAXBElement <T> con la sua T dietro getValue () - java, xml, json, jaxb, jackson

Jackson MixIn per sostituire la classe generica JAXBElement <T> con la sua T dietro getValue () - java, xml, json, jaxb, jackson

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 № 1

Questa 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.