Software Entwicklung II: Reflection PDF

Summary

Diese Vorlesung des FH Münster behandelt die Thematik der Reflection in der Softwareentwicklung. Die Folien decken Konzepte wie dynamische Polymorphie, Annotationen, Objektserialisierung und Dynamische Proxys ab. Zudem werden die Klassen ‘Class’, ‘Constructor’, ‘Method’ und ‘Field’ im Detail besprochen.

Full Transcript

Inhalt 1. Einführung Einleitung 2. Grundlagen Java Reflection 3. Java Database Connectivity (JDBC) Analyse der Struktur...

Inhalt 1. Einführung Einleitung 2. Grundlagen Java Reflection 3. Java Database Connectivity (JDBC) Analyse der Struktur Zugriff, Instanziierung und Aufruf 4. XML-Technologien Arrays 5. Reflection Proxy 6. Annotationen 7. Objektserialisierung 8. JavaBeans 9. Jakarta Persistence API (JPA) Prof. Dr. Claus Grewe Software-Entwicklung II 207 Reflection Einleitung Übersetzung eines C-Programms ▪ C ist eine prozedurale Sprache Compiler legt zur Kompilierzeit die Programmelemente fest Bindung der Datentypen: Größe, Dimension, Sichtbarkeit etc. Static Dispatch: Zuordnung des Methodenaufrufs zum Methodenrumpf Objektmodul x.o Aufruf von Methoden x.c in Objektmodul y.o Aufruf von Methoden in Objektmodul z.o Lauffähiges Programm Objektmodul y.o Aufruf von Methoden y.c in Objektmodul x.o Linker Objektmodul z.o z.c Der Linker bindet die Module zusammen. Hierzu Compiler werden z. B. symbolische Methodennamen in konkrete Adressen übersetzt. Prof. Dr. Claus Grewe Software-Entwicklung II 208 Reflection Einleitung Übersetzung eines C-Programms ▪ Statische bzw. frühe Bindung (Static / Early Binding) Fixierung der Datentypen und Aufrufe zur Kompilierzeit Compiler kann hochoptimierten Binärcode generieren ▪ Nachteile unterstützt keinen dynamischen Polymorphismus kaum Spielraum für generische Entwicklungswerkzeuge und konfigurierbare Anwendungen Prof. Dr. Claus Grewe Software-Entwicklung II 209 Reflection Einleitung Ziele ▪ Komposition von Komponenten zu Applikationen dynamische Zusammenfügung zuvor unbekannter Komponenten (z. B. Dependency Injection) Nutzung von Funktionalität, die erst zur Laufzeit bekannt ist späte Bindung von Abhängigkeiten ▪ Aufruf von Funktionalität in entfernten Adressräumen dortige Objekte sind häufig a priori unbekannt Kernidee der Remote Method Invocation (RMI) und der (Enterprise) JavaBeans Prof. Dr. Claus Grewe Software-Entwicklung II 210 Reflection Einleitung Unterstützung dynamischer Polymorphie ▪ Betrachtung: Aufruf einer öffentlichen Java-Methode die konkrete Methode wird zur Laufzeit dynamisch aufgelöst hierzu wird mit Hilfe der Referenz der konkrete Instanztyp bestimmt Dynamic Single Dispatch List list = List.of(new Circle(10.0), new Square(1.5)); polymorpher Aufruf for (Shape s : list) { s.draw(); } Der Typ der Variablen Der Variablen können alle Objekte zugewiesen beschreibt ein Interface werden, die das Interface implementieren Prof. Dr. Claus Grewe Software-Entwicklung II 211 Reflection Einleitung Unterstützung dynamischer Polymorphie ▪ Dynamische bzw. späte Bindung (Dynamic/Late Binding) Bindung zur Ausführungszeit ! Java nutzt weitgehend die dynamische Bindung für Methoden und Variablen. Ausnahme bilden jene Methoden und Variablen, die mit static, private oder final deklariert wurden. Diese werden bereits zur Kompilierzeit gebunden. ▪ Run-Time Type Identification (RTTI) Prof. Dr. Claus Grewe Software-Entwicklung II 212 Reflection Einleitung Run-Time Type Identification (RTTI) ▪ Ermittlung der Klassenzugehörigkeit mittels der Basisreferenz Basis des Downcastings sowie des instanceof-Operators stellt die Typkompatibilität sicher ! Der RTTI-Mechanismus unterstützt die späte Bindung überschriebener Methodenaufrufe. Javas strenge Typisierung verlangt darüber hinaus, dass alle Datentypen, die zur Laufzeit aufgelöst werden sollen, zur Kompilierzeit bekannt sein müssen. Die Klasse Student muss Student s = new Student(); dem Java-Compiler vorliegen! s.setName("Harry Hacker"); s.setStudentNumber("M665544");... String name = s.getName(); Prof. Dr. Claus Grewe Software-Entwicklung II 213 Reflection Einleitung Weitergehende Anforderungen ▪ Nutzung von Klassen, die dem Compiler nicht vorliegen mittels robuster Programmierschnittstelle ▪ Analyse des strukturellen Aufbaus von Modulen, Packages, Klassen und Instanzen reflexive Erkundung von Metainformationen (Introspection) zu Konstruktoren, Methoden, Felder und Parametern ▪ Initiierung von Instanzen sowie Modifikation des Zustandes Prof. Dr. Claus Grewe Software-Entwicklung II 214 Reflection Einleitung Umsetzung ▪ Reflection In der Literatur werden die Begriffe Reflection und Introspection teilweise synonym benutzt. reflexive Programmierung Andere Autoren verweisen darauf, dass Introspection primär die reflexive Erkundung beschreibt. verfügbar in verschiedenen Hochsprachen z. B. #, J v pt, J v , … ▪ Adressierung von Code-Strukturelementen mittels Namen Prof. Dr. Claus Grewe Software-Entwicklung II 215 Reflection Einleitung Beispiel in Java Die Klasse Student muss zur Student s = new Student(); … Kompilierzeit vorliegen. ▪ Statische Typprüfung s.setName("Harry Hacker"); s.setStudentNumber("M665544"); … durch den Compiler String name = s.getName(); deklarierte Methoden und Konstruktor Argumente try { Class clazz = Class.forName( "Student" ); ▪ Reflexiver Ansatz Object s = clazz.getDeclaredConstructor().newInstance(); … Method m1 = clazz.getMethod("setName", String.class); Laufzeitauswertung m1.invoke(s, "Harry Hacker"); Method m2 = clazz.getMethod("setStudentNumber", String.class); dynamische Typprüfung m2.invoke(s, "M665544"); … Method m3 = clazz.getMethod("getName"); Object name = m3.invoke(s); } catch (InstantiationException | IllegalAccessException | Die Klasse Student muss zur Kompilierzeit NoSuchMethodException | SecurityException | nicht vorliegen. Allerdings entfallen dadurch IllegalArgumentException | InvocationTargetException | auch die statischen Typprüfungen. ClassNotFoundException e ) { Reflection-Einsatz // exception handling … Metainformationen } weitere Argumente Prof. Dr. Claus Grewe Software-Entwicklung II 216 Inhalt 1. Einführung Einleitung 2. Grundlagen Java Reflection 3. Java Database Connectivity (JDBC) Analyse der Struktur Zugriff, Instanziierung und Aufruf 4. XML-Technologien Arrays 5. Reflection Proxy 6. Annotationen 7. Objektserialisierung 8. JavaBeans 9. Jakarta Persistence API (JPA) Prof. Dr. Claus Grewe Software-Entwicklung II 217 Reflection Java Reflection Reflection ▪ Core Reflection API mächtiger Laufzeitmechanismus typsicheres und gesichertes API im Package java.lang.reflect Basis für Objektserialisierung und Remote Method Invocation (RMI) inklusive Enums und Records ▪ Mögliche Operationen Einsicht in den strukturellen Aufbau von Modulen, Packages, Klassen und Objekten Instanziierung von Klassen und Modifikation von Objektzuständen Hinweise Reflection wurde im JDBC-Kontext schon eingesetzt, um den JDBC-Treiber nachzuladen. Reflection bildet eine Grundlage für JavaBeans und somit auch für die Enterprise JavaBeans. Prof. Dr. Claus Grewe Software-Entwicklung II 218 Reflection Java Reflection Jedes Java-Objekt besitzt in seinem Object Header eine Klasse Object Referenz (klass pointer), die auf die typspezifische Beschreibung der Klasse im Metaspace verweist. ▪ Klasse Object ist die Wurzel der gesamten Klassenhierarchie alle Klassen in Java erben von java.lang.Object mittels der Methode Object.getClass() besitzt jedes beliebige Objekt die Fähigkeit, ein Klassenobjekt zu liefern // Auflösung des Class-Objektes für eine Klasse Java Compiler identifiziert das Class intClazz = Integer.class; notwendige Class-Objekt // Dynamische Auflösung zur Laufzeit für ein Objekt Double dblObj = Double.valueOf( 1.0 ); Einschränkung auf Class clazz = Class.forName("org.apache.derby.jdbc.ClientDriver"); } catch (ClassNotFoundException e) {... } Prof. Dr. Claus Grewe Software-Entwicklung II 220 Reflection Java Reflection Einige Methoden der Klasse Class Methoden der Klasse Class Erläuterungen Class forName(String className) liefert das Class-Objekt zum gegebenen Klassennamen Class[] getInterfaces() liefert alle Interfaces der Klasse und deren Superklassen in Form von Class-Objekten String getName() gibt den Namen der Klasse inklusive des Packages zurück Constructor[] getConstructors() liefert ein Array der öffentlichen Konstruktoren der Klasse und deren Superklassen Constructor[] liefert ein Array mit allen Konstruktoren, welche die Klasse selbst definiert getDeclaredConstructors() Method[] getMethods() liefert ein Array der öffentlichen Methoden der betrachteten Klasse und deren Superklassen Method[] getDeclaredMethods() liefert ein Array mit allen Methoden, welche die Klasse selbst definiert Field[] getFields() liefert ein Array der öffentlichen Felder der betrachteten Klasse und deren Superklassen Field[] getDeclaredFields() liefert ein Array mit allen Feldern, welche die Klasse selbst definiert int getModifiers() liefert die in einer ganzen Zahl bitkodierten Modifikatoren der Klasse oder des Interfaces. Jedem Modifikator ist eine eindeutige Bitposition zugeordnet, s. java.lang.reflect.Modifier boolean isInstance(Object obj) prüft, ob das gegebene Objekt obj zuweisungskompatibel ist zu einem Objekt, das durch das Class- Objekt beschrieben wird. Die Funktionalität ist mit der instanceof-Prüfung vergleichbar. … … Prof. Dr. Claus Grewe Software-Entwicklung II 221 Zusatzfolie Reflection Java Reflection Die Klasse Class gibt es seit Java 1.0, das Klasse Class Java Collections API erst seit Java 1.2. t t t t t v t t t t p p t t t p t p t t t t p t t p t t t. t t t. t t t t t. t t Die Methoden getX() liefern alle t t t. öffentlichen X (z. B. Felder oder Methoden) t t t ,p t p t. t der betrachteten Klasse und deren t t t p t p t. t t Superklassen. t t t. t p t t. p t t t t. t Die Methoden getDeclaredX() liefert t t t t. t t ausschließlich die in der jeweilig t t t. betrachteten Klasse deklarierten X t t t ,p t p t. t (z. B. Felder oder Methoden). t t t p t p t. t t... Prof. Dr. Claus Grewe Software-Entwicklung II 222 Zusatzfolie Reflection Java Reflection Beispiel: Nutzung der Klasse Class try { // generiert ein Class-Objekt anhand des vollqualifizierten Namens einer Klasse Class clazz = Class.forName("java.lang.Double"); // holte die Beschreibung der Superklasse Class superClazz = clazz.getSuperclass(); System.out.println("Klasse [" + clazz.getName() + "]"); if (superClazz != null) { System.out.println("erweitert die Klasse [" + superClazz.getName() + "]"); } } catch (ClassNotFoundException e) { e.printStackTrace(); }... ▪ Ausgabe Klasse [java.lang.Double] erweitert die Klasse [java.lang.Number] Prof. Dr. Claus Grewe Software-Entwicklung II 223 Expertenfolie Reflection Java Reflection Alternative zu Reflection in Java JEP-416 (Java 18) befasst sich mit der Neuimplementierung von Reflection auf Basis der Method Handles ▪ Klassen MethodHandle und MethodType seit Java 7 im Package java.lang.invoke unterstützt dynamische Skriptsprachen, die auf der JVM basieren ▪ Methoden-Handle typisierter, direkt ausführbarer Verweis auf eine zugrunde liegende Methode, einen Konstruktor bzw. ein Feld Zugriff erfolgt u. U. schneller als bei Reflection, da die Zugriffsprüfung im Augenblick der Erstellung erfolgt und nicht zur Laufzeit allerdings sind die Anforderungen auch strenger Prof. Dr. Claus Grewe Software-Entwicklung II 224 Inhalt 1. Einführung Einleitung 2. Grundlagen Java Reflection 3. Java Database Connectivity (JDBC) Analyse der Struktur Zugriff, Instanziierung und Aufruf 4. XML-Technologien Arrays 5. Reflection Proxy 6. Annotationen 7. Objektserialisierung 8. JavaBeans 9. Jakarta Persistence API (JPA) Prof. Dr. Claus Grewe Software-Entwicklung II 225 Reflection Analyse der Struktur Klassen Constructor, Method und Field ▪ Repräsentation der Konstruktoren, Methoden und Felder t t t t t t t t t t t......... t t Stellt Informationen zu einem Klassenkonstruktor t t t bereit und erlaubt den Zugriff auf diesen. tB t tB t t t t t t t t t t t t t t t t t t t t t t t t p t t t t t t v t , t...... t t, v t v...... tB t, z v tB t t, t v t t, v t t t, t v Abfrage und Modifikation Gestattet die Analyse von Klassen t t t, t v von Feldwerten soweit und Methodenaufrufe in Objekten. t t, v t t t, t v dieses gestattet ist. t t, v...... Prof. Dr. Claus Grewe Software-Entwicklung II 226 Reflection Analyse der Struktur Klassen Constructor, Method und Field ▪ Alle drei Klassen implementieren das Member-Interface B t t t... t t t v t t t t t t t... t t t t t t t t t t t t...... Methoden des Interfaces Member Erläuterungen String getName() liefert den Namen des Konstruktors, der Methode bzw. des Feldes int getModifiers() stellt alle Modifikatoren des Konstruktors, der Methode bzw. des Feldes bereit die Modifikatoren sind bitweise kodiert (ODER-Verknüpfung) → Analyse mittels der Methoden der Klasse java.lang.reflect.Modifier Prof. Dr. Claus Grewe Software-Entwicklung II 227 Reflection Analyse der Struktur Klassen Constructor, Method und Field ▪ Class[] Constructor.getParameterTypes() ▪ Class[] Method.getParameterTypes() liefern alle Parameter des Konstruktors bzw. der Methode in der korrekten Reihenfolge zurück jedes Array-Element repräsentiert dabei die Klasse des korrespondierenden formalen Arguments Parametertypen werden als Class-Objekte dargestellt ▪ Class Method.getReturnType() liefert den Parametertyp des Rückgabewertes einer Methode Prof. Dr. Claus Grewe Software-Entwicklung II 228 Zusatzfolie Reflection Analyse der Struktur Beispiel: Nutzung der Constructor-Klasse Class clazz = Class.forName("java.lang.Double"); ▪ Beispiele Constructor[] constructors = für java.lang.Double clazz.getConstructors(); public java.lang.Double(java.lang.String) // Nimm den ersten Konstruktor Constructor c = constructors; // Hole den Namen und die Parameter für java.util.Date String name = c.getName(); Class[] paramTypes = c.getParameterTypes(); public java.util.Date(long) // Gib die Modifikatoren und den Namen aus System.out.print( Modifier.toString( c.getModifiers() ) ); System.out.print( " " + name + "("); für java.net.URL // Gib alle Parameter aus for (int j = 0; j < paramTypes.length; j++) { public java.net.URL(java.lang.String, if (j > 0) System.out.print(", "); System.out.print(paramTypes[j].getName()); java.lang.String, } java.lang.String) System.out.println(")"); Prof. Dr. Claus Grewe Software-Entwicklung II 229 Zusatzfolie Reflection Analyse der Struktur Beispiel: Nutzung der Method-Klasse Class clazz = Class.forName("java.lang.Double"); ▪ Beispiele Method[] methods = für java.lang.Double clazz.getDeclaredMethods(); public boolean equals(java.lang.Object) Method m = methods; Class retType = m.getReturnType(); Class[] paramTypes = m.getParameterTypes(); System.out.print( Modifier.toString( m.getModifiers() )); für java.sql.DriverManager System.out.print(" " + retType.getName() + " " + m.getName() + "("); public static synchronized void for (int j = 0; j < paramTypes.length; j++) { deregisterDriver(java.sql.Driver); if (j > 0) System.out.print(", "); System.out.print(paramTypes[j].getName()); } System.out.println(") "); Prof. Dr. Claus Grewe Software-Entwicklung II 230 Zusatzfolie Reflection Analyse der Struktur Beispiel: Nutzung der Field-Klasse Class clazz = Class.forName("java.lang.Double"); ▪ Beispiele Field[] fields = clazz.getFields(); für java.lang.Double Field f = fields; public static final double POSITIVE_INFINITY String fieldName = f.getName(); Class type = f.getType(); System.out.print( Modifier.toString( f.getModifiers() )); für java.net.URL System.out.println(" " + type.getName() + " " + fieldName); Prof. Dr. Claus Grewe Software-Entwicklung II 231 Reflection Analyse der Struktur Umgang mit den primitiven Datentypen Primitive Wrapper- Datentypen Klassen ▪ Wrapper-Klasse boolean Boolean dient der objektorientierten Darstellung eines primitiven Datentyps char Character byte Byte kapselt einen primitiven Datentyp in einer objektorientierten Hülle short Short stellt zusätzliche Methoden und Konstanten bereit int Integer long Long float Float double Double Integer a = 5; // autoboxing int b = a; // autounboxing Integer c = Integer.valueOf(10); // Fabrikmethode double d = c.doubleValue(); // Hilfsfunktion short e = Short.MIN_VALUE; // Konstante Prof. Dr. Claus Grewe Software-Entwicklung II 232 Reflection Analyse der Struktur Umgang mit den primitiven Datentypen Typ Klassenobjekt ▪ Konstante TYPE der Wrapper-Klassen boolean Boolean.TYPE char Character.TYPE beinhaltet statisches Class-Objekt byte Byte.TYPE dienen der Darstellung des primitiven Datentyps in Reflection short Short.TYPE int Integer.TYPE Literal.class liefert für primitive Datentypen die Konstante long Long.TYPE float Float.TYPE double Double.TYPE void Void.TYPE // TYPE repräsentiert den primitiven Datentyp assert (Byte.TYPE == byte.class); Beschreibt den „ “ Rückgabetyp void. // Class-Objekt der Wrapper-Klasse entspricht nicht // dem Class-Objekt des primiten Datentyps assert (Integer.TYPE != Integer.class); Prof. Dr. Claus Grewe Software-Entwicklung II 233 Expertenfolie Reflection Analyse der Struktur Erweiterungen ▪ Parameter-Klasse liefert weitere Metainformationen zu Übergabenparameter in Konstruktoren und Methoden z. B. die Namen der Variablen allerdings muss der Java Compiler explizit aufgefordert werden, die zusätzliche Information im Bytecode zu speichern! ▪ Modularisierung (seit Java 9) die freien Zugriffsmöglichkeiten via Reflection bleiben innerhalb eines Moduls erhalten modulübergreifend müssen die Sichtbarkeitsregeln beachtet werden Prof. Dr. Claus Grewe Software-Entwicklung II 234 Inhalt 1. Einführung Einleitung 2. Grundlagen Java Reflection 3. Java Database Connectivity (JDBC) Analyse der Struktur Zugriff, Instanziierung und Aufruf 4. XML-Technologien Arrays 5. Reflection Proxy 6. Annotationen 7. Objektserialisierung 8. JavaBeans 9. Jakarta Persistence API (JPA) Prof. Dr. Claus Grewe Software-Entwicklung II 235 Reflection Zugriff, Instanziierung und Aufruf Zugriff auf laufende Objekte ▪ Beobachtung und Modifikation von Instanzobjekten anhand der bereitgestellten Strukturinformationen wird z. B. ein Feld gewählt und der aktuelle Wert ausgelesen bzw. modifiziert Aufruf von Methoden ▪ Reflection berücksichtigt Javas Zugriffskontrolle d. h. auf private-deklarierte Felder kann nicht unmittelbar zugegriffen werden bei entsprechender Berechtigung kann dieser Schutzmechanismus übersteuert werden hilfreich für Java-eigene Dienste wie Serialisierung und für Entwicklungswerkzeuge Prof. Dr. Claus Grewe Software-Entwicklung II 236 Reflection Zugriff, Instanziierung und Aufruf Zugriff und Modifikation ▪ Methoden der Klasse Field Methode der Klasse Field Erläuterungen Object get(Object obj) liest das betreffende Feld des referenzierten Objektes aus und liefert den Wert als Object zurück. Die Methode dient zum Lesen von Referenztypen. PTYPE getPTYPE(Object obj) liest das betreffende Feld des referenzierten Objektes aus und liefert den gelesenen Wert zurück. Die Methode liest zum Lesen der Primitivtypen void set(Object obj, Object value) setzt den Wert value der Referenzvariablen im Instanzobjekt obj ist das Feld mit dem Modifikator static als Klassenvariable gekennzeichnet, so kann obj mit null vorgegeben werden void setPTYPE(Object obj, PTYPE value) setzt den Wert value eines Primitivtyps in das Feld des Instanzobjektes obj ist das Feld mit dem Modifikator static als Klassenvariable gekennzeichnet, so kann obj mit null vorgegeben werden PTYPE steht für die in Java vorhandenen Primitivtypen long, int, char etc. Prof. Dr. Claus Grewe Software-Entwicklung II 237 Reflection Zugriff, Instanziierung und Aufruf Zugriff auf laufende Objekte ▪ Beispiel Employee emp = new Employee("Larry Leisure", 40000, LocalDate.of(2022, Month.JUNE, 1)); Class clazz = emp.getClass(); try { Field f = clazz.getDeclaredField("name"); System.out.println( f.get(emp) ); } catch(...) { // es müssen mehrere Exceptions behandelt werden // handle exception... } ▪ Employee-Klasse Ausschließlich die Instanzvariable public class Employee { name ist hier public! public String name; private double salary; private LocalDate hireDate; … Eine Record-Klasse beinhaltet ausschließlich mit } private gekennzeichnete Felder. Prof. Dr. Claus Grewe Software-Entwicklung II 238 Reflection Zugriff, Instanziierung und Aufruf Instanziierung und Methodenaufruf ▪ Methoden zur Instanziierung und zum Methodenaufruf Methode der Klasse Constructor Erläuterungen T newInstance(Object... initargs) ruft einen parameterbehafteten bzw. den parameterlosen Konstruktor der jeweiligen Klasse auf T newInstance() liefert das instanziierte Objekt vom Typ T zurück Methode der Klasse Method Erläuterungen Object invoke(Object obj, ruft eine Methode des Objektes obj mit den entsprechenden Object... args) Parametern auf liefert das Resultat des Methodenaufrufes als Object zurück Prof. Dr. Claus Grewe Software-Entwicklung II 239 Reflection Zugriff, Instanziierung und Aufruf Instanziierung ▪ Um einen passenden Konstruktor zu finden, kann 1. die gesamte Liste aller verfügbaren bzw. sichtbaren Konstruktoren durchsucht und ausgewertet oder 2. der gesuchte Konstruktor gezielt spezifiziert werden Constructor Class.getConstructor(Class... parameterTypes) Beispiel: Konstruktor java.awt.Point(int x, int y) Class clazz = Class.forName("java.awt.Point"); Constructor constructor = clazz.getConstructor(Integer.TYPE, Integer.TYPE); Object p = constructor.newInstance(100, 200); Hier muss die TYPE-Konstante der Wrapper-Klasse für den primitiven Datentypen int verwendet werden. Prof. Dr. Claus Grewe Software-Entwicklung II 240 Reflection Zugriff, Instanziierung und Aufruf Methodenaufruf ▪ Methodenaufruf die aufzurufende Methode kann näher spezifiziert und vom Class-Objekt bereitgestellt werden Method getMethod(String name, Class... parameterTypes) Beispiel 1: Point.setLocation(int x, int y) Method m1 = clazz.getMethod("setLocation", Integer.TYPE, Integer.TYPE); m1.invoke( p, 111, 222 ); p ist ein instanziiertes Point-Objekt Beispiel 2: Point.setLocation(Point p) Method m2 = clazz.getMethod("setLocation", new Class[] { Point.class } ); m2.invoke( p, new Point (33, 44) ); alternativ: Array von Class-Objekten Prof. Dr. Claus Grewe Software-Entwicklung II 241 Inhalt 1. Einführung Einleitung 2. Grundlagen Java Reflection 3. Java Database Connectivity (JDBC) Analyse der Struktur Zugriff, Instanziierung und Aufruf 4. XML-Technologien Arrays 5. Reflection Proxy 6. Annotationen 7. Objektserialisierung 8. JavaBeans 9. Jakarta Persistence API (JPA) Prof. Dr. Claus Grewe Software-Entwicklung II 242 Reflection Arrays Arrays ▪ Arrays sind außergewöhnliche Objekte in Java sie besitzen keine explizite Klassendefinition und keinen Konstruktor sie sind grundsätzlich eindimensional, können aber als Komponententyp erneut ein Array beinhalten String[][] str2DArr = {{"a", "b", "c"}, {"d", "e", "f"}}; // 2D array String[] str1DArr0 = str2DArr; // {a, b, c} String[] str1DArr1 = str2DArr; // {d, e, f} ▪ Klasse java.lang.reflect.Array Methoden zum Erzeugen von ein- und mehrdimensionalen Arrays Prof. Dr. Claus Grewe Software-Entwicklung II 243 Reflection Arrays PTYPE steht auch hier für die in Java vorhandenen Die Klasse Array Primitivtypen long, int, char etc. ▪ Wichtige Array-Methoden Methoden der Klasse java.lang.reflect.Array Erläuterungen Object get(Object array, int index) liefert die indizierte Komponente aus dem Array zurück PTYPE getPTYPE(Object array, int index) liefert die indizierte Komponente aus dem Array als Primitivtyp PTYPE void set(Object array, überschreibt die indizierte Komponente im Array mit dem gegebenen Objekt newValue int index, Object newValue) void setPTYPE(Object array, überschreibt die indizierte Komponente im Array mit dem gegebenen Wert newValue vom int index, PTYPE newValue) Primitivtyp PTYPE int getLength(Object array) liefert die Länge des Arrays zurück Object newInstance( kreiert ein neues eindimensionales Array für den spezifizierten Komponententyp Class componentType, int length) componentType und der gegebenen Länge Object newInstance( kreiert ein neues mehrdimensionales Array für den spezifizierten Komponententyp Class componentType, int... dimensions) componentType und die gegebenen Dimensionen Generell kann in Java anstelle einer variablen Argumentenliste auch ein Array übergeben werden, hier also int[] Prof. Dr. Claus Grewe Software-Entwicklung II 244 Zusatzfolie Reflection Arrays Beispiele: Klasse Array ▪ Beispiele Object ar = Array.newInstance(Integer.TYPE, 3); int[] iar = (int[]) ar; Erzeugung eines int[]-Arrays der Länge 3 assert (iar.length == 3); Object ar = Array.newInstance( String.class, new int[] {3, 5}); String[][] sar = (String[][]) ar; Erzeugung eines String[][]-Arrays assert (sar.length == 3); assert (sar.length == 5); int[] ar = new int[] { 3, 2, 1 }; for (int i = 0; i < Array.getLength(ar); ++i) { Zugriff auf Arrays int v = Array.getInt(ar, i); Array.set(ar, i, Integer.valueOf(v * 2)); } // ar: {6, 4, 2} Prof. Dr. Claus Grewe Software-Entwicklung II 245 Reflection Arrays Arrays ▪ Untersuchung bestehender Arrays wie in Reflection üblich mittels der Class-Klasse Weitere Methoden der Klasse Class Erläuterungen boolean isArray() bestimmt, ob die Klasse ein Array-Klasse verkörpert Class getComponentType() liefert den Komponententyp des Arrays in Form eines Class Objektes ▪ Beispiel Point[] p = new Point; Class componentType = arrayClazz.getComponentType(); System.out.println("Component type: " + componentType.getName()); } Ausgabe: Component type: java.awt.Point Prof. Dr. Claus Grewe Software-Entwicklung II 246 Inhalt 1. Einführung Einleitung 2. Grundlagen Java Reflection 3. Java Database Connectivity (JDBC) Analyse der Struktur Zugriff, Instanziierung und Aufruf 4. XML-Technologien Arrays 5. Reflection Proxy 6. Annotationen 7. Objektserialisierung 8. JavaBeans 9. Jakarta Persistence API (JPA) Prof. Dr. Claus Grewe Software-Entwicklung II 247 Reflection Proxy GoF-Entwurfsmuster: Proxy Definition Ein alternativer Name für Proxy Ein Proxy ist ein vorgelagertes Stellvertreterobjekt, das den Zugriff auf ein Objekt kontrolliert. lautet Surrogat. (in Anlehnung an [GHJ+11]) t Objektbasiertes Strukturmuster Der Client ruft Methoden des Proxys auf, der sie an ein Objekt weiterdelegiert. t t v t t z, t t t, p p t tz z Prof. Dr. Claus Grewe Software-Entwicklung II 248 Reflection Proxy Wozu dienen Proxys? Arten Erläuterungen Logger Proxy protokolliert die Methodenaufrufe Schutz-Proxy kontrolliert den Zugriff auf das reale Subject hilfreich, wenn das Originalobjekt über unterschiedliche Zugriffsrechte verfügt vgl. Firewall-Instanz im Netzwerk Remote Proxy Stellvertreter für ein Objekt in einem anderen Adressraum Routing von Aufrufen an entfernte Server Verbergung von Netzwerkverbindungen oder Anbindungsschnittstellen zu Legacy-Anwendungen Virtueller Proxy erzeugt teure Objekte auf Verlangen Transaktionaler Proxy Kapselung transaktionaler Kontexte Verlagerung der Transaktionsverwaltung in Proxy-Schicht Smart Reference Ersatz für einfache Referenzen kann zusätzliche Aktionen durchführen, wenn auf das Objekt zugegriffen wird, z. B. Validierungen Trennung der Geschäftslogik von logischen Aspekten → Ansätze der aspektorientierten Programmierung (AOP) erkennbar Prof. Dr. Claus Grewe Software-Entwicklung II 249 Reflection Proxy Proxy ▪ Proxys stehen zwischen der aufrufenden und der aufgerufenen Methode Proxy-Klassen werden zur Laufzeit dynamisch kreiert und instanziiert ▪ Dynamischer Proxy (Dynamic Proxy) implementiert eine Liste von zur Laufzeit spezifizierten Interfaces die konkreten Methoden müssen vom Entwickler nicht realisiert werden alle Methodenaufrufe der spezifizierten Interfaces werden an eine generische Behandlungsmethode im Invocation Handler delegiert Prof. Dr. Claus Grewe Software-Entwicklung II 250 Reflection Proxy Dynamischer Proxy ▪ Eigenschaften eines dynamischen Proxy-Objekts erweitert die Klasse java.lang.reflect.Proxy ist public final und nicht abstrakt der Name einer kreierten Proxy-Klasse beginnt mit $Proxy Methoden der Klasse java.lang.reflect.Proxy Erläuterungen public static Object newProxyInstance( erstellt ein Proxy-Objekt, welches die spezifizierten Interfaces implementiert und durch ClassLoader loader, den gegebenen Classloader bereitgestellt wird. Der Proxy besitzt einen Invocation Class[] interfaces, Handler. InvocationHandler h) public static prüft, ob die spezifizierte Klasse cl eine dynamisch generierte Proxy-Klasse ist. boolean isProxyClass(Class cl) Prof. Dr. Claus Grewe Software-Entwicklung II 251 Reflection Proxy Dynamischer Proxy ▪ Jeder dynamische Proxy besitzt einen Invocation Handler dieser wird bei der Kreierung des Proxys als Parameter übergeben der Invocation Handler implementiert das Interface java.lang.reflect.InvocationHandler // Erstellung eines Invocation Handlers InvocationHandler handler = new MyInvocationHandler(myParams); // Übergabe des Handlers an den Proxy Object proxy = Proxy.newProxyInstance(null, new Class[] { Comparable.class }, handler); Der Classloader ist relevant für das Sicherheitsmodell; Bereitstellung des Liste der Interfaces, hier das im lokalen Kontext kann null für den Default-CL gewählt werden. Invocation Handlers Comparable-Interface Prof. Dr. Claus Grewe Software-Entwicklung II 252 Reflection Proxy Dynamischer Proxy ▪ Interface InvocationHandler Methode des Interfaces Erläuterungen java.lang.reflect.InvocationHandler Object invoke( Object proxy, verarbeitet die an den Proxy gerichteten Methodenaufrufe Method method, und liefert die Methodenresultate zurück. Object[] args ) ▪ Delegation ruft die Anwendung eine Interface-Methode des Proxys auf, so wird der Methodenaufruf an invoke(…) weitergereicht anhand der Parameter können sowohl die aufgerufene Methode als auch deren Übergabeparameter ausgewertet werden der Invocation Handler implementiert die Reaktionen des Proxys auf die einzelnen Methodenaufrufe Prof. Dr. Claus Grewe Software-Entwicklung II 253 Zusatzfolie Reflection Proxy Beispiel: Logger Proxy ▪ Ein einfacher Taschenrechner public interface Calculator { public int add(int s1, int s2); } public class CalculatorImpl implements Calculator { @Override public int add(int s1, int s2) { int sum = s1 + s2; System.out.printf("CalculatorImpl.add(): [%d] + [%d] = [%d]%n", s1, s2, sum); return sum; } } Prof. Dr. Claus Grewe Software-Entwicklung II 254 Zusatzfolie Reflection Proxy Beispiel: Logger Proxy ▪ Nutzung des Taschenrechners public class TestCalculator { public static void main(String[] args) { t t t t t p Calculator calc = new CalculatorImpl(); , int result = calc.add(1, 2); , } } ▪ Aufgabe: Erweiterung um einen Logger Proxy der Taschenrechner soll mittels eines Proxys vor und nach dem Aufruf der add(…)-Methode die Übergabeparameter und Ergebnisse ausgeben Prof. Dr. Claus Grewe Software-Entwicklung II 255 Zusatzfolie Reflection Proxy Beispiel: Logger Proxy ▪ Realisierung des Invocation Handlers public class LoggerProxy implements InvocationHandler { private Object realSubject; // logic of the real subject public LoggerProxy(Object realSubject) { Dem Konstruktor wird ein Objekt übergeben, das die this.realSubject = realSubject; implementierte Bearbeitungslogik beinhaltet } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String proxyName = proxy.getClass().getName(); System.out.printf("LoggerProxy.invoke(%s): before call of [%s] with %s%n", proxyName, method.getName(), Arrays.toString(args)); Der Proxy ruft die implementierte // call target implementation Bearbeitungslogik auf. Object result = method.invoke(realSubject, args); System.out.printf("LoggerProxy.invoke(%s): method [%s] ends with [%s]%n", proxyName, method.getName(), result.toString() ); return result; } } Prof. Dr. Claus Grewe Software-Entwicklung II 256 Zusatzfolie Reflection Proxy Beispiel: Logger Proxy ▪ Einsatz des Logger Proxys public class TestCalculator { public static void main(String[] args) { Calculator calc = new CalculatorImpl(); // Kreierung des Proxys Calculator calcProxy = (Calculator) Proxy.newProxyInstance(calc.getClass().getClassLoader(), calc.getClass().getInterfaces(), new LoggerProxy(calc)); result = calcProxy.add(1, 2); } } Der generische Proxy delegiert den Aufruf an die reale Implementierung weiter Ausgaben des Programms: LoggerProxy.invoke($Proxy0): before call of [add] with [1, 2] CalculatorImpl.add(): + = LoggerProxy.invoke($Proxy0): method [add] ends with Prof. Dr. Claus Grewe Software-Entwicklung II 257 Zusatzfolie Reflection Proxy Beispiel: Logger Proxy ▪ Einsatz des Logger Proxys t t t t v t t p , v p , t , , , , v p , t , , , Implementierung des Interfaces Calculator. Prof. Dr. Claus Grewe Software-Entwicklung II 258 Reflection Proxy Lokale Objekte ▪ Identität, Lebenszyklus und Zustand alle Objekte befinden sich in einem gemeinsamen Adressraum Objekte und deren Methoden sind lokal bekannt Zugriff mittels lokaler Objektreferenzen Erreichbarkeit wird durch Modifikatoren gesteuert ▪ Nachteile Subsysteme sind von außen nicht direkt nutzbar begrenzte Ressourcen Hang zu monolithischen Strukturen Prof. Dr. Claus Grewe Software-Entwicklung II 259 Reflection Proxy Verteilte Objekte ▪ Idee: Räumliche Verteilung von Objekten Identität, Lebenszyklus, Zustand und Ort Ausführung in verschiedenen Adressräumen Methodenaufrufe, Parameter- und Ergebnistransporte erfolgen über das Netzwerk ▪ Client/Server-Architekturstil vgl. Webanwendungen und lokale Methodenaufrufe Prof. Dr. Claus Grewe Software-Entwicklung II 260 Reflection Proxy Verteilte Objekte ▪ Neue Herausforderungen Adressierung, Auffinden und Bereitstellung entfernter Objekte Heterogenität der Plattformen und Sprachen zahlreiche neue potenzielle Fehlerquellen durch das Netzwerk subtile Unterschiede zwischen lokalen und entfernten Objekten Prof. Dr. Claus Grewe Software-Entwicklung II 261 Reflection Proxy Remote Proxy ▪ Generischer Ansatz mit Proxys entfernter Methodenaufruf wird an ein lokales Proxy-Objekt gerichtet Proxys implementieren die Schnittstelle des entfernten Server-Objektes Proxys verbergen die Netzkommunikation und den Transport von Daten t t t v v t t t v t Prof. Dr. Claus Grewe Software-Entwicklung II 262 Expertenfolie Reflection Proxy Ablauf in Javas RMI-Architektur Server Proxy t t t t t t p t t v t t v t t z t p t p t p t t t t t Client Proxy v , v t p t v v v , v t p t p t p Prof. Dr. Claus Grewe Software-Entwicklung II 263 Inhalt 1. Einführung Einleitung 2. Grundlagen Annotationen in Java 3. Java Database Connectivity (JDBC) Analyse mit Reflection Mehrfache Annotation 4. XML-Technologien 5. Reflection 6. Annotationen 7. Objektserialisierung 8. JavaBeans 9. Jakarta Persistence API (JPA) Prof. Dr. Claus Grewe Software-Entwicklung II 264 Annotationen Einleitung Was sind Annotationen? Annotation (lat.): Anmerkung, Vermerk ▪ Annotationen sind strukturierte Metadaten im Quellcode sie dienen der Markierung von Programmelementen ▪ Beispiel @Deprecated(since="V1.2") Die Annotation @Deprecated kennzeichnet die Methode getYesterday() als überholt. public Date getYesterday() {... } ! Annotationen sind verarbeitungsinvariant. Sie erweitern den Quellcode, sie verändern jedoch nicht dessen Logik. Sie teilen lediglich einen Sachverhalt mit. Prof. Dr. Claus Grewe Software-Entwicklung II 265 Annotationen Einleitung Was sind Annotationen? ▪ Auswertung und Verarbeitung der Annotationen bedarf zusätzlicher Werkzeuge Annotationsprozessoren ▪ Auswertung zu unterschiedlichen Zeitpunkten möglich Java-eigene Annotationen werden vom Java Compiler verarbeitet z. B. @Override und @SuppressWarning ▪ Schritt in Richtung deklarative Programmierung v p v , z. B. #, ,J v ,… sie ersetzen vermehrt externe Konfigurationsdateien Prof. Dr. Claus Grewe Software-Entwicklung II 266 Annotationen Einleitung Mögliche Einsatzgebiete von Annotationen ▪ Charakterisierung von Klassen, Methoden oder Feldern Charakterisierung Beispiele Beschränkungen oder String @NotNull s = getName(); mögliche Einsatzgebiete @Override public void methodFromSuperClass() { … } Verhalten @Transaction public executeMoneyTransfer() { … } drückt aus, dass eine Methode transaktional ausgeführt werden soll Art und Weise der @Column(name="MTKNR") Verarbeitung public matrikelnummer = null; drückt aus, in welche Tabellenspalte einer Datenbank ein Wert geschrieben bzw. aus welcher er gelesen wird Wesen eines Elementes @Entity class Customer { … } Klassenobjekt besitzt eine objektrelationale Abbildung in der Datenbank (Jakarta Persistence API) @Test public void testMethodA() { … } Methode ist ein auszuführender Testfall (JUnit 5) Prof. Dr. Claus Grewe Software-Entwicklung II 267 Inhalt 1. Einführung Einleitung 2. Grundlagen Annotationen in Java 3. Java Database Connectivity (JDBC) Analyse mit Reflection Mehrfache Annotation 4. XML-Technologien 5. Reflection 6. Annotationen 7. Objektserialisierung 8. JavaBeans 9. Jakarta Persistence API (JPA) Prof. Dr. Claus Grewe Software-Entwicklung II 268 Annotationen Annotationen in Java Arten der Java-Annotationen ▪ Eine Annotation kann Elemente spezifizieren die definierten Elemente können optional sein Bezeichnung Format Erläuterung Marker Annotation @TypeName keine Elemente Single Member Annotation @TypeName(elementValue) genau ein Elementwert Normal Annotation @TypeName(elementName1=elementValue1, mehrere benannte Elemente elementName2=elementValue2, …) (Schlüssel-Wert-Paare) public class TestSuite { ▪ Beispiele @TestCase( timeout = 10000 ) @BugReport( assignedTo = "Harry", severity = 2 ) @Important public void checkInputValues() { } } Prof. Dr. Claus Grewe Software-Entwicklung II 269 Annotationen Annotationen in Java Syntax der Annotationsdeklaration ▪ Annotation Interface Deklaration eines neuen Annotationstyps und seiner Elemente obligatorische und optionale Elemente werden als Methoden deklariert keine Unterstützung von Übergabeparametern und throw-Klauseln [modifiers] @interface TypeIdentifier { Deklaration eines obligatorischen Elementes des Annotationstyps elementDeclaration1 elementDeclarationx := type identifier(); elementDeclaration2 … Deklaration eines optionalen Elementes des Annotationstyps } elementDeclarationx := type identifier() default defaultValue; ▪ Element-Datentypen einer Annotationsdeklaration Datenprimitive, String, Class, Enumerationen, Annotationen eindimensionale Arrays der zuvor aufgezählten Datentypen Prof. Dr. Claus Grewe Software-Entwicklung II 270 Annotationen Annotationen in Java Syntax der Annotationsdeklaration ▪ Beispiel: Annotation Interface public @interface BugReport { enum Status { OPEN, CONFIRMED, FIXED, NOTABUG }; // eigene Enumeration boolean showStopper() default false; String assignedTo() default "[none]"; Class testCase() default Void.class; Status status() default Status.OPEN; Reference ref() default @Reference; // separater Annotationstyp int severity() default 0; String[] reportedBy(); // obligatorische Angabe } ▪ Anwendung der Annotation @BugReport( showStopper=true, assignedTo="Harry", testCase=MyTestCase.class, reportedBy={ "Carl" } ) @BugReport(reportedBy={ "Harry", "Carl" }, status=BugReport.Status.CONFIRMED) @BugReport(reportedBy={ "Pete" }, ref = @Reference(id="7555"), severity = 1 ) Prof. Dr. Claus Grewe Software-Entwicklung II 271 Annotationen Annotationen in Java Annotationen ▪ Wann werden Annotationen verarbeitet? Quellcode-Ebene Bytecode-Ebene Laufzeit-Ebene Informationen für den Bytecode Engineering: Laufzeitverarbeitung: Compiler: Annotationen Solange die Annotationen im Annotationen können zur können dem Compiler helfen, Bytecode enthalten sind, Laufzeit dynamisch Fehler aufzudecken oder können zusätzliche ausgewertet werden. Hierbei Warnungen zu unterdrücken. Werkzeuge, wie z. B. Apache kann die Durchführung Bytecode Engineering Library zusätzlicher Programmlogik Unterstützung der (BCEL), den Bytecode initiiert werden, z. B. für Tests Entwicklungsumgebung: basierend auf den oder zur Validierung. Einige Software-Werkzeuge Annotationen statisch oder verwenden Annotationen, um dynamisch beim Laden der Code oder andere Artefakte zu Klasse modifizieren. generieren (z. B. EJB- Deskriptoren). Prof. Dr. Claus Grewe Software-Entwicklung II 272 Annotationen Annotationen in Java Anwendung der Annotationen Annotationen Deklarationen Typnutzung (Type Use) Module Instanziierung neuer Objekte (new) Packages Rückgabetypen in Methoden Klassen (inkl. Enumeration und Records) Typumwandlung (Type Casting) Interfaces (inkl. der Annotations-Interfaces) Exception Clause Konstruktoren Vererbung Methoden und Methodenparameter Generics und Arrays Instanz-Felder this-Referenz Die Java Language Specification definiert 17 Kontexte, Lokale Variablen … in den Type-Annotationen eingesetzt werden können. Record-Komponenten Die Anwendbarkeit einer Annotation lässt sich einschränken Prof. Dr. Claus Grewe Software-Entwicklung II 273 Zusatzfolie Annotationen Annotationen in Java Anwendung der Annotationen ▪ Beispiele: Annotation an Deklarationen @BugReport( reportedBy={ "Harry", "Carl" }, status=Status.CONFIRMED ) public double calculate(long accountId, long custumerId) {... } @Entity public class Customer {... } @Resource(name="customerDB") private DataSource ds; ▪ Beispiele: Annotation der Typnutzung myString = (@NonNull String) str; void monitorTemperature() throws @Critical TemperatureException {... } public @Positive Integer f1(int a, int b) { return a+b; } String @MaxLen(10) [] @NotZeroLen [] strArray; bezieht sich auf die erste Array-Ebene bezieht sich auf die zweite Array-Ebene Prof. Dr. Claus Grewe Software-Entwicklung II 274 Zusatzfolie Annotationen Annotationen in Java Beispiel: JUnit 5 Test Framework (Fortsetzung) public class TestAnnotations {... private static List list = null; @Test @BeforeAll public void everythingOk() { public static void setUpBeforeClass() { Assertions.assertNotNull(list); list = new ArrayList(); Assertions.assertEquals(2, list.size(), } "list size"); } @AfterAll public static void tearDownAfterClass() { @Test list = null; public void accessOutOfBounds() { } Assertions.assertThrows( IndexOutOfBoundsException.class, @BeforeEach () -> { list.get(2); } public void setUp() { ); list.add("Hello"); } list.add("World"); } @Disabled public void notCompleted() { @AfterEach // this test case is still under construction public void tearDown() { } list.clear(); } } Prof. Dr. Claus Grewe Software-Entwicklung II 275 Zusatzfolie Annotationen Annotationen in Java Beispiel: RESTful Web Services in Java ▪ Serverseitiges Remote Object Bereitstellung durch REST-fähige Serverinfrastruktur import jakarta.ws.rs.*; @Path("/calculator") public class CalculatorService { @GET Die Parameter sind im Pfad kodiert @Path("/add/{v1}/{v2}") @Produces(MediaType.TEXT_PLAIN) public String addText(@PathParam("v1") double v1, @PathParam("v2") double v2) { return (v1 + v2) + ""; } @GET Einsatz von URL-Parametern @Path("/add") @Produces(MediaType.TEXT_XML) public String add(@QueryParam("v1") double v1, @QueryParam("v2") double v2) { return "" + "" + (v1 + v2) + ""; }... Prof. Dr. Claus Grewe Software-Entwicklung II 276 Annotationen Annotationen in Java Einige Standard-Annotationen in Java SE Annotation Interface anwendbar auf Zweck Deprecated alle Sprachelemente markiert ein Sprachelement als überholt (deprecated) SuppressWarnings alle Sprachelemente außer Packages unterdrückt Warnungen des Compilers und Annotationen Override Methoden Compiler überprüft, dass eine Methode eine Methode der Superklassen überschreibt SafeVarargs Konstruktoren, Methoden versichert dem Compiler, dass Varargs-Parameter mit Generics zur Laufzeit nicht mit einem unpassenden Generics-Typ ersetzt werden. FunctionalInterface Schnittstellen mit genau einer kennzeichnet eine Schnittstelle als funktionale Schnittstelle. Variablen dieses Typs können abstrakten Methode typkompatible Lambda-Ausdrücke zugewiesen werden. Target Annotationen spezifiziert die Sprachelemente, auf welche die deklarierte Annotation angewandt werden ka