Create JPA EntityManager without persistence.xml configuration file

JpaRuntimeEntitymanagerpersistence.xml

Jpa Problem Overview


Is there a way to initialize the EntityManager without a persistence unit defined? Can you give all the required properties to create an entity manager? I need to create the EntityManager from the user's specified values at runtime. Updating the persistence.xml and recompiling is not an option.

Any idea on how to do this is more than welcomed!

Jpa Solutions


Solution 1 - Jpa

> Is there a way to initialize the EntityManager without a persistence unit defined?

You should define at least one persistence unit in the persistence.xml deployment descriptor.

> Can you give all the required properties to create an Entitymanager?

  • The name attribute is required. The other attributes and elements are optional. (JPA specification). So this should be more or less your minimal persistence.xml file:

<persistence>
    <persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
        SOME_PROPERTIES
    </persistence-unit>
</persistence>

> In Java EE environments, the jta-data-source and non-jta-data-source elements are used to specify the global JNDI name of the JTA and/or non-JTA data source to be used by the persistence provider.

So if your target Application Server supports JTA (JBoss, Websphere, GlassFish), your persistence.xml looks like:

<persistence>
    <persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
        <!--GLOBAL_JNDI_GOES_HERE-->
        <jta-data-source>jdbc/myDS</jta-data-source>
    </persistence-unit>
</persistence>

If your target Application Server does not support JTA (Tomcat), your persistence.xml looks like:

<persistence>
    <persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
        <!--GLOBAL_JNDI_GOES_HERE-->
        <non-jta-data-source>jdbc/myDS</non-jta-data-source>
    </persistence-unit>
</persistence>

If your data source is not bound to a global JNDI (for instance, outside a Java EE container), so you would usually define JPA provider, driver, url, user and password properties. But property name depends on the JPA provider. So, for Hibernate as JPA provider, your persistence.xml file will looks like:

<persistence>
    <persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <class>br.com.persistence.SomeClass</class>
        <properties>
            <property name="hibernate.connection.driver_class" value="org.apache.derby.jdbc.ClientDriver"/>
            <property name="hibernate.connection.url" value="jdbc:derby://localhost:1527/EmpServDB;create=true"/>
            <property name="hibernate.connection.username" value="APP"/>
            <property name="hibernate.connection.password" value="APP"/>
        </properties>
    </persistence-unit>
</persistence>

Transaction Type Attribute

> In general, in Java EE environments, a transaction-type of RESOURCE_LOCAL assumes that a non-JTA datasource will be provided. In a Java EE environment, if this element is not specified, the default is JTA. In a Java SE environment, if this element is not specified, a default of RESOURCE_LOCAL may be assumed.

  • To insure the portability of a Java SE application, it is necessary to explicitly list the managed persistence classes that are included in the persistence unit (JPA specification)

> I need to create the EntityManager from the user's specified values at runtime

So use this:

Map addedOrOverridenProperties = new HashMap();

// Let's suppose we are using Hibernate as JPA provider
addedOrOverridenProperties.put("hibernate.show_sql", true);

Persistence.createEntityManagerFactory(<PERSISTENCE_UNIT_NAME_GOES_HERE>, addedOrOverridenProperties);

Solution 2 - Jpa

Yes you can without using any xml file using spring like this inside a @Configuration class (or its equivalent spring config xml):

@Bean
public LocalContainerEntityManagerFactoryBean emf(){
    properties.put("javax.persistence.jdbc.driver", dbDriverClassName);
    properties.put("javax.persistence.jdbc.url", dbConnectionURL);
    properties.put("javax.persistence.jdbc.user", dbUser); //if needed

    LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
    emf.setPersistenceProviderClass(org.eclipse.persistence.jpa.PersistenceProvider.class); //If your using eclipse or change it to whatever you're using
    emf.setPackagesToScan("com.yourpkg"); //The packages to search for Entities, line required to avoid looking into the persistence.xml
    emf.setPersistenceUnitName(SysConstants.SysConfigPU);
    emf.setJpaPropertyMap(properties);
    emf.setLoadTimeWeaver(new ReflectiveLoadTimeWeaver()); //required unless you know what your doing
    return emf;
}

Solution 3 - Jpa

Here's a solution without Spring. Constants are taken from org.hibernate.cfg.AvailableSettings :

entityManagerFactory = new HibernatePersistenceProvider().createContainerEntityManagerFactory(
            archiverPersistenceUnitInfo(),
            ImmutableMap.<String, Object>builder()
                    .put(JPA_JDBC_DRIVER, JDBC_DRIVER)
                    .put(JPA_JDBC_URL, JDBC_URL)
                    .put(DIALECT, Oracle12cDialect.class)
                    .put(HBM2DDL_AUTO, CREATE)
                    .put(SHOW_SQL, false)
                    .put(QUERY_STARTUP_CHECKING, false)
                    .put(GENERATE_STATISTICS, false)
                    .put(USE_REFLECTION_OPTIMIZER, false)
                    .put(USE_SECOND_LEVEL_CACHE, false)
                    .put(USE_QUERY_CACHE, false)
                    .put(USE_STRUCTURED_CACHE, false)
                    .put(STATEMENT_BATCH_SIZE, 20)
                    .build());

entityManager = entityManagerFactory.createEntityManager();

And the infamous PersistenceUnitInfo

