Skip to content
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

Problems deserializing object when default values for constructor parameters are used #29

Closed
knes1 opened this issue May 15, 2016 · 10 comments

Comments

@knes1
Copy link

knes1 commented May 15, 2016

I'm having problems deserializing object when when default values for constructor parameters are used. Jackson is attempting to set a parameter that is missing in json to null in Kotlin even though the parameter has a default value. Here's the example that fails:

class KotlinJacksonTest {
    @Test
    fun testDeserialization() {
        val mapper = ObjectMapper()
        mapper.registerModule(KotlinModule())
        val test = mapper.readValue("""{"name": "bla"}""", TestObj::class.java)
        println(test)

    }
}

data class TestObj(val name: String, val other: String = "test")

Here's the stacktrace:

com.fasterxml.jackson.databind.JsonMappingException: Instantiation of [simple type, class TestObj] value failed: Parameter specified as non-null is null: method TestObj.<init>, parameter other

    at com.fasterxml.jackson.databind.deser.std.StdValueInstantiator.wrapException(StdValueInstantiator.java:399)
    at com.fasterxml.jackson.databind.deser.std.StdValueInstantiator.createFromObjectWith(StdValueInstantiator.java:231)
    at com.fasterxml.jackson.databind.deser.impl.PropertyBasedCreator.build(PropertyBasedCreator.java:135)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:442)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1099)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:296)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:133)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3736)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2726)
    at io.github.knes1.kotao.brew.KotlinJacksonTest.testDeserialization(KotlinJacksonTest.kt:17)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: java.lang.IllegalArgumentException: Parameter specified as non-null is null: method TestObj.<init>, parameter other
@apatrida
Copy link
Member

apatrida commented Jun 3, 2016

This would be hard to fix in Jackson since we cannot control the actual constructor call and it cannot call using the Kotlin reflection callBy way of invoking a method of constructor. I am working on Kotlin plugin for Jackson-Jr which WOULD be able to handle this.

The only way we can handle this is if Jackson has a way for a plugin to do the actual constructor invoke and gives a list of all known parameters that it has to pass in, @cowtowncoder is it possible to have an extension point to do the actual construction? I need to know the decided constructor or factory method, and the parameters to be passed in along with any names given for the parameter from the implicit naming part of the plugin. At that point I can identify which are missing and do the special call returning an instance.

Or the whole "here are the JSON properties I have, do something with them" step could be delegated to a plugin that can do a best fit match against constructor and properties and then ask for each one by the expected type and then do construction (which could be constructor + setting mutable properties).

@cowtowncoder
Copy link
Member

@apatrida Would this PR from jackson-databind -- FasterXML/jackson-databind#1224 -- be of any help here? It does give some control over to ValueInstantiator (and whoever calls it), and value instantiators are replaceable.

@apatrida
Copy link
Member

apatrida commented Jun 3, 2016

@cowtowncoder maybe, it looks like it is covering this type of case. I can quickly build on it to do default, nullable, and mixed model construction in Kotlin to find out. Is that on a SNAPSHOT build somewhere?

@cowtowncoder
Copy link
Member

@apatrida I think Travis has snapshot deploy enabled, but just in case I'll do explicit snapshot deploy now.

@apatrida
Copy link
Member

apatrida commented Jun 3, 2016

so these go to sonatype snapshots or where is the snapshot repo? (maybe it is in the pom.xml if I read it, along with the version pushed)

@cowtowncoder
Copy link
Member

@apatrida Should go to Sonatype I think, as per default config. I rely on local snapshot builds so I am bit ignorant on where automated builds (or just mvn deploy for default settings) go unfortunately.
Snapshot repo definitions do come from either jackson-parent, or ,more likely its parent oss-parent (poorly named, but within FasterXML github org)

@apatrida
Copy link
Member

apatrida commented Jun 4, 2016

I'm trying this out now...

@apatrida
Copy link
Member

apatrida commented Jun 4, 2016

Fixed, committing soon.

apatrida added a commit that referenced this issue Jun 4, 2016
@apatrida apatrida closed this as completed Jun 4, 2016
@martintreurnicht
Copy link

It would be cool if we could get this ported to 2.7.5

@apatrida
Copy link
Member

Depends if the patch FasterXML/jackson-databind#1224 can be backported to 2.7.x that this module change depends upon, @cowtowncoder / @michaelhixson?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants