jackson-module-kotlin: @JsonUnwrapped fails if parameter is non-nullable
I’ve made a commit onto my fork that demonstrates an error I’ve been trying to resolve for the whole day. It seems that JsonUnwrapped doesn’t work with non-nullable values.
If you run my commit, you’ll see that the first Boom
does not fail, as Bomb?
allows for null values (which are needed for some reason?), while Boom2
fails, with the error:
com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException: Instantiation of [simple type, class com.fasterxml.jackson.module.kotlin.test.TestCasesFromSlack1$Boom2] value failed for JSON property value due to missing (therefore NULL) value for creator parameter value which is a non-nullable type
at [Source:
{
"word": "HI"
}
; line: 4, column: 13] (through reference chain: com.fasterxml.jackson.module.kotlin.test.TestCasesFromSlack1$Boom2["value"])
at com.fasterxml.jackson.module.kotlin.KotlinValueInstantiator.createFromObjectWith(KotlinValueInstantiator.kt:44)
at com.fasterxml.jackson.databind.deser.impl.PropertyBasedCreator.build(PropertyBasedCreator.java:138)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeUsingPropertyBasedWithUnwrapped(BeanDeserializer.java:779)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeWithUnwrapped(BeanDeserializer.java:605)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:309)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:148)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3837)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2899)
at com.fasterxml.jackson.module.kotlin.test.TestCasesFromSlack1.testCzarSpringThing1(TestCasesFromSlack.kt:87)
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:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
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:147)
In addition, I’m running a test in my code that looks like this
public class JsonDeserializationTest
{
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
@Test
public void allClassesUsedByOurControllersShouldBeDeserializableByJackson() throws Exception
{
assertCanBeMapped(OSValueObject.class);
......
assertCanBeMapped(MoreValueObject.class);
}
private void assertCanBeMapped(Class<?> classToTest)
{
String message =
String.format("%s is not deserialisable, check the swallowed exception in StdDeserializerProvider.hasValueDeserializerFor",
classToTest.getSimpleName());
converter.getObjectMapper().findAndRegisterModules();
assertThat(message, converter.canRead(classToTest, MediaType.APPLICATION_JSON), is(true));
}
}
which fails if I don’t include @param:JsonProperty("data")
on the element, like so:
data class OSValueObject(
val oneId: OneId,
val twoId: TwoId,
@param:JsonProperty("details") @JsonUnwrapped val details: Details?
)
Error message:
java.lang.AssertionError: OSValueObject is not deserialisable, check the swallowed exception in StdDeserializerProvider.hasValueDeserializerFor
Expected: is <true>
but: was <false>
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
at com.company.loanapp.JsonDeserializationTest.assertCanBeMapped(JsonDeserializationTest.java:72)
at com.company.loanapp.JsonDeserializationTest.allClassesUsedByOurControllersShouldBeDeserializableByJackson(JsonDeserializationTest.java:59)
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.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
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:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
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:147)
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Reactions: 1
- Comments: 15 (6 by maintainers)
Links to this issue
Commits related to this issue
- cover Github #50 with test case, marked ignored because cannot be resolved yet. — committed to FasterXML/jackson-module-kotlin by apatrida 6 years ago
@cowtowncoder yes, it is possible, less idiomatic but just fine. Will close now.
I can reproduce error with following data classes and json:
data class Name (val firstName: String, val lastName: String)
data class Employee ( @get:JsonProperty(“useless”) @get:JsonUnwrapped val name: Name, val position: String )
JSON: {“firstName”:“John”,“lastName”:“Smith”,“position”:“Manager”}
I’m using version 2.8.4 of jackson-kotlin-module.
I’ve found workaround:
data class Name(val firstName: String, val lastName: String)
val JACKSON_WORKAROUND = Name(“”, “”)
data class Employee( @get:JsonProperty(“name”) @get:JsonUnwrapped val name: Name = JACKSON_WORKAROUND, val position: String )