2017-06-05 5 views
0

Ich versuche, ein Objekt mit JSON ObjectMapper zu deserialisieren. Ich sehe den unten Fehlermeldung, wennJackson Deserialize Abstrakte Klassen

com.fasterxml.jackson.databind.JsonMappingException deserialisieren versuchen: Kann Instanz com.phoenix.types.OrderItem nicht konstruieren: abstrakte Typen müssen entweder auf konkrete Typen abgebildet werden , haben benutzerdefinierte Deserializer, oder enthalten zusätzliche Informationen über [Quelle: [email protected]; Zeile: 112, Spalte: 7] (über Referenzkette: com.phoenix.types.GenerateRequest ["order"] -> com.phoenix.types.Order ["orderItems"] -> Object [] [0]) bei com.fasterxml.jackson.databind.JsonMappingException.from (JsonMappingException.java:261) bei com.fasterxml.jackson.databind.DeserializationContext.instantiationException (DeserializationContext.java:1456) bei com.fasterxml.jackson .databind.DeserializationContext.handleMissingInstantiator (DeserializationContext.java:1012) bei com.fasterxml.jackson.databind.deser.AbstractDeserializer.deserialize (AbstractDeserializer.java:149) bei com.fasterxml.jackson.databind.deser.s td.ObjectArrayDeserializer.deserialize (ObjectArrayDeserializer.java:196) bei com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize (ObjectArrayDeserializer.java:20) bei com.fasterxml.jackson.databind.deser. SettableBeanProperty.deserialize (SettableBeanProperty.java:499) bei com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet (MethodProperty.java:101) bei com.fasterxml.jackson.databind.deser.BeanDeserializer. vanillaDeserialize (BeanDeserializer.java:276) um com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize (BeanDeserializer.java:140) um com.fasterxml.j ackson.databind.deser.SettableBeanProperty.deserialize (SettableBeanProperty.java:499) bei com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet (MethodProperty.java:101) bei com.fasterxml.jackson. databind.deser.BeanDeserializer.vanillaDeserialize (BeanDeserializer.java:276) bei com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize (BeanDeserializer.java:140) bei com.fasterxml.jackson.databind.ObjectMapper. _readMapAndClose (ObjectMapper.java:3789) bei com.fasterxml.jackson.databind.ObjectMapper.readValue (ObjectMapper.java:2833)

Ich bin auf diese post zur Durchführung der polymorphen Deserialisierung gestoßen. Dies bietet grundsätzlich die Lösung zur Behebung des oben aufgeführten Fehlers. Die Klassen (In diesem Fall OrderItem usw.), die ich für die Deserialisierung verwende, sind Teil einer JAR-Datei. Es gibt jedoch eine Möglichkeit, JsonDeserialize als Teil von objectmapper zu definieren, wenn ich versuche, die Deserialisierung durchzuführen, anstatt Annotation zur Klasse selbst hinzuzufügen, da ich keinen Zugriff darauf habe.

Antwort

1

Ja, Sie können Ihre eigenen Custom Deserializer für die abstrakte Klasse schreiben. Dieser Deserializer muss bestimmen, welche konkrete Klasse der JSON darstellt, und eine Instanz davon instanziieren.

Es ist wahrscheinlich ein idiomatischer Weg, dies zu tun, aber hier ist ein schnelles und unsauberes Beispiel:

public class Test { 
    public static void main(String... args) throws IOException { 
     final ObjectMapper mapper = new ObjectMapper(); 
     final SimpleModule module = new SimpleModule(); 
     module.addDeserializer(Animal.class, new AnimalDeserializer()); 
     mapper.registerModule(module); 

     final String json = "{\"aGoodBoy\": true}"; 
     final Animal animal = mapper.readValue(json, Animal.class); 
     System.out.println(animal.talk()); 
    } 

    public static abstract class Animal { 
     public abstract String talk(); 
    } 

    public static class Fish extends Animal { 
     @Override 
     public String talk() { 
      return "blub blub I'm a dumb fish"; 
     } 
    } 

    public static class Dog extends Animal { 
     public boolean aGoodBoy; 

     @Override 
     public String talk() { 
      return "I am a " + (aGoodBoy ? "good" : "bad") + " dog"; 
     } 
    } 

    public static class AnimalDeserializer extends StdDeserializer<Animal> { 
     protected AnimalDeserializer() { 
      this(null); 
     } 

     protected AnimalDeserializer(final Class<?> vc) { 
      super(vc); 
     } 

     @Override 
     public Animal deserialize(final JsonParser parser, final DeserializationContext context) 
     throws IOException, JsonProcessingException { 
      final JsonNode node = parser.getCodec().readTree(parser); 
      final ObjectMapper mapper = (ObjectMapper)parser.getCodec(); 
      if (node.has("aGoodBoy")) { 
       return mapper.treeToValue(node, Dog.class); 
      } else { 
       return mapper.treeToValue(node, Fish.class); 
      } 
     } 
    } 
} 
+0

Dank Andrew. Gibt es ein Beispiel, um mithilfe von Custom Deserializer konkrete Klassen für abstrakte Klassen anzugeben? –

+0

Mit einem Codebeispiel aktualisiert. Ich bin mir sicher, dass es einen besseren Weg gibt, den zugrunde liegenden 'ObjectMapper' zu erhalten, als den ObjectCodec zu werfen, aber ich habe Probleme, es von meinem Kopf zu finden. Sie können die konkreten Instanzen auch einfach manuell erstellen, aber ich möchte diese Arbeit vermeiden. –

+0

Danke Andrew! Ich werde das versuchen und updaten. –

Verwandte Themen