반응형
그니_
삽질탐방기
그니_
  • 분류 전체보기 (24)
    • 개발 (15)
    • ETC (1)
    • 트러블슈팅 & 삽질기록 (7)
    • 성능개선 (1)

인기 글

최근 글

최근 댓글

태그

  • chatgpt 히스토리 삭제
  • chatgpt 확장 추천
  • chatgpt 채팅 삭제
  • java
  • chatgpt 기록 삭제
  • 마이크로소프트 ai tour
  • 네트워크
  • spring docker
  • GPT 플러그인
  • timeunit
  • easyrandom
  • chatgpt 정리
  • chatgpt 확장 프로그램
  • Spring
  • db
  • spring docker compose
  • index
  • spring log
  • springboot
  • Database
hELLO · Designed By 정상우.
그니_

삽질탐방기

개발

[Jackson] 추상클래스, 인터페이스를 파라미터로?

2022. 6. 27. 04:18
반응형

Rest API를 설계 및 구현을 하다보면 같은 맥락의 요청이지만 필드의 값이나 또는 필드의 존재 유무로 처리하려다 보면 클래스의 멤버변수가 많아져 지저분해 지는 경우가 많다.

뭐 여러가지 방법이 있을것이다.

  1. loop를 돌며 처리(map)
  2. object mapper로 deserialize 등등..
  3. 클래스에 모든 필드 다 때려넣기..(비대해짐. 최악인듯?)

뭔가 하나의 api와 하나의 클래스로 분기를 할수 있다면 좋겠다란 생각에 좀 찾아 봤더니 Jackson에서 지원 하는 몇가지 있었다.

 

@Target(value={ANNOTATION_TYPE,TYPE,FIELD,METHOD,PARAMETER})
@Retention(value=RUNTIME)
public @interface JsonTypeInfo
Annotation used for configuring details of if and how type information is used with JSON serialization and deserialization, to preserve information about actual class of Object instances. This is necessarily for polymorphic types, and may also be needed to link abstract declared types and matching concrete implementation.
Some examples of typical annotations:

  // Include Java class name ("com.myempl.ImplClass") as JSON property "class"
  @JsonTypeInfo(use=Id.CLASS, include=As.PROPERTY, property="class")
  
  // Include logical type name (defined in impl classes) as wrapper; 2 annotations
  @JsonTypeInfo(use=Id.NAME, include=As.WRAPPER_OBJECT)
  @JsonSubTypes({com.myemp.Impl1.class, com.myempl.Impl2.class})
Alternatively you can also define fully customized type handling by using @JsonTypeResolver annotation (from databind package).
This annotation can be used both for types (classes) and properties. If both exist, annotation on property has precedence, as it is considered more specific.

When used for properties (fields, methods), this annotation applies to values: so when applied to structure types (like Collection, Map, arrays), will apply to contained values, not the container; for non-structured types there is no difference. This is identical to how JAXB handles type information annotations; and is chosen since it is the dominant use case. There is no per-property way to force type information to be included for type of container (structured type); for container types one has to use annotation for type declaration.

Note on visibility of type identifier: by default, deserialization (use during reading of JSON) of type identifier is completely handled by Jackson, and is not passed to deserializers. However, if so desired, it is possible to define property visible = true in which case property will be passed as-is to deserializers (and set via setter or field) on deserialization.

On serialization side, Jackson will generate type id by itself, except if there is a property with name that matches property(), in which case value of that property is used instead.

대강 해석 하자면 추상클래스나 인터페이스에 대해 구현체나 상속받은 클래스를 등록해두면  다형성을 위해 직렬화 및 역직렬화를 해준다라고 설명이 되있다.

이말인 즉슨 파라미터로 인스턴스화가 불가능한 인터페이스나 추상클래스를 파라미터로 받아 맵핑이 가능해 진다는 얘기! 

 

@JsonSubTypes

@Target(value={ANNOTATION_TYPE,TYPE,FIELD,METHOD,PARAMETER})
@Retention(value=RUNTIME)
public @interface JsonSubTypes
Annotation used with JsonTypeInfo to indicate sub types of serializable polymorphic types, and to associate logical names used within JSON content (which is more portable than using physical Java class names).

