Autovalue - create immutable value types using annotation processor support from a Gradle build

https://github.com/google/auto

Intro

This is used to create immutable value types using Javac annotation processor support from within the Gradle JavaCompile task.

Why?, What? and How?

Setup

Gradle 2.1 introduces a simpler plugin specification. This improves project build scaffolding where it can be shared without the copy/pasta blocks of xml (maven) or groovy script.

The Gradle community plugins listing https://plugins.gradle.org.

The build.gradle below uses the local java plugin and ewerk auto-value-plugin.

A plugin is effectivley importing an external build script that can create additional configurations and add dependencies.

plugins {
    id 'java'
    id 'com.ewerk.gradle.plugins.auto-value' version '1.0.1'
}

repositories {
    jcenter()
}

The gradle compileJava task will use the plugin to detect @AutoValue classes and generate the java source to a default location “src/auto-value/<package/AutoValue_Classname”. This specific location means it won’t conflict with other similar plugins.

The AutoValue_ class wont exist before the annotation processor runs. The static create method can return null initially. More than one static factory creation method can be used and given any name.


Cash monetary class

@AutoValue
public abstract class Cash {

    public abstract Currency currency();
    public abstract BigDecimal amount();

    public static Cash create(Currency currency, BigDecimal amount) {
        return new AutoValue_Cash(currency, amount.setScale(2, RoundingMode.HALF_UP));
    }

    public static Cash fromString(Currency currency, String amount) {
        return create(currency, new BigDecimal(amount));
    }

}

Extra usage - with Jackson json annotations

@AutoValue
public abstract class Cash {

    public abstract Currency currency();
    public abstract BigDecimal amount();

    @JsonCreator
    public static Cash create(@JsonProperty("currency") Currency currency, 
                              @JsonProperty("amount") BigDecimal amount) {
        return new AutoValue_Cash(currency, amount.setScale(2, RoundingMode.HALF_UP));
    }

}
    Cash fiver = Cash.create(Currency.getInstance(Locale.UK), new BigDecimal("5.00"));

Best Practice: Add a package private constructor to prevent external subclassing.

@AutoValue
public abstract class Cash {
    
    Cash() {}
 
    public abstract Currency currency();
    public abstract BigDecimal amount();

    public static Cash create(Currency currency, BigDecimal amount) {
        return new AutoValue_Cash(currency, amount.setScale(2, RoundingMode.HALF_UP));
    }

}

Source code https://github.com/griffio/autovalue-gradle