Extending Java EE with CDI and JBoss Forge

  • View
    1.537

  • Download
    5

  • Category

    Software

Preview:

Citation preview

ExtendJavaEEwithCDI

AntoineSabot-Durand·AntonioGoncalves

AntoineSabot-Durand

RedHatCDIspeclead@antoine_sdnext-presso.comgithub.com/antoinesd

AntonioGoncalves

JavaChampionContractordevelopperantoniogoncalves.org@agoncalgithub.com/agoncal

Agenda

MeetExpensEEsMeetCDIBasicDIProducersInterceptorsQualifiersProgrammaticLookupContextsEventsExtensionsConclusion

ExpensesmadeEEsy

MeetExpensEEs

WewereaskedtobuildthisappAwebapptomanageexpensesBasedonJavaEE7CDI1.2JPA2.1JSF2.2JAX-RS2.0Abletointegratelegacylibs

Storyboard-HomeScreen

Storyboard-LoginScreen

Storyboard-NewUserScreen

Storyboard-LoggedIn

Storyboard-Profile

Storyboard-ExpenseDetail

Storyboard-ExpenseConfirm

Storyboard-ViewExpenses

Architecture-ModelUser

String loginString passwordString nameString emailUserRole role

Reimbursement

Date dateSet<Expense> expensesCurrency currencyUser userConference conference

Expense

descriptionDate dateFloat amountExpenseType expenseTypeprivate Currency currency

Conference

String nameDate dateString countryString city

1

*

1 *

1

*

Let’sForgeExpensEEs!

JBossForge

Forge

1. Generation&Scaffoldingtool2. Shellcommands&IDEIntegration3. Getsyoustartquickly4. Takescareofintegration5. Pluginbased6. JavaEE…Butanythingelsereally7. Moreinfoonforge.jboss.org/

Backtodemo RunJBossForge

CreateJPAEntities

ScaffoldJSFCRUDpages

ScaffoldRESTEndpoint

RunForgescript

ArchitectureForgehtml

web rest

model

ConferenceCRUDExpenseCRUD ReimbursementCRUD UserCRUD

ConferenceBeanExpenseBean ReimbursementBean UserBean ConferenceEndpoint

ConferenceExpenseService Reimbursement User

useuse use use

useuseuse use use

NotFinishedYet

1. OnlyaCRUDapp2. No"Createexpenses"Wizard3. NoLogin/logout4. Primefaces5. JavaEE6insteadofJavaEE76. JTA1.2@Transactional7. JPA2.1InsertdatainDB8. NotinfullCDIprogrammingmodel!

Backtodemo

Refactortheapp

Addaservicelayer

AddJavaEE7dependencies

LessEJBMoreCDI

WebjarforTwitterBootstrap

2hourslater…

NewArchitecturehtml

web rest

service

model

ConferenceCRUDExpenseCRUD ReimbursementCRUD UserCRUD

ConferenceBeanExpenseBean ReimbursementBean UserBean ConferenceEndpoint

ConferenceServiceExpenseService ReimbursementService UserService

ConferenceExpense Reimbursement User

useuse use use

@Inject@Inject@Inject @Inject @Inject

useuse use use

ContextsandDependencyInjection

MeetCDI

WhatisCDI?AJavaEEspec.ASL2(evenTCK)LaunchedinJavaEE62releasessincelaunch1.2islast(JavaEE7)2.0onitsway2majorimpl.JBossWeld(RI)ApacheOpenWebBeans

What’sincluded?CDIProvides:

1. Apowerfulprogrammingmodel2. DifferentLifecyclesforstateful

objects3. ATypesafeDImechanism4. Theabilitytodecorateinjected

objects5. Theabilitytointerceptmethods6. Aneventnotificationmodel7. ASPIallowingportableextensionstointegrate3rdpartytech

“CDIexplainedtoyourboss

CDIbringsapowerfulandmodernprogrammingmodelthatstandardizesgoodpractices.

CDIprovidesaconsistentandseamlesswaytointegrate3rdpartyframeworkstothismodel.

Onceadopted,CDIwillbecometheinvisiblebackboneofourprojects.

Onecontainertorulethemall ThecontaineristheheartofCDI

ThecontainerchecksallpossibleCDIcodeatboottime

Thecontainermanagesyourcomponentslifecycleandservices

Yet,you’llneverseeit(exceptinadvanceddevelopment)

Containerisyourapplication’sinvisibleconductor

@Inject

AlmostEverythingisabean

Duringboottime,thecontainerscanseachclasstocheckifitmeetstheconditionstobeabean

Theseconditionsareverylooseso,mostpojoclassesarebeans

public class HelloService { public String hello() { return "Hello World!"; }}

HelloService isaconcreteclasswithadefaultconstructor,thereforeit’sabean

