概要
这几天,我们的系统里连续出现了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(); } }