最近调试程序时忽然出现异常,在使用jackson的方式objectMapper.writeValueAsString(obj)将java对象转换成json字符串时出现了堆栈溢出异常。

Exception in thread "SynchronizeDBQueueService-pool-4-thread-1" java.lang.RuntimeException: JSON 序列化失败
	atjava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError)

  一般StackOverflowError异常考虑是代码中出现了循环调用的情况。例如类A中引用了类B,类B中同时也引用了类A。导致类加载器在加载对象时,一直循环无法结束,最后塞满堆栈。
但我查看要打印的对象,发现就是一个普通的obj。继承了一个父类,对象本身只有几个简单的属性,并没有引用别的对象。不存在循环调用的情况。
  最后,查看打印日志,定位到引起异常的地方竟然是对象的一个深度复制方法。getCopy()。getCopy是业务用到的深度复制方法,会将当前对象的值复制给一个完全新的实例对象,并返回。
  而Jackson 在序列化对象时,会遍历所有以 get 或 is 开头的方法。当它遇到 getCopy() 方法时,会调用这个方法,而 getCopy() 返回一个新的对象,这个对象又有 getCopy() 方法,如此循环,导致 StackOverflowError。

知道原因解决的办法就简单了

  最简单的方法是将getCopy()方法修改一个方法名称,不要使用get和set开头。避免被Jackson 误认即可。
  而我的代码里这个getCopy()方法应用非常广泛,影响范围太广,不适合修改方法名。所以,采用一些方式使得jackson绕过getCopy()方法。

方案1

  在getCopy()方法增加 @JsonIgnore注解。或者@JsonProperty(access = JsonProperty.Access.READ_ONLY)注解。这两个注解的意思是告知jackson在转换时忽略这个方法。

方案2

  在Jackson 的转json字符串时,给objectMapper增加静态配置,

objectMapper.setVisibility(PropertyAccessor.ALL,JsonAutoDetect.Visibility.NONE);
objectMapper.setVisibility(PropertyAccessor.FIELD,JsonAutoDetect.Visibility.ANY);

  这两个配置的意思是只序列化字段,忽略所有的getter和setter方法。
  以上方案任选择一种即可解决问题了。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