1

1

Injectioninbeanfield Abeancaninjectotherbeansorbeinjectedintootherbeans

public class MyBean { @Inject private HelloService service;

public void displayHello() { display(service.hello(); }}

@Inject annotationdefinesaninjectionpoint(hereafield)

Thecontainerlooksaforthebeantoinjectbyitstype(here HelloService )

12

1

2

Injectioninbeanconstructor

Tobecomeabeanaclassmusthaveaconstructorwithnoparametersoraconstructorannotated @Inject

public class MyBean {

private HelloService service;

@Inject private MyBean(HelloService service) { this.service = service; }}

Onlyoneconstructorcanbeannotatedwith @Inject

Injectioninamethod Suchmethodiscalledinitializermethods

public class MyBean {

private HelloService service;

@Inject public void initService(HelloService service) { this.service = service; }}

allinitializermethodsarecalledatbeaninstantiation

TherecouldbeonlyoneEachinjectionpointischeckedatboottime:

Ifnobeaniseligibleforit,theinjectionpointisunsatisfied

Ifmultiplebeansareeligibleforit,theinjectionpointisambiguous

Inbothcasea DeploymentException isthrownbythecontainer

Backtodemo

InjectaLoggerinto UserService

Logamessagein persist method

Whenyoudon’townyourbean’sclass,use

Producers

Whatisaproducer?Awaytodeclareabean…

…fromafieldoramethod…

…foraclassyoudon’town…

…oranonCDIclass.

DeclaringaProducerpublic class ProducingBean { @Produces private List<Integer> mapInt = new ArrayList<>();

@Produces @French public List<String> FrenchListStrProducer() { List<String> res = Arrays.asList("bonjour"); return res; }}

ProducersshouldbedeclaredinaBeanclass

It’safieldoramethodannotatedwith @Produces (staticmethodssupported)

Producerscanhavequalifiers

valueoffieldormethodreturnedvalueisthebeaninstance

12

23

4

1

2

3

4

Producersareanotherkindofbean theycanhavequalifierslikeanyotherbean

producermethod(orfield)iscalledtocreatethebeaninstance

public class MyBean {

@Inject @French private List<String> frenchListStrBean;

@Inject public MyBean(List<Integer> initValues) { ... }}

DisposersareProducer’shousekeeping Disposerscanfreeresourceswhenproducedbeanisdestroyed

public class ProducingBean {

@Produces public MyNonCDIClass myProducer() { return new MyNonCdiClass(); }

public void releaseMyInstance(@Disposes MyNonCdiClass inst) { inst.clean(); }}

Willbecalledatthebeaninstanceendoflife

1

1

Producermethodscanhaveparameters Parameterswillbeinjectedbythecontaineratinstantiationtime

Theyshouldhavematchingbeansotherwisedeploymentfails

public class ProducingBean {

@Produces public MyNonCDIClass listStrProducer(MyBean bean) { ... }}

Thecontainerresolves MyBean andpassesittotheproducerwhenaninstanceofthebeanisrequested

1

1

Backtodemo

Theclass LoggerProducer producesaLogger

Injectingaloggerinservicedoesn’tchange

AccessingInjectionPointmetadata ThecontainercanprovidemetadataabouttheInjectionPoint

public class ProducingBean {

@Produces public Logger produceLog(InjectionPoint injectionPoint) { return Logger.getLogger(injectionPoint.getMember() .getDeclaringClass().getName()); }}

InjectionPoint isaSPIinterface.Thecontainercaninjectittogiveinfoabouttheinjectionpoint

1

1

Backtodemo

Add InjectionPoint APItotheproducer

Injectingaloggerinservicedoesn’tchange

InterceptorsandDecorators

InterceptorsvsDecorators TheyarebothAspectOrientedProgrammingtools

Interceptorsaretechnicaloriented:transaction,security,logging

Interceptorsareboundtoanybeanorbeanmethod

Decoratorsarebusinessoriented:changethebehaviourofabean

Decoratorsareboundtoabeantype

Interceptors Interceptorsaredefinedintheirownspecification

Usershouldcreateanannotationasaninterceptorbinding

Interceptorclassmustbeboundtoaninterceptorbinding

Interceptorclasscontainsinterceptingmethodswhichareboundtolifecyclephaseofinterceptedbean

Interceptorbindingisaddedtointerceptedbeanormethod

Interceptorbindingexample Aninterceptorbindingisannotationusedintwodifferentplaces

Ontheinterceptorandontheinterceptedelementtolinkthem

@InterceptorBinding @Target({METHOD, TYPE})@Retention(RUNTIME)public @interface Loggable {}

Thisannotationcomesfrominterceptorspecification.Itmakes @Loggable aninterceptorbinding

1

1

Interceptorexample@Interceptor

@Loggable

@Priority(Interceptor.Priority.APPLICATION) public class LogInterceptor {

@AroundInvoke public Object log(InvocationContext ic) throws Exception { System.out.println("Entering " + ic.getMethod().getName()); try { return ic.proceed(); } finally { System.out.println("Exiting " + ic.getMethod().getName()); } }}

Wemaketheclassaninterceptor( @Interceptor comesfromInterceptorspec)

Webindthisinterceptortothe @Loggable interceptorbinding

Weactivateandgiveaprioritytotheinterceptor(canbedonein beans.xml configfileaswell)

Thisinterceptingmethodwillbeinvokedinsteadoftheinterceptedone.

12

3

4

1

2

3

4

InterceptorUsage@Loggable public class MyBean { ... }

public class MyOtherBean {

@Loggable public String hello() { ... }

}

Allbean’smethodwillbeintercepted

Thismethodwillbeintercepted

1

2

1

2

Decorators Tobedecorated,abeanshouldimplementaninterface

Thedecoratorhastoimplementthesameinterface

Itisdeclaredwith @Decorator annotation

Itcanbeanabstractclass(letsyouchoosemethodstodecorate)

Itinjectsthedecoratedbeanwith @Delegate annotation

DecoratorExample@Decorator

@Priority(Interceptor.Priority.APPLICATION)

public abstract class HelloDecorator implements HelloService {

@Inject @Delegate HelloService service;

public String hello() { return service.hello() + "-decorated"; }}

Declaresthattheclassisadecorator

Activatesandgivesaprioritytothedecorator(couldbedonevia beans.xml file)

Decoratorscanbeabstractandshouldsharethesameinterfacethandecoratedbeans

Decoratedbeanisannotatedwith @Delegate (otherbeanscouldbeinjectedindecorator)

Decoratingmethodiscalledinsteadofdecoratedbeanmethod.Delegatecanbeusedinit.

12

3

4

5

1

2

3

4

5

Backtodemo Createa @Loggable interceptorbinding

Createa LoggingInterceptor

Add LoggingInterceptor toeachservice

Enableinterceptorinthe beans.xml

Solvingambiguouscaseswith

Qualifiers

Whenaninjectionpointresolvestomultiplebeans…public class MyBean { @Inject HelloService service;}

public interface HelloService { public String hello();}

public class FrenchHelloService implements HelloService { public String hello() { return "Bonjour tout le monde!"; }}

public class EnglishHelloService implements HelloService { public String hello() { return "Hello World!"; }}

deploymentfailswithan Ambiguous dependencies error.

ThesolutionistocreateQualifiers…@Qualifier@Retention(RUNTIME)@Target({FIELD, TYPE, METHOD, PARAMETER})public @interface French {}

@Qualifier@Retention(RUNTIME)@Target({FIELD, TYPE, METHOD, PARAMETER})public @interface English {}

Qualifiersareannotationsannotatedwith @Qualifier

toqualifybeanssharingthesametype…

@Frenchpublic class FrenchHelloService implements HelloService { public String hello() { return "Bonjour tout le monde!"; }}

@Englishpublic class EnglishHelloService implements HelloService { public String hello() { return "Hello World!"; }}

anddistinguishthematinjectionpoints.

public class MyBean { @Inject @French HelloService serviceFr;

@Inject @English HelloService serviceEn; }

Qualifiersaretypesenhancinginjection,yetkeepingitstrongtyped

Qualifierscanhavemembers@Qualifier@Retention(RUNTIME)@Target({FIELD, TYPE, METHOD, PARAMETER})public @interface Language {

LangChoice value();

@Nonbinding String description() default "";

public enum LangChoice { FRENCH, ENGLISH }}

@Nonbinding member’svalueisn’tusedinbeanresolutionmechanism

1

1

Bindingmemberslimitthenumberofannotationstoaddtoyourcode

@Language(FRENCH)public class FrenchHelloService implements HelloService { public String hello() { return "Bonjour tout le monde!"; }}

@Language(ENGLISH)public class EnglishHelloService implements HelloService { public String hello() { return "Hello World!"; }}

public class MyBean { @Inject @Language(value = FRENCH, description = "ici on parle français") HelloService serviceFr;

@Inject @Language(value = ENGLISH, description = "english spoken here") HelloService serviceEn;}

Multiplequalifiers Abeancanhavemultiplequalifiers

@Language(FRENCH) @Console public class FrenchHelloService implements HelloService { public String hello() { return "Bonjour tout le monde!"; }}

public class MyBean { @Inject @Language(FRENCH) @Console HelloService serviceFr;}

@Console isaqualifier

1

1

Multiplequalifiers

Injectionpointcanhaveanonemptysubsetofthebean’squalifiers

@Language(FRENCH) @Consolepublic class FrenchHelloService implements HelloService { public String hello() { return "Bonjour tout le monde!"; }}

public class MyBean { @Inject @Console HelloService serviceFr;}

Multiplequalifiers Injectionpointcan’thaveasupersetofbean’squalifier

@Language(FRENCH) @Consolepublic class FrenchHelloService implements HelloService { public String hello() { return "Bonjour tout le monde!"; }}

public class MyBean { @Inject @Language(FRENCH) @Console @Language(CANADIAN) HelloService serviceFr;}

Unsatisfiedinjectionpoint:deploymentfails

1

1

Built-inqualifiers

@Named setbeannameforweaktypedenvironment(EL,Javascript)

@Default addedtobeanswithoutqualifierorhavingonly@Named

@Any addedtoallbeansforprogrammaticlookupanddecorators

@Intercepted & @Decorated toinjectinterceptedbeaninaninterceptor/Decorator

@Initialized toqualifyeventswhenacontextisstarted

Examplespublic class MyBean { ... } @Namedpublic class MyBean2 { ... }

@Named @Language(FRENCH) public class MyBean2 { @Inject MyBean2 bean;}

thisbeanhas @Default and @Any qualifiers

thisbeanhas @Default , @Named and @Any qualifiers

thisbeanhas @Language(FRENCH) , @Named and @Any qualifiers

thisinjectionpointhas @Default qualifier

1

2

3

4

1

2

3

4

BeanTypes Abeanhasasetoftypesdependingonitsdefinition

Beantypessetforamanagedbeancontainsthebeanclass,everysuperclassandallinterfacesitimplementsdirectlyorindirectly.

Beantypescanberestrictedbyusing @Typed annotation( Objectisalwaysintheset)

BeantypesExamplepublic interface HelloService extends Hello { ... }

public class MyBean { @Produces

public HelloService prodHelloService() { ... } }

public class FrHelloService extends GenericService<String> implements HelloService { ... }

@Typed({HelloService.class})

public class FrHelloService extends GenericService<String> implements HelloService { ... }

class MyBean and Object

HelloService , Hello and Object

FrHelloService , GenericService<String> , HelloService , Hello and Object

HelloService and Object

1

2

3

4

1

2

3

4

Parameterizedtypescount Parameterizedtypesinformationiskept(i.e.notypeerasure)

public class MyBean {

@Inject Service<User> userService;

@Inject Service<Staff> staffService; }

Injectionpointsabovecanbesatisfiedwithoutambiguity

PerformingTypesafeResolution Whenresolvingabeantobeinjectedtoaninjectionpoint…

…thecontainerconsidersbeantypeandqualifiers.

Ifthebeanhasabeantypethatmatchesinjectionpointtype…

…andthebeanhasallthequalifiersoftheinjectionpoint…

…thebeanisassignabletotheinjectionpoint.

Backtodemo Createa @Clear and @Encrypted qualifiers

Createa DigestPassword interface

Twoimplementations ClearPassword and EncryptPassword

Injectencryptedpassworddigestinto AccountBean andUserService

Resolvingbeansatruntime

ProgrammaticLookup

MeetInstance interface Instance interfaceletsperformtypesaferesolutionatruntime

public class MyBean {

@Inject Instance<HelloService> service;

public void displayHello() { display(service.get().hello()); }}

Instance<T> injectionpointsarealwayssatisfiedandneverfailatdeploymenttime

with Instance<T> youcontrolwhenbeanainstanceisrequestedwiththe get() method

1

2

1

2

Checkbeanexistenceatruntime Instance<T> containsmethodstotestbeanresolution

public class MyBean {

@Inject Instance<HelloService> service;

public void displayHello() { if (!(service.isUnsatisfied() || service.isAmbiguous())) { display(service.get().hello()); } }}

iftouskipthetest get() maythrowanexception

1

1

Loopingonallbeansinthe Instance

Instance<T> isiterable

It’swhereweusethe @Any qualifierpresentonallbeans

public class MyBean {

@Inject @Any Instance<HelloService> services;

public void displayHello() { for (HelloService service : services) { display(service.hello()); } }}

Selectabeanbyitsqualifier

AnnotationLiteral isahelperclasstocreateanannotationinstance

public class MyBean {

@Inject @Any Instance<HelloService> services;

public void displayHello() { display( services.select(new AnnotationLiteral()<French> {}).get()); }}

select() alsoacceptsatype.

youcanuse TypeLiteral tocreateinstancesofparameterizedtypes

1

1

Backtodemo Loopthroughall DigestPassword

Thanksto @Any

Useeither @Encrypted or @Clear

Beanslifeanddeath

Contexts

Bean,ScopeandContexts AllBeanshaveascopedefinedbyanannotation

Eachscopeisassociatedtoacontextobject

Soeachbeanisboundtoacontext

Thecontextisinchargeofcreatingbeaninstances

TheContainerisinchargeofcreatinganddestroyingcontexts

Availablescopes

CDIprovidesthefollowingbuilt-inscopes(andassociatedcontexts):

@Dependent (default)beanhasthesamescopethanitsinjector @ApplicationScoped instanceislinkedtoapplicationlifecycle @SessionScoped instanceislinkedtohttpsessionlifecycle @RequestScoped instanceislikedtohttprequestlifecycle @ConversationScoped lifecyclemanuallycontrolledwithinsession

Instanceiscreatedatfirstrequestanddestroyedwithitsboundcontext

CDISPIallowsthirdpartytocreatetheircustomcontexts

Examplespublic class BaseHelloService implements HelloService { ... }

@RequestScoped public class RequestService { @Inject HelloService service;}

@ApplicationScoped public class ApplicationService { @Inject RequestService service; }

Beanhasdefaultscope @Dependent ,instancesarecreatedforeachinjection

Beanis @RequestScoped .Instanceiscreatedbyrequestcontextanddestroyedwithrequestcontext

Beanis @ApplicationScoped .Instanceiscreatedbyapplicationcontextandwillliveduringallapplication

Noproblemtoinjectbeanfromanotherscope:CDIwillprovidetherightbean

1

2

3

4

1

2

3

4

Goodtoknow

instancesarecreatedwhenfirstaccessednotwiththeircontext

Abeaninstanceisasingletoninitscontext

WithSPIyoucanmanuallydestroyaninstanceinacontext

Acontextcanbeinactivewithoutbeingdestroyed

Requestcontextismorethanamappingto ServletRequest lifecycle

Moreon@ConversationScoped Acontextwhoselifecycleiscontrolledbythedev

Conversationistransientorlongrunning

It’spromotedtolongrunningwith Conversation built-inbean…

…bycalling begin() method…

…andterminatedwith end() .

TherecanbemultipleconversationsinoneHttpSession

Conversation id isusedtoretrievetheactiveconversation

Example@ConversationScopedpublic class WizardBean {

@Inject Conversation conversation;

public startWizard() { ... conversation.begin() ... }

public endWizard() { ... conversation.end() ... }}

Backtodemo Wizardtocreatenewexpenses

Useof @ConversationScoped

JSFdealswith cid

Contextsarenotalwaysconvenient

Lifecyclemagicmanagementcanlimityou

Beaninstancesaredestroyedonlywhencontextends

Andyoumightwanttogetridofinstancebutkeepthecontext

CDI1.1addedaprogrammaticwaytodestroyaninstance

Example-Logoutandsessioninvalidation@Inject FacesContext facesContext;

public String logout(){ try{ facesContext.getExternalContext().invalidateSession(); return "success?faces-redirect=true"; } catch(Exception e){ return "error"; }}

redirectisimportanttoendcurrentrequestandkillthesessioneffectively

wemightwanttokeepthecurrentsessionandlogoutuser

notagoodpracticetocallUIlayerfromservicetoperformbusiness

1

1

Example-DologoutinaCDIway@Named@SessionScopedpublic class AccountBean implements Serializable {

@Inject private Instance<AccountBean> myInstance;

public String doLogout() { myInstance.destroy(myInstance.get()); return "/index"; }

SinceCDI1.1, Instance providesa destroy() methodtoremoveaninstancefromitscontext

1

1

Backtodemo

AccountBean injectsareferencetoitself

AccountBean destroysitforlogout

Alternatives&Stereotypes

Alternatives

Analternativeisabeanthatmustbeexplicitlyselected

Whenselecteditsuperseedsbeanssharingthesametype

AconvenientwaytocreateMockorspecificimplementation

Analternativecanbeactivatedin beans.xml orwith @Priority

AlternativeExamplepublic SapService implements ErpService { }

@Alternativepublic MockSapService implements ErpService { }

@ApplicationScopedpublic OrderService { @Inject ErpService service; }

Aservicedoingheavyorcostlyoperation

Canbemockedwithanalternative

Beansinjectingtheservicehavenothingtodo.Alternativewillreplacetheoriginalbeanifselected

1

2

3

1

2

3

SelectingtheAlternative

With @Priority annotaion(forthewholeapp)

@Alternative@Priority(Interceptor.Priority.APPLICATION) public MockSapService implements ErpService {}

With beans.xml file(forthecurrentmodule)

<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"> <alternatives> <class>com.acme.MockSapService</class> </alternatives></beans>

1

Stereotypes

Stereotypesarealiasforannotations

AnhelptoavoidannotationsHell

Anotherwaytoenablealterntives

Stereotypes

wehavealotofbeanwith @Conversation and @Named

wecancreateastereotypegatheringboth

@Stereotype @Named @ConversationScoped @Retention(RetentionPolicy.RUNTIME)@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})@Documentedpublic @interface Wizard {}

