web-dev-qa-db-fra.com

SpringBoot JPA Hibernate: Erreur lors de la création du bean avec le nom 'entityManagerFactory'

J'essaie de configurer une application Spring Boot, qui utilise SpringBoot Security pour authentifier les utilisateurs, qui sont stockés dans ma base de données MySQL. J'ai suivi quelques tutoriels sur la façon de le faire, cependant, lorsque j'essaie d'exécuter l'application avec maven, j'obtiens l'erreur suivante:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.Java:1628) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.Java:555) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.Java:483) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.Java:306) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.Java:230) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.Java:302) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.Java:197) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.Java:1078) ~[spring-context-4.3.10.RELEASE.jar:4.3.10.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.Java:857) ~[spring-context-4.3.10.RELEASE.jar:4.3.10.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.Java:543) ~[spring-context-4.3.10.RELEASE.jar:4.3.10.RELEASE]
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.Java:122) ~[spring-boot-1.5.6.RELEASE.jar:1.5.6.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.Java:693) [spring-boot-1.5.6.RELEASE.jar:1.5.6.RELEASE]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.Java:360) [spring-boot-1.5.6.RELEASE.jar:1.5.6.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.Java:303) [spring-boot-1.5.6.RELEASE.jar:1.5.6.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.Java:1118) [spring-boot-1.5.6.RELEASE.jar:1.5.6.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.Java:1107) [spring-boot-1.5.6.RELEASE.jar:1.5.6.RELEASE]
    at com.proba.Userboard.UserboardApplication.main(UserboardApplication.Java:11) [classes/:na]
    at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_121]
    at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:62) ~[na:1.8.0_121]
    at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43) ~[na:1.8.0_121]
    at Java.lang.reflect.Method.invoke(Method.Java:498) ~[na:1.8.0_121]
    at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.Java:49) [spring-boot-devtools-1.5.6.RELEASE.jar:1.5.6.RELEASE]
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl.Java:954) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.Java:882) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
    at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.Java:60) ~[spring-orm-4.3.10.RELEASE.jar:4.3.10.RELEASE]
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.Java:353) ~[spring-orm-4.3.10.RELEASE.jar:4.3.10.RELEASE]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.Java:370) ~[spring-orm-4.3.10.RELEASE.jar:4.3.10.RELEASE]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.Java:359) ~[spring-orm-4.3.10.RELEASE.jar:4.3.10.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.Java:1687) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.Java:1624) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
    ... 21 common frames omitted
Caused by: org.hibernate.MappingException: Could not determine type for: Java.util.Set, at table: role, for columns: [org.hibernate.mapping.Column(users)]
    at org.hibernate.mapping.SimpleValue.getType(SimpleValue.Java:431) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.mapping.SimpleValue.isValid(SimpleValue.Java:398) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.mapping.Property.isValid(Property.Java:225) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.mapping.PersistentClass.validate(PersistentClass.Java:595) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.mapping.RootClass.validate(RootClass.Java:265) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.boot.internal.MetadataImpl.validate(MetadataImpl.Java:329) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.Java:443) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.Java:879) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
    ... 27 common frames omitted

Si je ne me trompe pas, cela signifie que je ne peux pas me connecter à ma base de données, j'ai donc du mal à créer l'entité beanManagerFactory

Donc, c'est mon fichier pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.Apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.Apache.org/POM/4.0.0 http://maven.Apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mjamsek</groupId>
    <artifactId>Userboard</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>Userboard</name>
    <description>Userboard</description>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <Java.version>1.8</Java.version>
    </properties>
    <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-freemarker</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.hsqldb</groupId>
            <artifactId>hsqldb</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
        </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.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

Mon application.properties:

spring.datasource.url=jdbc:mysql://localhost:3306/userboard?useSSL=false
spring.datasource.username=my_username
spring.datasource.password=my_pass
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.ftl
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.session.store-type=jdbc
spring.session.jdbc.table-name=SESSIONS
spring.messages.basename=validation

Ensuite, j'ai défini les deux entités suivantes:

ser.Java

package com.proba.Userboard.entity;

import Java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
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;

