Полиморфная десериализация в Джексоне без аннотаций - PullRequest
1 голос
/ 19 марта 2019

У меня есть класс CloudEvent<T>, который использует полиморфную десериализацию с использованием Джексона (2.9.0 - последняя версия), например:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class CloudEvent<T> {

    @NonNull
    private String eventType;

    @JsonTypeInfo(
            use = JsonTypeInfo.Id.NAME,
            include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
            property = "eventType",
            defaultImpl = Void.class)
    @JsonSubTypes({
            @JsonSubTypes.Type(value = MyEvent1.class, name = "event-1"),
            @JsonSubTypes.Type(value = MyEvent2.class, name = "event-2")
    })
    private T data;
}

А затем десериализовать с помощью:

String cloudEventJson1 = "{\"eventType\":\"event-1\",\"data\":{\"id\":\"123\",\"details\":\"detail1\"}}";

CloudEvent deserializedEvent1 = objectMapper.readValue(cloudEventJson1, CloudEvent.class);   //without subtypes

Все это прекрасно работает. Но из-за некоторых ограничений я не могу использовать аннотации к классу CloudEvent (обеспечивается внешней зависимостью).

Итак, я настроил ObjectMapper следующим образом:

    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.registerSubtypes(new NamedType(MyEvent1.class, "event-1"));
    objectMapper.registerSubtypes(new NamedType(MyEvent2.class, "event-2"));

    TypeResolverBuilder  typeResolverBuilder = new ObjectMapper.DefaultTypeResolverBuilder(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE)
      .init(JsonTypeInfo.Id.NAME, null)   //CLASS works
      .inclusion(JsonTypeInfo.As.EXTERNAL_PROPERTY)
      .typeProperty("eventType")
      .typeIdVisibility(true)
//    .defaultImpl(Void.class);
    objectMapper.setDefaultTyping(typeResolverBuilder);

Но десериализация тем же способом, что и выше, не работает. Он читает eventType, но не может соответствовать зарегистрированному подтипу. Я не могу использовать дженерики или TypeReferance при десериализации, потому что мне нужно использовать spring-integration для чтения событий, которые принимает только основной класс; сопоставление с образцом выполняется вручную после десериализации.

Исключение:

com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve type id 'event-1' as a subtype of [simple type, class java.lang.Object]: known type ids = [] (for POJO property 'data')
 at [Source: (String)"{"eventType":"event-1","data":{"id":"123","details":"detail1"}}"; line: 1, column: 271]

Также это настройка ObjectMapper для всех входных классов. Можно ли подключить эти typeResolverBuilder и subtypes к CloudEvent.class (как это делает способ аннотации).

1 Ответ

2 голосов
/ 19 марта 2019

Вы все еще можете полагаться на аннотации, даже если вы не можете изменить свой класс.Джексон поддерживает функцию под названием mix-ins : вы можете рассматривать ее как своего рода аспектно-ориентированный способ добавления большего количества аннотаций во время выполнения для дополнения статически определенных.

Сначала определите интерфейсследующим образом:

public interface CloudEventMixIn<T> {

     @JsonTypeInfo(
            use = JsonTypeInfo.Id.NAME,
            include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
            property = "eventType",
            defaultImpl = Void.class)
    @JsonSubTypes({
            @JsonSubTypes.Type(value = MyEvent1.class, name = "event-1"),
            @JsonSubTypes.Type(value = MyEvent2.class, name = "event-2")
    })
    public T getData();
}

Затем настройте ObjectMapper для использования определенного интерфейса в качестве дополнения для фактического класса / интерфейса:

ObjectMapper mapper = new ObjectMapper();
mapper.addMixIn(CloudEvent.class, CloudEventMixIn.class);

Из addMixIn(Class<?> target, Class<?> mixinSource) документация к методу:

Метод, используемый для добавления дополнительных комментариев, которые используются для расширения указанного класса или интерфейса.Все аннотации mixinSource используются для переопределения аннотаций target (или его супертипов).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...