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
Presently, there are a few issues which make Kotlin Data Classes incompatible/difficult to use with Vert.x's @DataObject code generation (e.g. #17, #43).
For example, instead of using data classes idiomatically:
@DataObject
data classAuthor(valname:String, valemail:String)
you're forced to write code which is significantly lengthier and less 'safe': can be instantiated without all parameters, parameters are defined with mutable var instead of val, etc.:
From what I recall, the two main sources of ire are:
Required JsonObject constructor
Data object classes must provide a constructor which takes a single io.vertx.core.json.JsonObject or java.lang.String parameter
Unlike Java, [secondary constructors in Kotlin must call the primary constructor](https ://kotlinlang.org/docs/classes.html#secondary-constructors) :
@DataObject
data classAuthor(valname:String, valemail:String) {
// Illegal: name and email must be passed to this(). constructor(json:JsonObject):this() {
AuthorConverter.fromJson(json, this)
}
// Legal, but difficult to maintain if your class has several parameters.constructor(json:JsonObject):this(
name = json.getString("name"),
email = json.getString("email")
)
}
Required no-arg constructor (for the generated converter and ...Of methods)
As mentioned above, data classes must be instantiated with all the required parameters. That constraint makes them incompatible with the generated Converter.fromJson methods, as that requires the class to be instantiated, and the properties to be mutible:
public static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json, YourType obj) {
for (java.util.Map.Entry<String, Object> member : json) {
switch (member.getKey()) {
case "aBoolean":if (member.getValue() instanceof Boolean) {
obj.setABoolean((Boolean)member.getValue());
}
break;
...
It also makes them incompatible with the generated yourTypeOf(...) methods, which similarly requires the class to be instantiated before it can populate values:
@ConstructorBinding
@ConfigurationProperties("blog")
data classBlogProperties(vartitle:String, valbanner:Banner) {
data classBanner(valtitle:String? = null, valcontent:String)
}
I'm not sure the feasibility of implementing something like this, as it's presumably dynamic and could lead to security issues. Neverthless, I'm including it here for inspiration.
Yes, that's what I was referring to by `...Of` methods.
Those are useful for constructing Java data objects in Kotlin but, in my
experience, aren't as compelling or reliable for generating Kotlin data
objects.
I've opened two issues relating to the codegen of these builders (#158,
#161), and there are probably other issues rooting from Kotlin's
idiosyncrasies. That said, fixing those wouldn't address the larger pain
points, like builders requiring a no-arg constructor.
Fundamentally, the issue is that DataObject constraints (and utilities)
aren't compatible with Kotlin's data classes, which are a core language
feature. That's a huge pain point, and I'd like to see how/if we can
improve the experience.
P.S., Are there plans to support Java Records? If so, those would face
similar challenges.
Description
Presently, there are a few issues which make Kotlin Data Classes incompatible/difficult to use with Vert.x's
@DataObject
code generation (e.g. #17, #43).For example, instead of using data classes idiomatically:
you're forced to write code which is significantly lengthier and less 'safe': can be instantiated without all parameters, parameters are defined with mutable
var
instead ofval
, etc.:From what I recall, the two main sources of ire are:
Required
JsonObject
constructorUnlike Java, [secondary constructors in Kotlin must call the primary constructor](https ://kotlinlang.org/docs/classes.html#secondary-constructors) :
Required no-arg constructor (for the generated converter and
...Of
methods)As mentioned above, data classes must be instantiated with all the required parameters. That constraint makes them incompatible with the generated
Converter.fromJson
methods, as that requires the class to be instantiated, and the properties to be mutible:It also makes them incompatible with the generated
yourTypeOf(...
) methods, which similarly requires the class to be instantiated before it can populate values:vertx-lang-kotlin/vertx-lang-kotlin/src/main/kotlin/io/vertx/kotlin/pgclient/PgConnectOptions.kt
Lines 148 to 152 in ae327c4
Solutions
With everything I previously mentioned in mind, what can we do to improve the experience?
Some ideas off the top of my head:
@ConstructorBinding
Spring Boot introduced the
@ConstructorBinding
annotation, which eliminates the need for a no-arg constructor :I'm not sure the feasibility of implementing something like this, as it's presumably dynamic and could lead to security issues. Neverthless, I'm including it here for inspiration.
Static
@JsonCreator
methodIn Jackson, you can define a static method annotated with
@JsonCreator
, which will be used to instantiate the class:This could be an alternative to the
JsonObject
constructor, and mitigate having to stuff values into thethis()
block.Kotlinx.Serialization
Kotlinx.Serialization is a native serialization library which generates encodes and decoders at compile time.
Perhaps we could leverage kotlinx.serialization to generate safe encoders and decoders?
Custom Codegen
We could augment
vertx-lang-kotlin-gen
, or write a Kotlin Compiler Plugin, to generate Kotlin-friendly converters and...Of
methods.The text was updated successfully, but these errors were encountered: