Spring Framework
  1. Spring Framework
  2. SPR-8594

PersistenceAnnotationBeanPostProcessor does not operate on the most specific persistence annotation declaration

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Complete
    • Affects Version/s: 3.0.5
    • Fix Version/s: 3.0.6, 3.1 RC1
    • Component/s: Data
    • Labels:
      None
    • Last commented by a User:
      true

      Description

      Hello guys, I've got an issue with the PersistenceAnnotationBeanPostProcessor
      when using multiple persistence units and inheritance. The problem is in
      findPersistenceMetadata method which looks for persistence annotations in
      registered beans.

      The current implementation loops through declared fields and declared
      methods of the actual class of the bean to detect eventual persistence
      annotation and register a PersistenceElement for each.

      And this process is repeated in a do ... while loop for each class in the
      inheritance hierarchy of the bean's class.

      Here is a simplified verion of the current algorithm:

      Class<?> targetClass = clazz;do {
      LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<InjectionMetadata.InjectedElement>();
      for (Field field : targetClass.getDeclaredFields())

      { // .... currElements.add(new PersistenceElement(field, null)); }

      for (Method method : targetClass.getDeclaredMethods())

      { // .... PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method); currElements.add(new PersistenceElement(method, pd)); }

      elements.addAll(0, currElements);
      targetClass = targetClass.getSuperclass();
      }while (targetClass != null && targetClass != Object.class);
      metadata = new InjectionMetadata(clazz, elements);

      The problem is that a PersistentElement is registered for each definition of a
      field or method in the class hierarchy : the most specific definition is not
      the only one registered.

      As a consequence having this:

      public class GenericRepository {

      private EntityManager entityManager;

      @PersistenceContext
      public void setEntityManager(EntityManager em)

      { this.entityManager = em; }

      // ....}

      public class UserRepository extends GenericRepository {

      @Override
      @PersistenceContext(unitName="my-unit")
      public void setEntityManager(EntityManager em)

      { parent.setEntityManager(em); }

      // ....}

      Would leed to 2 injected elements in metadata:

      • One for @PersistenceContext without unitName
      • One for @PersistenceContext with unitName "my-unit"

      Then Spring injects the EntityManager based on the first element definition and
      skip the second one which is the most specific!

      There might be a good reason for iterating through each declared field/method
      of each super class of the bean's class but I don't get why you do not simply
      use the getMethods() and getFields() reflection methods which return the most
      specific definition of the field/method with annotations and would avoid having
      multiple injectedElements for persistence matadata?

        Activity

        Hide
        Juergen Hoeller added a comment -

        This turned out to be a bug in the "most specific method" check that we had there anyway: Due to bad ordering, the most specific method only got checked for the @PersistenceUnit annotation but not for @PersistenceContext...

        Fixed for 3.1 RC1 as well as 3.0.6 now. Thanks for raising it!

        Juergen

        Show
        Juergen Hoeller added a comment - This turned out to be a bug in the "most specific method" check that we had there anyway: Due to bad ordering, the most specific method only got checked for the @PersistenceUnit annotation but not for @PersistenceContext... Fixed for 3.1 RC1 as well as 3.0.6 now. Thanks for raising it! Juergen
        Hide
        Loïc Frering added a comment -

        Thanks a lot Juergen,

        Nice catch on the parenthesis for pc Unable to render embedded object: File (= null && ClassUtils.getMostSpecificMethod) not found. I'm sure that this will resolve a lot of problems for those using multiple persistence units in their projects.

        Show
        Loïc Frering added a comment - Thanks a lot Juergen, Nice catch on the parenthesis for pc Unable to render embedded object: File (= null && ClassUtils.getMostSpecificMethod) not found. I'm sure that this will resolve a lot of problems for those using multiple persistence units in their projects.

          People

          • Assignee:
            Juergen Hoeller
            Reporter:
            Loïc Frering
            Last updater:
            Trevor Marshall
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:
              Days since last comment:
              2 years, 35 weeks, 5 days ago