vertx-lang-kotlin
vertx-lang-kotlin copied to clipboard
JsonObject,mapTo no support data class
I got this data class
data class User(
val Id: ObjectId,
var Phone: String,
var Name: String = "",
var Gender: String = ""
)
when use JsonObject.mapTo(User::class.java), got Error
java.lang.IllegalArgumentException: Cannot construct instance of User
(no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:3738)
at com.fasterxml.jackson.databind.ObjectMapper.convertValue(ObjectMapper.java:3656)
at io.vertx.core.json.JsonObject.mapTo(JsonObject.java:105)
it's sames error from jackson , and I found https://github.com/FasterXML/jackson-module-kotlin may fix this,will it be updated ?
I think that you should use this library along with Vert.x. you can access Jackson factories as static members of the io.vertx.core.json.Json class and add this module yourself when you start the application.
already done that ,Thanks for Attention~
object JacksonFix {
var isFixed:Boolean=false
fun fixVertxJson() {
if(!isFixed){
Json.mapper.registerModule(com.fasterxml.jackson.databind.module.SimpleModule()
.addSerializer(JsonObject::class.java, object : com.fasterxml.jackson.databind.JsonSerializer<JsonObject>() {
override fun serialize(value: JsonObject, gen: JsonGenerator, serializers: SerializerProvider?) {
gen.writeRawValue(if (value.isEmpty) "{}" else value.encode())
}
})
.addSerializer(JsonArray::class.java, object : com.fasterxml.jackson.databind.JsonSerializer<JsonArray>() {
override fun serialize(value: JsonArray, gen: JsonGenerator, serializers: SerializerProvider) {
gen.writeRawValue(if (value.isEmpty) "[]" else value.encode())
}
}))
Json.mapper.registerKotlinModule().findAndRegisterModules()
isFixed=true
}
}
}
simple to use it
JacksonFix. fixVertxJson()
or in java
JacksonFix.INSTANCE.fixVertxJson();
those code is what i'm using for
- fix vertx.core.json serial empty JsonObject as {"map":{}}
- fix vertx.core.json serial empty JsonArray as {"list":[] } note to avoid json format miss match for other systems
- registerd https://github.com/FasterXML/jackson-module-kotlin
Notes
May not have vertx.core.json element as property type,it will not be Deserialized properly use Map<String,Any> to replace JsonObject AND MutableSet<Any> to Replace JsonArray()
hope could be help for those one who have same needs
how about blogging about it ?
I usually do this to add support for jackson-module-kotlin
Json.mapper.apply {
registerKotlinModule()
}
Json.prettyMapper.apply {
registerKotlinModule()
}
as long kotlin module is registered to Json mapper, it will be fixed.
@vietj how about to make kotlin module enabled by default?
@jasoet's solution worked for me: IMO this is something that should be added as a dependency since it would be nice to marshal arbitrary JSON into data classes without having to think about it in Kotlin.
@jasoet we don't enable module plugin, people should register it. @mach-kernel to what should it be added ? vertx-lang-kotlin artifact ?
Can't get this to work....
// Here I have Instant which is giving me problems even though I'm using
// compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: '2.9.7'
data class Workflow(
var key: String,
var script: String,
var created: Instant = Instant.now(),
var udpated: Instant = Instant.now(),
){}
// I register the mappers on io.vertx.core.json.Json
Json.mapper.apply {
registerKotlinModule()
findAndRegisterModules()
}
val workflow = Workflow("testScript", "println(\"Hello World\")")
val strJSON = JsonObject.mapFrom(workflow)
eventBus.send("addres", strJson) // won't work
eventBus.send("addres", strJson.encode()) // does work but then I have an extra step
If I send on the event bus a message as a string using strJSON.encode() then it works, because at the consumer I can take the string convert it to JsonObject(strJSON) then use mapTo and it works. Strange because I would think that eventbus would use the same method to convert. If I send the straight JsonObject I get an error
java.lang.IllegalStateException: Illegal type in JsonObject: class java.math.BigDecimal
Can anyone point me to what I'm missing? @vietj ?
Update:
Looks like when I send a JsonObject through eventbus it uses JsonObjectMessageCodec which serializes the object to buffer and it doesn't use Jackson. Maybe we can add support for sending objects as strings, then it can use Jackson to serialize for all objects?
@vietj Why not add and enable jackson-module-kotlin
by default in vertx-lang-kotlin
? I would assume everyone that uses Kotlin and Jackson in the same project would need to (de)serialize JSON from/to data classes at some point, they are just the natural representation for exchange formats like this and it would be nice if it worked out of the box.
how could it be enabled by default ?
One way would be with an extension function since these already exist for kotlin anyways (e.g. #jsonArrayOf
etc.).
private var kotlinModuleRegistered = false
fun <T> JsonObject.toDataClass(type: Class<T>): T {
if(!kotlinModuleRegistered) {
kotlinModuleRegistered = true
DatabindCodec.mapper().registerKotlinModule()
}
return mapTo(type)
}
I don't know if this needs to be synchronized but the name can surely be improved :smile:
yes but if the user don't use them, then they are not loaded and no registration is done I think
It looks like there is a way for jackson to discover and register modules on the classpath. I believe vertx already does some configuration inside io.vertx.core.json.Json#initialize
. This would be the perfect place to call this code.
Then the only thing left to do is to add the kotlin module as a dependency for vertx-lang-kotlin
. If that sounds good then I can create PRs for this.
I am not in favour of this option because it is an open door for potential security issues
On 26 Apr 2020, at 07:35, Selim Dincer [email protected] wrote:
It looks like there is a way for jackson to discover and register modules on the classpath https://fasterxml.github.io/jackson-databind/javadoc/2.7/com/fasterxml/jackson/databind/ObjectMapper.html#findAndRegisterModules(). I believe vertx already does some configuration inside io.vertx.core.json.Json#initialize. This would be the perfect place to call this code. Then the only thing left to do is to add the kotlin module as a dependency for vertx-lang-kotlin. If that sounds good then I can create PRs for this.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/vert-x3/vertx-lang-kotlin/issues/43#issuecomment-619485627, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABXDCTQ27IIJUZ2PYNWMILROPB3PANCNFSM4EGHBVCA.
Is there an opportunity to use kotlinx.serialization
here instead?
My understanding is that encoders/decoders are generated at compile-time, which would mitigate security concerns associated with Jackson's use of reflection. Not to mention the benefit of a Kotlin-native serialization library.
See solution in https://github.com/vert-x3/vertx-lang-kotlin/issues/43#issuecomment-356157748