Java Fundamentals, 2016-11-22 Michael Rasmussen · Reflection •What is it good for? –Examining...

Post on 12-May-2018

214 views 1 download

Transcript of Java Fundamentals, 2016-11-22 Michael Rasmussen · Reflection •What is it good for? –Examining...

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: jf@zeroturnaround.com

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);