Проблема сериализации Джексона с наследованием и перегрузкой метода - PullRequest
0 голосов
/ 31 января 2020

Я использую Джексона вместе с Джерси + Джетти для моего приложения RESTful. Библиотеки Джексона: jackson-annoations-2.8.0 jackson-core-2.8.9 и jackson-databind-2.8.9.

Я не могу заставить Джексона вывести значения подкласса. Он всегда выводит значения наследующего класса. Хотя я явно поставляю конкретный объект. Сценарий немного сложен, чтобы правильно его сформулировать, я надеюсь, что следующий пример объясняет его лучше.

Вот псевдокод сериализуемых классов:

  • Parent0. java:

    class Parent0 {
      protected Child0 child;
    
      public Parent0() {}
    
      public Child0 getChild() {
         return child;
      }
    
      public void setChild(Child0 child) {
         this.child = child;
      }
    }
    
  • Parent1. java:

    class Parent1 extends Parent0 {}
    
  • Child0. java:

    class Child0 {
      protected int id;
    
      public Child0() {}
    
      public void setId(int id) {
         this.id = id;
      }
    
      public int getId() {
         return this.id;
       }
    
       @Override
       public boolean equals(Object o) {
          if (this == o) return true;
          if (o == null || getClass() != o.getClass()) return false;
          Child0 child0 = (Child0) o;
          return id == child0.id;
       }
    
       @Override
       public int hashCode() {
          return Objects.hash(id);
       }
    }
    
  • Child1. java:

    class Child1 extends Child0 {
       private String childName;
    
       public Child1() {}
    
       public String getChildName() {
          return childName;
        }
    
        public void setChildName(String childName) {
           this.childName = childName;
        }    
    }
    
  • Внутри главного контроллера:

    Parent0 p0 = new Parent0();
    Child0 c0 = new Child0();
    c0.setId(0);
    p0.setChild(c0);
    
    Parent0 p1 = new Parent1();
    Child1 c1 = new Child1();
    c1.setId(1);
    c1.setChildName("C1");
    p1.setChild(c1);
    
    serializeAndPrint(p0); // #1
    serializeAndPrint(p1); // #2
    

Вывод:

    #1 Parent0.json
    {
        child: {
            id: 0
        }
    }

    #2 Parent1.json
    {
        child: {
            id: 1
        }
    }

Ожидается:

    #2 Parent1.json
    {
        child: {
            id: 1,
            childName: "C1"
        }
    }

Сериализация выполняется средой Jersey. Я отмечаю свою конечную точку с помощью @Produces(MediaType.APPLICATION_JSON), которая в основном заботится о преобразовании.

Ответы [ 2 ]

0 голосов
/ 01 февраля 2020

Не похоже, что Джексон используется JSON провайдером (как Клайв Биксби показывает в его ответ ). Те зависимости (библиотеки), которые вы говорите, у вас недостаточно. Они являются только основными зависимостями для Джексона. Jackson имеет библиотеку, поддерживающую JAX-RS, и, если вы используете Jersey, для библиотеки поддержки Jackson JAX-RS имеется оболочка Jersey.

Если вы используете Jersey 2. х, тогда вам нужна зависимость jersey-media-json-jackson. После добавления зависимости вы должны зарегистрировать JacksonFeature в конфигурации своего приложения на Джерси (либо в Интернете. xml, либо в ResourceConfig). В настоящее время, вероятно, есть какой-то другой JSON провайдер, которого вы используете, и вы его не знаете. Проверьте любую другую jersey-media-json-xxx зависимость. Если у вас есть что-то кроме Джексона, то удалите его. Если jersey-media-json-jackson является единственным провайдером, который у вас есть в classpath, вам не нужно регистрировать JacksonFeature, по умолчанию будет использоваться тот, который используется.

Если вы используете Jersey 1.x, тогда зависимость равна jersey-json. После добавления зависимости вам нужно установить для свойства com.sun.jersey.api.json.POJOMappingFeature значение true в конфигурации вашего приложения (либо init-param с веб-интерфейсом. xml, либо в вашем ResourceConfig)

Примечание: Если вы добавляете jar-файлы вручную, а не используете менеджер зависимостей, такой как Maven, тогда потребуется немного больше усилий для определения всех необходимых jar-файлов, например jersey-media-json-jackson или * 1025. * оба зависят от нескольких других банок.

0 голосов
/ 31 января 2020

Какова реализация вашего метода serializeAndPrint?
Я написал модульный тест, чтобы воспроизвести проблему:

public class JsonTest {

@Test
public void test() throws JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();

    Parent0 p0 = new Parent0();
    Child0 c0 = new Child0();
    c0.setId(0);
    p0.setChild(c0);

    Parent0 p1 = new Parent1();
    Child1 c1 = new Child1();
    c1.setId(1);
    c1.setChildName("C1");
    p1.setChild(c1);

    System.out.println(mapper.writer(new DefaultPrettyPrinter()).writeValueAsString(p0));
    System.out.println(mapper.writer(new DefaultPrettyPrinter()).writeValueAsString(p1));

}

}

Вывод соответствует вашим ожиданиям:

{
  "child" : {
  "id" : 0
  }
}
{
  "child" : {
   "id" : 1,
   "childName" : "C1"
   } 
}
...