目前我正在开发一个带有hibernate的dropwizard API。我在两个模型之间定义了多对多的关系:User
和Role
。
我有以下数据库结构:
当我尝试检索数据库中的所有用户时,我得到LazyInitializationException
。根据{{3}}我需要在@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 :(得分:0)
我似乎错误地调试了这个问题。它与AuthorizationService
。
在我的UserResource
课程中,我有@Auth
和@RolesAllowed
注释,以检查是否允许用户访问此资源。
AuthenticationService
调用了UserDAO但不知何故没有Hibernate会话,尽管资源是用@UnitOfWork
注释的。所以我必须打开自己的会话并在用户模型中初始化集合。
这感觉就像一个黑客,但它似乎工作。
以下是一些为您提供某些背景信息的代码:
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();
}
}
}