WearedelcaringaStereotype

Alltheannotationswewanttoputinthestereotype

12

2

1

2

UsingStereotypes

Wecanusethestereotypebyreplacing

@Named @ConversationScopedpublic class ConferenceBean implements Serializable {...}

by…

@Wizardpublic class ConferenceBean implements Serializable {...}

Moredecouplingwith

Events

Eventsinactionpublic class FirstBean {

@Inject Event<Post> postEvent;

public void saveNewPost(Post myPost) {

postEvent.fire(myPost); }}

public class SecondBean {

public void listenPost(@Observes Post post) { System.out.println("Received : " + evt.message()); }}

Event<T> isinjectedatthefiringside. T istheeventpayloadtype(heremy Post class)

Whenneeded,wefiretheeventwithourinstanceof T (herethe Post objecttosave)

Attheconsumingside,wedefineanobserverforagivenpayloadtypewith @Observes annotation.Ifobservedtypematchfiredeventtype,theobserveriscalled.

1

2

3

1

2

3

Observerresolutionmimicstypesaferesolution(inalooserway)public class FirstBean { @Inject Event<Post> postEvent;

public void saveNewPost(Post myPost) { postEvent.select(new AnnotationLiteral()<French> {}).fire(myPost); }}

public class SecondBean { public void listenFrPost(@Observes @French Post post) {} public void listenPost(@Observes Post post) {} public void listenObject(@Observes Object obj) {} public void listenEnPost(@Observes @English Post post) {} }