구현체를 등록하는 어노테이션이다.

@Target(value={ANNOTATION_TYPE,TYPE})
 @Retention(value=RUNTIME)
public @interface JsonTypeName
Annotation used for binding logical name that the annotated class has. Used with JsonTypeInfo (and specifically its JsonTypeInfo.use() property) to establish relationship between type names and types.
Author:
tatu

타입의 이름을 지정하는 어노테이션

 

 

이제 사용을 한번 해보자!

@JsonTypeInfo(
        use= JsonTypeInfo.Id.NAME,
        include = JsonTypeInfo.As.EXISTING_PROPERTY,
        property = "eventType"
)
@JsonSubTypes({
        @JsonSubTypes.Type(value = Event.TourEvent.class),
        @JsonSubTypes.Type(value = Event.specialEvent.class)
})
@Data
public abstract class Event {
    private EventType eventType;

    @Data
    @EqualsAndHashCode(callSuper = true)
    @JsonTypeName("TOUR")
    public static class TourEvent extends Event{
        private String transportation;
        private String attractions;
        private int price;
    }

    @EqualsAndHashCode(callSuper = true)
    @Data
    @JsonTypeName("SPECIAL")
    public static class specialEvent extends Event{
        private int specialPrice;
    }


    public enum EventType {
        TOUR,
        SPECIAL
    }
}

대충 이벤트인데 투어 이벤트냐 스페셜 이벤트냐에 따라 필드가 좀 다르다.  그냥 결과를 보여주기 위한 클래스다.

@PostMapping("/events")
public void getEvents(@RequestBody Event event) {
    log.info(event.toString());
    if(event instanceof Event.TourEvent) {
        Event.TourEvent tourEvent = (Event.TourEvent) event;
        log.info("투어이벤트:: "+ tourEvent);
    }else if(event instanceof Event.specialEvent) {
        Event.specialEvent specialEvent = (Event.specialEvent) event;
        log.info("스페셜 이벤트~~~:: "+ specialEvent);
    }
}

 

 

controller에 api를 추가해 보자,  junit으로 해도 된다 편한대로~! 파라미터는 위에서 정의한 Event 추상클래스를 받는다.

 

결과값은 어떻게 될지 한번 봐보자!

{
    "transportation" : "버스",
    "attractions" : "용인",
    "price" : "2000",
    "eventType" : "TOUR"
}
2022-06-27 04:08:02.362  INFO 69642 --- [nio-8080-exec-1] c.jpa.study.controller.MemberController  : Event.TourEvent(transportation=버스, attractions=용인, price=2000)
2022-06-27 04:08:02.363  INFO 69642 --- [nio-8080-exec-1] c.jpa.study.controller.MemberController  : 투어이벤트:: Event.TourEvent(transportation=버스, attractions=용인, price=2000)
{
    "specialPrice" : "555555",
    "eventType" : "SPECIAL"
}

2022-06-27 04:09:37.998  INFO 69642 --- [nio-8080-exec-5] c.jpa.study.controller.MemberController  : Event.specialEvent(specialPrice=555555)
2022-06-27 04:09:37.999  INFO 69642 --- [nio-8080-exec-5] c.jpa.study.controller.MemberController  : 스페셜 이벤트:: Event.specialEvent(specialPrice=555555)

각기 다른 처리로직이라면 여러개의 구현체를 둬 로직 분리까지 할수 있는 이점을 취할수 있다는 장점..?

 

*주의할점

JsonTypeName을 잘 정의해 둬야된다.

  ->안그러면 제대로 매핑이 안되 exception을 발생시키기 때문이다.

 

반응형

'개발' 카테고리의 다른 글

SSH into docker container  (0) 2022.07.11
VLAN  (0) 2022.07.07
WebRTC  (0) 2022.07.06
참고 사이트 정리  (0) 2022.07.06
DB Index란?  (0) 2022.06.29
    '개발' 카테고리의 다른 글
    • VLAN
    • WebRTC
    • 참고 사이트 정리
    • DB Index란?
    그니_
    그니_
    머리속에서만 존재하는 내용을 글로 정리

    티스토리툴바