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 Ihre context Instanz-variable (bevorzugt), oder 2. nicht mit einem Map<String, Object> aber ein ObjectNode. In jedem Fall ist das ein primäres Beispiel für ein code smell.
  • Die context variable verwendet wird in einer Weise ähnlich zu der HttpSession (Es stellt Spring Batch ist ExecutionContext um genau zu sein) also ich würde es nicht als ein Geruch...das ist es, was eine Map 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 einem ObjectNode zumindest, ist, dass Sie die JSON direkt; Sie können daher in der Abfrage den Typ des Feldes, mit allen, die JsonNode hat, zu helfen.
Schreibe einen Kommentar