Contents

Jackson 中jsonmappingexception异常

1. 概述

在这个快速教程中,我们将分析没有 getter 的实体的编组以及Jackson JsonMappingException异常的解决方案。

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

这将允许在没有 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"));
}