我有一个JPA持久层,有许多@Entity类,它们有许多OneToMany和ManyToMany关系。 我想通过RestEasy将这些实体暴露给Jackson2作为序列化程序,将JSON作为REST服务。
我知道@JsonIdentityInfo用于解析循环引用。 问题在于我需要暴露实体字段的不同子集的不同REST服务。此外,我需要为集合公开不同级别的depts(OneToMany,OneToOne等)。 例如,对于这个简单的实体:
class User {
Long id;
String name;
Company company;
}
class Company {
Long id;
String name;
List<User> users;
List<Product> products;
}
class Product {
Long id;
String name;
List<User> users;
}
和这个REST服务:
class MyResource {
User getUser() { //... }
List<User> getUsers() { //... }
Company getCompany() { //... }
List<Company> getComanies() { //... }
}
在方法getUser()
中,我需要返回包含内部Company对象的完整User对象的JSON。但该公司当然只需要包含他们的id
和name
字段,而不是完整的用户列表。更重要的是内部公司JSON不得包含products
!这是合乎逻辑的。如果我们收到用户,我们就不需要与该用户相关的公司产品。如果我们需要它们,我们将发送另一个REST请求。
但是在方法getCompany()
中,我需要返回带有完整Company对象的JSON,包括User和Product对象的内部JSON数组。当然,这次User对象不需要为Company对象包含内部JSON。
出于这个原因,我无法使用@JsonIgnore。在一种情况下,我们需要一些领域而在另一种情况下我们不需要。
现在我想出了使用Jackson视图(@JsonView注释)的方法。我为每个MyResource getter提供了具有不同视图的View类。
public class Views {
public static class User {}
public static class Users {}
public static class Company {}
public static class Companies {}
// etc...
}
和MyResoruce类为
class MyResource {
@JsonView(Views.User.class)
User getUser() { //... }
@JsonView(Views.Users.class)
List<User> getUsers() { //... }
@JsonView(Views.Company.class)
Company getCompany() { //... }
@JsonView(Views.Companies.class)
List<Company> getComanies() { //... }
}
并为每个实体提供一个MixIn类,每个字段都注释为
public abstract class UserMixIn {
@JsonView({ Views.User.class, Views.Users.class, Views.Company.class, Views.Companies.class })
public abstract Long getId();
@JsonView({ Views.User.class, Views.Users.class, Views.Company.class, Views.Companies.class })
public abstract String getName();
@JsonView({ Views.User.class, Views.Users.class })
public abstract Company getCompany();
}
public abstract class CompanyMixIn {
@JsonView({ Views.Company.class, Views.Companies.class, Views.User.class, Views.Users.class })
public abstract Long getId();
@JsonView({ Views.Company.class, Views.Companies.class, Views.User.class, Views.Users.class })
public abstract String getName();
@JsonView({ Views.Company.class, Views.Companies.class })
public abstract List<User> getUsers();
@JsonView({ Views.Company.class, Views.Companies.class })
public abstract List<Product> getProducts();
}
public abstract class ProductMixIn {
@JsonView({ Views.Company.class, Views.Companies.class })
public abstract Long getId();
@JsonView({ Views.Company.class, Views.Companies.class })
public abstract String getName();
public abstract List<User> getUsers();
}
支持案例的复数,其中getUsers()
并不需要每个用户的完整内部公司对象(性能)。
当然只有示例类。真正的课程更大更复杂。
我不喜欢这种方法,因为我担心将来它可能是一场噩梦(太多不可管理的观点)。也许有将JPA实体暴露为REST服务的通用方法?我相信这是一项相当普遍的任务。但无法找到关于其他人如何做到这一点的任何可理解的信息。也许是一些最佳实践。
答案 0 :(得分:2)
@Entity
个对象。示例:
对于服务1(专注于用户管理):
public class UserDto {
private Long id;
private String name;
private CompanyDtoLight company;
}
public class CompanyDtoLight {
private Long id;
private String name;
}
服务2(专注于公司管理):
public class CompanyDto {
private Long id;
private String name;
List<UserDtoLight > users;
List<ProductDtoLight > products;
}
public class UserDtoLight {
private Long id;
private String name;
}
class ProductDtoLight {
private Long id;
private String name;
}
(您的DTO的命名是你的)
如何:
您需要Mappers将@Entity
转换为DTO并将其转换为DTO。有些lib存在,如Dozer或MapStruct(还有很多其他的)。