我的回答做了一些额外的假设:
- 使用 JPA 2.1,您可以使用实体图有条件地获取实体的一部分,无论是惰性的还是急切的。
- 将 JAX-RS 与 Jackson JSON 提供程序一起使用,您可以使用
@JsonView
相同的方法将对象呈现为 JSON。
考虑以下示例:用户具有一组角色。默认情况下,角色是惰性获取的,不需要在 JSON 中呈现。但在某些情况下,您希望它们被急切地获取,因为您希望它们以 JSON 格式呈现。
@Entity
@NamedQueries({
@NamedQuery(name = "User.byName", query = "SELECT u FROM User u WHERE u.name = :name"),
@NamedQuery(name = "Users.all", query = "SELECT u FROM User u ORDER BY u.name ASC")
})
@NamedEntityGraph(name = "User.withRoles", attributeNodes = {
@NamedAttributeNode("roles") // make them fetched eager
})
public class User implements Serializable {
public static interface WithoutRoles {}
public static interface WithRoles extends WithoutRoles {}
@Id
private Long id;
@Column(unique = true, updatable = false)
private String name;
@ManyToMany // fetched lazy by default
@JoinTable(/* ... */)
private Set<Role> roles;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// include in JSON only when "@JsonView(WithRoles.class)" is used:
@JsonView(WithRoles.class)
public Set<Role> getRoles() {
if (roles == null)
roles = new HashSet<>();
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
@Entity
public class Role implements Serializable {
/* ... */
}
以下是加载用户的代码,无论有无角色:
public User getUser(String name, boolean withRoles) {
TypedQuery<User> query = entityManager.createNamedQuery("User.byName", User.class)
.setParameter("name", name);
if (withRoles) {
EntityGraph<User> graph = (EntityGraph<User>) entityManager.createEntityGraph("User.withRoles");
query.setHint("javax.persistence.loadgraph", graph);
}
try {
return query.getSingleResult();
} catch (NoResultException e) {
return null;
}
}
public List<User> getAllUsers() {
return entityManager.createNamedQuery("Users.all", User.class)
.getResultList();
}
现在是 REST 资源:
@RequestScoped @Path("users")
public class UserResource {
private @Inject UserService userService;
// user list - without roles
@GET @Produces(MediaType.APPLICATION_JSON)
@JsonView(User.WithoutRoles.class)
public Response getUserList() {
List<User> users = userService.getAllUsers();
return Response.ok(users).build();
}
// get one user - with roles
@GET @Path("{name}") @Produces(MediaType.APPLICATION_JSON)
@JsonView(User.WithRoles.class)
public Response getUser(@PathParam("name") String name) {
User user = userService.getUser(name, true);
if (user == null)
throw new NotFoundException();
return Response.ok(user).build();
}
}
因此,在持久性方面(JPA、Hibernate),您可以使用延迟获取来防止加载实体的某些部分,而在 Web 层(JAX-RS、JSON)上,您可以使用@JsonView
来决定应该在(de -) 实体的序列化。