Warum ich so auf das c von cdi stehe

Post on 12-Feb-2017

157 views 0 download

Transcript of Warum ich so auf das c von cdi stehe

Warum CDI odergibt es einen tieferen Sinn dahinter?

warum denn CDI ? ;-)

@SvenRuppert 4/122

Warum CDI odergibt es einen tieferen Sinn dahinter?

oft gehörte Antwort

kürzere Notation.. *oje*

Manchmal ist die Notation per Inject kürzer. Sobald allerdings die einzelnenQualifier dazukommen, ist meist der Aufwand zum Aufruf eines Konstruktorskaum unterschiedlich.

Verkürzen der Notation ist natürlich nicht das Ziel von CDI

@SvenRuppert 5/122

Warum CDI odergibt es einen tieferen Sinn dahinter?

lösen/entfernen von statischen Abhängigkeiten

@SvenRuppert 6/122

Warum CDI odergibt es einen tieferen Sinn dahinter?

lösen/entfernen von statischen Abhängigkeiten

Dieser Punkt ist einer der wesentlichen.

Also: Wie kann man zur Entwicklungszeit die Abhängigkeiten zu den anderenProjektmodulen möglichst gering halten?

@SvenRuppert 7/122

Warum CDI odergibt es einen tieferen Sinn dahinter?

lösen/entfernen von statischen Abhängigkeiten

Dieser Punkt ist einer der wesentlichen.

Also: Wie kann man zur Entwicklungszeit die Abhängigkeiten zu den anderenProjektmodulen möglichst gering halten?

Gehen wir von der Definition einer Liste aus. Als Rückgabewert einer Methodewird eine Instanz der Implementierung von List verwendet.

public List<Data> execute(){ ... }; JAVA

@SvenRuppert 8/122

Warum CDI odergibt es einen tieferen Sinn dahinter?

Damit sind nachfolgende Aufrufer nicht mehr an die Implementierung der Listgebunden.

import java.util.List;import java.util.ArrayList;

