Results 1 to 10 of 19

Thread: Transforming JPA related beans to JavaConfig

Hybrid View

  1. #1
    Join Date
    Aug 2008
    Location
    Billings, Montana
    Posts
    47

    Default Transforming JPA related beans to JavaConfig

    I am working on creating a dynamic spring config for my project using Java Config. How about translating the following XML using JavaConfig?

    LocalContainerEntityManagerFactoryBean is not related to javax.persistence.EntityManagerFactory. So, I am having trouble configuring entityManagerFactory using Java Config.

    <bean id="personDao" class="impl.PersonDaoImpl">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerE ntityManagerFactoryBean">
    <property name="persistenceUnitName" value="personPU" />
    <property name="dataSource" ref="dataSource"/>
    <property name="jpaVendorAdapter">
    <bean class="org.springframework.orm.jpa.vendor.Hibernat eJpaVendorAdapter">
    <property name="showSql" value="${jdbc.showSql}"/>
    <property name="generateDdl" value="${jdbc.generateDdl}"/>
    <property name="databasePlatform" value="${jdbc.databasePlatform}"/>
    </bean>
    </property>
    </bean>
    <bean id="jpaTransactionManager" class="org.springframework.orm.jpa.JpaTransactionM anager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
    <property name="dataSource" ref="dataSource"/>
    </bean>

    I appreciate any insight into this issue.

    Thank you,
    Arul

  2. #2
    Join Date
    Apr 2007
    Posts
    307

    Default

    Hi Arul,

    The following should get you started. First, make sure that you upgrade to the latest nightly snapshot release. Instructions for this can be found at http://springframework.org/javaconfig.

    Code:
    @Configuration
    @AnnotationDrivenTx
    @PropertiesValueSource(locations="classpath:path/to/db.properties")
    @Import(DataSourceConfig.class)
    public abstract class JpaConfiguration {
    
        abstract @ExternalValue("jdbc.showSql") String showSql();
        abstract @ExternalValue("jdbc.generateDdl") String generateSql();
        abstract @ExternalValue("jdbc.databasePlatform") String databasePlatform();
    
        abstract @ExternalBean DataSource dataSource();
    
        public @Bean PersonDao personDao() {
            PersonDaoImpl personDao = new PersonDaoImpl();
            personDao.setEntityManagerFactory(entityManagerFactory());
        }
    
        public @Bean EntityManagerFactory entityManagerFactory() {
            LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
            em.setPersistenceUnitName("personPU");
            em.setDataSource(dataSource());
            em.setJpaVendorAdapter(jpaVendorAdapter());
        }
    
        public @Bean HibernateJpaVendorAdapter jpaVendorAdapter() {
            HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
            adapter.setShowSql(showSql());
            adapter.setGenerateDdl(generateDdl());
            adapter.setDatabasePlatform(databasePlatform());
        }
    
        public @Bean PlatformTransactionManager transactionManager() {
            JpaTransactionManager txManager = new JpaTransactionManager();
            txManager.setEntityManagerFactory(entityManagerFactory());
            txManager.setDataSource(dataSource());
        }
    
    }
    Notes:

    @AnnotationDrivenTx behaves exactly like <tx:annotation-driven/>. It assumes that you have a bean named 'transactionManager' (and in the above configuration, you do). See the JavaDoc for full details.

    @Import(DataSourceConfig.class) assumes you have another @Configuration class defined named DataSourceConfig that defines a @Bean of type DataSource.

    You'll notice that the combination of @PropertiesValueSource and @ExternalBean replace what you're used to with <contextroperty-placeholder/> / PropertyPlaceholderConfigurer

    Again, this is just a start. You may encounter additional issues, please ask if you do, and when possible include a complete set of sample code. As several of these features are unreleased, there is no official documentation, but in most cases you'll find sufficient Javadoc in the code.
    Chris Beams
    Spring Framework committer, VMware
    http://github.com/cbeams

  3. #3
    Join Date
    Aug 2008
    Location
    Billings, Montana
    Posts
    47

    Default

    Thanks Chris for your detailed explanation. I am really excited about this project due to its expressiveness.

    In fact, I had almost similar configuration. Here is the slightly updated code. I have added return statements to all the methods. I am not able to return from entityManagerFactory as LocalContainerEntityManagerFactoryBean does not belong to this type.
    Code:
    @Configuration
    @AnnotationDrivenTx
    @PropertiesValueSource(locations = "classpath:path/to/db.properties")
    @Import(DataSourceConfig.class)
    public abstract class JpaConfiguration {
    
      abstract @ExternalValue("jdbc.showSql") boolean showSql();
      abstract @ExternalValue("jdbc.generateDdl") boolean generateDdl();
      abstract @ExternalValue("jdbc.databasePlatform") String databasePlatform();
    
      abstract @ExternalBean  DataSource dataSource();
    
      public @Bean PersonDao personDao() {
        PersonDaoImpl personDao = new PersonDaoImpl();
        personDao.setEntityManagerFactory(entityManagerFactory());
        return personDao;
      }
    
      public @Bean EntityManagerFactory entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setPersistenceUnitName("personPU");
        em.setDataSource(dataSource());
        em.setJpaVendorAdapter(jpaVendorAdapter());
        return em;//incompatible types: required javax.persistence.EntityManagerFactory
      }
    
      public @Bean HibernateJpaVendorAdapter jpaVendorAdapter() {
        HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
        adapter.setShowSql(showSql());
        adapter.setGenerateDdl(generateDdl());
        adapter.setDatabasePlatform(databasePlatform());
        return adapter;
      }
    
      public @Bean PlatformTransactionManager transactionManager() {
        JpaTransactionManager txManager = new JpaTransactionManager();
        txManager.setEntityManagerFactory(entityManagerFactory());
        txManager.setDataSource(dataSource());
        return txManager;
      }
    
    }
    I was trying to pull the snapshot using the following in my POM.

    Code:
        <repositories>
            <!-- Necessary if using snapshot builds of SpringSource products (as above) -->
            <repository>
                <id>SpringSource Enterprise Bundle Repository - External Bundle Snapshots</id>
                <url>repository.springsource.com/maven/bundles/snapshot</url>
            </repository>
    
            <!-- Required, as Spring JavaConfig has dependencies on released versions of SpringSource products -->
            <repository>
                <id>SpringSource Enterprise Bundle Repository - SpringSource Bundle Releases</id>
                <url>repository.springsource.com/maven/bundles/release</url>
            </repository>
    
            <!-- Required, as Spring JavaConfig has dependencies on External OSGi bundles -->
            <repository>
                <id>SpringSource Enterprise Bundle Repository - External Bundle Releases</id>
                <url>repository.springsource.com/maven/bundles/external</url>
            </repository>      
            <repository>
                <id>spring-milestone</id>
                <name>Spring Milestone Repository</name>
                <url>s3browse.com/explore/repository.springsource.com/maven/bundles/snapshot</url>
            </repository>
        </repositories>
    
            <dependency>
                <groupId>org.springframework.javaconfig</groupId>
                <artifactId>org.springframework.config.java</artifactId>
                <version>1.0.0.BUILD-SNAPSHOT</version>
            </dependency>
    But, I could not fetch the snapshot from the maven repo defined above.

    Am I missing something here?

    [Note: I had intentionally removed the http prefix from the repository URLs because the forum posting does not allow me to include URL until I have made 15 posts.]

  4. #4
    Join Date
    Apr 2007
    Posts
    307

    Default

    Regarding EntityManagerFactory, I was a bit hasty in the code above. Because LocalContainerEntityManagerFactory is a FactoryBean, it must be treated specially. Here is the revised code:

    Code:
    public abstract class JpaConfiguration extends ConfigurationSupport {
      public @Bean EntityManagerFactory entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setPersistenceUnitName("personPU");
        em.setDataSource(dataSource());
        em.setJpaVendorAdapter(jpaVendorAdapter());
        return (EntityManagerFactory) this.getObject(em);
      }
    }
    Note that the class now extends ConfigurationSupport, which provides a protected 'getObject()' method. This method internally calls the FactoryBean's getObject() method, which in your case returns an EntityManagerFactory. It also runs that returned object through the container lifecycle, in order to perform any bean post-processing, etc that may be required.


    Regarding the pom and dependencies, your configuration is close, but using the s3browse url will not work. Take a look at JavaConfig's petclinic sample pom:

    https://fisheye.springframework.org/...xml?r=796#l196
    Chris Beams
    Spring Framework committer, VMware
    http://github.com/cbeams

  5. #5
    Join Date
    Aug 2008
    Location
    Billings, Montana
    Posts
    47

    Default

    Thanks Chris. I fixed the config and maven. It worked like a charm.

    My PersonDaoImpl extends JpaDaoSupport which provides "Spring JPA" benefits.

    In my PersonDaoImpl, I need to add the following to support it from the SJC:

    Code:
      private EntityManagerFactory entityManagerFactory;
    
      @PersistenceContext
      public void setEntityManager(EntityManagerFactory entityManagerFactory) {
          this.entityManagerFactory = entityManagerFactory;
      }
    Do you think this would hurt my DAO having multiple references to EMF?
    I was just curious to know if the below would return a new EMF or the one injected above.
    Code:
    getJpaTemplate().getEntityManagerFactory()
    Do you know if there is any timeframe I could see these features (AnnotationDrivenTx, PropertiesValueSource) part of a milestone release?

    Thanks once again for your timely support.

  6. #6
    Join Date
    Apr 2007
    Posts
    307

    Default

    Arul,

    Either of the approaches you mention should work fine. If one does not, and it appears related to SJC, please post here with the error, etc.

    With regard to the timeline for the features, you can always follow the roadmap in JIRA. These features are currently scheduled for 1.0.0.m4, which is due out shortly.
    Chris Beams
    Spring Framework committer, VMware
    http://github.com/cbeams

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •