Enterprise Java

Spring Data JPA Tutorial Part One: Configuration

Spring Data JPA is a project which aims both to simplify the creation of JPA based repositories and to reduce the amount of code needed to communicate with a database. I have been using it for a while at my work and in my personal hobby projects and it has indeed make things a lot more simpler and cleaner. Now it is time to share my knowledge with you.

This is the first part of my Spring Data JPA tutorial and it will describe to you, how you can configure Spring Data JPA when you are using Hibernate as your JPA provider. Before we will get started, I want to make one thing straight: This tutorial is not an introductory level tutorial to Hibernate, JPA or Spring. You must have some experience about these technologies if you want to understand the concepts described in my Spring Data JPA tutorial.

The dependencies of this tutorial are following:

  • BoneCP 0.7.1.RELEASE (You can use other data source implementations as well)
  • Hibernate 4.0.1.Final
  • Spring Framework 3.1.0.RELEASE
  • Spring Data JPA 1.0.2
  • Servlet API 3.0

Also, since I am using Maven as a build tool, you must install it if you want to run my example application.

Getting Started

It is time to get started. You can configure the Spring Data JPA by following these steps:

  • You have to obtain the needed dependencies.
  • You must configure the needed beans in your Spring application context configuration. The beans needed by the Spring Data JPA are: data source, transaction manager and entity manager factory.
  • You have to configure the Spring Data JPA.

These steps are explained with more details in following:

Obtaining the Needed Depedencies

First, you need to obtain the needed dependencies. You can do this by configuring the needed dependencies in your pom.xml file. The pom.xml of my example looks following:

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
    <modelVersion>4.0.0</modelVersion>
    <groupId>net.petrikainulainen.spring</groupId>
    <artifactId>data-jpa-tutorial-part-one</artifactId>
    <packaging>war</packaging>
    <version>0.1</version>
    <name>Spring Data JPA Tutorial Part One</name>
    <description>Spring Data JPA Tutorial Part One</description>
    <licenses>
        <license>
            <name>Apache License 2.0</name>
            <url>http://www.apache.org/licenses/LICENSE-2.0</url>
        </license>
    </licenses>
    <repositories>
        <repository>
            <id>repository.jboss.org-public</id>
            <name>JBoss repository</name>
        </repository>
    </repositories>
    <properties>
        <hibernate.version>4.0.1.Final</hibernate.version>
        <mysql.connector.version>5.1.18</mysql.connector.version>
        <slf4j.version>1.6.1</slf4j.version>
        <spring.version>3.1.0.RELEASE</spring.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <!-- Spring Framework -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- Spring MVC -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2.2</version>
        </dependency>
        <!-- Spring Data JPA -->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
            <version>1.0.2.RELEASE</version>
        </dependency>
        <!-- Hibernate -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <!-- H2 Database -->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.3.160</version>
        </dependency>
        <!-- MySQL JDBC connector -->
        <!-- If you want to use MySQL, uncomment this dependency declation. -->
        <!--
       <dependency>
           <groupId>mysql</groupId>
           <artifactId>mysql-connector-java</artifactId>
           <version>${mysql.connector.version}</version>
       </dependency>
       -->
        <!-- PostgreSQL JDBC 4 -->
        <!-- If you don't want to use PostgreSQL, uncomment this dependency declaration. -->
        <!--
       <dependency>
           <groupId>postgresql</groupId>
           <artifactId>postgresql</artifactId>
           <version>9.0-801.jdbc4</version>
       </dependency>
       -->
        <!-- BoneCP -->
        <dependency>
            <groupId>com.jolbox</groupId>
            <artifactId>bonecp</artifactId>
            <version>0.7.1.RELEASE</version>
        </dependency>
        <!-- Servlet API 3.0 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <!-- Logging dependencies -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.16</version>
        </dependency>
        <!-- Testing Dependencies -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.9</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <finalName>data-jpa-tutorial-part-one</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.1.1</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.mortbay.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>8.1.0.RC2</version>
                <configuration>
                    <scanIntervalSeconds>0</scanIntervalSeconds>
                    <webAppConfig>
                        <defaultsDescriptor>src/main/resources/webdefault.xml</defaultsDescriptor>
                    </webAppConfig>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-site-plugin</artifactId>
                <version>3.0</version>
                <configuration>
                    <reportPlugins>
                        <!-- Cobertura Plugin -->
                        <plugin>
                            <groupId>org.codehaus.mojo</groupId>
                            <artifactId>cobertura-maven-plugin</artifactId>
                            <version>2.5.1</version>
                        </plugin>
                    </reportPlugins>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Configuring the Spring Application Context

