如何定义自定义ObjectMapper bean而不覆盖Spring Boot使用的bean

时间:2018-03-06 19:53:54

标签: java spring-boot jackson

我有一个包含多个@RestController类的Spring Boot Web应用程序。 我喜欢我的REST控制器返回的默认json格式。

为了在我的DAO bean(使用json序列化和反序列化)中使用,我创建了一个自定义ObjectMapper

@Configuration
public class Config{

  @Bean
  public ObjectMapper getCustomObjectMapper() {
    final ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    objectMapper.setPropertyNamingStrategy(new PropertyNamingStrategy.SnakeCaseStrategy());
    return objectMapper;
  }
}

在我的每个DAO课程中,我都会自动调整我的自定义ObjectMapper

@Repository
@Transactional
public class MyDaoImpl implements MyDao {

@Autowired
ObjectMapper objectMapper

//Dao implementation...

}

一切正常。问题是我的自定义ObjectMapper被Spring自动选中并用于序列化REST响应 这是不可取的。对于REST控制器,我想保留Spring默认创建的ObjectMapper

如何判断Spring Boot 检测并使用我的自定义ObjectMapper bean进行内部工作?

4 个答案:

答案 0 :(得分:1)

您可以提供标准的ObjectMapper和自定义对象映射器,并将标准设置为df.loc[df.B.ne('one'),['B','D']] Out[207]: B D 2 two 0.742752 3 three -1.264271 4 two -0.112787 5 two 0.667358 7 three -0.213575

然后为您的自定义ObjectMapper命名,并将其与@Qualifier注释一起使用。

@Primary

现在您可以引用自定义映射器

@Configuration
public class Config{

  //This bean will be selected for rest
  @Bean
  @Primary
  public ObjectMapper stdMapper(){
     return new ObjectMapper();
  }

  //You can explicitly refer this bean later
  @Bean("customObjectMapper")
  public ObjectMapper getCustomObjectMapper() {
    final ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    objectMapper.setPropertyNamingStrategy(new PropertyNamingStrategy.SnakeCaseStrategy());
    return objectMapper;
  }
}
  

@Repository @Transactional public class MyDaoImpl implements MyDao { @Autowired @Qualifier("customObjectMapper") ObjectMapper objectMapper //Dao implementation... } 将同时执行@Autowired和@Resource("custonmObjectMapper")

答案 1 :(得分:0)

您可以创建:

public class MapperUtils {

    private static final ObjectMapper mapper = new ObjectMapper();

    public static <T> T parseResponse(byte[] byteArrray, Class<T> parseType) throws JsonParseException, JsonMappingException, IOException {
        return mapper.readValue(byteArrray, parseType);
    }
}

ObjectMapper是线程安全的。但是,由于性能问题(Should I declare Jackson's ObjectMapper as a static field?),有些人不鼓励使用单个实例。

答案 2 :(得分:0)

由于我不想触摸Spring的默认ObjectMapper,因此无法创建@Primary ObjectMapper来遮盖Spring的默认ObjectMapper

相反,我最终要做的是创建一个BeanFactoryPostProcessor,它在Spring的上下文中注册了一个自定义的非主要ObjectMapper

@Component
public class ObjectMapperPostProcessor implements BeanFactoryPostProcessor {

public static final String OBJECT_MAPPER_BEAN_NAME = "persistenceObjectMapper";

@Override
public void postProcessBeanFactory(final ConfigurableListableBeanFactory beanFactory) {
    final AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
        .genericBeanDefinition(ObjectMapper.class, this::getCustomObjectMapper)
        .getBeanDefinition();
    // Leave Spring's default ObjectMapper (configured by JacksonAutoConfiguration)
    // as primary
    beanDefinition.setPrimary(false);
    final AutowireCandidateQualifier mapperQualifier = new AutowireCandidateQualifier(PersistenceObjectMapper.class);
    beanDefinition.addQualifier(mapperQualifier);
    ((DefaultListableBeanFactory) beanFactory).registerBeanDefinition(OBJECT_MAPPER_BEAN_NAME, beanDefinition);
}

private ObjectMapper getCustomObjectMapper() {
    final ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    objectMapper.setPropertyNamingStrategy(new PropertyNamingStrategy.SnakeCaseStrategy());
    return objectMapper;
}
}

从上面的代码中可以看出,我还为自定义ObjectMapper bean分配了一个限定符。
我的限定词是一个用@Qualifier注释的注释:

@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface PersistenceObjectMapper {
}

然后我可以使用我的自定义注释自动为我的自定义ObjectMapper接线,

@Repository
public class MyDao {
@Autowired
public MyDao(DataSource dataSource, @PersistenceObjectMapper ObjectMapper objectMapper) {
// constructor code
}

答案 3 :(得分:0)

Simone Pontiggia 答案是正确的方向。您应该创建一个 @Primary bean,Spring将在其内部使用它,然后创建自己的ObjectMapper bean,并使用 @Qualifier 将它们自动连线。

这里的问题是,创建默认的bean像这样:

@Bean
@Primary
public ObjectMapper objectMapper() {
    return new ObjectMapper();
}

实际上无法按预期工作,因为Spring默认的ObjectMapper具有其他配置。 创建将由spring使用的默认ObjectMapper的正确方法是:

@Bean
@Primary
public ObjectMapper objectMapper() {
    return Jackson2ObjectMapperBuilder.json().build();
}

您可以在以下位置找到有关Spring默认ObjectMapper的更多信息:https://docs.spring.io/spring-boot/docs/current/reference/html/howto-spring-mvc.html 79.3 Customize the Jackson ObjectMapper