[Android] @AutoValue 에 대하여.

An Introduction to AutoValue라는 글을 보면서 @AutoValue의 사용에 대해 한글로 정리된 글이 별로 없어서 아래와 같이 정리해본다. (An Introduction to AutoValue에서 예시들을 가져왔음을 밝힌다)

우선 들어가기 전에 Java에서 유명한 책인 Effective Java의 저자 Joshua Bloch가 AutoValue와 관련해서 아래와 같은 말을 했다고 한다.
"AutoValue is a great tool for eliminating the drudgery of writing mundane value classes in Java. It encapsulates much of the advice in Effective Java Chapter 2, and frees you to concentrate on the more interesting aspects of your program. The resulting program is likely to be shorter, clearer, and freer of bugs. Two thumbs up."
-- Joshua Bloch, author, Effective Java

위의 말을 발로 번역을 해보자면

"AutoValue는 평범한 Value Class 작성의 힘든 작업들을 줄여주기 위한 훌륭한 툴이다.
 Effective Java 2장의 많은 Advice들을 캡슐화해서, 당신의 프로그램에서 흥미로운 부분에 좀 더 집중할 수 있게 해준다. 그 결과로 프로그램은 좀 더 짧아지고, 깨끗하지며, 버그로부터 자유로워 질수 있다. 쌍따봉!!"
-- Joshua Bloch, author, Effective Java


은근 책을 홍보하는 내용이 담겨있기는 하지만, AutoValue는 우리 코드 작성을 줄여주는데 도움을 주는 도구이다. 라는 정도만 이해하고 진행하도록 하자.

1. 기본적인 용도


Android를 개발하다보면(아니 어떤 프로그래밍이든), 다양한 Data Class 들을 만들게 된다. 우선 아래는 Money라는 간단한 Class를 정의했고, 이 Class를 통해 AutoValue에 대해 알아볼 것이다.
위와 같은 형식의 코드를 많이 작성하게 되는데, 여기에 추가적으로 아래코드와 같이 equals(), hashcode(), toString() 등과 같은 method들도 override하는 일이 종종 있다.
이런작업은 솔직히 여간 귀찮은 일이 아닐 수 없다.
이런 Model Class가 한두개도 아니고, 매번 클래스를 만들때마다 이런 작업을 해야한다면, 생각보다 시간도 낭비되는 점이 있다.


이러한 부분에서 @AutoValue가 큰 도움을 줄 수 있다.


어떻게 도움을 줄수 있는지 살펴보기 전에 기본 Setting!
AutoValue를 사용하기 위해서는 gradle파일서 auto-value를 추가해야 한다.
우선 Project Gradle파일에 아래와 같이 추가를 한다.

그리고 App Gradle파일에 아래와 같이 추가를 하면 된다.

