我嘗試在Java Web項目中爲用戶開發分層模型。 我用Java Spring,JPA和Hibernate實現了數據庫數據對象。 任何「用戶」都有一個具有OneToMany關係的同一類型爲「用戶」的子項列表。Java JPA實體OneToMany同一實體導致彙編程序堆棧溢出
類用戶
@Entity
@Table(name = "emsusers")
public class User extends DomainEntity implements Serializable {
@Column(name = "username", nullable = false, unique = true)
private String username;
@Column(name = "password", nullable = false)
private String password;
@JoinColumn(name = "role", nullable = false)
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
private Role role;
@JoinColumn(name = "parent")
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
private User parent;
@JoinColumn(name = "children")
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
private final Set<User> children;
@JoinColumn(name = "servers")
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
private Set<Server> servers;
private User(String username, String password, Role role, User parent, Set<Server> servers) {
super(UUID.randomUUID().toString());
if (username == null) {
throw new IllegalArgumentException("username == null");
}
this.username = username;
if (password == null) {
throw new IllegalArgumentException("password == null");
}
this.password = password;
if (role == null) {
throw new IllegalArgumentException("role == null");
}
this.role = role;
this.parent = parent;
this.children = Sets.newHashSet();
if (servers == null) {
this.servers = Sets.newHashSet();
}
else {
this.servers = Sets.newHashSet(servers);
}
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public Role getRole() {
return role;
}
public User getParent() {
return parent;
}
public ImmutableSet<User> getChildren() {
return ImmutableSet.copyOf(children);
}
public ImmutableSet<Server> getServers() {
return ImmutableSet.copyOf(servers);
}
public void updatePassword(String oldPassword, String newPassword) {
if (!this.password.equals(oldPassword)) {
throw new IllegalArgumentException("Wrong old password.");
}
if (oldPassword.equals(newPassword)) {
throw new IllegalArgumentException("New password is equal to old password.");
}
this.password = newPassword;
}
public void update(Role role, Set<Server> servers) {
this.role = role;
this.servers = Sets.newHashSet(servers);
}
public void addChild(User child) {
this.children.add(child);
}
public void delChild(User child) {
this.children.remove(child);
}
public static User of(String username, String password, Role role, User parent, Set<Server> servers) {
return new User(username, password, role, parent, servers);
}
// Solo per JPA
protected User() {
this.children = Sets.newHashSet();
}
}
現在我定義了一些服務,例如該服務回報從父用戶創建的所有用戶的分頁列表:
服務
@Transactional(readOnly = true)
@Override
public PageDTO<UserDTO> getListByParent(String id, Pageable page) {
final User parent = userRepository.findOne(id);
if (parent == null) {
throw new IllegalStateException("User parent not exist.");
}
final Page<User> usersPage = userRepository.findAll(UserSpecifications.withParent(parent), page);
return UserAssembler.toDTOPage(usersPage);
}
然後,類UserAssembler實現一些方法,在這種情況下是服務使用兩個關鍵的方法:
轉換用戶到UserDTO
public static UserDTO toDTO(User input) {
final UserDTO dto = new UserDTO();
dto.setId(input.getIdentity());
dto.setUsername(input.getUsername());
dto.setPassword(input.getPassword());
dto.setRole(RoleAssembler.toDTO(input.getRole()));
if (input.getParent() != null) {
dto.setParent(UserAssembler.toDTO(input.getParent()));
}
if (input.getChildren().isEmpty() == false) {
dto.getChildren().addAll(toListDTO(input.getChildren()));
}
if (input.getServers() != null) {
dto.getServers().addAll(ServerAssembler.toListString(input.getServers()));
}
return dto;
}
轉換設置爲列表
public static List<UserDTO> toListDTO(Set<User> input) {
final List<UserDTO> users = new ArrayList<>();
for (User usr : input) {
users.add(toDTO(usr));
}
return users;
}
正如你所看到的方法 「toDTO」 調用方法 「toListDTO」 ,稱爲方法「toDTO」,這個遞歸導致一個java堆棧溢出錯誤,當一個控制器調用服務來產生json rest api。
我嘗試使用@BatchSize註釋限制OneToMany子項,但未解決錯誤。
你能幫我或建議解決方案嗎?
謝謝。
那麼,一個UserDTO有一個父UserDTO,它具有子UserDTO,它具有一個父UserDTO,它具有子UserDTO等等。所以,是的,這是一個無限遞歸循環。 Hibernate對此無能爲力。你的DTO的設計是個問題。選擇在您的DTO或孩子中擁有父母,但不能同時擁有父母。 –