Warum ich so auf das c von cdi stehe

120
Warum CDI oder gibt es einen tieferen Sinn dahinter? warum denn CDI ? ;-)

Transcript of Warum ich so auf das c von cdi stehe

Page 1: Warum ich so auf das c von cdi stehe

Warum CDI odergibt es einen tieferen Sinn dahinter?

warum denn CDI ? ;-)

Page 2: Warum ich so auf das c von cdi stehe

@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

Page 3: Warum ich so auf das c von cdi stehe

@SvenRuppert 5/122

Warum CDI odergibt es einen tieferen Sinn dahinter?

lösen/entfernen von statischen Abhängigkeiten

Page 4: Warum ich so auf das c von cdi stehe

@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?

Page 5: Warum ich so auf das c von cdi stehe

@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

Page 6: Warum ich so auf das c von cdi stehe

@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

Page 7: Warum ich so auf das c von cdi stehe

@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

Page 8: Warum ich so auf das c von cdi stehe

@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.

Page 9: Warum ich so auf das c von cdi stehe

@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.

Page 10: Warum ich so auf das c von cdi stehe

@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.

Page 11: Warum ich so auf das c von cdi stehe

@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.

Page 12: Warum ich so auf das c von cdi stehe

@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

Page 13: Warum ich so auf das c von cdi stehe

@SvenRuppert 15/122

Warum CDI odergibt es einen tieferen Sinn dahinter?

Haben wir damit etwas erreicht?

Page 14: Warum ich so auf das c von cdi stehe

@SvenRuppert 16/122

Warum CDI odergibt es einen tieferen Sinn dahinter?

Haben wir damit etwas erreicht?

... bzw was haben wir damit erreicht?

Page 15: Warum ich so auf das c von cdi stehe

@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.

Page 16: Warum ich so auf das c von cdi stehe

@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! ;-)

Page 17: Warum ich so auf das c von cdi stehe

@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

Page 18: Warum ich so auf das c von cdi stehe

@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

Page 19: Warum ich so auf das c von cdi stehe

@SvenRuppert 21/122

Warum CDI odergibt es einen tieferen Sinn dahinter?

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

Page 20: Warum ich so auf das c von cdi stehe

@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.

Page 21: Warum ich so auf das c von cdi stehe

@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.

Page 22: Warum ich so auf das c von cdi stehe

@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.

Page 23: Warum ich so auf das c von cdi stehe

@SvenRuppert 25/122

Warum CDI odergibt es einen tieferen Sinn dahinter?

Anforderung Nr 1: keine statischen Abhängigkeiten zu spezifischenImplementierungen

Page 24: Warum ich so auf das c von cdi stehe

@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

Page 25: Warum ich so auf das c von cdi stehe

@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 ???

Page 26: Warum ich so auf das c von cdi stehe

@SvenRuppert 28/122

Lösungsversuch Nr 1basierend auf Java SE

Eine etwas dynamischere Lösung...

Page 27: Warum ich so auf das c von cdi stehe

@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

Page 28: Warum ich so auf das c von cdi stehe

@SvenRuppert 30/122

Lösungsversuch Nr 1basierend auf Java SE

Eine etwas dynamischere Lösung...

Die Komplexität der Entscheidung liegt nun im ContextResolver

Page 29: Warum ich so auf das c von cdi stehe

@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

Page 30: Warum ich so auf das c von cdi stehe

@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.

Page 31: Warum ich so auf das c von cdi stehe

@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.

Page 32: Warum ich so auf das c von cdi stehe

@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.

Page 33: Warum ich so auf das c von cdi stehe

@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.

Page 34: Warum ich so auf das c von cdi stehe

@SvenRuppert 36/122

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

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

Page 35: Warum ich so auf das c von cdi stehe

@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

Page 36: Warum ich so auf das c von cdi stehe

@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

Page 37: Warum ich so auf das c von cdi stehe

@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

Page 38: Warum ich so auf das c von cdi stehe

@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

Page 39: Warum ich so auf das c von cdi stehe

@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

Page 40: Warum ich so auf das c von cdi stehe

@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

Page 41: Warum ich so auf das c von cdi stehe

@SvenRuppert 43/122

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

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

Page 42: Warum ich so auf das c von cdi stehe

@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

Page 43: Warum ich so auf das c von cdi stehe

@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

Page 44: Warum ich so auf das c von cdi stehe

@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

Page 45: Warum ich so auf das c von cdi stehe

@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

Page 46: Warum ich so auf das c von cdi stehe

@SvenRuppert 48/122

CDIwas wurde bis jetzt erreicht?

Trennung der statischen Abhängigkeiten auf Klassenebene innerhalb derVererbung

Page 47: Warum ich so auf das c von cdi stehe

@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

Page 48: Warum ich so auf das c von cdi stehe

@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

Page 49: Warum ich so auf das c von cdi stehe

@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?

Page 50: Warum ich so auf das c von cdi stehe

@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...

Page 51: Warum ich so auf das c von cdi stehe

@SvenRuppert 53/122

CDIwas wurde dafür in Kauf genommen?

statische Kopplung über AnnotationsLiterale:

@Inject @MyQualifier List liste; JAVA

Page 52: Warum ich so auf das c von cdi stehe

@SvenRuppert 54/122

CDIwas wurde dafür in Kauf genommen?

statische Kopplung über AnnotationsLiterale:

schlechterer Umgang mit Generics

@Inject @MyQualifier List liste; JAVA

Page 53: Warum ich so auf das c von cdi stehe

@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

Page 54: Warum ich so auf das c von cdi stehe

@SvenRuppert 56/122

CDI explained by codeHelloLogger zum aufwärmen/wiederholen

klassischer Fall, Logger im System

