On Reflection in OO Programming Languages

1,235 views

Published on

A tutorial on reflection, with a particular emphasis on Java, with comparisons with C++ and Smalltalk working examples.

The tutorial focuses on four common problems:
- Avoid using instanceof when code must bypass the compiler and virtual machine’s choice of the method to call.
- Create external, user-defined pieces of code loaded, used, and unloaded at run-time.
- Translate data structures or object state into a format that can be stored (file, network...).
- Monitor the execution of a program to understand its behaviour, measure its space and time complexity.

It shows working examples of Java, Smalltalk, and C++ code solving the four common problems through four scenarios:
- Scenario 1: invoke an arbitrary method on an object (see the problems with instanceof and plugins).
- Scenario 2: access the complete (including private) state of an object (see the problem with serialisation).
- Scenario 3: count the number of instances of a class created at runtime (see the problem with debugging/profiling).
- Scenario 4: patch the method of a class to change its behaviour (see the problem with patching).

It also discusses the different kinds of interconnections among objects that are available in common programming languages (linking, forking, subclassing, inter-process communication, and dynamic loading/invoking), some theory about reflection, and specifically the class-loading mechanism of Java.

Published in: Technology, Lifestyle
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,235
On SlideShare
0
From Embeds
0
Number of Embeds
182
Actions
Shares
0
Downloads
28
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