public List<Data> execute(){ final List<Data> result = new ArrayList<>(); //.... return result;}

JAVA

@SvenRuppert 9/122

Warum CDI odergibt es einen tieferen Sinn dahinter?

Damit sind nachfolgende Aufrufer nicht mehr an die Implementierung der Listgebunden.

In der Methode jedoch besteht meist die Abhängigkeit zu der entsprechendenImplementierung obwohl auch das meist nicht notwendig ist.

import java.util.List;import java.util.ArrayList;

public List<Data> execute(){ final List<Data> result = new ArrayList<>(); //.... return result;}

JAVA

@SvenRuppert 10/122

Warum CDI odergibt es einen tieferen Sinn dahinter?

Gehen wir davon aus, dass keine spezifischen Methoden der ArrayListverwendet werden. Selten werden Methoden wie z.B. trimToSize() verwendet.

@SvenRuppert 11/122

Warum CDI odergibt es einen tieferen Sinn dahinter?

Gehen wir davon aus, dass keine spezifischen Methoden der ArrayListverwendet werden. Selten werden Methoden wie z.B. trimToSize() verwendet.

Somit ist die statische Abhängigkeit zu der ArrayList nicht notwendig.

@SvenRuppert 12/122

Warum CDI odergibt es einen tieferen Sinn dahinter?

Gehen wir davon aus, dass keine spezifischen Methoden der ArrayListverwendet werden. Selten werden Methoden wie z.B. trimToSize() verwendet.

Somit ist die statische Abhängigkeit zu der ArrayList nicht notwendig.

Sollte sich zur Laufzeit herausstellen, das die Wahl dieser Implementierung nichtoptimal gewesen ist, muss der Quelltext angepasst und neu verteilt werden.

@SvenRuppert 13/122

Warum CDI odergibt es einen tieferen Sinn dahinter?

Gehen wir davon aus, dass keine spezifischen Methoden der ArrayListverwendet werden. Selten werden Methoden wie z.B. trimToSize() verwendet.

Somit ist die statische Abhängigkeit zu der ArrayList nicht notwendig.

Sollte sich zur Laufzeit herausstellen, das die Wahl dieser Implementierung nichtoptimal gewesen ist, muss der Quelltext angepasst und neu verteilt werden.

z.B. Mit std SE Mitteln kann man das durch entsprechende Factories lösen.

@SvenRuppert 14/122

Warum CDI odergibt es einen tieferen Sinn dahinter?

Mit std SE Mitteln kann man das durch entsprechende Factories lösen.

Beispielhaft soll hier folgende Implementierung verwendet werden.

import java.util.ArrayList;import java.util.LinkedList;import java.util.List;

public class ListFactory { public List createArrayList() { return new ArrayList(); } public List createLinkedList() { return new LinkedList(); } public List createList() { return new ArrayList(); }}

JAVA

@SvenRuppert 15/122

Warum CDI odergibt es einen tieferen Sinn dahinter?

Haben wir damit etwas erreicht?

@SvenRuppert 16/122

Warum CDI odergibt es einen tieferen Sinn dahinter?

Haben wir damit etwas erreicht?

... bzw was haben wir damit erreicht?

@SvenRuppert 17/122

Warum CDI odergibt es einen tieferen Sinn dahinter?

Haben wir damit etwas erreicht?

... bzw was haben wir damit erreicht?

z.B. Die Entwickler verwenden nun diese Factory.

@SvenRuppert 18/122

Warum CDI odergibt es einen tieferen Sinn dahinter?

Haben wir damit etwas erreicht?

... bzw was haben wir damit erreicht?

z.B. Die Entwickler verwenden nun diese Factory. -> wenn sie wissen das es diesegibt! ;-)

@SvenRuppert 19/122

Warum CDI odergibt es einen tieferen Sinn dahinter?Vorher / Nachher (1/2)

import java.util.List;import java.util.ArrayList;public List<Data> execute(){ final List<Data> result = new ArrayList<>(); //.... return result;}

JAVA

@SvenRuppert 20/122

Warum CDI odergibt es einen tieferen Sinn dahinter?Vorher / Nachher (2/2)

import java.util.List;import java.util.ArrayList;public List<Data> execute(){ final List<Data> result = new ArrayList<>(); //.... return result;}import java.util.List;import org.rapidpm.demo.ListFactory;public List<Data> execute(){ final List list = new ListFactory().createArrayList(); //.... return result;}

JAVA

@SvenRuppert 21/122

Warum CDI odergibt es einen tieferen Sinn dahinter?

Bisher wurde nun die statische Abhängigkeit zur ArrayList verhindert.

@SvenRuppert 22/122

Warum CDI odergibt es einen tieferen Sinn dahinter?

Bisher wurde nun die statische Abhängigkeit zur ArrayList verhindert.

Die Entscheidung eine ArrayList zu nehmen ist jedoch immer noch explizitgefallen.

@SvenRuppert 23/122

Warum CDI odergibt es einen tieferen Sinn dahinter?

Bisher wurde nun die statische Abhängigkeit zur ArrayList verhindert.

Die Entscheidung eine ArrayList zu nehmen ist jedoch immer noch explizitgefallen.

Die Abhängigkeit zur Factory wurde hinzugefügt.

@SvenRuppert 24/122

Warum CDI odergibt es einen tieferen Sinn dahinter?

Bisher wurde nun die statische Abhängigkeit zur ArrayList verhindert.

Die Entscheidung eine ArrayList zu nehmen ist jedoch immer noch explizitgefallen.

Die Abhängigkeit zur Factory wurde hinzugefügt.

Die Implementierung der ListFactory selber hat auch wieder die statischenAbhängigkeiten zu allen vorgesehenen Implementierungen.

@SvenRuppert 25/122

Warum CDI odergibt es einen tieferen Sinn dahinter?

Anforderung Nr 1: keine statischen Abhängigkeiten zu spezifischenImplementierungen

@SvenRuppert 26/122

Warum CDI odergibt es einen tieferen Sinn dahinter?

Anforderung Nr 1: keine statischen Abhängigkeiten zu spezifischenImplementierungen

Anforderung Nr 2: keine statischen Entscheidungen für spezifischeImplementierungen

@SvenRuppert 27/122

Warum CDI odergibt es einen tieferen Sinn dahinter?

Anforderung Nr 1: keine statischen Abhängigkeiten zu spezifischenImplementierungen

Anforderung Nr 2: keine statischen Entscheidungen für spezifischeImplementierungen

Was ist jetzt eine mögliche Lösung ???

@SvenRuppert 28/122

Lösungsversuch Nr 1basierend auf Java SE

Eine etwas dynamischere Lösung...

@SvenRuppert 29/122

Lösungsversuch Nr 1basierend auf Java SE

Eine etwas dynamischere Lösung...

import java.util.ArrayList;import java.util.LinkedList;import java.util.List;import org.rapidpm.demo.cdi.commons.registry.ContextResolver;

public class ListFactory { public List createList(final ContextResolver contextResolver){ if(contextResolver == null){ return createArrayList(); } else { if(contextResolver.resolveContext()){ return createArrayList(); } else{ return createLinkedList(); } } }}

JAVA

@SvenRuppert 30/122

Lösungsversuch Nr 1basierend auf Java SE

Eine etwas dynamischere Lösung...

Die Komplexität der Entscheidung liegt nun im ContextResolver

@SvenRuppert 31/122

Lösungsversuch Nr 1basierend auf Java SE

Eine etwas dynamischere Lösung...

Die Komplexität der Entscheidung liegt nun im ContextResolver

Abhängigkeit in der Factory zum ContextResolver hinzugefügt

@SvenRuppert 32/122

Lösungsversuch Nr 1basierend auf Java SE

Eine etwas dynamischere Lösung...

Die Komplexität der Entscheidung liegt nun im ContextResolver

Abhängigkeit in der Factory zum ContextResolver hinzugefügt

Gewonnen: zur Laufzeit sich für eine Implementierung entscheiden.

@SvenRuppert 33/122

Lösungsversuch Nr 1basierend auf Java SE

Möchte man nun die Factory so erstellen, dass diese wiederum keine statischenAbhängigkeiten zu den jeweiligen Contexten bzw Implementierungen der Listehat, muss eine z.B. Registry gebaut werden.

@SvenRuppert 34/122

Lösungsversuch Nr 1basierend auf Java SE

Möchte man nun die Factory so erstellen, dass diese wiederum keine statischenAbhängigkeiten zu den jeweiligen Contexten bzw Implementierungen der Listehat, muss eine z.B. Registry gebaut werden.

Dort kann man zur Laufzeit die jeweiligen Implementierungen registrieren undfür eine Auflösung zur Verfügung stellen.

@SvenRuppert 35/122

Lösungsversuch Nr 1basierend auf Java SE

Möchte man nun die Factory so erstellen, dass diese wiederum keine statischenAbhängigkeiten zu den jeweiligen Contexten bzw Implementierungen der Listehat, muss eine z.B. Registry gebaut werden.

Dort kann man zur Laufzeit die jeweiligen Implementierungen registrieren undfür eine Auflösung zur Verfügung stellen.

Hier hilft CDI durch seine Konzepte, ohne das man sich mit derBasisimplementierung der Infrastruktur beschäftigen muss.

@SvenRuppert 36/122

endlich CDI ;-)basierend auf Weld / WELD-SE

Instanzen werden per @Inject durch den Container zur Verfügung gestellt

@SvenRuppert 37/122

endlich CDI ;-)basierend auf Weld / WELD-SE

Instanzen werden per @Inject durch den Container zur Verfügung gestellt

@Inject List list; JAVA

@SvenRuppert 38/122

endlich CDI ;-)basierend auf Weld / WELD-SE

Instanzen werden per @Inject durch den Container zur Verfügung gestellt

@Inject @CDILegacyTest List list; JAVA

@SvenRuppert 39/122

endlich CDI ;-)basierend auf Weld / WELD-SE

Instanzen werden per @Inject durch den Container zur Verfügung gestellt

@Inject @CDILegacyTest List list;

@Produces @CDILegacyTestpublic List createList(...){...}

JAVA

@SvenRuppert 40/122

endlich CDI ;-)basierend auf Weld / WELD-SE

Instanzen werden per @Inject durch den Container zur Verfügung gestellt

@Inject @CDILegacyTest List list;

@Produces @CDILegacyTestpublic List createList(InjectionPoint injectionPoint, BeanManager beanManager, ContextResolver contextResolver){ ....}

JAVA

@SvenRuppert 41/122

endlich CDI ;-)basierend auf Weld / WELD-SE

Instanzen werden per @Inject durch den Container zur Verfügung gestellt

@Inject @CDILegacyTest List list;

@Produces @CDILegacyTestpublic List createList(InjectionPoint injectionPoint, BeanManager beanManager, ContextResolver contextResolver){ boolean b = contextResolver.resolveContext(...); //treffen der Entscheidungen... if(b){ return new LinkedList(); } else { return new ArrayList(); }}

JAVA

@SvenRuppert 42/122

endlich CDI ;-)basierend auf Weld / WELD-SE

Instanzen werden per @Inject durch den Container zur Verfügung gestellt

Aber leider ist das immer noch zu dem Zeitpunkt zu dem die umliegende Instanzerzeugt wird.

@Inject @CDILegacyTest List list;

@Produces @CDILegacyTestpublic List createList(InjectionPoint injectionPoint, BeanManager beanManager, ContextResolver contextResolver){ boolean b = contextResolver.resolveContext(...); //treffen der Entscheidungen... if(b){ return new LinkedList(); } else { return new ArrayList(); }}

JAVA

@SvenRuppert 43/122

endlich CDI ;-)basierend auf Weld / WELD-SE

Instanzen können auch erst zum Zeitpunkt der Verwendung instanziiert werden.

@SvenRuppert 44/122

endlich CDI ;-)basierend auf Weld / WELD-SE

Instanzen können auch erst zum Zeitpunkt der Verwendung instanziiert werden.

Damit sind späte Entscheidungen möglich

@SvenRuppert 45/122

endlich CDI ;-)basierend auf Weld / WELD-SE

Instanzen können auch erst zum Zeitpunkt der Verwendung instanziiert werden.

Damit sind späte Entscheidungen möglich

@Inject @CDILegacyTest Instance<List> listInstance; JAVA

@SvenRuppert 46/122

endlich CDI ;-)basierend auf Weld / WELD-SE

Instanzen können auch erst zum Zeitpunkt der Verwendung instanziiert werden.

Damit sind späte Entscheidungen möglich

@Inject @CDILegacyTest Instance<List> listInstance;//..späterfinal List list = listInstance.get();

JAVA

@SvenRuppert 47/122

endlich CDI ;-)basierend auf Weld / WELD-SE

Instanzen können auch erst zum Zeitpunkt der Verwendung instanziiert werden

damit sind späte Entscheidungen möglich

@Inject @CDILegacyTest Instance<List> listInstance;//..späterfinal List list = listInstance.get();

@Produces @CDILegacyTestpublic List createList(InjectionPoint injectionPoint, BeanManager beanManager, ContextResolver contextResolver){ boolean b = contextResolver.resolveContext(...); //treffen der Entscheidungen... if(b){ return new LinkedList(); } else { return new ArrayList(); }}

JAVA

@SvenRuppert 48/122

CDIwas wurde bis jetzt erreicht?

Trennung der statischen Abhängigkeiten auf Klassenebene innerhalb derVererbung

@SvenRuppert 49/122

CDIwas wurde bis jetzt erreicht?

Trennung der statischen Abhängigkeiten auf Klassenebene innerhalb derVererbung

Keine "allwissende" Factory, die alle statischen Abhängigkeiten besitzt

@SvenRuppert 50/122

CDIwas wurde bis jetzt erreicht?

Trennung der statischen Abhängigkeiten auf Klassenebene innerhalb derVererbung

Keine "allwissende" Factory, die alle statischen Abhängigkeiten besitzt

Für jede Entscheidung einen Producer

@SvenRuppert 51/122

CDIwas wurde bis jetzt erreicht?

Trennung der statischen Abhängigkeiten auf Klassenebene innerhalb derVererbung

Keine "allwissende" Factory, die alle statischen Abhängigkeiten besitzt

Für jede Entscheidung einen Producer.. wie funktioniert das praktisch?

@SvenRuppert 52/122

CDIwas wurde bis jetzt erreicht?

Trennung der statischen Abhängigkeiten auf Klassenebene innerhalb derVererbung

Keine "allwissende" Factory, die alle statischen Abhängigkeiten besitzt

Für jede Entscheidung einen Producer.. wie funktioniert das praktisch?

... sehen wir uns gleich noch an.... Bitte ein wenig Geduld...

@SvenRuppert 53/122

CDIwas wurde dafür in Kauf genommen?

statische Kopplung über AnnotationsLiterale:

@Inject @MyQualifier List liste; JAVA

@SvenRuppert 54/122

CDIwas wurde dafür in Kauf genommen?

statische Kopplung über AnnotationsLiterale:

schlechterer Umgang mit Generics

@Inject @MyQualifier List liste; JAVA

@SvenRuppert 55/122

CDIwas wurde dafür in Kauf genommen?

statische Kopplung über AnnotationsLiterale:

schlechterer Umgang mit Generics

keine Komplexitätsreduktion für den Entwickler

@Inject @MyQualifier List liste; JAVA

@SvenRuppert 56/122

CDI explained by codeHelloLogger zum aufwärmen/wiederholen

klassischer Fall, Logger im System

@Inject @CDILogger Logger logger; JAVA

@SvenRuppert 57/122

CDI explained by codeHelloLogger zum aufwärmen/wiederholen

klassischer Fall, Logger im System

@Inject @CDILogger Logger logger;

@Qualifier@Retention(value = RetentionPolicy.RUNTIME)@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})public @interface CDILogger {}

