Spring ORM - Using LocalContainerEntityManagerFactoryBean for setting up JPA EntityManagerFactory Programmatically

[Updated: Nov 24, 2017, Created: Nov 23, 2017]

As compare to LocalEntityManagerFactoryBean (last example), LocalContainerEntityManagerFactoryBean gives more control for setting up EntityManagerFactory. From docs:

As with LocalEntityManagerFactoryBean, configuration settings are usually read in from a META-INF/persistence.xml config file, residing in the class path, according to the general JPA configuration contract. However, this FactoryBean (LocalContainerEntityManagerFactoryBean) is more flexible in that you can override the location of the persistence.xml file, specify the JDBC DataSources to link to, etc. Furthermore, it allows for pluggable class instrumentation through Spring's LoadTimeWeaver abstraction, instead of being tied to a special VM agent specified on JVM startup.

Example

In following example, we are going to use Hibernate as a JPA provider.

JPA persistence xml file

src/main/resources/jpa/my-persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
             xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="example-unit" transaction-type="RESOURCE_LOCAL">
    </persistence-unit>
</persistence>

As seen above, instead of using the default name for persistence.xml file, we have a custom name and location for it, also it just needs to have the persistence unit declaration, the rest of the configuration can be done programmatically via LocalContainerEntityManagerFactoryBean.

Java Config

@Configuration
public class AppConfig {

  @Bean
  public DataSource h2DataSource() {
      return new EmbeddedDatabaseBuilder()
              .setType(EmbeddedDatabaseType.H2)
              .build();
  }

  @Bean
  public LocalContainerEntityManagerFactoryBean factoryBean() {
      LocalContainerEntityManagerFactoryBean factory =
              new LocalContainerEntityManagerFactoryBean();
      factory.setDataSource(h2DataSource());
      factory.setPersistenceProviderClass(HibernatePersistenceProvider.class);
      //comment the following line if you want to use default META-INF/persistence.xml
      factory.setPersistenceXmlLocation("jpa/my-persistence.xml");
      Properties properties = new Properties();
      properties.setProperty("javax.persistence.schema-generation.database.action", "create");
      factory.setJpaProperties(properties);
      return factory;
  }
}

JPA Entity

package com.logicbig.example;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Person {
  @Id
  @GeneratedValue
  private int id;
  private String name;
    .............
}
public class ExampleMain {

  public static void main(String[] args) {
      AnnotationConfigApplicationContext context =
              new AnnotationConfigApplicationContext(AppConfig.class);
      EntityManagerFactory emf = context.getBean(EntityManagerFactory.class);
      try {
          nativeQuery(emf, "SHOW TABLES");
          nativeQuery(emf, "SHOW COLUMNS from Person");
          Person person = new Person();
          person.setName("Joe");
          persistEntity(emf, person);
          nativeQuery(emf, "Select * from Person");
      } finally {
          emf.close();
      }
  }

  private static void persistEntity(EntityManagerFactory emf, Person person) {
      System.out.println("------------");
      System.out.println("Persisting person: " + person);
      EntityManager em = emf.createEntityManager();
      em.getTransaction().begin();
      em.persist(person);
      em.getTransaction().commit();
      em.close();
  }

  private static void nativeQuery(EntityManagerFactory emf, String s) {
      EntityManager em = emf.createEntityManager();
      System.out.printf("---------------------------%n'%s'%n", s);
      Query query = em.createNativeQuery(s);
      List list = query.getResultList();
      for (Object o : list) {
          if (o instanceof Object[]) {
              System.out.println(Arrays.toString((Object[]) o));
          } else {
              System.out.println(o);
          }
      }
      em.close();
  }
}

Output

---------------------------
'SHOW TABLES'
[PERSON, PUBLIC]
---------------------------
'SHOW COLUMNS from Person'
[ID, INTEGER(10), NO, PRI, NULL]
[NAME, VARCHAR(255), YES, , NULL]
------------
Persisting person: Person{id=0, name='Joe'}
---------------------------
'Select * from Person'
[1, Joe]

Example Project

Dependencies and Technologies Used :

  • spring-context 5.0.1.RELEASE: Spring Context.
  • spring-orm 5.0.1.RELEASE: Spring Object/Relational Mapping.
  • hibernate-core 5.2.12.Final: The core O/RM functionality as provided by Hibernate.
  • h2 1.4.196: H2 Database Engine.
  • JDK 1.8
  • Maven 3.3.9

Spring JPA with LocalContainerEntityManagerFactoryBean Example Select All Download
  • jpa-local-container-entity-manager-bean
    • src
      • main
        • java
          • com
            • logicbig
              • example
        • resources
          • jpa

See Also