| CDI 2.0 (JSR 365) Contexts and Dependency Injection for Java 2.0 Akihiro Nishikawa Cloud Technology Business Unit Oracle Corporation Japan 17, May, 2017 Java Day Tokyo 2017 #JavaDayTokyo
| Safe Harbor Statement The following is intended to outline our general product direction. It is intended for information purposes only, and may not be incorporated into any contract. It is not a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions. The development, release, and timing of any features or functionality described for Oracle’s products remains at the sole discretion of Oracle. 2
| What’s CDI? • Lifecycle for stateful objects bound to lifecycle contexts • Type-safe dependency injection mechanism • Event notification • Integration with the Unified Expression Language (EL) • ... 5 Major theme of CDI is “loose coupling”
| 8 CDI Timeline December 2009 CDI 1.0 (Java EE 6) June 2013 CDI 1.1 (Java EE 7) April 2014 CDI 1.2 (1.1 Maintenance Release) September 2014 CDI 2.0 starts… May 2017 CDI 2.0
| CDI 1.0 (JSR-299) • 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 9 Contexts and Dependency Injection for the Java EE platform 1.0
| CDI 1.1/1.2 (JSR-346) • Add automatic enablement of CDI in Java EE (beans.xml is not required) • 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 of CDI Lifecycle and Events 10 Contexts and Dependency Injection for the Java EE platform 1.1/1.2
| CDI 1.1/1.2 (JSR-346) • Reworking Bean defining annotation to avoid conflict with other JSR 330 frameworks • Clarification on conversation resolution • OSGi official support in the API 11 Contexts and Dependency Injection for the Java EE platform 1.1/1.2
| 12 CDI is associated with the following specs DI (Dependency Injection) EJB (Enterprise JavaBeans) Bean Validation Interceptors Managed Beans Common Annotation CDI JSF (JavaServer Faces)
| Major Changes • Spec was split into 3 parts • Java SE Support – Using CDI outside Java EE • Alignment on Java 8 features (streams, lambdas, repeating qualifiers) • Event enhancement • Configurators for major SPI elements • Possibility to configure or veto observer methods • Add built-in annotation literals • Make possible to apply interceptor on producers 14
| Why the spec was split? • To align on many other Java EE spec which support Java SE bootstrapping – JAX-RS, JPA... • To boost CDI adoption for Spec and Frameworks – Java SE has been already supported by Weld, Apache OpenWebBeans, Apache DeltaSpike and so on, but API is different from each implementation. – Programming model should be defined to avoid user confusion. • To provide a mean of building new stacks out of Java EE (MicroProfile) 17
| CDI 1.x • Not specified • Depending upon each implementation – Weld – Apache DeltaSpike – ... CDI 2.0 • Standard API is specified • Must explicitly boot CDI container 20 API to boot CDI in Java SE
| API to boot CDI in Java SE import javax.enterprise.inject.se.SeContainer; import javax.enterprise.inject.se.SeContainerInitializer; public class Sample { public static void main(String... args) { try (SeContainer container = SeContainerInitializer .newInstance() .initialize()) { ... } } } 21
| SeContainer interface • Handle for CDI Interface – The handle is used to access the BeanManager • AutoCloseable • Extends javax.enterprise.inject.Instance – Able to use SeContainer to look up Instance programatically – If no qualifier is passed to SeContainer#select(), the @Default qualifier is assumed. – If no required type is given, the required type is the same as the parent’s one. • Able to use CDI#current() 23 javax.enterprise.inject.se.SeContainer
| Request Context Management • In Java SE, most of built-in contexts is unavailable… –Request context –Session context –Conversation context –... 26 Why is this feature required?
| Request Context Management • Start and stop request context programmatically through built-in bean • Provide built-in Interceptor to handle it automatically • This feature is also available for Java EE. 27 How to manage request contexts
| Java 8 Alignment • Use Java 8 feature and functionalities heavily – Functional Interface – Stream • For example, Instance directly supports Stream API – Previously, unable to use Stream API along with Instance • Custom libraries using CDI 1.x might be built again to align with CDI 2.0 31
| Repeating Qualifier • Able to qualify classes and methods using the same annotation – Supported by language level • In case of get all annotations… 33 javax.enterprise.inject.spi.Annotated.getAnnotations()
| Event Ordering • Event ordering using @Priority – The lowest value is first – Observers with no explicit priority have a middle range priority for allowing observer to be called last – Observer with the same priority are called in an undefined order • Only applicable to synchronous events – @Priority does not work for ordering asynchronous events 35
| Events in CDI 1.x • Sync/Async is not specified, but implementation uses Synchronous model – Observers are called in the firing thread (i.e. synchronous event) without particular order specified • Immutable status of the payload is not specified – Payload is mutated in some implements and framework • Observers may inject beans • Observers are aware of Transactional and security contexts 39
| Asynchronous Events • Unable to mutate payload • Unable to access CDI contexts state at the firing point • Not transactional Event#fireAsync() @ObservesAsync 41 CDI 2.0
| Asynchronous Events • Exception raised in one async observer does not stop execution as in sync observer. – One of the reasons why firing async event does not trigger sync observers. • Event.fireAsync returns CompletionStage – Exception in fireAsync returned CompletionStage is CompletionException, which holds all the exceptions in the suppressed exception set. • Allowing integration of async events in standard Java 8 async pipeline. 45 Exception handling
| Asynchronous Events • stage.whenComplete() – To handle result or exception • stage.handle() – Same as above but allows transformation of stage. • stage.exceptionally() – Used in the only case for treating exception 47 Exception handling with standard Java 8 Asynchronous API
| Are you planning migration to asynchronous events? • Simple replacement might raise problems! • Recommendation – In case of using sync events as of now, you should keep as it is. – Some limitation should be recognized. – Going sync/async should be a decision taken from firing side. – Being sync should be possible from observing side. 49
| Threading and Events in Java SE • Async events – Able to use Custom Executor • Sync events – Always within the same thread – When observers handle synchronous event in Java SE, request scope activation might be required. 50 @Inject Event <Pojo> event; @ActivateRequestContext public void syncSender() { event.fire(event); ... } public void syncReceiver( @Observes Pojo event ) { ... }
| Previous • BeanManager#fireEvent() CDI 2.0 • BeanManager#getEvent() – Able to get Event object – Event is typed to Object and implicitly annotated with @Default qualifier • BeanManager#fireEvent() is deprecated since CDI 2.0. 51 Programmatic Events
| 53 Indeed AnnotationLiteral is helpful if there is no member in an annotation. Standard Annotation Instances Annotation instance = new AnnotationLiteral<ApplicationScoped>(){};
| 54 But we have to create a class when an annotation has members... Standard Annotation Instances public class NamedLiteral extends AnnotationLiteral<Named> implements Named{ private String value; public NamedLiteral(String value) { this.value = value; } @Override public String value() { return null; } }
| Built-in annotation literals Default defaultLiteral = new Default.Literal(); // No members ApplicationScoped literal = ApplicationScoped.Literal.INSTANCE; // If annotation have members Initialized initializedForApplicationScoped = new Initialized.Literal(ApplicationScoped.class); Initialized initializedForRequestScoped = Initialized.Literal.of(RequestScoped.class); 56 Example
| Configurators for metadata • AnnotatedType • InjectionPoint • Bean • ObserverMethod 58 Even if adding info to an existing metadata, quite verbose work is required.
| 59 In CDI 1.2 Configurators for metadata I want to modify some legacy framework which contains @CacheContext annotations in order to adapt CDI. What should I do? If I were you, I would create some extension to replace @CacheContext annotation with @Inject in AnnotatedTypes... But Do I have to create huge codes to do so? Exactly...
| 61 In CDI 2.0 Configurators for meta-data What do you do when you want to adapt CDI to some legacy framework? If I were you, I would create metadata with “configurators”, which are accessible through container lifecycle events and automatically built by the container at the end of observer invocation. Oh, it sounds nice…
| Add new methods in ProcessObserverMethod public interface ProcessObserverMethod<T, X> { ... // Replaces the ObserverMethod public void setObserverMethod(ObserverMethod<T> observerMethod); // Returns a ObserverMethodConfigurator initialized with the ObserverMethod processed by this event public ObserverMethodConfigurator<T> configureObserverMethod(); // forces the container to ignore the ObserverMethod public void veto(); } 67 javax.enterprise.inject.spi.ProcessSyntheticObserverMethod<T, X>
| 69 Able to apply @Transactional to a producer method Interceptor is not bound to a produced Bean in CDI 1.x @Produces @Transactional public MyService produceService() { ... }
| Programmatic lookup – Instance Enhancement Instance obj; ... if( !obj.isAmbiguous() && !obj.isUnsatisfied() ) { ... } 73 Previous isUnsatisfied() Returns true if there is no bean found, or false otherwise. isAmbiguous() Returns true if there is more than one bean found, or false otherwise.
| Key takeaway • Able to use CDI 2.0 on Java EE as well as Java SE. • Enhancements and new features help increase developer productivity. • Weld 3.0, reference Implementation of CDI, will be integrated with GlassFish 5 soon! 76
| Safe Harbor Statement The preceding is intended to outline our general product direction. It is intended for information purposes only, and may not be incorporated into any contract. It is not a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions. The development, release, and timing of any features or functionality described for Oracle’s products remains at the sole discretion of Oracle. 79