Spring Persistence (Hibernate and JPA) with a JNDI datasource

1. Overview

In this article, we’ll create a Spring application using Hibernate/JPA
with a
JNDI
data source.

If you want to read discover Spring and Hibernate basics, check out
this article.

2. Defining a Datasource

2.1. System

Since we’re using a JNDI data source, we won’t define it in our
application, We’ll define it in our application container. In this
example, we’re going to use 8.5.4 version of
Tomcat.

We’ll also need a database server. In this case, we’ll use 9.5.4 version
of PostgreSQL.

You should be able to replicate the same steps using any other Java
application container and a database of your choice (as long as you have
proper JDBC jars for it!).

2.2. Declaring Datasource

We’ll declare our datasource in <tomcat_home>/conf/server.xml file
inside the <GlobalNamingResources> element.

Assuming that the database server is running on the same machine as the
application container, and that the intended database is named
postgres, and that the username is baeldung with password
pass1234, a resource would look like this:

<Resource name="jdbc/BaeldungDatabase" auth="Container"
  type="javax.sql.DataSource" driverClassName="org.postgresql.Driver"
  url="jdbc:postgresql://localhost:5432/postgres"
  username="baeldung" password="pass1234" maxActive="20" maxIdle="10" maxWait="-1"/>

Take note that we’ve named our resource jdbc/BaeldungDatabase. This
will be the name to be used when referencing this datasource.

We’ve also had to specify its type and database driver’s class name. For
it to work, you must also place the corresponding jar in
<tomcat_home>/lib/ (in this case, PostgreSQL’s JDBC jar).

Remaining configuration parameters are:

  • auth=”Container” – means that the container will be signing on to
    the resource manager on behalf of the application

  • maxActive, maxIdle, and maxWait – are pool connection’s
    configuration parameters

We must also define a ResourceLink inside the <Context> element in
<tomcat_home>/conf/context.xml, which would look like:

<ResourceLink name="jdbc/BaeldungDatabase"
  global="jdbc/BaeldungDatabase" type="javax.sql.DataSource"/>

Note that we are using the name we defined in our Resource in
server.xml.

3. Using the Resource

3.1. Setting the Application

We’re going to define a simple Spring MVC + JPA + Hibernate application
using pure Java config now.

We’ll start by defining the Spring context’s configuration. Keep in mind
that we are focusing on JNDI here and assuming that you already know the
basic of Spring’s configuration.

3.2. Spring Context Configuration

Let’s start with a common Spring MVC’s context configuration:

@EnableWebMvc
@Configuration
@ComponentScan({ "org.baeldung.web" })
public class SpringWebConfig extends WebMvcConfigurerAdapter {
    @Bean
    public InternalResourceViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver
          = new InternalResourceViewResolver();
        viewResolver.setViewClass(JstlView.class);
        viewResolver.setPrefix("/WEB-INF/views/jsp/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }
}

Now let’s define the root context, JPA and Hibernate config:

@Configuration
@EnableTransactionManagement
@PropertySource({ "classpath:persistence-jndi.properties" })
@ComponentScan({ "org.baeldung.persistence" })
@EnableJpaRepositories(basePackages = "org.baeldung.persistence.dao")
public class PersistenceJNDIConfig {

    @Autowired
    private Environment env;

    public PersistenceJNDIConfig() {
        super();
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean em
          = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource());
        em.setPackagesToScan(new String[] { "org.baeldung.persistence.model" });
        em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
        em.setJpaProperties(additionalProperties());
        return em;
    }

    @Bean
    public DataSource dataSource() {
        try {
            return (DataSource) new JndiTemplate()
              .lookup(env.getProperty("jdbc.url"));
        } catch (NamingException e) {
            throw new IllegalArgumentException(
              "Error looking up JNDI datasource", e);
        }
    }

    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(emf);
        return transactionManager;
    }

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
        return new PersistenceExceptionTranslationPostProcessor();
    }

    Properties additionalProperties() {
        Properties hibernateProperties = new Properties();
        hibernateProperties.setProperty(
          "hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
        hibernateProperties.setProperty(
          "hibernate.dialect", env.getProperty("hibernate.dialect"));
        hibernateProperties.setProperty(
          "hibernate.cache.use_second_level_cache", "false");
        return hibernateProperties;
    }
}

Note that all configuration is the same as the one used in the
Spring 4 and JPA with
Hibernate
article with an addition of dataSource bean creation.

In order to create a dataSource bean we need to look for the JNDI
resource defined as:

java:comp/env/jdbc/BaeldungDatabase

We will store this in properties file under the jdbc.url key among
other properties:

jdbc.url=java:comp/env/jdbc/BaeldungDatabase

hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
hibernate.show_sql=false
hibernate.hbm2ddl.auto=update

In the jdbc.url property we are defining a root name to look for:
java:comp/env/ and then the same name we used in server.xml:
jdbc/BaeldungDatabase.

Additionally, we are defining a Hibernate dialect and setting the
hdm2dll to update.

Let’s set up our Initializer and we are ready to go. Since our
application container is Servlet 3.0+ ready, we can stick to the Java
config only:

public class WebInitializer
  extends AbstractAnnotationConfigDispatcherServletInitializer {

   @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[] { PersistenceJNDIConfig.class };
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[] { SpringWebConfig.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }
}

Our Servlet 3.0+ container will pick this class up and run it
automatically.

4. JPA Configuration

4.1. Model, DAO, and Service

We’re going to use a simple model with the @Entity annotation with a
generated id and a name:

@Entity
public class Foo {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "ID")
    private long id;
    @Column(name = "NAME")
    private String name;

    //default getters and setters
}

Let’s define a simple repository like this:

@Repository
public class FooDao {

    @PersistenceContext
    private EntityManager entityManager;

    public List<Foo> findAll() {
        return entityManager
          .createQuery("from " + Foo.class.getName()).getResultList();
    }

}

And lastly, let’s create a simple service:

@Service
@Transactional
public class FooService {

    @Autowired
    private FooDao dao;

    public List<Foo> findAll() {
        return dao.findAll();
    }

}

4.2. Displaying Results

In order to display results, we need two more things: a Controller and
a View.

Let’s build a simple Controller responding with a list of all Foo
entries to HTTP GET requests:

@Controller
public class MainController {

    @Autowired
    private FooService fooService;

    @GetMapping("/")
    public String main(Model model) {
        model.addAttribute("foos", fooService.findAll());
        return "index";
    }

}

Finally, let’s create a simple View showcasing all received items:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Baeldung - Spring JNA JNDI</title>
    </head>
    <body>
        <c:forEach var="foo" items="${foos}">
            <p>
                <c:out value="${foo.name}" />
            </p>
        </c:forEach>
    </body>
</html>

Now, if we deploy our application to our application server, we can go
to http://localhost:8080/<app_name&gt; and see something like:

6. Conclusion

In this article, we created an example Spring application with a JPA
Hibernate setup working with a JNDI data source.

The full project can be found on
GitHub.

Leave a Reply

Your email address will not be published.