Gson ExclusionStrategy 를 활용한 annotation기반 json 출력 제외

2015/12/18 10:53

서비 JAVA ,

Json Object Mapper로 널리 쓰이고 있는 Gson,
객체를 Json으로 변환하는데 클래스의 특정 필드를 출력하지 않고 싶을 때 사용 가능한 방법.
아쉽게 Gson은 필드를 json으로 출력하라는 @Expose 어노테이션만 존재할 뿐 제외하라는 @Exclude 같은 어노테이션은 아직까진 없다.

그러니까 현재까지는 어떤 필드 출력을 제외하고 싶으면 출력할 모든 필드에 @Expose 어노테이션을 적용 하고 Gson create 시에 다음처럼 @Expose 어노테이션이 없는 필드를 제외하라.. 고 설정할 필요가 있다.
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();


그런데 대부분의 필드를 출력하고 일부만 제외하고 싶을 경우가 더 많을것 같은데.. 그 몇개 제외하자고 모든 필드에 @Expose 붙이는것도 귀찮은 일.
간단하게 @NonExpose 라든가 @Exlude 같은 어노테이션을 제공해주면 편할텐데... 우리가 생각치 못한 어떤 이유가 있겠지...

다행히 Gson 생성시 제외 조건을 설정할 수 있는 .setExclusionStrategies() 메소드를 제공한다. 그러면 다음처럼 @Exclude 어노테이션 기반 출력 제외 처리가 가능하다.

우선, 우리가 사용할 어노테이션을 정의하고...
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.FIELD)
 public @interface Exclude {
 }
 


feildSkip 확인 코드에서 위에서 작성한 어노테이션이 있으면 제외처리되도록 Gson의 ExclusionStrategy 구현체를 작성 
 public class AnnotationBasedExclusionStrategy implements ExclusionStrategy {
     @Override
     public boolean shouldSkipField(FieldAttributes f) {
         return f.getAnnotation(Exclude.class) != null;
     }
     @Override
     public boolean shouldSkipClass(Class<?> clazz) {
         return false;
     }
 }
 


마지막으로 Gson 객체 생성 시 위 AnnotationExclusionStrategy 를 적용.
new GsonBuilder().setExclusionStrategies(new AnnotationBasedExclusionStrategy()).create();

이제 제외하고 싶은 필드에 @Exclude 적용하면 끝~.
2015/12/18 10:53 2015/12/18 10:53
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다
  1. 저는 GSon 을 사용안하고 Jackson을 주로 사용하는 편입니다.
    exclude,include 관련 옵션은 Jackson이 더 편한것 같네요.

    하지만 아무튼 가급적 exclude를 지정하기 보다는 expose(include)를 지정하는 것이 올바를 것 같습니다. 그래서 GSon도 exclude관련 기본 옵션을 두지 않은 것은 아닌가 싶습니다.

    white list 방식(expose할 필드를 명시적으로 지정하는 방식)의 처리를 하는게 맞다고 보는 것이지요.

    black list 방식(exclude를 설정하는 방식)으로 하게되면 신규 필드가 추가되었는데 그게 보안상 노출되면 안되는 필드라고 했을 때 해당 필드를 추가한 개발자가 명시적으로 exclusion을 하지 않으면 의도치 않게 그것을 외부에 노출시켜버리게 됩니다.

    더불어 다른 문제도 있는데 객체가 양방향 관계를 맺은 상태일 때입니다. 양방향 관계를 맺은 필드를 추가한 상황에서 exclusion을 잊어버리고 표시하지 않으면 실행시점이 될 때까지 오류 상황 파악을 못하고 stackoverflow를 만나게 됩니다.

    내부 API용이라면 그런대로 괜찮겠지만 특히나 아무나 데이터를 볼 수 있는 web browser와 통신하는 경우에는 white list 방식을 사용하는게 조금 귀찮더라도 보안성 더 좋을 것 같습니다.

  2. Blog Icon
    서비

    권남님 의견 감사합니다.
    말씀 주신 의도가 맞는것 같습니다.GSon 개발팀은 보안과 편의 중 보안 쪽 손을 들었을듯 합니다.... 댓글 달면서 갑자기 궁금해졌는데 @Expose 와 ExclusionStrategy를 동시에 적용하면 어느 쪽이 적용될까요? 구글 개발팀의 원래 의도대로라면 비노출 되어야 할것 같은데... 한번 확인해봐야 겠네요.

java json 라이브러리 별 parser 속도 비교.

우선, 테스트 진행한 json 라이브러리 후보군은
  • JSON.simple ( Yidong Fang )
  • GSON ( Google )
  • Jackson ( FasterXML )
  • JSONP  ( Oracle )
과 같음. 상기 라이브러리를 이용한 비교적 큰 사이즈의 json 문서 파싱 속도 벤치마킹 결과를 java 어플리케이션 성능평가/모니터링 도구를 개발하는 Takipi에서 공개.

벤치마크는 190MB 짜리( https://github.com/zeMirco/sf-city-lots-json )와 1KB 짜리( http://www.json-generator.com/ ) JSON 파일을 파싱하는 속도를 측정. AWS c3.large 인스턴스에서 큰 파일은 라이브러리당 10회 씩, 작은 파일은 10,000회 씩 수행한 결과를 정리했다고 함.

큰 파일 파싱
대용량 파일 처리 결과

이미지 출처 http://blog.takipi.com

큰 파일 파싱에는 Jackson과 Json.simple 이 빠르고 Jsonp와 gson이 상대적으로 느린걸로...

가장 빠른 Jakson 성능을 기준으로 나타낸 상대 수치.
Jackson 기준 상대 속도

이미지 출처 http://blog.takipi.com


작은 파일 파싱
작은 파일 파싱

이미지 출처 http://blog.takipi.com

큰 파일 때와는 다른 양상을 보임. 작은 파일일때는 정도의 차이는 있지만 모든 라이브러리들이 측정 때마다 들쑥날쑥한 결과를 보임.  GSON 이 1순위를 가장많이 나타내고 있고 Json.simple 은 1순위가 한번도 없음.

가장 빠른 GSON 성능을 기준으로 나타낸 상대 수치.
Gson 기준 상대 비교

이미지 출처 http://blog.takipi.com


결론.
  • 당신의 개발 환경이 빅데이터처리와 같이 주로 큰사이즈의 JSON을 처리해야한다면 Jackson 을 써라. 대용량 환경에서 GSON은 좋지않은 선택임.
  • 마이크로 서비스와 분산아키텍처 설정등과 같이 작은 용량의 많은 json 파일을 처리하는 환경이라면 GSON을 써라.
  • 대용량과 소용량 모두를 다양하게 처리하는 환경이라면 양쪽에서 2순위 정도를 기록한 JSON.simple 이 좋을수도 있겠다.
2015/10/20 10:19 2015/10/20 10:19
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다