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

Firing events with dynamic parameterized types

XMLWordPrintable

    • Icon: Feature Request Feature Request
    • Resolution: Obsolete
    • Icon: Major Major
    • 2.1 (Discussion)
    • 1.2.Final
    • Events
    • None

      For the time being, either by using Event.select(...), respectively BeanManager.fireEvent(...), it is not possible to fire an event whose runtime type is a dynamic parameterized type, as specified in The Event interface:

      If the container is unable to resolve the parameterized type of the event object, it uses the specified type to infer the parameterized type of the event types.

      If the runtime type of the event object contains an unresolvable type variable, an IllegalArgumentException is thrown.

      Respectively in Firing an event:

      If the runtime type of the event object contains a type variable, an IllegalArgumentException is thrown.

      While, it is possible to pass a TypeLiteral to the Event.select(...) method, e.g.:

      @Inject
      Event<Object> event;
      
      event.select(new TypeLiteral<String>() {});
      

      It is not possible to pass a type variable known at runtime as the TypeLiteral class relies on the declared type variable and does not permit to override that behavior as the TypeLiteral.getType() method is declared final.

      Yet, there are use cases where that need is valid, for example:

      <T> CdiEventEndpoint<T> cdiEventEndpoint(InjectionPoint ip, CamelContext context, @Any Event<Object> event) throws Exception {
          // Represents the runtime type for T
          Type type = ((ParameterizedType) ip.getType()).getActualTypeArguments()[0];
          String uri = endpointUri(type, ip.getQualifiers());
          if (context.hasEndpoint(uri) == null) {
              // Work around to pass the dynamic type
              TypeLiteral<T> literal = new TypeLiteral<T>() {};
              for (Field field : TypeLiteral.class.getDeclaredFields()) {
                   if (field.getType().equals(Type.class)) {
                      field.setAccessible(true);
                      field.set(literal, type);
                      break;
                  }
              }
              // Here we used the dynamic type
              Event<T> typedEvent = event.select(literal, ip.getQualifiers().toArray(new Annotation[ip.getQualifiers().size()]));
              context.addEndpoint(uri, new CdiEventEndpoint<>(typedEvent, uri, context));
          }
          return CamelContextHelper.getMandatoryEndpoint(context, uri, CdiEventEndpoint.class);
      }
      

      In the example above, the TypeLiteral class could have a constructor taking the dynamic type as argument.

      Another alternative would be to enrich the BeanManager SPI with the following method:

      public void fireEvent(Object event, Type type, Annotation... qualifiers);
      

      That use case is taken from the CDI event Camel endpoint in the Camel CDI extension.

              Unassigned Unassigned
              astefanu@redhat.com Antonin Stefanutti
              Votes:
              1 Vote for this issue
              Watchers:
              7 Start watching this issue

                Created:
                Updated:
                Resolved: