[cdi-dev] [JBoss JIRA] (CDI-516) Firing events with dynamic parameterized types
Antonin Stefanutti (JIRA)
issues at jboss.org
Sun Mar 8 13:49:18 EDT 2015
[ https://issues.jboss.org/browse/CDI-516?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Antonin Stefanutti updated CDI-516:
-----------------------------------
Description:
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|http://docs.jboss.org/cdi/spec/1.2/cdi-spec.html#event]:
{quote}
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.
{quote}
Respectively in [Firing an event|http://docs.jboss.org/cdi/spec/1.2/cdi-spec.html#bm_fire_event]:
{quote}
If the runtime type of the event object contains a type variable, an {{IllegalArgumentException}} is thrown.
{quote}
While, it is possible to pass a {{TypeLiteral}} to the {{Event.select(...)}} method, e.g.:
{code}
@Inject
Event<Object> event;
event.select(new TypeLiteral<String>() {});
{code}
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:
{code}
<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);
}
{code}
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:
{code}
public void fireEvent(Object event, Type type, Annotation... qualifiers);
{code}
That use case is taken from the [CDI event Camel endpoint|https://github.com/astefanutti/camel-cdi/blob/84426570bcd7815eb98f87b07739aa9ddfc44191/impl/src/main/java/org/apache/camel/cdi/CdiCamelFactory.java#L91] in the [Camel CDI extension|https://github.com/astefanutti/camel-cdi].
was:
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|http://docs.jboss.org/cdi/spec/1.2/cdi-spec.html#event]:
{quote}
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.
{quote}
Respectively in [Firing an event|http://docs.jboss.org/cdi/spec/1.2/cdi-spec.html#bm_fire_event]:
{quote}
If the runtime type of the event object contains a type variable, an {{IllegalArgumentException}} is thrown.
{quote}
While, it is possible to pass a {{TypeLiteral}} to the {{Event.select(...)}} method, e.g.:
{code}
@Inject
Event<Object> event;
event.select(new TypeLiteral<String>() {});
{code}
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:
{code}
<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);
}
{code}
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:
{code}
public void fireEvent(Object event, Type type, Annotation... qualifiers);
{code}
> Firing events with dynamic parameterized types
> ----------------------------------------------
>
> Key: CDI-516
> URL: https://issues.jboss.org/browse/CDI-516
> Project: CDI Specification Issues
> Issue Type: Feature Request
> Components: Events
> Reporter: Antonin Stefanutti
>
> 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|http://docs.jboss.org/cdi/spec/1.2/cdi-spec.html#event]:
> {quote}
> 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.
> {quote}
> Respectively in [Firing an event|http://docs.jboss.org/cdi/spec/1.2/cdi-spec.html#bm_fire_event]:
> {quote}
> If the runtime type of the event object contains a type variable, an {{IllegalArgumentException}} is thrown.
> {quote}
> While, it is possible to pass a {{TypeLiteral}} to the {{Event.select(...)}} method, e.g.:
> {code}
> @Inject
> Event<Object> event;
> event.select(new TypeLiteral<String>() {});
> {code}
> 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:
> {code}
> <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);
> }
> {code}
> 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:
> {code}
> public void fireEvent(Object event, Type type, Annotation... qualifiers);
> {code}
> That use case is taken from the [CDI event Camel endpoint|https://github.com/astefanutti/camel-cdi/blob/84426570bcd7815eb98f87b07739aa9ddfc44191/impl/src/main/java/org/apache/camel/cdi/CdiCamelFactory.java#L91] in the [Camel CDI extension|https://github.com/astefanutti/camel-cdi].
--
This message was sent by Atlassian JIRA
(v6.3.11#6341)
More information about the cdi-dev
mailing list