Second, you must configure the Spring application context. As you might remember, you need to configure the data source, transaction manager and entity manager factory beans. If you are using Spring 3.1 and Servlet 3.0, you can do this by implementing a Java configuration class and loading that configuration class in your web application initializer. The content of my application context configuration class is given in following:

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import com.jolbox.bonecp.BoneCPDataSource;
import org.hibernate.ejb.HibernatePersistence;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.*;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.core.env.Environment;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
 
import javax.annotation.Resource;
import javax.sql.DataSource;
 
/**
 * An application context Java configuration class. The usage of Java configuration
 * requires Spring Framework 3.0 or higher with following exceptions:
 * <ul>
 *     <li>@EnableWebMvc annotation requires Spring Framework 3.1</li>
 * </ul>
 * @author Petri Kainulainen
 */
@Configuration
@ComponentScan(basePackages = {"net.petrikainulainen.spring.datajpa.controller"})
@EnableWebMvc
@ImportResource("classpath:applicationContext.xml")
@PropertySource("classpath:application.properties")
public class ApplicationContext {
    
    private static final String VIEW_RESOLVER_PREFIX = "/WEB-INF/jsp/";
    private static final String VIEW_RESOLVER_SUFFIX = ".jsp";
 
    private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver";
    private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";
    private static final String PROPERTY_NAME_DATABASE_URL = "db.url";
    private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username";
 
    private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
    private static final String PROPERTY_NAME_HIBERNATE_FORMAT_SQL = "hibernate.format_sql";
    private static final String PROPERTY_NAME_HIBERNATE_NAMING_STRATEGY = "hibernate.ejb.naming_strategy";
    private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
    private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN = "entitymanager.packages.to.scan";
 
    private static final String PROPERTY_NAME_MESSAGESOURCE_BASENAME = "message.source.basename";
    private static final String PROPERTY_NAME_MESSAGESOURCE_USE_CODE_AS_DEFAULT_MESSAGE = "message.source.use.code.as.default.message";
 
    @Resource
    private Environment environment;
 
    @Bean
    public DataSource dataSource() {
        BoneCPDataSource dataSource = new BoneCPDataSource();
 
        dataSource.setDriverClass(environment.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER));
        dataSource.setJdbcUrl(environment.getRequiredProperty(PROPERTY_NAME_DATABASE_URL));
        dataSource.setUsername(environment.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME));
        dataSource.setPassword(environment.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));
 
        return dataSource;
    }
 
    @Bean
    public JpaTransactionManager transactionManager() throws ClassNotFoundException {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
 
        transactionManager.setEntityManagerFactory(entityManagerFactoryBean().getObject());
 
        return transactionManager;
    }
 
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() throws ClassNotFoundException {
        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
 
        entityManagerFactoryBean.setDataSource(dataSource());
        entityManagerFactoryBean.setPackagesToScan(
environment.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN));
        entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistence.class);
 
        Properties jpaProterties = new Properties();
        jpaProterties.put(PROPERTY_NAME_HIBERNATE_DIALECT, environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
        jpaProterties.put(PROPERTY_NAME_HIBERNATE_FORMAT_SQL, environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_FORMAT_SQL));
        jpaProterties.put(PROPERTY_NAME_HIBERNATE_NAMING_STRATEGY, environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_NAMING_STRATEGY));
        jpaProterties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
 
        entityManagerFactoryBean.setJpaProperties(jpaProterties);
 
        return entityManagerFactoryBean;
    }
 
    @Bean
    public MessageSource messageSource() {
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
 
        messageSource.setBasename(
environment.getRequiredProperty(PROPERTY_NAME_MESSAGESOURCE_BASENAME));
        messageSource.setUseCodeAsDefaultMessage(
Boolean.parseBoolean(
environment.getRequiredProperty(PROPERTY_NAME_MESSAGESOURCE_USE_CODE_AS_DEFAULT_MESSAGE)));
 
        return messageSource;
    }
 
    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
 
        viewResolver.setViewClass(JstlView.class);
        viewResolver.setPrefix(VIEW_RESOLVER_PREFIX);
        viewResolver.setSuffix(VIEW_RESOLVER_SUFFIX);
 
        return viewResolver;
    }
}

My web application initializer looks like this:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
 
import javax.servlet.*;
 
/**
 * Web application Java configuration class. The usage of web application
 * initializer requires Spring Framework 3.1 and Servlet 3.0.
 * @author Petri Kainulainen
 */
public class DataJPAExampleInitializer implements WebApplicationInitializer {
    
