WebService CXF系列: CXF JaxRS 使用Jackson进行序列化和反序列化的注意事项

介绍

  • 在公司使用WebService CXF的JaxRS集成 Jackson时遇到一个问题:对JSON进行反序列化时,报错信息如下:
    Unrecognized field “request” (class com.value.jaxrs.bean.RequestInfo), not marked as ignorable (one known property: “user”])

原因跟踪

JaxRs配置类中引入Jackson的内容

JacksonJaxbJsonProvider

@Configuration
public class JaxRsConfig {

    @Autowired
    private SpringBus bus;

    @Bean
    public Server jaxRsServer() {
        JAXRSServerFactoryBean rsEndpoint = new JAXRSServerFactoryBean();
        rsEndpoint.setBus(bus);
        rsEndpoint.setAddress("/rest/");
        rsEndpoint.setProviders(Arrays.asList(jacksonJaxbJsonProvider()));
        rsEndpoint.setFeatures(Arrays.asList(new LoggingFeature()));
        rsEndpoint.setServiceBeans(Collections.singletonList(new HelloServiceImpl()));
        return rsEndpoint.create();
    }

    /**
     * 配置一个对象与json转换的工具
     */

    @Bean
    public JacksonJaxbJsonProvider jacksonJaxbJsonProvider() {
        return new JacksonJaxbJsonProvider();
    }
}

分析JacksonJaxbJsonProvider源码

进一步跟踪new JacksonJaxbJsonProvider()的源码发现对Jackson的ObjectMapper没有引入,采用默认的;

@Provider
@Consumes(MediaType.WILDCARD) // NOTE: required to support "non-standard" JSON variants
@Produces(MediaType.WILDCARD)
public class JacksonJaxbJsonProvider extends JacksonJsonProvider {
    /**
     * Default annotation sets to use, if not explicitly defined during
     * construction: use Jackson annotations if found; if not, use
     * JAXB annotations as fallback.
     */
    public final static Annotations[] DEFAULT_ANNOTATIONS = {
        Annotations.JACKSON, Annotations.JAXB
    };
    /**
     * 默认构造函数,通常在提供程序被自动配置为与JAX-RS实现一起使用时使用
     */
    public JacksonJaxbJsonProvider()
    {
        this(null, DEFAULT_ANNOTATIONS);
    }
    /**
     * @param annotationsToUse Annotation set(s) to use for configuring
     *    data binding
     */
    public JacksonJaxbJsonProvider(Annotations... annotationsToUse)
    {
        this(null, annotationsToUse);
    }
    
    /**
	 * 在使用自定义映射器(通常是已配置的序列化器/反序列化器工厂等组件)时使用的构造函数。 	
     * 应该使用这个
     */
    public JacksonJaxbJsonProvider(ObjectMapper mapper, Annotations[] annotationsToUse)
    {
        super(mapper, annotationsToUse);
    }
}

所以我们分析需要使用第三个含参构造器。即 new JacksonJaxbJsonProvider(objectMapper, JacksonJaxbJsonProvider.DEFAULT_ANNOTATIONS);

解决方案

1. application.yml 增加jackson的相关配置

   spring:
	  jackson:
	    #日期格式化
	    date-format: yyyy-MM-dd HH:mm:ss
	    serialization:
	      #格式化输出
	      indent_output: true
	      #忽略无法转换的对象
	      fail_on_empty_beans: false
	      wrap_root_value: true
	    #设置空如何序列化
	    defaultPropertyInclusion: NON_EMPTY
	    deserialization:
	      #允许对象忽略json中不存在的属性
	      fail_on_unknown_properties: false
	      #反序列化带根对象
	      unwrap_root_value: true
	    parser:
	      #允许出现特殊字符和转义符
	      allow_unquoted_control_chars: true
	      #允许出现单引号
	      allow_single_quotes: true

2. JaxRsConfig 引入ObjectMapper

@Configuration
public class JaxRsConfig {

    @Autowired
    private SpringBus bus;

    /**
     * 引入Jackson的ObjectMapper
     */
    @Autowired
    private ObjectMapper objectMapper;

    @Bean
    public Server jaxRsServer() {
        JAXRSServerFactoryBean rsEndpoint = new JAXRSServerFactoryBean();
        rsEndpoint.setBus(bus);
        rsEndpoint.setAddress("/rest/");
        rsEndpoint.setProviders(Arrays.asList(jacksonJaxbJsonProvider()));
        rsEndpoint.setFeatures(Arrays.asList(new LoggingFeature()));
        rsEndpoint.setServiceBeans(Collections.singletonList(new HelloServiceImpl()));
        return rsEndpoint.create();
    }

    /**
     * 配置一个对象与json转换的工具
     */

    @Bean
    public JacksonJaxbJsonProvider jacksonJaxbJsonProvider() {
        return new JacksonJaxbJsonProvider(objectMapper, JacksonJaxbJsonProvider.DEFAULT_ANNOTATIONS);
    }
}

3. Jackson的第二种配置方式:创建Config类

@Configuration
public class JacksonConfig {

    @Bean
    @Primary
    @ConditionalOnMissingBean(ObjectMapper.class)
    public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder)
    {
        ObjectMapper objectMapper = builder.createXmlMapper(false).build();

        // 通过该方法对mapper对象进行设置,所有序列化的对象都将按改规则进行系列化
        // Include.Include.ALWAYS 默认
        // Include.NON_DEFAULT 属性为默认值不序列化
        // Include.NON_EMPTY 属性为 空("") 或者为 NULL 都不序列化,则返回的json是没有这个字段的。这样对移动端会更省流量
        // Include.NON_NULL 属性为NULL 不序列化
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
        objectMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
        objectMapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 允许出现特殊字符和转义符
        //
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
        // 允许出现单引号
        objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        // 字段保留,将null值转为""
        objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>()
        {
            @Override
            public void serialize(Object o, JsonGenerator jsonGenerator,
                                  SerializerProvider serializerProvider)
                    throws IOException
            {
                jsonGenerator.writeString("");
            }
        });
        return objectMapper;
    }
}

Jackson的反/序列化启用root对象配置

objectMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
objectMapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);

或者

spring:
  jackson:
    serialization:
      #序列化带root对象
      wrap_root_value: true
    deserialization:
      #反序列化带root对象
      unwrap_root_value: true
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值