ClassCastException при десериализации с ObjectMapper на параметризованный класс, даже используя TypeReference и TypeFactory - PullRequest
0 голосов
/ 26 февраля 2019

Я получаю следующее исключение при попытке десериализации с ObjectMapper на параметризованный класс (отлично работает для непараметризированных классов):

java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class com.xyz.A (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; com.xyz.A is in unnamed module of loader 'app')

Вот исходный код:

Foo<A> request = OBJECT_MAPPER.readValue(payload, Foo.class);

Я пытался:

Foo<A> request = OBJECT_MAPPER.readValue(payload, new TypeReference<Foo<A>>() {});

А также:

JavaType myType = OBJECT_MAPPER.getTypeFactory()
    .constructParametricType(Foo.class, A.class);
Foo<A> request = OBJECT_MAPPER.readValue(payload, myType);

Но я все еще получаю то же исключение.

Может ли быть что-то особенное в моем сценарииэто не рассматривается в этих вопросах?

Одна вещь, о которой я могу думать, это то, что мой Foo на самом деле является @AutoMatter -аннотированным интерфейсом, который генерируеткласс:

@AutoMatter
public interface Foo<T> {
  Optional<T> parent;
  Optional<List<T>> children;
}

Обычно у нас нет проблем с отображением классов, сгенерированных AutoMatter.Это просто добавление параметризации <T>, которая, кажется, вызывает проблемы.

У кого-нибудь есть идея?


Изменить, чтобы ответить на вопросы @ MichalZiober:

В моем тестовом коде я на самом деле просто сериализую то, что, как я знаю, является действительным объектом, то есть , а затем десериализуем это, чтобы вернуть объект, с которого я начал:

Foo<A> myExampleObject;
ByteString.encodeUtf8(OBJECT_MAPPER.writeValueAsString(myExampleObject));

Редактировать 2

Хорошо, похоже, мы уже импортируем этот модуль:

  @VisibleForTesting
  public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper()
      .registerModule(new JodaModule())
      .registerModule(new GuavaModule())
      .registerModule(new AutoMatterModule())
      .registerModule(new Jdk8Module())
      .registerModule(new ProtobufModule())
      .setSerializationInclusion(JsonInclude.Include.NON_NULL)
      .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
      .configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false)
      .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
      .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

Ответы [ 2 ]

0 голосов
/ 26 февраля 2019

Пока мне просто пришлось отказаться от параметризации.У меня было так много классов,

Foo<A>
Foo<B>
Foo<C>

Было проще просто создать каждый явно:

@AutoMatter
public interface FooA {
  A parent;
  List<A> children;
}

@AutoMatter
public interface FooB {
  B parent;
  List<B> children;
}

@AutoMatter
public interface FooC {
  C parent;
  List<C> children;
}

(я также понял, что Optional не нужны).

Не совсем ответ, поэтому не принимаю его.

0 голосов
/ 26 февраля 2019

Когда вы используете Optional в POJO структуре, вам нужно включить Jdk8Module из jackson-modules-java8.Приведенный ниже пример показывает, что с этим зарегистрированным модулем мы можем сериализовать и десериализовать данные:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import io.norberg.automatter.AutoMatter;
import io.norberg.automatter.jackson.AutoMatterModule;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class JsonApp {

    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        mapper.enable(SerializationFeature.INDENT_OUTPUT);
        mapper.registerModule(new AutoMatterModule());
        mapper.registerModule(new Jdk8Module());

        String json = "{\"parent\":\"Aaaa\", \"children\":[\"a\"]}";
        System.out.println(mapper.readValue(json, Foo.class));


        Foo<StringWrapper> foo = new FooBuilder<StringWrapper>()
                .parent(new StringWrapperBuilder().value("PARENT").build())
                .children(Arrays.asList(new StringWrapperBuilder().value("CHILD1").build()))
                .build();
        json = mapper.writeValueAsString(foo);
        System.out.println(json);
        System.out.println(mapper.readValue(json, Foo.class));
    }
}
@AutoMatter
interface Foo<T> {
    Optional<T> parent();
    Optional<List<T>> children();
}

@AutoMatter
interface StringWrapper {
    String value();
}

Над отпечатками кода:

Foo{parent=Optional[Aaaa], children=Optional[[a]]}
{
  "parent" : {
    "value" : "PARENT"
  },
  "children" : [ {
    "value" : "CHILD1"
  } ]
}
Foo{parent=Optional[{value=PARENT}], children=Optional[[{value=CHILD1}]]}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...