3

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!

0

4 Answers 4

3

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;
    }

}
Sign up to request clarification or add additional context in comments.

3 Comments

I added a very basic example to my answer. Hope it helps :)
Thanks for this example, its more clear now what you ment. But we don't use Spring in this project and i couldn't see where you configure the schema? (do i miss something?)
Oh... apologies. I have no idea how to do this without SPring
1

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>

Comments

0

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")

2 Comments

Wouldn't it hard code the schema so the user can't change it at all?
It does. Avoid this kind of hard coding.
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.