Reflection und Annotationen

Reflection-API

UML-Klassendiagramm erstellen

Unter http://yuml.me/diagram/scruffy/class/draw findet man ein Online-Programm, was aus Text ein UML-Diagram erzeugt. Spiele mit den Möglichkeiten in dem vom YUML gegebenen Texfeld.

YUML DiagrammYUML erzeugt die Grafiken auf dem Server. Die Grafik <img src="https://yuml.me/diagram/scruffy/class/[Wages]^-[Salaried], [Wages]^-[Contractor]" > .

Generiere für eine beliebige Klasse, von der nur der voll qualifizierte Name gegeben ist, so ein Diagram-Text, den man in die Textbox von Yuml kopieren kann.

  1. Das Diagramm soll den Typ und seine Basistypen (Oberklassen und implementierte Schnittstellen) zeigen.
  2. Das Diagramm soll rekursiv auch die Typen der Oberklassen mit aufführen.
  3. Nimm alle Attribute (ohne Typ!) und Operationen (ohne Rückgaben und Parameter) mit auf.

Lösung

Komponenten und Klassen

Eine Firma möchte Komponenten implementieren und auch anderen Anbietern die Möglichkeit geben, Komponenten zu entwickeln. Da das Einfügen neuer Komponenten möglichst einfach sein soll, sollen sie in ein Verzeichnis gestellt werden. Wird die Software neu gestartet, so soll sie automatisch die neuen Komponenten erkennen und einbinden.

Klassen dynamisch laden *

Man kann Klassen mit forName() nachladen, wenn man den Klassennamen kennt. Mit newInstance() kann man dann ein Exemplar der Klasse erzeugen. Ein Beispiel:

Class<?> clazz = Class.forName( "java.util.Date" );
Object o = clazz.newInstance();

Lade alle mathematischen Klassen im Verzeichnis und erzeuge ein Objekt von ihnen mit Hilfe der newInstance()-Methode. Mit toString() kann man erkennen, ob alles gut ging. Fange die entsprechenden Ausnahmen ab.

Übergebe dazu alle gefundenen Klassen von list() der Methode klasseLaden(), die das Objekt vom Typ MathOp zurückliefert.

Automatisch CSV-Dateien schreiben

In einer CSV-Datei werden die Einträge durch Semikolons getrennt, etwa so:

1;2;3
4;5;6

Schreibe eine statische Methode writeAsCsv(List<?> list, Writer out), die alle Objekte der Liste abläuft und per Reflection alle Bean-Getter aufruft und dann die Ergebnisse der Properites in den Ausgabestrom schreibt. So kann die Methode etwa wie folgt genutzt werden:

Point p = new Point( 1, 2 );
Point q = new Point( 3, 4 );
List<?> list = new ArrayList<Point>( Arrays.asList( p, q ) );
Writer out = new StringWriter();
writeAsCsv( list, out );
System.out.println( out );

Annotationen

Annotationen als Modifizierer

Wenn eine Annotation ein Modifizierer wie public, static oder final ist, welche Konsequenz hat das?

Markierungsannotationen

Mit EJB 3 ist es möglich, ohne XML-Konfigurationsdateien (aka Deployment-Deskriptor) Enterprise JavaBeans zu schreiben. Ein Beispiel:

// import javax.ejb.Stateless;
// import javax.ejb.Remote;

@Remote
@Stateless
public class CalculatorBean // implements Calculator
{
  public int add( int x, int y )
  {
    return x + y;
  }

  public int subtract( int x, int y )
  {
    return x - y;
  }
}

Definiere die dafür nötigen Annotations-Typen.

Elemente für Annotationen

Der Annotations-Typ @Stateless soll um Elemente erweitert werden.

  1. Definiere ein Element name vom Typ String. Es soll standardmäßig auf "" stehen.
  2. Definiere eine neue Aufzählung TransactionManagementType (nicht im Inneren von @Stateless), mit den Elementen CONTAINER und BEAN. @Stateless soll ein Element transactionManagement bekommen, welches standardmäßig auf CONTAINER steht.

Erzeuge eine neue Annotation @Stateful. Kopiere die Elemente aus @Stateless, denn es sind die selben!

@Stateless/@Stateful annotieren

  1. Welcher @Target ist bei @Stateless/@Stateful sinnvoll?
  2. Erzeuge eine neue Annotation @Remove, welches nur auf Methoden angewendet werden darf. Es soll ein Element boolean retainIfException() default false; definieren.
  3. Siehe in der EJB 3 Spezifikation im Kapitel "10.1.1/10.1.2 Stateless/Stateful Session Beans" nach, ob und wie @Retention gesetzt ist.

Zugriff auf die Annotationen

Teste, ob der Typ CalculatorBean eine Annotation trägt. Erfrage, welche Annotationen mit den Klassen verbunden sind.

Lösung CalculatorBean, GetAnnotationsDemo, Remote, Stateful, Stateless, TransactionManagementType

Annotationen für Testfälle (15 Minuten)

Was macht die folgende Klasse? Bringe das Beispiel mit einem neuen Annotations-Typ @Test zum Laufen.

import java.lang.reflect.Method;

public class TestRunner {
 static void executeTests( String className ) {
  try {
   executeTests( Class.forName(className) );
  }
  catch ( ClassNotFoundException e ) {
   e.printStackTrace();
  }
 }

 static void executeTests( Class<?> clazz ) {
  try {
   Object testObject = clazz.newInstance();
   Method[] methods = testObject.getClass().getDeclaredMethods();

   for ( Method amethod : methods )  {
    Test testAnnotation = amethod.getAnnotation( Test.class );
    if ( testAnnotation != null ) {
     System.out.print( testAnnotation.value() + " : " );
     String result = invoke( amethod, testObject );
     System.out.println( result );
    }
   }
  }
  catch ( Exception e ) {
   e.printStackTrace();
  }
 }

 static String invoke( Method m, Object o ) {
  try {
   m.invoke( o, (Object[]) null );
   return "passed";
  }
  catch ( Exception x ) {
   return "failed";
  }
 }

 public static void main( String[] args ) {
  executeTests( "ClassToTest" );
//  executeTests( ClassToTest.class );
 }
}