Я пытаюсь десериализовать эти данные json в список объектов:
[{
"a": {
"commonField": 1,
"aField": "AAA"
}
}, {
"b": {
"commonField": 2,
"bField": "BBB"
}
}]
Каждый объект может быть одного из нескольких типов, имеющих как общие, так и уникальные поля. Информация о точной форме объекта хранится в json как ключ к объекту-оболочке.
Я создал соответствующие классы для каждой известной формы (набор уникальных полей), расширяя класс, содержащий все общие поля. Кроме того, я добавил аннотации Джексона в классы, чтобы включить полиморфную десериализацию. Упрощенные результирующие классы выглядят так:
@JsonTypeInfo(use = Id.NAME, include = As.WRAPPER_OBJECT, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(KeyBasedSubTypeA.class),
@JsonSubTypes.Type(KeyBasedSubTypeB.class)
})
public abstract class KeyBasedSuperType {
public String type;
public int commonField;
}
@JsonTypeName("a")
public class KeyBasedSubTypeA extends KeyBasedSuperType {
public String aField;
}
@JsonTypeName("b")
public class KeyBasedSubTypeB extends KeyBasedSuperType {
public String bField;
}
С этой настройкой Джексон отлично работает почти . Он может выбрать правильный подтип во время десериализации и заполнить все поля, включая общие и уникальные. Однако поле type
не обновляется Джексоном, значение ключа, использованное для выбора подтипа, нигде не сохраняется. Другими словами, данные десериализуются в следующую структуру:
[KeyBasedSubTypeA { type=null; commonField=1; aField=AAA },
KeyBasedSubTypeB { type=null; commonField=2; bField=BBB }]
Примечание type
поле, имеющее нулевое значение. Итак, вопрос - Как я могу заставить Джексона хранить ключ оболочки, используемый для выбора подтипа где-то в результирующем объекте?
Вот мой тест JUnit для процесса
public class PolymorphicTest {
private static ObjectMapper mapper;
@BeforeClass
public static void init() {
mapper = new ObjectMapper();
}
@Test
public void testKeyDenominator() throws IOException {
TypeReference<List<KeyBasedSuperType>> dataShape =
new TypeReference<List<KeyBasedSuperType>>() {};
List<KeyBasedSuperType> result = mapper.readValue(
PolymorphicTest.class.getResourceAsStream("polymorphic-key.json"), dataShape);
assertEquals(2, result.size());
assertEquals(KeyBasedSubTypeA.class, result.get(0).getClass());
assertEquals(KeyBasedSubTypeB.class, result.get(1).getClass());
assertEquals(1, result.get(0).commonField);
assertEquals(2, result.get(1).commonField);
assertEquals("a", result.get(0).type); // <---- this line fails
assertEquals("b", result.get(1).type); // <---- this line fails
assertEquals("AAA", ((KeyBasedSubTypeA) result.get(0)).aField);
assertEquals("BBB", ((KeyBasedSubTypeB) result.get(1)).bField);
}
}