@Inject @CDILogger Logger logger; JAVA

Page 55: Warum ich so auf das c von cdi stehe

@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

Page 56: Warum ich so auf das c von cdi stehe

@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

Page 57: Warum ich so auf das c von cdi stehe

@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

Page 58: Warum ich so auf das c von cdi stehe

@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

Page 59: Warum ich so auf das c von cdi stehe

@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

Page 60: Warum ich so auf das c von cdi stehe

@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

Page 61: Warum ich so auf das c von cdi stehe

@SvenRuppert 63/122

CDI explained by codeQualifier und AnnotationsLiterale

@Inject @CDILogger Logger logger; JAVA

Page 62: Warum ich so auf das c von cdi stehe

@SvenRuppert 64/122

CDI explained by codeQualifier und AnnotationsLiterale

@Inject @CDILogger Logger logger; JAVA

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

Page 63: Warum ich so auf das c von cdi stehe

@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

Page 64: Warum ich so auf das c von cdi stehe

@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

Page 65: Warum ich so auf das c von cdi stehe

@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

Page 66: Warum ich so auf das c von cdi stehe

@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

Page 67: Warum ich so auf das c von cdi stehe

@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

Page 68: Warum ich so auf das c von cdi stehe

@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

Page 69: Warum ich so auf das c von cdi stehe

@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

Page 70: Warum ich so auf das c von cdi stehe

@SvenRuppert 72/122

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

Page 71: Warum ich so auf das c von cdi stehe

@SvenRuppert 73/122

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

Page 72: Warum ich so auf das c von cdi stehe

@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

Page 73: Warum ich so auf das c von cdi stehe

@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

Page 74: Warum ich so auf das c von cdi stehe

@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

Page 75: Warum ich so auf das c von cdi stehe

@SvenRuppert 77/122

CDI explained by code 3b / 6ContextResolver

Durch Interzeptoren meist nur allgemeine Umschaltlogik darstellbar

Page 76: Warum ich so auf das c von cdi stehe

@SvenRuppert 78/122

CDI explained by code 3b / 6ContextResolver

Durch Interzeptoren meist nur allgemeine Umschaltlogik darstellbar

Benötigt wird aber evtl differenziertes Umschalten.

Page 77: Warum ich so auf das c von cdi stehe

@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....

Page 78: Warum ich so auf das c von cdi stehe

@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

Page 79: Warum ich so auf das c von cdi stehe

@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

Page 80: Warum ich so auf das c von cdi stehe

@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

Page 81: Warum ich so auf das c von cdi stehe

@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

Page 82: Warum ich so auf das c von cdi stehe

@SvenRuppert 84/122

CDI explained by code 6 / 6ContextResolver

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

Page 83: Warum ich so auf das c von cdi stehe

@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

Page 84: Warum ich so auf das c von cdi stehe

@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

Page 85: Warum ich so auf das c von cdi stehe

@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

Page 86: Warum ich so auf das c von cdi stehe

@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.

Page 87: Warum ich so auf das c von cdi stehe

@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

Page 88: Warum ich so auf das c von cdi stehe

@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

Page 89: Warum ich so auf das c von cdi stehe

@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

Page 90: Warum ich so auf das c von cdi stehe

@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 ?

Page 91: Warum ich so auf das c von cdi stehe

@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

Page 92: Warum ich so auf das c von cdi stehe

@SvenRuppert 94/122

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

Injizieren der Referenz auf DemoLogic

Page 93: Warum ich so auf das c von cdi stehe

@SvenRuppert 95/122

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

Injizieren der Referenz auf DemoLogic

Holen einer Instanz der DemoLogic

Page 94: Warum ich so auf das c von cdi stehe

@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)

Page 95: Warum ich so auf das c von cdi stehe

@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.

Page 96: Warum ich so auf das c von cdi stehe

@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

Page 97: Warum ich so auf das c von cdi stehe

@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

Page 98: Warum ich so auf das c von cdi stehe

@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)

Page 99: Warum ich so auf das c von cdi stehe

@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.

Page 100: Warum ich so auf das c von cdi stehe

@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.

Page 101: Warum ich so auf das c von cdi stehe

@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

Page 102: Warum ich so auf das c von cdi stehe

@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

Page 103: Warum ich so auf das c von cdi stehe

@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

Page 104: Warum ich so auf das c von cdi stehe

@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

Page 105: Warum ich so auf das c von cdi stehe

@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

Page 106: Warum ich so auf das c von cdi stehe

@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

Page 107: Warum ich so auf das c von cdi stehe

@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.

Page 108: Warum ich so auf das c von cdi stehe

@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

Page 109: Warum ich so auf das c von cdi stehe

@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

Page 110: Warum ich so auf das c von cdi stehe

@SvenRuppert 112/122

Cross Language Injection.. am Beispiel von Kotlin..

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

JAVA

Page 111: Warum ich so auf das c von cdi stehe

@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

Page 112: Warum ich so auf das c von cdi stehe

@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

Page 113: Warum ich so auf das c von cdi stehe

@SvenRuppert 115/122

CDI und TDD... kaskadierte MOCKS

Service A injected Service B injected Service C

Page 114: Warum ich so auf das c von cdi stehe

@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

Page 115: Warum ich so auf das c von cdi stehe

@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

Page 116: Warum ich so auf das c von cdi stehe

@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

Page 117: Warum ich so auf das c von cdi stehe

@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.

Page 118: Warum ich so auf das c von cdi stehe

@SvenRuppert 120/122

finally at amazon..

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

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

Page 119: Warum ich so auf das c von cdi stehe

<Thank You!>

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

www www.rapidpm.org

Page 120: Warum ich so auf das c von cdi stehe

www www.rapidpm.orggithub github.com/svenruppert