Upgrade to Pro — share decks privately, control downloads, hide ads and more …

AutoValue and Extensions by Vincent Dubedout

AutoValue and Extensions by Vincent Dubedout

GDG Montreal

April 26, 2017
Tweet

More Decks by GDG Montreal

Other Decks in Technology

Transcript

  1. ABOUT ME - VINCENT DUBEDOUT ➤ Started on Android 1.5

    with an HTC Hero (2009) ➤ Worked with Cross Platform Xamarin C# ➤ Company ➤ Web&App Agency ➤ Project ➤ Kijiji for Street Objects ➤ Messaging 2
  2. FIRST - WHAT’S IDENTITY @Test
 public void testMonkeyBananaIdentity(){
 String object1

    = new String("banana");
 String object2 = new String("banana");
 
 // Comparison on IDENTITY
 assertThat(object1 == object2).isFalse(); // Comparison on VALUE
 assertThat(object1.equals(object2)).isTrue();
 
 // Comparison on IDENTITY String object3 = object2; assertThat(object2 == object3).isTrue();
 
 } 3
  3. IMMUTABILITY CONCEPT ➤ Once built, doesn’t change ➤ Thread safe,

    cannot be corrupted ➤ Simple to construct, test and use ➤ No need of a copy constructor or clone method ➤ Hashcode can use lazy initialization ➤ Good Map/Set keys 4
  4. CONCURRENCY CONTEXT task1.setStartDate(new Date("1 Jan 98"); task2.setStartDate(task1.getTaskDate()); // use task

    1 data //then somewhere in the task class void delay(int delayDays) { _startDate.setDate(_startDate.getDate() + delayDays); // somewhere else task2.delay(5); // now you find task1's start date has changed 5
  5. IMMUTABLE OBJECTS - CONS ➤ New State = New Object

    ➤ Garbage collection ➤ Not usable in intensive loops (games etc…) ➤ Painful to write 6
  6. WHAT’S A JAVA VALUE TYPE OBJECT ➤ Value Based ➤

    Immutable and Final ➤ No Accessible constructors ➤ Don’t allow to change internal mutable objects ➤ No use of identity-sensitive operations ➤ Substitutable when equals 7
  7. WHAT’S AUTO VALUE ➤ Released as V1 in January 2015

    ➤ Current version 1.4.1 ➤ Compatible Java 1.6 ➤ Goal: ➤ Immutable Value Types Generation 8
  8. JAVA, CREATING AN IMMUTABLE ➤ New class with 3 variables

    - 5 lines public final class Area {
 private final long longitude;
 private final long latitude;
 private final float radius;
 } 9
  9. JAVA, CREATING AN IMMUTABLE ➤ Constructor + 5 lines public

    final class Area {
 private final long longitude;
 private final long latitude;
 private final float radius;
 
 public Area(long longitude, long latitude, float radius) {
 this.longitude = longitude;
 this.latitude = latitude;
 this.radius = radius;
 }
 } 10
  10. JAVA, CREATING AN IMMUTABLE ➤ Getters + 9 lines public

    final class Area {
 private final long longitude;
 private final long latitude;
 private final float radius;
 
 public Area(long longitude, long latitude, float radius) {
 this.longitude = longitude;
 this.latitude = latitude;
 this.radius = radius;
 }
 
 public long getLongitude() {
 return longitude;
 }
 
 public long getLatitude() {
 return latitude;
 }
 
 public float getRadius() {
 return radius;
 }
 } 11
  11. JAVA, CREATING AN IMMUTABLE ➤ Hashcode + 7 lines @Override


    public int hashCode() {
 int result = (int) (longitude ^ (longitude >>> 32));
 result = 31 * result + (int) (latitude ^ (latitude >>> 32));
 result = 31 * result + (radius != +0.0f ? Float.floatToIntBits(radius) : 0);
 return result;
 } 12
  12. JAVA, CREATING AN IMMUTABLE ➤ Equals + 11 lines @Override


    public boolean equals(Object o) {
 if (this == o) return true;
 if (o == null || getClass() != o.getClass()) return false;
 
 Area area = (Area) o;
 
 if (longitude != area.longitude) return false;
 if (latitude != area.latitude) return false;
 if (Float.compare(area.radius, radius) != 0) return false;
 
 return true;
 } 13
  13. JAVA, CREATING AN IMMUTABLE ➤ toString + 7 lines @Override


    public String toString() {
 return "Area{" +
 "longitude=" + longitude +
 ", latitude=" + latitude +
 ", radius=" + radius +
 '}';
 } 14
  14. JAVA, CREATING AN IMMUTABLE ➤ Bonus: Parcelable + 29 lines

    @Override
 public int describeContents() {
 return 0;
 }
 
 @Override
 public void writeToParcel(Parcel dest, int flags) {
 dest.writeLong(this.longitude);
 dest.writeLong(this.latitude);
 dest.writeFloat(this.radius);
 }
 
 protected Area(Parcel in) {
 this.longitude = in.readLong();
 this.latitude = in.readLong();
 this.radius = in.readFloat();
 }
 
 public static final Creator<Area> CREATOR = new Creator<Area>() {
 @Override
 public Area createFromParcel(Parcel source) {
 return new Area(source);
 }
 
 @Override
 public Area[] newArray(int size) {
 return new Area[size];
 }
 }; 15
  15. JAVA, CREATING AN IMMUTABLE public final class Area implements Parcelable{


    private final long longitude;
 private final long latitude;
 private final float radius;
 
 public Area(long longitude, long latitude, float radius) {
 this.longitude = longitude;
 this.latitude = latitude;
 this.radius = radius;
 }
 
 public long getLongitude() {
 return longitude;
 }
 
 public long getLatitude() {
 return latitude;
 }
 
 public float getRadius() {
 return radius;
 }
 
 @Override
 public boolean equals(Object o) {
 if (this == o) return true;
 if (o == null || getClass() != o.getClass()) return false;
 
 Area area = (Area) o;
 
 if (longitude != area.longitude) return false;
 if (latitude != area.latitude) return false;
 if (Float.compare(area.radius, radius) != 0) return false;
 
 return true;
 }
 
 @Override
 public int hashCode() {
 int result = (int) (longitude ^ (longitude >>> 32));
 result = 31 * result + (int) (latitude ^ (latitude >>> 32));
 result = 31 * result + (radius != +0.0f ? Float.floatToIntBits(radius) : 0);
 return result;
 }
 
 @Override
 public String toString() {
 return "Area{" +
 "longitude=" + longitude +
 ", latitude=" + latitude +
 ", radius=" + radius +
 '}';
 }
 
 
 @Override
 public int describeContents() {
 return 0;
 }
 
 @Override
 public void writeToParcel(Parcel dest, int flags) {
 dest.writeLong(this.longitude);
 dest.writeLong(this.latitude);
 dest.writeFloat(this.radius);
 }
 
 protected Area(Parcel in) {
 this.longitude = in.readLong();
 this.latitude = in.readLong();
 this.radius = in.readFloat();
 }
 
 public static final Creator<Area> CREATOR = new Creator<Area>() {
 @Override
 public Area createFromParcel(Parcel source) {
 return new Area(source);
 }
 
 @Override
 public Area[] newArray(int size) {
 return new Area[size];
 }
 };
 } 16
  16. JAVA, CREATING AN IMMUTABLE ➤ 73 lines to create a

    Value Type Object ➤ 63 lines ➤ that can be generated by Android Studio ➤ that you will change each time you modify the class 17
  17. AUTOVALUE LIBRARY @AutoValue
 public abstract class Area implements Parcelable {


    public abstract long latitude();
 public abstract long longitude();
 public abstract float radius();
 
 public static Area create(long latitude, long longitude, float radius) {
 return new AutoValue_Area(latitude, longitude, radius);
 }
 } ➤ AutoValue_Area Generated at Compile Time 18
  18. AUTOVALUE LIBRARY @AutoValue
 public abstract class Area {
 public abstract

    long latitude();
 public abstract long longitude();
 public abstract float radius();
 
 public static Builder builder() {
 return new AutoValue_Area.Builder();
 }
 
 @AutoValue.Builder
 public abstract static class Builder {
 public abstract Builder setLatitude(long latitude);
 public abstract Builder setLongitude(long longitude);
 public abstract Builder setRadius(float radius);
 
 public abstract Area build();
 }
 } 19
  19. AUTOVALUE LIBRARY ➤ Generate Immutable Value Type Object ➤ Generates

    all toString, equals, etc ➤ Minimal impact on method count ➤ Can use Builders ➤ Generated class means Debugger is usable ➤ Checks for Null Objects (use @Nullable) ➤ Don’t use mutable objects or wrap them ➤ Awesome documentation 20
  20. INSTALLATION (main.gradle) buildscript {
 repositories {
 jcenter()
 }
 dependencies {


    classpath 'com.android.tools.build:gradle:2.3.1'
 classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
 }
 } (app.gradle) dependencies {
 compile fileTree(dir: 'libs', include: ['*.jar'])
 apt 'com.google.auto.value:auto-value:1.4.1'
 provided 'com.jakewharton.auto.value:auto-value-annotations:1.4'
 // apt 'com.squareup:javapoet:1.8.0'
 } 21
  21. PARCELABLE (RYAN HARTER) @AutoValue
 public abstract class Area implements Parcelable

    {
 public abstract long latitude();
 public abstract long longitude();
 public abstract float radius();
 
 public static Area create(long latitude, long longitude, float radius) {
 return new AutoValue_Area(latitude, longitude, radius);
 }
 } Installation apt ‘com.ryanharter.auto.value:auto-value-parcel:0.2.5' https://github.com/rharter/auto-value-parcel 23
  22. WITHER (GABRIEL ITTNER) @AutoValue
 public abstract class Area {
 public

    abstract long latitude();
 public abstract long longitude();
 public abstract float radius();
 
 public abstract Area withLatitude(long latitude);
 } Installation apt 'com.gabrielittner.auto.value:auto-value-with:1.0.0' https://github.com/gabrielittner/auto-value-with 24
  23. AUTOVALUE-REDACTED (SQUARE) @Retention(RetentionPolicy.SOURCE)
 @Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
 public @interface Redacted {

    } @AutoValue
 public abstract class Area {
 public abstract long latitude();
 public abstract long longitude();
 @Redacted public abstract float radius();
 
 public static Area create(long latitude, long longitude, float radius) {
 return new AutoValue_Area(latitude, longitude, radius);
 }
 } E/AUTOVALUE: Redacted message, Area{latitude=75, longitude=75, radius=██} ➤ Installation apt 'com.squareup.auto.value:auto-value-redacted:1.0.1' ➤ https://github.com/square/auto-value-redacted
  24. AUTOVALUE-GSON (RYAN HARTER) @AutoValue
 public abstract class Area {
 @SerializedName("latitude")

    public abstract long latitude();
 @SerializedName("longitude") public abstract long longitude();
 @SerializedName("radius") public abstract float radius();
 
 public static TypeAdapter<Area> typeAdapter(Gson gson) {
 return new AutoValue_Area.GsonTypeAdapter(gson);
 }
 } Installation apt 'com.ryanharter.auto.value:auto-value-gson:0.4.6' provided 'com.ryanharter.auto.value:auto-value-gson:0.4.6' https://github.com/rharter/auto-value-gson 26
  25. AUTOVALUE-GSON (RYAN HARTER) @GsonTypeAdapterFactory
 public abstract class MyAdapterFactory implements TypeAdapterFactory

    {
 public static TypeAdapterFactory create() {
 return new AutoValueGson_MyAdapterFactory();
 }
 } Gson gson = new GsonBuilder()
 .registerTypeAdapterFactory(MyAdapterFactory.create())
 .create(); new Retrofit.Builder()
 .addConverterFactory(GsonConverterFactory.create(gson)) 27
  26. AUTOVALUE-GSON - SPEED TEST public static String DUMMY_JSON = "[\n"

    +
 " {\n" +
 " \"_id\": \"576869ed835bc5884bf7179e\",\n" +
 " \"index\": 0,\n" +
 " \"guid\": \"5f4b447c-4911-4ee2-bdc4-8d71c7f2a6d4\",\n" +
 " \"picture\": \"http://placehold.it/32x32\",\n" +
 " \"age\": 31,\n" +
 " \"eyeColor\": \"green\",\n" +
 " \"name\": \"Gwendolyn Riggs\",\n" +
 " \"gender\": \"female\",\n" +
 " \"company\": \"XOGGLE\",\n" +
 " \"email\": \"[email protected]\",\n" +
 " \"phone\": \"+1 (983) 458-3698\",\n" +
 " \"address\": \"923 Calyer Street, Toftrees, Oklahoma, 2959\",\n" +
 " \"about\": \"Consectetur dolor sit duis laboris incididunt non ex qui. Dolore cillum Lorem consectetur consequat sint id amet ullamco pariatur irure. Elit amet eu occaecat qui ad. Ex amet mollit commodo reprehenderit eiusmod. Laboris ad irure consectetur eiusmod excepteur tempor consequat incididunt mollit aliquip consectetur nulla.\ \r\\n\"\n" +
 " } 28
  27. AUTOVALUE-GSON - SPEED TEST //// code 1 //// long startTimer

    = System.currentTimeMillis(); 
 Gson gson = new GsonBuilder().create();
 Type type = new TypeToken<ArrayList<UserDetailWithoutAutoValue>>() {}.getType();
 for (int i = 0; i < loopNumber; i++) {
 List<UserDetailWithoutAutoValue> userDetail = gson.fromJson(DummyJsonProvider.DUMMY_JSON, type);
 }
 float totalDuration = System.currentTimeMillis() - startTimer; //// code 2 //// long startTimer = System.currentTimeMillis();
 
 Gson gson = new GsonBuilder()
 .registerTypeAdapterFactory(MyAdapterFactory.create())
 .create();
 Type type = new TypeToken<ArrayList<UserDetailAutoValued>>() {}.getType();
 for (int i = 0; i < loopNumber; i++) {
 List<UserDetailAutoValued> userDetail = gson.fromJson(DummyJsonProvider.DUMMY_JSON, type);
 }
 
 float totalDuration = System.currentTimeMillis() - startTimer; 29
  28. AUTOVALUE-MOSHI (RYAN HARTER) @AutoValue public abstract class Foo {
 abstract

    String bar();
 @Json(name="Baz") abstract String baz();
 
 public static JsonAdapter<Foo> jsonAdapter(Moshi moshi) {
 return new AutoValue_Foo.MoshiJsonAdapter(moshi);
 }
 } Moshi moshi = new Moshi.Builder() .add(MyAdapterFactory.create()) .build(); ➤ Installation apt 'com.ryanharter.auto.value:auto-value-moshi:0.4.3'
 provided 'com.ryanharter.auto.value:auto-value-moshi-annotations:0.4.3' ➤ https://github.com/rharter/auto-value-moshi
  29. AUTOVALUE-CURSOR (GABRIEL ITTNER) @AutoValue
 public abstract class Area {
 public

    abstract long latitude();
 public abstract long longitude();
 @ColumnName("area_radius") public abstract float radius();
 
 public static Area create(Cursor cursor) {
 return AutoValue_Area.createFromCursor(cursor);
 }
 } ➤ Installation apt 'com.gabrielittner.auto.value:auto-value-cursor:1.0.1'
 compile 'com.gabrielittner.auto.value:auto-value-cursor-annotations:1.0.1' ➤ https://github.com/gabrielittner/auto-value-cursor
  30. AUTOVALUE-FIREBASE (MATT LOGAN) @AutoValue @FirebaseValue
 public abstract class Area {


    @FirebaseAdapter(LocationAdapter.class) public abstract Location location();
 public abstract float radius();
 
 public static Area create(Location location, float radius) {
 return new AutoValue_Area(location, radius);
 }
 
 public static Area create(DataSnapshot dataSnapshot){
 return dataSnapshot.getValue(AutoValue_Area.FirebaseValue.class).toAutoValue();
 }
 
 public Object toFirebaseValue(){
 return new AutoValue_Area.FirebaseValue(this);
 }
 
 } ➤ Add two methods Create and toFirebaseValue ➤ For non default values, use adapters
  31. AUTOVALUE-FIREBASE ➤ Dumb Location Adapter class LocationAdapter implements TypeAdapter<Location, String>

    {
 @Override
 public Location fromFirebaseValue(String value) {
 String[] split = value.split(";");
 Location location = new Location("firebase");
 location.setLatitude(Double.parseDouble(split[0]));
 location.setLongitude(Double.parseDouble(split[1]));
 return location;
 }
 
 @Override
 public String toFirebaseValue(Location value) {
 return value.getLatitude()+";"+value.getLongitude();
 }
 }
  32. ONE YEAR USING IT ➤ Really easy to work with

    ➤ Less code written -> less bugs ➤ Easy refactoring and object manipulation ➤ No “Oups I forgot to modify this toString” ➤ Somewhat faster de/serialization ➤ Somewhat slower compile time ➤ Thread safety