2016-04-14 15 views
0

Ich versuche, ein einfaches Beispiel der Deserialisierung JSON in polymorphe Klassen zu machen. Die Deserialisierung schlägt mit dem Fehler:Jackson Deserialize polymorphe Klassen nicht als Array

org.codehaus.jackson.map.JsonMappingException: Could not resolve type id 'aField' into a subtype of [simple type, class ...SubClassA] 

Wenn ich die Deserialisierung für eine einzelne Unterklasse versuchen, nur für diese Klasse der JSON verwendet, ist es erfolgreich ist, aber wenn ich die zwei Klassen zusammen in der SubClassTestObject, es funktioniert nicht. Irgendwelche Ideen, um das zu beheben? Muss ich einen benutzerdefinierten Deserializer schreiben?

Hier meine JSON ist:

{ 
    "classA":{ 
     "aField":"A", 
     "baseField":"baseA" 
    }, 
    "classB":{ 
     "baseField":"baseB", 
     "bField":"B" 
    } 
} 

Hier meine Klassen sind:

@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.WRAPPER_OBJECT) 
@JsonSubTypes({ 
    @JsonSubTypes.Type(value = SubClassA.class, name = "classA"), 
    @JsonSubTypes.Type(value = SubClassB.class, name = "classB") 
}) 

@JsonIgnoreProperties(ignoreUnknown = true) 
public abstract class AbstractSimpleClass { 
    String baseField; 

    public String getBaseField() { 
     return baseField; 
    } 

    public void setBaseField(String baseField) { 
     this.baseField = baseField; 
    } 
} 

public class SubClassA extends AbstractSimpleClass { 
    String aField; 

    public String getaField() { 
     return aField; 
    } 

    public void setaField(String aField) { 
     this.aField = aField; 
    } 
} 

public class SubClassB extends AbstractSimpleClass { 
    String bField; 

    public String getbField() { 
     return bField; 
    } 

    public void setbField(String bField) { 
     this.bField = bField; 
    } 

} 
@JsonIgnoreProperties(ignoreUnknown = true) 
public class SubClassTestObject { 
    @JsonProperty("classA") 
    SubClassA a; 

    @JsonProperty("classB") 
    SubClassB b; 

    public SubClassA getA() { 
     return a; 
    } 
    public void setA(SubClassA a) { 
     this.a = a; 
    } 
    public SubClassB getB() { 
     return b; 
    } 
    public void setB(SubClassB b) { 
     this.b = b; 
    } 
} 

Und hier ist mein Test:

@Test 
public void testBoth() throws IOException, URISyntaxException { 
    ClassLoader classLoader = getClass().getClassLoader(); 
    json = new String(Files.readAllBytes(Paths.get(classLoader.getResource("test/so-example.json").toURI()))); 
    ObjectMapper mapper = new ObjectMapper(); 
    mapper.registerSubtypes(SubClassA.class, SubClassB.class); 

    SubClassTestObject testObj = mapper.readValue(json, SubClassTestObject.class); //Fails here 
    SubClassA a = testObj.getA(); 
    SubClassB b = testObj.getB(); 

    assertTrue(a.getBaseField().equals("baseA")); 
    assertTrue(b.getBaseField().equals("baseB")); 
    assertTrue(a.getaField().equals("A")); 
    assertTrue(b.getbField().equals("B")); 

} 
+0

Aktualisiere Frage ... – PunDefeated

+0

Bitte überprüfen Sie in der Zukunft Ihre Frage, bevor Sie sie posten. Dies ist ein ganz anderes Szenario. – Savior

+0

Meine schlechte, nachdem ich die erste Antwort gesehen habe, sah ich, was eines der Probleme war, also reparierte ich es, und es verwandelte sich in ein anderes Problem. – PunDefeated

Antwort

1

nach dem edit:

Diese

@JsonProperty("classA") 
SubClassA a; 

ist völlig unabhängig von

@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.WRAPPER_OBJECT) 

Die JsonTypeInfo.As.WRAPPER_OBJECT soll implizit sein. Es ist nicht etwas, was Sie in Ihren POJOs abbilden. Sie können Ihren aktuellen JSON nicht mit dieser Strategie verknüpfen. Entweder tun Sie, was unten steht, oder ändern Sie Ihre JsonTypeInfo, um beispielsweise eine JsonTypeInfo.As.PROPERTY zu verwenden, und geben Sie dann die entsprechende @type-Eigenschaft (und den entsprechenden Wert) in JSON an.


Pre-edit:

Ihre SubClassTestObject Klasse hat zwei Eigenschaften, a und b wegen

public SubClassA getA() { 
    return a; 
} 
public SubClassB getB() { 
    return b; 
} 

Diese in Ihrem JSON nicht vorhanden sind. Und da Sie Jackson gesagt haben, unbekannte Eigenschaften zu ignorieren, versäumt es es nicht, zu deserialisieren. Beide werden jedoch nicht initialisiert.

Die JSON Sie deserialisieren gemeint ist

{ 
    "a": { 
     "classA": { 
      "aField": "A", 
      "baseField": "baseA" 
     } 
    }, 
    "b": { 
     "classB": { 
      "baseField": "baseB", 
      "bField": "B" 
     } 
    } 
} 

die a und b für Ihre Wurzel SubClassTestObject Objekt hat. Und diese verwenden Wrapper-Objekte mit dem entsprechenden Namen JsonTypeInfo.

+0

Hmm okay, Ich muss den JSON aber gleich behalten. Ich aktualisiere meine Frage. – PunDefeated

+0

Ist dies ohne Änderung der JSON erreichbar? Ich mache diesen einfachen Fall für die Praxis, aber in meinem Projekt muss ich mit JSON in dem Format umgehen, in dem es sich gerade befindet. Es sieht dann so aus, als wäre meine einzige Option, einen benutzerdefinierten Deserializer für das SubClassTestObject zu schreiben. – PunDefeated

+1

@PunDefeated Mit Ihrem aktuellen JSON, nein, ich sehe keinen klaren Weg mit 'JsonTypeInfo'. – Savior

Verwandte Themen