IT_Programming/Dev Libs & Framework

[펌] An Introduction to AutoValue Gson

JJun ™ 2017. 1. 9. 14:02



 출처

 : https://medium.com/@joongwon/autovalue-라이브러리를-소개합니다-80014ca0c3ff



An Introduction to AutoValue Gson




개발자라면 코드의 양을 줄이기 위해 노력해야 한다. 그러한 요구 사항에 맞춰서 언어도 발전하고 다양한 라이브러리도 개발되고 있다. 오늘은 Java 개발에 유용하게 쓰일 수 있는 AutoValue라는 라이브러리를 소개하고자 한다.

AutoValue는 코드 자동 생성 라이브러리다. Java 개발에서 불필요한 코드가 반복적으로 노가다를 유발하는 곳이 어디일까?

바로 POJO 클래스다.

불필요한 코드 작성을 없앨 수 있다면 상당히 편리하고 개발 시간도 단축되며 가독성도 높아질 것이다.

모바일 환경은 아무래도 성능에도 신경을 쓸 수밖에 없는데 AutoValue는 Reflection을 이용한 런타임 방식이 아닌 apt를 이용하여 컴파일 타임에 코드를 생성해주기 때문에 성능상에 불이익은 없다.

구현체별 GitHub 주소(다양한 구현체가 존재한다.)


일반적으로 앱 개발시 서버와의 데이터 연동에서 Json 포맷을 이용하기 때문에 Gson을 이용한 AutoValue 작성법을 알아보자.

우선 gradle 세팅부터 해야겠지?



apt를 사용하기 위한 top level의 build.gradle 설정




gson, auto-value, auto-value-gson 설정

AutoValue를 사용하기 위한 세팅은 끝났다. AutoValue를 이용한 코드를 보면 약간 생소할 수가 있다. 아래는 AutoValue 어노테이션을 이용한 기본적인 방법이다.

 

  @AutoValue

  public abstract class Product {

         @SerializedName("id")
         public abstract long getId();
  
         @SerializedName("name")
         public abstract String getName();
  
         @SerializedName("price")
         public abstract float getPrice();
  
         public static TypeAdapter<Product> typeAdapter(Gson gson) {
                  return new AutoValue_Product.GsonTypeAdapter(gson);  
         }
  }

 


코드를 보면 알겠지만 변수가 없다. id, name, price의 변수가 있어야 할 것 같은데 해당 변수는 자동 생성 되는 AutoValue_Product 클래스에 생성된다. 마찬가지로 abstract 키워드가 의문일 텐데 자동 생성되는 클래스는 위의 Product 클래스를 상속받고 abstract 메서드를 구현하게 된다.

예제 코드에서는 @SerializedName 어노테이션을 사용하였고 get을 prefix로 메서드를 정의하였지만 어노테이션을 제거하고 id(), name(), price() 이런 식으로 메서드 이름을 데이터 이름과 맞춰주면 @SerializedName 어노테이션이 필요 없지만 간혹 서버에서 내려주는 이름이 카멜 표기법을 준수하지 않는 경우도 있고 네이밍을 변경 시 크게 의미가 바뀌지 않는 이상 @SerializedName 어노테이션만 변경하면 되기 때문에 필자는 위와 같이 주로 쓰는 편이다.

이제 typeAdapter라는 static 메서드의 용도가 무엇일지 궁금할 것이다. @GsonTypeAdapterFactory와 관련이 있는데 위에 작성된 메서드 시그너처를 반드시 지켜서 선언해야 한다.

Class 타입에 따라 Gson 매핑을 하는 AutoValueGson_AutoValueGsonFactory라는 클래스가 자동 생성되는데 Class 타입에 따라 분기되고 해당 클래스의 typeAdapter 메서드를 호출하게 된다.

 

 @GsonTypeAdapterFactory

public abstract class AutoValueGsonFactory implements TypeAdapterFactory {

@Override public static TypeAdapterFactory create() { return new AutoValueGson_AutoValueGsonFactory(); } }

 


