'Collection of role could not initialize proxy - no Session only from a filter

I have a Relation ManyToMany:

@Entity
@Data
@Table(name = "usuarios")
public class Usuario implements Serializable{
...
    @JsonIgnoreProperties({"usuario", "hibernateLazyInitializer", "handler"})
    @ManyToMany(fetch=FetchType.LAZY, cascade = CascadeType.MERGE)
    @JoinTable(name="usuarios_roles", 
        joinColumns= @JoinColumn(name="usuario_id"),
        inverseJoinColumns=@JoinColumn(name="role_id"),
        uniqueConstraints = {@UniqueConstraint(columnNames = {"usuario_id","role_id"})})
    private List<Role> role = new ArrayList<>();
...
}

@Entity
@Data
@Table(name = "roles")
public class Role implements Serializable{
.....
    @JsonIgnoreProperties({"usuarios","hibernateLazyInitializer", "handler"})
    @ManyToMany(fetch = FetchType.LAZY, mappedBy = "role")
    private List<Usuario> usuario = new ArrayList<>();
...
}

When I run it as a simple rest it works perfectly, it returns the user and all his roles.

The problem is when I run it from the filter:

public class CustomFilter extends OncePerRequestFilter {
    @Autowired
    private IUsuarioService usuarioService;
    
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        try {
            if(usuarioService == null){
                ServletContext servletContext = request.getServletContext();
                WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
                usuarioService = webApplicationContext.getBean(IUsuarioService.class);
            }
            String[] path = request.getRequestURI().split("/");
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            Usuario usuario = usuarioService.findByEmail(authentication.getName());
            if(usuarioService.existsPermission(request.getMethod(), path[2], authentication.getName())) {
                filterChain.doFilter(request, response);
            } else {
                response.sendError(HttpServletResponse.SC_FORBIDDEN);
            }           
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

The service is:

@Override
public Boolean existsPermission(String method, String rest, String email) {
    Usuario usuario = usuarioDao.findByEmail(email);
    Rest restcontroller = new Rest();
    restcontroller = restDao.findByMetodoAndRestcontroller(method, rest);
    for(Role role : usuario.getRole()) {
        return restDao.existsPermission(restcontroller.getId(), role.getId());
    }
    return false;
}

This error:

failed to lazily initialize a collection of role: iteam.ronald.project.models.entity.Usuario.role, could not initialize proxy - no Session

In debug mode getRole() returns the following error:

Exception occurred: com.sun.jdi.InvocationException: Exception occurred in target VM occurred invoking method..

It makes me suppose that the way I enable userService to use it from this filter is not correct. What am I missing?



Solution 1:[1]

You get this message because you are calling usario.getRole outside a transaction and the fetchType is LAZY.

To solve this problem you can either :

  • put existsPermission in a transaction or
  • in usuarioDao.findByEmail do something like this :

code sample :

public Usuario findByEmail(String email) {
  Usuario usuario;
  //fetch usuario
  //load roles
  usuario.getRole().size();
  return usuario;
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1