Top Banner
@antoine_sd @cdispec #Devoxx #CDI2 CDI 2.0 is upon us Antoine Sabot-Durand Red Hat CDI spec lead
59

CDI 2.0 is upon us Devoxx

Feb 21, 2017

Download

Software

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

CDI 2.0 is upon usAntoine Sabot-Durand

Red HatCDI spec lead

Page 2: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #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

Page 3: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

AgendaFlashback 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

Page 4: CDI 2.0 is upon us Devoxx

Previously on CDI

Page 5: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

CDI Timeline

Dec 2009 June 2013 Apr 2014 Sep 2014

CDI 1.0

(Jav

a EE

6)

CDI 1.1

(Jav

a EE

7)

CDI 1.2

(1.1 M

R)

CDI 2.0

Star

ts

jan 2017

CDI 2.0

relea

sed

Page 6: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

CDI 1.0 - December 2009A 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

Page 7: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #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

Page 8: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

CDI 1.2 - April 2014Clarification 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

Page 9: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

CDI 2.0 status

JSR 365 started in September 2014

EDR1 released in 2015

EDR2 released in august.

Weld 3 Alpha 17 is the RI for EDR2

Release expected in January 2017

Page 10: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

cdi-spec.org

Page 11: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

CDI 2.0 new features

Page 12: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Java SE supportusing CDI outside Java EE

Page 13: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #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

Page 14: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

What did we do?

CDI Specification

CDI Core CDI for Java EECDI for Java SE

Page 15: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Java SE bootstrap API

public static void main(String[] args) { SeContainer container = SeContainerInitializer.newInstance() .disableDiscovery() .addBeanClasses(MyService.class) .initialize(); MyService service = container.select(MyService.class).get(); service.sayHello(); container.close();}

Page 16: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Controlling the Request Context

In Java SE, most of our built-in contexts are unavailable:

Request context

Session context

Conversation context

That’s why we added tools to activate Request context programmatically

This feature is also available for Java EE

Page 17: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Controlling the Request Context

@ApplicationScopedpublic class MyBean { @Inject private RequestContextController requestContextController; public void doRequest(String body) { // activate request context requestContextController.activate(); // do work in a request context. // deactivate the request context requestContextController.deactivate(); }}

Page 18: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

In interceptor mode

@ApplicationScopedpublic class MyBean { @ActivateRequestContext public void doRequest(String body) { // Request Context will be activated during this invocation } }

Page 19: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Enhancing eventsMaking popular feature even more popular

Page 20: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #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

Page 21: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #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

Page 22: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Events ordering

public void observer1(@Observes @Priority(1) Payload p) { }

public void observer2(@Observes @Priority(2) Payload p) { }

Page 23: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Events ordering in extensions

public class MyExtension implements Extension { public void firstPat(@Observes @Priority(1) ProcessAnnotatedType<?> pat) { … }

public void secondPat(@Observes @Priority(2) ProcessAnnotatedType<?> pat) { … }}

Page 24: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #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…

Page 25: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Synchronous events - firing pattern

@InjectEvent<Payload> event;

public void someBSCriticalBusinessMethod() { event.fire(new Payload());}

Page 26: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Synchronous events - observing pattern

public void callMe(@Observes Payload payload) { // Do something with the event }

Page 27: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Events are sync in CDI 1

All the observers are called in the firing thread

In no particular order (at least not specified)

The payload may be mutated

Observers may inject beans

Observers are aware of Transactional and security contexts

Page 28: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Asynchronous EventsAsync events can’t:

Mute Payload

Access CDI contexts states at the firing point

Be transactional

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

Page 29: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Async events - firing pattern

@InjectEvent<Payload> event;

public void someEvenMoreCriticalBusinessMethod() { event.fireAsync(new Payload());}

Page 30: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Async events - observing pattern

public void callMe(@ObservesAsync Payload payload) { // I am called in another thread}

Page 31: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #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

Page 32: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Adding an Executor to fireAsync

@InjectEvent<PanelUpdater> event;

public void someOtherCriticalBusinessMethod() { event.fireAsync(new PanelUpdater(green), executor); }

Page 33: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Async event in the GUI thread

@InjectEvent<PanelUpdater> event;

public void someOtherCriticalBusinessMethod() { event.fireAsync(new PanelUpdater(green), SwingUtilities::invokeLater);}

Page 34: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Handling exceptions

@InjectEvent<PanelUpdater> event;

public void someOtherCriticalBusinessMethod() { CompletionStage<PanelUpdater> stage = event.fireAsync(new PanelUpdater(green), SwingUtilities::invokeLater);}

Page 35: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #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

Page 36: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Handling exceptions

The Exception in fireAsync returned CompletionStage is

CompletionException

It holds all the exceptions in the suppressed exception set

Page 37: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #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

Page 38: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

SPI enhancementNew configurators for meta data

Page 39: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Standard annotations instances

CDI makes an heavy use of Annotations

Java doesn’t provide easy way to create an annotation instance

We provided AnnotationLiteral, to help users create their instances

Annotation instance = new AnnotationLiteral<ApplicationScoped>(){};

Page 40: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

When members are here a class has to be created

public class NamedLiteral extends AnnotationLiteral<Named> implements Named{ private String value; public NamedLiteral(String value) { this.value = value; } @Override public String value() { return null; }}

Page 41: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

CDI 2.0 provides helpers out of the box

ApplicationScoped literal = ApplicationScoped.Literal.INSTANCE;

Named literal2 = NamedLiteral.of("myName");

Page 42: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Configurators for meta-dataSome 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

Page 43: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #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

Page 44: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Example 1/7

First we need to implement an AnnotatedType to decorate the original one and modify AnnotatedField set

Page 45: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Example 2/7

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); } }…

Page 46: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Example 3/7

… public Set<AnnotatedField<? super X>> getFields() { return fields; } public Class<X> getJavaClass() { return delegate.getJavaClass(); } // 7 more similar methods }

Page 47: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Example 4/7Then 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()); }…

Page 48: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Example 5/7

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; }

...

Page 49: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Example 6/7

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 }

Page 50: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Example 7/7Finaly 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())); }}

Page 51: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #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

Page 52: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

In CDI 2.0All 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)); }}

Page 53: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

AOP enhancementSupport AOP on custom or produced bean

Page 54: CDI 2.0 is upon us Devoxx
Page 55: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Support AOP on producerIn 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() {

...}

Page 56: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Support Interceptor on producerAnswer is probably the new InterceptionFactory

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 InterceptionFactory<T> { InterceptionProxyFactory<T> ignoreFinalMethods(); AnnotatedTypeConfigurator<T> configure(); <T> T createInterceptedInstance(T InstanceToWrap);}

Page 57: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Add @transaction on one produced bean method

@Produces@RequestScopedpublic MyClass createJpaEmAssumed(InterceptionFactory<MyClass> ify) { AnnotatedTypeConfigurator<MyClass> atc = ify.configure(); atc.filterMethods(m -> m.getJavaMember().getName().equals("doSomething")) .findFirst() .ifPresent(m -> m.add(new AnnotationLiteral<Transactional>() { })); return ify.createInterceptedInstance(new MyClass());}

Page 58: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #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

Page 59: CDI 2.0 is upon us Devoxx

@antoine_sd @cdispec#Devoxx #CDI2

Which JSR you’ll use 365 days a year?…

JSR 365