    private static final String DISPATCHER_SERVLET_NAME = "dispatcher";
    private static final String DISPATCHER_SERVLET_MAPPING = "/";
    
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
        rootContext.register(ApplicationContext.class);
 
        ServletRegistration.Dynamic dispatcher = servletContext.addServlet(DISPATCHER_SERVLET_NAME, new DispatcherServlet(rootContext));
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping(DISPATCHER_SERVLET_MAPPING);
 
        servletContext.addListener(new ContextLoaderListener(rootContext));
    }
}

You might have noticed that I used the @PropertySource annotation to specify the location of a properties file which contains the values of used configuration parameters. The content of my application.properties file is following:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# The default database is H2 memory database but I have also
# added configuration needed to use either MySQL and PostgreSQL.
 
#Database Configuration
db.driver=org.h2.Driver
#db.driver=com.mysql.jdbc.Driver
#db.driver=org.postgresql.Driver
db.url=jdbc:h2:mem:datajpa
#db.url=jdbc:mysql://localhost:3306/datajpa
#db.url=jdbc:postgresql://localhost/datajpa
db.username=sa
db.password=
 
#Hibernate Configuration
hibernate.dialect=org.hibernate.dialect.H2Dialect
#hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
#hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
hibernate.format_sql=true
hibernate.ejb.naming_strategy=org.hibernate.cfg.ImprovedNamingStrategy
hibernate.show_sql=true
 
#MessageSource
message.source.basename=i18n/messages
message.source.use.code.as.default.message=true
 
#EntityManager
#Declares the base package of the entity classes
entitymanager.packages.to.scan=net.petrikainulainen.spring.datajpa.model

Configuring Spring Data JPA

Third, you must configure the Spring Data JPA. If you were paying attention, you might have noticed that I used the @ImportResource annotation in my application context configuration class to import additional configuration from a XML configuration file. At the moment Spring Data JPA does not support Java configuration. Thus, the only way to configure it is to use a XML configuration file. My applicationContext.xml file looks following:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?xml version="1.0" encoding="UTF-8"?>
      xsi:schemaLocation="
    <!--
       Configures the location of static resources such as css files.
       Requires Spring Framework 3.0 or higher.
   -->
    <mvc:resources mapping="/static/**" location="/static/"/>
 
    <!--
       Ensures that dispatcher servlet can be mapped to '/' and static resources
       are still served by the containers default servlet. Requires Spring Framework
       3.0 or higher.
   -->
    <mvc:default-servlet-handler/>
 
    <!--
       Configures Spring Data JPA and sets the base package of my DAOs.
   -->
    <jpa:repositories base-package="net.petrikainulainen.spring.datajpa.repository"/>
</beans>

You Are Done

That is it. I have now demonstrated to you how you can configure the Spring Data JPA. I also have created an example application to demonstrate that this configuration is actually working. You can test the configuration yourself by getting my example application from Github and running the example web application by using the Maven Jetty plugin (Note: Remember to create the model and repository packages first. Since it is not possible to add empty directories to the Git staging area, the Github repository does not have them either).

The second part of my Spring Data JPA tutorial describes how you can create a simple CRUD web application by using Spring Data JPA. Stay tuned.
 

Reference: Spring Data JPA Tutorial Part One: Configuration from our JCG partner Petri Kainulainen at the Petri Kainulainen blog.

Petri Kainulainen

Petri is passionate about software development and continuous improvement. He is specialized in software development with the Spring Framework and is the author of Spring Data book.
Subscribe
Notify of
guest


This site uses Akismet to reduce spam. Learn how your comment data is processed.

4 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Rafał
11 years ago

Hi Petri,

Pretty good article! Clear and consistent.

I use there a bit different approach to configure Spring Data JPA: annotations (@EnableJpaRepositories). Thanks to that you can fully get rid of XML configuration.

In case you are interested in quickly starting up with Spring MVC with JPA and Spring Data JPA project have a look at my Maven Archetype: https://github.com/kolorobot/spring-mvc-quickstart-archetype

Petri Kainulainen
11 years ago
Reply to  Rafał

Hi Rafal,

I am happy to hear that you liked the article.

By the way, I use Java configuration as well but when I wrote that blog post, I had to use XML configuration because Java configuration was not supported by the Spring Data JPA.

It was quite annoying. Luckily those days are over.

Paulo
Paulo
11 years ago

Hi Petri, great tutorial, it helped me alot

Congratulations, thanks man !

Geeta
Geeta
9 years ago

Thank you for good tutorial. Could you please provide code which uses XML mapping configuration and not annotation based ?

Thank you,
Geeta

Back to top button