Spring Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE
Persistence top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

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> 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.

Spring bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE
Persistence bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE
Comments are closed on this article!