2016-06-13 5 views
0

Java Webプロジェクトでユーザーの階層モデルを開発しようとしています。 Java Spring、JPA、およびHibernateでデータベースデータオブジェクトを実装しました。 "User"には、同じタイプの "User"というOneToMany関係の子のリストがあります。Java JPAエンティティOneToManyが同じエンティティを使用すると、アセンブラのスタックオーバーフローが発生する

@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); 
    } 

サービス

クラスユーザー

@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(); 
    } 
} 

は、今私は、いくつかのサービスを定義した例については、このサービスは、親ユーザから作成されたすべてのユーザーのページング可能なリストを返します

次に、クラスUserAssemblerはいくつかのメソッドを実装します。この場合、サービスあなたがメソッドを呼び出す "toListDTO" "toDTO" 方法を見ることができるように

public static List<UserDTO> toListDTO(Set<User> input) { 
     final List<UserDTO> users = new ArrayList<>(); 
     for (User usr : input) { 
      users.add(toDTO(usr)); 
     }   
     return users; 
    } 

を一覧表示するように設定し変換

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; 
    } 

にUserDTO

変換ユーザー:2つの重要なメソッドを使用しますこのメソッドは "toDTO"メソッドを呼び出し、この再帰により、サービスがjson rest APIを生成するためにコントローラによって呼び出されたときに、Javaスタックオーバーフローエラーが発生します。

@BatchSizeアノテーションを使用してOneToManyの子を制限しようとしましたが、エラーを解決できません。

解決方法を教えてもらえますか?

ありがとうございました。

+0

まあ、UserDTOには親UserDTOがあります。子UserDTOには親UserDTOがあり、子UserDTOなどがあります。したがって、無限回帰ループです。 Hibernateはそれについて何もできません。あなたのDTOの設計が問題です。あなたのDTOまたは子供に親を持つことを選択しますが、両方を選択することはできません。 –

答えて

0

意志サイクル無限toDTOメソッド内でこれらの呼び出し、

dto.setParent(UserAssembler.toDTO(input.getParent())); 

と最初のコードは、順番にtoListDTOを呼び出して、親のtoDTOメソッドを呼び出します

toListDTO(Set<User> input) 

、これは子供に戻って最初は親のtoDTOを呼び出します。だから、無限のサイクルが続きます...

私の提案では、親に対して同じtoDTOメソッドを使用しないで、getParentメソッドとgetChildrenメソッドを除いたUserをDTOに変換する別のメソッド(toUserDTO)を作成してください。

public static UserDTO toUserDTO(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.getServers() != null) { 
     dto.getServers().addAll(ServerAssembler.toListString(input.getServers())); 
    } 

    return dto; 
} 

次にtoListDTOに、それは無限にバックtoDTO方法に再帰的ではないであろう、

public static List<UserDTO> toListDTO(Set<User> input) { 
    final List<UserDTO> users = new ArrayList<>(); 
    for (User usr : input) { 
     users.add(toUserDTO(usr)); 
    }   
    return users; 
} 

としてこのように、このようなループを変更します。

関連する問題