-
Notifications
You must be signed in to change notification settings - Fork 175
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Using Kotlin Default Parameter Values when JSON value is null and Kotlin parameter type is Non-Nullable #130
Comments
I've also noticed that, an I think, if the I think that in some cases, |
I'm facing this issue in its more basic form. I have a non nullable no default value Kotlin |
I totally aggree with both @crypticmind and @gerob311. If i wanted myInteger to default to 0 in case of missing, i would have written : Please remove jackson-module-kotlin/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinValueInstantiator.kt Line 45 in c8d88c6
|
In my travels, I have discovered that enabling I've also discovered a slightly related case, which I'm not sure if it should be a separate ticket or not. If I declare something like |
I tried with |
@crypticmind Minor version of components should be the same, as compatibility across minor versions is not guaranteed (patch versions need not match). But often adjacent minor versions do work in some combinations. |
@cowtowncoder will do. Thank you for the heads up! |
It should do the trick. Too bad it's wrapped into a generic |
@gerob311 There is no type erasure. val prop = TestObject::class.memberProperties.single { it.name == "timesOfDay" }
println(prop.returnType)
//kotlin.collections.List<kotlin.String> |
Has anyone figured this out? or found a kotlin json marshaller that is a simple as GSON but respects default values? |
also curious about this. i am using a third party REST api which i have no control over and theoretically everything could be null...
the problem with this solution is a lot of boilerplate!. i gave a very simple example with only 1 variable, but in reality there are many more...
obviously the problem with this is that its kind of stupid to make every single variable nullable, expecially
ideally i would have this:
and if in the json i get from the server how can i go about achieving this? |
There are conflicts with various settings and picking one model. Kotlin itself does not treat For a non nullable type should we treat |
Your workaround for now is to remove the |
expected behavior (at least for me):
not a good solution as many developers are using 3rd party APIs which they have no control over |
This is coming up when trying to use Arrow's |
Hello, Is there a way to just ignore nulls during deserialization? Similar to how we have a @include(NON_NULLS) for serialization. |
@jmiecz Yes, Jackson 2.9 has https://medium.com/@cowtowncoder/jackson-2-9-features-b2a19029e9ff for an example of how it works. |
@cowtowncoder That does not work with Kotlin's data classes. I see an error being thrown saying a non-null value is being assigned to null. |
@jmiecz That may be (and if so, sounds like a possible bug in Kotlin module). But that is the mechanism that should work from general Jackson API perspective. It might make sense to file a separate issue showing intended working, based on how similar POJO works wrt |
@cowtowncoder Not really, with Kotlin's data class, you have to set the values or provide defaults (IE: data class someClass(@JsonProperty("test") someJson: String = "") ) Jackson isn't ignoring the setter (even though you config it to ignore it) and setting a value it shouldn't be setting (IE of json: { "test": null } ) |
Kotlin data class vals are creator parameters, not setters, so I suspect that's why marking setters as ignored doesn't have any effect. The data class will only have two constructors - one to specify every val, and an additional one to also indicate which vals should take their default value -- calling that from Java is quite painful, as I remember. Some issues above can be solved by having Jackson go through a data class (with lots of nullable values) as a builder, but if you need to do it a lot, that's going to feel like lots of boilerplate too. |
@jmiecz I think you may be misunderstanding what I am saying (or reading too much into naming): It may be that the way Kotlin runtime handles default values has effect on how jackson-databind/kotlin module need to use that information, but configuration of what should happen should come from |
Hey, is there any plans to fix it? For now my workaround - creating a separate constructor special for Jackson:
|
Another way to workaround when you don't have primitive types in constructors.
|
I am also facing the same issue with deserialization of csv data containing null/empty values. |
For me I fixed it, add var paramVal = if (!isMissing || paramDef.isPrimitive() || jsonProp.hasInjectableValueId()) {
buffer.getParameter(jsonProp) ?: return@forEachIndexed
} else {
jsonProp.valueDeserializer?.getNullValue(ctxt)
} I think it will be better if this behavior will be depend on @JsonSetter or another configurable. But in kotlin this behavior it should be by default. |
It would be possible for Kotlin-module-provided |
I just did a couple of tests ... source "{}" -> to be parsed as a) data class Foo(val s:String?="default", val i:Int?=100) Both cases get parsed properly ... a) source: {} b) source: {} tested with jackson 2.9.9 using the following configuration ...
Hope this helps. |
@bastman try parsed same like this Spoiler: you do not receive the expected result |
@NumezmaT , just tried your use case. I summed it up here: https://gist.github.com/bastman/94f6c8afb86edfaf6a302b990dcfe210 |
Cannot work, you have both constructors with the same JVM signature :( |
This issue is confusing because most of the cases are not represented as full test cases. The best way to state a case for something that is a bit hard to describe verbally is to provide a unit test you expect to pass that is not passing, in its entirety here. I think you would then find opposing unit tests that counter wanting this change as-is. This seems like something that must be configured to treat So to change the behavior, because obviously it is desired to have the option, it should be configurable, and not default behavior. |
Branch 2.10 now allows
|
@apatrida feel free to revert if this was a conflicting change taking things in wrong direction. |
@cowtowncoder I worked it out with an option, so it would not break expectations of people who want it enforced as-is, but allowing the flexibility for those who need it and cannot change their JSON to avoid the problem. We are good. |
Brilliant this worked thanks.
|
ObjectMapper()
.registerKotlinModule()
.registerModules(
Builder()
.enable(NullIsSameAsDefault)
.build()
) |
This does not work for me with Here is a simple example: fun main() {
val mapper = jacksonObjectMapper()
val component = Component()
val json = mapper.writeValueAsString(component)
println(json) // {} works correctly
println(mapper.readValue<Component>(json)) // fails
}
class Component(
random: Random = Random
) The failure:
It does work however with the following example: class Component(
id: String = UUID.randomUUID().toString()
) |
On
|
This works fine in 2.15. Thanks for the answer!!! |
Any update on this? Am I doing something wrong or is this a bug? |
@alturkovic After checking that the problem exists in latest version (2.17.2), you may want to file a new issue for remaining problem (closed issues are rarely if ever re-opened if marked as fixed in release notes), with reference to this issue for background. If so, make sure to include full stand-alone reproduction of the issue. |
I've got the following simplified JSON example, which I'm trying to decode into the simplified Kotlin Data Class below.
The key thing here is that the Kotlin properties are not nullable, but there is a known default value for them. However, the JSON sometimes contains
null
for those fields.I am trying to get the example JSON to decode using the default values in place of the nulls since the type is non-nullable. However, this doesn't work out of the box, instead throwing a
MissingKotlinParameterException
.I had a look at modifying the code with a feature flag to behave the way I wanted. This was easy enough to do with some minor alterations to
createFromObjectWith()
inKotlinValueInstantiator
for theString
case. However, for theBoolean
case it does not work, as in Java, that non-optional Boolean becomes aboolean
primitive type, which cannot takenull
and thus Jackson Data Binding sets it with the default value offalse
.So, assuming I haven't missed the point completely with this, I'm wondering if there's a way in the
KotlinValueInstantiator
to know that the primitive types were set with their default values by Jackson Data Binding in order to make this work for primitive types too?The text was updated successfully, but these errors were encountered: