Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Going Further with CDI 1.2


Published on

This presentation introduces the advanced features of CDI (Contexts and Dependency Injection). It was authored by Antoine Sabot-Durand, the co-spec lead for CDI.

In less than five years of existence, Contexts and Dependency Injection (CDI) has become one of the major specifications in Java EE. However, its advanced features are still not well known among the majority of the developers, who see it as a simple Dependency Injection solution. In this session, we’ll deep dive into advanced features like the CDI SPI and portable extensions. Then we'll view some examples of how CDI can be used to extend, in a portable way, the Java EE stack.

Published in: Technology
  • Be the first to comment

Going Further with CDI 1.2

  1. 1. Going further with CD1 1.2 Antoine Sabot-Durand - Antonin Stefanutti
  2. 2. Antoine Sabot-Durand E Senior Software Engineer 3 CD1 co—spec lead, Java EE 8 EG E Red Hat, Inc. Y @antoine_sd a www. next—presso. com O github. com/ antoinesd
  3. 3. Agenda 0 Meet CDI SP1 0 Introducing CDI Extensions 9 Slides available at
  4. 4. CPI can ‘Be 313:‘; -fit; in parts
  5. 5. CPI can be spm: 55.1. 41- parts ‘F .1 Type meta—model
  6. 6. SPI can be split in 4 parts 0 CD1 meta—model
  7. 7. CPI can ' e spm: film. 4 parts ‘I’ 4. CD1 entry points
  8. 8. SPI can be split in 4 parts 0 SP1 dedicated to extensions
  9. 9. Why Having a Type Meta-Model? 9 Because @Annotations are configuration (7 but they are also read-only 97 So to configure we need a mutable meta—model. .. 9 . . . for annotated types
  10. 10. P (D Annotatedconstructar '1 0 C onstructomx) 5etJavr1ember() I’ A AnnotatedI. ’aLL¢tLe 0 Llstmnnat atedParameter<x » getvarameter s() SP1 for Type meta-model 0 Type getEaseType() o Set<I’ype> getYype(1osure() o <1 extends Annatatiom getAnnutatim(c1ass<T>) o Set<Annatat1an> geunnotati ons () o hoolean isAn notationwesent (C1ass<P extend s Annotatiom) ® Annotatenflype I’ A AnnatatedParmneter 0 int getPusition() o Annotatedca1lah1e<x> getneclar1ngcal1able() o Class<x> getJavaC1ass() O Seturlnatitedcon structor<X>> getConstructors() o Set<AnnotatedMethod<? super X» getHe: hods() o Set(AnnutatedFie1d<? super )0) getFie1ds() 0 Member geIJavaHemher() VD boolean 1sStau: () Q AnnotatedType<x> getDeclar1ngType() E ®Amo: n«ruLa 0 F1 eld getlavafllemb er() 5 ®AnnotutedWethod 0 Method getJavaMe«ber()
  11. 11. SPI Dedicated to CD1 Meta-Model o Yype getType() ieeaiaunm : $:: :‘; ::. ::: ::: :$; ::: §’ : :;Il': ::. ::: ::°; ::, ’Wl. ,.(, > . . . : : :': "_’l§: |:: ::9) o Setdnnatztnon) get0bsenredQua11fiers() Classd extends Annatatxam getScme() O Mnouud n‘motned0 0 Reception getReception() String getName() 5 o ‘I’rans: ¢t1onPhase getTransacuonPhase() Seuclasst? extends Annotation» getstereotypeso : o void notiFy(T) bonlean isA1ternative() o T produce(Creat1ona1(ontext<T>) a void dispase(T) o Set<1njectlonPo: lnt> getInjectionPo: lnts() 0 Setcknnotation) getQua11fiers() o C1ass(? ) getBeanClass() n Injectiorwolnt get! njectionPolnt() o Set<1njectlonPoint> get! njectionPoints() 0 Type getType() a boolean £sIu1lab1e() c void 1nject(T, Cr'eat1ona1Context<T>) a void posttonstruct(T) a void preDestmy(Y) o Set<Annotation> getlntercepturaindingso g boolean Intercepts(Intertept1onType type) an Object : lnter<ept(InterceptlonType, 1’, lnvocitiontontext) 0 Type getDelegateType() o Set<Mnotation> getDe1eaateQua11f1ers() o Set<Type> getDecoratedTypes()
  12. 12. This SPI can be used in your code 1 9 Inj ectionPoi nt can be used to get info about what’s being injected @Qua1ifier @Retention(RUNTIME) @Target({TYPE, METHOD, FIELD, PARAMETER}) public @interface HttpParam { @Nonbinding public String value() } ébroduces @HttpParam("") String getParamVa1ue(InjectionPoint ip, HttpServ1etRequest req) { return req. getParameter(ip. getAnnotated(). getAnnotation(HttpParam. class). value()) } @HttpParam("productId") @Inject String productld
  13. 13. This SPI can be used in your code 2 9 Inj ectionPoint contains info about requested type at @Inject public class MyMapProducer() { @Produces public <K, V> Map<K, V> produceMap(InjectionPoint ip) { if (va1ueIsNumber(((ParameterizedType)ip. getType()))) return new TreeMap<K, V>() return new HashMap<K, V>() } private boolean valueIsNumber(ParameterizedType t) { Class<? > valueclass = (Class<? >) t. getActualTypeArguments()[1] return Number. class. isAssignableFrom(valueClass)
  14. 14. This SPI can be used in your code 3 9 An abstract superclass can use meta to provide generic resolution public ‘ class Abstractservice { / /resoLver' with same quaLifiers than the Current bean private Resolver resolver; — / /@Inject can be used on an initiaLizer method void initkesolver(2<AbstractService> meta, — _<ReS01Ver‘> r‘eS01Vef‘S) { Annotation[] beanQua1i-Fiers = (Annotation[]) meta. getQua1i-Fiers(). toArray() resolver = resolvers. select(beanQualifiers). get() } public Resolver getResolver() { return resolver } }
  15. 15. This SPI can be used in your code 4 9 Eve ntMetadata contains type and qualifier info about the event @ApplicationScoped public class Myservice { private void strictListen(@0bserves @Qua1ified Payload evt, EventMetadata meta) { if(meta. getQualifiers(). contains(new QualifiedLitera1()) && meta. getType(). equals(Payload. class)) System. out. println("Do something") else System. out. print1n("ignore")
  16. 16. SPI providing CDI Entry points fr Object getReference(Bean<? >, Type, Cveat: lonalContext<? > ) Object getlnjectab1eReference(InjectionPoint, Creaticna1CaItext<? > ) " Set<Bean<? >> getBea1s(Type, i9nnotation[]) ~ Beam? extends X) resolve(Set<Bea1<? extends X») : : void va11date(Inject1onPo1nt) ' void fin-eEvent(Object, Annotation[]) » >sane methods sk1ped~ CD1'Provider , boolean 1sQua11f1er(class<? extends Annotat: lon>) boolean isStereotype(C1ass<? extends Annotation>) , boolean ar ualifiersi uivalalt annotation Annotation : ; boolean arzgnterceptorgindingfiéuivalent(Ainatatlon, Ar)Inotatian) Context getCormext(C1ass<? extends Annutatlnm) K, Eulesolver getELReso1ver() ExpresslonFactory irapExpress1onFactory(Exp: -ess1onFactor'y) r AnnotatedType<T) creatmnnotatedType(C1ass<T>) . : Inject1onTarget<T> createInject: lanTarget(AmotatedType<T>) ‘ InjectionTargetFat! :ury<T> getlnjectionhrgetFactory(AnnatatedType<T>) . , BeanAttributes<T> createBeanAttributes(AnnotatedType<T>) Bean<T> createBean(BeanAttr1butes<T>, C1ass<X>, ProducerFactory<x>) '; Inject1onPo1nt createInject1a1Po: lnt(MnotatedF: le1d<? >) Unmanaged E : UnInanaged(BeanFanapr, Class<T>) A. Unmanaged(class<T>) 4:: UnmanagedInstance<T> newInstance() Unmanaged Instance E 0 T 8610 Cl UnmanagedInstance<T> produce() ii um| anagedInsta1ce<T> 1nject() I) Set<CDIProv: lder> discoverewrcvlders Q CDIPravider configur-edProvi. der (‘ CDI<0hject> current() void seI£DIPrvvider(CDlPrvvider provider) «. / Bearflanager get-BeanMnnager() i: i unmanagedInstan: e<T> postconstruzt () U1 UnuanagedInstau: e<T> pr-eDestruy() . _-i unmanagedInsta1ce<T> d1spose()
  17. 17. SPI Dedicated to Extensions . Beforeseanaiscavery O ‘flerwwtscwery : m:: ::: ::; :1:*: ::. ::: ':: :.: m:t°a:1.n. .. ...1.. |ztAlternat1ves() Omeww-e»= wu«»rw» T Q eddSterectype(c]ass<? extends Mnoutlon >, Annotatl. on[ ) : w$: ::: :E;0 T Q a1h1rm| rceptnrIindir§(Cla ss<? amends Annataunm Annotation[]) . “d‘nm“teflypl(MmtnlflyP“b) ' Q addAnnotated‘rype(AnnotatedType<? >, String) 0 After-Beanotseavery 0 addlea n(Bem<? >) addDbserverMetrod(¢: sewemeuod(? >) Iddculhextfloncext) Q Annotab: dType<T> | etAnnotztedl’ype(Class('I’>, String) 0 Iteri: le<ArImtItedType<T» | etAnrm: ItedTyp(Cl. Iss<T>) O Processaeanatcributes E Q Anmtated ¢tAmutIted() 0 lelIAttril: utes¢T> gtIeanAttributes() Q setBeanAttr1butes(BeaMttr1butes<T>) 0 vetn() I’ . Pracessflnnotatedlype A o IamotatedType<x> [etMnotnedType() o V| Ig(; etllIlIflbl bedType(Annuuted1ype<x>) 0 V: E O PFOCQSSHEUH Q Annotated utAmvtIted() 0 Nil (X) $238300 E O ProcessProdue-er Q Annotatednewev-<‘I’> getAnnotatedHed>er() 0 PI-d0.Icer(X> | etProducer() F’ . Process1nJectl. onTarpet A Q Nwmatedfypecl) petlnnotatedType() o Injectionm-| et<x> gtlruectlunm-| et() O Processohserverwthod . Anmtltedlbthoddb geunnot ntea1ethod() Q 0bserverIEthnd(T> [et! lzserverlhtlIu¢l() T O Frocessmjectionrotnt Q Irljectiovwuint ¢etInjectiunPnint() Q setlnjectinnPnint(! nject. imPniIIt) 0 setInje: tlmTaroet(In1 ect 1onTar| et<x>) e setrroducen-(llmm oer<x>)
  18. 18. All these SPI interaces are events containing meta-model SP1 3 These events fired at boot time can only be observed in a CD1 “ extension 7 4 For instance: / / / ‘i Zil”S:2f!75Zff. ,s0 dConsuucC1|u: :): :: A Proc es sAn notat edTy pe<T> event is ’ V T ~ . . Q triggered for each type discovered at boot time Observing ProcessAnnotatedType<Foo> 9 allow you to prevent Foo to become a h bean by calling ProcessAnnotatedType#veto()
  19. 19. Introducing CD1 Portable Extensions
  20. 20. P4 (nil 9°! ‘-’! " Portable Extensions One of the most powerful feature of the CDI specification Not really popularized, partly due to: Their high level of abstraction The good knowledge on Basic CD1 and SP1 Lack of information (CDI is often reduced to a basic DI solution)
  21. 21. Extensions What for? 9 To integrate 3rd party libraries, frameworks or legacy components 9 To change exisiting configuration or behavior 9 To extend CD1 and Java EE 9 thanks to them, Java EE can evolve between major release
  22. 22. Extensions How? (9 Observing SPI Events at boot time according l to BeanManger Lifecycle 9 Checking what meta-data are being created 9 Modifying these meta-data or creating new i ones
  23. 23. More concretely Service provider of the service 3, javax. enterprise. inject . spi. Extension declared in META-INF/ services 9 Just put the fully qualified name of your extension class in this file irrport javax. enterprise. event.0bserves; irrport javax. enterprise . inject . spi. Extension; class CdiExtension implements Extension { void beforeaeanbiscovery(@Observes BeforeBeanDiscovery bbd) { } void afterDeploymentValidat: l.on(@Dbserves AfterDeploymentValidation adv) { } }
  24. 24. Bean Manager Lifecycle Before Process After De lo ment Scan . > pstayrt ‘ Bean Annotated ' Type Discovery Type Discovery Process Process Process Bean Bean Injection Injection Eligibility Attributes Target Point Check Process Process Bean Producer C: Undeploy Before Application After Bean Discovery Process Observer Method After Deployment Validation Internal Step H. .-, .. . i
  25. 25. Example: Ignoring IPA Entities 0 The following extension prevents CDI to manage entities E This is a commonly admitted good practice public class VetoEntity implements Extension { void noEntity(@0bserves @withAnnotations(Entity. class) ProcessAnnotatedType<? > p) { p. veto(); } }
  26. 26. Example: Register a Bean from an annotation 1/4 9 To integrate MongoDB with CD1 we want to provide a way to write this: @MongoClientDefinition(name = "myMongo", url = "mongodb: //localhost") public class Anyclass { } <7 and have the corresponding Mongoclient produced so we can inject it: public class Myservice { @Inject Mongoclient myclient; } 9 In the same spirit than @DataSourceDefinition
  27. 27. Example: Register a Bean from an annotation 2/4 9 Rather standard annotation code: @Target(value = {TYPE}) @Retention(value = RUNTIME) @Documented public @interface MongoClientDefinition { String name(); String description() default ""; String ur1() default ""; }
  28. 28. Example: Register a Bean from an annotation 3/4 public class MongoExtension implements Extension { private Mongoclientoefinition mongoDef = null; void detectnongaclientnefinition( @observes @withAnnotations(nongoclientoefinition. class) ProcessAnnotatedType<? > pat) { AnnotatedType at = pat. getAnnotatedType(); mongooef = at. getAnnotation(MongoC1ientDefin1tion. c1ass); } void registerbatasourceaeans(@0bserves AfterBeanDiscovery abd, BeanManager bm) { MongoClientURI uri = new MongoClientURI(mongoDef. url()); abd. addBean(bm. createBean(new MongoclientBeanAttributes(bm. createBeanAttributes(bm. createAnnotatedType (MongoClient. class))), MongoClient. class, new MongoclientProducerFactory(uri))); } private static class Mongoclientneankttributes implements BeanAttr1butes<MongpClient> { private BeanAttr1butes<MongoC1ient> delegate; MongoclientBeanAttributes(BeanAttributes<MongoC1ient> beanAttributes) { delegate = beanAttributes; } public Class<? extends Annotation> getScope() { return App1icationScoped. class; } / /shiping delegating methods }
  29. 29. Example: Register a Bean from an annotation 4/4 private static class MongoC1:l. entProducerFactory implements Inject: l.onTargetFactory<Hong>C1:lent> { MongoC1:'LentURI uri; Mongocl1entProducerFactory(MongoC11entURI uri) { th: ls. uri = uri; } public InjectionTarget<MongoC1ient> createInjec1:: lonTarge1:(Bean<MongoC1ient> bean) { return new InjectionTarget<MongoC1ient>() { public Mongoclient produce(Creationa1Context<MongoC1ient> ctx) { try { return new MongoC1:l. ent(uri); } catch (UnknownHostException e) { throw new I11ega1ArgumentExcept: l.nn(e); } } public void d: lspose(MongoC1ient instance) { instance. c1ose(), ' } / / skipping empty methods }; } }
  30. 30. y Extensions are launched during 1 R9,, ’ bootstrap and are based on CD1 events 911259 . 54:‘ Once the application is bootstrapped, the Bean Manager is in read-only mode (no runti1ne bean registration) You only have to @obser-ves bui1i—in CD1 events to create your extensions
  31. 31. Conclusion
  32. 32. Questions @antoine_sd @cdi—spec