Reflection Arthur Zaczek Nov 2014 Reflection 1 Einleitung 1.1 Definition Reflection ist das Auslesen von Metainformationen über Klassen, deren Methoden & Eigenschaften zur Laufzeit. 1.2 • • • • 2 2.1 Anwendungsfälle Analyse von Programmen (Plugins in der Entwicklungsumgebung) Plugin-Frameworks IoC-Pattern (Inversion of control) etc. Beispiele Java // Class Objekt für my.crm.Person Class c = new Person().getClass(); // Class Objekt für java.util.HashSet Set<String> s = new HashSet<String>(); Class c = s.getClass(); // Class Objekt für den Value-Type boolean Class c = boolean.class; // Class Objekt für my.crm.Customer Class c = my.crm.Customer.class; 2.2 CS // Type Objekt für My.CRM.Person Type t = new Person.GetType(); // Type Objekt für List<int>() IList<int> l = new List<int>(); Type t = l.GetType(); // Type Objekt für den Value-Type bool Type t = typeof(bool); // Type Objekt für My.CRM.Customer Type t = typeof(My.CRM.Customer); 2.3 Erklärung getClass()/GetType() gibt den Typ/Klasse für eine Instanz zurück. .class/typeof(. . . ) gibt den Typ/Klasse für einen bekannten Typ zurück. 1 Reflection 3 Klassen zur Laufzeit laden 3.1 Java // Lädt die Klasse „MyLocaleServiceProvider“ Class c = Class.forName("com.duke.MyLocaleServiceProvider"); // Erzeugt ein neues Objekt (Instanz) der Klasse IService s = (IService)c.newInstance() 3.2 CS // Läd die Klasse „ServiceProvider“ Type t = Type.GetType(„MyApp.Services.ServiceProvider"); // Läd die Klasse „ServiceProvider“, mit Angabe einer Assembly Type t2 = Type.GetType(„MyApp.Services.ServiceProvider, MyApp"); // Erzeugt ein neues Objekt (Instanz) der Klasse IService s = (IService)Activator.CreateInstance(t); 3.3 Anwendungen Dynamisches Laden von Programmteilen. z.B. können Plugin-Frameworks oder Applikationen Plugins aufgrund einer Konfiguration laden. 3.4 Beispiel Ein SMPT Server unterstützt das Speichern von Mails in frei definierbaren Storages. z.B.: • MemoryMailStore • DatabaseMailStore • FileMailStore 3.5 Beispiel Ein einfacher Web Server auf einem Embedded Device unterstützt das Einbinden von neuen Funktionen. z.B.: • Darstellung eines Temeraturverlaufs • Darstellung des Status der Alarmanlage • Steuerung der Markisen 4 4.1 Java - laden von Klassen Arten von Klassen Java kennt 3 “Arten” von Klassen 2 Reflection 1. Bootstrap classes 2. Extension classes 3. User classes 4.2 Bootstrap classes Bootstrap sind all jene Klassen, die benötigt werden um die virtuelle Maschine zu initialisieren. • rt.jar • jre/lib Dieser Pfad kann angepasst werden, wird jedoch so gut wie nie benötigt. 4.3 Extension Classes Sind all jene Klassen, die in jre/lib/ext lokalisiert sind. Es werden nur Klassen aus .jar Dateien geladen. 4.4 User classes Sind all jene Klassen, die auf dem Java Plattform aufbauen. Sie werden mit Hilfe des user class path geladen. Der user class path ist eine Liste mit • Verzeichnissen • .jar Dateien • .zip Dateien 4.5 .class Eine .class Datei muss sich in einem Verzeichnis befinden, dass den Package Namen wiederspiegelt. com.mypackage.MyClass /myclasses /myclasses/com/mypackage/MyClass.class Analoges gilt für die .jar und die .zip Dateien 4.6 CLASSPATH Der CLASSPATH ist eine Liste von Verzeichssen und .jar Dateien. Als Quelle dienen: • • • • Das aktuelle Verzeichnis die CLASSPATH Umgebungsvariable -cp bzw. -classpath Command Line Argument Die .jar Datei, die mit java -jar angegeben wurde 3 Reflection 4.7 JAR-Datei Eine .jar Datei beinhaltet ein Manifest, in dem auch ein CLASSPATH angegeben werden kann. 4.8 URLClassLoader Mit dem URLClassLoader können zur Laufzeit Klassen aus .jar Dateien geladen werden. URL jarURL = new URL("file:///path/to/my.jar"); URL[] classUrls = { jarURL }; URLClassLoader ucl = new URLClassLoader(classUrls); Class c = ucl.loadClass("MyPackage.MyClass"); 4.9 URLClassLoader Unter Windows muss man den Syntax des Pfades beachten 1 : For the UNC Windows file path \\laptop\My Documents\FileSchemeURIs.doc The corresponding valid file URI in Windows is the following: file://laptop/My%20Documents/FileSchemeURIs.doc For the local Windows file path C:\Documents and Settings\davris\FileSchemeURIs.doc The corresponding valid file URI in Windows is: file:///C:/Documents%20and%20Settings/davris/FileSchemeURIs.doc Das bedeutet, dass unter Windows unter Umständen ein / eingefügt werden muss. 5 C# - laden von Typen 5.1 Assemblies Typen (Klassen, etc) werden immer in Assemblies kompiliert. Das kann eine .dll oder .exe Datei sein. 5.2 Referenzen Assemblies müssen bekannt geben, welche anderen Assemblies benötigt werden - Referenzen. 1 http://blogs.msdn.com/b/ie/archive/2006/12/06/file-uris-in-windows.aspx 4 Reflection Figure 1: Referenzen 5 Reflection 5.3 Referenzen Referenzen können “lose” sein, oder Strong Named. Bei einer Strong Name Referenz wird die Assembly digital signiert und die Referenz beinhaltet • den Namen • eine Versionsnummer • Hash des Public Keys der Signatur 5.4 Assembly Loader Assemblies werden in einer genau definierten Reihenfolge gesucht 2 : 1. 2. 3. 4. 5.5 Auswerten der Konifguration Prüfen von bereits geladenen Assemblies GAC (Global Assembly Cache) Suche in der CodeBase Assembly Loader Assemblies, die nicht aus dem GAC geladen werden müssen sich im CodeBase Verzeichnis befinden oder darunter. CodeBase: Das ist jenes Verzeichnis, in dem die startende Assembly liegt. “oder darunter”: Nur, wenn es im Config File angegeben wurde (ProbePath) 5.6 LoadFrom Assemblies können auch händisch geladen werden. Assembly.LoadFrom("c:\\Sample.Assembly.dll"); Die genannten Einschänkungen gelten dann nicht mehr, es kommen jedoch neue hinzu. 5.7 Referenzen umleiten Wenn sich z.B. eine Versionsnummer ändert, kann eine Referenz umgeleitet werden, ohne die Referenzierende Assembly neu zu kompilieren <configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="Autofac" publicKeyToken="17863af14b0044da" culture="neutral" /> <bindingRedirect oldVersion="0.0.0.0-3.5.0.0" newVersion="3.5.0.0" /> </dependentAssembly> </assemblyBinding> </runtime> </configuration> 2 http://msdn.microsoft.com/en-us/library/yx7xezcf(v=vs.110).aspx 6 Reflection 6 Anotations 6.1 Anwendung Anotations bzw. Attribute können über Typen/Klassen, Methoden, Felder etc. geschrieben werden, um Informationen über den Typ anzugeben. • • • • 6.2 Unit Tests Plugins: Art des Plugins XMLSerializer uvm. Java @Before public void setUp() throws Exception { } @After public void tearDown() throws Exception { } @Test public void helloWorld() throws Exception { } 6.3 CS [TestFixture] public class UEB1 : AbstractTestFixture<IUEB1> { [SetUp] public void SetUp() { } [Test] public void HelloWorld() { } } 7 7.1 Fields Java - Fields // Gibt das Field mit dem Namen „fieldname“ zurück c.getField("fieldname"); // Gibt alle Fields zurück 7 Reflection c.getDeclaredFields(); // Gibt die Class des Fields zurück f.getType(); // Gibt den Namen des Fields zurück f.getName(); 7.2 C# - Fields // Gibt das Field mit dem Namen „fieldname“ zurück T.GetField(„fieldname“); // Gibt alle public Fields zurück t. GetFields(); // Gibt die Class des Fields zurück f.FieldType; // Gibt den Namen des Fields zurück f.Name; 7.3 Java – r/w von Fields public class Book { public long chapters = 0; public String[] characters = { "Alice", "White Rabbit" }; public static void main(String... args) { Book book = new Book(); try { Class<?> c = book.getClass(); Field chap = c.getDeclaredField("chapters"); out.format(fmt, "before", "chapters", book.chapters); chap.setLong(book, 12); out.format(fmt, "after", "chapters", chap.getLong(book)); } catch (Exception x) { x.printStackTrace(); } } 7.4 C# - r/w von Fields public class Book { public int chapters = 0; public static void Method(object maybebook) { Type t = maybebook.GetType(); FieldInfo f = t.GetField("chapters"); Console.WriteLine("Chapters = " + f.GetValue(maybebook)); f.SetValue(maybebook, 14); 8 Reflection Console.WriteLine("Chapters = " + ((Book)maybebook).chapters); } } 8 Nachteile 8.1 Nachteile Langsam! Klassen, Felder, Methoden müssen über Strings angesprochen werden. Typsicherheit! kann nicht garantiert werden. • Das Objekt muss nicht dem erwarteten Typ entsprechen. • Fehler werden erst zu Laufzeit erkannt. • keine Sicherheit durch einen Compiler. 9