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
toString
method.@DataClassGenerate(toString = Mode.KEEP)
will generatetoString
as in a usual data class.@DataClassGenerate(toString = Mode.OMIT)
will NOT generatetoString
for an annotated data class.
- Configures code generation of
equals
andhashCode
methods.@DataClassGenerate(equalsHashCode = Mode.KEEP)
will generateequals
andhashCode
as in usual data class.@DataClassGenerate(equalsHashCode = Mode.OMIT)
will NOT generateequals
andhashCode
for an annotated data class.
- Adds a marker super class
DataClassSuper
for 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.7.21 + -Xuse-k2 |
Public talks
Project team
DCG was created by the Kotlin Foundation team @ Meta:
License
DataClassGenerate is MIT-licensed.