Java 7 or higher is required to run the Immutables annotation processor.
Add the required dependencies for basic immutable object generation:
Snippet of Maven dependencies:
<dependency>
<groupId>org.immutables</groupId>
<artifactId>value</artifactId>
<version>2.10.1</version>
<scope>provided</scope>
</dependency>
In Maven, the dependency can be declared in the “provided” scope, or made “optional”. The artifact is not required at runtime; it is compile-only dependency.
If you are using multiple dependencies like org.immutables:serial
you can import the bill of materials (BoM) in your dependency management and go without specifying the version of the dependency individually:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.immutables</groupId>
<artifactId>bom</artifactId>
<version>2.10.1</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
The Immutables annotation processor runs under any Java build tool that uses javac
as compiler backend (assuming that annotation processing is not disabled in build tool configuration).
The Eclipse JDT compiler (ECJ) also supports this annotation processor. See Using annotation processor in IDE.
Assuming that required dependencies were added, create an abstract class with abstract accessor methods.
You can do the same by annotating with interfaces or even annotations (@interface
):
package info.sample;
import java.util.List;
import java.util.Set;
import org.immutables.value.Value;
@Value.Immutable
public abstract class FoobarValue {
public abstract int foo();
public abstract String bar();
public abstract List<Integer> buz();
public abstract Set<Long> crux();
}
It is now possible to generate and then use the generated immutable implementation:
package info.sample;
import java.util.List;
public class FoobarValueMain {
public static void main(String... args) {
FoobarValue value = ImmutableFoobarValue.builder()
.foo(2)
.bar("Bar")
.addBuz(1, 3, 4)
.build(); // FoobarValue{foo=2, bar=Bar, buz=[1, 3, 4], crux={}}
int foo = value.foo(); // 2
List<Integer> buz = value.buz(); // ImmutableList.of(1, 3, 4)
}
}
Congratulations! You’re done! See the sample generated code for an example of what kind of code is being generated by the processor.
Even basic immutable class generation has a lot more tricks to show. Check out the guide!
To comfortably use Immutables for Android development, the following steps are required to set up a working build configuration:
An annotation processor plugin should be configured for the Android build.
Although Immutables annotation processing works with javac
without specific a configuration, a plugin is required to ensure that output directories, dependency scopes and other miscellaneous details are being set up correctly. We’ve found that the android-apt
plugin works well for this, including interaction with Android Studio.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "com.android.tools.build:gradle:1.2.3"
// add dependency to plugin
classpath "com.neenbedankt.gradle.plugins:android-apt:1.6"
}
}
// ...
Then, use apply plugin: 'android-apt'
in modules to apply the plugin.
The Immutables annotation processor should be added to the special apt
scope (declared by the android-apt
plugin) and to the compile-time-only provided
scope (declared by the Android Gradle plugins).
apply plugin: "com.android.application"
apply plugin: "android-apt"
// ...
dependencies {
compile fileTree(dir: "libs", include: ["*.jar"])
apt "org.immutables:value:2.10.1" // <-- for annotation processor
provided "org.immutables:value:2.10.1" // <-- for annotation API
}
Other compile-only dependencies applicable to Android should be added in the provided
scope. Jar files with annotations such as org.immutables:builder:2.10.1 (see Factory Builders) or org.immutables:gson:2.10.1 (see GSON support) don’t have to be propagated to an Android application, especially if there are no runtime classes needed. For example, the gson
module provides optional runtime classes which are not suitable for Android apps.
dependencies {
// ...
apt "org.immutables:value:2.10.1" // for annotation processor
provided "org.immutables:value-annotations:2.10.1" // for annotations
provided "org.immutables:builder:2.10.1" // for annotations
provided "org.immutables:gson:2.10.1" // for annotations
}
Since version 2.0.19
, for some combined annotation and runtime artifacts there are separate annotation-only artifacts available.
For example, the value
and gson
modules have additional artifacts with annotations
classifiers. This allows for the reduction of dependencies and
avoids lint warnings about using certain types that are not available on Android (despite not being
required at runtime). The above example with the alternative dependencies could be rewritten as:
dependencies {
// ...
apt "org.immutables:value:2.10.1" // for annotation processor
provided "org.immutables:value:2.10.1:annotations" // annotation-only artifact
provided "org.immutables:builder:2.10.1" // there are only annotations anyway
provided "org.immutables:gson:2.10.1:annotations" // annotation-only artifact
}
Since version 2.7 in addition to org.immutables:value:annotations
artifact (with annotations
classifier), also available equivalent org.immutables:value-annotations
annotation-only artifact. It will be easier for some tools to consume artifacts without classifiers and including source jars.
Immutables itself and the surrounding ecosystem of build tools, compilers and even JVM may contain bugs. Please, try to upgrade to the latest stable version of tools you use if possible and report any issues found.
There’s known issue with the interaction between the incremental compilation feature of javac
and annotation processing.
Build tools like Maven are also affected by this bug. Typically, commands such as mvn clean compile
will resolve any such problems by a forcing full build.
Disabling incremental compilation is also an option:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<compilerVersion>1.8</compilerVersion>
<source>1.8</source>
<target>1.8</target>
<!-- Prevents an endPosTable exception during compilation -->
<useIncrementalCompilation>false</useIncrementalCompilation>
</configuration>
</plugin>
Search phrase: “java.lang.IllegalStateException: endPosTable already set”
Sometimes there are too many compilation errors due to generated files not found, that may hinder real annotation processing errors when max error limit is reached. The limit can be configured for javac as -Xmaxerrs 1000000
. For Maven it could be set as ...
<compilerArguments><Xmaxerrs>1000000</Xmaxerrs></compilerArguments></configuration>
for maven-compiler-plugin
.
In case of some spurious errors Some internal annotation processing errors may be not clearly reported for Maven, you may rerun build with -X
debug output and, possibly, quite verbose compiler configuration:
<compilerArgs>
<arg>-verbose</arg>
<arg>-XprintRounds</arg>
<arg>-XprintProcessorInfo</arg>
<arg>-Xlint</arg>
<arg>-J-verbose</arg>
</compilerArgs>