Theseobserverswillbetriggered(emptysubsetisacceptedforqualifierswhenresolvingobservers)

Thisobserverwon’tbetriggered

11

12

1

2

Hookingoncontextlifecyclewitheventspublic class SecondBean { public void beginRequest(@Observes @Initialized(RequestScoped.class) ServletRequest req) {}

public void endRequest(@Observes @Destroyed(RequestScoped.class) ServletRequest req) {}

public void beginSession(@Observes @Initialized(SessionScoped.class) HttpSession session) {}

public void endSession(@Observes @Destroyed(SessionScoped.class) HttpSession session) {}

public void beginApplication(@Observes @Initialized(ApplicationScoped.class) ServlerContext ctx) {}

public void endApplication(@Observes @Destroyed(ApplicationScoped.class) ServlerContext ctx) {}}

Observermustbedefinedinabean

Observerresolutionmaytriggerbeaninstancecreation.

Soobserversaboveareanicewaytoinitailizebeanwithitscontext

Backtodemo BankingService istheobserver

ReimburseService firestheevent

Theeventistypedto Reimbursement

IntroducingCDIPortableExtensions

Portableextensions

OneofthemostpowerfulfeatureoftheCDIspecification

Notreallypopularized,partlydueto:

1. Theirhighlevelofabstraction2. ThegoodknowledgeonBasicCDIandSPI3. Lackofinformation(CDIisoftenreducedtoabasicDIsolution)

