概要
这几天,我们的系统里连续出现了2个故障,故障原因很简单。我们在domain里平增了一个get方法,但是这个get方法并不是一般JAVA Bean里的getter/setter.
对这个domain进行JSON序列化时,jackson抛出了null pointer异常。
如果在Jackson序列化时将REQUIRE_SETTERS_FOR_GETTERS 设置为true,可以解决这个问题。
原因 && 解决方法
产生这个问题的根本原因是,以上的两个常见的JSON序列化工具在序列化domain时,会调用domain里的所有get方法。
解决这个事情的解决方法有很多
- 最好不要在domain里写复杂的处理逻辑
- 写public方法时,需要做非空校验
- 写的public方法换一个名字,不以get 开头
对于jackson来说,最好的解决方法是,给ObjectMapper增加一个配置
objectMapper.configure(SerializationConfig.Feature.REQUIRE_SETTERS_FOR_GETTERS, true);
REQUIRE_SETTERS_FOR_GETTERS 的说明
如果这个配置为false时,只有存在对应的构造器、setter或者field时,才调用getter。代码里的注释是
/**
* Feature that determines whether getters (getter methods)
* can be auto-detected if there is no matching mutator (setter,
* constructor parameter or field) or not: if set to true,
* only getters that match a mutator are auto-discovered; if
* false, all auto-detectable getters can be discovered.
*<p>
* Feature is disabled by default for backwards compatibility
* reasons.
*
* @since 1.9
*/
REQUIRE_SETTERS_FOR_GETTERS(false),
测试代码
以上配置的测试代码是
public class JacksonTest extends TestCase{
private static ObjectMapper objectMapper;
Foo foo = new Foo();
@Test
public void testOriginMapper() throws Exception{
objectMapper = new ObjectMapper();
try {
objectMapper.writeValueAsString(foo);
failBecauseExceptionWasNotThrown(NullPointerException.class);
} catch (Exception e) {
assertThat(e).hasMessageContaining("NullPointerException");
}
}
@Test
public void testNoGetter() throws Exception{
objectMapper = new ObjectMapper();
objectMapper.configure(SerializationConfig.Feature.REQUIRE_SETTERS_FOR_GETTERS, true);
assertThat(objectMapper.writeValueAsString(foo)).isEqualTo("{\"name\":null,\"age\":null}");
}
}
class Foo {
String name;
Integer age;
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getTrimName() {
return name.trim();
}
}