Custom Jackson deserializer doesn’t inject into @Autowired fields

I’m trying to inject my config into my custom StdDeserializer. The problem however is, even though I marked the class as @Component, the value of the field is never injected. The injection works without any problems in the other places of the application.

Therefore, I’ve come to the conclusion that the problem is with the way the deserializer is working, since it doesn’t get instantiated by us but rather like the example down here:

ClassToDeserialize myClass = new ObjectMapper().readValue(mockJson, ClassToDeserialize.class);

As you can see there is no explicit usage of my custom deserializer ClassToDeserializeDeserializer hence it detects the classes with the custom deserializer with the @JsonDeserialize(using = ClassToDeserialize.class) annotation.

Class that should be deserialized

@Data
@AllArgsConstructor
@SuperBuilder
@JsonDeserialize(using = MyClassDeserializer.class)
public class MyClass{
  private final String field1;
  private final String field2;
}

Config class that should be injected

@Configuration
@ConfigurationProperties(prefix = "myconfig")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class MyConfig {
   private final String confField1;
   private final String confField2;
}

MyClass’s custom deserializer:

@Component
public class MyClassDeserializer extends StdDeserializer<MyClass> {

    @Autowired
    MyConfig myConfig;

    public MyClassDeserializer () {
        this(null);
    }

    public MyClassDeserializer (Class<?> vc) {
        super(vc);
    }

    @Override
    public MyClassDeserializer deserialize(JsonParser parser, DeserializationContext context)
            throws IOException, JsonProcessingException {

         //Deserializing code that basically tries to read from myConfig
         myConfig.getConfField1(); //Hello NullPointerException my old friend
    }

}

Usage of the deserializer

MyClass myClass = new ObjectMapper().readValue(mockJson, MyClass.class);

Answer

Reason why it doesn’t work:

Jackson doesn’t know anything about Spring Boot stuff, so when you readValue(..) Jackson sees @JsonDeserialize annotation with deserializer class and creates new instance of the deserializer (it doesn’t pick up the bean, but rather just new MyClassDeserializer(..)), that is why you never see MyConfig being injected.

If you want to make it work, you need to somehow register this deserializer through Spring Boot, for example, like this: How to provide a custom deserializer with Jackson and Spring Boot

Leave a Reply

Your email address will not be published. Required fields are marked *