9 Replies Latest reply on Jan 22, 2010 12:00 AM by pmuir

    The usage of Nonbinding on Qualifiers

    meetoblivion

      I'm trying to understand a bit better the usage of Nonbinding.  From what I can tell, we're supposed to use it when we don't want to take the value of an annotation into consideration when resolving a producer/bean instance.


      The reason I'm asking is that I have the following qualifier:




      @Qualifier
      @Target({TYPE, METHOD, PARAMETER, FIELD})
      @Retention(RUNTIME)
      public @interface LoadedProperties {
          @Nonbinding public boolean classpathAware() default false;
          @Nonbinding public boolean xml() default false;
          @Nonbinding public String filename();
      }
      



      Now, this works fine, as long as the usage of the qualifier is classpathAware=false (so default), however, when I set it to try I get ambiguous resolution errors.  The complication is that I've created producer methods for Map<String,String> and java.util.Properties for this object, and if it means I have to create a new producer for each value in the annotation, it'll get very redundant.  This is the stack trace, but it's the generic ambiguous resolution exception.






      Caused by: javax.enterprise.inject.AmbiguousResolutionException: Cannot resolve an ambiguous dependency between [org.jboss.weld.bean-//PropTestWeb/-ProducerMethod-com.tad.weld.comps.propertyconfigurator.producers.PropertyProducer.produceProperties(javax.enterprise.inject.spi.InjectionPoint), org.jboss.weld.bean-//PropTestWeb/-ProducerMethod-com.tad.weld.comps.propertyconfigurator.producers.UtilPropertiesProducer.produceUtilProperties(javax.enterprise.inject.spi.InjectionPoint)
              at org.jboss.weld.BeanManagerImpl.resolve(BeanManagerImpl.java:1491)
              at org.jboss.weld.BeanManagerImpl.getBean(BeanManagerImpl.java:1071)
              at org.jboss.weld.BeanManagerImpl.getInjectableReference(BeanManagerImpl.java:1040)
              at org.jboss.weld.injection.FieldInjectionPoint.inject(FieldInjectionPoint.java:92)
              at org.jboss.weld.util.Beans.injectBoundFields(Beans.java:727)
              at org.jboss.weld.util.Beans.injectFieldsAndInitializers(Beans.java:739)
              at org.jboss.weld.SimpleInjectionTarget$1.proceed(SimpleInjectionTarget.java:115)
              at org.glassfish.weld.services.InjectionServicesImpl.aroundInject(InjectionServicesImpl.java:130)
              at org.jboss.weld.injection.InjectionContextImpl.run(InjectionContextImpl.java:47)
              at org.jboss.weld.SimpleInjectionTarget.inject(SimpleInjectionTarget.java:109)
              at org.glassfish.weld.services.JCDIServiceImpl.createManagedObject(JCDIServiceImpl.java:180)
              at org.glassfish.weld.services.JCDIServiceImpl.createManagedObject(JCDIServiceImpl.java:154)
              at com.sun.enterprise.container.common.impl.managedbean.ManagedBeanManagerImpl.createManagedBean(ManagedBeanManagerImpl.java:456)
              at com.sun.enterprise.container.common.impl.managedbean.ManagedBeanManagerImpl.createManagedBean(ManagedBeanManagerImpl.java:423)
              at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.createManagedObject(InjectionManagerImpl.java:295)



        • 1. Re: The usage of Nonbinding on Qualifiers
          meetoblivion

          Hmmm looks like I was mistaken.  Weld is just not happy about having an injection point for java.util.Properties.  All issues went away when I switched the injection target from java.util.Properties to a new class that extends java.util.Properties.


          I kind of feel like the opposite should be happening - since I have injection points for both, I would think that java.util.Properties should be able to resolve fine, since there's only one, but the extension of java.util.Properties should fail, since there's two possibilities.

          • 2. Re: The usage of Nonbinding on Qualifiers
            gavin.king

            There's no reason you shouldn't be able to inject a Properties object. Show your code.

            • 3. Re: The usage of Nonbinding on Qualifiers
              meetoblivion

              I have a feeling that the issue's along the same lines as to why Instance<String> doesn't work without an alternative.  That's a bug right now, right?


              This is my qualifier now




              @Target({TYPE, METHOD, PARAMETER, FIELD})
              @Retention(RUNTIME)
              @Qualifier
              public @interface PropertyFile {
                  @Nonbinding public String value() default "";
              }





              These are what my injection points look like (both Servlet and EJB tested)


              @Inject @PropertyFile("classpath:/loadable.properties") TypedProperties loadables;
              @Inject @PropertyFile("c:/any.properties") java.util.Properties props;


              My producers:




                  @Produces @PropertyFile
                  public TypedProperties produceTypedProperties(InjectionPoint ip) {
                  ...
                  }
              
                  @Produces @PropertyFile
                  public Properties produceUtilProperties(InjectionPoint ip) {
                  ....
                  }





              And this is what I think is the catch, the definition of TypedProperties:




              public class TypedProperties extends java.util.Properties {





              Exception's above, happens when Injection tries to happen.  In the case of the Servlet, I only get it when I try to access the servlet.  In the case of the EJB, I get when I try to deploy.

              • 4. Re: The usage of Nonbinding on Qualifiers
                meetoblivion

                oh and just to be clear, the producers are in different classes.

                • 5. Re: The usage of Nonbinding on Qualifiers
                  gavin.king


                  I have a feeling that the issue's along the same lines as to why Instance<String> doesn't work without an alternative. That's a bug right now, right?

                  What do you mean? If you define your own bean of type Instance<String>? Of course you must declare it @Alternative. It's ambiguous!


                  @Inject @PropertyFile("c:/any.properties") java.util.Properties props;



                  This looks like an ambiguous injection point to me. Both the producer methods match this injection point. Perhaps you meant to write:


                  @Produces @PropertyFile @Typed(TypedProperties.class)
                  public TypedProperties produceTypedProperties(InjectionPoint ip) {
                      ...
                  }



                  Which would eliminate the ambiguity.



                  In the case of the Servlet, I only get it when I try to access the servlet. In the case of the EJB, I get when I try to deploy.

                  Now that's a bug. The error should be reported at deployment time in both cases.

                  • 6. Re: The usage of Nonbinding on Qualifiers
                    meetoblivion

                    Well, I had never seen @Typed before.  I did figure it was going to be ambiguous, however, it was ambiguous the wrong way (at least in my opinion).  But yeah, adding @Typed fixed it on the producer. 


                    Should i submit a bug about the servlet injection piece? I was also a bit confused why it deployed but then errored.  Sounds like it could be on the GF side though, that it's not discovering the servlet until it's invoked the first time (not sure if it matters with how I've implemented it using pure annotations)

                    • 7. Re: The usage of Nonbinding on Qualifiers
                      gavin.king

                      however, it was ambiguous the wrong way (at least in my opinion).

                      It's ambiguous because both producers produce an object that is assignable to the injection point.



                      Sounds like it could be on the GF side though

                      Yes, I imagine the bug is in GF.

                      • 8. Re: The usage of Nonbinding on Qualifiers
                        meetoblivion


                        It's ambiguous because both producers produce an object that is assignable to the injection point.



                        Right, because isAssignableFrom is returning true for both producer methods.  So just to understand better, @Typed is useful when we want to strongly bind the production of an implementation of some abstract/nonfinal class/interface to the injection points targeting that same class.  I added @Typed to both producers, but only the TypedProperties would be required, correct?


                        I'm a bit surprised that Weld isn't saying, ok I have a producer that produces an implementation of this class, as well as a producer that produces this exact class, let me pick the exact match.  To me, that's a bit more type safe, no?  That would obviously only apply to cases where there's multiple producers matching the injection point.


                        Of course, I may have a one off use case.

                        • 9. Re: The usage of Nonbinding on Qualifiers
                          pmuir

                          Gavin King wrote on Jan 10, 2010 16:46:


                          however, it was ambiguous the wrong way (at least in my opinion).

                          It's ambiguous because both producers produce an object that is assignable to the injection point.

                          Sounds like it could be on the GF side though

                          Yes, I imagine the bug is in GF.


                          John, did you report this as a bug in GlassFish? Can you paste the link here for trackback please :-)


                          http://oss.sonatype.org/content/repositories/jboss-snapshots/org/jboss/weld/weld-core/1.0.1-SNAPSHOT/weld-core-1.0.1-20100121.211650-46.jar


                          Ahem, this is what the JSR-299 spec says we have to do ;-) BTW there is a great discussion between Bob and Gavin about this on the JSR-330 EG list - go read it!