Extensions,whatfor?

Tointegrate3rdpartylibraries,frameworksorlegacycomponents

Tochangeexistingconfigurationorbehavior

ToextendCDIandJavaEE

Thankstothem,JavaEEcanevolvebetweenmajorreleases

Extensions,how?

ObservingSPIeventsatboottimerelatedtothebeanmanagerlifecycle

Checkingwhatmeta-dataarebeingcreated

Modifyingthesemeta-dataorcreatingnewones

Moreconcretely

Serviceprovideroftheservicejavax.enterprise.inject.spi.Extension declaredinMETA-INF/services

Justputthefullyqualifiednameofyourextensionclassinthisfile

import javax.enterprise.event.Observes;import javax.enterprise.inject.spi.Extension;

public class CdiExtension implements Extension {

void beforeBeanDiscovery(@Observes BeforeBeanDiscovery bbd) { } //...

void afterDeploymentValidation(@Observes AfterDeploymentValidation adv) { }}

Internal Step Happen Once Loop on Elements

Beanmanagerlifecycle

DeploymentStart

BeforeBean

DiscoveryScan

Archive

ProcessAnnotated

Type

AfterType

Discovery

BeanEligibility

Check

ProcessInjection

Point

ProcessInjectionTarget

ProcessBean

Attributes

