微服务间调用导致的Could not write content: Infinite recursion (StackOverflowError)问题

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/liuchuanhong1/article/details/78416398

最近在开发中遇到了一个奇葩的问题,在本地调用没有任何问题,只要是通过feign调用就出现递归调用,异常信息如下:

2017-11-01 17:23:10.302 ERROR 4172 --- [nio-6006-exec-4] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: Infinite recursion (StackOverflowError) (through reference chain: org.hibernate.collection.internal.PersistentSet[0]->com.chhliu.srd.rdcloud.user.entity.SysPermission["roleList"]->org.hibernate.collection.internal.PersistentSet[0]->com.chhliu.srd.rdcloud.user.entity.SysRole["permissionList"]->org.hibernate.collection.internal.PersistentSet[0]->com.chhliu.srd.rdcloud.user.entity.SysPermission["roleList"]->org.hibernate.collection.internal.PersistentSet[0] with root cause

java.lang.StackOverflowError: null
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(Unknown Source)
	at java.security.SecureClassLoader.defineClass(Unknown Source)
	at java.net.URLClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.access$100(Unknown Source)
	at java.net.URLClassLoader$1.run(Unknown Source)
	at java.net.URLClassLoader$1.run(Unknown Source)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(Unknown Source)
	at java.lang.ClassLoader.loadClass(Unknown Source)
	at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
	at java.lang.ClassLoader.loadClass(Unknown Source)
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:709)
	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
	at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:149)
	at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:112)
	at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:25)
	at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:704)
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:690)
	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)

从上面的异常信息可以看出,权限表和角色表出现了递归调用,并且最终导致了StackOverflowError的错误。从异常中可以看出,是由于feign在序列化的时候,使用的是jackson,jackson在序列化的时候,导致了递归调用。

角色表如下:

@Entity
@Table(name = "t_sys_role")
@Setter
@Getter
@NoArgsConstructor
@ToString(exclude = {"permissionList", "userList"})
public class SysRole implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * 角色编号
	 */
	@Id
	@GeneratedValue
	@Column(name = "role_id")
	private Long roleId;

	/**
	 * 角色标识 程序中判断使用,如"admin",这个是唯一的:
	 */
	@Column(name = "role_name")
	private String roleName;

	/**
	 * 角色描述,UI界面显示使用
	 */
	@Column(name = "description")
	private String description;

	/**
	 * 是否可用,如果不可用将不会添加给用户
	 */
	@Column(name = "available")
	private Boolean available = Boolean.FALSE;

	/**
	 * 角色 -权限关系: 多对多关系;
	 */
	@ManyToMany(fetch = FetchType.EAGER)
	@JoinTable(name = "t_sys_role_permission", joinColumns = {
			@JoinColumn(name = "roleId") }, inverseJoinColumns = {
					@JoinColumn(name = "permissionId") })
	private Set<SysPermission> permissionList;

	/**
	 * 用户 - 角色关系定义;
	 */
	@JsonBackReference  // 解决循环调用的问题
	@ManyToMany
	@JoinTable(name = "t_sys_user_role", joinColumns = {
			@JoinColumn(name = "roleId")}, inverseJoinColumns = { @JoinColumn(name = "uid") })
	private Set<Employee> userList;
}

权限表如下:

@Entity
@Table(name = "t_sys_permission")
@Setter
@Getter
@NoArgsConstructor
@ToString(exclude = "roleList")
public class SysPermission implements Serializable {
	private static final long serialVersionUID = 1L;

	/**
	 * 主键
	 */
	@Id
	@GeneratedValue
	@Column(name = "permission_id")
	private long permissionId;
	
	/**
	 * 权限编码名称
	 */
	@Column(name = "permission_code")
	private String permissionCode;

	/**
	 * 名称
	 */
	@Column(name = "permission_name")
	private String permissionName;

	/**
	 * 一级菜单
	 */
	@Column(name = "first_menu")
	private String firstMenu;

	/**
	 * 二级菜单
	 */
	@Column(name = "second_menu")
	private String secondMenu;

	/**
	 * 资源路径
	 */
	@Column(name = "url")
	private String url;

	/**
	 * 权限字符串,menu例子:role:*,button例子:role:create,role:update,role:delete,role:view
	 */
	@Column(name = "permission")
	private String permission;

	/**
	 * 是否可用,如果不可用将不会添加给用户
	 */
	@Column(name = "available")
	private Boolean available = Boolean.FALSE;

	/**
	 * 权限- 角色关系定义 一个权限对应多个角色
	 */
        @JsonBackReference // 解决循环调用的问题
 @ManyToMany@JoinTable(name = "t_sys_role_permission", joinColumns = {@JoinColumn(name = "permissionId") }, inverseJoinColumns = { @JoinColumn(name = "roleId") })private Set<SysRole> roleList;}

解决方案如下:
比如角色和权限是ManyToMany的关系,那么就在权限对应的角色的setter上加上@JsonBackReference注解,来解决问题,例如上例中在roleList属性上加了该注解。

猜你喜欢

转载自blog.csdn.net/liuchuanhong1/article/details/78416398
今日推荐