Подтвердить что ты не робот

Как делегировать десериализацию по умолчанию в пользовательский десериализатор в Джексоне?

Предположим, что я пишу специальную сериализацию для некоторого класса, но хотел бы обработать одно из его полей с помощью методов по умолчанию.

Как это сделать?

При сериализации мы JsonGenerator#writeObjectField().

Но что такое соответствующий метод десериализации?

Обратите внимание на приведенный ниже код:

import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;

import java.io.IOException;
import java.util.Objects;

public class TryDelegate {

   public static class MyOuterClassSerializer extends JsonSerializer<MyOuterClass> {

      @Override
      public void serialize(MyOuterClass value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
         gen.writeStartObject();

         gen.writeObjectField("inner", value.getInner());

         gen.writeEndObject();
      }
   }

   public static class MyOuterClassDeserializer extends JsonDeserializer<MyOuterClass> {
      @Override
      public MyOuterClass deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {


         MyOuterClass ans = new MyOuterClass();

         JsonToken token;

         token = p.getCurrentToken();
         if( token != JsonToken.START_OBJECT ) {
            throw new JsonParseException("Start object expected", p.getCurrentLocation());
         }

         if( !"inner".equals(p.nextFieldName() ) ) {
            throw new JsonParseException("'inner; field expected", p.getCurrentLocation());
         }

         MyInnerClass inner = null;// how to desrialize inner from here with default processing???
         ans.setInner(inner);

         token = p.nextToken();
         if( token != JsonToken.END_OBJECT ) {
            throw new JsonParseException("End object expected", p.getCurrentLocation());
         }

         return ans;

      }
   }

   public static class MyInnerClass {
      private int value;

      public int getValue() {
         return value;
      }

      public void setValue(int value) {
         this.value = value;
      }

      @Override
      public String toString() {
         return "{\"value\":" + value + "}";
      }
   }

   @JsonDeserialize(using = MyOuterClassDeserializer.class)
   @JsonSerialize(using = MyOuterClassSerializer.class)
   public static class MyOuterClass {

      private MyInnerClass inner;

      public MyInnerClass getInner() {
         return inner;
      }

      public void setInner(MyInnerClass inner) {
         this.inner = inner;
      }

      @Override
      public String toString() {
         return "{\"inner\":" + Objects.toString(inner) + "}";
      }
   }

   public static void main(String[] args) throws IOException {

      ObjectMapper mapper = new ObjectMapper();
      String string;

      MyInnerClass inner = new MyInnerClass();
      inner.setValue(12);

      MyOuterClass outer = new MyOuterClass();
      outer.setInner(inner);

      string = mapper.writeValueAsString(outer);
      System.out.println(string);

      MyOuterClass outer2 = mapper.readValue(string, MyOuterClass.class);
      System.out.println(outer2); // inner was not deserialized


   }
}

Как реализовать MyOuterDeserializer?

4b9b3361

Ответ 1

DeserializationContext предлагает эти инструменты.

После проверки имени поля для "inner" перейдите к следующему токену, началу объекта JSON и используйте DeserializationContext для десериализации объекта JSON в объект MyInnerClass.

if (!"inner".equals(p.nextFieldName())) {
    throw new JsonParseException("'inner; field expected", p.getCurrentLocation());
}
p.nextToken(); // consumes the field name token

MyInnerClass inner = ctxt.readValue(p, MyInnerClass.class);

Состояние javadoc

Метод удобства, который может использоваться композитным или контейнером десериализаторы, для чтения одноразовых значений, содержащихся (для последовательностей, это более эффективна для фактического получения десериализатора один раз для целого сбор).


Осторожно, используя DeserializationContext. Не пытайтесь рекурсивно десериализовать типы, для которых вы зарегистрировали пользовательские десериализаторы.