ProcessBean

ProcessProducer

ProcessObserverMethod

AfterBean

Discovery

AfterDeploymentValidation

ApplicationRunning

BeforeShutdown

UndeployApplication

Example:IgnoringJPAentities

ThefollowingextensionpreventsCDItomanageentities

Thisisacommonlyadmittedgoodpractice

public class VetoEntity implements Extension {

void vetoEntity(@Observes @WithAnnotations(Entity.class) ProcessAnnotatedType<?> pat) { pat.veto(); }}

ExtensionsarelaunchedduringbootstrapandarebasedonCDIevents

Oncetheapplicationisbootstrapped,theBeanManagerisinread-onlymode(noruntimebeanregistration)

Youonlyhaveto@Observes built-inCDIeventstocreateyourextensions

Remember

UnderstandingSPItobuildCDIextensions

SPIcanbesplitin4parts

SPIcanbesplitin4parts

Typemeta-model

SPIcanbesplitin4parts

CDImeta-model

SPIcanbesplitin4parts

CDIentrypoints

SPIcanbesplitin4parts

SPIdedicatedtoextensions

Whyhavingatypemeta-model?

Because @Annotations areconfiguration

buttheyarealsoread-only

Sotoconfigureweneedamutablemeta-model…

…forannotatedtypes

