2016-01-11 4 views
0

В настоящее время я работаю над API-интерфейсом dropwizard с спящим режимом. У меня есть много разных отношений между двумя моделями: User и Role.Dropwizard org.hibernate.LazyInitializationException: не удалось лениво инициализировать коллекцию, не удалось инициализировать прокси - no Session

У меня есть следующая структура базы данных:

ERD

Когда я пытаюсь получить все пользователи в базе данных я получаю LazyInitializationException. В соответствии с Dropwizard documentation мне нужно на аннотацию @UnitOfWork к моему ресурсу. Это еще не решило мою проблему.

Когда я изменяю fetchType отношения к FetchType.EAGER, я на самом деле получаю результаты, но он возвращает повторяющиеся результаты.

Как решить эту проблему. Является ли мое отношение определенным правильным, или я делаю здесь большую ошибку? Ясно, что я что-то упускаю.

Вот мой User.java класс:

@Entity 
@Table(name = "\"user\"") 
public class User implements Principal { 

    @Id @GeneratedValue @Column(name = "id") 
    private long id; 

    @NotEmpty @Email @JsonView(View.Public.class) @Column(name = "email") 
    private String email; 

    @NotEmpty @JsonView(View.Protected.class) @Column(name = "password") 
    private String password; 

    @ManyToMany(targetEntity = Role.class) 
    @JoinTable(name = "user_role", 
     joinColumns = @JoinColumn(name = "user_id"), 
     inverseJoinColumns = @JoinColumn(name = "role_id")) 
    private Set<Role> roles; 

    public long getId() 
    { 
     return id; 
    } 

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

    public void setId(long id) 
    { 
     this.id = id; 
    } 

    public String getEmail() 
    { 
     return email; 
    } 

    public void setEmail(String email) 
    { 
     this.email = email; 
    } 

    public String getPassword() 
    { 
     return password; 
    } 

    @JsonIgnore 
    public String getName() 
    { 
     return email; 
    } 

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

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

    public boolean hasRole(String roleName) { 
     if (roles != null) 
     { 
      for(Role role : roles) 
      { 
       if(role.getName().equals(roleName)) 
       { 
        return true; 
       } 
      } 
     } 

     return false; 
    } 
} 

Вот мой Role.java класс:

@Entity 
@Table(name = "role") 
public class Role { 

    @Id @GeneratedValue @Column(name = "id") @JsonView(View.Public.class) 
    private long id; 

    @JsonView(View.Public.class) @Column(name = "name", nullable = false, length = 255) 
    private String name; 

    @ManyToMany(targetEntity = User.class, mappedBy = "roles") 
    @JsonIgnore 
    private Set<User> users = new HashSet<>(); 

    public Role() { 
     // Empty constructor 
    } 

    public Role(long id, String name) { 
     this.id = id; 
     this.name = name; 
    } 

    @JsonProperty 
    public long getId() { 
     return id; 
    } 

    public void setId(long id) { 
     this.id = id; 
    } 

    @JsonProperty 
    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    @JsonIgnore 
    public Set<User> getUsers() 
    { 
     return users; 
    } 

    @JsonIgnore 
    public void addUser(User user) 
    { 
     this.users.add(user); 
    } 
} 

UserResource:

@Path("/users") 
@Produces(MediaType.APPLICATION_JSON) 
public class UserResource { 
    private final UserDAO dao; 

    public UserResource(UserDAO userDAO) 
    { 
     dao = userDAO; 
    } 

    @GET 
    @JsonView(View.Public.class) 
    @RolesAllowed("beheerder") 
    @UnitOfWork 
    @Timed 
    public List<User> retrieveAll(@Auth User user) 
    { 
     return dao.findAll(); 
    } 

    @GET 
    @Path("/{id}") 
    @JsonView(View.Public.class) 
    @UnitOfWork 
    public User retrieve(@PathParam("id") int id) 
    { 
     return dao.findById(id); 
    } 

    @POST 
    @Consumes(MediaType.APPLICATION_JSON) 
    @JsonView(View.Protected.class) 
    @UnitOfWork 
    public void create(User user) 
    { 
     dao.create(user); 
    } 

