Sebastian
Sebastian

Reputation: 868

JPA: create EntityManagerFactory from properties

i am using JPA in a JAR-Project and used the persistence.xml to setup my EntityManager.

But since the persistence.xml is inside the JAR after the build it is very complicated for the user to change the settings afterwards. So i'm looking for a solution where i can configure my connection over a propertyfile which is loaded at runtime.

I came across this solution on the web:

Map properties = new HashMap();

// Configure the internal EclipseLink connection pool
properties.put(JDBC_DRIVER, "oracle.jdbc.OracleDriver");
properties.put(JDBC_URL, "jdbc:oracle:thin:@localhost:1521:ORCL");
properties.put(JDBC_USER, "user-name");
properties.put(JDBC_PASSWORD, "password");

Persistence.createEntityManagerFactory("unit-name", properties);

Which is the solution i was looking for but i'm missing one thing here: In my persistence.xml i also declare a schema name over a mapping file:

persistence.xml:

<persistence version="2.0" ...>
  <persistence-unit name="jpa" transaction-type="RESOURCE_LOCAL">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <class>...</class>
    <exclude-unlisted-classes>true</exclude-unlisted-classes>
    <properties>
      <property name="javax.persistence.jdbc.url" value="..."/>
      <property name="javax.persistence.jdbc.password" value="..."/>
      <property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver"/>
      <property name="javax.persistence.jdbc.user" value="..."/>
    </properties>
    <mapping-file>META-INF/orm.xml</mapping-file>
  </persistence-unit>
</persistence>

orm.xml:

<entity-mappings ...>
 <persistence-unit-metadata>
  <persistence-unit-defaults>
   <schema>SCHEMA_NAME</schema>
  </persistence-unit-defaults>
 </persistence-unit-metadata>
</entity-mappings>

So my question is basically: Is there a property i can use to set the schema at runtime, just like i do with the other properties?

Or is there even a better solution?

Thanks in advance!

Upvotes: 3

Views: 19819

Answers (4)

Ronald Coarite
Ronald Coarite

Reputation: 4726

Use this class PersistenceUnitProperties for names.

The see link https://gerardnico.com/jpa/property

Propertie example

javax.persistence.jdbc.driver=org.sqlite.JDBC
eclipselink.ddl-generation=create-tables
#eclipselink.ddl-generation=none
javax.persistence.jdbc.url=jdbc:sqlite:domo.db

Persistence example (persistence.xml)

<persistence
    version="2.0" 
    xmlns="http://java.sun.com/xml/ns/persistence" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    <persistence-unit name="PersistenceNameExample" transaction-type="RESOURCE_LOCAL">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <properties></properties>
    </persistence-unit>
</persistence>

Instance

Properties props = new Properties();
//props.setProperty("hibernate.hbm2ddl.auto", "none");
props.load(new FileInputStream("prop_example.properties"));
Persistence.createEntityManagerFactory("PersistenceNameExample",props);

Eclipse example dependence for provider

    <dependency>
        <groupId>org.eclipse.persistence</groupId>
        <artifactId>org.eclipse.persistence.jpa</artifactId>
        <version>2.7.4</version>
    </dependency>

Upvotes: 1

Jonathan Rosenne
Jonathan Rosenne

Reputation: 2217

META-INF/orm.xml is the default name, and if the file exists it will be used whether it has been specified in the persistence unit or not. If the mapping file in the persistence.xml has another name then the default name is not used.

To use several incompatible database providers, such as SQL Server and Oracle, it is possible to have several persistence-units in the persistence.xml, and to select the suitable unit at run time. If the mapping files are named with non-default names, each unit can have its own mapping file or none at all.

Upvotes: 0

Leon
Leon

Reputation: 12481

Switch to java config. Then you can easily inject property values by autowiring Environment

This example is extremely basic. But in general if you know how to do the xml config you can map it straight onto the Java config

contextConfig.java

/**
 * Spring Context configuration.
 */
@ComponentScan(basePackages = { "com.example" })
@PropertySource({ "classpath:common.properties" })
@Configuration
@Import(JpaConfig.class)
public class ContextConfig extends WebMvcConfigurerAdapter {
    /**
     * This bean is needed because Spring when you use xml config to load property files the bean is automatically
     * created... when you use @PropertySource then not so much
     * @return new bean
     */
    @Bean
    public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }
}

jpaConfig.java

@Configuration
@EnableJpaRepositories("com.example.repository")
public class JpaConfig {

    @Autowired
    private Environment env;

    /**
     * Create the fooDataSource Bean.
     * @return fooDataSource Bean
     */
    @Bean
    public BasicDataSource fooDataSource() {

        BasicDataSource basicDataSource = new BasicDataSource();
        basicDataSource.setDriverClassName(env.getProperty("cfg_foo.driver.name"));
        basicDataSource.setUrl(env.getProperty("cfg_foo.jdbc.url"));
        basicDataSource.setUsername(env.getProperty("cfg_foo.username"));
        basicDataSource.setPassword(env.getProperty("cfg_foo.password"));
        basicDataSource.setPoolPreparedStatements(Boolean.valueOf(env.getProperty("cfg_foo.poolPreparedStatements")));
        basicDataSource.setInitialSize(Integer.valueOf(env.getProperty("cfg_foo.poolInitialSize")));
        basicDataSource.setMaxActive(Integer.valueOf(env.getProperty("cfg_foo.poolMaxActive")));
        basicDataSource.setMaxIdle(Integer.valueOf(env.getProperty("cfg_foo.poolMaxIdle")));
        basicDataSource.setValidationQuery("SELECT '1'");

        return basicDataSource;
    }

    /**
     * Create the hibernateJpaVendorAdapter Bean.
     * @return hibernateJpaVendorAdapter Bean
     */
    @Bean
    public HibernateJpaVendorAdapter hibernateJpaVendorAdapter() {

        HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
        adapter.setDatabasePlatform("org.hibernate.dialect.MySQLDialect");
        adapter.setShowSql(Boolean.valueOf(env.getProperty("show.sql")));
        adapter.setGenerateDdl(Boolean.valueOf(env.getProperty("format.sql")));

        return adapter;
    }

    /**
     * Create the entityManagerFactory Bean.
     * @return entityManagerFactory Bean
     */
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {

        LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactory.setPersistenceUnitName("foo");
        entityManagerFactory.setDataSource(fooDataSource());
        entityManagerFactory.setJpaVendorAdapter(hibernateJpaVendorAdapter());
        entityManagerFactory.setPackagesToScan("com.example.repository");

        return entityManagerFactory;
    }

}

Upvotes: 3

Shmil The Cat
Shmil The Cat

Reputation: 4670

I don't know if its a better solution, but you can annotate your JPA entities w/ the desired schema

@Entity
@Table(name = "Foo", schema = "Bar")

Upvotes: 0

Related Questions