interface field를 역직렬화하기

hyyyynjn·2023년 5월 18일
0

개발 기록

목록 보기
2/3
post-thumbnail

deserialize interface to enum

public interface Animal {}
public enum Dog implement Animal { DOG_1, DOG_2 }
public enum Cat implement Animal { CAT_1, CAT_2 }
@NoArgsConstructor
public class AnimalRequest {
	private Animal animal;
}

Enum 클래스 Dog, Cat는 Animal이라는 인터페이스의 구현체이다.
Animal(interface)을 Dog 또는 Cat(Enum)으로 Deserialize 하기 위해서 Animal에 대한 JsonDeserializer를 커스텀해야 한다.

JsonDeserializer 커스터마이징

JsonDeserializer.java

public abstract class JsonDeserializer<T>
    implements NullValueProvider // since 2.9
{
    /*
    /**********************************************************
    /* Main deserialization methods
    /**********************************************************
     */
    
    /**
     * Method that can be called to ask implementation to deserialize
     * JSON content into the value type this serializer handles.
     * Returned instance is to be constructed by method itself.
     *<p>
     * Pre-condition for this method is that the parser points to the
     * first event that is part of value to deserializer (and which 
     * is never JSON 'null' literal, more on this below): for simple
     * types it may be the only value; and for structured types the
     * Object start marker or a FIELD_NAME.
     * </p>
     * <p>
     * The two possible input conditions for structured types result
     * from polymorphism via fields. In the ordinary case, Jackson
     * calls this method when it has encountered an OBJECT_START,
     * and the method implementation must advance to the next token to
     * see the first field name. If the application configures
     * polymorphism via a field, then the object looks like the following.
     *  <pre>
     *      {
     *          "@class": "class name",
     *          ...
     *      }
     *  </pre>
     *  Jackson consumes the two tokens (the <tt>@class</tt> field name
     *  and its value) in order to learn the class and select the deserializer.
     *  Thus, the stream is pointing to the FIELD_NAME for the first field
     *  after the @class. Thus, if you want your method to work correctly
     *  both with and without polymorphism, you must begin your method with:
     *  <pre>
     *       if (p.currentToken() == JsonToken.START_OBJECT) {
     *         p.nextToken();
     *       }
     *  </pre>
     * This results in the stream pointing to the field name, so that
     * the two conditions align.
     * <p>
     * Post-condition is that the parser will point to the last
     * event that is part of deserialized value (or in case deserialization
     * fails, event that was not recognized or usable, which may be
     * the same event as the one it pointed to upon call).
     *<p>
     * Note that this method is never called for JSON null literal,
     * and thus deserializers need (and should) not check for it.
     *
     * @param p Parsed used for reading JSON content
     * @param ctxt Context that can be used to access information about
     *   this deserialization activity.
     *
     * @return Deserialized value
     */
    public abstract T deserialize(JsonParser p, DeserializationContext ctxt)
        throws IOException, JacksonException;

StdDeserializer.java

/**
 * Base class for common deserializers. Contains shared
 * base functionality for dealing with primitive values, such
 * as (re)parsing from String.
 */
public abstract class StdDeserializer<T>
    extends JsonDeserializer<T>
    implements java.io.Serializable,
        ValueInstantiator.Gettable // since 2.12
{
    private static final long serialVersionUID = 1L;

how?

JsonDeserializer의 deserialize 메소드에서 요청 필드를 Animal 타입으로 변환해야 한다.

public class AnimalDeserializer extends StdDeserializer<Animal> {
  protected AnimalDeserializer() {
    super(Animal.class);
  }

  @Override
  public Animal deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
    final String nameOfEnum = p.getText();
    return Animal.valueOf(nameOfEnum);
  }
}

StdDeserializer의 구현 클래스를 private Animal animal; 필드의 deserializer로써 등록해주자.

@NoArgsConstructor
public class AnimalRequest {
	@JsonDeserialize(using = AnimalDeserializer.class)
	private Animal animal;
}

0개의 댓글