You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Somewhat regarding to #275 comment 3 ... This may be more of just a documentation than an issue with Parceler, but here we go...
Kotlin allows parameters to have default values in function and constructor definitions. This (among other things) allows compact definition of data classes (think them as POJO's). e.g.
data classTimeStamp(valvalue:Long = System.currentTimeMillis())
As Parceler does the handling of serialization and deserialization of view models and whatnot keeping programmers sane in Android-world, consider following (bad) example:
@Parcel(Parcel.Serialization.BEAN)
data classMyScreenViewModel @ParcelConstructor constructor(
valtitle:ObservableField<String> = ObservableField(),
valsubTitle:ObservableField<String> = ObservableField()
) {
// This provided here only as some kind of additional non-default behaviour.// Has nothing to do with the issue otherwise and could be left away.constructor(title:String) :this(
title =ObservableField(title)
)
}
One can now create instances of that class in few ways:
val vmDefault =MyScreenViewModel() // calls the primary ctor with all defaults.
.apply { title.set("Options") } // syntactic kotlin-sugar.val vmSpecific =MyScreenViewModel("Options") // calls secondary ctor; not an issue.
However, this doesn't work with Parceler (at least 1.1.8...1.1.9) due error Parceler: Too many @ParcelConstructor annotated constructors found..
Insides
It seems that if all arguments of a data class have default parameters, kotlinc will generate a default no-argument constructor with the @ParcelConstructor annotation and the compilation will fail. If there is at least one argument without default value, compilation seems to succeed even though there are multiple of annotated constructors.
Internal decompilation shows, that there is at least one synthetic method added to data classes that handles the optionality of the parameters case by case (var3 is a bitmask):
data class Test @ParcelConstructor constructor(val i: Int, val s: String? = null)
->
// expected
@ParcelConstructor public Test(int i, @Nullable String s)
// synthetic, causes no error.
@ParcelConstructor public Test(int var1, String var2,
int var3, DefaultConstructorMarker var4)
If all arguments have defaults, there will be default constructor too:
data class Test @ParcelConstructor constructor(val i: Int = 4, val s: String? = null)
->
// extra
@ParcelConstructor public Test() : this(4, null, 3, null)
// full
@ParcelConstructor public Test(int i, @Nullable String s)
// synthetic
@ParcelConstructor public Test(int var1, String var2,
int var3, DefaultConstructorMarker var4)
The synthetic constructor always calls full/expected constructor.
The default constructor calls synthetic constructor.
Workarounds
1
The issue can be worked around by having no defaults in primary constructor, although being a bit more verbose (but still much shorter than its java-version):
data classMyScreenVm @ParcelConstructor constructor(
valtitle:ObservableField<String>,
valsubTitle:ObservableField<String>
) {
constructor() :this(
title =ObservableField(),
subTitle =ObservableField()
)
}
Here the primary constructor has no defaults, thus no synthetic method for defaults is generated, no default constructor is generated (but the explicit one exists without conflicting annotation), and the annotation is on only one constructor.
2
Other workaround is to declare the default constructor by hand and calling the primary constructor with at least one parameter:
The default of title is kind of declared twice now, but it forces this to call the primary (or rather the synthetic) constructor and makes the default no-arg constructor to not have conflicting annotation.
The text was updated successfully, but these errors were encountered:
@monowar1993, all the documentation (readme, website) is fork-friendly. A pull request with some appropriate Kotlin examples would be much appreciated.
Somewhat regarding to #275 comment 3 ... This may be more of just a documentation than an issue with Parceler, but here we go...
Kotlin allows parameters to have default values in function and constructor definitions. This (among other things) allows compact definition of data classes (think them as POJO's). e.g.
As Parceler does the handling of serialization and deserialization of view models and whatnot keeping programmers sane in Android-world, consider following (bad) example:
One can now create instances of that class in few ways:
However, this doesn't work with Parceler (at least 1.1.8...1.1.9) due error
Parceler: Too many @ParcelConstructor annotated constructors found.
.Insides
It seems that if all arguments of a data class have default parameters, kotlinc will generate a default no-argument constructor with the
@ParcelConstructor
annotation and the compilation will fail. If there is at least one argument without default value, compilation seems to succeed even though there are multiple of annotated constructors.Internal decompilation shows, that there is at least one synthetic method added to data classes that handles the optionality of the parameters case by case (var3 is a bitmask):
If all arguments have defaults, there will be default constructor too:
The synthetic constructor always calls full/expected constructor.
The default constructor calls synthetic constructor.
Workarounds
1
The issue can be worked around by having no defaults in primary constructor, although being a bit more verbose (but still much shorter than its java-version):
Here the primary constructor has no defaults, thus no synthetic method for defaults is generated, no default constructor is generated (but the explicit one exists without conflicting annotation), and the annotation is on only one constructor.
2
Other workaround is to declare the default constructor by hand and calling the primary constructor with at least one parameter:
The default of
title
is kind of declared twice now, but it forcesthis
to call the primary (or rather the synthetic) constructor and makes the default no-arg constructor to not have conflicting annotation.The text was updated successfully, but these errors were encountered: