4

I was getting the error "Could not write JSON: Infinite recursion" when trying to access the endpoint http://localhost:8080/categoryOfPermissions. I've researched and found various solutions here (@JsonManagedReference / @JsonBackReference, @JsonIgnore, @JsonIdentityInfo), but none of them seemed to work. Finally, I found an answer stating that it was necessary to change from Set to List, in order for the @JsonIdentityInfo solution to work. I tested it an it really starts to work after changing from Set to List.

I thought that it was strange, but I found out something even stranger: after changing from Set to List, I removed the @JsonIdentityInfo annotations and everything continued to work. In other words, all that I really needed to do was changing from Set to List to get rid of the exception. Nothing else. No need of any of the solutions :@JsonManagedReference / @JsonBackReference, @JsonIgnore, @JsonIdentityInfo.

Below is the code that was producing the exception. All I had to do was changing private Set<Permission> permission to private List<Permission> permission.

I would like to know why, especially because I would prefer to use Set, in order to avoid Hibernate to use the "Bags" paradigm (which may cause some undesirable behaviors).

Permission.java :

@Entity
@Data
public class Permission{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @NotBlank
    private String name;
            
    @NotNull    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "category_of_permission_id")
    private CategoryOfPermission categoryOfPermission;    
}

CategoryOfPermission.java :

@Entity
@Data
public class CategoryOfPermission{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @NotBlank
    private String name;
            
    @NotNull    
    @OneToMany(mappedBy = "categoryOfPermission", fetch=FetchType.LAZY)
    private Set<Permission> permission;
}

CategoryOfPermissionRepo.java :

public interface CategoryOfPermissionRepo extends CrudRepository<CategoryOfPermission, Integer>{
}
viniciussss
  • 4,404
  • 2
  • 25
  • 42

1 Answers1

11

It is because Set in Java uses equals contract to determine whether two objects are the same or not, and the way equals method in Permission class is implemented(using lombok) causes infinite recursion.

it is part of the generated code for equals method in Permission

    Object this$categoryOfPermission = this.getCategoryOfPermission();
    Object other$categoryOfPermission = other.getCategoryOfPermission();
    if (this$categoryOfPermission == null) {
      if (other$categoryOfPermission != null) {
        return false;
      }
    } else if (!this$categoryOfPermission.equals(other$categoryOfPermission)) {
      return false;
    }

and it is the generated code for the CategoryOfPermission class

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

        Object this$permission = this.getPermission();
        Object other$permission = other.getPermission();
        if (this$permission == null) {
          if (other$permission != null) {
            return false;
          }
        } else if (!this$permission.equals(other$permission)) {
          return false;
        }

        return true;
      }
    }
  }

as you see Permission class calls equals method of CategoryOfPermission class and CategoryOfPermission calls equals method of Permision class which finally causes stackoverflow problem!.

badger
  • 2,908
  • 1
  • 13
  • 32
  • Thanks!!! How do you have access to the code that Lombok generates? I've search about it and it seems that I have to use Delombok. Is that right? I use Eclipse. – viniciussss Feb 09 '22 at 23:12
  • you are welcome, I just examined the generated code in `target` folder. Intellij automatically recreate the source code from .class file – badger Feb 09 '22 at 23:16
  • great! Sorry if I'm asking too much, but what do you think is the best option, to use List instead Set or to override the equals method? – viniciussss Feb 09 '22 at 23:17
  • sorry! I really don't know the pros and cons of each approach, maybe you should ask another question. community probably better helps you – badger Feb 09 '22 at 23:22
  • ok, thanks a lot – viniciussss Feb 09 '22 at 23:24