javaspringspring-bootjackson

Jackson collection serializer error despite @JsonIgnore


I am having a problem with the jackson deserializer.

I have two spring boot applications and a separate module for the shared model.

    app1-> <dependency>
              <groupId>com.fasterxml.jackson.core</groupId>
              <artifactId>jackson-databind</artifactId>
              <version>2.5.0</version>
           </dependency>
           <dependency>
              <groupId>eu.emif.security</groupId>
              <artifactId>model</artifactId>
              <version>0.0.1-SNAPSHOT</version>
           </dependency>

    app2-> <dependency>
              <groupId>com.fasterxml.jackson.core</groupId>
              <artifactId>jackson-databind</artifactId>
              <version>2.5.0</version>
           </dependency>
           <dependency>
              <groupId>eu.emif.security</groupId>
              <artifactId>model</artifactId>
              <version>0.0.1-SNAPSHOT</version>
           </dependency>

   model-> <dependency>
             <groupId>com.fasterxml.jackson.core</groupId>
             <artifactId>jackson-databind</artifactId>
             <version>2.5.0</version>
           </dependency>

in the model I have a User and Role object

package eu.emif.security.model;

import org.codehaus.jackson.annotate.JsonAutoDetect;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.annotate.JsonMethod;
import org.codehaus.jackson.annotate.JsonProperty;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

@Entity
@Table(name = "user", schema = "public")
@JsonAutoDetect(value = JsonMethod.NONE)
public class User implements Serializable, UserDetails {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @JsonProperty
    private Long id;

    @NotNull
    @JsonProperty
    private String username;
    @NotNull
    private String password;

    @ManyToMany(fetch = FetchType.EAGER,mappedBy = "users")
    @JsonIgnore
    private List<Role> roles;

    public User() { }

    @JsonIgnore
    public Collection<? extends GrantedAuthority> getAuthorities() {
        ArrayList<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
        for (Role role : roles) {
            grantedAuthorities.add(new SimpleGrantedAuthority(role.getRoleName()));
        }
        return grantedAuthorities;
    }

    public boolean isAccountNonExpired() {
        return true;
    }


    public boolean isAccountNonLocked() {
        return true;
    }


    public boolean isCredentialsNonExpired() {
        return true;
    }


    public boolean isEnabled() {
        return true;
    }


    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }


    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public List<Role> getRoles() {
        return roles;
    }

    public void setRoles(List<Role> roles) {
        this.roles = roles;
    }

    public Long getId() {
        return id;
    }
}




    import org.codehaus.jackson.annotate.JsonAutoDetect;
    import org.codehaus.jackson.annotate.JsonIgnore;
    import org.codehaus.jackson.annotate.JsonMethod;
    import org.codehaus.jackson.annotate.JsonProperty;
    
    import javax.persistence.*;
    import java.io.Serializable;
    import java.util.List;
    
    @Entity
    @Table(name = "role", schema = "public")
    @JsonAutoDetect(value = JsonMethod.NONE)
    public class Role implements Serializable {
    
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        @JsonProperty
        private Long id;
    
        @ManyToMany
        @JoinTable(name="user_roles", joinColumns=@JoinColumn(name="role_id"), inverseJoinColumns=@JoinColumn(name="user_id"))
        @JsonIgnore
        private List<User> users;
    
        public Role() {
        }
        @JsonProperty
        private String roleName;
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public String getRoleName() {
            return roleName;
        }
    
        public void setRoleName(String roleName) {
            this.roleName = roleName;
        }
    
        public List<User> getUsers() {
            return users;
        }
    
        public void setUsers(List<User> users) {
            this.users = users;
        

}
}

The problem is that when I run my application I get a stack overflow exception because when the user object is serialized jackson then tries to serialize the roles which in turn have users and it infinite loops.

I believe the @JsonIgnore annotation is ignored (no pun intended)

Does anyone of you have an idea why this is occurring?

Is their a way of telling jackson in spring boot where it needs to look for classes which are annotated which jackson annotations. I believe that the mapper in app1 simply has no idea that their are classes in the separate module which are annotated.


Solution

  • From your pom.xml it seems that you're using Jackson 2.x but the annotations are from the old Jackson (1.xx). Could you please try the following:

    Change

    import org.codehaus.jackson.annotate.JsonIgnore;
    

    to

    import org.fasterxml.jackson.annotate.JsonIgnore;