The question is published on by Tutorial Guruji team.
I’m struggling with Java Spring Hibernate, I’m trying to implement Oauth2 and I keep getting an error while connecting table User to Roles through @ManyToMany. I have read all the answers available referencing my problem and no matter what I try I still get a org.hibernate.MappingException.
Below are the full details of what I’m trying to do.
Database Structure
CREATE TABLE IF NOT EXISTS `role` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1; INSERT INTO `role` (`id`, `name`) VALUES (1, 'ROLE_USER'), (2, 'ROLE_ADMIN'), (3, 'ROLE_GUEST'); -- -------------------------------------------------------- CREATE TABLE IF NOT EXISTS `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `email` varchar(255) NOT NULL, `nickname` varchar(255) NOT NULL, `password` varchar(255) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `user_email_uindex` (`email`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1; INSERT INTO `user` (`id`, `email`, `nickname`, `password`) VALUES (1, 'test@test.com', 'Admin', 'test'); -- -------------------------------------------------------- -- -- Table structure for table `user_role` -- DROP TABLE IF EXISTS `user_role`; CREATE TABLE IF NOT EXISTS `user_role` ( `id` int(11) NOT NULL AUTO_INCREMENT, `email` varchar(255) NOT NULL, `role_id` int(11) NOT NULL, PRIMARY KEY (`id`), KEY `email_fk` (`email`), KEY `role_fk` (`role_id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1; -- -- Dumping data for table `user_role` -- INSERT INTO `user_role` (`id`, `email`, `role_id`) VALUES (1, 'test@test.com', 1), (2, 'test@test.com', 2); ========================================
Roles.java
@Entity public class Role implements GrantedAuthority { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; @NotBlank private String name; @JsonIgnore @ManyToMany(mappedBy = "roles") private Set<User> users = new HashSet<>(); @Override public String getAuthority() { return name; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<User> getUsers() { return users; } public void setUsers(Set<User> users) { this.users = users; } }
User.java
@Entity @Table(name = "user") public class User { private Integer id; private String email; private String password; private String nickname; @JsonIgnore @ManyToMany(fetch = FetchType.EAGER) @JoinTable(name = "user_role", joinColumns = { @JoinColumn(name = "email") }, inverseJoinColumns = { @JoinColumn(name = "role_id") }) private Set<Role> roles = new HashSet<>(); public User(User user) { super(); this.id = user.getId(); this.email = user.getEmail(); this.password = user.getPassword(); this.nickname = user.getNickname(); this.roles = user.getRoles(); } public User() { } @Id @Column(name = "id", nullable = false) public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } @Basic @Column(name = "email", nullable = false, length = 255) public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } @Basic @Column(name = "password", nullable = false, length = 255) public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Basic @Column(name = "nickname", nullable = false, length = 255) public String getNickname() { return nickname; } public void setNickname(String nickname) { this.nickname = nickname; } public Set<Role> getRoles() { return roles; } public void setRoles(Set<Role> roles) { this.roles = roles; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User that = (User) o; return Objects.equals(id, that.id) && Objects.equals(email, that.email) && Objects.equals(password, that.password) && Objects.equals(nickname, that.nickname); } @Override public int hashCode() { return Objects.hash(id, email, password, nickname); } }
Dependencies
** <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-rest</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jersey</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web-services</artifactId> </dependency> <dependency> <groupId>de.codecentric</groupId> <artifactId>spring-boot-admin-starter-server</artifactId> </dependency> <dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> <version>2.3.3.RELEASE</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.restdocs</groupId> <artifactId>spring-restdocs-mockmvc</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>5.2.3.Final</version> </dependency> <dependency> <groupId>javax.persistence</groupId> <artifactId>persistence-api</artifactId> <version>1.0.2</version> </dependency> </dependencies>**
Issue:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘entityManagerFactory’ defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: Could not determine type for: java.util.Set, at table: user, for columns: [org.hibernate.mapping.Column(roles)]
Answer
This issue relates to access strategy, in your User Class access strategy is determined by @Id annotation(which is put on getter method getId()).
So you should put your annotations:
@JsonIgnore @ManyToMany(fetch = FetchType.EAGER) @JoinTable(name = "user_role", joinColumns = { @JoinColumn(name = "email") }, inverseJoinColumns = { @JoinColumn(name = "role_id") })
right on getter method getRoles()