2016-04-14 3 views
0

Я пытаюсь сделать простой пример десериализации json в полиморфные классы. Десериализации завершается с ошибкой:Jackson Deserialize Полиморфные классы не как массив

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

Если я пытаюсь десериализации для одного подкласса, просто с помощью JSON для этого класса, это удается, но когда я ставлю два класса вместе внутри SubClassTestObject, он терпит неудачу. Любые идеи для исправления этого? Нужно ли писать собственный десериализатор?

Вот мой JSON:

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

Вот мои классы:

@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; 
    } 
} 

А вот мой тест:

@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

Обновление вопроса ... – PunDefeated

+0

В будущем, пожалуйста, просмотрите ваш вопрос, прежде чем публиковать его. Это совсем другой сценарий. – Savior

+0

Неплохо, увидев первый ответ, я увидел, какая проблема была, поэтому я ее исправил, и это стало еще одной проблемой. – PunDefeated

ответ

1

После правки:

Это

@JsonProperty("classA") 
SubClassA a; 

не имеет никакого отношения к

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

JsonTypeInfo.As.WRAPPER_OBJECT предназначается, чтобы быть неявным. Это не то, что вы нарисовали в своих POJO. Вы не сможете сопоставить свой текущий JSON с этой стратегией. Либо сделайте то, что ниже, либо измените свой JsonTypeInfo, чтобы использовать, например, JsonTypeInfo.As.PROPERTY, затем укажите соответствующее свойство (и его соответствующее значение) в JSON.


Предварительное редактирование:

Ваш SubClassTestObject класс имеет два свойства, a и b, из-за

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

Они не присутствуют в вашем JSON. И поскольку вы сказали Джексону игнорировать неизвестные свойства, он не преминет десериализовать. Однако оба они останутся неинициализированными.

JSON вы имели в виду десериализации является

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

который имеет a и b для корневого объекта SubClassTestObject. И они используют объекты-обертки с соответствующим именем JsonTypeInfo.

+0

Хм, хорошо, Тем не менее, я должен держать json одинаковым. Я обновляю свой вопрос. – PunDefeated

+0

Является ли это достижимым без изменения JSON? Я делаю этот простой случай для практики, но в моем проекте мне придется иметь дело с JSON в том формате, в котором он сейчас находится. Похоже, что моим единственным вариантом может быть создание настраиваемого десериализатора для SubClassTestObject. – PunDefeated

+1

@PunDefeated С вашим текущим JSON, нет, я не вижу четкого пути с 'JsonTypeInfo'. – Savior

Смежные вопросы