& @Data导致栈溢出StackOverflowError

使用lombok的@Data会导致栈溢出StackOverflowError。

问题代码

用户->角色->权限

@Data
class SysUser{
    private Set<SysRole> roles;
}

@Data
class SysRole{
    private Set<SysUser> users;
}
import lombok.Data;
import java.util.HashSet;
import java.util.Set;

public class Test {
    public static void main(String[] args) {
        SysUser user = new SysUser();
        SysRole role = new SysRole();

        Set<SysUser> users = new HashSet<>();
        users.add(user);

        Set<SysRole> roles = new HashSet<>();
        roles.add(role);

        user.setRoles(roles);
        role.setUsers(users);
        System.out.println(user);
//        System.out.println(role);
    }
}

执行结果:栈溢出

image-20210725134245051

问题分析

查看class文件

import java.util.Set;

class SysUser {
    private Set<SysRole> roles;

    public SysUser() {
    }

    public Set<SysRole> getRoles() {
        return this.roles;
    }

    public void setRoles(final Set<SysRole> roles) {
        this.roles = roles;
    }

    public boolean equals(final Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof SysUser)) {
            return false;
        } else {
            SysUser other = (SysUser)o;
            if (!other.canEqual(this)) {
                return false;
            } else {
                Object this$roles = this.getRoles();
                Object other$roles = other.getRoles();
                if (this$roles == null) {
                    if (other$roles != null) {
                        return false;
                    }
                } else if (!this$roles.equals(other$roles)) {
                    return false;
                }

                return true;
            }
        }
    }

    protected boolean canEqual(final Object other) {
        return other instanceof SysUser;
    }

    public int hashCode() {
        int PRIME = true;
        int result = 1;
        Object $roles = this.getRoles();
        int result = result * 59 + ($roles == null ? 43 : $roles.hashCode());
        return result;
    }

    public String toString() {
        return "SysUser(roles=" + this.getRoles() + ")";
    }
}
import java.util.Set;

class SysRole {
    private Set<SysUser> users;

    public SysRole() {
    }

    public Set<SysUser> getUsers() {
        return this.users;
    }

    public void setUsers(final Set<SysUser> users) {
        this.users = users;
    }

    public boolean equals(final Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof SysRole)) {
            return false;
        } else {
            SysRole other = (SysRole)o;
            if (!other.canEqual(this)) {
                return false;
            } else {
                Object this$users = this.getUsers();
                Object other$users = other.getUsers();
                if (this$users == null) {
                    if (other$users != null) {
                        return false;
                    }
                } else if (!this$users.equals(other$users)) {
                    return false;
                }

                return true;
            }
        }
    }

    protected boolean canEqual(final Object other) {
        return other instanceof SysRole;
    }

    public int hashCode() {
        int PRIME = true;
        int result = 1;
        Object $users = this.getUsers();
        int result = result * 59 + ($users == null ? 43 : $users.hashCode());
        return result;
    }

    public String toString() {
        return "SysRole(users=" + this.getUsers() + ")";
    }
}

@Data重写了ToString方法,出现了循环打印。

进一步测试

打印user的hashcode方法

System.out.println(user.hashCode());

同样会出现栈溢出

image-20210725140207387

原因是 计算user的hashcode,需要去获取role的hashcode, 而计算role的hashcode ,又要去获取user的hashcode。所以出现了死循环。

解决方案

不要使用@Data, 换为使用@Getter, @Setter。

总结

User->Role , Role->User 循环引用

当两个类,有循环引用时,使用lombok注解@Data,会重写hashCode()和toString()方法,造成死循环!!!

原文地址:https://www.cnblogs.com/doagain/p/15057816.html