SPIfortypemeta-model

Annotated

Type getBaseType()Set<Type> getTypeClosure()<T extends Annotation> getAnnotation(Class<T>)Set<Annotation> getAnnotations()boolean isAnnotationPresent(Class<? extends Annotation>)

AnnotatedMemberX

Member getJavaMember()boolean isStatic()AnnotatedType<X> getDeclaringType()

AnnotatedParameterX

int getPosition()AnnotatedCallable<X> getDeclaringCallable()

AnnotatedTypeX

Class<X> getJavaClass()Set<AnnotatedConstructor<X>> getConstructors()Set<AnnotatedMethod<? super X>> getMethods()Set<AnnotatedField<? super X>> getFields()

AnnotatedCallableX

List<AnnotatedParameter<X>> getParameters()

AnnotatedFieldX

Field getJavaMember()

AnnotatedConstructorX

Constructor<X> getJavaMember()

AnnotatedMethodX

Method getJavaMember()

SPIdedicatedtoCDImeta-model

BeanAttributesT

Set<Type> getTypes()Set<Annotation> getQualifiers()Class<? extends Annotation> getScope()String getName()Set<Class<? extends Annotation>> getStereotypes()boolean isAlternative()

BeanT

Class<?> getBeanClass()Set<InjectionPoint> getInjectionPoints()boolean isNullable()

InterceptorT

Set<Annotation> getInterceptorBindings()boolean intercepts(InterceptionType type)Object intercept(InterceptionType, T, InvocationContext)

DecoratorT

Type getDelegateType()Set<Annotation> getDelegateQualifiers()Set<Type> getDecoratedTypes()

ProducerT

T produce(CreationalContext<T>)void dispose(T)Set<InjectionPoint> getInjectionPoints()

InjectionTargetT

void inject(T, CreationalContext<T>)void postConstruct(T)void preDestroy(T)

InjectionPoint

Type getType()Set<Annotation> getQualifiers()Bean<?> getBean()Member getMember()Annotated getAnnotated()boolean isDelegate()boolean isTransient()

ObserverMethodT

Class<?> getBeanClass()Type getObservedType()Set<Annotation> getObservedQualifiers()Reception getReception()TransactionPhase getTransactionPhase()void notify(T)

EventMetadata

Set<Annotation> getQualifiers()InjectionPoint getInjectionPoint()Type getType()

SPIprovidingCDIentrypoints

IterableT

Iterator<T> iterator()void forEach()Spliterator<T> spliterator()

InstanceT

T get()Instance<T> select()Instance<T> select();boolean isUnsatisfied()boolean isAmbiguous()void destroy()

CDIT

Set<CDIProvider> discoveredProvidersCDIProvider configuredProvider

CDI<Object> current()void setCDIProvider(CDIProvider provider)BeanManager getBeanManager()

BeanManager

Object getReference(Bean<?>, Type, CreationalContext<?> )Object getInjectableReference(InjectionPoint, CreationalContext<?> )Set<Bean<?>> getBeans(Type, Annotation[])Bean<? extends X> resolve(Set<Bean<? extends X>>)void validate(InjectionPoint)void fireEvent(Object, Annotation[])

boolean isQualifier(Class<? extends Annotation>)boolean isStereotype(Class<? extends Annotation>)boolean areQualifiersEquivalent(Annotation, Annotation)boolean areInterceptorBindingsEquivalent(Annotation, Annotation)Context getContext(Class<? extends Annotation>)ELResolver getELResolver()ExpressionFactory wrapExpressionFactory(ExpressionFactory)AnnotatedType<T> createAnnotatedType(Class<T>)InjectionTarget<T> createInjectionTarget(AnnotatedType<T>)InjectionTargetFactory<T> getInjectionTargetFactory(AnnotatedType<T>)BeanAttributes<T> createBeanAttributes(AnnotatedType<T>)Bean<T> createBean(BeanAttributes<T>, Class<X>, ProducerFactory<X>)InjectionPoint createInjectionPoint(AnnotatedField<?>)

