问题描述
本次遇到问题时所使用的框架是Spring Boot,处理完请求之后,返回数据之前,在POJO转化成JSON时,有些属性违背输出规则或者有些属性循环引用会造成无法输出。
报错信息:org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: No serializer found for class java.lang.Object and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS); nested exception is com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class java.lang.Object and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
部分代码片段:
@Override
public ReviewReportDto getReviewReport(String requestId) {
ReviewReportDto resDto = new ReviewReportDto();
...
...
//Object对象实例导致序列化错误
resDto.setOffLineDto(new Object());
return resDto;
}
当然解决方式有很多种,在最初版本的代码开发过程中,由于部分业务的缺失,暂时把空位补上new Object(),而其表示的其实就是null(空对象),导致序列化时报错。
解决方法
- 第一种方法:
直接把new Object()替换为null,即可解决序列化错误问题。 - 第二种方法
通过设置,使Jackson遇到空对象不抛异常。
@Bean("objectMapper")
public ObjectMapper myMapper() {
return new ObjectMapper().disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
}
- 第三种方法(spring mvc项目)
通过xml配置自定义类来覆盖默认配置
//自定义类
public class MyMapper extends ObjectMapper {
public MyMapper() {
configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);
}
}
<!-- xml-springMVC 配置 -->
<mvc:annotation-driven>
<mvc:message-converters>
...
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
...
<!-- 配置自定义的objectMapper -->
<property name="objectMapper">
<bean class="com.myPackage.MyMapper">
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
序列化过程配置的规整
此处贴出SerializationFeature的源码,以及对部分常用配置方式的总结:
package com.fasterxml.jackson.databind;
import com.fasterxml.jackson.databind.cfg.ConfigFeature;
public enum SerializationFeature implements ConfigFeature {
//是否环绕根元素,默认false,如果为true,则默认以类名作为根元素。根元素名称也可以通过@JsonRootName来自定义。
WRAP_ROOT_VALUE(false),
//是否缩放排列输出,默认false,有些场合为了便于排版阅读则需要对输出做缩放排列
INDENT_OUTPUT(false),
//遇到空对象则失败
FAIL_ON_EMPTY_BEANS(true),
//自我引用则失败
FAIL_ON_SELF_REFERENCES(true),
//com.fasterxml.jackson.annotation.JsonUnwrapped包下相关联的类将会抛出异常
WRAP_EXCEPTIONS(true),
FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS(true),
CLOSE_CLOSEABLE(false),
FLUSH_AFTER_WRITE_VALUE(true),
WRITE_DATES_AS_TIMESTAMPS(true),
//序列化日期时以timestamps输出,默认true
WRITE_DATE_KEYS_AS_TIMESTAMPS(false),
WRITE_DATES_WITH_ZONE_ID(false),
WRITE_DURATIONS_AS_TIMESTAMPS(true),
//序列化char[]时以json数组输出,默认false
WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS(false),
//序列化枚举是以toString()来输出,默认false,即默认以name()来输出
WRITE_ENUMS_USING_TO_STRING(false),
//序列化枚举是以ordinal()来输出,默认false
WRITE_ENUMS_USING_INDEX(false),
WRITE_NULL_MAP_VALUES(true),
/** @deprecated */
@Deprecated
WRITE_EMPTY_JSON_ARRAYS(true),
//序列化单元素数组时不以数组来输出,默认false
WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED(false),
/** @deprecated */
@Deprecated
//序列化BigDecimal时之间输出原始数字还是科学计数,默认false,即是否以toPlainString()科学计数方式来输出
WRITE_BIGDECIMAL_AS_PLAIN(false),
WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS(true),
//序列化Map时对key进行排序操作,默认false
ORDER_MAP_ENTRIES_BY_KEYS(false),
EAGER_SERIALIZER_FETCH(true),
USE_EQUALITY_FOR_OBJECT_ID(false);
private final boolean _defaultState;
private final int _mask;
private SerializationFeature(boolean defaultState) {
this._defaultState = defaultState;
this._mask = 1 << this.ordinal();
}
public boolean enabledByDefault() {
return this._defaultState;
}
public int getMask() {
return this._mask;
}
public boolean enabledIn(int flags) {
return (flags & this._mask) != 0;
}
}
By the way:引用请标明出处。如有错误,请批评指正。