question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

`@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:closed
  • Created 8 years ago
  • Comments:15 (10 by maintainers)

github_iconTop GitHub Comments

2reactions
david-bakincommented, Oct 30, 2015

OK. The workaround turned out to be trivial, once I thought of it - use a mixin. I just add this module to my mapper:

    @JsonIgnoreType
    private static class IgnoreMe {  };

    public Module getIgnoreJacksonModule() {
        return new SimpleModule().setMixInAnnotation(ObjectMapper.class, IgnoreMe.class);
    }

Now I can inject my class which has a property that returns an ObjectMapper.

0reactions
cowtowncodercommented, Apr 16, 2020

@devinrsmith Thank you! This took a while… but better late than never. 😃

Read more comments on GitHub >

github_iconTop Results From Across the Web

SUSE alert SUSE-SU-2022:1678-1 (jackson-databind ...
... case-insensitive deserialization + '@JsonInject' fails on trying to find deserializer even if inject-only + Polymorphic deserialization ...
Read more >
Custom Jackson deserializer doesn't inject into @Autowired ...
The problem however is, even though I marked the class as @Component , the value of the field is never injected. The injection...
Read more >
Using @JacksonInject to inject values during deserialization
@JacksonInject annotation is used to indicate that value of annotated property will be injected during deserialization. This is useful if we ...
Read more >
Graceful Error Handling/Collection on Databind (2.9.0.pr2)
I'm looking to simply return null and add errors to a Map<JsonPointer,Exception> from all JsonDeserializer<?> instances when a JsonMappingException is ...
Read more >
Jackson Annotations for JSON (Part 3): Deserialization - DZone
Use this annotation when your JSON property names are different to the fields of the Java object class, and you want to map...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found