I have written a custom JsonDeserializer
which contains an autowired service, as follows:
public class PersonDeserializer extends JsonDeserializ
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;
}
cleanup to the above answer using spring boot,
@Bean
public HandlerInstantiator handlerInstantiator(ApplicationContext context) {
return new SpringHandlerInstantiator(context.getAutowireCapableBeanFactory());
}
@Bean
public ObjectMapper objectMapper(HandlerInstantiator handlerInstantiator) {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.handlerInstantiator(handlerInstantiator);
return builder.build();
}
As suggested in this comment and found on this link you need to create custom HandlerInstantiator:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.KeyDeserializer;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.cfg.HandlerInstantiator;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.jsontype.TypeIdResolver;
import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder;
@Component
public class SpringBeanHandlerInstantiator extends HandlerInstantiator {
private ApplicationContext applicationContext;
@Autowired
public SpringBeanHandlerInstantiator(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public JsonDeserializer<?> deserializerInstance(DeserializationConfig config,
Annotated annotated,
Class<?> deserClass) {
try {
return (JsonDeserializer<?>) applicationContext.getBean(deserClass);
} catch (Exception e) {
// Return null and let the default behavior happen
}
return null;
}
@Override
public KeyDeserializer keyDeserializerInstance(DeserializationConfig config,
Annotated annotated,
Class<?> keyDeserClass) {
try {
return (KeyDeserializer) applicationContext.getBean(keyDeserClass);
} catch (Exception e) {
// Return null and let the default behavior happen
}
return null;
}
@Override
public JsonSerializer<?> serializerInstance(SerializationConfig config, Annotated annotated, Class<?> serClass) {
try {
return (JsonSerializer<?>) applicationContext.getBean(serClass);
} catch (Exception e) {
// Return null and let the default behavior happen
}
return null;
}
@Override
public TypeResolverBuilder<?> typeResolverBuilderInstance(MapperConfig<?> config, Annotated annotated,
Class<?> builderClass) {
try {
return (TypeResolverBuilder<?>) applicationContext.getBean(builderClass);
} catch (Exception e) {
// Return null and let the default behavior happen
}
return null;
}
@Override
public TypeIdResolver typeIdResolverInstance(MapperConfig<?> config, Annotated annotated, Class<?> resolverClass) {
try {
return (TypeIdResolver) applicationContext.getBean(resolverClass);
} catch (Exception e) {
// Return null and let the default behavior happen
}
return null;
}
}
Custom ObjectMapper:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.cfg.HandlerInstantiator;
public class CustomObjectMapper extends ObjectMapper {
private static final long serialVersionUID = -8865944893878900100L;
@Autowired
ApplicationContext applicationContext;
public JamaxObjectMapper() {
// Problems serializing Hibernate lazily initialized collections? Fix here.
// HibernateModule hm = new HibernateModule();
// hm.configure(com.fasterxml.jackson.module.hibernate.HibernateModule.Feature.FORCE_LAZY_LOADING, true);
// this.registerModule(hm);
// Jackson confused by what to set or by extra properties? Fix it.
this.setSerializationInclusion(JsonInclude.Include.NON_NULL);
this.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
this.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
}
@Override
@Autowired
public Object setHandlerInstantiator(HandlerInstantiator hi) {
return super.setHandlerInstantiator(hi);
}
}
and register your custom ObjectMapper:
<bean id="jacksonObjectMapper" class="com.acme.CustomObjectMapper" />
<bean id="jacksonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="prefixJson" value="false" />
<property name="supportedMediaTypes" value="application/json" />
<property name="objectMapper" ref="jacksonObjectMapper" />
</bean>
At this moment you can use:
@JsonDeserialize(contentUsing=PersonDeserializer.class)
public void setPerson(Person person) {
...
}
... and personService will not be null.