一、问题描述
在使用jackson进行序列化时,报npe。最终定位到原因:有一个public方法是is开头的,该方法里调用的对象为null,导致序列化的时候出现npe。
二、问题复现
1、创建Tpp类
public class Tpp implements Serializable {
private String tppName;
private TppSrc reqSrc;
public String getTppName() {
return tppName;
}
public void setTppName(String tppName) {
this.tppName = tppName;
}
public TppSrc getReqSrc() {
return reqSrc;
}
public void setReqSrc(TppSrc reqSrc) {
this.reqSrc = reqSrc;
}
public boolean isAaaTpp() {
return tppName.equals("aaa");
}
public String cal() {
return null;
}
@Override
public String toString() {
return "Tpp{" +
"tppName='" + tppName + '\'' +
", reqSrc=" + reqSrc +
'}';
}
}
2、测试用例
@Test
public void test() {
Tpp tpp = new Tpp();
ObjectMapper mapper = new ObjectMapper();
try {
mapper.writeValueAsString(tpp);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
3、测试结果
com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: org.luo.test.jsontest.Tpp["aaaTpp"])
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:394)
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:353)
at com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:316)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:727)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:3905)
at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3219)
at org.luo.test.jsontest.JacksonTest.test22(JacksonTest.java:414)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: java.lang.NullPointerException
at org.luo.test.jsontest.Tpp.isAaaTpp(Tpp.java:37)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:688)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719)
... 28 more
三、问题定位
使用调试模式,最终定位到jackson的相关代码:
jackson在进行序列化时,会迭代类里的属性、方法(get和is开头的方法),获取要进行序列化的字段,在这个过程中,识别出Tpp类有3个属性:tppName,reqSrc,aaaTpp。如下图所示:
之后,在序列化的过程中,会通过反射调用者三个方法:
因此,当反射执行isAaaTpp()方法时,由于tppName字段是null,就出现了npe错误。
四、总结
在使用jackson进行序列化和反序列化时,要注意is和get开头的方法,序列化器会把这个方法名识别为一个字段,然后通过反射区执行这个方法,当这个房里里的字段没有初始化时,就会出现npe问题。