6 Replies Latest reply on Feb 5, 2013 4:54 AM by rzd

    Alternative and @Produces question

    wujek
      Hi.
      The @Alternative annotation can be put on fields and methods, as well as types. Now, I have a bean FooProvider that has a @Produces method, and another bean TestFooProvider that has a method annotated @Produces @Alternative. According to the specs (5.1.1) an alternative is selected if:
      (...)the alternative is a producer method, field or resource, and the bean class that declares the method or field is listed(...)

      I think my @Produces method is an alternative as it is annotated as such. I also list the class that defines it in beans.xml. However, when used in Weld SE / Weld Core duo (1.0.1-Final) I get this:
      org.jboss.weld.exceptions.DeploymentException: WELD-001422 Enabled alternative bean class class com.test.TestFooProvider is not annotated @Alternative

      Ok, the exception is pretty explicit what is wrong. It does go away if I annotate the TestFooProvider with @ALternative. But, what is the alternative now? The whole bean TestFooProvider, or its @Produces method? I can now delete the @Alternative from the method, and it also works fine.

      This also means that I cannot have code like this:

      public class FooProvider {

          @Produces
          public Foo produceFoo() {
              return new StandardFoo("<<< creating foo >>>");
          }

          @Produces
          @Alternative
          public Foo produceFooAlternative() {
              return new TestFoo("<<< creating test >>>");
          }
      }
      because if I list the class in beans.xml, I will get the exception as above.

      What does the @Alternative on a @Produces method / field mean?


      I am probably not understanding things. Maybe the code that I just pasted is totally wrong?

      Thanks and regards,
      Wujek
        • 1. Re: Alternative and @Produces question
          gavin.king

          Hrm, actually this is sort of a hole in the spec. What you would really like to do is:


          <alternatives>
              <method>package.FooProvider.produceFooAlternative</method>
          </alternatives>



          But we don't yet support that. So indeed @Alternative at the method level is not very useful. We should probably go ahead and add <method> in the maintenance release.


          In the meantime, use an @Alternative stereotype for your usecase.

          • 2. Re: Alternative and @Produces question
            koichik0818

            If TestFooProvider is an alternative class, you must write




            @Alternative
            public class TestFooProvider {...}
            




            This may be different from your intention.
            You shoud use stereotype for producer methods or fields.




            @Stereotype
            @Alternative
            @Target( { TYPE, METHOD, FIELD })
            @Retention(RUNTIME)
            public @interface MyAlternative {
            }
            
            public class FooProvider {
                ...
            
                @Produces
                @MyAlternative
                public Foo produceFooAlternative() {
                    return new TestFoo("<<< creating test >>>");
                }
            }
            
            <beans>
              <alternatives>
                <stereotype>MyAlternative</stereotype>
              </alternatives>
            </bean>
            




            • 3. Re: Alternative and @Produces question
              wujek
              Hi. Thank you both for your answers.
              @Gavin: the <method> element sounds nice.

              I created Testalternative stereotype, as hinted by Gavin and Koichi, and it is annotated @Alternative. now I can have two methods, one 'standard', and the other one 'alternative', in one bean class, and it works fine.

              Can you please explain why alternative stereotype works, and plain @Alternative does not? What is the difference in semantics? This particular stereotype doesn't add any value above the @Alternative (except that it makes my case work fine ;d), so it looks like a kind of a workaround, which could be easily avoided - since CDI / Weld is able to process @Alternative on a stereotype, I guess it could do as well for plain @Alternative? I say I guess as I don't know the code and maybe (probably) there is a reason that one works and the other does not. The only thing that comes to my mind is the sentence from the specs that I quoted before, which says that an alternative producer must have its class annotated @Alternative. Would this be dropped in the maintanance release if support for <method> is added?

              Anyways, thanks for the help with this question.

              Best regards,
              Wujek
              • 4. Re: Alternative and @Produces question
                koichik0818

                Because FooProvider 'Class' is not specified an @Alternative, you can not list the class into <class> element in beans.xml. See P.39 in CDI spec:





                Each child <class> element must specify the name of an alternative bean class.



                Also, because produceFooAlternative() 'Method' is not a class, you can not list the method into <class> element in beans.xml.

                • 5. Re: Alternative and @Produces question
                  wujek
                  Hi.

                  Thank you for your time and answers.

                  I understand the difference between class / method, and I understand the cause of the error.

                  The question was more conceptual, like: why does a provider method / field not support @Alternative and requires it to be placed on the class (making the whole class an alternative, which is quite a different thing) while the definition of this annotation says that it may be placed on a method / field, and at the same time, a stereotype which has @Alternative works just fine when put on a producer, as described by both of you, and proved to fix this for me?
                  Why is the restriction in 5.1.1 made that for a producer field / method to be an enabled alternative using plain @Alternative, the @Alternative must be placed on the class that defines the producer, whereas an alternative stereotype on a method / field works just fine? As I said in my previous post, a stereotype that is created only with @Alternative to be used on producers (just the thing you suggested and works perfect) looks like a redefinition of the exactly same concept as plain @Alternative is for, except for this use case of course.
                  It seems to me that stereotypes actually have much finer granularity than @Alternative (per method / field vs per class), and the new <method> element in maintenance would fix this little inconsistency.

                  The reason why I inquire this is that we decided to lean on CDI heavily in our new project, and I am a strong believer that I need to understand the technology well to use it correctly and produce anything of good quality. This particular use case (@Produces @Alternative) is something I stumbled upon, and I wanted to make sure that I do understand whay this works and that doesn't.

                  Best regards,
                  Wujek
                  • 6. Re: Alternative and @Produces question
                    rzd

                    This makes annotating producer methods and fields as alternatives pretty useless, doesn't it? I haven't found an issue in JIRA, should I create one?