Spring-boot+JPA EntityManager inject fails

38.4k views Asked by At

In my J2EE application I try to use spring-boot and JPA technologies with injection of EntityManager into DAO layer. However, I have some problems... My repository for user CRUD:

@Repository
public class UserRepositoryImpl implements UserRepository {

@PersistenceContext(unitName = "data")
private EntityManager entityManager;
// and crud methods
}

My spring-boot application class:

@SpringBootApplication
public class App {
    public static void main(String [] args) {
        SpringApplication.run(App.class, args);
    }

}

And finally my persistence.xml, located in src/main/resources/META-INF folder:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence          http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="data" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
    <class>com.example.domain.User</class>
    <exclude-unlisted-classes>true</exclude-unlisted-classes>
    <properties>
        <property name="hibernate.connection.autocommit" value="false" />
        <property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect" />
        <property name="hibernate.c3p0.min_size" value="4" />
        <property name="hibernate.c3p0.max_size" value="128" />
        <property name="javax.persistence.jdbc.url" value="jdbc:sqlserver://localhost:1433;databaseName=qwerty;sendStringParametersAsUnicode=false" />
        <property name="javax.persistence.jdbc.user" value="sa" />
        <property name="javax.persistence.jdbc.driver" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
        <property name="javax.persistence.jdbc.password" value="" />
        <property name="hibernate.hbm2ddl.auto" value="update" />
        <property name="hibernate.show_sql" value="false" />
    </properties>
</persistence-unit>

So, when I try using this injected entityManager I get NullPointerException. Other @Autowired fields are injected without any problems. What's wrong with this code? Do I need some extra configuration? I am a beginner (not even a Junior developer) and I do have some misunderstanding of what Spring-boot is and how to configure it, like Spring in xml file. If such an xml configuration is needed due to inject EM, please, show how to do it.

upd2. Dependencies

<dependencies>
    <!-- logger -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
    </dependency>

    <!-- db -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-c3p0</artifactId>
    </dependency>
    <dependency>
        <groupId>org.javassist</groupId>
        <artifactId>javassist</artifactId>
    </dependency>
    <dependency>
        <groupId>com.microsoft</groupId>
        <artifactId>sqljdbc4</artifactId>
    </dependency>
    <dependency>
        <groupId>org.quartz-scheduler</groupId>
        <artifactId>quartz</artifactId>
        <version>2.2.1</version>
    </dependency>

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>2.5.3</version>
    </dependency>

    <!-- csv -->
    <dependency>
        <groupId>com.opencsv</groupId>
        <artifactId>opencsv</artifactId>
        <version>3.3</version>
    </dependency>

    <!-- spring-boot -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
        <version>1.2.4.RELEASE</version>

        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-logging</artifactId>
            </exclusion>
        </exclusions>

    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-log4j</artifactId>
        <version>1.2.4.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>4.1.6.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>1.2.4.RELEASE</version>

        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-logging</artifactId>
            </exclusion>
        </exclusions>

    </dependency>
4

There are 4 answers

6
stalet On BEST ANSWER

You should use the dependency for spring-boot-starter-data-jpa

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

And to use a persistence xml you should define a bean as it says in the documentation.

Spring doesn’t require the use of XML to configure the JPA provider, and Spring Boot assumes you want to take advantage of that feature. If you prefer to use persistence.xml then you need to define your own @Bean of type LocalEntityManagerFactoryBean (with id ‘entityManagerFactory’, and set the persistence unit name there.

http://docs.spring.io/spring-boot/docs/current/reference/html/howto-data-access.html#howto-use-traditional-persistence-xml

Or you could skip the persistence.xml entirely and define connection properties in the application.properties file.

Quote from the documentation

DataSource configuration is controlled by external configuration properties in spring.datasource.*. For example, you might declare the following section in application.properties:

spring.datasource.url=jdbc:mysql://localhost/test
spring.datasource.username=dbuser
spring.datasource.password=dbpass
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-sql.html#boot-features-connect-to-production-database

(change the driver and other data to match your environment)

Good luck!

0
BERGUIGA Mohamed Amine On

you can use java configuration in order to configure jpa persistence. The code bellow show you sample example of configuration:

@Component
public class JpaConfiguration {

    @Bean
    @Primary
    public DataSource dataSource() {

        final SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
        dataSource.setDriver(new org.postgresql.Driver());
        dataSource.setUrl("jdbc:postgresql://localhost:5432/users"); 
        dataSource.setUsername("postgres");
        dataSource.setPassword("admin");

        return dataSource;
    }

    @Bean
    public JpaVendorAdapter jpaVendorAdapter() {
        HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
        jpaVendorAdapter.setGenerateDdl(true);
        jpaVendorAdapter.setShowSql(true);
        jpaVendorAdapter.setDatabasePlatform("org.hibernate.dialect.PostgreSQLDialect");

        return jpaVendorAdapter;
    }  

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {

        LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
        lef.setPackagesToScan("tn.bergit.crud.entity");
        lef.setDataSource(dataSource());
        lef.setJpaVendorAdapter(jpaVendorAdapter());

        Properties properties = new Properties();
        properties.setProperty("hibernate.show_sql", "true");
        properties.setProperty("hibernate.jdbc.fetch_size", "100");
        properties.setProperty("hibernate.hbm2ddl.auto", "update");

        lef.setJpaProperties(properties);
        return lef;
    }    


}

You can see this example on github (click here)

0
Eagle_Eye On

The class from which you're asking for the EntityManager should be a Spring Bean if you're using the following

public class Foo {
  @PersistenceContext
  private EntityManager entityManager;
}

Here, if you're using new keyword to get an instance of Foo class above, then EntityManager will be null.

Hope this helps someone!

0
vedat On

if you want to keep using persistence.xml file just add the below code in your configuration class

    @Bean
public LocalEntityManagerFactoryBean entityManagerFactory(){
    LocalEntityManagerFactoryBean factoryBean = new LocalEntityManagerFactoryBean();
    factoryBean.setPersistenceUnitName("data");
    return factoryBean;
}