JAVA

@SvenRuppert 58/122

CDI explained by codeHelloLogger zum aufwärmen/wiederholen

klassischer Fall, Logger im System

@Inject @CDILogger Logger logger;

@Qualifier@Retention(value = RetentionPolicy.RUNTIME)@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})public @interface CDILogger {}

@Produces @CDILoggerpublic Logger produceLog4JLogger(InjectionPoint iP, BeanManager beanManager){ final Class<?> declaringClass = iP.getMember().getDeclaringClass(); return new Logger(declaringClass);}

JAVA

@SvenRuppert 59/122

CDI explained by codeHelloLogger zum aufwärmen/wiederholen

klassischer Fall, Logger im System

@Inject @CDILogger Logger logger;

@Qualifier@Retention(value = RetentionPolicy.RUNTIME)@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})public @interface CDILogger {}

@Produces @CDILoggerpublic Logger produceLog4JLogger(InjectionPoint iP, BeanManager beanManager){ final Class<?> declaringClass = iP.getMember().getDeclaringClass(); return new Logger(declaringClass); //Logger nicht gemanaged !!!}

JAVA

@SvenRuppert 60/122

CDI explained by codeHelloLogger zum aufwärmen / Hat uns das jetzt richtig weitergebracht?

Referenz auf Factory wird ersetzt durch Qualifier. :-(

@Inject @CDILogger Logger logger; JAVA

@SvenRuppert 61/122

CDI explained by codeHelloLogger zum aufwärmen / Hat uns das jetzt richtig weitergebracht?

Referenz auf Factory wird ersetzt durch Qualifier. :-(

Spezifische Producer losgelöst von den anderen Producern

@Inject @CDILogger Logger logger; JAVA

@SvenRuppert 62/122

CDI explained by codeHelloLogger zum aufwärmen / Hat uns das jetzt richtig weitergebracht?

Referenz auf Factory wird ersetzt durch Qualifier. :-(

Spezifische Producer losgelöst von den anderen Producern

zentrale Stelle für context-bezogene Entscheidungen

@Inject @CDILogger Logger logger; JAVA

@SvenRuppert 63/122

CDI explained by codeQualifier und AnnotationsLiterale

@Inject @CDILogger Logger logger; JAVA

@SvenRuppert 64/122

CDI explained by codeQualifier und AnnotationsLiterale

@Inject @CDILogger Logger logger; JAVA

@Producer @CDILogger Logger create(...); JAVA

@SvenRuppert 65/122

CDI explained by codeQualifier und AnnotationsLiterale

@Inject @CDILogger Logger logger; JAVA

@Producer @CDILogger Logger create(...); JAVA

@Producer @CDILogger Logger create(..){ AnnotationsLiteral<T> prodAL = contextResolver.resolve(..);};

JAVA

@SvenRuppert 66/122

CDI explained by codeQualifier und AnnotationsLiterale

@Inject @CDILogger Logger logger; JAVA

@Producer @CDILogger Logger create(...); JAVA

@Producer @CDILogger Logger create(BeanManager bm,ContextResolver cr){ AnnotationsLiteral<T> prodAL = contextResolver.resolve(..); return creator.getManagedInstance(Logger.class, annotationLiteral);};

JAVA

@SvenRuppert 67/122

CDI explained by codeQualifier und AnnotationsLiterale

Es wird dynamisch auf ein AnnotationsLiteral aufgelöst.

@Inject @CDILogger Logger logger; JAVA

@Producer @CDILogger Logger create(...); JAVA

@Producer @CDILogger Logger create(BeanManager bm,ContextResolver cr){ AnnotationsLiteral<T> prodAL = contextResolver.resolve(..); return creator.getManagedInstance(Logger.class, annotationLiteral);};

JAVA

@SvenRuppert 68/122

CDI explained by codeQualifier und AnnotationsLiterale

Es wird dynamisch auf ein AnnotationsLiteral aufgelöst.

AnnotationsLiteral und Klasse -> Auswahl des Producers

@Inject @CDILogger Logger logger; JAVA

@Producer @CDILogger Logger create(...); JAVA

@Producer @CDILogger Logger create(BeanManager bm,ContextResolver cr){ AnnotationsLiteral<T> prodAL = contextResolver.resolve(..); return creator.getManagedInstance(Logger.class, annotationLiteral);};

JAVA

@SvenRuppert 69/122

CDI explained by code 1 / 6ContextResolver / aus der Sicht des Entwicklers

@Inject CDIContext context; //z.B. ein Singleton@Inject ContextResolver cr;

@Testpublic void testMockedModus001() throws Exception { Assert.assertFalse(context.isMockedModusActive()); final AnnotationLiteral annotationLiteralProd = cr.resolveContext(this.getClass()); Assert.assertEquals(new AnnotationLiteral<CDICommons>() {},annotationLiteralProd);

}

JAVA

@SvenRuppert 70/122

CDI explained by code 1 / 6ContextResolver / aus der Sicht des Entwicklers

@Inject CDIContext context; //z.B. ein Singleton@Inject ContextResolver cr;

@Testpublic void testMockedModus001() throws Exception { Assert.assertFalse(context.isMockedModusActive()); final AnnotationLiteral annotationLiteralProd = cr.resolveContext(this.getClass()); Assert.assertEquals(new AnnotationLiteral<CDICommons>() {},annotationLiteralProd);

((TestContext)context).setTestModus(true); Assert.assertTrue(context.isMockedModusActive());

}

JAVA

@SvenRuppert 71/122

CDI explained by code 1 / 6ContextResolver / aus der Sicht des Entwicklers

@Inject CDIContext context; //z.B. ein Singleton@Inject ContextResolver cr;

@Testpublic void testMockedModus001() throws Exception { Assert.assertFalse(context.isMockedModusActive()); final AnnotationLiteral annotationLiteralProd = cr.resolveContext(this.getClass()); Assert.assertEquals(new AnnotationLiteral<CDICommons>() {},annotationLiteralProd);

((TestContext)context).setTestModus(true); Assert.assertTrue(context.isMockedModusActive());

final AnnotationLiteral annotationLiteral = cr.resolveContext(this.getClass()); Assert.assertEquals(new AnnotationLiteral<CDICommonsMocked>() {},annotationLiteral);}

JAVA

@SvenRuppert 72/122

CDI explained by code 1 / 6ContextResolver / aus der Sicht des Entwicklers

@SvenRuppert 73/122

CDI explained by code 1 / 6ContextResolver / aus der Sicht des Entwicklers

@SvenRuppert 74/122

CDI explained by code 2a / 6ContextResolver

Die Annotation mit @CDINotMapped, um das Interface explizit in denNamensraum zu setzen

@CDINotMappedpublic interface CDIContext { public boolean isMockedModusActive();}

JAVA

@SvenRuppert 75/122

CDI explained by code 2b / 6ContextResolver

Mit klassischen Interzeptoren kann man Querschnittsthemen deklarieren.

Nur allgemein umschalten auf Mocked/NotMocked möglich?

@InterceptorBinding@Target({ElementType.TYPE, ElementType.METHOD})@Retention(value = RetentionPolicy.RUNTIME)@Inheritedpublic @interface CheckMockedContext { }

public interface ContextResolver { @CheckMockedContext public AnnotationLiteral resolveContext(final Class<?> targetClass);}

JAVA

@SvenRuppert 76/122

CDI explained by code 3a / 6ContextResolver

@Interceptor @CheckMockedContextpublic class MockedInterceptor implements Serializable { @Inject CDIContext context; private @Inject @CDILogger Logger logger;

@AroundInvoke public Object checkMockedMode(InvocationContext ctx) throws Exception { if (context.isMockedModusActive()) { if (logger.isDebugEnabled()) { logger.debug("MockedModus active"); } return new AnnotationLiteral<CDICommonsMocked>() { }; } else { return ctx.proceed(); } }}

JAVA

@SvenRuppert 77/122

CDI explained by code 3b / 6ContextResolver

Durch Interzeptoren meist nur allgemeine Umschaltlogik darstellbar

@SvenRuppert 78/122

CDI explained by code 3b / 6ContextResolver

Durch Interzeptoren meist nur allgemeine Umschaltlogik darstellbar

Benötigt wird aber evtl differenziertes Umschalten.

@SvenRuppert 79/122

CDI explained by code 3b / 6ContextResolver

Durch Interzeptoren meist nur allgemeine Umschaltlogik darstellbar

Benötigt wird aber evtl differenziertes Umschalten.

Interzeptoren werden statisch definiert - schade....

@SvenRuppert 80/122

CDI explained by code 4a / 6ContextResolver

@CDICommonspublic class DefaultContextResolver implements ContextResolver { @Inject @CDILogger Logger logger; @Inject BeanManager beanManager;

public Set<ContextResolver> gettAllContextResolver() { final Set<ContextResolver> resultSet = new HashSet<>(); final Set<Bean<?>> allBeans = beanManager .getBeans(ContextResolver.class, new AnnotationLiteral<Any>() {}); allBeans.forEach(b-> b.getTypes().stream() .filter(t -> t.equals(ContextResolver.class)) .filter(r -> !r.getClass().isAnnotationPresent(CDICommonsMocked.class)) .forEach(t -> { final ContextResolver cr = ((Bean<ContextResolver>) b) .create(beanManager.createCreationalContext((Bean<ContextResolver>) b)); resultSet.add(cr); })); return resultSet; }

JAVA

@SvenRuppert 81/122

CDI explained by code 4b / 6ContextResolver

public Set<ContextResolver> gettAllMockedContextResolver() { final Set<ContextResolver> resultSet = new HashSet<>(); final Set<Bean<?>> allBeans = beanManager .getBeans(ContextResolver.class, new AnnotationLiteral<CDICommonsMocked>() {}); allBeans.forEach(b-> b.getTypes().forEach(type->{ if (type.equals(ContextResolver.class)) { final ContextResolver t = ((Bean<ContextResolver>) b) .create(beanManager.createCreationalContext((Bean<ContextResolver>) b)); resultSet.add(t); } })); return resultSet;}

JAVA

@SvenRuppert 82/122

CDI explained by code 4c / 6ContextResolver

public AnnotationLiteral resolveContext(Class targetClass) { Stream<ContextResolver> contextResolversMocked = gettAllMockedContextResolver().stream(); Stream<ContextResolver> contextResolvers = gettAllContextResolver().stream(); return contextResolversMocked .filter(r -> (r.resolveContext(targetClass) != null)) .map(r -> r.resolveContext(targetClass)) .findFirst().orElse( contextResolvers .filter(r -> !r.getClass().isAnnotationPresent(CDICommonsMocked.class)) .filter(r -> !r.getClass().equals(DefaultContextResolver.class)) .filter(r -> (r.resolveContext(targetClass) != null)) .map(r -> r.resolveContext(targetClass)) .findFirst().orElse(null) );}

JAVA

@SvenRuppert 83/122

CDI explained by code 5 / 6ContextResolver

@Singletonpublic class TestContext implements CDIContext { private boolean testModus = false; @Override public boolean isMockedModusActive() {return testModus;} public boolean isTestModus() {return testModus;} public void setTestModus(boolean testModus) {this.testModus = testModus;}}public class TestContextResolver implements ContextResolver { @Inject CDIContext context; @CheckMockedContext @Override public AnnotationLiteral resolveContext(Class<?> targetClass) { //entscheide ob Du zuständig bist return new AnnotationLiteral<CDICommons>() {}; } }

JAVA

@SvenRuppert 84/122

CDI explained by code 6 / 6ContextResolver

Wir sind nun in der Lage dynamisch auf den Systemzustand zu reagieren.

@SvenRuppert 85/122

CDI explained by code 6 / 6ContextResolver

Wir sind nun in der Lage dynamisch auf den Systemzustand zu reagieren.

ContextResolver sind immer nur in ihrem fachlichen Bereich aktiv

@SvenRuppert 86/122

CDI explained by code 6 / 6ContextResolver

Wir sind nun in der Lage dynamisch auf den Systemzustand zu reagieren.

ContextResolver sind immer nur in ihrem fachlichen Bereich aktiv

Unterscheidung auf z.B. Mandantenebene leicht realisierbar

@SvenRuppert 87/122

CDI explained by code 1 / 7CDI managed DynamicObjectAdapter - besserer Decorator

klassischer Decorator in CDI

@Decoratorpublic abstract class CoderDecorator implements Coder { @Inject @Delegate @Any Coder coder; public String codeString(String s, int tval) { int len = s.length(); return "\"" + s + "\" becomes " + "\"" + coder.codeString(s, tval) + "\", " + len + " characters in length"; }}Inside beans.xml<decorators> <class>decorators.CoderDecorator</class></decorators>

JAVA

@SvenRuppert 88/122

CDI explained by code 2 / 7CDI managed DynamicObjectAdapter - der bessere Decorator

Ein Decorator in CDI muss in der beans.xml definiert werden.

@SvenRuppert 89/122

CDI explained by code 2 / 7CDI managed DynamicObjectAdapter - der bessere Decorator

Ein Decorator in CDI muss in der beans.xml definiert werden.

Klasse mit einer speziellen Annotation @Decorator

@SvenRuppert 90/122

CDI explained by code 2 / 7CDI managed DynamicObjectAdapter - der bessere Decorator

Ein Decorator in CDI muss in der beans.xml definiert werden.

Klasse mit einer speziellen Annotation @Decorator

Innerhalb des Decorators muss die Instanz des Originals injiziert werden

@SvenRuppert 91/122

CDI explained by code 2 / 7CDI managed DynamicObjectAdapter - der bessere Decorator

Ein Decorator in CDI muss in der beans.xml definiert werden.

Klasse mit einer speziellen Annotation @Decorator

Innerhalb des Decorators muss die Instanz des Originals injiziert werden

Decorator muss von der Original-Implementierung oder dem Interface ableiten

@SvenRuppert 92/122

CDI explained by code 2 / 7CDI managed DynamicObjectAdapter - der bessere Decorator

Ein Decorator in CDI muss in der beans.xml definiert werden.

Klasse mit einer speziellen Annotation @Decorator

Innerhalb des Decorators muss die Instanz des Originals injiziert werden

Decorator muss von der Original-Implementierung oder dem Interface ableiten

... geht das auch schöner ?

@SvenRuppert 93/122

CDI explained by code 3 / 7CDI managed DynamicObjectAdapter - der bessere Decorator

Aus der Sicht des Entwicklers

@CDINotMappedpublic interface DemoLogic { public default int add(int a, int b){ return a+b; } public default int sub(int a, int b){ return a-b; }}@CDINotMappedpublic class DemoLogicAdapter_A implements DemoLogic{ public int add(int a, int b){ return a+b + 100; }}@Singleton //sollte schon bekannt sein ;-)public class Context { public boolean original = true; }

JAVA

@SvenRuppert 94/122

CDI explained by code 4a / 7CDI managed DynamicObjectAdapter - besserer Decorator

Injizieren der Referenz auf DemoLogic

@SvenRuppert 95/122

CDI explained by code 4a / 7CDI managed DynamicObjectAdapter - besserer Decorator

Injizieren der Referenz auf DemoLogic

Holen einer Instanz der DemoLogic

@SvenRuppert 96/122

CDI explained by code 4a / 7CDI managed DynamicObjectAdapter - besserer Decorator

Injizieren der Referenz auf DemoLogic

Holen einer Instanz der DemoLogic

Aufruf der Methode add(1,1)

@SvenRuppert 97/122

CDI explained by code 4a / 7CDI managed DynamicObjectAdapter - besserer Decorator

Injizieren der Referenz auf DemoLogic

Holen einer Instanz der DemoLogic

Aufruf der Methode add(1,1)

Überprüfung ob das Ergebnis den Erwartungen entspricht, hier der Wert 2.

@SvenRuppert 98/122

CDI explained by code 4a / 7CDI managed DynamicObjectAdapter - besserer Decorator

Injizieren der Referenz auf DemoLogic

Holen einer Instanz der DemoLogic

Aufruf der Methode add(1,1)

Überprüfung ob das Ergebnis den Erwartungen entspricht, hier der Wert 2.

Context-Switch auf mandantenabhängige Implementierung

@SvenRuppert 99/122

CDI explained by code 4a / 7CDI managed DynamicObjectAdapter - besserer Decorator

Injizieren der Referenz auf DemoLogic

Holen einer Instanz der DemoLogic

Aufruf der Methode add(1,1)

Überprüfung ob das Ergebnis den Erwartungen entspricht, hier der Wert 2.

Context-Switch auf mandantenabhängige Implementierung

Holen einer Instanz der DemoLogic

@SvenRuppert 100/122

CDI explained by code 4a / 7CDI managed DynamicObjectAdapter - besserer Decorator

Injizieren der Referenz auf DemoLogic

Holen einer Instanz der DemoLogic

Aufruf der Methode add(1,1)

Überprüfung ob das Ergebnis den Erwartungen entspricht, hier der Wert 2.

Context-Switch auf mandantenabhängige Implementierung

Holen einer Instanz der DemoLogic

Aufruf der Methode add(1,1)

@SvenRuppert 101/122

CDI explained by code 4a / 7CDI managed DynamicObjectAdapter - besserer Decorator

Injizieren der Referenz auf DemoLogic

Holen einer Instanz der DemoLogic

Aufruf der Methode add(1,1)

Überprüfung ob das Ergebnis den Erwartungen entspricht, hier der Wert 2.

Context-Switch auf mandantenabhängige Implementierung

Holen einer Instanz der DemoLogic

Aufruf der Methode add(1,1)

Überprüfung ob das Ergebnis den Erwartungen entspricht, hier der Wert 102.

@SvenRuppert 102/122

CDI explained by code 4a / 7CDI managed DynamicObjectAdapter - besserer Decorator

Injizieren der Referenz auf DemoLogic

Holen einer Instanz der DemoLogic

Aufruf der Methode add(1,1)

Überprüfung ob das Ergebnis den Erwartungen entspricht, hier der Wert 2.

Context-Switch auf mandantenabhängige Implementierung

Holen einer Instanz der DemoLogic

Aufruf der Methode add(1,1)

Überprüfung ob das Ergebnis den Erwartungen entspricht, hier der Wert 102.

Kaffee trinken.

@SvenRuppert 103/122

CDI explained by code 4b / 7CDI managed DynamicObjectAdapter - besserer Decorator

@Inject @DynamicDecoratorTest Instance<DemoLogic> demoLogic; @Inject Context context; @Test public void testDemoLogicOriginalTest() throws Exception { Assert.assertNotNull(demoLogic); final DemoLogic demoLogic1 = demoLogic.get(); final int add = demoLogic1.add(1, 1); Assert.assertEquals(2,add); System.out.println("add = " + add); context.original = false; final DemoLogic demoLogic2 = demoLogic.get(); final int addAdapted = demoLogic2.add(1, 1); Assert.assertEquals(102,addAdapted); System.out.println("addAdapted = " + addAdapted); }

JAVA

@SvenRuppert 104/122

CDI explained by code 4c / 7CDI managed DynamicObjectAdapter - besserer Decorator

manuelles aktivieren von CDI.. yepp das geht

public <T> T activateCDI(T t) { final Class aClass = t.getClass(); if (logger.isDebugEnabled()) { logger.debug("activateCDI-> " + aClass); } AnnotatedType annotationType = beanManager.createAnnotatedType(aClass); InjectionTarget injectionTarget = beanManager.createInjectionTarget(annotationType); CreationalContext creationalContext = beanManager.createCreationalContext(null); injectionTarget.inject(t, creationalContext); injectionTarget.postConstruct(t); return t;}

JAVA

@SvenRuppert 105/122

CDI explained by code 5 / 7CDI managed DynamicObjectAdapter - besserer Decorator

public class DemoLogicProducer { @Inject Instance<DynamicObjectAdapterFactory> dOAFInstance; @Inject Context context;

@Produces @DynamicDecoratorTest public DemoLogic create(ManagedInstanceCreator instanceCreator){ final DemoLogic demoLogic = instanceCreator.activateCDI(new DemoLogic() {}); final DynamicObjectAdapterFactory dynamicObjectAdapterFactory = dOAFInstance.get();

final Object adapter; if (context.original){ adapter = new Object(); } else { //kann hier beliebig komplex werden adapter = instanceCreator.activateCDI(new DemoLogicAdapter_A()); } //hier interface notwendig... see insight return dynamicObjectAdapterFactory.adapt(demoLogic, DemoLogic.class, adapter); }

JAVA

@SvenRuppert 106/122

CDI explained by code 6 / 7CDI managed DynamicObjectAdapter - besserer Decorator

public class DynamicObjectAdapterFactory { @Inject Instance<CDIInvocationHandler> cdiInvocationHandlerInstance;

public<T> T adapt(final Object adaptee, final Class<T> target, final Object adapter) { final CDIInvocationHandler invocationHandler = cdiInvocationHandlerInstance.get().adapter(adapter).adaptee(adaptee);

return (T) Proxy.newProxyInstance( target.getClassLoader(), new Class[]{target}, //hier Interface notwendig! invocationHandler ); }}

JAVA

@SvenRuppert 107/122

CDI explained by code 7a / 7cCDI managed DynamicObjectAdapter - besserer Decorator

public class MethodIdentifier { private final String name; private final Class[] parameters;

public MethodIdentifier(Method m) { name = m.getName(); parameters = m.getParameterTypes(); } // we can save time by assuming that we only compare against // other MethodIdentifier objects public boolean equals(Object o) { MethodIdentifier mid = (MethodIdentifier) o; return name.equals(mid.name) && Arrays.equals(parameters, mid.parameters); } public int hashCode() { return name.hashCode(); }}

JAVA

@SvenRuppert 108/122

CDI explained by code 7b / 7cCDI managed DynamicObjectAdapter - besserer Decorator

public class CDIInvocationHandler implements InvocationHandler { private Map<MethodIdentifier, Method> adaptedMethods = new HashMap<> (); private Object adapter; private Object adaptee;

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (adaptedMethods.isEmpty()){ Method[] methods = adapter.getClass().getDeclaredMethods(); for (Method m : methods) { adaptedMethods.put(new MethodIdentifier(m), m); } } try { Method other = adaptedMethods.get(new MethodIdentifier(method)); if (other != null) { return other.invoke(adapter, args); } else { return method.invoke(adaptee, args); } } catch (InvocationTargetException e) { throw e.getTargetException(); } }...

JAVA

@SvenRuppert 109/122

CDI explained by code 7c / 7cCDI managed DynamicObjectAdapter - besserer Decorator

Mit diesem Pattern sind wir in der Lage die Unzulänglichkeiten des CDIDecorators auszugleichen.

@SvenRuppert 110/122

CDI explained by code 7c / 7cCDI managed DynamicObjectAdapter - besserer Decorator

Mit diesem Pattern sind wir in der Lage die Unzulänglichkeiten des CDIDecorators auszugleichen.

Spätere Änderungen an dem Interface führen nicht dazu, dass alle Adapterangepasst werden müssen

@SvenRuppert 111/122

CDI explained by code 7c / 7cCDI managed DynamicObjectAdapter - besserer Decorator

Mit diesem Pattern sind wir in der Lage die Unzulänglichkeiten des CDIDecorators auszugleichen.

Spätere Änderungen an dem Interface führen nicht dazu, dass alle Adapterangepasst werden müssen

Alle Komponenten sind von dem verwendeten CDI-Container verwaltet

@SvenRuppert 112/122

Cross Language Injection.. am Beispiel von Kotlin..

class DemoLogicKotlin() { public fun workOnString(): String { return "DemoLogicKotlin" }}

JAVA

@SvenRuppert 113/122

Cross Language Injection.. am Beispiel von Kotlin..

entweder : Adapter mit Delegator

@CDINotMappedpublic class DemoLogicKotlinWrapper implements DemoLogic { private @Inject DemoLogicKotlin kotlin; public String workOnString() { return kotlin.workOnString(); }}

JAVA

@SvenRuppert 114/122

Cross Language Injection.. am Beispiel von Kotlin..

oder mittels Producer direkt verfügbar machen

@CDINotMappedpublic class DemoLogicKotlinProducer {

@Inject ManagedInstanceCreator creator; //@Inject DemoLogicKotlin kotlin;

@Produces @KotlinImpl public DemoLogic create(){ final DemoLogic logic = new DemoLogicKotlinWrapper(); return creator.activateCDI(logic); }}

JAVA

@SvenRuppert 115/122

CDI und TDD... kaskadierte MOCKS

Service A injected Service B injected Service C

@SvenRuppert 116/122

CDI und TDD... kaskadierte MOCKS

Service A injected Service B injected Service C

Service A (mocked) injected Service B injected Service C

@SvenRuppert 117/122

CDI und TDD... kaskadierte MOCKS

Service A injected Service B injected Service C

Service A (mocked) injected Service B injected Service C

Service A injected Service B (mocked) injected Service C

@SvenRuppert 118/122

CDI und TDD... kaskadierte MOCKS

Service A injected Service B injected Service C

Service A (mocked) injected Service B injected Service C

Service A injected Service B (mocked) injected Service C

Service A (mocked) injected Service B (mocked) injected Service C

@SvenRuppert 119/122

CDI und TDD... kaskadierte MOCKS

Service A injected Service B injected Service C

Service A (mocked) injected Service B injected Service C

Service A injected Service B (mocked) injected Service C

Service A (mocked) injected Service B (mocked) injected Service C

beliebige Kombinationen können so dynamisch zusammen geschaltet werden.

@SvenRuppert 120/122

finally at amazon..

my book with Dr, Heinz KabutzBook about Reflection - part one

Dynamic Proxies z.B. ...dynamic static proxies... ;-)

<Thank You!>

g+ www.google.com/+SvenRupperttwitter @SvenRuppert

www www.rapidpm.org

www www.rapidpm.orggithub github.com/svenruppert