Jackson: Deserialisieren eines Map<String, Object> richtigen Typ für jeden Wert
Habe ich eine Klasse, die wie folgt aussieht
public class MyClass {
private String val1;
private String val2;
private Map<String,Object> context;
//Appropriate accessors removed for brevity.
...
}
Ich bin auf der Suche, um in der Lage sein, um die round-trip-mit Jackson von Objekt zu JSON und zurück. Ich kann serialisieren Sie das Objekt über feine und erhalten die folgende Ausgabe:
{
"val1": "foo",
"val2": "bar",
"context": {
"key1": "enumValue1",
"key2": "stringValue1",
"key3": 3.0
}
}
Die Frage, die ich gelaufen bin, ist, dass, da die Werte in die serialisierte map nicht haben jede Art von Informationen, Sie sind nicht korrekt deserialisiert. Zum Beispiel, in dem obigen Beispiel, enumValue1 sollte deserialisiert werden als enum-Wert, sondern deserialisiert als String. Ich habe gesehen, Beispiele für stützen, welche Art auf eine Vielzahl von Dingen, aber in meinem Szenario, ich will nicht wissen, was die Typen sind (Sie werden Nutzer-generierte Objekte, die ich nicht im Voraus wissen) also ich muss in der Lage sein serialisiert werden die Typ-Informationen mit den Schlüssel-Wert-paar. Wie kann ich erreichen das mit Jackson?
Für das Protokoll, ich bin mit Jackson version 2.4.2. Der code, den ich verwende zum testen die hin-und Rückfahrt wie folgt:
@Test
@SuppressWarnings("unchecked")
public void testJsonSerialization() throws Exception {
//Get test object to serialize
T serializationValue = getSerializationValue();
//Serialize test object
String json = mapper.writeValueAsString(serializationValue);
//Test that object was serialized as expected
assertJson(json);
//Deserialize to complete round trip
T roundTrip = (T) mapper.readValue(json, serializationValue.getClass());
//Validate that the deserialized object matches the original one
assertObject(roundTrip);
}
Da dies eine Spring-basierte Projekt, der mapper wird wie folgt erstellt:
@Configuration
public static class SerializationConfiguration {
@Bean
public ObjectMapper mapper() {
Map<Class<?>, Class<?>> mixins = new HashMap<Class<?>, Class<?>>();
//Add unrelated MixIns
..
return new Jackson2ObjectMapperBuilder()
.featuresToDisable(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS)
.dateFormat(new ISO8601DateFormatWithMilliSeconds())
.mixIns(mixins)
.build();
}
}
- Nun, natürlich, dass ein
Object
müssen nicht jede Art von Informationen; es gibt keine Weise um, die anderen als 1. erstellen Sie ein POJO für Ihrecontext
Instanz-variable (bevorzugt), oder 2. nicht mit einemMap<String, Object>
aber einObjectNode
. In jedem Fall ist das ein primäres Beispiel für ein code smell. - Die
context
variable verwendet wird in einer Weise ähnlich zu derHttpSession
(Es stellt Spring Batch istExecutionContext
um genau zu sein) also ich würde es nicht als ein Geruch...das ist es, was eineMap
ist für. Was ich nicht verstehe, ist, warum Jackson können nicht hinzufügen ein Feld, das zeigt den Typ. Wenn Sie den Wert, er hat die Klasse, und kann daher bestimmen Sie den Typ. Was bin ich? - Und wo würde es in diesem Feld hinzufügen? Sie nur sagen, dass es zu Deserialisieren, die zu einer
Object
. Der Vorteil mit einemObjectNode
zumindest, ist, dass Sie die JSON direkt; Sie können daher in der Abfrage den Typ des Feldes, mit allen, dieJsonNode
hat, zu helfen.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich denke, die einfachste Möglichkeit, das zu erreichen, was Sie wollen, ist die Verwendung:
Diese fügen geben Sie Informationen in das serialisierte json.
Hier sind Sie ein Beispiel, dass Sie die Notwendigkeit der Anpassung an den Frühling:
Wird das Objekt serialisiert werden, in etwas ähnlich:
Und deserialisiert werden wieder richtig, und die Behauptung übergeben werden.
Bytheway es gibt mehrere Möglichkeiten, dies zu tun, schauen Sie bitte in https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization für mehr info.
Ich hoffe, es wird helfen.