Rodrigo Silva
06/16/2020, 7:18 PMjackson-module-kotlin,
to serialize but I'm having an error:gmariotti
07/02/2020, 8:34 AMmapOf("key" to mapOf("innerKey" to "value"))
serialized as { "key": "{\"innerKey\": \"value\"}" }
instead of {"key": {"innerKey": "value"}}
Dariusz Kuc
07/20/2020, 5:50 PMundefined
(field is omitted), null
(field=null) and also can have a value
(field=value). Within JVM we either have value or no-value (i.e. null
) so we are trying to represent those 3 states using Kotlin sealed classes - something along the lines
sealed class OptionallyDefined<T> {
object Undefined : OptionallyDefined<Nothing>()
data class Defined<T>(val data: T) : OptionallyDefined<T>()
}
Unfortunately cannot get the deserialization to work. I tried using custom serializer (i.e. @JsonDeserialize(using = NullAwareDeserializer::class)
) but cannot get it to work correctly. Any pointers would be greatly appreciated!Jgafner
10/07/2020, 10:06 AMpublic class SimpleClass {
private String path;
@JsonProperty("somePath")
private void unpackPath(Map<String, Object> somePath) {
this.path = (String) somePath.get("toString");
}
}
When I use the IDE convertor I am getting this:
class SimpleClass {
private var path: String? = null
@JsonProperty("somePath")
private fun unpackPath(somePath: Map<String, Any>) {
path = somePath["toString"] as String?
}
}
Is that correct ?Jukka Siivonen
10/21/2020, 4:47 PMDariusz Kuc
03/18/2021, 4:14 PMsealed class MyServerRequest
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
data class SingleRequest(val request: String) : MyServerRequest()
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
class BatchRequest @JsonCreator constructor(@get:JsonValue val requests: List<SingleRequest>) : MyServerRequest()
Between those two there is no extra type
field that I could use to detect correct type using @JsonTypeInfo/@JsonSubTypes
. Instead, I parse the incoming requests to a JsonNode
and check whether it is an array to determine appropriate target, i.e.
val jsonNode = rawRequest.bodyToMono(JsonNode::class.java).awaitFirst()
if (jsonNode.isArray) {
objectMapper.treeToValue(jsonNode, BatchRequest::class.java)
} else {
objectMapper.treeToValue(jsonNode, SingleRequest::class.java)
}
the above works fine but I'd like to simplify it and use custom deserializer to handle it, i.e.
@JsonDeserialize(using = MyRequestDeserializer::class)
sealed class MyServerRequest
class MyRequestDeserializer : JsonDeserializer<MyServerRequest>() {
override fun deserialize(parser: JsonParser, ctxt: DeserializationContext): MyServerRequest {
val codec = parser.codec
val jsonNode = codec.readTree<JsonNode>(parser)
return if (jsonNode.isArray) {
codec.treeToValue(jsonNode, SingleRequest::class.java)
} else {
codec.treeToValue(jsonNode, BatchRequest::class.java)
}
}
}
this though fails with stackoverflow error as sealed class implementations look up the root deserializer... any ideas how to make it work?Slackbot
03/31/2021, 3:06 PMJoe
04/30/2021, 8:02 PM@JacksonInject
. I've got it working like this:
class ClassToDeserialize {
@JacksonInject
private val dependency: ThirdPartyUndeserializableObject? = null
@JsonPropery
private val simpleValue: String
/// ... etc
}
To avoid nullability (and since I don't really have an instance of the dependency I can assign statically), I'd like to use constructor injection instead:
class ClassToDeserialize(
@JacksonInject
private val dependency: ThirdPartyUndeserializableObject
) {
@JsonPropery
private val simpleValue: String
/// ... etc
}
but doing so still results in jackson trying to manage the dependency prior to using the injected value (manifests as Invalid definition for property
since the class isn't json deserializable due to conflicting setters within the third party class). Adding a @JsonIgnore
doesn't appear to have any effect, either. Is there a way to do this?Fredrik Larsen
05/19/2021, 11:08 AMdata class Resource(
val fooInterval: Milliseconds,
val barInterval: Milliseconds?,
…
)
@JvmInline
value class Milliseconds(val units: Int)
The generated json for fooInterval
becomes
"fooInterval-kqdxTu8": 900,
And for the nullable property it becomes
"barInterval-OO-hnm0": {
"units": 900
}
The suffix comes from the generated type (value class) but It looks like a bug that it is used as part of the parameter name.
Any thoughts?Dariusz Kuc
05/21/2021, 9:49 PMkenkyee
06/28/2021, 2:43 PMmaxmello
08/18/2021, 2:21 PMdata class Example(@get:JsonProperty("element") val elements: List<Element> = listOf())
I remembered somehow that you need to add the get: part to a JsonProperty annotation such that it would be at the getter and not the field from Javas point of view, or else it woudn’t work right (which seems to be not the case after all), but this code above resulted in the following exception:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `int` from Array value (token `JsonToken.START_ARRAY`)
Now I strongly assume this is because List has a method get
with parameter of type Int
, but is this really how this annotation format should work? How would I even attach an annotation to the java getter in this case then?
I fixed it now by removing the get:, just curious 🤔Philipp Mayer
08/31/2021, 1:28 PMsealed class ApiResult {
data class Error(val errors: List<ApiError>) : ApiResult() {
data class ApiError(
val propertyName: String,
val errorMessage: String,
val errorCode: String,
)
}
}
And I want to serialize some response json into ApiResult.Error
.
The Json looks like that:
[
{
"propertyName": "...",
"errorMessage": "...",
"errorCode": "..."
}
]
So I have an object with holds a list of elements. Instantiating the object manually would look like that:
ApiResult.Error(objectMapper.readValue(""))
But I want to serialize directly into ApiResultError
.
Usually I would do something along the lines of:
class ApiErrors: ArrayList<ApiErrors.ApiError>() {
data class ApiError(
val propertyName: String,
val errorMessage: String,
val errorCode: String,
)
So, implementing the ArrayList. This does not work inside a sealed class.
Any idea? Thanks in advance!Dariusz Kuc
10/18/2021, 7:09 PMULocale
object to/from basic en_US
String)
Above works fine when used in separation but now I'm trying to figure out a way to do both at the same time, i.e. conditionally serialize custom objects. Registering a module that configures custom serializer for given custom type seems to work but that also implies additional setup by the users of the library (i.e. auto generated code is used to communicate with server). Anyone has any ideas whether this setup could be automated? Or maybe there are alternatives that I could use without module registration? There is an SPI that could be used to auto register modules but its usage is supposedly discouraged....martmists
10/31/2021, 6:23 PMenum class Language {
AmericanEnglish,
BritishEnglish,
Japanese,
French,
German,
LatinAmericanSpanish,
Spanish,
Italian,
Dutch,
CanadianFrench,
Russian,
Korean,
TraditionalChinese,
SimplifiedChinese,
Unknown
}
data class TitleName(
val language: Language,
val name: String,
val publisher: String
)
data class NACP(
val title: List<TitleName>,
// TODO: Add more
)
XML (simplified):
<?xml version="1.0" encoding="utf-8"?>
<Application>
<Title>
<Language>AmericanEnglish</Language>
<Name>Mario Party Superstars</Name>
<Publisher>Nintendo</Publisher>
</Title>
<Title>
<Language>BritishEnglish</Language>
<Name>Mario Party Superstars</Name>
<Publisher>Nintendo</Publisher>
</Title>
<Title>
<Language>Japanese</Language>
<Name> ̄デ ̄テᆰ ̄ツᆰ ̄テム ̄テᄐ ̄テニ ̄ツᆪ  ̄ツᄍ ̄テᄐ ̄テム ̄テᄐ ̄ツᄍ ̄ツ ̄テᄐ ̄ツᄎ</Name>
<Publisher>Nintendo</Publisher>
</Title>
</Application>
Code:
val parser = XmlMapper.builder()
.addModule(
KotlinModule.Builder()
// Defaults
.withReflectionCacheSize(512)
.configure(KotlinFeature.NullToEmptyCollection, false)
.configure(KotlinFeature.NullToEmptyMap, false)
.configure(KotlinFeature.NullIsSameAsDefault, false)
.configure(KotlinFeature.SingletonSupport, false)
.configure(KotlinFeature.StrictNullChecks, false)
.build()
)
// Defaults
.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false)
.configure(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS, false)
.build()
parser.readValue<NACP>(xml)
// => com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `TitleName` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('AmericanEnglish')
thanksforallthefish
12/29/2021, 4:45 PMvalue class
with jackson?
fun main() {
val string = ObjectMapper().findAndRegisterModules()
.convertValue<Map<String, String>>(Value("any"))
println(string)
}
@JvmInline
value class Value(val value: String)
prints {value=any}
with jackson 2.12.5, but fails with jackson 2.13.0. error is
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `java.util.LinkedHashMap` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('any')
at [Source: UNKNOWN; byte offset: #UNKNOWN]
though https://github.com/FasterXML/jackson-module-kotlin/issues/464 makes me wonder if my expectation is wrong. my use case is the one marked as “broken”:
"broken": [ {"value":0}, {"value":0} ]
, though this is exactly what I wantrrva
01/17/2022, 6:16 PMdoubov
01/20/2022, 8:59 PMphil-t
03/03/2022, 4:48 PM@JsonAlias("data")
to two fields in my class so that I can have separate data classes representing the underlying data, but this doesn’t work - the alias seems to apply to one field or the other. I’ve tried these two methods so far but neither work:
data class MyResponse(
@JsonAlias("data")
val dataOne: dataClassOne?,
@JsonAlias("data")
val dataTwo: dataClassTwo?
)
data class MyResponse(
@JsonAlias("data")
val dataOne: dataClassOne?, val dataTwo: dataClassTwo?
)
Is it possible to apply the alias to both fields so that the data will be deserialised to one or the other, or should I go back to using a separate class for each schema?phil-t
05/06/2022, 3:22 PM"types": {
"10003327": {
"typeNumber": 11,
"classNumber": 335,
"display": 0,
"max": "2000",
"name": "My type"
}
},
The number 10003327
could be different in each response. If I was to use the data classes below I think it would work only for this example, but in another response with a different number it wouldn’t work:
data class Response(
val types: NumberType
)
data class NumberType(
@JsonProperty("10003327") val typeField: Type
)
data class Type(
val typeNumber: Int,
val classNumber: Int,
val display: Int,
val max: String,
val name: String
)
Is there a way to deserialise this completely when you don’t know what the number of the field will be, maybe with another annotation?Sam
07/13/2022, 8:11 AMrrva
08/25/2022, 10:14 AMRob Elliot
10/24/2022, 10:28 AM@JsonValue
work when the property is nullable and the json has null as the value?Fredrik Rødland
10/28/2022, 10:42 AMend_exclusive
. We have clients which are not able to update kotlin as easily (apps in the wild). They now get the following error:
Unrecognized field "end_exclusive" (class kotlin.ranges.IntRange), not marked as ignorable (2 known properties: "start", "end"
Does anybody know of a nice work-around for this. we thought about implementing our own small dataclass on the serverside which adhers to the IntRange
api of kotlin <= 1.7.10, but it's seems kinda hacky...Adam Firen
11/09/2022, 6:58 PMEric
01/03/2023, 5:03 PMEric
01/11/2023, 6:57 PMapplication.yaml
? for example
spring:
jackson:
kotlin:
null-to-empty-collection: true
null-to-empty-map: true
null-is-same-as-default: true
wrongwrong
01/14/2023, 4:07 PMwrongwrong
01/21/2023, 2:15 AMkotlin-reflect
with kotlinx-metadata-jvm
would benefit jackson-module-kotlin
users on Android
, please let me know.
https://kotlinlang.slack.com/archives/C0B8M7BUY/p1674267151483919wrongwrong
03/19/2023, 3:19 PMwrongwrong
03/19/2023, 3:19 PM