Spring Framework
  1. Spring Framework
  2. SPR-9741

Default PersistenceUnit is configured with wrong name, resulting in duplicates & causes RTE.

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Complete
    • Affects Version/s: 3.1.2
    • Fix Version/s: 3.1.3, 3.2 M2
    • Component/s: Data:ORM
    • Labels:
      None

      Description

      When specifying the name of a persistence unit to use for LocalContainerEntityManagerFactoryBean (ie., assuming there are multiple persistence units defined in persistence.xml), this name is now applied to the persistence unit from scanned pacakges.

      In 3.1.0, the name applied to the generated package was 'default'. However, now, the name applied is the one defined in the entityManager configuration.

      This results in an exception "Conflicting persistence unit definitions for name 'xxx'".

      This is a breaking change in behaviour from 3.1.0 to 3.1.2.

      The change is caused by new setter behaviour introduced in LocalContainerEntityManagerFactoryBean in 3.1.2, specifically this code:

      {{
      @Override
      public void setPersistenceUnitName(String persistenceUnitName)

      { super.setPersistenceUnitName(persistenceUnitName); this.internalPersistenceUnitManager.setDefaultPersistenceUnitName(persistenceUnitName); }

      }}

      This changes the internal defaultPersistenceUnitName from default. Later, when DefaultPersistenceUnit.buildDefaultPersistenceUnitInfo() is called, a new persistence unit is generated using this name:

      {{
      private SpringPersistenceUnitInfo buildDefaultPersistenceUnitInfo() {
      SpringPersistenceUnitInfo scannedUnit = new SpringPersistenceUnitInfo();
      scannedUnit.setPersistenceUnitName(this.defaultPersistenceUnitName);
      scannedUnit.setExcludeUnlistedClasses(true);
      }}

      This then results in an exception being thrown.

      As an example, here's the defined Persistence.xml, which contains both a prod config, and a test config:

      {{
      <?xml version="1.0" encoding="UTF-8"?>
      <persistence version="1.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_1_0.xsd">
      <persistence-unit name="production">
      <properties>
      <!-- JPA Configuration goes here -->
      </properties>
      </persistence-unit>
      <persistence-unit name="test" transaction-type="RESOURCE_LOCAL">
      <provider>org.hibernate.ejb.HibernatePersistence</provider>
      <properties>
      <!-- JPA Configuration goes here -->
      </properties>
      </persistence-unit>
      </persistence>
      }}

      Then, the appropriate config is selected in the EntityManager configration:

      {{
      <bean id="entityManagerFactory"
      class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
      <property name="dataSource" ref="dataSource" />
      <property name="packagesToScan">
      <list>
      <value>aa.bb.cc</value>
      </list>
      </property>
      <property name="persistenceUnitName" value="test" />
      <property name="jpaVendorAdapter">
      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
      <property name="showSql" value="true" />
      <property name="generateDdl" value="true" />
      <property name="databasePlatform" value="org.hibernate.dialect.H2Dialect" />
      </bean>
      </property>
      </bean>
      }}

      This causes the exception.

        Activity

        Hide
        Marty Pitt added a comment -

        Any update on this issue?

        Show
        Marty Pitt added a comment - Any update on this issue?
        Hide
        Juergen Hoeller added a comment -

        We expected the "packagesToScan" property to only be set when actually exposing the default persistence unit in the given LocalContainerEntityManagerFactoryBean...

        In your scenario, you seem to be setting a "packagesToScan" entry while nevertheless referring to a pre-defined persistence unit from your persistence.xml file. Aren't you effectively ignoring your scanned packages then, since you're building the default persistence unit that way but subsequently expose your "test" persistence unit instead?

        Juergen

        Show
        Juergen Hoeller added a comment - We expected the "packagesToScan" property to only be set when actually exposing the default persistence unit in the given LocalContainerEntityManagerFactoryBean... In your scenario, you seem to be setting a "packagesToScan" entry while nevertheless referring to a pre-defined persistence unit from your persistence.xml file. Aren't you effectively ignoring your scanned packages then, since you're building the default persistence unit that way but subsequently expose your "test" persistence unit instead? Juergen
        Hide
        Marty Pitt added a comment -

        Ah, I see.

        Glad to know that it's a configuration issue on my side.
        I'll fix the issue.

        However, it is a change in behaviour between versions. Perhaps some documentation could help lost souls like myself? ("Don't combine persistence.xml and 'packagesToScan' properties")

        One thought (and I suspect I'm showing my ignorance here)...

        We used the `packagesToScan` approach to work around having scanned @Entity classes in multiple modular jars.
        However, we use persistence units primarily to register extensions, such as `jadira.usertype.autoRegisterUserType` which enables JodaTime and JodaMoney mappings by default.

        Attempting to set these properties directly against the org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter caused an error:

        Caused by: org.springframework.beans.NotReadablePropertyException: Invalid property 'jadira' of bean class [org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter]: Bean property 'jadira' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?

        This is what lead us to using this combined approach. However, from reading your post, I suspect the config is invalid (which may explain other issues we encountered).

        Thanks for your help.

        Marty

        Show
        Marty Pitt added a comment - Ah, I see. Glad to know that it's a configuration issue on my side. I'll fix the issue. However, it is a change in behaviour between versions. Perhaps some documentation could help lost souls like myself? ("Don't combine persistence.xml and 'packagesToScan' properties") One thought (and I suspect I'm showing my ignorance here)... We used the `packagesToScan` approach to work around having scanned @Entity classes in multiple modular jars. However, we use persistence units primarily to register extensions, such as `jadira.usertype.autoRegisterUserType` which enables JodaTime and JodaMoney mappings by default. Attempting to set these properties directly against the org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter caused an error: Caused by: org.springframework.beans.NotReadablePropertyException: Invalid property 'jadira' of bean class [org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter] : Bean property 'jadira' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter? This is what lead us to using this combined approach. However, from reading your post, I suspect the config is invalid (which may explain other issues we encountered). Thanks for your help. Marty
        Hide
        Juergen Hoeller added a comment -

        As of Spring 3.1.3, we pick the same-named unit from persistence.xml in case of a conflict with the default persistence unit. This should allow your scenario to keep working as it did against Spring 3.1.0, even if you're effectively ignoring your "packagesToScan" setting that way.

        As for provider-specific properties: You can set them on the "jpaProperties" property on LocalContainerEntityManagerFactoryBean itself, through the generic JPA property mechanism. They will be passed through to Hibernate, without a need to touch Spring's HibernateJpaVendorAdapter.

        Hope that helps,

        Juergen

        Show
        Juergen Hoeller added a comment - As of Spring 3.1.3, we pick the same-named unit from persistence.xml in case of a conflict with the default persistence unit. This should allow your scenario to keep working as it did against Spring 3.1.0, even if you're effectively ignoring your "packagesToScan" setting that way. As for provider-specific properties: You can set them on the "jpaProperties" property on LocalContainerEntityManagerFactoryBean itself, through the generic JPA property mechanism. They will be passed through to Hibernate, without a need to touch Spring's HibernateJpaVendorAdapter. Hope that helps, Juergen

          People

          • Assignee:
            Juergen Hoeller
            Reporter:
            Marty Pitt
            Last updater:
            Chris Beams
          • Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:
              Days since last comment:
              1 year, 32 weeks ago