dataclassgenerate
or simply DCG
Motivation
DataClassGenerate is a Kotlin compiler plugin that addresses APK size overhead.
DCG brings data class’ app size contribution on-par with semantically identical Plain Java Objects.
Kotlin positions data class as an easy-to-use and low friction utility for representing plain-old data.
Despite appearing compact in source code, the compiler generates multiple utility methods for each data class, which impact APK size e.g.: hashCode, equals, toString, copy, componentN.
Before an optimizer (like Redex or R8) can strip these methods, it must prove that they are never used.
Since methods like toString, equals, and hashCode are so fundamental (defined on Object/Any), calls to them will exist all over the app, and the optimizer must prove that a data class would not flow into any of those call sites, which is often not possible.
How to use in your project
Apply the gradle plugin.
plugins {
id("com.facebook.kotlin.compilerplugins.dataclassgenerate") version <version>
}
And that's it! The default configuration will add the artifact which contains @DataClassGenerate automatically.
If needed, you can configure the DataClassGenerate plugin using dataClassGenerate block:
import com.facebook.kotlin.compilerplugins.dataclassgenerate.gradle.DataClassGenerateMode
dataClassGenerate {
enabled.set(true/false) // defaults to true
mode.set(DataClassGenerateMode.EXPLICIT/STRICT/IMPLICIT) // defaults to EXPLICIT
generateSuperClass.set(true/false) // defaults to false
}
How it works
DataClassGenerate Kotlin Compiler Plugin processes @DataClassGenerate annotation.
@DataClassGenerate ANNOTATION
NOTE: DCG is applicable to Kotlin data classes only.
NOTE: DCG configures an intent to generate (KEEP) or skip (OMIT) toString, equals, and hashCode methods generation.
NOTE: DCG does not configure copy, componentN, and other methods, but Redex or R8 will take care of them.
@DataClassGenerate annotation configures Kotlin data class code generation and bytecode optimizations.
@DataClassGenerate is applicable only to Kotlin data classes, and will not make any change if applied to a regular class (Unfortunately, Kotlin does not have a data class as an annotation target).
@DataClassGenerate annotation, together with applied DataClassGenerate compiler plugin, does 3 things:
- Configures code generation of
toStringmethod.@DataClassGenerate(toString = Mode.KEEP)will generatetoStringas in a usual data class.@DataClassGenerate(toString = Mode.OMIT)will NOT generatetoStringfor an annotated data class.
- Configures code generation of
equalsandhashCodemethods.@DataClassGenerate(equalsHashCode = Mode.KEEP)will generateequalsandhashCodeas in usual data class.@DataClassGenerate(equalsHashCode = Mode.OMIT)will NOT generateequalsandhashCodefor an annotated data class.
- Adds a marker super class
DataClassSuperfor suitable Data Classes to make them available for Redex Class Merging Optimization.- Do not upcast data classes to
DataClassSuper. There is no guarantee a concrete data class will get a marker super class.
- Do not upcast data classes to
Generation modes
How we can set @DataClassGenerate (toString = ???, equalsHashCode = ???) arguments?
| Mode | Explanation |
|---|---|
KEEP |
Express an intent to keep/generate a method(s) |
OMIT |
Express an intent to omit method(s) generation. |
Annotation defaults
@DataClassGenerate is declared with the following defaults:
annotation class DataClassGenerate(
val toString: Mode = Mode.OMIT,
val equalsHashCode: Mode = Mode.KEEP
)
Kotlin allows annotation parameter name ommission. The table below explains @DataClassGenerate shortcuts:
| Declaration | Explicit Equivalent |
|---|---|
@DataClassGenerate |
@DataClassGenerate(toString = Mode.OMIT, equalsHashCode = Mode.KEEP) |
@DataClassGenerate() |
@DataClassGenerate(toString = Mode.OMIT, equalsHashCode = Mode.KEEP) |
@DataClassGenerate(Mode.KEEP) |
@DataClassGenerate(toString = Mode.KEEP, equalsHashCode = Mode.KEEP) |
@DataClassGenerate(Mode.KEEP, Mode.OMIT) |
@DataClassGenerate(toString = Mode.KEEP, equalsHashCode = Mode.OMIT) |
@DataClassGenerate(equalsHashCode = Mode.OMIT) |
@DataClassGenerate(toString = Mode.OMIT, equalsHashCode = Mode.OMIT) |
DCG MODES
DataClassGenerate Kotlin compiler plugin works in multiple modes, but the most important is a STRICT mode.
STRICT mode
In STRICT mode:
Plugin applies only to data classes annotated with
@DataClassGenerate(...).- DCG will act following annotation instructions for method generation.
- DCG will add marker super classes.
Plugin reports a compilation error whenever it sees a data class without
@DataClassGenerate(...)annotation.
Example:
// Plugin will generate:
// -`toString`
// -`equals`, and `hashCode`
@DataClassGenerate(toString = Mode.KEEP, equalsHashCode = Mode.KEEP)
data class A(val i:Int)
// Plugin will report a compilation error
data class B(val l:Long)
EXPLICIT mode (current default)
In EXPLICIT mode:
- If a data class is annotated with
@DataClassGenerate, DCG will act according to the annotation instructions for method generation. - If data class is NOT annotated with @DataClassGenerate, DCG will only add marker super classes (read previous section for details).
Example:
// Plugin will generate:
// -`toString`
// -`equals`, and `hashCode`
@DataClassGenerate(toString = Mode.KEEP, equalsHashCode = Mode.KEEP)
data class A(val i:Int)
// Plugin will only create a marker super class
data class B(val l:Long)
// Plugin will do nothing
data class C(val l:Long): SomeSuperClass()
Releases
Coming soon
Compiler compatibility
| K1 | K2 |
|---|---|
| 1.5x | N/A |
| 1.6x | N/A |
| 1.7x-1.9x | 1.7.21 + -Xuse-k2 |
| N/A | 2.0+ |
Public talks
Project team
DCG was created by the Kotlin Foundation team @ Meta:
License
DataClassGenerate is MIT-licensed.