some methods skipped

UnmanagedT

Unmanaged(BeanManager, Class<T>)Unmanaged(Class<T>)UnmanagedInstance<T> newInstance()

UnmanagedInstanceT

T get()UnmanagedInstance<T> produce()UnmanagedInstance<T> inject()UnmanagedInstance<T> postConstruct()UnmanagedInstance<T> preDestroy()UnmanagedInstance<T> dispose()

provides

SPIdedicatedtoextensions

BeforeBeanDiscovery

addQualifier(Class<? extends Annotation>)addScope(Class<? extends Annotation>, boolean, boolean)addStereotype(Class<? extends Annotation>, Annotation[])addInterceptorBinding(Class<? extends Annotation>, Annotation[])addAnnotatedType(AnnotatedType<?>)

AfterTypeDiscovery

List<Class<?>> getAlternatives()List<Class<?>> getInterceptors()List<Class<?>> getDecorators()addAnnotatedType(AnnotatedType<?>, String)

AfterDeploymentValidation BeforeShutdown

AfterBeanDiscovery

addBean(Bean<?>)addObserverMethod(ObserverMethod<?>)addContext(Context)AnnotatedType<T> getAnnotatedType(Class<T>, String)Iterable<AnnotatedType<T>> getAnnotatedTypes(Class<T>)

ProcessAnnotatedTypeX

AnnotatedType<X> getAnnotatedType()void setAnnotatedType(AnnotatedType<X>)veto()

ProcessBeanX

Annotated getAnnotated()Bean<X> getBean()

ProcessBeanAttributesT

Annotated getAnnotated()BeanAttributes<T> getBeanAttributes()setBeanAttributes(BeanAttributes<T>)veto()

ProcessInjectionPointT, X

InjectionPoint getInjectionPoint()setInjectionPoint(InjectionPoint)

ProcessInjectionTargetX

AnnotatedType<X> getAnnotatedType()InjectionTarget<X> getInjectionTarget()setInjectionTarget(InjectionTarget<X>)

ProcessObserverMethodT, X

AnnotatedMethod<X> getAnnotatedMethod()ObserverMethod<T> getObserverMethod()

ProcessProducerT, X

AnnotatedMember<T> getAnnotatedMember()Producer<X> getProducer()setProducer(Producer<X>)

AlltheseSPIinterfacesareeventscontainingmeta-modelSPI

TheseeventsfiredatboottimecanonlybeobservedinCDIextensions

Forinstance:

A ProcessAnnotatedType<T> eventisfiredforeachtypebeingdiscoveredatboottime

Observing ProcessAnnotatedType<Foo>allowsyoutoprevent Foo tobedeployedasabeanbycallingProcessAnnotatedType#veto()

WegotthisJavadoc: Backtodemo

Backtodemo Wedon’thavethecodeofthe BillingService

Createa BillingServiceExtension whichcallsBillingService

Usingobservers BillingServiceObserver

Extensionhastobeenabled

CDI2.0

AboutCDI2.0

WorkisinprogressonCDI2.0

Comeseethesession"CDI2.0iscoming"thursday2pmroom8

Oneofthenewfeaturesistheasynchronousevents

Thegoodnewsis:"youcantestittoday"

Asynchronouseventexamplepublic class FirstBean { @Inject Event<Post> postEvent;

public void saveNewPost(Post myPost) {

postEvent.fireAsync(myPost); }}

public class SecondBean {

public void listenPost(@ObservesAsync Post post) { System.out.println("Received : " + evt.message()); }}

Weintroduceda fireAsync() method

Forbackwardcompatibilitywehadtoaddan @ObservesAsync observer

1

2

1

2

Let’stestasynchronousevent

Weld3Alpha(previewofCDI2.0RI)isavailable

WildFlyincludesapatchmechanismtoupgradeimplementations

WecanpatchWildFlywithasimplecommand

./jboss-cli.sh --command="patch apply ~/wildfly-10.0.0.CR4-weld-3.0.0.Alpha13-patch.zip"

Backtodemo

Let’saddasynchronousevent

Conclusion

References

CDISpecification-cdi-spec.org

Code&slidesrepository-github.com/antoinesd/cdi-forge-uni

SlidesgeneratedwithAsciidoctor,PlantUMLandDZSlidesbackend

Originalslidetemplate-DanAllen&SarahWhite

AntoineSabot-DurandAntonioGoncalves@antoine_sd@agoncal