@Entity
@Table(name="user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="user_id")
    private int id;
    @Column(name="username")
    private String username;
    @Column(name="pass")
    private String pass;
    @Column(name="name")
    private String name;
    private String passConfirm;
    private Set<Role> roles;

    public User() {

    }
    public User(String usr, String pas, String nam) {
        this.username = usr;
        this.pass = pas;
        this.name = nam;
    }
    @Override
    public String toString() {
        return String.format("{ id : %d, username : %s, pass : %s, name : %s }", this.id, this.username, this.pass, this.name);
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPass() {
        return pass;
    }
    public void setPass(String pass) {
        this.pass = pass;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @ManyToMany
    @JoinTable(name="user_role", joinColumns = @JoinColumn(name="user_id"), inverseJoinColumns = @JoinColumn(name="role_id"))
    public Set<Role> getRoles() {
        return roles;
    }
    public void setRoles(Set<Role> roles) {
        this.roles = roles;
    }
    public String getPassConfirm() {
        return passConfirm;
    }
    public void setPassConfirm(String passConfirm) {
        this.passConfirm = passConfirm;
    }
}

Role.Java

package com.proba.Userboard.entity;

import Java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

@Entity
@Table(name="role")
public class Role {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="role")
    private int id;
    @Column(name="role_name")
    private String name;
    private Set<User> users;

    public Role() {

    }
    public Role(String n) {
        this.name = n;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @ManyToMany(mappedBy = "roles")
    public Set<User> getUsers() {
        return users;
    }
    public void setUsers(Set<User> users) {
        this.users = users;
    }
    @Override
    public String toString() {
        return String.format("{ id : %s, name: %s }", this.id, this.name);
    }
}

J'ai les DAO suivants:

RoleDAO.Java

package com.proba.Userboard.dao;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.proba.Userboard.entity.Role;

@Repository
@Transactional
public interface RoleDAO extends JpaRepository<Role, Integer> {

}

serDAO.Java

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.proba.Userboard.entity.User;

@Repository
@Transactional
public interface UserDAO extends JpaRepository<User, Integer> {
    public User findByUsername(String username);
}

Mon Service utilisateur:

package com.proba.Userboard.service;

import Java.util.HashSet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import com.proba.Userboard.dao.RoleDAO;
import com.proba.Userboard.dao.UserDAO;
import com.proba.Userboard.entity.User;

public class UserServiceImpl implements UserService {
    @Autowired
    private UserDAO userDAO;
    @Autowired
    private RoleDAO roleDAO;
    @Autowired
    private BCryptPasswordEncoder bcrypt;

    @Override
    public void save(User user) {

        user.setPass(bcrypt.encode(user.getPass()));
        user.setRoles(new HashSet<>(roleDAO.findAll()));
        userDAO.save(user);

    }
    @Override
    public User findByUsername(String username) {
        return userDAO.findByUsername(username);
    }
}

Mon configuration de sécurité SpringBoot:

package com.proba.Userboard.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@Configuration
@EnableWebSecurity
public class SecurityConf extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserDetailsService userDetailsService;
    @Bean
    public BCryptPasswordEncoder bcyrpt() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/resource/**", "/registration").permitAll()
                .anyRequest().authenticated()
            .and()
                .formLogin()
                    .loginPage("/login")
                    .permitAll()
            .and()
                .logout()
                    .permitAll();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(bcyrpt());
    }
}

Donc, lorsque je lance mvn clean spring-boot: run, j'obtiens l'erreur mentionnée précédemment et je ne peux pas comprendre ce que je fais mal. Auparavant, je faisais une application similaire, qui fonctionnait, mais je ne peux pas comprendre pourquoi celle-ci ne fonctionne pas.

5
Miha Jamsek

Non, le problème n'est pas lié à la connexion à la base de données. Hibernate détermine sa stratégie pour vérifier les annotations de configuration en fonction de la place des annotations sur l'id (sur l'attribut lui-même ou sur une méthode).

Dans votre classe User, vous dites à hibernate d'attendre les annotations au niveau de l'attribut.

public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="user_id")
private int id;

Donc, pour la mise en veille prolongée, vous n'avez pas de mappage pour d'autres attributs comme les rôles, car il ne vérifiera pas les méthodes de mappage, donc ce que vous devez faire est de prendre l'annotation de la méthode et de la placer dans l'attribut.

@ManyToMany
@JoinTable(name="user_role", joinColumns = @JoinColumn(name="user_id"), inverseJoinColumns = @JoinColumn(name="role_id"))
private Set<Role> roles;

Vous devez le faire dans toutes vos annotations.

4
Amer Qarabsa

S'il y a une exception de mappage avec l'exception mentionnée ci-dessus, le problème peut être avec Jdk 11 et javassist.

Besoin d'ajouter ceci dans pom.xml

<dependency>
    <groupId>org.javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.23.1-GA</version>
</dependency>
1
Abhi Madduri