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!
This question is related to
jpa
runtime
entitymanager
persistence.xml
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.
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);
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;
}
};
}
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;
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;
}
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 NullPointerException
s 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
}
Source: Stackoverflow.com