    @PUT 
    @Path("/{id}") 
    @Consumes(MediaType.APPLICATION_JSON) 
    @JsonView(View.Protected.class) 
    @UnitOfWork 
    public void update(@PathParam("id") int id, @Auth User authenticator, User user) 
    { 
     dao.update(authenticator, id, user); 
    } 

    @DELETE 
    @Path("/{id}") 
    @RolesAllowed("beheerder") 
    @UnitOfWork 
    public void delete(@PathParam("id") int id) 
    { 
     dao.delete(id); 
    } 

    @GET 
    @Path("/me") 
    @JsonView(View.Private.class) 
    @UnitOfWork 
    public User authenticate(@Auth User authenticator) 
    { 
     return authenticator; 
    } 
} 

А вот исключение:

ERROR [2016-01-11 20:15:23,396] io.dropwizard.jersey.errors.LoggingExceptionMapper: Error handling a request: a2a5aa2494999e37 
! org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: nl.hsleiden.ipsen3.core.User.roles, could not initialize proxy - no Session 
! at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:576) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final] 

ответ

0

Кажется, я отладил проблему неправильно. Это имело отношение к AuthorizationService.

В моем классе UserResource у меня была анкета @Auth и @RolesAllowed, чтобы проверить, разрешен ли пользователю доступ к этому ресурсу.

AuthenticationService сделал вызов UserDAO, но так или иначе не имел сеанса Hibernate, хотя ресурс был аннотирован @UnitOfWork. Поэтому мне пришлось открыть свой сеанс и инициализировать коллекцию в модели User.

Это похоже на взлом, но, похоже, он работает.

Вот код, чтобы предоставить вам некоторый контекст:

AuthenticationService

public class AuthenticationService implements Authenticator<BasicCredentials, User>, Authorizer<User> { 

    private final UserDAO userDAO; 

    public AuthenticationService(UserDAO userDAO) { 
     this.userDAO = userDAO; 
    } 

    public Optional<User> authenticate(BasicCredentials credentials) 
     throws AuthenticationException { 
     User user = userDAO.getByEmail(credentials.getUsername()); 
     if (user != null && user.getPassword().equals(credentials.getPassword())) { 
      return Optional.of(user); 
     } 
     return Optional.absent(); 
    } 

    public boolean authorize(User user, String role) { 
     return user.hasRole(role); 
    } 
} 

UserResource

@Path("/users") 
@Produces(MediaType.APPLICATION_JSON) 
public class UserResource { 
    private final UserDAO dao; 

    public UserResource(UserDAO userDAO) 
    { 
     dao = userDAO; 
    } 

    @GET 
    @UnitOfWork 
    @JsonView(View.Public.class) 
    @RolesAllowed("beheerder") 
    public List<User> retrieveAll(@Auth User user) 
    { 
     List<User> users = dao.findAll(); 
     for (User u: users) { 
      Hibernate.initialize(u.getRoles()); 
     } 
     return users; 
    } 

    // Some other routes.. 
} 

И UserDAO

public class UserDAO extends AbstractDAO<User> { 
    private final SessionFactory sessionFactory; 

    /** 
    * Creates a new DAO with a given session provider. 
    * 
    * @param sessionFactory a session provider 
    */ 
    public UserDAO(SessionFactory sessionFactory) 
    { 
     super(sessionFactory); 
     this.sessionFactory = sessionFactory; 
    } 

    /** 
    * Retrieve all users. 
    * 
    * @return 
    */ 
    public List findAll() 
    { 
     return criteria().list(); 
    } 

    /** 
    * Finds a user by email. Used for authorization. 
    * 
    * @param email 
    * @return 
    */ 
    public User getByEmail(String email) 
    { 
     Session session = sessionFactory.openSession(); 
     try { 
      User user = (User) session.createCriteria(User.class).add(Restrictions.eq("email", email)) 
       .uniqueResult(); 
      Hibernate.initialize(user.getRoles()); 
      return user; 
     } finally { 
      session.clear(); 
     } 
    } 
} 
Смежные вопросы

 Смежные вопросы