Spring Data JPAの @ManyToMany にこの2日間苦しめられた。
使用しているバージョンは、Springboot v2.5
ネットで@ManyToManyを検索して、紹介されていたコードを片っ端から試してみたが、参考にしたコードはどれもUserが所有するRoleを取得することが出来なかった。
User を取得したところで実行を止めて変数の値をみると、以下のエラーが表示されていた。
エラー 例外が発生しました: メソッドを起動中に com.sun.jdi.InvocationException: Exception occurred in target VM が発生しました。
このエラーメッセージに2日間苦しめられていたが、ようやく、正常に動くコードを今朝、見つけることが出来たので、記録として残しておく。
User.java
package com.example.demo.entity;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@Entity
@Table
public class User implements Serializable {
public User(String userName, String password) {
this.userName = userName;
this.password = password;
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
private Long id;
@Column(name = "enabled")
private boolean enabled = true;
@Column(name = "username")
private String userName;
@Column(name = "password")
private String password;
@Column(name = "dept")
private String dept;
@ManyToMany(fetch=FetchType.EAGER)
@JoinTable(name="user_role",
joinColumns = @JoinColumn(name="user_id", referencedColumnName="user_id"),
inverseJoinColumns = @JoinColumn(name="role_id", referencedColumnName="role_id"))
private List<Role> roles = new ArrayList();
}
Role.java
package com.example.demo.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@Entity
@Table
public class Role implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "role_id")
private Long id;
private String name;
public Role(String name) {
this.name = name;
}
}
これで無事、rolesを取得することが出来ました。
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
:
User user = userRepository.findByName(username);
List<Role> roles = user.getRoles();
:
理由は判りませんが、fetch=FetchType.EAGER の指定が必須でした。
ネットで紹介されていたコードには、FetchType.EAGER を指定している例がひとつも無かったので、どこかのタイミングで仕様が変更にでもなったのだろうか?
@ManyToManyは、デフォルトで FetchType.LAZY になるらしいが、参照先のデータ量が大きい場合、このLAZYローディングが機能しないと使い物にならないように思うが、今日のところは、これで良しとしよう。
コメント