Reflection &
Dynamic ProxiesJava Fundamentals, 2016-11-22
Michael Rasmussen
Metaprogramming
• Programming paradigm
– Writing programs that treat programs as data
– The ability to modify, execute, transform,
generate programs, or parts thereof —
including itself — at runtime
– Reflection is often a crucial part thereof
What is Reflection
Introspection
Modification
Reflection
• What is it good for?
– Examining and/or executing code at
runtime, that was unknown at compile time,
and modify the application’s state.
– Poking around in private state that you
otherwise shouldn’t have access to directly
:)
Reflection: Introspection
• Determine class
– hierarchy
– members
– annotations
– attributes
– generics
Reflection: Modification
• get/set state
• invoke methods
• construct new instances
Reflection: Introspection
• Done through methods on Class
• Getter-methods for most
of your heart’s desires!
Reflection: Introspection• Getting the Class instance:
– Compile time knowledge, use .class:ArrayList.class, String.class, etc
– Find Class from an instance at runtime:
instance.getClass()
– Load a class via ClassLoader:Class.forName("name.of.MyClass", false, classLoader)
classLoader.loadClass("name.of.MyClass")
Reflection: Introspection
• Class hierarchical information:
– getSuperclass() : Class
– getInterfaces() : Class[]
Reflection: Introspection
• Outer class information
– getEnclosingMethod() : Method
– getEnclosingConstructor() : Constructor
– getEnclosingClass() : Class
– getDeclaringClass() : Class
Reflection: Introspection
• Nested class information
– getClasses() : Class[]
– getDeclaredClasses(): Class[]
Reflection: Introspection• Determine class members:
– For determining members, the introspective getters exist in two versions, declared and non-declared, example:
• getFields
• getDeclaredFields
– Declared version only looks on the specific class and disregardsvisibility, where as the non-declared version looks for public members in the class’ entire hierarchy.
Reflection: Introspection
– Fields:
• getFields() : Field[]getField(name) : Field
– Methods:
• getMethods() : Method[]getMethod(name, params…) : Method
– Constructors:
• getConstructors() : Constructor[]getConstructor(params…) : Constructor
Reflection: Introspection
• Annotations:
– getAnnotations() : Annotation[]
– getAnnotation(Class<A>) : A
– isAnnotationPresent(Class<A>) : boolean
– getAnnotationsByType(Class<A>) : A[]
Reflection: Introspection
• java.lang.reflect.Member
– getName() : String
– getDeclaringClass() : Class
Method, Field and Constructor all implement Member
Reflection: Introspection• java.lang.reflect.Member
– getModifiers() : int
• Modifier.isPublic(mod) : booleanModifier.isAbstract(mod) : booleanModifier.isVolatile(mod) : booleanetc…
• Modifiers can overlap between type of members!Only use methods applicable to your member type!
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html
Reflection: Modification
• java.lang.reflect.Field
– set(target, value)
– get(target) : value
– getType(): Class
Reflection: Modification
• java.lang.reflect.Method
– invoke(target, arguments…) : Object
– getReturnType() : Class
Reflection: Modification
• java.lang.reflect.Constructor
– newInstance() : Object
– newInstance(arguments…) : Object
Reflection: Introspection
• java.lang.reflect.Executable
– getParameterTypes() : Class[]
– getGenericParameterTypes() : Type[]
– getExceptionTypes() : Class[]
– getGenericExceptionTypes() : Type[]
Reflection• Accessibility
– isAccessible() : boolean
– setAccessible(boolean)
• Follows normal language level accessibility rules for private, protected and package-private members. Use setAccessible to disable accessibility checks (JDK9 changes this).
Method Example
Method addMethod = List.class.getDeclaredMethod("add", Object.class);
List<String> strList = new ArrayList<>();addMethod.invoke(strList, "Hello World");System.out.println(strList.get(0));
addMethod.invoke(strList, 1234);System.out.println(strList.get(1));
Method Example
Method intValue = Integer.class.getDeclaredMethod("intValue");Double d = 12.34;
System.out.println(intValue.invoke(d));
java.lang.IllegalArgumentException:object is not an instance of declaring class
Method Example
for (Method m: obj.getClass().getMethods()) {if (!Modifier.isStatic(m.getModifiers()) &&
Modifier.isPublic(m.getModifiers()) &&m.getParameterCount() == 0 &&m.getReturnType() != void.class &&m.getName().startsWith("get")) {
System.out.println(m.getName() + " => " + m.invoke(obj));}
}
Invoke all public, non-static, zero-arg, non-void
“get”-methods on an object, and write out the return value:
Method Example
for (Method m: Thread.class.getMethods()) {if (m.isAnnotationPresent(Deprecated.class)) {
System.out.println(m);}
}
List all deprecated methods on Thread
Method Example
for (Method m: File.class.getDeclaredMethods()) {for (Class<?> exType: m.getExceptionTypes()) {
if (IOException.class.isAssignableFrom(exType)) {System.out.println(m);break;
}}
}
List all methods on File that declare throwing
IOException or subtype thereof
Field example
Field outField = System.class.getDeclaredField("out");
PrintStream out = (PrintStream) outField.get(null);out.println("Hello World");
Read System.out reflectively, and invoke println
Field exampleField valueField = Integer.class.getDeclaredField("value");valueField.setAccessible(true);
Integer i = 6 * 9;System.out.println(valueField.get(i));
valueField.set(i, 42);System.out.println(valueField.get(i));
System.out.printf("6 * 9 = %d\n", 6 * 9);
Output:54426 * 9 = 42
Constructor example
ArrayList list1 = ArrayList.class.newInstance();
Constructor<ArrayList> con =ArrayList.class.getDeclaredConstructor(int.class);
ArrayList list2 = con.newInstance(10);
Dynamic Proxy
• Implementation of the GoF Proxy design
pattern
• Acts as a surrogate for the real object
Dynamic Proxy
– Allows you to intercept method invocations, modifying or delegating as you see fit
– Allows you to lazily create the delegate, for instance for creating resource heavy objects
– Allows you to update the delegate, pointing to a different instance, transparent to users
Dynamic Proxy
• JDK Dynamic Proxies are created using
java.lang.reflect.Proxy
• They only allow you to proxy interfaces
– There are libraries that allow you to proxy
concrete classes as well
Dynamic Proxy
• Commonly the delegate of the Proxy
implements the interfaces implemented by
the Proxy, but it’s not a requirement!
• A Proxy can be used to implement Duck-
typing in Java!
Dynamic Proxy
ClassLoader classLoader = ...;Class[] interfaces = ...;InvocationHandler invocationHandler = ...;
Object proxy = Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
Dynamic Proxy
public <T> T proxify(Class<T> iface, final Object obj) {ClassLoader classLoader = iface.getClassLoader();Class[] interfaces = new Class[] { iface };
InvocationHandler invocationHandler = new InvocationHandler() {public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
return m.invoke(obj, args);}
};
return (T)Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);}
Homework
– Implement a class containing a
method with the following signature:public <T> T proxify(Class<T> iface, final Object obj)
– The return value of the method should be a
dynamic proxy of the supplied interface, with obj
as the Object it should proxy.
Homework
– The invocation handler of the proxy should do the
following, in this order:
(1) If a method exists on obj that meets all the
requirements for it to implement the invoked
interface method, invoke that method on obj and
return the result.
Unless the method is marked @Deprecated!
Homework
– The invocation handler of the proxy should do the
following, in this order:
(2) If the invoked method adhere to the Design
Patterns for Properties conventions as specified in
the JavaBeanstm specifications (getters/setters),
and such a field exists, then access that field, either
getting or setting its value.
Homework
– The invocation handler of the proxy should do the
following, in this order:
(3) If no match for (1) or (2) was found:
throw a NoSuchMethodException
(from your InvocatioHandler’s invoke method)
Homework
Make tests for
your method!
Homework
Expect the Unexpected!
Homework: Hints
– How do you compare classes?
– Is a protected method a valid implementation
for a interface method?
– Is void setup(String arg) a setter?
– Can methods be overloaded with different
return types?
– Can interfaces have super interfaces?
Homework
• Homework number: 13
• Due date:
– November 28th
– 21:59:59 UTC (23:59:59 Europe/Tallinn)
• Send to: [email protected]
Flipping true <-> false
Field value = Boolean.class.getDeclaredField("value");value.setAccessible(true);value.set(Boolean.TRUE, new Boolean(false));value.set(Boolean.FALSE, new Boolean(true));
System.out.printf("False == %s\n", false);
if (Boolean.FALSE) {System.out.println("Hello World");
}
Destroy Integer cacheClass<?> cache = Class.forName("java.lang.Integer$IntegerCache");Field f = cache.getDeclaredField("cache");f.setAccessible(true);Integer[] integers = (Integer[]) f.get(null);Random r = new Random(123456789L);for (int i = 0; i < integers.length; i++) {
int x = r.nextInt(integers.length);Integer tmp = integers[i];integers[i] = integers[x];integers[x] = tmp;
}
int a = 10;int b = 20;System.out.printf("%d + %d = %d \n", a, b, a+b);
Top Related