JsonDeserializer 中的 Autowiring: SpringBeanAutowiringSupport vs HandlerInstantiator

2022-09-02 14:00:30

我编写了一个包含自动连接服务的自定义,如下所示:JsonDeserializer

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;
    }
}

当我第一次使用这个反序列化器时,我得到了NPE,因为personService没有被自动连接。从其他SO答案(特别是这个答案)来看,似乎有两种方法可以使自动布线正常工作。

选项 1 是在自定义反序列化程序的构造函数中使用:SpringBeanAutowiringSupport

public PersonDeserializer() { 

    SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); 
}

选项 2 是使用 a 并将其注册到我的 bean:HandlerInstantiatorObjectMapper

@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;
    }
}

我尝试了这两种选择,它们同样有效。显然,选项1要容易得多,因为它只有三行代码,但我的问题是:与该方法相比,使用是否有任何缺点?我的应用程序将每分钟反序列化数百个对象,如果这有什么区别的话。SpringBeanAutowiringSupportHandlerInstantiator

任何建议/反馈是值得赞赏的。


答案 1

除了Amir Jamak的答案之外,您不必创建自定义的HandlerInstantiator,因为Spring已经拥有它,这就是SpringHandlerInstantiator。

您需要做的是在Spring配置中将其连接到Jackson2ObjectMapperBuilder。

@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;
}

答案 2

正如此评论中的建议并在此链接上找到的那样,您需要创建自定义处理程序实例:

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;
    }
}

自定义对象映射器:

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);
    }
}

并注册您的自定义对象映射器:

<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>

此时,您可以使用:

@JsonDeserialize(contentUsing=PersonDeserializer.class)
public void setPerson(Person person) {
    ...
}

...和 personService 将不会为 null。


推荐