3 Replies Latest reply on Jan 7, 2013 9:33 PM by Ron Sigal

    Problem with Decorators

    Ron Sigal Master

      Hi,

       

      I'm having trouble injecting a delegate.  I have a producer field:

       

         @Produces

         @ResourceBinding

         private UpperBoundTypedResource<HierarchyHolder<Primate>> ubhhr = new UpperBoundTypedResource<HierarchyHolder<Primate>>(Primate.class);

       

      where @ResourceBinding is a qualifier, and a decorator:

       

      @Decorator

      public abstract class UpperBoundDecorator<T extends HierarchyHolder<? extends Primate>> implements UpperBoundTypedResourceIntf<T>

      {

         ...

       

         private UpperBoundTypedResourceIntf<T> resource;

       

         @Inject

         public UpperBoundDecorator(@Delegate @ResourceBinding UpperBoundTypedResourceIntf<T> resource)

         {

            this.resource = resource;

            System.out.println("UpperBoundDecorator got delegate: " + resource);

         }


         @Override

         public Response execute()

         {

            log.info("entering UpperBoundDecorator.execute()");

            Response response = resource.execute();

            log.info("leaving UpperBoundDecorator.execute()");

            return response;

         }


      }

      and the UpperBoundDecorator constructor and UpperBoundDecorator.execute() aren't getting called.  UpperBoundTypedResource.execute() gets called directly. There are no complaints from Weld, just a silent failure.

       

      If I remove @ResourceBinding from the UpperBoundDecorator constructor, everything works.  If I remove @ResourceBinding from the producer field, Weld complains about an unsatisfied dependency:

      Caused by: org.jboss.weld.exceptions.DeploymentException: WELD-001408 Unsatisfied dependencies for type [UpperBoundTypedResourceIntf<T>] with qualifiers [@ResourceBinding] at injection point [[parameter 1] of [constructor] @Inject public org.jboss.resteasy.cdi.generic.UpperBoundDecorator(UpperBoundTypedResourceIntf<T>)]

       

      Running my test in the Eclipse debugger, I see that the instance of UpperBoundTypedResource produced by the producer field doesn't have the qualifier @ResourceBinding, which would explain why it isn't being injected into the UpperBoundDecorator delegate field.  But, in that case, I would expect a complaint about an unsatisfied dependency.

       

      Looking at the CDI spec, it doesn't really say much about qualifiers on producer fields and methods.  It says, "A producer field may also specify scope, bean name, stereotypes and/or qualifiers.", but it doesn't, as far as I can see, elaborate on the meaning of qualifiers on producer fields.  I'm guessing that the intent is to determine if the produced object is eligible for injection into an injection point, but it doesn't seem to be spelled out.

       

      As an experiment, I tried annotating UpperBoundTypedResource with @ResourceBinding, which messes up the injection points in UpperBoundTypedResource, but it does, of course, add the qualifier to the class.  When I do that, AbstractClassBean.initDecorators() does, in fact, determine that UpperBoundDecorator is a decorator for UpperBoundTypedResource, but ManagedBean.produce(), which seems to be where decorators are applied, doesn't get called for UpperBoundTypedResource.   Note, by the way, that in these circumstances, the instance of UpperBoundTypedResource that eventually gets called by Resteasy is an instance of UpperBoundTypedResource.class, rather than a Weld proxy.

       

      Any ideas?

       

      -Ron

        • 1. Re: Problem with Decorators
          Ron Sigal Master

          I've added some logging to UpperBoundTypedResource:

             public UpperBoundTypedResource()

             {

                System.out.println("UpperBoundTypedResource<?>(): " + this);

             }

            

             public UpperBoundTypedResource(Class<?> clazz)

             {

                this.clazz = clazz;

                System.out.println("UpperBoundTypedResource(" + clazz + "): " + this);

             }

          and I've done some more experiments in which I varied the placement of the @ResourceBinding qualifier:

           

          * no qualifer on producer, decorator injection point:

           

          Eclipse: complains that multiple beans are eligible for injection

           

          Execution: There was no call to UpperBoundTypedResource(Class<?> clazz) to populate the producer field, an instance of UpperBoundTypedResource, created by the no-arg constructor, was injected into UpperBoundDecorator, and UpperBoundDecorator.execute() ran :

           

          21:05:30,561 INFO  [stdout] (http--127.0.0.1-8080-4) UpperBoundTypedResource<?>(): org.jboss.resteasy.cdi.generic.UpperBoundTypedResource$Proxy$_$$_WeldSubclass@5c0b8e42

          21:05:30,562 INFO  [stdout] (http--127.0.0.1-8080-4) UpperBoundTypedResource<?>(): org.jboss.resteasy.cdi.generic.UpperBoundTypedResource$Proxy$_$$_Weld$Proxy$@7aa8be43

          21:05:30,562 INFO  [stdout] (http--127.0.0.1-8080-4) UpperBoundDecorator got delegate: org.jboss.resteasy.cdi.generic.UpperBoundTypedResource$Proxy$_$$_WeldSubclass@5c0b8e42

          21:05:30,564 INFO  [org.jboss.resteasy.cdi.generic.UpperBoundDecorator] (http--127.0.0.1-8080-4) entering UpperBoundDecorator.execute()

           

          * qualifier on producer, no qualifier on decorator injection point

           

          Eclipse: no complaint

           

          Execution: There was no call to UpperBoundTypedResource(Class<?> clazz) to populate the producer field, an instance of UpperBoundTypedResource, created by the no-arg constructor, was injected into UpperBoundDecorator, and UpperBoundDecorator.execute() ran:

           

          21:08:24,352 INFO  [stdout] (http--127.0.0.1-8080-4) UpperBoundTypedResource<?>(): org.jboss.resteasy.cdi.generic.UpperBoundTypedResource$Proxy$_$$_WeldSubclass@5578cce2

          21:08:24,352 INFO  [stdout] (http--127.0.0.1-8080-4) UpperBoundTypedResource<?>(): org.jboss.resteasy.cdi.generic.UpperBoundTypedResource$Proxy$_$$_Weld$Proxy$@6dd33544

          21:08:24,353 INFO  [stdout] (http--127.0.0.1-8080-4) UpperBoundDecorator got delegate: org.jboss.resteasy.cdi.generic.UpperBoundTypedResource$Proxy$_$$_WeldSubclass@5578cce2

          21:08:24,355 INFO  [org.jboss.resteasy.cdi.generic.UpperBoundDecorator] (http--127.0.0.1-8080-4) entering UpperBoundDecorator.execute()

           

          * no qualifier on producer, qualifier on decorator injection point

           

          Eclipse: complains that no bean is eligible for injection

           

          Execution: test failed to run, with exception:

           

          Caused by: org.jboss.weld.exceptions.DeploymentException: WELD-001408 Unsatisfied dependencies for type [UpperBoundTypedResource<T>] with qualifiers [@ResourceBinding] at injection point [[parameter 1] of [constructor] @Inject public org.jboss.resteasy.cdi.generic.UpperBoundDecorator(UpperBoundTypedResource<T>)]

           

          * qualifier on producer and decorator injection point:

           

          Eclipse: no complaint

           

          Execution: There was a call to UpperBoundTypedResource(Class<?> clazz) to populate producer field, but no injection was performed on the decorator and UpperBoundDecorator.execute() did not run

           

          21:13:47,017 INFO  [stdout] (http--127.0.0.1-8080-3) UpperBoundTypedResource<?>(): org.jboss.resteasy.cdi.generic.UpperBoundTypedResource@58b8dfdf

          21:13:47,018 INFO  [stdout] (http--127.0.0.1-8080-3) UpperBoundTypedResource(class org.jboss.resteasy.cdi.generic.Primate): org.jboss.resteasy.cdi.generic.UpperBoundTypedResource@5171d6fa

           

          ============================================================================================

          As another experiment, I exchanged the GenericsProducer producer field for a producer method, with or without the @ResourceBinding qualifier:

             @Produces

             private UpperBoundTypedResource<HierarchyHolder<Primate>> producer()

             {

                UpperBoundTypedResource<HierarchyHolder<Primate>> ubhhr = new UpperBoundTypedResource<HierarchyHolder<Primate>>(Primate.class);

                System.out.println("GenericsProducer.producer() created: " + ubhhr);

                return ubhhr;

             }

          With these results:

           

          * no qualifer on producer, decorator injection point:

           

          Eclipse: complains that multiple beans are eligible for injection

           

          Execution: The producer method didn't run, an instance of UpperBoundTypedResource, created by the no-arg constructor, was injected into UpperBoundDecorator, and UpperBoundDecorator.execute() ran:

           

          21:42:27,997 INFO  [stdout] (http--127.0.0.1-8080-4) UpperBoundTypedResource<?>(): org.jboss.resteasy.cdi.generic.UpperBoundTypedResource$Proxy$_$$_WeldSubclass@6f6a719e

          21:42:27,997 INFO  [stdout] (http--127.0.0.1-8080-4) UpperBoundTypedResource<?>(): org.jboss.resteasy.cdi.generic.UpperBoundTypedResource$Proxy$_$$_Weld$Proxy$@35497537

          21:42:27,998 INFO  [stdout] (http--127.0.0.1-8080-4) UpperBoundDecorator got delegate: org.jboss.resteasy.cdi.generic.UpperBoundTypedResource$Proxy$_$$_WeldSubclass@6f6a719e

          21:42:28,000 INFO  [org.jboss.resteasy.cdi.generic.UpperBoundDecorator] (http--127.0.0.1-8080-4) entering UpperBoundDecorator.execute()

           

          * qualifier on producer, no qualifier on decorator injection point

           

          Eclipse: no complaint

           

          Execution: The producer method didn't run, an instance of UpperBoundTypedResource, created by the no-arg constructor, was injected into UpperBoundDecorator, and UpperBoundDecorator.execute() ran:

           

          21:40:12,589 INFO  [stdout] (http--127.0.0.1-8080-4) UpperBoundTypedResource<?>(): org.jboss.resteasy.cdi.generic.UpperBoundTypedResource$Proxy$_$$_WeldSubclass@21d8baaf

          21:40:12,590 INFO  [stdout] (http--127.0.0.1-8080-4) UpperBoundTypedResource<?>(): org.jboss.resteasy.cdi.generic.UpperBoundTypedResource$Proxy$_$$_Weld$Proxy$@1bc84885

          21:40:12,590 INFO  [stdout] (http--127.0.0.1-8080-4) UpperBoundDecorator got delegate: org.jboss.resteasy.cdi.generic.UpperBoundTypedResource$Proxy$_$$_WeldSubclass@21d8baaf

          21:40:12,594 INFO  [org.jboss.resteasy.cdi.generic.UpperBoundDecorator] (http--127.0.0.1-8080-4) entering UpperBoundDecorator.execute()

           

          * no qualifier on producer, qualifier on decorator injection point

           

          Eclipse: complains that no bean is eligible for injection

           

          Execution: test failed to run, with exception:

           

          Caused by: org.jboss.weld.exceptions.DeploymentException: WELD-001408 Unsatisfied dependencies for type [UpperBoundTypedResource<T>] with qualifiers [@ResourceBinding] at injection point [[parameter 1] of [constructor] @Inject public org.jboss.resteasy.cdi.generic.UpperBoundDecorator(UpperBoundTypedResource<T>)]

           

          * qualifier on producer and decorator injection point:

           

          Eclipse: no complaint

           

          Execution: The producer method didn't run, no injection was performed on the decorator, and UpperBoundDecorator.execute() did not run

           

          21:33:13,861 INFO  [stdout] (http--127.0.0.1-8080-4) UpperBoundTypedResource<?>(): org.jboss.resteasy.cdi.generic.UpperBoundTypedResource@4f9078ed

           

          I haven't come up with a consistent explanation.  What do you think?

           

          Thanks,

          Ron

          • 2. Re: Problem with Decorators
            Jozef Hartinger Master

            Weld does not support associating decorators with a result of a producer field/method.

            • 3. Re: Problem with Decorators
              Ron Sigal Master

              Ah, thanks, Jozef.  I don't see anything in the spec that requires it, but it seems a little unexpected that producer fiellds/methods would work in one situation and not another.