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 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.
https://googleads.g.doubleclick.net/pagead/ads?client=ca-pub-5680150941998747&output=html&h=280&adk=3448018228&adf=3093153155&pi=t.aa~a.998372420~i.17~rp.4&daaos=1679837813445~1679837813445&w=739&fwrn=4&fwrnh=100&lmt=1679854995&num_ads=1&rafmt=1&armr=3&sem=mc&pwprc=5246376519&ad_type=text_image&format=739×280&url=https%3A%2F%2Fandroidexample365.com%2Fa-kotlin-compiler-plugin-that-addresses-an-apk-size-overhead-from-kotlin-data-classes%2F&fwr=0&pra=3&rh=185&rw=739&rpe=1&resp_fmts=3&wgl=1&fa=27&uach=WyJXaW5kb3dzIiwiMTAuMC4wIiwieDg2IiwiIiwiMTExLjAuNTU2My4xMTEiLFtdLGZhbHNlLG51bGwsIjY0IixbWyJHb29nbGUgQ2hyb21lIiwiMTExLjAuNTU2My4xMTEiXSxbIk5vdChBOkJyYW5kIiwiOC4wLjAuMCJdLFsiQ2hyb21pdW0iLCIxMTEuMC41NTYzLjExMSJdXSxmYWxzZV0.&dt=1679854307062&bpp=122&bdt=43858&idt=122&shv=r20230322&mjsv=m202303210101&ptt=9&saldr=aa&abxe=1&cookie=ID%3Dcc05ee47dc029e80-22dbb4eb44da0084%3AT%3D1677641029%3ART%3D1677641029%3AS%3DALNI_MbAl9FUO_gLdD7fKXc5kvBzkG3MYA&gpic=UID%3D00000bce56fe0a0c%3AT%3D1677641029%3ART%3D1679854223%3AS%3DALNI_MYS2UtK9_OKenU2bELUDKKxRyBVxA&prev_fmts=0x0%2C1130x250%2C300x250%2C331x250&nras=3&correlator=110977595445&frm=20&pv=1&ga_vid=1721951681.1677641029&ga_sid=1679854302&ga_hid=1008504757&ga_fc=1&u_tz=330&u_his=1&u_h=768&u_w=1366&u_ah=728&u_aw=1366&u_cd=24&u_sd=1&dmc=8&adx=130&ady=1028&biw=1349&bih=625&scr_x=0&scr_y=0&eid=44759927%2C44759876%2C44777876%2C44759837%2C31073335%2C44785294%2C44787455&oid=2&psts=AHQMDFebxP02dpR8JZyGUveWEhQjbNIbyvZ4JZ8tGwTgHL4LdhR2voEe8WbrIifUymreK4LfWMBZYhmLVIJ8KnI&pvsid=2656590804749422&tmod=1300429753&uas=0&nvt=1&ref=https%3A%2F%2Fandroidexample365.com%2F&fc=1408&brdim=0%2C0%2C0%2C0%2C1366%2C0%2C0%2C0%2C1366%2C625&vis=1&rsz=%7C%7Cs%7C&abl=NS&fu=128&bc=31&ifi=6&uci=a!6&btvi=2&fsb=1&xpc=X8RhLSa0uz&p=https%3A//androidexample365.com&dtd=M
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
Public talks
Project team
DCG was created by the Kotlin Foundation team @ Meta:
License
DataClassGenerate is MIT-licensed.