Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Autowiring in JsonDeserializer: SpringBeanAutowiringSupport vs HandlerInstantiator

I have written a custom JsonDeserializer which contains an autowired service, as follows:

public class PersonDeserializer extends JsonDeserializer<Person> {

    @Autowired
    PersonService personService;

    @Override
    public Person deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {

        // deserialization occurs here which makes use of personService

        return person;
    }
}

When I first made use of this deserializer I was getting NPEs as personService was not being autowired. From looking at other SO answers (in particular, this one) it appears there is two ways of getting the autowiring to work.

Option 1 is to use SpringBeanAutowiringSupport within the constructor of the custom deserializer:

public PersonDeserializer() { 

    SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); 
}

Option 2 is to use a HandlerInstantiator and register it with my ObjectMapper bean:

@Component
public class SpringBeanHandlerInstantiator extends HandlerInstantiator {

    @Autowired
    private ApplicationContext applicationContext;

    @Override
    public JsonDeserializer<?> deserializerInstance(DeserializationConfig config, Annotated annotated, Class<? extends JsonDeserializer<?>> deserClass) {

        try {

            return (JsonDeserializer<?>) applicationContext.getBean(deserClass);

        } catch (Exception e) {

            // Return null and let the default behavior happen
            return null;
        }
    }
}

@Configuration  
public class JacksonConfiguration {

    @Autowired
    SpringBeanHandlerInstantiator springBeanHandlerInstantiator;

    @Bean
    public ObjectMapper objectMapper() {

        Jackson2ObjectMapperFactoryBean jackson2ObjectMapperFactoryBean = new Jackson2ObjectMapperFactoryBean();
        jackson2ObjectMapperFactoryBean.afterPropertiesSet();

        ObjectMapper objectMapper = jackson2ObjectMapperFactoryBean.getObject();

        // add the custom handler instantiator
        objectMapper.setHandlerInstantiator(springBeanHandlerInstantiator);

        return objectMapper;
    }
}

I have tried both options and they work equally well. Clearly option 1 is much easier as it's only three lines of code, but my question is: are there any disadvantages to using SpringBeanAutowiringSupport compared to the HandlerInstantiator approach? My application is going to be deserializing hundreds of objects per minute, if that makes any difference.

Any advice/feedback is appreciated.

like image 222
smilin_stan Avatar asked Feb 08 '15 11:02

smilin_stan


1 Answers

Adding to the Amir Jamak's answer, you don't have to create custom HandlerInstantiator as Spring has it already which is SpringHandlerInstantiator.

What you need to do is to hook it up to Jackson2ObjectMapperBuilder in Spring configuration.

@Bean
public HandlerInstantiator handlerInstantiator(ApplicationContext applicationContext) {
    return new SpringHandlerInstantiator(applicationContext.getAutowireCapableBeanFactory());
}

@Bean
public Jackson2ObjectMapperBuilder objectMapperBuilder(HandlerInstantiator handlerInstantiator) {
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
    builder.handlerInstantiator(handlerInstantiator);
    return builder;
}
like image 154
maxhuang Avatar answered Sep 22 '22 17:09

maxhuang