Weld 3.0.0.Alpha1 released!
Today we are releasing Weld 3.0.0.Alpha1. This release serves as an early proof of concept of some of the ideas that are being discussed by the CDI Expert Group for the upcoming CDI 2.0 specification. Furthermore, this is a great opportunity for the community to test-drive some of the proposed improvements and provide us with feedback. Be warned though that this released does not come with any guarantee of stability and that binary and functional compatibility is likely to be broken in the following releases.
Ordering of observer methods
The first of the new features are ordered observer methods. This requirement came up a long ago and several approaches were proposed in the meantime, as documented by
CDI-4.The Alpha1 release employs the general-purpose @Priority
annotation to determine the order in which observer methods are to be notified.
There are many open questions about this feature. Here are some of the rules we set for the purpose of this experimental implementation. These are by no means set in stone but instead we encourage you to give us feedback on these:
-
Each observer method has a certain priority value. An observer method that does not define a priority explicitly is given the default priority which is 2500 (in the middle of the
Interceptor.Priority.APPLICATION
range) -
The priority of an observer method determines the order. An observer method with lower value is called before an observer method with higher value
-
If multiple observer methods define the same priority value, the order is undefined
-
Observer methods priorities should match existing priority range convention
-
The ordering applies to both transactional and non-transactional observer methods
-
The priority annotation is applied on the event parameter (not the observer method)
Here’s an example:
public void sendWelcome(@Observes @Priority(APPLICATION + 800) @Registered User user) {
// ...
}
Note that javax.annotation.Priority
can currently only be applied to types. Therefore, we temporarily created a substitute called org.jboss.weld.experimental.Priority
which is identical
to the original except that it can also be applied on parameters (of observer methods). The plan is to propagate this change back to javax.annotation.Priority
. In the meantime, Weld’s twin
gets the job done.
In addition to the @Priority
annotation, the SPI was also enhanced to expose the priority of an observer method. We are not touching javax.enterprise
interfaces just yet. Instead,
the org.jboss.weld.experimental
package contains proposals for how the new SPI should look like. As the package name suggests, this SPI is good for a test-drive but do not expect it to be stable.
To use the experimental SPIs, you’ll need to add a dependency on weld-api.
Here’s an example of reading the observer method priority using the SPI in an Extension. ExperimentalProcessObserverMethod
and ExperimentalObserverMethod
interfaces come from the
org.jboss.weld.experimental package
.
public class SimpleExtension implements Extension {
void observe(@Observes ExperimentalProcessObserverMethod<User, ?> event) {
ExperimentalObserverMethod<User> observerMethod = event.getObserverMethod();
this.priority = observerMethod.getPriority();
}
}
Use the corresponding CDI ticket for any feedback on these features.
Vetoing and modifying observer methods
We’ll stay with observer methods for a few more paragraphs. A request was raised in the CDI issue tracker for making it possible to disable an
observer method using the ProcessObserverMethod
SPI.
This Alpha1 release introduces the veto()
methods (aligned with ProcessAnnotatedType.veto()
) for this:
void disableDebuggingObservers(@Observes ExperimentalProcessObserverMethod<?, Debug> event) {
if (projectStage != ProjectStage.Development) {
event.veto();
}
}
In addition, the observer method metadata may be altered by an extension. This is done similarly to how InjectionTarget
, InjectionPoint
or BeanAttribute
metadata are modified which
is most often by wrapping the original object (decorator design pattern). Any piece of metadata (including aforementioned priority) can be altered. For example, the transaction phase:
void alterObserver(@Observes ExperimentalProcessObserverMethod<User, ?> event) {
event.setObserverMethod(new ForwardingExperimentalObserverMethod<User>(event.getObserverMethod()) {
@Override
public TransactionPhase getTransactionPhase() {
return TransactionPhase.AFTER_SUCCESS;
}
});
}
Repeatable qualifiers and interceptor bindings
This release serves as a proof of concept for supporting repeating qualifiers and interceptor bindings. You can now fully utilize Java 8 features and use multiple qualifiers or interceptor bindings of the same type in the same location, for example:
public class School {
@Produces
@Speaks("English")
@Speaks("French")
public Student graduate() {
// ...
}
}
Repeating qualifiers can be used for both bean and event resolution. See the Java documentation for how to define a repeating annotation.
Interceptor bindings in invocation context
This is an often recurring scenario. An interceptor binding defines several @NonBinding
members which serve as configuration for the interceptor. How does an interceptor get hold of these values?
This is not easy as the interceptor binding may often appear on the intercepted method, the class that defined it or may be inherited from another interceptor binding or stereotype (even transitively!).
This problem gave birth to utilities such as
this one.
Still, even after all this effort the result is not entirely correct as it was obtained using Java reflection ignoring the fact that the interceptor binding may have been modified
(e.g. using ProcessAnnotatedType
).
This problem is being addressed as CDI-468. The Alpha1 release of Weld implements this feature and exposes new methods for obtaining interceptor bindings
that are in effect for the interception. This is done using ExperimentalInvocationContext.getInterceptorBindings()
or ExperimentalInvocationContext.getInterceptorBindingsByType()
.
Again, ExperimentalInvocationContext
can be found in the org.jboss.weld.experimental
package and depicts how the future version of javax.interceptor.InvocationContext
could look like.
@Interceptor
@Secure
public class SecurityInterceptor {
@Inject
private User user;
@AroundInvoke
public Object intercept(ExperimentalInvocationContext ctx) throws Exception {
Secure binding = ctx.getInterceptorBindingsByType(Secure.class).iterator().next();
if (!user.getRoles().contains(binding.requireRole())) {
throw new SecurityException();
}
return ctx.proceed();
}
}
Again, your feedback is welcome at CDI-468.
Changes in the Annotated layer
CDI provides an abstraction over the Reflection API - AnnotatedType and friends - which mostly allows extensions to alter the set of annotations present on a type, field, method, etc.
The Alpha1 release contains two minor additions to this API. Firstly, the API now supports Java 8 repeating annotations with a new method ExperimentalAnnotated.getAnnotationsByType(Class<T> annotationClass)
Secondly, it is now possible to access the java.lang.reflect.Parameter
instance that is wrapped by AnnotatedParameter
using ExperimentalAnnotatedParameter.getJavaParameter();
Give it a try!
[ Experimental API documentation ] [ Release notes ] [ Distribution ] [ Patch for WildFly 9 ]