1 Reply Latest reply on Aug 22, 2012 9:49 AM by mkouba

    Asymmetry between producer and event observer with @Nonbinding qualifier

    starksm64

      So I have a little test that has a producer generate a string based on a @Nonbinding value of a qualifier to set unique values for fields. The qualifier cannot be used to differentiate between events because of the @Nonbinding value however. Is there a way to customize the event selection that provides the same dynamic selection of who should receive the event?

       

      Here is the test code:

       

      package test.com.si.weld.ex1;
      
      
      import javax.enterprise.util.Nonbinding;
      import javax.inject.Qualifier;
      import java.lang.annotation.Retention;
      import java.lang.annotation.Target;
      import static java.lang.annotation.ElementType.*;
      import static java.lang.annotation.RetentionPolicy.*;
      
      
      @Qualifier
      @Retention(RUNTIME)
      @Target({TYPE, METHOD, FIELD, PARAMETER})
      public @interface TestSymbol {
          @Nonbinding String value();
      }
      package test.com.si.weld.symbol;
      
      
      import test.com.si.weld.ex1.TestSymbol;
      
      
      import javax.enterprise.context.ApplicationScoped;
      import javax.enterprise.event.Observes;
      import javax.inject.Inject;
      
      
      /**
       * @author Scott stark
       * @version $Revision:$
       */
      @ApplicationScoped
      public class SymbolConsumer {
          @Inject @TestSymbol("key1")
          private String value1;
          @Inject @TestSymbol("key2")
          private String value2;
      
      
          public void key1Event(@Observes @TestSymbol("key1") String value1) {
              this.value1 = value1;
              System.out.printf("key1Event, %s\n", value1);
          }
          public void key2Event(@Observes @TestSymbol("key2") String value2) {
              this.value2 = value2;
              System.out.printf("key2Event, %s\n", value2);
          }
      
      
          @Override
          public String toString() {
              return "SymbolConsumer{" +
                      "value1='" + value1 + '\'' +
                      ", value2='" + value2 + '\'' +
                      '}';
          }
      }
      package test.com.si.weld.symbol;
      
      
      import test.com.si.weld.ex1.TestSymbol;
      
      
      import javax.enterprise.context.ApplicationScoped;
      import javax.enterprise.event.Event;
      import javax.enterprise.inject.Produces;
      import javax.enterprise.inject.spi.BeanManager;
      import javax.enterprise.inject.spi.InjectionPoint;
      import javax.inject.Inject;
      import java.lang.annotation.Annotation;
      import java.util.Properties;
      import java.util.Set;
      
      
      /**
       * @author Scott Stark
       * @version $Revision:$
       */
      @ApplicationScoped
      public class SymbolProducer {
          private Properties symbols = new Properties();
          @Inject @TestSymbol("key1")
          private Event<String> key1Event;
          @Inject @TestSymbol("key2")
          private Event<String> key2Event;
      
      
          public static TestSymbol getTestSymbol(Set<Annotation> qualifiers) {
              TestSymbol symbol = null;
              for(Annotation a : qualifiers) {
                  if(TestSymbol.class.isAssignableFrom(a.getClass())) {
                      symbol = TestSymbol.class.cast(a);
                      break;
                  }
              }
              return symbol;
          }
      
      
          public SymbolProducer() {
              symbols.setProperty("key1", "value1");
              symbols.setProperty("key2", "value2");
          }
      
      
          @TestSymbol("")
          @Produces
          public String getSymbol(InjectionPoint ip, BeanManager beanManager) {
              String key = getTestSymbol(ip.getQualifiers()).value();
              String symbol = symbols.getProperty(key);
              System.out.printf("getSymbol(%s) = %s\n", ip, symbol);
              return symbol;
          }
      
      
          public void sendKey1Value(String value) {
              key1Event.fire(value);
          }
          public void sendKey2Value(String value) {
              key2Event.fire(value);
          }
      }
      package test.com.si.weld.symbol;
      
      
      import org.jboss.arquillian.container.test.api.Deployment;
      import org.jboss.arquillian.junit.Arquillian;
      import org.jboss.shrinkwrap.api.ShrinkWrap;
      import org.jboss.shrinkwrap.api.asset.EmptyAsset;
      import org.jboss.shrinkwrap.api.spec.JavaArchive;
      import org.junit.Test;
      import org.junit.runner.RunWith;
      import test.com.si.weld.ex1.TestSymbol;
      
      
      import javax.inject.Inject;
      
      
      /**
       * @author Scott Stark
       * @version $Revision:$
       */
      @RunWith(Arquillian.class)
      public class TestNonBinding {
      
      
          @Deployment
          public static JavaArchive createDeployment() {
              JavaArchive archive = ShrinkWrap.create(JavaArchive.class)
                      .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
              archive.addPackages(true, "test/com/si/weld/symbol");
              archive.addClass(TestNonBinding.class);
              archive.addClass(TestSymbol.class);
              return archive;
          }
      
      
          // Arquillian enables @Inject directly in the test case class itself!
          @Inject
          SymbolConsumer consumer;
          @Inject
          SymbolProducer producer;
      
      
          @Test
          public void testSymbols() {
              System.out.printf("consumer = %s\n", consumer);
              producer.sendKey1Value("value1.1");
              System.out.printf("consumer = %s\n", consumer);
          }
      }
      

      Output when the TestNonBinding.testSymbols is run:

       

      34 [main] INFO org.jboss.weld.Version - WELD-000900 1.1.9 (Final)
      consumer = getSymbol([field] @TestSymbol @Inject private test.com.si.weld.symbol.SymbolConsumer.value1) = value1
      getSymbol([field] @TestSymbol @Inject private test.com.si.weld.symbol.SymbolConsumer.value2) = value2
      SymbolConsumer{value1='value1', value2='value2'}
      key1Event, value1.1
      key2Event, value1.1
      consumer = SymbolConsumer{value1='value1.1', value2='value1.1'}
      

       

      So both the key1Event and key2Event observer methods are called when an event with a TestSymbol("key1") qualifier is sent out because the value of the TestSymbol qualifier is not used due to the NonBinding meta-annotation. It would be good to uniformally be able to map such a qualifier on both producers and events.