※ An Introduction to AutoValue에서는  apt 'com.google.auto.value:auto-value:1.2-rc1' apt를 사용하는 것을 가이드 했다. (APT는 Annotation Processing의 줄임말 이라고 한다.) (관심이 있는 사람은 이 링크를 참고! : http://pluu.github.io/blog/android/2015/12/26/annotation-processing/)
하지만 이런저런 방법으로 apt를 사용하기위해 아둥바둥 해봤지만, 정상적으로 사용할 수 없었다. 그래서 이 페이지에서 방법을 확인 후 적용할 수 있었다.
참고로 apt 대신 compile을 사용해도 적용은 되는데, AutoValue는 Build때만 적용되는 것이므로 compile을 사용하게 되면 최종 APK에 AutoValue 관련한 내용들이 포함될 가능성이 있다.(이것은 추후 확인후 공유!)

그리고 위에서 봤던 Money class를 아래와 같이 선언해주기만 하면 모든것이 끝난다.
위의 코드를 보면 알 수 있지만,
기존의 Money class를 abstract로 만들고 맨 앞에 @AutoValue Annotation을 붙였을 뿐이다.
(물론 currency()와 amount()도 abstract로 만들어 줘야 한다)



Abstract Class이니 이 Class의 객체를 만들고자 할때에 대한 자연스러운 고민이 생기는데, 그것은 아래와 같이 작성해주면 된다.

위의 코드에서 눈치챘겠지만, Money Class를 abstract로 바꾼 후 @AutoValue를 붙여준다면, AutoValue_Money라는 새로운 Class가 생긴다. 그렇다고 코드에서 직접 AutoValue_Money를 쓰는 것은 좀... 그러니까.. 위와 같이 팩토리패턴스럽게 create()를 통해 new AutoValue_Money()를 리턴하도록 한다. (이렇게 사용하지 않는다고, AutoValue를 사용할 수 없는 것은 아니지만, 이점은 권장사항 수준...)

아래 코드가 AutoValue에 의해 생성된 AutoValue_Money Class이다.
위 코드를 보면, toString(), equals(), hashCode()가 자동으로 생성되어 있는 것을 확인할 수 있다.
다시 기억해야 할 점은, 위의 코드는 자동으로 생성된 것이라는 점이다.
실제로 단 5줄의 작성만으로 이정도의 코드를 생성할 수 있다.
 참고해야 할 점은, 이 AutoValue Annotation으로 코드가 생성되는 시점은 Build Time이다. 즉... AutoValue Annotation을 붙였다면, 한번은 빌드를 해야 정상 반영이 된다는 사실.


2. 확장! Extensions!

  위에서는 AutoValue가 어떤 작업을 대신해주고, 어떤식으로 우리의 손발이 편해지는지를 알아봤다. 하지만 AutoValue가 여기서 끝나는 것이 아니었다. 어쩌면 AutoValue의 강점은 여기서부터라고 봐도 될 것 같다.
다양한 확장이 존재하지만, 여기서는 Parcel Extension에 대해서 살짝 알아보려고 한다.
  우선 위의 예시로 들었던 AutoValue를 적용한 Money Class를 다시 보자.
 자, 여기서 이 객체를 Parcelable로 만들고자 하면... 사실 이것을 다 코드로 작성하고자 하면 일이 커진다. 물론 이 Class는 Value가 그렇게 많지 않지만, 많은 Value들을 포함한 Class라면 Parcelable로 작성해주는 것이 꽤 귀찮다. 또한 유지보수하는 과정에서 Value가 추가되거나 하는 경우에도 지속적으로 신경써줘야하는 일이 생긴다.

 자 여기까지만 마음의 준비를 하고,
 우선 아래와 같이 Gradle 파일에 추가를 해보자.

여기서도 가이드는 apt를 쓰도록 나와있지만, 위와같이 provided-annotationProcessor를 사용하도록 한다.

그리고 Money Class에는 아래와 같이 implements Parcelable을 추가해보자.
이렇게 만들고 나서 한번 Build를 해주면 Parcelable을 지원하는 Class가 생기게 된다.
이쯤 되니, 앞서 AutoValue에 의해 자동생성 되었던 AutoValue_Money Class의 내부가 어떻게 되었을지 궁금해진다.

해당 클래스의 내부는 아래와 같다.
다시한번 말해두지만 위 코드는 자동생성된 코드이다.
눈으로 확인할 수 있는 것처럼, 깔끔하게 Parcelable이 생성되어있다.
그런데 자세하게 보면, 이전에 있던 코드들이 많이 사라진 것처럼 보인다. Value들을 받는 Constructor와 final value들 그리고 toString(), equals()등이 모두 안보인다. 그리고 AutoValue_Money Class는 $AutoValue_Money를 상속받는 구조로 변경되었다.

그리고 $AutoValue_Money에는 아래와 같이 우리가 알고 있던, 기본적인 코드들이 들어가 있다.

여기까지 확인한 AutoValue Extension으로 생성되는 구조를 정리하면 다음과 같다.

위와 같이 단계별로 Wrapping하는 구조를 갖는것으로 보여진다.
여기까지 간단하게 AutoValue Extension중 Parcel에 대한 것을 알아봤다.
AutoValue-Extension은 다양한데 그 종류는 아래와 같다.(컨스트레인트 레이아웃, 오토밸류 익스텐션 등에서 일부 가져왔다.)
 - auto-value-parcel: 안드로이드의 Parcelable 인터페이스 구현
 - auto-value-cursor: 안드로이드 Cursor객체를 통해 DB 값을 marshal/unmarshal 지원
 - auto-value-redacted: 민감한 개인정보 등에 대해 redact속성 적용
 - auto-value-moshi: Moshi JSON serialization 라이브러리로 JsonAdapter생성
 - auto-value-gson: Google의 Gson Json serialization 라이브러리에 최적화된 TypeAdapter생성
 - auto-value-with: 밸류 타입에 대한 약간의 차이만 있는 카피를 쉽게 구현 가능

이런 Extension들은 Google에서 직접 내놓는 것들도 있지만, 개발자들이 개발해서 내놓는 것들도 있는 듯 하다.
Extension들의 목록과 최신버전은 아래에서 확인할 수 있다.
http://search.maven.org/#search%7Cga%7C1%7Cauto-value

댓글

이 블로그의 인기 게시물

[Android] DataBinding의 동작방식 - 4. include Tag 혹은 ViewStub 사용시의 Binding

[Android] DataBinding의 동작방식 - 5. Listener, Callback (CustomView의 Callback을 람다식으로 Binding하기)

[Android] DataBinding의 동작방식 - 2. BindingAdapter의 기본 및 사용 시점