13

i have a project setup where i have modularized a project, and packaged a module into a jar file which gets included in the main project when we create a war and deploy it. The problem that i am facing is that, i have an Entity present in the module which does not load when the JPA Container EntityManagerFactory for the unitName is built during startup.

The basic question that i have is doesnt the EntityManager lookup at the persistence.xml and then load the properties that are specified, and then scan all the packages for @Entity annotation?

Any insight on how this works and how can i resolve this would be great.

I found this link and it mentions about creating seperate persistenceUnits, but here i dont need a seperate persistence unit. i just need the module to piggy back on the parent project and load the entity and any other @Resource, @Component classes, which it does due to the context:component scan and the annotation config.

http://javathoughts.capesugarbird.com/2009/02/jpa-and-multiple-persistence-units.html

Here is my code/configuration

<bean id="entityManagerFactory"  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="persistenceUnitName" value="LineManagement" />
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="generateDdl" value="false" />
            <property name="showSql" value="false" />
            <property name="databasePlatform" ref="cpsHibernateDialectClassName" />
        </bean>
    </property>
    <property name="beanName" value="entityManager"></property>
</bean>

definition of the EnitityManagerFactory to startup the Entity Manager.

<persistence-unit name="LineManagement" transaction-type="RESOURCE_LOCAL">
    <properties>
        <property name="hibernate.id.new_generator_mappings" value="true" />
        <property name="hibernate.current_session_context_class" value="thread" />
        <property name="hibernate.default_batch_fetch_size" value="200" />

....

Persistence.xml which defines the second level cache and other hibernate properties.

Then, the module which has an entity.

import javax.persistence.Entity;


@Entity
@Table(name = IntegrationEvent.TABLE_NAME, uniqueConstraints =    @UniqueConstraint(columnNames = "INTGRTN_EVNT_QUEUE_SK"))
@GenericGenerator(name = "UUID_GEN", strategy = "org.hibernate.id.UUIDHexGenerator",     parameters = { @Parameter(name = "separator", value = "-") })
public class IntegrationEvent implements Serializable {

.... }

Note: the entity is in a different package than the parent, since it is a seperate module on its own.

The entity which loads fine in the main project.

package com.parent.line.entity;

import javax.persistence.Entity;

@Entity
@Table(name = "ACCOUNT")
@Cacheable(true)
public class Account
  implements LMLookupTypeEntityByDivision, Serializable, Comparable<Account> {
Ahmed Nabil
  • 17,392
  • 11
  • 61
  • 88
Hrishikesh
  • 2,033
  • 1
  • 16
  • 26
  • 1
    The problem was because i had the module added as a dependency to my parent project since it is completely seperated. Hence it would be placed in my WEB-INF/lib folder. After debugging the JPA code where it loads the entities, i realised that the classpath where it starts scanning for @Entity annotations was from the WEB-INF/classes. which makes sense, since lib is read only. now, i have to think of adding the module in the classes folder or use the tag in the persistence.xml some way to enable the jar entity to be scanned and loaded – Hrishikesh Mar 01 '12 at 17:57

4 Answers4

7

if you are using spring boot use the entity scan annotation in your main springboot class

@EntityScan(
        basePackageClasses = {externalpackage.classname.class}
)
Mohammed Rafeeq
  • 2,586
  • 25
  • 26
4

To scan entities residing in jar, you have to include it in persistence.xml. <jar-file>packedEntity.jar</jar-file>.

If you want to load unit from the package, then you can try directly injecting it from jar. @PersistenceContext(unitName = "../packedEntity.jar#main")

Haven't tried but you can enable hibernate auto detection for entities <property name="hibernate.archive.autodetection" value="class, hbm"/>

Nayan Wadekar
  • 11,444
  • 4
  • 50
  • 73
2

Simply use

@EntityScan("com...pakage-which-contains-entities...")

Or if you have multiple entities packages, use

@EntityScan(basePackages = {"...pkg1...", "...pkg2..."} )
Ahmed Nabil
  • 17,392
  • 11
  • 61
  • 88
1

At work we don't use JPA but Hibernate, and our project is totally modularized. We handle about 30 countries which do not use the same modules, and we are able to load all these module's entities in a session factory by simply changing the maven dependencies (no orm file to modify)

The solution used is to use the Java SPI. The ServiceLoader will lookup for classes that implement a core interface EntityProvider. Each EntityProvider of every module will hardcode the entities it brings and return a list of entities when calling ServiceLoader.load(EntityProvider.class). Thus in the platform core we just need to create a spring based session factory in which we provide the entities list by a factory bean which will call the SPI.

I don't know if it will be easy with JPA but i'm pretty sure it's possible but you may need to create manually the EMF from a spring context, and also the PersistenceUnit i guess... What you may want is a persistence unit that is a "merge" of the persistence units of all your modules (at least for your entities) Take a look at SPI and also the javax.persistence.spi package.

Check also how to create an EMF with Spring: AbstractEntityManagerFactoryBean

Edit: you can check this: using the MergingPersistenceUnitManager to load entity

Community
  • 1
  • 1
Sebastien Lorber
  • 89,644
  • 67
  • 288
  • 419