@GsonTypeAdapterFactory 어노테이션을 이용하여 TypeAdapterFactory 인터페이스를 구현한다. auto-value-gson 0.3.0 버전까지는 저렇게 AutoValueGson_AutoValueGsonFactory 클래스가 자동 생성되지 않고 개발자가 직접 해당 로직을 구현해야 한다. 0.3.0 이상 버전을 사용하면 위와 같이 작성하기만 해도 된다.

지금까지 AutoValue에 대해서 간단히 살펴보았다. 그런데 의문이 생길 것이다. get메서드는 제공하는데 set은 없네?

그렇다. AutoValue는 기본적으로 Immutable을 기본 전제로 한다. 그렇다면 해당 클래스의 속성 등을 변경하고자 한다면 어떻게 해야 할까? Immutable을 기본 전제로 하기 때문에 새로운 객체로 생성해야 된다. 아래처럼 static factory 메서드를 제공할 수도 있다.

 

 @AutoValue

  public abstract class Product {

@SerializedName("id") public abstract long getId();

  
         @SerializedName("name")
         public abstract String getName();
  
         @SerializedName("price")
         public abstract float getPrice();
  
         public static TypeAdapter<Product> typeAdapter(Gson gson) {
                  return new AutoValue_Product.GsonTypeAdapter(gson);  
         }
  
         public static Product create(long id, String name, float price) {

return new AutoValue_Product(id, name, price);

         }
  }

 


하지만 Effective Java에서도 설명하고 있지만 위와 같은 create메서드는 텔레스코핑패턴이라는 안티 패턴이다. 위의 Product 클래스는 3개의 속성뿐이 없지만 만약 속성이 많은 클래스거나 속성이 추가된다면 메서드 호출자는 파라미터의 순서 및 데이터 타입에 혼돈이 생길 것이다.

텔레스코핑 패턴을 보완하기 위해 빌더 패턴이 존재한다. 아마 AutoValue Gson 개발자도 그러한 요구 사항을 받았을 것이고 Builder 패턴을 적용하기 위한 어노테이션을 제공한다. @AutoValue.Builder 어노테이션이다.

 

 @AutoValue

  abstract class ProductBuilder {
         @SerializedName("id")
         abstract long getId();

         @SerializedName("name")
         abstract String getName();

         @SerializedName("price")
         abstract float getPrice();

         static TypeAdapter<ProductBuilder> typeAdapter(Gson gson) {
                  return new AutoValue_ProductBuilder.GsonTypeAdapter(gson);
         }

         static Builder builder() {
                  return new AutoValue_ProductBuilder.Builder();
         }

         @AutoValue.Builder
         static abstract class Builder {
                  abstract Builder setId(long id);
                  abstract Builder setName(String name);
                  abstract Builder setPrice(float price);
                  abstract ProductBuilder build();
         }
  }

 


주의해야 될 점이 있는데 Builder 클래스에 모든 속성에 대한 메서드가 정의되지 않으면 AutoValue_ProductBuilder.Builder 클래스가 생성되지 않는다.

지금까지 AutoValue와 Gson을 이용한 개발 방법을 소개했다. 가장 중요한 게 남아 있는데 간단하고 가장 중요한 사실이다.

AutoValue_ 로 시작하는 자동 생성 클래스를 생성하기 위해선 코드를 다시 컴파일 해야 한다. Android Studio의 rebuild project를 통해 AutoValue 코드가 생성되도록 하자. 그렇지 않으면 AutoValue_ 로 시작하는 클래스는 생성되지 않을 것이다.

예제 코드의 풀소스는 https://github.com/joongwon/AutoValueExample 에서 확인하면 된다.


AutoValueExample-master.zip



     Sample project using twitter api to search tweets (MVVM, Rxjava 2, Retrofit 2, Databinding)

Tweetz-master.zip




Tweetz-master.zip
0.18MB
AutoValueExample-master.zip
0.09MB