1. 概述
在这个快速教程中,我们将分析没有getter方法的实体的序列化,并解决Jackson引发的JsonMappingException
异常。
如果你想深入了解Jackson 2的其他酷炫功能,请访问主Jackson教程。
2. 问题
默认情况下,Jackson 2只会处理公有字段或具有公有getter方法的字段。如果实体的所有字段都是私有或包内可见的,序列化将会失败:
public class MyDtoNoAccessors {
String stringValue;
int intValue;
boolean booleanValue;
public MyDtoNoAccessors() {
super();
}
// no getters
}
@Test(expected = JsonMappingException.class)
public void givenObjectHasNoAccessors_whenSerializing_thenException()
throws JsonParseException, IOException {
String dtoAsString = new ObjectMapper().writeValueAsString(new MyDtoNoAccessors());
assertThat(dtoAsString, notNullValue());
}
完整的异常如下:
com.fasterxml.jackson.databind.JsonMappingException:
No serializer found for class dtos.MyDtoNoAccessors
and no properties discovered to create BeanSerializer
(to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) )
3. 解决方案
显而易见的解决方案是为字段添加getter方法。如果实体在我们的控制范围内,这是可行的。如果不能修改实体的源代码,Jackson提供了几种备选方案。
3.1. 全局自动检测任何可见性的字段
对于这个问题的一个解决方案是全局配置ObjectMapper
,使其检测所有字段,不论其可见性:
objectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
这将允许Jackson检测到没有getter方法的私有和包内可见字段,从而实现正确的序列化:
@Test
public void givenObjectHasNoAccessors_whenSerializingWithAllFieldsDetected_thenNoException()
throws JsonParseException, IOException {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
String dtoAsString = objectMapper.writeValueAsString(new MyDtoNoAccessors());
assertThat(dtoAsString, containsString("intValue"));
assertThat(dtoAsString, containsString("stringValue"));
assertThat(dtoAsString, containsString("booleanValue"));
}
3.2. 在类级别控制字段可见性
Jackson 2还提供了另一种选择,即通过@JsonAutoDetect
注解在类级别控制字段可见性:
@JsonAutoDetect(fieldVisibility = Visibility.ANY)
public class MyDtoNoAccessors { ... }
使用这个注解,这个特定类的序列化现在应该可以正常工作:
@Test
public void givenObjectHasNoAccessorsButHasVisibleFields_whenSerializing_thenNoException()
throws JsonParseException, IOException {
ObjectMapper objectMapper = new ObjectMapper();
String dtoAsString = objectMapper.writeValueAsString(new MyDtoNoAccessors());
assertThat(dtoAsString, containsString("intValue"));
assertThat(dtoAsString, containsString("stringValue"));
assertThat(dtoAsString, containsString("booleanValue"));
}
4. 在Jackson中禁用fail_on_empty_beans
在Jackson中,fail_on_empty_beans
特性决定了在序列化过程中遇到空对象(没有属性)时是否抛出异常。默认情况下,Jackson会遇到空bean时抛出异常。
值得注意的是,fail_on_empty_beans
特性默认启用,若要禁用它,我们需要明确设置为false
。具体方法取决于我们的具体用例。
4.1. 使用ObjectMapper配置
我们可以直接在ObjectMapper
上禁用fail_on_empty_beans
:
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
通过这种方式配置ObjectMapper
,我们告诉Jackson在序列化过程中遇到空bean时不抛出异常。
4.2. 使用Spring Boot
在Spring Boot中,我们可以在application.properties
文件中设置以下属性以全局禁用fail_on_empty_beans
:
spring.jackson.serialization.FAIL_ON_EMPTY_BEANS=false
这个属性可以在应用级别设置,以控制Jackson序列化在整个应用中的行为。
5. 总结
本文说明了如何绕过Jackson中的默认字段可见性,通过全局配置ObjectMapper
或在单个类上进行定制。Jackson提供了更深入的自定义选项,允许我们精确控制getter、setter或特定可见性字段被映射器看到的方式。
所有示例和代码片段的实现可以在我的GitHub项目中找到:GitHub项目 - 这是一个基于Eclipse的项目,导入并运行起来非常方便。