`@JsonInject` fails on trying to find deserializer even if inject-only
See original GitHub issue@JsonInject
tries to “process” the injected class for deserialization even though it is not deserialized. As a result, you may get errors if the class is not suitable for deserialization, e.g., two getters with the same name but different signature. Jackson 2.6.1.
The following code fails as is - stack trace below - but works if you comment out one of the setA
methods on class InjectMe
. (Uses TestNG, AssertJ.)
(I believe it is probably a common use case that you might use @JsonInject
to inject instances of classes from your application environment that you never expect to serialize/deserialize. They may very well have multiple setters with the same name but different signature. ObjectMapper
itself is like this: that’s how I discovered this issue.)
import java.io.IOException;
import org.testng.annotations.Test;
import com.fasterxml.jackson.annotation.JacksonInject;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.InjectableValues;
import com.fasterxml.jackson.databind.ObjectMapper;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.StrictAssertions.fail;
public class TestInject
{
public static class InjectMe
{
private String a;
public void setA(String a) {
this.a = a;
}
public void setA(Integer a) {
this.a = a.toString();
}
public String getA() {
return a;
}
}
public static class Injectee
{
private String b;
@JsonCreator
public Injectee(@JacksonInject InjectMe injectMe, @JsonProperty("b") String b) {
this.b = b;
}
public String getB() {
return b;
}
}
@Test
public void injected() {
// ARRANGE
InjectMe im = new InjectMe();
ObjectMapper sut = new ObjectMapper()
.setInjectableValues(new InjectableValues.Std().addValue(TestInject.InjectMe.class, im));
String test = "{\"b\":\"bbb\"}";
// ACT
Injectee actual = null;
try {
actual = sut.readValue(test, Injectee.class);
}
catch (IOException e) {
fail("failed to deserialize", e);
}
// ASSERT
assertThat(actual.getB()).isEqualTo("bbb");
}
}
Stacktrace:
FAILED: injected
java.lang.AssertionError: failed to deserialize
at com.ispot.TestInject.injected(TestInject.java:64)
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.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:85)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:639)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:821)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1131)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:124)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:108)
at org.testng.TestRunner.privateRun(TestRunner.java:773)
at org.testng.TestRunner.run(TestRunner.java:623)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:357)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:352)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:310)
at org.testng.SuiteRunner.run(SuiteRunner.java:259)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1185)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1110)
at org.testng.TestNG.run(TestNG.java:1018)
at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:111)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:204)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:175)
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Conflicting setter definitions for property "a": com.ispot.TestInject$InjectMe#setA(1 params) vs com.ispot.TestInject$InjectMe#setA(1 params)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:269)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
at com.fasterxml.jackson.databind.DeserializationContext.findContextualValueDeserializer(DeserializationContext.java:428)
at com.fasterxml.jackson.databind.deser.impl.PropertyBasedCreator.construct(PropertyBasedCreator.java:79)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.resolve(BeanDeserializerBase.java:549)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:296)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:461)
at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:3804)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3698)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2714)
at com.ispot.TestInject.injected(TestInject.java:61)
... 24 more
Caused by: java.lang.IllegalArgumentException: Conflicting setter definitions for property "a": com.ispot.TestInject$InjectMe#setA(1 params) vs com.ispot.TestInject$InjectMe#setA(1 params)
at com.fasterxml.jackson.databind.introspect.POJOPropertyBuilder.getSetter(POJOPropertyBuilder.java:299)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.filterBeanProps(BeanDeserializerFactory.java:592)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.addBeanProps(BeanDeserializerFactory.java:488)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:229)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:142)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer2(DeserializerCache.java:403)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:352)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:264)
... 37 more
Issue Analytics
- State:
- Created 8 years ago
- Comments:15 (10 by maintainers)
Top GitHub Comments
OK. The workaround turned out to be trivial, once I thought of it - use a mixin. I just add this module to my mapper:
Now I can inject my class which has a property that returns an
ObjectMapper
.@devinrsmith Thank you! This took a while… but better late than never. 😃