private static PersistenceUnitInfo archiverPersistenceUnitInfo() {
    return new PersistenceUnitInfo() {
        @Override
        public String getPersistenceUnitName() {
            return "ApplicationPersistenceUnit";
        }

        @Override
        public String getPersistenceProviderClassName() {
            return "org.hibernate.jpa.HibernatePersistenceProvider";
        }

        @Override
        public PersistenceUnitTransactionType getTransactionType() {
            return PersistenceUnitTransactionType.RESOURCE_LOCAL;
        }

        @Override
        public DataSource getJtaDataSource() {
            return null;
        }

        @Override
        public DataSource getNonJtaDataSource() {
            return null;
        }

        @Override
        public List<String> getMappingFileNames() {
            return Collections.emptyList();
        }

        @Override
        public List<URL> getJarFileUrls() {
            try {
                return Collections.list(this.getClass()
                                            .getClassLoader()
                                            .getResources(""));
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
        }

        @Override
        public URL getPersistenceUnitRootUrl() {
            return null;
        }

        @Override
        public List<String> getManagedClassNames() {
            return Collections.emptyList();
        }

        @Override
        public boolean excludeUnlistedClasses() {
            return false;
        }

        @Override
        public SharedCacheMode getSharedCacheMode() {
            return null;
        }

        @Override
        public ValidationMode getValidationMode() {
            return null;
        }

        @Override
        public Properties getProperties() {
            return new Properties();
        }

        @Override
        public String getPersistenceXMLSchemaVersion() {
            return null;
        }

        @Override
        public ClassLoader getClassLoader() {
            return null;
        }

        @Override
        public void addTransformer(ClassTransformer transformer) {

        }

        @Override
        public ClassLoader getNewTempClassLoader() {
            return null;
        }
    };
}

Solution 4 - Jpa

I was able to create an EntityManager with Hibernate and PostgreSQL purely using Java code (with a Spring configuration) the following:

@Bean
public DataSource dataSource() {
	final PGSimpleDataSource dataSource = new PGSimpleDataSource();

	dataSource.setDatabaseName( "mytestdb" );
	dataSource.setUser( "myuser" );
	dataSource.setPassword("mypass");

	return dataSource;
}

@Bean
public Properties hibernateProperties(){
	final Properties properties = new Properties();

	properties.put( "hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect" );
	properties.put( "hibernate.connection.driver_class", "org.postgresql.Driver" );
	properties.put( "hibernate.hbm2ddl.auto", "create-drop" );

	return properties;
}

@Bean
public EntityManagerFactory entityManagerFactory( DataSource dataSource, Properties hibernateProperties ){
	final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
	em.setDataSource( dataSource );
	em.setPackagesToScan( "net.initech.domain" );
	em.setJpaVendorAdapter( new HibernateJpaVendorAdapter() );
	em.setJpaProperties( hibernateProperties );
	em.setPersistenceUnitName( "mytestdomain" );
	em.setPersistenceProviderClass(HibernatePersistenceProvider.class);
	em.afterPropertiesSet();

	return em.getObject();
}

The call to LocalContainerEntityManagerFactoryBean.afterPropertiesSet() is essential since otherwise the factory never gets built, and then getObject() returns null and you are chasing after NullPointerExceptions all day long. >:-(

It then worked with the following code:

PageEntry pe = new PageEntry();
pe.setLinkName( "Google" );
pe.setLinkDestination( new URL( "http://www.google.com" ) );

EntityTransaction entTrans = entityManager.getTransaction();
entTrans.begin();
entityManager.persist( pe );
entTrans.commit();

Where my entity was this:

@Entity
@Table(name = "page_entries")
public class PageEntry {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private long id;

	private String linkName;
	private URL linkDestination;

	// gets & setters omitted
}

Solution 5 - Jpa

With plain JPA, assuming that you have a PersistenceProvider implementation (e.g. Hibernate), you can use the PersistenceProvider#createContainerEntityManagerFactory(PersistenceUnitInfo info, Map map) method to bootstrap an EntityManagerFactory without needing a persistence.xml.

However, it's annoying that you have to implement the PersistenceUnitInfo interface, so you are better off using Spring or Hibernate which both support bootstrapping JPA without a persistence.xml file:

this.nativeEntityManagerFactory = provider.createContainerEntityManagerFactory(
    this.persistenceUnitInfo, 
    getJpaPropertyMap()
);

Where the PersistenceUnitInfo is implemented by the Spring-specific MutablePersistenceUnitInfo class.

Solution 6 - Jpa

DataNucleus JPA that I use also has a way of doing this in its docs. No need for Spring, or ugly implementation of PersistenceUnitInfo.

Simply do as follows

import org.datanucleus.metadata.PersistenceUnitMetaData;
import org.datanucleus.api.jpa.JPAEntityManagerFactory;

PersistenceUnitMetaData pumd = new PersistenceUnitMetaData("dynamic-unit", "RESOURCE_LOCAL", null);
pumd.addClassName("mydomain.test.A");
pumd.setExcludeUnlistedClasses();
pumd.addProperty("javax.persistence.jdbc.url", "jdbc:h2:mem:nucleus");
pumd.addProperty("javax.persistence.jdbc.user", "sa");
pumd.addProperty("javax.persistence.jdbc.password", "");
pumd.addProperty("datanucleus.schema.autoCreateAll", "true");

EntityManagerFactory emf = new JPAEntityManagerFactory(pumd, null);

Solution 7 - Jpa

You can also get an EntityManager using PersistenceContext or Autowired annotation, but be aware that it will not be thread-safe.

@PersistenceContext
private EntityManager entityManager;

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionjavydreamercswView Question on Stackoverflow
Solution 1 - JpaArthur RonaldView Answer on Stackoverflow
Solution 2 - JpaFrank OrellanaView Answer on Stackoverflow
Solution 3 - JpaBriceView Answer on Stackoverflow
Solution 4 - JpaSledView Answer on Stackoverflow
Solution 5 - JpaVlad MihalceaView Answer on Stackoverflow
Solution 6 - Jpauser3973283View Answer on Stackoverflow
Solution 7 - JpaAnkit SharmaView Answer on Stackoverflow