StackOverflowError序列化递归JSON
我有一个基本的用户类,其中包括一个用户名和一个朋友variables:
data class User ( val username: String, @ManyToMany(fetch = FetchType.EAGER) @JoinTable( name = "users_friends", joinColumns = arrayOf(JoinColumn(name = "user_id", referencedColumnName = "id")), inverseJoinColumns = arrayOf(JoinColumn(name = "friends_id", referencedColumnName = "id"))) val friends: Collection?)
我从一个springboot控制器调用内置的kotlin函数getFriends():
@ApiOperation("Get Friends") @RequestMapping(value = "/friends", method = RequestMethod.GET) public Collection getFriends(@RequestParam final String username) { return userService.getFriends(userService.findByUsername(username).get()); }
其中调用该服务:
@Override public Collection getFriends(final User user) { Optional myUser = repository.findById(user.getId()); if(myUser.isPresent()){ return myUser.get().getFriends(); } }
但我得到一个java.lang.StackOverflowError
因为UserA有一个UserB的朋友和UserB有一个UserA的朋友,因此当jackson试图序列化用户返回,大概是试图返回像(psudocode):
userA { friend { userB { friend { userA { etc... etc... } } } } }
我怎样才能改变控制器,所以它只会返回用户,他们的朋友,然后停止递归?
我已经尝试了@JsonIgnore上的朋友val停止错误,但我不能再检索该值。
我也尝试过@JsonBackReference,但是这是设计,IIRC,OneToMany分辨率。
注意:用户类是Kotlin,其他都是Java
我有这个相同的问题,老实说,我没有find解决方案搜索。 所以我想出了一个序列化的修复(在我的情况下,我用了Gson)。
注意:这个解决方案不完全干净,通常最好的解决方案是在模型结构之间建立更好的关系。 这个解决方案只是为了帮助那些负担不起的人
我的解决方案
循环引用永远是一个常数,即它是在那里或不是。
因此,在序列化之前,通过将循环引用的起点设置为null,然后在序列化之后,我们“再次设置循环”之后,很容易在序列化之前欺骗我们的程序。
基本示例:
public class Circular { private String name; private Circular friend; public String getName() { return name; } public void setName(String name) { this.name = name; } public Circular getFriend() { return friend; } public void setFriend(Circular friend) { this.friend = friend; } }
上面的Circular
类有一个参考friend
。 它有或没有朋友。 让我们打电话给我们的主要对象A
,它是朋友B
A
是B
的朋友,反之亦然( B
是A
的朋友)。 我们的圈子已经创建。 既然我们知道这将永远是一个常数,我们可以这样做:
//A is an instance of circular A.getFriend().setFriend(null) //Perform serialization
现在我们可以序列化我们的数据。 然后在反序列化之后,我们简单地设置循环引用:
//deserialize A A.getFriend().setFriend(A)
现在我们把原来的对象和循环引用关联起来。
请记住:只有在我早先说过的时候,
你有一个通常的参考或者你没有