On Reflection in OO Programming Languages

  1. 1. Yann-Gaël Guéhéneuc This work is licensed under a Creative Commons Attribution-NonCommercial- ShareAlike 3.0 Unported LicenseDépartement de génie informatique et de génie logiciel On Reflection in OO Programming Languages yann-gael.gueheneuc@polytmtl.ca Version 1.5.5 2014/04/30
  2. 2. 2/210 Any questions/comments are welcome at yann-gael.gueheneuc@polymtl.ca The source code is available at http://www.ptidej.net/tutorial/javareflection
  3. 3. 3/210 Outline  Rationale  Definition  Context – Interconnections  Scenarios  Theory  Conclusion  Class Loading
  4. 4. 4/210 Outline  Rationale  Definition  Context – Interconnections  Scenarios  Theory  Conclusion  Class Loading
  5. 5. 5/210 Use of instanceof public abstract class Animal { } public class Cat extends Animal { } public class Dog extends Animal { } public class Expression { public static String speak(final Animal anAnimal) { final String sound; if (anAnimal instanceof Dog) { sound = "woof"; } else if (anAnimal instanceof Cat) { sound = "miaow"; } else { sound = ""; } return sound; } public static void main(final String[] args) { final Dog fido = new Dog(); System.out.println(Expression.speak(fido)); } }
  6. 6. 6/210 Use of instanceof public abstract class Animal { } public class Cat extends Animal { } public class Dog extends Animal { } public class Expression { public static String speak(final Animal anAnimal) { final String sound; if (anAnimal instanceof Dog) { sound = "woof"; } else if (anAnimal instanceof Cat) { sound = "miaow"; } else { sound = ""; } return sound; } public static void main(final String[] args) { final Dog fido = new Dog(); System.out.println(Expression.speak(fido)); } } Must test the type of the object at run-time
  7. 7. 7/210 Use of instanceof public abstract class Animal { } public class Cat extends Animal { } public class Dog extends Animal { } public class Expression { public static String speak(final Animal anAnimal) { final String sound; if (anAnimal instanceof Dog) { sound = "woof"; } else if (anAnimal instanceof Cat) { sound = "miaow"; } else { sound = ""; } return sound; } public static void main(final String[] args) { final Dog fido = new Dog(); System.out.println(Expression.speak(fido)); } } Must test the type of the object at run-time Breaks information hiding of Cat and Dog
  8. 8. 8/210 Use of instanceof public abstract class Animal { } public class Cat extends Animal { } public class Dog extends Animal { } public class Expression { public static String speak(final Animal anAnimal) { final String sound; if (anAnimal instanceof Dog) { sound = "woof"; } else if (anAnimal instanceof Cat) { sound = "miaow"; } else { sound = ""; } return sound; } public static void main(final String[] args) { final Dog fido = new Dog(); System.out.println(Expression.speak(fido)); } } Must test the type of the object at run-time Breaks information hiding of Cat and Dog Requires special case
  9. 9. 9/210 Use of instanceof  Reason – Must bypass the compiler and virtual machine’s choice of the method to call – Remember that overloading is resolved by the static type of the argument, not its run-time type (cf. Week 2)
  10. 10. 10/210 Use of instanceof  Problem “Don't repeat yourself” (DRY): “Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.” —Andy Hunt and Dave Thomas (in The Pragmatic Programmer)
  11. 11. 11/210 Use of instanceof public abstract class Animal { public abstract String speak(); } public class Cat extends Animal { @Override public String speak() { return "miaow"; } } public class Dog extends Animal { @Override public String speak() { return "woof"; } } public class Expression { public static void main(final String[] args) { final Dog fido = new Dog(); System.out.println(fido.speak()); } }
  12. 12. 12/210 Use of instanceof public abstract class Animal { public abstract String speak(); } public class Cat extends Animal { @Override public String speak() { return "miaow"; } } public class Dog extends Animal { @Override public String speak() { return "woof"; } } public class Expression { public static void main(final String[] args) { final Dog fido = new Dog(); System.out.println(fido.speak()); } }
  13. 13. 13/210 Use of instanceof public class Cat { public String speak() { return "miaow"; } } public class Dog { public String speak() { return "woof"; } } public class Expression { public static void main(final String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { final Dog fido = new Dog(); final Method[] method = Dog.class.getDeclaredMethods(); System.out.println(method[0].invoke(fido, new Object[0])); } }
  14. 14. 14/210 Use of instanceof public class Cat { public String speak() { return "miaow"; } } public class Dog { public String speak() { return "woof"; } } public class Expression { public static void main(final String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { final Dog fido = new Dog(); final Method[] method = Dog.class.getDeclaredMethods(); System.out.println(method[0].invoke(fido, new Object[0])); } } Discover method of object of unrelated classes
  15. 15. 15/210 Plugins  Plugins are external, user-defined pieces of code loaded, used, and unloaded to benefit from their features only when needed  Problem – Closed-world assumption (at compile-time and runtime) leads to the need for a mechanism to perform dynamic loading
  16. 16. 16/210 Serialisation  Serialisation is the process of translating data structures or object state into a format that can be stored (file, network…)  Problem – Information hiding prevents access to the internals of the data structures and to the complete object states
  17. 17. 17/210 Debugging/Profiling  Debugging/profiling are the processes of monitoring the execution of a program – To understand its behaviour – To measure its space and time complexity  Problem – Accessing the internals of objects and controlling the program to collect relevant data
  18. 18. 18/210 Patching  Patching is the process of changing the behaviour of a class or an object – To modify its behaviour – To add new behaviour  Problem – Modifying the behaviour at run-time without the need to recompile and restart the program
  19. 19. 19/210 Outline  Rationale  Definition  Context – Interconnections  Scenarios  Theory  Conclusion  Class Loading
  20. 20. 20/210 Definition  Reflection is the ability of a computer program to examine and modify the structure and behaviour of an object at runtime
  21. 21. 21/210 Definition  Reflection is the ability of a computer program to examine and modify the structure and behaviour of an object at runtime Problem: inspect objects and change their behaviour at runtime Solution: reflection
  22. 22. 22/210 Use of instanceof public abstract class Animal { public abstract String speak(); } public class Cat extends Animal { @Override public String speak() { return "miaow"; } } public class Dog extends Animal { @Override public String speak() { return "woof"; } } public class Expression { public static void main(final String[] args) { final Dog fido = new Dog(); System.out.println(fido.speak()); } }
  23. 23. 23/210 Use of instanceof public abstract class Animal { public abstract String speak(); } public class Cat extends Animal { @Override public String miaow() { return "miaow"; } } public class Dog extends Animal { @Override public String bark() { return "woof"; } } public class Expression { public static void main(final String[] args) { final Dog fido = new Dog(); final Method[] method = Dog.class.getDeclaredMethods(); System.out.println(method[0].invoke(fido, new Object[0])); } }
  24. 24. 24/210 Use of instanceof public abstract class Animal { public abstract String speak(); } public class Cat extends Animal { @Override public String miaow() { return "miaow"; } } public class Dog extends Animal { @Override public String bark() { return "woof"; } } public class Expression { public static void main(final String[] args) { final Dog fido = new Dog(); final Method[] method = Dog.class.getDeclaredMethods(); System.out.println(method[0].invoke(fido, new Object[0])); } } Unrelated classes
  25. 25. 25/210 Use of instanceof public abstract class Animal { public abstract String speak(); } public class Cat extends Animal { @Override public String miaow() { return "miaow"; } } public class Dog extends Animal { @Override public String bark() { return "woof"; } } public class Expression { public static void main(final String[] args) { final Dog fido = new Dog(); final Method[] method = Dog.class.getDeclaredMethods(); System.out.println(method[0].invoke(fido, new Object[0])); } } Unrelated classes Choice at run-time
  26. 26. 26/210 Use of instanceof public abstract class Animal { public abstract String speak(); } public class Cat extends Animal { @Override public String miaow() { return "miaow"; } } public class Dog extends Animal { @Override public String bark() { return "woof"; } } public class Expression { public static void main(final String[] args) { final Dog fido = new Dog(); final Method[] method = Dog.class.getDeclaredMethods(); System.out.println(method[0].invoke(fido, new Object[0])); } } Unrelated classes Choice at run-time
  27. 27. 27/210 Outline  Problems  Definition  Context – Interconnections  Scenarios  Theory  Conclusion  Class Loading
  28. 28. 28/210 Context  Reflection – Ability of a computer program to examine and modify the structure and behaviour of an object at runtime
  29. 29. 29/210 Context  Reflection – Theoretical interest • What is an interpreter? Brian Cantwell Smith “Procedural Reflection in Programming Languages” (Ph.D. thesis, 1982) – Practical interest • Libraries • Frameworks
  30. 30. 30/210 Context  Reflection – Theoretical interest • What is an interpreter? Brian Cantwell Smith “Procedural Reflection in Programming Languages” (Ph.D. thesis, 1982) – Practical interest • Libraries • Frameworks
  31. 31. 31/210 Context  Reflection – Theoretical interest • What is an interpreter? Brian Cantwell Smith “Procedural Reflection in Programming Languages” (Ph.D. thesis, 1982) – Practical interest • Libraries • Frameworks
  32. 32. 32/210 Context  Libraries – Collections of data structures and algorithms (possibly encapsulated in classes) used to develop and run programs  Frameworks – Reusable sets of libraries, tools, and conventions used to develop and run programs
  33. 33. 33/210 Context  Libraries – Collections of data structures and algorithms (possibly encapsulated in classes) used to develop and run programs  Frameworks – Reusable sets of libraries, tools, and conventions used to develop and run programs Problem: connection between clients and libraries/frameworks Solution: linking, forking, subclassing, IPC, and dynamic loading
  34. 34. 34/210 Interconnections  Clients–Libraries/Frameworks – Linking – Forking – Subclassing – Inter-process communication – Dynamic loading/invoking
  35. 35. 35/210 Interconnections  Linking (Contrast with virtual machines) – Typically C/C++ – Several object files (.o) – One executable (.exe)
  36. 36. 36/210 Interconnections  Forking – Typical in most languages – Process duplication • Is a real duplication • Creates a new OS process final StringBuffer commandLine = new StringBuffer(); commandLine.append("..DOTbindotty "); commandLine.append(aFilePath); final Process process = Runtime.getRuntime().exec(commandLine.toString()); final OutputMonitor errorStreamMonitor = new OutputMonitor(...,process.getErrorStream(),...); errorStreamMonitor.start(); final OutputMonitor inputStreamMonitor = new OutputMonitor(...,process.getInputStream(),...); inputStreamMonitor.start(); try { process.waitFor(); } catch (final InterruptedException ie) { ie.printStackTrace( Output.getInstance().errorOutput()); } if (process.exitValue() != 0) { ... }
  37. 37. 37/210 Interconnections  IPC – Typical in most languages – Use remote procedure calls – Use well-defined protocols • COM • CORBA • XML-RPC – Web services
  38. 38. 38/210 Interconnections package kr.ac.yonsei.cse3009.rpc; import java.net.URL; import org.apache.xmlrpc.client.XmlRpcClient; import org.apache.xmlrpc.client.XmlRpcClientConfigImpl; public class Client { public static void main(final String[] args) throws Exception { final XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl(); config.setServerURL( new URL("http://127.0.0.1:8080/xmlrpc")); final XmlRpcClient client = new XmlRpcClient(); client.setConfig(config); final Object[] params = new Object[] { new Integer(33), new Integer(9) }; final Integer result = (Integer) client.execute("Calculator.add", params); System.out.println(result); } } package kr.ac.yonsei.cse3009.rpc; import org.apache.xmlrpc.server.PropertyHandlerMapping; import org.apache.xmlrpc.server.XmlRpcServer; import org.apache.xmlrpc.webserver.WebServer; public class Server { public static void main(final String[] args) throws Exception { final WebServer webServer = new WebServer(8080); final XmlRpcServer xmlRpcServer = webServer.getXmlRpcServer(); final PropertyHandlerMapping phm = new PropertyHandlerMapping(); phm.addHandler("Calculator", Calculator.class); xmlRpcServer.setHandlerMapping(phm); webServer.start(); } } package kr.ac.yonsei.cse3009.rpc; public class Calculator { public int add(final int i1, final int i2) { return i1 + i2; } public int sub(final int i1, final int i2) { return i1 - i2; } }
  39. 39. 39/210 Interconnections  Subclassing – Typical in most object- oriented languages – Structural, static relation public class OutputMonitor extends Thread { ... public OutputMonitor(...) { this.setName(threadName); this.setPriority(Thread.MAX_PRIORITY); ... } public void run() { try { int value = 0; byte[] bytes; char lastWrittenChar; while ((value = this.inputStream.read()) > 0) { synchronized (System.err) { synchronized (System.out) { if (value != 13 && value != 10) { lastWrittenChar = (char) value; ... }} } } catch (final IOException ioe) { ...
  40. 40. 40/210 Interconnections  Subclassing – Hooks and templates • Hot spots = hooks • Frozen spots = templates – Hooks are typically abstract methods – Templates typically use hooks
  41. 41. 41/210 Interconnections  Subclassing – Hooks and templates • JUnit
  42. 42. 42/210 Interconnections  Template  Hooks public abstract class TestCase extends Assert implements Test { public void runBare() throws Throwable { setUp(); try { runTest(); } finally { tearDown(); } } protected void setUp() throws Exception { } protected void tearDown() throws Exception { } ... }
  43. 43. 43/210 Interconnections  Subclassing – Heavily used in object-oriented programs – Heavily used in design patterns (Only Singleton does not explicitly use subclassing) • Abstract Factory • Composite • Decorator • Observer • Visitor
  44. 44. 44/210 Interconnections  Dynamic loading – In different programming languages (but not all), it is the possibility to load, use, and unload a piece of code at runtime – In Java, it is the possibility to load and unload a class and to choose and invoke its methods (and to access its fields…) at runtime
  45. 45. 45/210 Interconnections  Poor man’s profiler – Calls the main() method of a class whose name is given at runtime, by the user – Displays the time spent in the called method public final class PoorManProfiler { public static void main(final String[] args) { try { final Class toBeRun = Class.forName(args[0]); final Method mainMethod = toBeRun.getMethod("main", new Class[] { String[].class }); final long startTime = System.currentTimeMillis(); mainMethod.invoke(null, new Object[] { new String[0] }); final long endTime = System.currentTimeMillis(); System.out.println(); System.out.println(endTime - startTime); } catch (final Exception e) { e.printStackTrace(); } } }
  46. 46. 46/210 Return to Reflection  Reflection enables dynamic loading – Reflection  dynamic loading – Dynamic loading  Reflection • Think of dynamically-loaded shared libraries in C-based operating systems, such as AmigaOS, Linux, UN*X, Windows… 
  47. 47. 47/210 Outline  Rationale  Definition  Context – Interconnections  Scenarios  Theory  Conclusion  Class Loading
  48. 48. 48/210 Scenarios  Original problem – Different interpretations – Different contexts  Four scenarios  Three programming languages Problem: inspect objects and change their behaviour at runtime Solution: reflection
  49. 49. 49/210 Scenarios  Scenario 1: invoke an arbitrary method on an object (see the problems with instanceof and plugins) – Given a class C – Given an object o, instance of C – Identify all the methods available on o – Invoke a method using its name foo
  50. 50. 50/210 Scenarios  Scenario 2: access the complete (including private) state of an object (see the problem with serialisation) – Given an object o, instance of C – Save on disk the complete state of o – Restore from disk the object o at a later time
  51. 51. 51/210 Scenarios  Scenario 3: count the number of instances of a class created at runtime (see the problem with debugging/profiling) – Given a class C – Record the number of its instances ever created – Report this number when the program ends
  52. 52. 52/210 Scenarios  Scenario 4: patch the method of a class to change its behaviour (see the problem with patching) – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo()
  53. 53. 53/210 Scenarios Java Smalltalk C++
  54. 54. 54/210 Scenarios  Scenario 1: – Given a class C – Given an object o, instance of C – Identify all the methods available on o – Invoke a method using its name foo public class C { private int i; public C(final int anInt) { this.i = anInt; } public void foo(final String s) { System.out.print(s); System.out.println(this.i); } }
  55. 55. 55/210 Scenarios  Scenario 1: – Given a class C – Given an object o, instance of C – Identify all the methods available on o – Invoke a method using its name foo Identify all the methods available on o foo getClass hashCode equals toString notify notifyAll wait wait wait Invoke a method using its name foo This is foo: 42
  56. 56. 56/210 Scenarios  Scenario 1: – Given a class C – Given an object o, instance of C – Identify all the methods available on o – Invoke a method using its name foo final C o = new C(42); System.out.println("Identify all the methods available on o"); final Class<?> classOfO = o.getClass(); final Method[] methodsOfC = classOfO.getMethods(); for (int i = 0; i < methodsOfC.length; i++) { final Method method = methodsOfC[i]; System.out.print('t'); System.out.println(method.getName()); } System.out.println("Invoke a method using its name foo"); final Method fooMethod = classOfO.getMethod("foo", new Class[] { String.class }); fooMethod.invoke(o, new Object[] { "tThis is foo: " });
  57. 57. 57/210 Scenarios  Scenario 1: – Given a class C – Given an object o, instance of C – Identify all the methods available on o – Invoke a method using its name foo Identify all the methods available on o foo getClass hashCode equals toString notify notifyAll wait wait wait Invoke a method using its name foo This is foo: 42
  58. 58. 58/210 Scenarios  Scenario 2: – Given an object o, instance of C – Save on disk the complete state of o – Restore from disk the object o at a later time public class C { private int i; public C() { this(-1); } public C(final int anInt) { this.i = anInt; } public void foo(final String s) { System.out.print(s); System.out.println(this.i); } }
  59. 59. 59/210 Scenarios  Scenario 2: – Given an object o, instance of C – Save on disk the complete state of o – Restore from disk the object o at a later time Save on disk the complete state of o i = 42 Restore from disk the object o at a later time This is foo on o2: 43
  60. 60. 60/210 Scenarios  Scenario 2: – Given an object o, instance of C – Save on disk the complete state of o – Restore from disk the object o at a later time final C o1 = new C(42); System.out.println("Save on disk the complete state of o"); final Class<?> classOfO = o1.getClass(); final Field[] fieldsOfC = classOfO.getDeclaredFields(); for (int i = 0; i < fieldsOfC.length; i++) { final Field field = fieldsOfC[i]; field.setAccessible(true); System.out.print('t' + field.getName()); System.out.println(" = " + field.getInt(o1)); } System.out.println("Restore from disk the object o at a later time"); final C o2 = (C) classOfO.newInstance(); final Field fieldiOfC = classOfO.getDeclaredField("i"); fieldiOfC.setAccessible(true); fieldiOfC.setInt(o2, 43); o2.foo("tThis is foo on o2: ");
  61. 61. 61/210 Scenarios  Scenario 2: – Given an object o, instance of C – Save on disk the complete state of o – Restore from disk the object o at a later time Save on disk the complete state of o i = 42 Restore from disk the object o at a later time This is foo on o2: 43
  62. 62. 62/210 Scenarios  Scenario 3: – Given a class C – Record the numbers of its instance ever created – Report this number when the program ends public class C { private static int numberOfInstances; public static int getNumberOfInstances() { return C.numberOfInstances; } private int i; public C() { this(-1); } public C(final int anInt) { C.numberOfInstances++; this.i = anInt; } public void foo(final String s) { System.out.print(s); System.out.println(this.i); } }
  63. 63. 63/210 Scenarios  Scenario 3: kr.ac.yonsei.it.cse3009.reflection.scenario3.C@150bd4d kr.ac.yonsei.it.cse3009.reflection.scenario3.C@1bc4459 kr.ac.yonsei.it.cse3009.reflection.scenario3.C@12b6651 3 – Given a class C – Record the numbers of its instance ever created – Report this number when the program ends
  64. 64. 64/210 Scenarios  Scenario 3: public class Main { public static void main(final String[] args) { final C o1 = new C(42); final C o2 = new C(1); final C o3 = new C(100); System.out.println(o1 + "n" + o2 + 'n' + o3); System.out.println(C.getNumberOfInstances()); } } – Given a class C – Record the numbers of its instance ever created – Report this number when the program ends
  65. 65. 65/210 Scenarios  Scenario 3: kr.ac.yonsei.it.cse3009.reflection.scenario3.C@150bd4d kr.ac.yonsei.it.cse3009.reflection.scenario3.C@1bc4459 kr.ac.yonsei.it.cse3009.reflection.scenario3.C@12b6651 3 – Given a class C – Record the numbers of its instance ever created – Report this number when the program ends
  66. 66. 66/210 Scenarios  Scenario 3: kr.ac.yonsei.it.cse3009.reflection.scenario3.C@150bd4d kr.ac.yonsei.it.cse3009.reflection.scenario3.C@1bc4459 kr.ac.yonsei.it.cse3009.reflection.scenario3.C@12b6651 3 To fulfill this scenario, we must modify C – Given a class C – Record the numbers of its instance ever created – Report this number when the program ends
  67. 67. 67/210 Scenarios  Class Class is a metaclass – It describes other classes  Class Method is a class – It describes methods  Class Field is a class – It describes fields
  68. 68. 68/210 Scenarios  Class Class is a metaclass – It allows to reify classes  Class Method is a class – It allows to reify methods, these language constructs become first-class entities  Class Field is a class – It allows to reify fields , these language constructs become first-class entities
  69. 69. 69/210 Scenarios  Class Class is a metaclass – It allows to reify classes  Class Method is a class – It allows to reify methods, these language constructs become first-class entities  Class Field is a class – It allows to reify fields, these language constructs become first-class entities
  70. 70. 70/210 Scenarios  Class Class is a metaclass – It allows to reify classes  Class Method is a class – It allows to reify methods, these language constructs become first-class entities  Class Field is a class – It allows to reify fields, these language constructs become first-class entities Reification is the process of making available an implicit construct of a language
  71. 71. 71/210 Scenarios  We never modified class Class – We only used it to obtain the methods and fields declared by particular classes, e.g., C  We used static fields and methods to count number of instances
  72. 72. 72/210 Scenarios  Scenario 4: public interface I { public void foo(final String s); } public class C implements I { private int i; public C(final int anInt) { this.i = anInt; } public void foo(final String s) { System.out.print(s); System.out.println(this.i); } } – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo()
  73. 73. 73/210 Scenarios  Scenario 4: This is o: 42 Forwarding method: "foo" Original arguments: "This is o: " New arguments: "THIS IS O: " THIS IS O: 42 – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo()
  74. 74. 74/210 Scenarios  Scenario 4: final I o = new C(42); o.foo("This is o: "); final InvocationHandler handler = new InvokationHandler(o); final I proxy = (I) Proxy.newProxyInstance( I.class.getClassLoader(), new Class[] { I.class }, handler); Assert.assertTrue(proxy instanceof I); Assert.assertFalse(proxy instanceof C); Assert.assertTrue(proxy.equals(o)); proxy.foo("This is o: "); – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo()
  75. 75. 75/210 Scenarios Scenario4: public class InvokationHandler implements InvocationHandler { private final I i; public InvokationHandler(final I aConcreteImplementationOfI) { this.i = aConcreteImplementationOfI; } public Object invoke( final Object aProxy, final Method aMethod, final Object[] someArgs) throws Throwable { if (aMethod.getName().equals("foo")) { final String arg = (String) someArgs[0]; final String newArg = arg.toUpperCase(); System.out.print("Forwarding method: ""); System.out.print(aMethod.getName()); System.out.print(""ntOriginal arguments: ""); System.out.print(arg); System.out.print(""ntNew arguments: ""); System.out.print(newArg); System.out.println('"'); this.i.foo(newArg); return null; } else { return aMethod.invoke(this.i, someArgs); } } } –Givenanobjecto,instanceofC –WithoutchangingoorC –Changethebehaviourofo.foo()
  76. 76. 76/210 Scenarios  Scenario 4: final I o = new C(42); o.foo("This is o: "); final InvocationHandler handler = new InvokationHandler(o); final I proxy = (I) Proxy.newProxyInstance( I.class.getClassLoader(), new Class[] { I.class }, handler); Assert.assertTrue(proxy instanceof I); Assert.assertFalse(proxy instanceof C); Assert.assertTrue(proxy.equals(o)); proxy.foo("This is o: "); – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo()
  77. 77. 77/210 Scenarios  Scenario 4: final I o = new C(42); o.foo("This is o: "); final InvocationHandler handler = new InvokationHandler(o); final I proxy = (I) Proxy.newProxyInstance( I.class.getClassLoader(), new Class[] { I.class }, handler); Assert.assertTrue(proxy instanceof I); Assert.assertFalse(proxy instanceof C); Assert.assertTrue(proxy.equals(o)); proxy.foo("This is o: "); Properties of the proxy ensured by the Java VM – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo()
  78. 78. 78/210 Scenarios  Smalltalk – Everything is an object
  79. 79. 79/210 Scenarios  Smalltalk – Everything is an object – Everything is an object, really static
  80. 80. 80/210 Scenarios  Smalltalk – SmalltalkImage is the class that “represent[s] the current image and runtime environment, including system organization, the virtual machine, object memory, plugins, and source files. [Its] instance variable #globals is a reference to the system dictionary of global variables and class names. [Its] singleton instance is called Smalltalk.”
  81. 81. 81/210 Scenarios  Smalltalk – Object is “the root class for almost all of the other classes in the class hierarchy. […] Class Object provides default behavior common to all normal objects, such as access, copying, comparison, error handling, message sending, and reflection. Also utility messages that all objects should respond to are defined here.”
  82. 82. 82/210 Scenarios  Smalltalk – Class “[adds] instance-specific behavior to various class-describing objects in the system. This typically includes messages for initializing class variables and instance creation messages particular to a class. There is only one instance of a particular Metaclass, namely the class which is being described.”
  83. 83. 83/210 Scenarios  Scenario 1: – Given a class C – Given an object o, instance of C – Identify all the methods available on o – Invoke a method using its name foo Object subclass: #C instanceVariableNames: 'i' classVariableNames: '' poolDictionaries: '' category: 'CSE3009'. C class compile: 'newWithi: anInt ^(self new) i: anInt ; yourself.'. C compile: 'foo: aText Transcript show: aText. Transcript show: i. Transcript cr.'. C compile: 'i: anInt i := anInt.'.
  84. 84. 84/210 Scenarios  Scenario 1: – Given a class C – Given an object o, instance of C – Identify all the methods available on o – Invoke a method using its name foo Identify all the methods available on o an IdentitySet(#handles: #longPrintString #actionMap #hasContentsInExplorer [...] #foo: [...] #i: [...] #creationStamp) Invoke a method using its name foo This is foo: 42
  85. 85. 85/210 Scenarios  Scenario 1: – Given a class C – Given an object o, instance of C – Identify all the methods available on o – Invoke a method using its name foo |o| o := C newWithi: 42. Transcript show: 'Identify all the methods available on o' ; cr. Transcript show: C allSelectors ; cr. Transcript show: 'Invoke a method using its name foo' ; cr. (C compiledMethodAt: #foo:) valueWithReceiver: o arguments: #('This is foo: ').
  86. 86. 86/210 Scenarios  Scenario 1: – Given a class C – Given an object o, instance of C – Identify all the methods available on o – Invoke a method using its name foo |o| o := C newWithi: 42. Transcript show: 'Identify all the methods available on o' ; cr. Transcript show: C allSelectors ; cr. Transcript show: 'Invoke a method using its name foo' ; cr. (C compiledMethodAt: #foo:) valueWithReceiver: o arguments: #('This is foo: '). Simple and straightforward
  87. 87. 87/210 Scenarios  Scenario 2: – Given an object o, instance of C – Save on disk the complete state of o – Restore from disk the object o at a later time Object subclass: #C instanceVariableNames: 'i' classVariableNames: '' poolDictionaries: '' category: 'CSE3009'. C class compile: 'newWithi: anInt ^(self new) i: anInt ; yourself.'. C compile: 'foo: aText Transcript show: aText. Transcript show: i. Transcript cr.'. C compile: 'i: anInt i := anInt.'.
  88. 88. 88/210 Scenarios  Scenario 2: – Given an object o, instance of C – Save on disk the complete state of o – Restore from disk the object o at a later time Save on disk the complete state of o 42 Restore from disk the object o at a later time This is foo on o2: 43
  89. 89. 89/210 Scenarios  Scenario 2: – Given an object o, instance of C – Save on disk the complete state of o – Restore from disk the object o at a later time |o1 o2| o1 := C newWithi: 42. Transcript show: 'Save on disk the complete state of o' ; cr. Transcript show: (o1 instVarAt: 1) ; cr. Transcript show: 'Restore from disk the object o at a later time' ; cr. o2 := C new. o2 instVarNamed: 'i' put: 43. o2 foo: 'This is foo on o2: '.
  90. 90. 90/210 Scenarios  Scenario 2: – Given an object o, instance of C – Save on disk the complete state of o – Restore from disk the object o at a later time |o1 o2| o1 := C newWithi: 42. Transcript show: 'Save on disk the complete state of o' ; cr. Transcript show: (o1 instVarAt: 1) ; cr. Transcript show: 'Restore from disk the object o at a later time' ; cr. o2 := C new. o2 instVarNamed: 'i' put: 43. o2 foo: 'This is foo on o2: '. Again, simple and straightforward
  91. 91. 91/210 Scenarios  Scenario 2: – Pharo (a recent implementation of Smalltalk) provides is a general object serialiser that can serialise any object – Uses reflection to implement these methods! – Given an object o, instance of C – Save on disk the complete state of o – Restore from disk the object o at a later time 1@2 serializeToFileNamed: 'hello.fuel'. FLMaterializer materializeFromFileNamed: 'hello.fuel' Thanks to Marcus Denker for pointing out these helper methods
  92. 92. 92/210 Scenarios  Scenario 3: Object subclass: #C instanceVariableNames: 'i' classVariableNames: 'NumberOfInstances' poolDictionaries: '' category: 'CSE3009'. C class compile: 'newWithi: anInt ^(self new) i: anInt ; yourself.'. C compile: 'foo: aText Transcript show: aText. Transcript show: i. Transcript cr.'. C compile: 'i: anInt i := anInt.'. – Given a class C – Record the numbers of its instance ever created – Report this number when the program ends
  93. 93. 93/210 Scenarios  Scenario 3: Object subclass: #C instanceVariableNames: 'i' classVariableNames: 'NumberOfInstances' poolDictionaries: '' category: 'CSE3009'. C class compile: 'newWithi: anInt ^(self new) i: anInt ; yourself.'. C compile: 'foo: aText Transcript show: aText. Transcript show: i. Transcript cr.'. C compile: 'i: anInt i := anInt.'. – Given a class C – Record the numbers of its instance ever created – Report this number when the program ends Only difference with Scenarios 1 and 2
  94. 94. 94/210 Scenarios  Scenario 3: C class compile: 'newWithi: anInt ^(self new) i: anInt ; yourself.'. C compile: 'foo: aText Transcript show: aText. Transcript show: i. Transcript cr.'. C compile: 'i: anInt i := anInt.'. – Given a class C – Record the numbers of its instance ever created – Report this number when the program ends
  95. 95. 95/210 Scenarios  Scenario 3: C class compile: 'newWithi: anInt ^(self new) i: anInt ; yourself.'. C compile: 'foo: aText Transcript show: aText. Transcript show: i. Transcript cr.'. C compile: 'i: anInt i := anInt.'. Same as Scenarios 1 and 2 – Given a class C – Record the numbers of its instance ever created – Report this number when the program ends
  96. 96. 96/210 Scenarios  Scenario 3: C class compile: 'initialize NumberOfInstances := 0.'. C class compile: 'new NumberOfInstances := NumberOfInstances + 1. ^ self basicNew initialize.'. C class compile: 'numberOfInstances ^ NumberOfInstances.'. – Given a class C – Record the numbers of its instance ever created – Report this number when the program ends
  97. 97. 97/210 Scenarios  Scenario 3: C class compile: 'initialize NumberOfInstances := 0.'. C class compile: 'new NumberOfInstances := NumberOfInstances + 1. ^ self basicNew initialize.'. C class compile: 'numberOfInstances ^ NumberOfInstances.'. – Given a class C – Record the numbers of its instance ever created – Report this number when the program ends “Write access” to the metaclass
  98. 98. 98/210 Scenarios  Scenario 3: |o1 o2 o3| C initialize. o1 := C newWithi: 42. o2 := C newWithi: 1. o3 := C newWithi: 100. Transcript show: o1 ; show: ' ' ; show: o2 ; show: ' ' ; show: o3 ; cr. Transcript show: C numberOfInstances. – Given a class C – Record the numbers of its instance ever created – Report this number when the program ends
  99. 99. 99/210 Scenarios  Scenario 3: a C a C a C 3 – Given a class C – Record the numbers of its instance ever created – Report this number when the program ends
  100. 100. 100/210 Scenarios  Scenario 3: a C a C a C 3 To fulfill this scenario, we modified C class not C – Given a class C – Record the numbers of its instance ever created – Report this number when the program ends
  101. 101. 101/210 Scenarios  Scenario 3: In Smalltalk, each class has one anonymous meta-class, which can be modified • Adding new variables and methods which are thus class variables and class methods • These methods apply on the class, these fields belong to the class (thus unique) – Given a class C – Record the numbers of its instance ever created – Report this number when the program ends
  102. 102. 102/210 Scenarios  Scenario 3: – What about a subclass D of C? – How would its instances be counted? a C a C a C 3 – Given a class C – Record the numbers of its instance ever created – Report this number when the program ends Thanks to Christophe Dony for suggesting this use of class vs. class instance variables
  103. 103. 103/210 Scenarios  Scenario 3: – In C++ and Java: static = global • The class variables is shared by all the instances of its declaring class… and its subclasses! final D o4 = new D(); // Eclipse advises to use C to call getNumberOfInstances(). System.out.println(o4); System.out.println(D.getNumberOfInstances()); – Given a class C – Record the numbers of its instance ever created – Report this number when the program ends
  104. 104. 104/210 Scenarios  Scenario 3: – In Smalltalk: class vs. class instance • Class variable vs. class instance variable – A class variable is shared by all the instance of the class and all the instances of its subclasses – A class instance variable is unique to each class, inherited from the super-class, like instance variables C class instanceVariableNames: 'IndividualClassNumberOfInstances' – Given a class C – Record the numbers of its instance ever created – Report this number when the program ends
  105. 105. 105/210 Scenarios  Scenario 3: – In Smalltalk: class vs. class instance C subclass: #D instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Ptidej'. D class compile: 'initialize IndividualClassNumberOfInstances := 0.'. D class compile: 'new NumberOfInstances := NumberOfInstances + 1. IndividualClassNumberOfInstances := IndividualClassNumberOfInstances + 1. ^ self basicNew initialize.'. D class compile: 'numberOfInstances ^ NumberOfInstances.'. D class compile: 'individualClassNumberOfInstances ^ IndividualClassNumberOfInstances.'. – Given a class C – Record the numbers of its instance ever created – Report this number when the program ends
  106. 106. 106/210 Scenarios  Scenario 3: – In Smalltalk: class vs. class instance | o4 | D initialize. o4 := D new. Transcript show: o4 ; cr. Transcript show: C numberOfInstances ; cr. Transcript show: D numberOfInstances ; cr. Transcript show: D individualClassNumberOfInstances ; cr. – Given a class C – Record the numbers of its instance ever created – Report this number when the program ends a D 4 4 1
  107. 107. 107/210 Scenarios  Scenario 3: – In Java: the JVM contains the world • Possible to connect to a JVM using the Java Debug Interface of the Java Platform Debug Architecture • Possible to reify the classes existing in the remote JVM and to obtain their instances com.sun.jdi.ReferenceType.instances(long) • Special feature of the JVM, “outside” of the normal constructs of the language – Given a class C – Record the numbers of its instance ever created – Report this number when the program ends http://stackoverflow.com/questions/1947122/ is-there-a-simple-way-of-obtaining-all-object-instances-of-a-specific-class-in-j/1947200#1947200
  108. 108. 108/210 Scenarios  Scenario 3: – In Smalltalk: the image contains the world • Possible to ask it all the instances of a particular class or all the instances currently in memory Transcript show: (C allInstances size). – Given a class C – Record the numbers of its instance ever created – Report this number when the program ends Thanks to Marcus Denker for pointing out this solution
  109. 109. 109/210 Scenarios  Scenario 4: – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo() Object subclass: #C instanceVariableNames: 'i' classVariableNames: '' poolDictionaries: '' category: 'CSE3009'. C class compile: 'newWithi: anInt ^(self new) i: anInt ; yourself.'. C compile: 'foo: aText Transcript show: aText. Transcript show: i. Transcript cr.'. C compile: 'i: anInt i := anInt.'.
  110. 110. 110/210 Scenarios  Scenario 4: – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo() This is o: 42 Intercepting message send: foo: Original arguments: This is o: New arguments: THIS IS O: THIS IS O: 42
  111. 111. 111/210 Scenarios  Scenario 4: Several choices • ObjectWrappers: http://magaloma.seasidehosting.st/ Kernel#ObjectTracer • MethodWrappers: http://pharo.gforge.inria.fr/ PBE1/PBE1ch15.html • Reflectivity: http://scg.unibe.ch/Research/Reflectivity • … – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo()
  112. 112. 112/210 Scenarios  Scenario 4: Several choices • ObjectWrappers: http://magaloma.seasidehosting.st/ Kernel#ObjectTracer • MethodWrappers: http://pharo.gforge.inria.fr/ PBE1/PBE1ch15.html • Reflectivity: http://scg.unibe.ch/Research/Reflectivity • … – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo()
  113. 113. 113/210 Scenarios  Scenario 4: – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo() | o aWrapper | o := C newWithi: 42. o foo: 'This is o: '. aWrapper := WrapperForC on: o. "o become: aWrapper." aWrapper foo: 'This is o: '. aWrapper xxxUnTrace.
  114. 114. 114/210  Scenario 4: – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo() ObjectTracer subclass: #WrapperForC instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'CSE3009'. WrapperForC compile: 'doesNotUnderstand: aMessage "Intercept the selector foo:" | sel arg newArg | sel := aMessage selector. sel = ''foo:'' ifTrue: [ arg := (aMessage arguments) at: 1. newArg := arg asUppercase. Transcript show: ''Intercepting message send: '' ; show: sel ; cr. Transcript tab ; show: ''Original arguments: '' ; show: arg ; cr. Transcript tab ; show: ''New arguments: '' ; show: newArg ; cr. aMessage argument: newArg. aMessage sendTo: (self xxxViewedObject) ] ifFalse: [ "Transcript show: aMessage." ]'.
  115. 115. 115/210 Scenarios  Scenario 4: – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo() This is o: 42 Intercepting message send: foo: Original arguments: This is o: New arguments: THIS IS O: THIS IS O: 42 | o aWrapper | o := C newWithi: 42. o foo: 'This is o: '. aWrapper := WrapperForC on: o. "o become: aWrapper." aWrapper foo: 'This is o: '. aWrapper xxxUnTrace.
  116. 116. 116/210 Scenarios  Scenario 4: – We created the class WrappedForC that does not understand many messages (as subclass of ProtoObject) – We wrapped an instance of WrappedForC around o and use doesNotUnderstand: to proxy messages – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo()
  117. 117. 117/210 Scenarios  Scenario 4: – We created the class WrappedForC that does not understand many messages (as subclass of ProtoObject) – We wrapped an instance of WrappedForC around o and use doesNotUnderstand: to proxy messages – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo()
  118. 118. 118/210 Scenarios  Scenario 4: Several choices • ObjectWrappers: http://magaloma.seasidehosting.st/ Kernel#ObjectTracer • MethodWrappers: http://pharo.gforge.inria.fr/ PBE1/PBE1ch15.html • Reflectivity: http://scg.unibe.ch/Research/Reflectivity • … – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo()
  119. 119. 119/210 Scenarios  Reflectivity – Marcus Denker, RMOD Team, INRIA Lille, and others – Extensions to the standard reflection features of Smalltalk (both structural and behavioural) • Structural reflection is extended by sub-method reflection: method bodies are first-class • Behavioural reflection is provided by Geppetto, an implementation of Partial Behavioural Reflection
  120. 120. 120/210 Scenarios  Scenario 4: – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo() Object subclass: #C instanceVariableNames: 'i' classVariableNames: '' poolDictionaries: '' category: 'CSE3009'. C class compile: 'newWithi: anInt ^(self new) i: anInt ; yourself.'. C compile: 'foo: aText Transcript show: aText. Transcript show: i. Transcript cr.'. C compile: 'i: anInt i := anInt.'.
  121. 121. 121/210 Scenarios  Scenario 4: – Sub-method reflection – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo() nodes := (C>>#foo:) sends select: [:each | ((each selector ~= #show:) or: (each arguments) size ~= 1) ifTrue: [ false ] ifFalse: [ (each arguments at: 1) name = 'aText'. ]. ].
  122. 122. 122/210 Scenarios  Scenario 4: – Meta-object – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo() gpLink := GPLink metaObject: [:arg1 :node | | newArg | newArg := arg1 asUppercase. Transcript show: 'Intercepting message send: '. Transcript show: node ; cr. Transcript tab ; show: 'Original arguments: '. Transcript show: arg1 ; cr. Transcript tab ; show: 'New arguments: '. Transcript show: newArg ; cr. Transcript show: newArg. ]. gpLink control: #instead.
  123. 123. 123/210 Scenarios  Scenario 4: – Linking – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo() o := C newWithi: 42. o foo: 'This is o: '. nodes do: [:node | node link: gpLink]. o foo: 'This is o: '. gpLink uninstall. This is o: 42 Intercepting message send: foo: Original arguments: This is o: New arguments: THIS IS O: THIS IS O: 42
  124. 124. 124/210 Scenarios  Scenarios 1, 2, 3, and 4 More difficult to implement “as is” • http://stackoverflow.com/questions/359237/why-does- c-not-have-reflection • http://www.open-std.org/jtc1/sc22/wg21/docs/papers/ 2005/n1751.html
  125. 125. 125/210 Scenarios  Scenarios 1, 2, 3, and 4 Third-party solutions • Mirror: http://kifri.fri.uniza.sk/~chochlik/mirror- lib/html/index.html#introduction • VisualStudio.NET: http://msdn.microsoft.com/en- us/library/y0114hz2%28v=vs.110%29.aspx • …
  126. 126. 126/210 Scenarios  Scenarios 1, 2, 3, and 4 Third-party solutions • Mirror: http://kifri.fri.uniza.sk/~chochlik/mirror- lib/html/index.html#introduction • VisualStudio.NET: http://msdn.microsoft.com/en- us/library/y0114hz2%28v=vs.110%29.aspx • …
  127. 127. 127/210 Scenarios  Mirror – Matúš Chochlík, University of Žilina, Žilina, Slovakia “[C]ompile-time and run-time meta-data describing C++ constructs like namespaces, types typedef-ined types, enums, classes with their base classes, member variables, constructors, member functions, etc.”
  128. 128. 128/210 Scenarios  Scenario 1: – Given a class C – Given an object o, instance of C – Identify all the methods available on o – Invoke a method using its name foo namespace cse3009 { class C { private: int i; public: C(const int _i) : i(_i) { } int get_i(void) const { return this->i; } void set_i(const int _i) { this->i = _i; } void foo(const std::string _s) const { std::cout << _s << this->i << std::endl; } }; }
  129. 129. 129/210 Scenarios  Scenario 1: – Given a class C – Given an object o, instance of C – Identify all the methods available on o – Invoke a method using its name foo Identify all the methods available on o (The type of o is cse3009::C) cse3009::C::i cse3009::C::foo Invoke a method using its name foo This is foo: 42
  130. 130. 130/210 Scenarios  Scenario 1: – Given a class C – Given an object o, instance of C – Identify all the methods available on o – Invoke a method using its name foo int main(void) { cse3009::C * o = new cse3009::C(42); std::cout << "Identify all the methods available on o" << std::endl; identify_members(o); std::cout << "Invoke a method using its name foo" << std::endl; invoke_member_function(o); return 0; }
  131. 131. 131/210 Scenarios  Scenario 1: – Given a class C – Given an object o, instance of C – Identify all the methods available on o – Invoke a method using its name foo template<typename O> void identify_members(O * _o) { using namespace mirror; typedef MIRRORED_CLASS(O) meta_Class; std::cout << "t(The type of o is " << meta_Class::full_name() << ")" << std::endl; std::cout << "t"; mp::for_each_ii< all_member_variables<meta_Class> >(info_printer()); std::cout << std::endl << "t"; mp::for_each_ii< member_functions<meta_Class> >(info_printer()); std::cout << std::endl; }
  132. 132. 132/210 Scenarios  Scenario 1: – Given a class C – Given an object o, instance of C – Identify all the methods available on o – Invoke a method using its name foo template<typename O> void invoke_member_function(O * _o) { using namespace mirror; typedef MIRRORED_CLASS(cse3009::C) meta_Class; typedef mp::at_c<overloads< mp::at_c<member_functions<meta_Class>, 0>::type>, 0>::type meta_foo; my_invoker_maker::invoker<meta_foo>::type invoker( std::string("tThis is foo: ")); invoker.call_on(*_o); }
  133. 133. 133/210 Scenarios  Mirror – Provides essentially the same concepts and features as java.lang.reflect of Java – Uses templates and (manual) registration to collect metadata that does not exist unless manually created through macro preprocessing
  134. 134. 134/210 Scenarios  Scenario 1: – Given a class C – Given an object o, instance of C – Identify all the methods available on o – Invoke a method using its name foo MIRROR_REG_BEGIN MIRROR_QREG_GLOBAL_SCOPE_NAMESPACE(std) MIRROR_REG_CLASS_BEGIN(struct, std, string) MIRROR_REG_CLASS_END MIRROR_QREG_GLOBAL_SCOPE_NAMESPACE(cse3009) MIRROR_REG_CLASS_BEGIN(class, cse3009, C) MIRROR_REG_CLASS_MEM_VARS_BEGIN MIRROR_REG_CLASS_MEM_VAR_GET_SET( private, _, int, i, _.get_i(), _.set_i(_i)) MIRROR_REG_CLASS_MEM_VARS_END MIRROR_REG_MEM_FUNCTIONS_BEGIN MIRROR_REG_MEM_OVLD_FUNC_BEGIN(foo) MIRROR_REG_MEM_FUNCTION_BEGIN(public, _, void, foo, 1) MIRROR_REG_MEM_FUNCTION_PARAM(std::string, _s) MIRROR_REG_MEM_FUNCTION_END(1, _) MIRROR_REG_MEM_OVLD_FUNC_END(foo) MIRROR_REG_MEM_FUNCTIONS_END MIRROR_REG_CLASS_END MIRROR_REG_END
  135. 135. 135/210 Scenarios  Scenario 1: – Given a class C – Given an object o, instance of C – Identify all the methods available on o – Invoke a method using its name foo template<class Unused> struct my_manufacturer<std::string, Unused> { const std::string s; template<class ConstructionInfo> inline my_manufacturer(const std::string _s, const ConstructionInfo construction_info) : s(_s) { } void finish(std::string) const { } inline std::string operator()(void) const { return s; } }; typedef mirror::invoker_maker<my_manufacturer, mirror::default_fact_suppliers, my_enumerator, void> my_invoker_maker;
  136. 136. 136/210 Scenarios  Mirror – Uses complex code that can be easily and advantageously hidden in libraries – Will possibly become part of Boost and the standard reflection library for C++ • http://kifri.fri.uniza.sk/~chochlik/jtc1_sc22_wg21/ std_cpp_refl-latest.pdf
  137. 137. 137/210 Scenarios  Scenario 2: namespace cse3009 { class C { private: int i; public: C(const int _i) : i(_i) { } int get_i(void) const { return this->i; } void set_i(const int _i) { this->i = _i; } void foo(const std::string _s) const { std::cout << _s << this->i << std::endl; } }; } – Given an object o, instance of C – Save on disk the complete state of o – Restore from disk the object o at a later time
  138. 138. 138/210 Scenarios  Scenario 2: – Given an object o, instance of C – Save on disk the complete state of o – Restore from disk the object o at a later time Save on disk the complete state of o (The type of o is cse3009::C) cse3009::C::i = 42 Restore from disk the object o at a later time 43
  139. 139. 139/210 Scenarios  Scenario 2: – Given an object o, instance of C – Save on disk the complete state of o – Restore from disk the object o at a later time int main(void) { cse3009::C * o = new cse3009::C(42); std::cout << "Save on disk the complete state of o" << std::endl; save_on_disk(o); std::cout << "Restore from disk the object o at a later time" << std::endl; restore_from_disk<cse3009::C>(); return 0; }
  140. 140. 140/210 Scenarios  Scenario 2: – Given an object o, instance of C – Save on disk the complete state of o – Restore from disk the object o at a later time template<typename O> void save_on_disk(O * _o) { using namespace mirror; typedef MIRRORED_CLASS(O)meta_Class; std::cout << "t(The type of o is " << meta_Class::full_name() << ")" << std::endl << "t"; mp::for_each_ii<all_member_variables<meta_Class>>( info_printer_variables<O>(*_o)); std::cout << std::endl; }
  141. 141. 141/210 Scenarios  Scenario 2: – Given an object o, instance of C – Save on disk the complete state of o – Restore from disk the object o at a later time template<class O> struct info_printer_variables { O o; inline info_printer_variables(O _o) : o(_o) { } template<class IterInfo> void operator()(IterInfo) { using namespace mirror; std::cout << IterInfo::type::full_name() << " = " << IterInfo::type::get(o); if (!IterInfo::is_last::value) std::cout << ", "; } };
  142. 142. 142/210 Scenarios  Scenario 2: – Given an object o, instance of C – Save on disk the complete state of o – Restore from disk the object o at a later time template<class O> struct info_printer_variables { O o; inline info_printer_variables(O _o) : o(_o) { } template<class IterInfo> void operator()(IterInfo) { using namespace mirror; std::cout << IterInfo::type::full_name() << " = " << IterInfo::type::get(o); if (!IterInfo::is_last::value) std::cout << ", "; } }; Get the value of reflected variable
  143. 143. 143/210 Scenarios  Scenario 2: – Given an object o, instance of C – Save on disk the complete state of o – Restore from disk the object o at a later time template<typename O> void restore_from_disk(void) { using namespace mirror; typedef typename my_factory_maker::factory<O>::type my_factory_type; my_factory_type my_factory(43); O o(my_factory()); std::cout << "t" << o.get_i() << std::endl; }
  144. 144. 144/210 Scenarios  Scenario 2: – Given an object o, instance of C – Save on disk the complete state of o – Restore from disk the object o at a later time typedef mirror::factory_maker< my_manufacturer, mirror::default_fact_suppliers, my_enumerator, void> my_factory_maker;
  145. 145. 145/210 Scenarios  Scenario 2: – Given an object o, instance of C – Save on disk the complete state of o – Restore from disk the object o at a later time typedef mirror::factory_maker< my_manufacturer, mirror::default_fact_suppliers, my_enumerator, void> my_factory_maker; Factory generating instances of (possibly) different types
  146. 146. 146/210 Scenarios  Scenario 2: – Given an object o, instance of C – Save on disk the complete state of o – Restore from disk the object o at a later time template<class Unused> struct my_manufacturer<void, Unused> { template<typename Context> my_manufacturer(int _value, Context) { } void finish(int) { } template<class ConstructionInfo> inline int add_constructor( int _value, ConstructionInfo) const { return _value; } inline int index(void) { return 0; } };
  147. 147. 147/210 Scenarios  Scenario 2: – Given an object o, instance of C – Save on disk the complete state of o – Restore from disk the object o at a later time template<class Unused> struct my_manufacturer<void, Unused> { template<typename Context> my_manufacturer(int _value, Context) { } void finish(int) { } template<class ConstructionInfo> inline int add_constructor( int _value, ConstructionInfo) const { return _value; } inline int index(void) { return 0; } }; To pass on to the constructor
  148. 148. 148/210 template<class Product, typename IsEnum> struct my_base_manufacturer { Product x; struct constr_param_name_printer { template<class IterInfo> inline void operator()(IterInfo) const { if (!IterInfo::is_first::value) std::cout << ", "; std::cout << IterInfo::type::base_name(); } }; struct constr_context_printer { template<class IterInfo> inline void operator()(IterInfo) const { if (!IterInfo::is_first::value) std::cout << "::"; std::cout << IterInfo::type::base_name(); } }; template<class ConstructionInfo> my_base_manufacturer(int tabs, ConstructionInfo construction_info, const Product& _x) : x(tabs) { } void finish(int) { } inline Product operator()(void) { return x; } }; template<class Product, class Unused> struct my_enumerator : my_base_manufacturer<Product, std::true_type> { template<class ConstructionInfo> inline my_enumerator(int tabs, ConstructionInfo construction_info) : my_base_manufacturer<Product, std::true_type>( tabs, construction_info, Product()) { } void finish(int) { } inline Product operator()(void) { return NULL; } }; template<class Product, class Unused> struct my_manufacturer { typedef typename mirror::factory_maker< my_manufacturer, mirror::default_fact_suppliers, my_enumerator, Unused> maker; typename maker::template factory<Product>::type f; template<class ConstructionInfo> inline my_manufacturer( int _value, ConstructionInfo construction_info) : f(construction_info) { } void finish(int) { } inline Product operator()(void) { return f(); } };
  149. 149. 149/210 template<class Product, typename IsEnum> struct my_base_manufacturer { Product x; struct constr_param_name_printer { template<class IterInfo> inline void operator()(IterInfo) const { if (!IterInfo::is_first::value) std::cout << ", "; std::cout << IterInfo::type::base_name(); } }; struct constr_context_printer { template<class IterInfo> inline void operator()(IterInfo) const { if (!IterInfo::is_first::value) std::cout << "::"; std::cout << IterInfo::type::base_name(); } }; template<class ConstructionInfo> my_base_manufacturer(int tabs, ConstructionInfo construction_info, const Product& _x) : x(tabs) { } void finish(int) { } inline Product operator()(void) { return x; } }; template<class Product, class Unused> struct my_enumerator : my_base_manufacturer<Product, std::true_type> { template<class ConstructionInfo> inline my_enumerator(int tabs, ConstructionInfo construction_info) : my_base_manufacturer<Product, std::true_type>( tabs, construction_info, Product()) { } void finish(int) { } inline Product operator()(void) { return NULL; } }; template<class Product, class Unused> struct my_manufacturer { typedef typename mirror::factory_maker< my_manufacturer, mirror::default_fact_suppliers, my_enumerator, Unused> maker; typename maker::template factory<Product>::type f; template<class ConstructionInfo> inline my_manufacturer( int _value, ConstructionInfo construction_info) : f(construction_info) { } void finish(int) { } inline Product operator()(void) { return f(); } }; Less complex than it looks!
  150. 150. 150/210 template<class Product, typename IsEnum> struct my_base_manufacturer { Product x; struct constr_param_name_printer { template<class IterInfo> inline void operator()(IterInfo) const { if (!IterInfo::is_first::value) std::cout << ", "; std::cout << IterInfo::type::base_name(); } }; struct constr_context_printer { template<class IterInfo> inline void operator()(IterInfo) const { if (!IterInfo::is_first::value) std::cout << "::"; std::cout << IterInfo::type::base_name(); } }; template<class ConstructionInfo> my_base_manufacturer(int tabs, ConstructionInfo construction_info, const Product& _x) : x(tabs) { } void finish(int) { } inline Product operator()(void) { return x; } }; template<class Product, class Unused> struct my_enumerator : my_base_manufacturer<Product, std::true_type> { template<class ConstructionInfo> inline my_enumerator(int tabs, ConstructionInfo construction_info) : my_base_manufacturer<Product, std::true_type>( tabs, construction_info, Product()) { } void finish(int) { } inline Product operator()(void) { return NULL; } }; template<class Product, class Unused> struct my_manufacturer { typedef typename mirror::factory_maker< my_manufacturer, mirror::default_fact_suppliers, my_enumerator, Unused> maker; typename maker::template factory<Product>::type f; template<class ConstructionInfo> inline my_manufacturer( int _value, ConstructionInfo construction_info) : f(construction_info) { } void finish(int) { } inline Product operator()(void) { return f(); } }; Less complex than it looks!Can be replaced by existing factories
  151. 151. 151/210 Scenarios  Scenario 2: – Mirror provides many ready-to-use factories • From strings (mirror/example/factories/tetrahedron_script.cpp) • From a SOCI database (mirror/example/factories/tetrahedron_soci.cpp) – Given an object o, instance of C – Save on disk the complete state of o – Restore from disk the object o at a later time // make the input object for the factory script_factory_input in; // create a factory plugged with the script parser script_factory_maker::factory<tetrahedron>::type f = in.data(); // make a tetrahedron object factory soci_quick_factory_maker::factory<test::tetrahedron>::type tetrahedron_factory = soci_fact_data(r); while(r != e) { test::tetrahedron t = tetrahedron_factory(); // and write it to std output std::cout << stream::to_json::from(t, [&i](std::ostream& out) { out << "tetrahedron_" << i; } ) << std::endl;
  152. 152. 152/210 Scenarios  Scenario 3: namespace cse3009 { class C { private: int i; static int numberOfInstances; public: C(const int _i) : i(_i) { numberOfInstances++; } ... void foo(const std::string _s) const { std::cout << _s << this->i << std::endl; } static int getNumberOfInstances() { return numberOfInstances; } }; } – Given a class C – Record the numbers of its instance ever created – Report this number when the program ends
  153. 153. 153/210 Scenarios  Scenario 3: int cse3009::C::numberOfInstances = 0; int main(void) { cse3009::C * o1 = new cse3009::C(42); cse3009::C * o2 = new cse3009::C(1); cse3009::C * o3 = new cse3009::C(100); std::cout << o1 << std::endl << o2 << std::endl << o3 << std::endl; std::cout << cse3009::C::getNumberOfInstances() << std::endl; return 0; } – Given a class C – Record the numbers of its instance ever created – Report this number when the program ends
  154. 154. 154/210 Scenarios  Scenario 3: 0x800418f8 0x80041908 0x80041918 3 – Given a class C – Record the numbers of its instance ever created – Report this number when the program ends
  155. 155. 155/210 Scenarios  Scenario 3: 0x800418f8 0x80041908 0x80041918 3 – Given a class C – Record the numbers of its instance ever created – Report this number when the program ends To fulfill this scenario, we must modify C as in Java
  156. 156. 156/210 Scenarios  Scenario 4: – Several choices • Bjarne Stroustrup's Template: http://www.stroustrup.com/wrapper.pdf • Herb Sutter's Functor-based Approach: http://channel9.msdn.com/Shows/Going+Deep/ C-and-Beyond-2012-Herb-Sutter-Concurrency-and- Parallelism • Ion Armagedescu’s CPatcher: http://www.codeproject.com/Articles/34237/A-C-Style- of-Intercepting-Functions – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo()
  157. 157. 157/210 Scenarios  Scenario 4: – Several choices • Bjarne Stroustrup's Template: http://www.stroustrup.com/wrapper.pdf • Herb Sutter's Functor-based Approach: http://channel9.msdn.com/Shows/Going+Deep/ C-and-Beyond-2012-Herb-Sutter-Concurrency-and- Parallelism • Ion Armagedescu’s CPatcher: http://www.codeproject.com/Articles/34237/A-C-Style- of-Intercepting-Functions – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo()
  158. 158. 158/210 Scenarios  Scenario 4: – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo() Bjarne Stroustrup's Template: (Prefix::operator->()) This is o: 42
  159. 159. 159/210 Scenarios  Scenario 4: – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo() int main(void) { std::cout << "Bjarne Stroustrup's Template:" << std::endl; cse3009::C o2(42); Prefix<cse3009::C> prefixed_o2(&o2); prefixed_o2->foo("This is o: "); std::cout << std::endl; return 0; }
  160. 160. 160/210 Scenarios  Scenario 4: – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo() template<class T> class Prefix { T* p; public: Prefix(T * _p) : p(_p) { } T* operator->() { std::cout << "(Prefix::operator->())" << std::endl; return p; } };
  161. 161. 161/210 Scenarios  Scenario 4: – Is similar to a proxy in Java – Cannot easily access and modify the arguments of the proxy’ed method call – Makes it difficult to do something after the original method call – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo()
  162. 162. 162/210 Scenarios  Scenario 4: – Several choices • Bjarne Stroustrup's Template: http://www.stroustrup.com/wrapper.pdf • Herb Sutter's Functor-based Approach: http://channel9.msdn.com/Shows/Going+Deep/ C-and-Beyond-2012-Herb-Sutter-Concurrency-and- Parallelism • Ion Armagedescu’s CPatcher: http://www.codeproject.com/Articles/34237/A-C-Style- of-Intercepting-Functions – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo()
  163. 163. 163/210 Scenarios  Scenario 4: Dependent on the compiler! GCC v4.8.2 vs. Microsoft Visual Studio Express 2013 – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo() Visual C++ 2013 06157-004-0441005-02428
  164. 164. 164/210 Scenarios  Scenario 4: – GCC v4.8.2 In file included from ..Sourcescenario4.cpp:32:0: ..Source../CPatcher/patcher.h: In instantiation of 'void CPatch::HookClassFunctions(T1&, T2, bool, bool) [with T1 = void (cse3009::C::*)(std::basic_string<char>); T2 = void (class_for_patches::*)(std::basic_string<char>)]': ..Source../CPatcher/patcher_defines.h:131:2: required from 'CPatch::CPatch(TReturnVal (TClassSource::*&)(TArg1), TReturnVal (TClassTarget::*)(TArg1), bool, bool) [with TClassSource = cse3009::C; TClassTarget = class_for_patches; TReturnVal = void; TArg1 = std::basic_string<char>]' ..Sourcescenario4.cpp:52:61: required from here – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo()
  165. 165. 165/210 Scenarios  Scenario 4: – GCC v4.8.2 may not be legal • http://www.codeproject.com/Articles/34237/A-C-Style- of-Intercepting-Functions?msg=4796042 • http://stackoverflow.com/questions/1307278/casting- between-void-and-a-pointer-to-member-function – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo() *reinterpret_cast<long*>(&fn_funcToHook) *reinterpret_cast<long*>(&fn_Hook)
  166. 166. 166/210 Scenarios  Scenario 4: – Microsoft Visual Studio Express 2013 – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo() void(ptidej::C::*pfn_foo)(const std::string) = &ptidej::C::foo; class proxy { public: void my_foo(const std::string s) { std::cout << "Function foo() is patched!" << std::endl << std::flush; (reinterpret_cast<ptidej::C*>(this)->*pfn_foo)(s); } }; int _tmain(int argc, _TCHAR* argv[]) { CPatch patch_aclass_doSomething(pfn_foo, &proxy::my_foo); ptidej::C o(42); o.foo(std::string("This is o: ")); return 0; }
  167. 167. 167/210 Scenarios  Scenario 4: – Microsoft Visual Studio Express 2013 – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo() Function foo() is patched! This is o: 42
  168. 168. 168/210 Scenarios  Scenario 4: – Is similar to a proxy in Java – Can easily access and modify the arguments of the proxy’ed method call – Makes it difficult to do something after the original method call – Given an object o, instance of C – Without changing o or C – Change the behaviour of o.foo()
  169. 169. 169/210 Scenarios Java  Smalltalk  C++ 
  170. 170. 170/210 Conclusion Java  Smalltalk  C++ 
  171. 171. 171/210 Conclusion Java  Smalltalk  C++  Differences in semantics and syntax mostly due to the presence (or absence) of virtual machines
  172. 172. 172/210 Outline  Rationale  Definition  Context – Interconnections  Scenarios  Theory  Conclusion  Class Loading
  173. 173. 173/210 Theory  Class – A programming construct that encapsulates some state (fields) and behaviours (methods) – A construct whose instances are objects  Metaclass – A programming construct that encapsulates some state (fields) and behaviours (methods) – A construct whose instances are classes Aristote (Ἀριστοτέλης) *-384 †-322
  174. 174. 174/210 Theory  An object is an instance of a class – A class generates an object  A class is an instance of a metaclass – A metaclass generates a class  A metaclass is an instance of…
  175. 175. 175/210 Theory  An object is an instance of a class – A class generates an object  A class is an instance of a metaclass – A metaclass generates a class  A metaclass is an instance of… (a) A meta-metaclass?
  176. 176. 176/210 Theory  An object is an instance of a class – A class generates an object  A class is an instance of a metaclass – A metaclass generates a class  A metaclass is an instance of… (a) A meta-metaclass? (b) Itself?
  177. 177. 177/210 Theory  An object is an instance of a class – A class generates an object  A class is an instance of a metaclass – A metaclass generates a class  A metaclass is an instance of… (a) A meta-metaclass? (b) Itself
  178. 178. 178/210 Theory  The class Object is the parent of all classes, including metaclasses  The class Class is the generator of all classes, including Object
  179. 179. 179/210 Des langages de programmation à objets à la représentation des connaissances à travers le MOP : vers une intégration par Gabriel Pavillet. Thèse de doctorat en Informatique sous la direction de Roland Ducournau, soutenue en 2000 à Montpellier 2
  180. 180. 180/210 Theory  The classes – Class – Method – Field – … reify constructs of the programming languages, they become first-class entities, to allow programs to manipulate these constructs at runtime
  181. 181. 181/210 Theory Java  Field  C  Method  C  Static field  C  Static method  C   Smalltalk  Instance variable  C  Instance method  C  Class variable  C class  Class method  C class  Class instance variables – To count the numbers of instances of subclasses of C (D, E…) independently from one another
  182. 182. 182/210 Theory  Earlier, we said that reflection is of – Theoretical interest • What is an interpreter? Brian Cantwell Smith “Procedural Reflection in Programming Languages” (Ph.D. thesis, 1982) – Practical interest • Libraries • Frameworks
  183. 183. 183/210 Theory  Earlier, we said that reflection is of – Theoretical interest • What is an interpreter? Brian Cantwell Smith “Procedural Reflection in Programming Languages” (Ph.D. thesis, 1982) – Practical interest • Libraries • Frameworks
  184. 184. 184/210 Theory  Earlier, we said that reflection is of – Theoretical interest • What is an interpreter? Brian Cantwell Smith “Procedural Reflection in Programming Languages” (Ph.D. thesis, 1982) – Practical interest • Libraries • Frameworks A virtual machine is an interpreter
  185. 185. 185/210 Theory  In Java, the metaclass is anonymous and cannot be modified  In Smalltalk, “[t]here is only one instance of a particular Metaclass, namely the class which is being described”
  186. 186. 186/210 Theory  Many other variations are possible – LISP • http://www.cliki.net/mop – Perl 5, 6 • http://search.cpan.org/perldoc?Class::MOP – Python • https://www.python.org/doc/essays/metaclasses/ – MetaclassTalk – Noury Bouraqadi, Pierre Cointe • http://csl.ensm-douai.fr/MetaclassTalk – NeoClassTalk – Fred Rivard, Pierre Cointe • http://c2.com/cgi/wiki?NeoClassTalk – OpenC++ – Shigeru Chiba, Gregor Kiczales • http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/openc++.html
  187. 187. 187/210 Theory  A Meta Object Protocol exposes some or all internal structure of the interpreter to the programmer  The MOP is (often) a set of classes and methods that allow a program to inspect the state of the supporting system and alter its behaviour
  188. 188. 188/210 Theory  MOP can be accessible at – Compile-time • OpenJava – http://www.csg.ci.i.u-tokyo.ac.jp/openjava/ – Load-time • Javassist – http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/ – Run-time • AspectJ – http://eclipse.org/aspectj/
  189. 189. 189/210 Outline  Rationale  Definition  Context – Interconnections  Scenarios  Theory  Conclusion  Class Loading
  190. 190. 190/210 Conclusion  Scenario 1: invoke an arbitrary method on an object (see the problems with instanceof and plugins)  Scenario 2: access the complete (including private) state of an object (see the problem with serialisation)  Scenario 3: count the number of instances of a class created at runtime (see the problem with debugging/profiling)  Scenario 4: modify the behaviour at run-time of a method without the need to recompile and restart the program (see the problem with patching)
  191. 191. 191/210 Conclusion  Reflection helps addressing these scenarios – Depends on the capabilities of the programming language and underlying execution environment – Yields more or less elegant code  Use reflection sparingly and purposefully – Complexity – Performance
  192. 192. 192/210 Conclusion Java  Smalltalk  C++ 
  193. 193. 193/210 Conclusion Java  Smalltalk  C++ 
  194. 194. 194/210 Conclusion Java  Smalltalk  C++  Differences in semantics and syntax mostly due to the presence (or absence) of virtual machines
  195. 195. 195/210 Outline  Rationale  Definition  Context – Interconnections  Scenarios  Theory  Conclusion  Class Loading
  196. 196. 196/210 Class Loading  Virtual machines – Interpreters – Closed world  Must – Access resources – Load classes
  197. 197. 197/210 Class Loading  Virtual machines – Interpreters – Closed world  Must – Access resources – Load classes
  198. 198. 198/210 Class Loading  Virtual machines – Interpreters – Closed world  Must – Access resources – Load classes
  199. 199. 199/210 Class Loading  Example – Given an interface ICommand – Load at runtime a class implementing ICommand using its binary name • A binary name is in the form <pckg1>.….<pckgn>.<ClassName> – net.ptidej.reflection.java.scenario1.C final Class<ICommand> command = this.classLoader.loadClass(binaryName);
  200. 200. 200/210 Class Loading http://map.sdsu.edu/geog583/images/week8.3.gif
  201. 201. 201/210 Class Loading http://www.onjava.com/2005/01/26/graphics/Figure01_MultipleClassLoaders.JPG
  202. 202. 202/210 Class Loading public class ClassLoader extends java.lang.ClassLoader { private final String directory; public ClassLoader( final java.lang.ClassLoader parent, final String directory) { super(parent); this.directory = directory; }
  203. 203. 203/210 Class Loading protected Class findClass(final String name) { Class newClass = null; try { newClass = super.findClass(name); } catch (final ClassNotFoundException cnfe) { final String osName = this.directory + name.replace('.', '/') + ".class"; try { final FileInputStream fis = new FileInputStream(osName); newClass = this.defineClasses(name, fis); } catch (final ClassFormatError cfe) { cfe.printStackTrace(Output.getInstance().errorOutput()); } catch (final FileNotFoundException fnfe) { // fnfe.printStackTrace(); } } return newClass; }
  204. 204. 204/210 Class Loading protected Class findClass(final String name) { Class newClass = null; try { newClass = super.findClass(name); } catch (final ClassNotFoundException cnfe) { final String osName = this.directory + name.replace('.', '/') + ".class"; try { final FileInputStream fis = new FileInputStream(osName); newClass = this.defineClasses(name, fis); } catch (final ClassFormatError cfe) { cfe.printStackTrace(Output.getInstance().errorOutput()); } catch (final FileNotFoundException fnfe) { // fnfe.printStackTrace(); } } return newClass; } Use the method defined in the superclass on this CL
  205. 205. 205/210 Class Loading private Class defineClasses(final String name, final InputStream inputStream) { try { int b; int length = 0; byte[] bytes = new byte[4]; while ((b = inputStream.read()) != -1) { if (length == bytes.length) { final byte[] temp = new byte[length + 4]; System.arraycopy(bytes, 0, temp, 0, length); bytes = temp; } bytes[length] = (byte) b; length++; } System.out.println(name); final Class newClass = this.defineClass(name, bytes, 0, length); return newClass; } catch (final IOException ioe) { return null; } catch (final NoClassDefFoundError ncdfe) { ncdfe.printStackTrace(Output.getInstance().errorOutput()); return null; } }
  206. 206. 206/210 Class Loading private Class defineClasses(final String name, final InputStream inputStream) { try { int b; int length = 0; byte[] bytes = new byte[4]; while ((b = inputStream.read()) != -1) { if (length == bytes.length) { final byte[] temp = new byte[length + 4]; System.arraycopy(bytes, 0, temp, 0, length); bytes = temp; } bytes[length] = (byte) b; length++; } System.out.println(name); final Class newClass = this.defineClass(name, bytes, 0, length); return newClass; } catch (final IOException ioe) { return null; } catch (final NoClassDefFoundError ncdfe) { ncdfe.printStackTrace(Output.getInstance().errorOutput()); return null; } } Use the method defined in the superclass on this CL
  207. 207. 207/210 Class Loading http://www.onjava.com/2005/01/26/graphics/Figure01_MultipleClassLoaders.JPG
  208. 208. 208/210 Class Loading protected Class findClass(final String name) { Class newClass = null; try { newClass = this.getParent().loadClass(name); } catch (final ClassNotFoundException cnfe) { final String osName = this.directory + name.replace('.', '/') + ".class"; try { final FileInputStream fis = new FileInputStream(osName); newClass = this.defineClasses(name, fis); } catch (final ClassFormatError cfe) { cfe.printStackTrace(Output.getInstance().errorOutput()); } catch (final FileNotFoundException fnfe) { // fnfe.printStackTrace(); } } return newClass; }
  209. 209. 209/210 Class Loading protected Class findClass(final String name) { Class newClass = null; try { newClass = this.getParent().loadClass(name); } catch (final ClassNotFoundException cnfe) { final String osName = this.directory + name.replace('.', '/') + ".class"; try { final FileInputStream fis = new FileInputStream(osName); newClass = this.defineClasses(name, fis); } catch (final ClassFormatError cfe) { cfe.printStackTrace(Output.getInstance().errorOutput()); } catch (final FileNotFoundException fnfe) { // fnfe.printStackTrace(); } } return newClass; } Ask the parent CL if it already knows the class
  210. 210. 210/210 Conclusion  Virtual machines must access resources and load classes, in specific cases – Can extend ClassLoader – Must override (typically) method • Class findClass(String) – Must be careful with inheritance vs. delegation! • super vs. getParent()

×