开发者

Decouple a JPA entities jar from persistence.xml in SE environment

开发者 https://www.devze.com 2022-12-26 06:33 出处:网络
Is there a way to reuse a jar with JPA anno开发者_StackOverflowtated entities in more than one SE applications (as a dependency)? <jar-file> in persistence.xml is not supported in SE environment

Is there a way to reuse a jar with JPA anno开发者_StackOverflowtated entities in more than one SE applications (as a dependency)? <jar-file> in persistence.xml is not supported in SE environments so is there another way?


Officially (per specification), you have to specify all classes using the class element. Quoting the chapter 6.2.1.6 mapping-file, jar-file, class, exclude-unlisted-classes of the JSR-220:

A list of named managed persistence classes may also be specified instead of, or in addition to, the JAR files and mapping files. Any mapping metadata annotations found on these classes will be processed, or they will be mapped using the mapping annotation defaults. The class element is used to list a managed persistence class. A list of all named managed persistence classes must be specified in Java SE environments to insure portability. Portable Java SE applications should not rely on the other mechanisms described here to specify the managed persistence classes of a persistence unit. Persistence providers may also require that the set of entity classes and classes that are to be managed must be fully enumerated in each of the persistence.xml files in Java SE environments.

Now, if you don't mind being not portable, Hibernate supports using the jar-file element in Java SE (in this case an absolute url is needed, not handy). Hibernate actually also supports auto-detection even in JSE. Much better:

<persistence 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_1_0.xsd"
  version="1.0">
  <persistence-unit name="foo">

    <!-- This is required to be spec compliant, Hibernate however supports auto-detection even in JSE. -->
    <class>foo.Bar<class>

    <properties>
      <!-- Scan for annotated classes and Hibernate mapping XML files -->
      <property name="hibernate.archive.autodetection" value="class, hbm"/>
      ...
    </properties>
  </persistence-unit>

</persistence>


As far as I know, there is no way to get the class scanning for annotations to work in that configuration. You can however explicitly point your persistence.xml file at each entity class.

<persistence 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_1_0.xsd"
                     version="1.0">

  <persistence-unit name="punit">

    <provider>org.hibernate.ejb.HibernatePersistence</provider>

    <jta-data-source>java:/myDS</jta-data-source>

    <!-- Must be explicit as classes are in separate jar -->
    <class>com.foo.Bar</class>
    <class>com.foo.Baz</class>

    <properties/>      
  </persistence-unit>

</persistence>


From my experience - It now works.

We are using: Hibernate3.jar 3.6.0.Final hibernate-jpa-2.0-api-1.0.0.Final.jar

The < jar-file >file:...< /jar-file > knows how to look for relative paths - and it works both for jar files or directories.

I'm using this ability twice:

  • with a Jar holding my entities - which is used in several apps. each app has it's own persistence.xml - mainly to provide different ehcache settings.
  • With Junits when I want all my tests, in all other dependent projects to have a single persistence.xml file that will point to all the entities in the entities project. Then we keep the persistence.xml in the entities project under test/resources/META-INF pointing to the Bin directory of that project: < jar-file >file:../entities/bin< /jar-file >


This was a problem I ran into. Slightly more preverse as I need to run several jar standalone as well as part of a war deployment.

There are a few hacks out there which seem to revolve around either multiple persistence.xml files and/or some strange-looking attempt at trying to reference the jar file using spring resource loaders (which didn't work for me).

My personal hack is to use spring resource loaders to resolve a resource which is in ALL the entity jars, parse out the URL jar reference and use a Spring persistence unit manager to inject these into the jar-file tag in the virtual persistence.xml

This is round-about way of doing it but avoids having multiple persistence.xml - which is technically invalid.

public class SpringPersistenceUnitManager extends DefaultPersistenceUnitManager implements ApplicationContextAware {

private final Logger log = LoggerFactory.getLogger(getClass());

private ApplicationContext ctx = null;


private String jarLocationPattern;

@Override
protected void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui) {
    super.postProcessPersistenceUnitInfo(pui);
    try {
        Resource[] resources = ctx.getResources("classpath*:applicationContext.xml");
        for (Resource res : resources) {
            String resJar = resolveJar(res.getURL());
            if (!resJar.equals(pui.getPersistenceUnitRootUrl().toString())) {
                log.info("Adding " + resJar + " to persistence context");
                pui.addJarFileUrl(new URL(resJar));
            }
        }
    }
    catch (IOException e) {
        log.error("error", e);
    }
}

private String resolveJar(URL fileInJar) {
    String path = fileInJar.getPath();
    return path.substring(0, path.indexOf('!'));
}

and the spring context stuff:

<util:properties id="hibernate.properties" location="classpath:hibernate.properties" />

<bean id="persistenceUnitManager" class="com.rokksoft.blackice.util.SpringPersistenceUnitManager"
    p:defaultDataSource-ref="jdbcDataSourcePool"
/>

<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" lazy-init="true"
    p:persistenceUnitManager-ref="persistenceUnitManager"
    p:persistenceUnitName="blackicePU"
    p:dataSource-ref="jdbcDataSourcePool"
    p:jpaProperties-ref="hibernate.properties">
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
    </property>
</bean>

You want to filter the jar names ideally though - 3rd party jar could have anything in.

0

精彩评论

暂无评论...
验证码 换一张
取 消