Uploaded image for project: 'Spring Framework'
  1. Spring Framework
  2. SPR-8594

PersistenceAnnotationBeanPostProcessor does not operate on the most specific persistence annotation declaration

    Details

    • Type: Bug
    • Status: Closed
    • Priority: 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?

        Attachments

          Activity

            People

            • Assignee:
              juergen.hoeller Juergen Hoeller
              Reporter:
              loicfrering 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:
                6 years, 45 weeks, 6 days ago