Demonstrates an issue caused by kapt generating a private constructor when an inline class is passed as a constructor argument.
This issue is problematic for the Android Architecture Components Room annotation processor,
which relies on having a public constructor for classes annotated with @Entity
.
Inside the project you'll finde Example.kt
which has the following contents:
inline class LinkId(val name: String)
@Entity
data class Link(
@PrimaryKey val id: LinkId
)
@Database(
version = 1,
entities = [
Link::class
]
)
abstract class ExampleDatabase : RoomDatabase()
Room requires an object annotated with @Entity
to have a public constructor. It appears that Link
does,
but when the project is built, compilation fails with the following error:
e: <path>\app\build\tmp\kapt3\stubs\debug\me\samthompson\kaptinlineclass\Link.java:7: error: Entities and Pojos must have a usable public constructor. You can have an empty constructor or a constructor whose parameters match the fields (by name and type).
public final class Link {
^
e: <path>\app\build\tmp\kapt3\stubs\debug\me\samthompson\kaptinlineclass\Link.java:10: error: Cannot find setter for field.
private final java.lang.String id = null;
Inspecting the linked stub shows the following:
@androidx.room.Entity()
@kotlin.Metadata(...)
public final class Link {
@org.jetbrains.annotations.NotNull()
@androidx.room.PrimaryKey()
private final java.lang.String id = null;
@org.jetbrains.annotations.NotNull()
public final java.lang.String getId() {
return null;
}
private Link(java.lang.String id) {
super();
}
@org.jetbrains.annotations.NotNull()
public final java.lang.String component1() {
return null;
}
@org.jetbrains.annotations.NotNull()
@java.lang.Override()
public java.lang.String toString() {
return null;
}
@java.lang.Override()
public int hashCode() {
return 0;
}
@java.lang.Override()
public boolean equals(@org.jetbrains.annotations.Nullable()
java.lang.Object p0) {
return false;
}
}
Note that the stub generated has a private constructor. When id
is changed to a String
, the stub is generated with a public
constructor and compilation succeeds.
Run ./gradlew :app:assembleDebug
in the root directory of this project. You'll need the android sdk.
A private constructor will be generated by kapt even if the value passed into the constructor is not a val
/var
. E.g.
class Link(id: LinkId)
will generate a stub with a private constructor. Properties that are not part of the constructor and have an inline class do not seem to have any effect on the access modifier of the constructor.