Chris Lacy's Software Engineering Blog

Sunday Sep 07, 2008

Hibernate using JPA Annotations in One Eclipse Project

I finally put together a small Java web app that has all of my favorite tools: Spring, Hibernate, JPA annotations, and Maven (m2eclipse); all in one Eclipse project. If you've ever tried to get these to work together you know it can be a hassle. Recent improvements in m2eclipse have made things a lot easier. For this blog entry I want to share with you one of the last pieces of my puzzle.

My understanding is that the Spring/Hibernate combination works in two modes: Hibernate and JPA. In both modes you can scan for annotated entities, but in the JPA mode the scan depends on EJB3 package compilation artifacts. I could have tried creating a separate project for the EJBs, but imo that's too much work, especially when you get Maven involved. Instead, I dove into the Spring and Hibernate internals and hacked together my own solution. Then, of course, I read this blog post (warning, language), and followed up by exploring loom. They use a bean post processor, which is much cleaner than my hack. Here's the low down:

<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
    p:dataSource-ref="dataSource">
        
    <property name="persistenceUnitPostProcessors">
          <bean class="net.chrislacy.webapp.HibernateJpaPostProcessor" p:packages="net.chrislacy.webapp"/>
    </property>
        
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
            p:database="HSQL"
            p:showSql="false"
            p:generateDdl="true">
        </bean>
    </property>
        
    <property name="persistenceXmlLocation" value="/META-INF/persistence.xml" />
</bean>
public class HibernateJpaPostProcessor implements PersistenceUnitPostProcessor, InitializingBean {

	
	private ClassPathScanningCandidateComponentProvider provider;
	private String[] packages = new String[] {};

	
	/**
	 * Search for persistent classes under the configured folders and register
	 * them in the persistence unit.
	 */
	public void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo unit) {
		
		for (String pakage : packages) {
			
			for (BeanDefinition bean : provider.findCandidateComponents(pakage)) {
				
				unit.addManagedClassName(bean.getBeanClassName());
			}
		}
	}

	public void afterPropertiesSet() {
		
		if (provider == null) {
			
			provider = new ClassPathScanningCandidateComponentProvider(false);
			provider.addIncludeFilter(new AnnotationTypeFilter(Entity.class, false));
		}
	}

	public void setProvider(ClassPathScanningCandidateComponentProvider provider) {
		
		this.provider = provider;
	}

	public void setPackages(String[] packages) {
		
		this.packages = packages;
	}

}

Comments:

Post a Comment:
Comments are closed for this entry.

Calendar

Feeds

Search

Links

Navigation

Referrers