Uploaded image for project: 'CDI Specification Issues'
  1. CDI Specification Issues
  2. CDI-268

Limitations in the SPI for creating beans

    XMLWordPrintable

Details

    • Bug
    • Resolution: Done
    • Critical
    • 1.1.PFD
    • 1.1.EDR
    • Portable Extensions
    • None
    • Release Notes

    Description

      The CDI SPI provides an SPI that helps extension developers to build Bean implementations.

      An example follows:

      AnnotatedType<Foo> annotatedType = manager.createAnnotatedType(Foo.class);
      BeanAttributes<Foo> attributes = manager.createBeanAttributes(annotatedType);
      InjectionTarget<Foo> injectionTarget = manager.createInjectionTarget(annotatedType);
      Bean<Foo> bean = manager.createBean(attributes, Foo.class, injectionTarget);
      

      This sequence allows an extension to easily build Bean<Foo>. Obviously, the extension could modify the artifacts along the way to modify the behavior.

      However, this SPI has limitations. There is a circular dependency between the initialization of Bean and InjectionTarget which is not expressed by the SPI.

      A Bean implemetation (be it container-provided one or not) almost always uses an InjectionTarget to delegate bean instance creation and destruction to. So far so good as the InjectionTarget is one of the arguments of BeanManager.createBean()

      On the other hand, the InjectionTarget also needs a reference to a Bean instance at initialization should it serve as an InjectionTarget for a Bean. This is not obvious but there are two reasons why this is needed:

      1.) InjectionPoint.getBean() always returns null

      InjectionTarget.getInjectionPoints() returns a set of InjectionPoint instances. The InjectionPoint has the method getBean(). This method would always return null (e.g. for InjectionTarget<Foo> above) because there is no way to tell the container that this InjectionTarget is an InjectionTarget of a Bean.

      This causes problems since the getBean() method is used for validation of injection points - certain types of injection points are allowed to be placed on beans only (e.g. Bean metadata, injection point metadata).

      There exists a workaround for this where the ProcessInjectionPoint is used to wrap every such InjectionPoint with a wrapper that returns the Bean instance:

          void wrapInjectionPoints(@Observes ProcessInjectionPoint<Foo, ?> event) {
              final InjectionPoint delegate = event.getInjectionPoint();
              if (delegate.getBean() == null) {
                  event.setInjectionPoint(new ForwardingInjectionPoint() {
      
                      @Override
                      public Bean<?> getBean() {
                          return bean;
                      }
      
                      @Override
                      protected InjectionPoint delegate() {
                          return delegate;
                      }
                  });
              }
          }
      

      2.) Decorators cannot be applied

      Bean<Foo> in the example above would not be decorated even if there were enabled decorators matching the bean. This is because the InjectionTarget, which takes care of creating instances and whose produce() method is responsible for building decorators for the instance does not know whether what it creates actually is a bean or not. Even if it knew, it would need to know the types and qualifiers of the bean, which it does not.

      To sum it up: Although BeanAttributes, Bean and InjectionTarget seem to be independent layers out of which a Bean can be composed, there are actually circular relations which the SPI currently fails to notice.

      Attachments

        Activity

          People

            pmuiratbleepbleep Pete Muir (Inactive)
            rhn-engineering-jharting Jozef Hartinger
            Votes:
            0 Vote for this issue
            Watchers:
            6 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: