New features coming in CDI 2.0, talk given during Java One 2016
- Java SE support
- Async events
- Ordered events
- Meta data configurators
- Interceptors on producers
2. MicroProfile 1.0 Released!
Microservice Collaboration and Innovation in the Java Community
microprofilelunch.com, Thursday 11:30am - 2:00pm
Learn more at microprofile.io
MicroProfile BOF, Tuesday 10:30 - 11:30, Hilton Lombard Room
(3rd tower, 6th floor)
3. @antoine_sd @cdispec#CDI2
Me, Myself and I
Antoine Sabot-Durand
Software Engineer at Red Hat
CDI spec lead
CDI evangelist
Follow me: @antoine_sd
Follow CDI: @cdispec
4. @antoine_sd @cdispec#CDI2
Agenda
Flashback on CDI & CDI 2.0 status
CDI 2.0 new features
Java SE support
Enhancing events
Metadata configurators
Interceptor and Decorators on Produced / custom beans (coming)
Questions and Feedback
7. @antoine_sd @cdispec#CDI2
CDI 1.0 - December 2009
A well-defined lifecycle for stateful objects bound to lifecycle contexts
Where the set of contexts is extensible
A type-safe dependency injection mechanism without verbose configuration
Dependencies can be selected at development or deployment time
Type-safe decorators and interceptors
An event notification model
An SPI allowing portable extensions to integrate cleanly with the container
8. @antoine_sd @cdispec#CDI2
CDI 1.1 / 1.2 – June 2013 / April 2014
Add automatic enablement of CDI in Java EE
Add introspection with event, bean, decorator and interceptor meta data
Ease access to bean manager from outside CDI with CDI class
Add global enablement of interceptors using the @Priority annotation
Add Unmanaged allowing easy access to non-contexutal instances
Spec clarification
9. @antoine_sd @cdispec#CDI2
CDI 1.2 - April 2014
Clarification in the spec regarding:
CDI Lifecycle
Events
Reworking Bean defining annotation to avoid conflict with other JSR 330
frameworks
Clarification on conversation resolution
OSGi official support in the API
10. @antoine_sd @cdispec#CDI2
CDI 2.0 status
JSR 365 started in September 2014
EDR1 released in 2015
EDR2 released in august.
Weld 3 Aplha 17 is the RI for EDR2
Release expected in January 2017
14. @antoine_sd @cdispec#CDI2
Java SE support - Why?
To align on many other Java EE spec which support Java SE bootstrapping
To boost CDI adoption for Spec and Frameworks
To provide a mean of building new stacks out of Java EE
18. @antoine_sd @cdispec#CDI2
Enhancing events
CDI events are a very loved feature
We took a very long time to see how to enhance them
In CDI 2.0 we are introducing
Event ordering
Asynchronous events
19. @antoine_sd @cdispec#CDI2
Events ordering
By adding a @Priority (from commons annotations) on an observer.
The lowest value is first
Observers with no explicit priority have a middle range priority
Allowing observer to be called last
Observer with the same priority are called in an undefined order
No priority on async events
21. @antoine_sd @cdispec#CDI2
public class MyExtension implements Extension {
public void firstPat(@Observes @Priority(1) ProcessAnnotatedType<?> pat) {
…
}
public void secondPat(@Observes @Priority(2) ProcessAnnotatedType<?> pat) {
…
}
}
Events ordering in extensions
22. @antoine_sd @cdispec#CDI2
CDI 1.x: Sync / Async
Sync / Async is not specified
The immutable status of the payload is not specified
Implementations use a Sync model
The payload is mutated in some implementations / framework
Going async “blindly” might raise problems…
25. @antoine_sd @cdispec#CDI2
Events are sync in CDI 1
Right now:
All the observers are called in the firing thread
In no particular order (at least not specified)
The payload may be mutated
26. @antoine_sd @cdispec#CDI2
Events and contexts
Contexts:
Two contexts are critical: transactions and HTTP requests / sessions
Events are aware of those contexts
In an all-sync world, everything is fine
But in an async world, we will be in trouble
27. @antoine_sd @cdispec#CDI2
Asynchronous Events
So designing backward compatible async events is more tricky than it looks:
A currently sync event should remain sync
Going sync / async should be a decision taken from the firing side
Being sync should be possible from the observing side
30. @antoine_sd @cdispec#CDI2
Sync vs Async Events in a nutshell
callMe(@Observes payload) callMe(@ObservesAsync payload)
event.fire(payload) Sync call Not notified
event.fireAsync(payload) Not notified Async call
34. @antoine_sd @cdispec#CDI2
Handling exceptions
Exception in one async observer doesn’t stop execution as in sync observer
One of the reasons why firing async event doesn’t trigger sync observers
Event.fireAsync returns a CompletionStage
Allowing integration of async events in standard Java 8 async pipeline
36. @antoine_sd @cdispec#CDI2
Handling exceptions
Exception handling is done with the Standard Java 8 async api, with:
stage.whenComplete() to deal with result or exception
stage.handle() same as above but allows transformation of stage
stage.exceptionally() to only treat exception case
38. @antoine_sd @cdispec#CDI2
Configurators for meta-data
Some meta-data are very verbose to create
AnnotatedType
Bean
InjectionPoint
ObserverMethod
If you only need to add info to an existing meta-data, it’s very boring
39. @antoine_sd @cdispec#CDI2
Example with CDI 1.2
I have a legacy framework
I want to adapt it for CDI
I need to detect all @CacheContext annotations on fields…
...And transform them in injection point
I’ll use an extension to replace @CacheContext annotation by @Inject in
AnnotatedTypes
41. @antoine_sd @cdispec#CDI2
public class AutoInjectingAnnotatedType<X> implements AnnotatedType<X> {
private final AnnotatedType<X> delegate;
private final Set<AnnotatedField<? super X>> fields;
public AutoInjectingAnnotatedType(AnnotatedType<X> delegate) {
this.delegate = delegate;
fields = new HashSet<>();
for (AnnotatedField<? super X> field : delegate.getFields()) {
if (field.isAnnotationPresent(CacheContext.class))
fields.add(new AutoInjectingAnnotatedField(field));
else
fields.add(field);
}
}
…
Example 2/7
43. @antoine_sd @cdispec#CDI2
Example 4/7
Then we need to do the same for AnnotatedField to add @Inject to the
field annotations set
public class AutoInjectingAnnotatedField<X> implements AnnotatedField<X> {
private final Set<Annotation> annotations;
private final AnnotatedField<X> delegate;
public AutoInjectingAnnotatedField(AnnotatedField<X> delegate) {
this.delegate = delegate;
annotations = new HashSet<>(delegate.getAnnotations());
annotations.add(new InjectLiteral());
}
…
44. @antoine_sd @cdispec#CDI2
public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
if (annotationType.equals(Inject.class))
return (T) new InjectLiteral();
return delegate.getAnnotation(annotationType);
}
public Set<Annotation> getAnnotations() {
return annotations;
}
...
Example 5/7
45. @antoine_sd @cdispec#CDI2
public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
if (annotationType.equals(Inject.class))
return true;
return delegate.isAnnotationPresent(annotationType);
}
public Set<Type> getTypeClosure() {
return delegate.getTypeClosure();
}
// 4 similar methods
}
Example 6/7
46. @antoine_sd @cdispec#CDI2
Example 7/7
Finaly we need to write the extension to use our custom AnnotatedType
and AnnotatedField
public class AutoInjectExtension implements Extension {
public <T> void CreateIP(
@Observes @WithAnnotations(CacheContext.class)
ProcessAnnotatedType<T> pat) {
pat.setAnnotatedType(
new AutoInjectingAnnotatedType<T>(pat.getAnnotatedType()));
}
}
47. @antoine_sd @cdispec#CDI2
In CDI 2.0
We introduced configurators, helping creation of these metadata
This configurators are accessible thru container lifecycle events
They are automatically built by the container at the end of
observer invocation
48. @antoine_sd @cdispec#CDI2
In CDI 2.0
All the previous code fits in this extension
public class AutoInjectExtension implements Extension {
public <T> void CreateIP(
@Observes @WithAnnotations(CacheContext.class) ProcessAnnotatedType<T> pat) {
pat.configureAnnotatedType().filterFields(
f -> f.isAnnotationPresent(CacheContext.class)
)
.forEach(f -> f.add(InjectLiteral.INSTANCE));
}
}
51. @antoine_sd @cdispec#CDI2
Support AOP on producer
In CDI 1.x you cannot bind an interceptor to a produced bean
When you write:
@Transactional is applied to producer method
@Produces
@Transactional
public MyService produceService() {
...
}
52. @antoine_sd @cdispec#CDI2
Support AOP on producer
Answer is probably the new InterceptionProxyFactory
This factory uses an AnnotatedType to know where adding interceptor bindings in
the class
Could also be used in Custom Bean create method
public interface InterceptionProxyFactory<T> {
InterceptionProxyFactory<T> ignoreFinalMethods();
AnnotatedTypeConfigurator<T> configure();
<T> T createInterceptionProxy(T InstanceToWrap);
}
53. @antoine_sd @cdispec#CDI2
@Produces
@RequestScoped
public MyClass createJpaEmAssumed(InterceptionProxyFactory<MyClass> ipf) {
AnnotatedTypeConfigurator<MyClass> atc = ipf.configure();
atc.filterMethods(m -> m.getJavaMember().getName().equals("doSomething"))
.findFirst()
.ifPresent(m -> m.add(new AnnotationLiteral<Transactional>() { }));
return ipf.createInterceptionProxy(new MyClass());
}
Add @transaction on one produced bean method
54. @antoine_sd @cdispec#CDI2
CDI 2.0 needs you
CDI 2.0 specification is open to everyone
Come on join us on the mailing list and IRC channel
All infos on http://cdi-spec.org or by following to @cdispec on
twitter
The more we are the more we’ll deliver