Reflection Madness - JAX London 2014 
1 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Reflection Madness 
Dr Heinz M. Kabutz 
! 
© 2009-2013 Heinz Kabutz – All Rights Reserved
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
The Java Painkiller 
l Reflection is like Opium 
– A bit too strong for every day use 
– But can relieve serious pain 
– Please do not become a Reflection Addict! 
2
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Heinz Kabutz 
l Author of The Java Specialists' Newsletter 
– Articles about advanced core Java programming 
l http://www.javaspecialists.eu 
3
Reflection Madness - JAX London 2014 
4 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Introduction to 
Reflection
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Introduction To Reflection 
l Java Reflection has been with us since Java 1.1 
– We can find out what type an object is and what it can do 
– We can call methods, set fields and make new instances 
5 
Job interview: "Do 
you know reflection?" 
"Yes, I do. You can use it to 
modify private final fields and 
call methods dynamically." 
"This interview is over."
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Benefits Of Reflection 
l Flexibility 
– Choose at runtime which methods to call 
l Raw Power 
– Background work such as reading private data 
l Magic Solutions 
– Do things you should not be able to do 
• Sometimes binds you to JVM implementation 
6
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Dangers Of Reflection 
l Static Code Tools 
l Complex Code 
l Static compiling does not find typical errors 
– For example, code is written in XML and converted 
dynamically to Java objects 
l Runtime Performance 
l Limited Applicability 
– Does not always work in Sandbox 
7
Reflection Madness - JAX London 2014 
8 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Overview - Reflection Package
Reflection Madness - JAX London 2014 
9 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
With Class Class Drawn In 
All classes in 
reflection refer 
to java.lang.Class
Reflection Madness - JAX London 2014 
10 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Working With Class Objects 
l Once we have the class object, we can find out information 
about what its objects can do: 
– What is the superclass? 
– What interfaces does it implement? 
– What accessible methods and fields does it have? 
• Include methods from parent classes 
– What are all the methods and fields defined in the class, including 
private and inaccessible? 
– What are the inner classes defined? 
– What constructors are available? 
– We can cast objects
Reflection Madness - JAX London 2014 
11 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
More Interesting - What Can't We Do? 
lWith standard reflection, we cannot find 
– Names of parameters for a method 
• Java 8 allows under certain conditions 
– Anonymous classes declared in methods and classes 
– Generic type parameters of an object 
• At runtime ArrayList<String> and ArrayList<Integer> are 
the same class 
lWe can find some of them with non-reflection tricks
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Accessing Members 
l From the class, we can get fields, methods and 
constructors 
– getField(name), getDeclaredField 
– getMethod(name, parameters...), getDeclaredMethod 
– getConstructor(parameters...), getDeclaredConstructor 
l Private members require setAccessible(true) 
12
Reflection Madness - JAX London 2014 
13 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Modifying Private 
State
Reflection Madness - JAX London 2014 
14 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Private Members 
l Can be made "accessible" 
– member.setAccessible(true) 
– Requires security manager support 
! 
public class StringDestroyer { 
public static void main(String... args) 
throws IllegalAccessException, NoSuchFieldException { 
Field value = String.class.getDeclaredField("value"); 
value.setAccessible(true); 
value.set("hello!", "cheers".toCharArray()); 
System.out.println("hello!"); 
} 
} cheers
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Newsletter #014, March '01 
l String is a special case 
– Shared object between classes if the same static content 
15 
System.out.println("hello!"); 
StringDestroyer.main(null); 
System.out.println("hello!".equals("cheers")); 
hello! 
cheers 
true
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
String History Lesson 
l Java 1.0 - 1.2 
– String contained char[], offset, count 
l Java 1.3 - 1.6 
– Added a cached hash code 
– String became a shared, mutable, but thread-safe class 
l Java 1.7 
– Got rid of offset and length and added hash32 
l Java 1.8 
– Got rid of hash32 again 
16
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Newsletter #102, January '05 
l Integers can also be mangled 
– Java typically caches auto-boxed Integers -128 to 127 
– We can modify these with reflection 
17 
Field value = Integer.class.getDeclaredField("value"); 
value.setAccessible(true); 
value.set(42, 43);
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Destroying Integer Integrity 
l Integers are more vulnerable than Strings 
18 
Field value = Integer.class.getDeclaredField("value"); 
value.setAccessible(true); 
value.set(42, 43); 
! 
System.out.printf("Six times Seven = %d%n", 6 * 7); 
Six times Seven = 43
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Meaning Of Life 
l Hitchhiker's Guide to the Galaxy 
– Modifying a field related to hashCode is a very bad idea 
19 
Field value = Integer.class.getDeclaredField("value"); 
value.setAccessible(true); 
value.set(42, 43); 
! 
! 
! 
Map<Integer, String> meaningOfLife = new HashMap<>(); 
meaningOfLife.put(42, "The Meaning of Life"); 
! 
System.out.println(meaningOfLife.get(42)); 
System.out.println(meaningOfLife.get(43)); 
The Meaning of Life 
The Meaning of Life
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Meaning Of Life 
l Hitchhiker's Guide to the Galaxy 
– Now we modify field after using it as a hash value 
– Newsletter # 031 from Nov '01 
20 
Map<Integer, String> meaningOfLife = new HashMap<>(); 
meaningOfLife.put(42, "The Meaning of Life"); 
! 
Field value = Integer.class.getDeclaredField("value"); 
value.setAccessible(true); 
value.set(42, 43); 
! 
System.out.println(meaningOfLife.get(42)); 
System.out.println(meaningOfLife.get(43)); 
null 
null
Reflection Madness - JAX London 2014 
21 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Size of Objects
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Determining Object Size 
l Object Size is not defined in Java 
– Differs per platform (Newsletters #029 Aug '01 and #078 Sep '03) 
• Java 1.0 - 1.3: Each field took at least 4 bytes 
• 32-bit: Pointer is 4 bytes, minimum object size 8 bytes 
• 64-bit: Pointer is 8 bytes, minimum object size 16 bytes 
• All platforms we looked at increase memory usage in 8 byte chunks 
– Can be measured with the Instrumentation API 
• Newsletter #142 - March '07 
– We traverse object graph using reflection and IdentityHashMap to 
avoid duplicates 
• You might need to define your own endpoints 
22
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Reflection-Based Memory Counting 
l Find all connected objects and measure size 
– Count each object only once (IdentityHashMap) 
– Skip shared objects (Strings, Boxed Primitives, Classes, Enums, etc.) 
l Result is scary 
– In "C", "Heinz" was 6 bytes 
• String "Heinz" uses 80 bytes on a 64-bit JVM 
– Unless it is an "interned" String, then zero 
– Empty HashMap uses 216 bytes 
– List of 100 boolean values set to true 
– LinkedList uses 6472 bytes 
– ArrayList uses 3520 bytes 
– BitSet uses 72 bytes 
23
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
String Deduplication 
l Java 1.8.0_20, with G1, char[]s in Strings shared 
– Happens automatically 
– Can save substantial memory on some systems 
– -XX:+UseG1GC -XX:+UseStringDeduplication 
– Show effect with -XX:+PrintStringDeduplicationStatistics 
24
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Reified Primitive Types? 
l Java 7 was going to support ArrayList<int> 
– Fortunately this was dropped 
– Each int would use 24 bytes! 
• Rather use primitive specific collection classes 
25
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Instrumentation-Based Memory Counting 
l Implementation-specific estimate of object size 
! 
! 
! 
! 
! 
! 
! 
– Only a shallow size, for deep sizes we still need reflection 
26 
public class MemoryCounterAgent { 
private static Instrumentation inst; 
/** Initializes agent */ 
public static void premain( 
String agentArgs, Instrumentation inst) { 
MemoryCounterAgent.inst = inst; 
} 
/** Returns object size. */ 
public static long sizeOf(Object obj) { 
return instrumentation.getObjectSize(obj); 
} 
}
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Application of MemoryCounter 
l Educational Tool 
– Explains why Java needs 100 TB of RAM just to boot up 
l Debugging 
– One customer used it to discover size of user sessions 
• Need to define custom end-points in object graph 
l Ongoing Monitoring 
– Not that useful, too much overhead 
27
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Java Caller ID 
28
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Finding Out Who Called You 
lWith Sun's JVM, we have sun.reflect.Reflection 
– Used in Class.forName(String) 
29 
public class CallerID { 
public static Class<?> whoAmI() { 
return sun.reflect.Reflection.getCallerClass(2); 
} 
} 
! 
public class CallerIDTest { 
public static void main(String... args) { 
class CallerIDTest 
System.out.println(CallerID.whoAmI()); 
} 
}
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
@CallerSensitive 
l Java 8 disabled the call to 
Reflection.getCallerClass(int) 
l For finding out direct caller, use 
! 
l However, it doesn't give us classes deeper in stack 
30 
Class<?> clazz = MethodHandles.lookup().lookupClass();
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Finding Out Who Called You #2 
l JVM independent using Exception Stack Traces 
– Does not tell you parameter types, only method name 
31 
public class CallerID { 
public static String whoAmI() { 
Throwable t = new Throwable(); 
StackTraceElement directCaller = t.getStackTrace()[1]; 
return directCaller.getClassName() + "." + 
directCaller.getMethodName() + "()"; 
} 
} 
class CallerIDTest.main()
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Application of CallerID 
l Creating Loggers (Newsletter #137 - Dec '06) 
– Loggers often created with copy & paste 
32 
public class Application { 
private final static Logger logger = 
Logger.getLogger(Application.class.getName()); 
}
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Avoiding Copy & Paste Bugs 
lWe can do this instead 
33 
public class LoggerFactory { 
public static Logger create() { 
Throwable t = new Throwable(); 
StackTraceElement caller = t.getStackTrace()[1]; 
return Logger.getLogger(caller.getClassName()); 
} 
} 
public class Application { 
private final static Logger logger = 
LoggerFactory.create(); 
}
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Cost of Throwable.getStackTrace? 
l Creating a new Throwable is expeeeennnsssiiivvee 
– The fillInStackTrace() method is a native method call 
– However, the actual stack trace objects are empty 
• During debugging, if you want to see the actual stack 
trace of an exception, watch the getStackTrace() method 
(idea by Maik Jäkel) 
• The getStackTrace() method is even more expensive! 
l However, you need call it only once per logger 
34
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Finding Out Who Called You #3 
l JVM independent using Security Manager 
35 
public class CallerID { 
public static Class<?> whoAmI() { 
MySecMgr sm = new MySecMgr(); 
return sm.getClassContext()[2]; 
} 
private static class MySecMgr extends SecurityManager { 
public Class[] getClassContext() { 
return super.getClassContext(); 
} 
} 
} class CallerIDTest
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Application of CallerID for JUnit 
l Make running unit tests from main() 
36 
public class UnitTestRunner { 
public static void run() { 
MySecMgr sm = new MySecMgr(); 
Class<?> clazz = sm.getClassContext()[2]; 
System.out.println("Running unit tests for " + clazz); 
TestRunner.run(new JUnit4TestAdapter(clazz)); 
} 
! 
private static class MySecMgr extends SecurityManager { 
public Class[] getClassContext() { 
return super.getClassContext(); 
} 
} 
}
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Normal Unit Test With JUnit 4 
l Cannot be directly invoked from the command line 
37 
import org.junit.*; 
import static org.junit.Assert.assertEquals; 
! 
public class MyTest { 
@Test 
public void testHello() { 
assertEquals("HELLO", "hello".toUpperCase()); 
} 
}
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Augmented Unit Test With JUnit 4 
l Context aware method UnitTestRunner.run() 
38 
import org.junit.*; 
import static org.junit.Assert.assertEquals; 
! 
public class MyTest { 
@Test 
public void testHello() { 
assertEquals("HELLO", "hello".toUpperCase()); 
} 
! 
public static void main(String... args) { 
UnitTestRunner.run(); 
} 
}
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Tests Automagically Run 
l Context aware method UnitTestRunner.run() 
39 
Running unit tests for class MyTest 
. 
Time: 0.048 
! 
OK (1 test)
Reflection Madness - JAX London 2014 
40 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
The Delegator
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Automatic Delegator 
l MI5 want to see bytes flowing across my sockets 
– Java provides plugin methods to specify SocketImpl 
! 
! 
! 
! 
! 
! 
! 
! 
– Only catch, default SocketImpl classes are package access 
41 
public class MonitoringSocketFactory 
implements SocketImplFactory { 
public SocketImpl createSocketImpl() { 
return new MonitoringSocketImpl(); 
} 
} ! 
SocketImplFactory socketImplFactory = 
new MonitoringSocketFactory(); 
Socket.setSocketImplFactory(socketImplFactory); 
ServerSocket.setSocketFactory(socketImplFactory);
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Delegating To Inaccessible Methods 
l All methods in SocketImpl are protected 
lWe cannot call them directly, only with reflection 
– But how do we know which method to call? 
lWe want to write 
! 
! 
! 
! 
– Should automatically call correct methods in wrapped object 
42 
public void close() throws IOException { 
delegator.invoke(); 
} 
public void listen(int backlog) throws IOException { 
delegator.invoke(backlog); 
}
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Impossible? 
lWith Stack Trace CallerID, we can get close 
– If there is a clash, we specify method explicitly 
– First, we find the method that we are currently in 
43 
private String extractMethodName() { 
Throwable t = new Throwable(); 
return t.getStackTrace()[2].getMethodName(); 
}
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Finding The Correct Method By Parameters 
44 
l Simple search 
– Find method with same name and number of parameters 
• Check that each of the objects are assignable 
– If not exactly one method is found, throw an exception
private Method findMethod(Reflection Madness String methodName, - JAX London Object[] 2014 
args) { 45 
Class<?> clazz = superclass; 
if (args.length == 0) 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Finding The Correct Method By Parameters 
return clazz.getDeclaredMethod(methodName); 
Method match = null; 
next: 
for (Method method : clazz.getDeclaredMethods()) { 
if (method.getName().equals(methodName)) { 
Class<?>[] classes = method.getParameterTypes(); 
if (classes.length == args.length) { 
for (int i = 0; i < classes.length; i++) { 
Class<?> argType = classes[i]; 
argType = convertPrimitiveClass(argType); 
if (!argType.isInstance(args[i])) continue next; 
} 
if (match == null) match = method; 
else throw new DelegationException("Duplicate"); 
} 
} 
} 
if (match != null) return match; 
throw new DelegationException("Not found: " + methodName); 
}
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Manual Override 
l Delegator allows you to specify method name and 
parameter types for exact match 
46 
public void connect(InetAddress address, int port) 
throws IOException { 
delegator 
.delegateTo("connect", InetAddress.class, int.class) 
.invoke(address, port); 
}
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Invoking The Method 
l Generics "automagically" casts to return type 
47 
public final <T> T invoke(Object... args) { 
try { 
String methodName = extractMethodName(); 
Method method = findMethod(methodName, args); 
@SuppressWarnings("unchecked") 
T t = (T) invoke0(method, args); 
return t; 
} catch (NoSuchMethodException e) { 
throw new DelegationException(e); 
} 
}
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
When Generics Fail 
lWorkaround: Autoboxing causes issues when we 
convert automatically 
! 
! 
lWorkaround: Inlining return type makes it 
impossible to guess what type it is 
48 
public int getPort() { 
Integer result = delegator.invoke(); 
return result; 
} 
public InputStream getInputStream() throws IOException { 
InputStream real = delegator.invoke(); 
return new DebuggingInputStream(real, monitor); 
}
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Fixing Broken Encapsulation 
l Socket implementations modify parent fields 
directly 
– Before and after calling methods, we copy field values 
over 
49 
writeFields(superclass, source, delegate); 
method.setAccessible(true); 
Object result = method.invoke(delegate, args); 
writeFields(superclass, delegate, source);
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Fixing Broken Encapsulation 
l Method writeFields() uses basic reflection 
– Obviously only works on fields of common superclass 
50 
private void writeFields(Class clazz, Object from, Object to) { 
for (Field field : clazz.getDeclaredFields()) { 
field.setAccessible(true); 
field.set(to, field.get(from)); 
} 
}
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Complete Code 
l Newsletter #168 - Jan '09 
– Includes primitive type mapper 
– Allows you to delegate to another object 
• Without hardcoding all the methods 
lWarning: 
– Calling delegated methods via reflection is much slower 
51
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Application Of Delegator 
lWrapping of SocketImpl object 
52 
public class MonitoringSocketImpl extends SocketImpl { 
private final Delegator delegator; 
! 
public InputStream getInputStream() throws IOException { 
InputStream real = delegator.invoke(); 
return new SocketMonitoringInputStream(getSocket(), real); 
} 
! 
public OutputStream getOutputStream() throws IOException { 
OutputStream real = delegator.invoke(); 
return new SocketMonitoringOutputStream(getSocket(), real); 
} 
! 
public void create(boolean stream) throws IOException { 
delegator.invoke(stream); 
} 
! 
public void connect(String host, int port) throws IOException { 
delegator.invoke(host, port); 
} 
// etc. 
}
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Alternative To Reflection 
l Various other options exist: 
– Modify SocketImpl directly and put into boot class path 
– Use Aspect Oriented Programming to replace call 
• Needs to modify all classes that call 
Socket.getInputStream() and 
Socket.getOutputStream() 
53
Reflection Madness - JAX London 2014 
54 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Of "Final" Fields
Reflection Madness - JAX London 2014 
55 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Manipulating Objects – Final Fields 
l Final fields cannot be reassigned 
l If they are bound at compile time, they will get 
inlined 
l However, reflection may allow us to rebind them 
with some versions of Java 
– Can introduce dangerous concurrency bugs 
– Final fields are considered constant and can be inlined at 
runtime by HotSpot compilers 
– Only ever do this for debugging or testing purposes
Reflection Madness - JAX London 2014 
56 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Setting "Final" Field 
l Can be set since Java 1.5 
– char[] value is actually "final" 
• We could still modify contents of array 
public class StringDestroyer { 
public static void main(String... args) 
throws IllegalAccessException, NoSuchFieldException { 
Field value = String.class.getDeclaredField("value"); 
value.setAccessible(true); 
value.set("hello!", "cheers".toCharArray()); 
System.out.println("hello!"); 
} 
} cheers
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Setting "Static Final" Fields 
l Should not be possible, according to Lang Spec 
l However, here is how you can do it (Sun JVM): 
1.Find the field using normal reflection 
2.Find the "modifiers" field of the Field object 
3.Change the "modifiers" field to not be "final" 
1. modifiers &= ~Modifier.FINAL; 
4.Get the FieldAccessor from the 
sun.reflect.ReflectionFactory 
5.Use the FieldAccessor to set the final static field 
57
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
ReflectionHelper Class 
l Now we can set static final fields 
– Newsletter #161 in May '08 
58 
import sun.reflect.*; import java.lang.reflect.*; 
public class ReflectionHelper { 
private static final ReflectionFactory reflection = 
ReflectionFactory.getReflectionFactory(); 
! 
public static void setStaticFinalField(Field field, Object value) 
throws NoSuchFieldException, IllegalAccessException { 
field.setAccessible(true); 
Field modifiersField = Field.class.getDeclaredField("modifiers"); 
modifiersField.setAccessible(true); 
int modifiers = modifiersField.getInt(field); 
modifiers &= ~Modifier.FINAL; 
modifiersField.setInt(field, modifiers); 
FieldAccessor fa = reflection.newFieldAccessor(field, false); 
fa.set(null, value); 
} 
}
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Example of ReflectionHelper 
59 
public class StaticFieldTest { 
private final static Object obj = "Hello world!"; 
! 
public static void main(String... args) 
throws NoSuchFieldException, IllegalAccessException { 
ReflectionHelper.setStaticFinalField( 
StaticFieldTest.class.getDeclaredField("obj"), 
"Goodbye cruel world!" 
); 
System.out.println("obj = " + obj); 
} 
} Goodbye cruel world!
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Application Of Setting Final Fields 
l Create new enum values dynamically for testing 
60 
public enum HumanState { HAPPY, SAD } 
! 
public class Human { 
public void sing(HumanState state) { 
switch (state) { 
case HAPPY: singHappySong(); break; 
case SAD: singDirge(); break; 
default: 
Any 
problems? 
new IllegalStateException("Invalid State: " + state); 
throw 
} 
} 
private void singHappySong() { 
System.out.println("When you're happy and you know it ..."); 
} 
private void singDirge() { 
System.out.println("Don't cry for me Argentina, ..."); 
} 
}
Reflection Madness - JAX London 2014 
61 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
New "enum" Values
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Most Protected Class 
l Enums are subclasses of java.lang.Enum 
l Almost impossible to create a new instance 
– One hack was to let enum be an anonymous inner class 
• Newsletter #141 - March '07 
• We then subclassed it ourselves 
• This hack was stopped in Java 6 
– We can create a new instance using sun.reflect.Reflection 
• But the enum switch statements are tricky 
– Adding a new enum will cause an 
ArrayIndexOutOfBoundsException 
62
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Creating New Enum Value 
lWe use the sun.reflect.ReflectionFactory class 
– The clazz variable represents the enum's class 
63 
Constructor cstr = clazz.getDeclaredConstructor( 
String.class, int.class 
); 
ReflectionFactory reflection = 
ReflectionFactory.getReflectionFactory(); 
Enum e = reflection.newConstructorAccessor(cstr). 
newInstance("BLA",3);
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Original Human.Sing() 
! 
! 
! 
! 
! 
! 
l Let's see how this is converted into byte code 
64 
public void sing(HumanState state) { 
switch (state) { 
case HAPPY: 
singHappySong(); 
break; 
case SAD: 
singDirge(); 
break; 
default: 
new IllegalStateException( 
"Invalid State: " + state); 
} 
}
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
An Inner Class Is Generated 
l Decompiled with Pavel Kouznetsov's JAD 
65 
public void sing(HumanState state) { 
static class _cls1 { 
static final int $SwitchMap$HumanState[] = 
new int[HumanState.values().length]; 
static { 
try { 
$SwitchMap$HumanState[HumanState.HAPPY.ordinal()] = 1; 
} catch(NoSuchFieldError ex) { } 
try { 
$SwitchMap$HumanState[HumanState.SAD.ordinal()] = 2; 
} catch(NoSuchFieldError ex) { } 
} 
} 
...
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Generated Enum Switch 
66 
switch(_cls1.$SwitchMap$HumanState[state.ordinal()]) { 
case 1: 
singHappySong(); 
break; 
case 2: 
singDirge(); 
break; 
default: 
new IllegalStateException( 
"Invalid State: " + state); 
break; 
}
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Modifying Enum "Switch" Statements 
l Follow this procedure: 
1.Specify which classes contain enum switch statements 
2.For each class, find all fields that follow the pattern 
$SwitchMap$enum_name 
3.Make fields (int[]) larger by one slot 
4.Set field values to new int[] 
67
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Memento Design Pattern 
l Every time we make a change, first copy the state 
– Allows us to undo previous change 
– Useful for testing purposes 
l EnumBuster class contains stack of undo 
mementos 
68
EnumBuster<HumanState> Reflection buster Madness = - JAX London 2014 
69 
new EnumBuster<>(HumanState.class, Human.class); 
try { 
Human heinz = new Human(); 
heinz.sing(HumanState.HAPPY); 
heinz.sing(HumanState.SAD); 
HumanState MELLOW = buster.make("MELLOW"); 
buster.addByValue(MELLOW); 
System.out.println(Arrays.toString(HumanState.values())); 
try { 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Testing Human Class 
heinz.sing(MELLOW); 
fail("Should have caused an IllegalStateException"); 
} catch (IllegalStateException success) { } 
} finally { 
System.out.println("Restoring HumanState"); 
buster.restore(); 
System.out.println(Arrays.toString(HumanState.values())); 
}
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Test Output 
lWhen we run it, we should see the following 
! 
! 
! 
! 
! 
– Note that when the test run is complete, all the classes 
have been changed back to what they were before 
70 
When you're happy and you know it ... 
Don't cry for me Argentina, ... 
[HAPPY, SAD, MELLOW] 
Restoring HumanState 
[HAPPY, SAD] 
! 
AssertionFailedError: Should have caused an IllegalStateException 
at HumanTest.testSingingAddingEnum(HumanTest.java:23)
Reflection Madness - JAX London 2014 
71 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Constructing 
without Constructor
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Serialization Basics 
lWhen we serialize an object, fields are read with 
reflection and written to stream 
lWhen we deserialize it again, an object is 
constructed without calling the constructor 
– We can use the same mechanism to create objects 
72
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Basic Class 
lWhenever this object is instantiated, a message is 
printed to console 
– Furthermore, i is always 42 
73 
public class MyClass { 
private int i = 42; 
public MyClass(int i) { 
System.out.println("Constructor called"); 
} 
public String toString() { 
return "MyClass i=" + i; 
} 
}
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Serialization Mechanism 
l Serialization can make objects without calling 
constructor 
– We can use the same mechanism (JVM specific) 
74 
ReflectionFactory rf = 
ReflectionFactory.getReflectionFactory(); 
Constructor objDef = Object.class.getDeclaredConstructor(); 
Constructor intConstr = rf.newConstructorForSerialization( 
MyClass.class, objDef 
mc = MyClass i=0 
class MyClass 
); 
! 
MyClass mc = (MyClass) intConstr.newInstance(); 
System.out.println("mc = " + mc.toString()); 
System.out.println(mc.getClass());
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Unsafe 
l Alternatively, we can use sun.misc.Unsafe 
– Again, JVM specific 
75 
Object o = Unsafe.getUnsafe().allocateInstance( 
MyClass.class); 
System.out.println("o = " + o.toString()); 
System.out.println(o.getClass());
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Or Just Make New Constructor 
l Alternatively, we can use sun.misc.Unsafe 
– Again, JVM specific 
76 
public class MagicConstructorMaker { 
public static <T> Constructor<T> make(Class<T> clazz) 
throws NoSuchMethodException, IllegalAccessException, 
InvocationTargetException, InstantiationException { 
Constructor<?> constr = 
Constructor.class.getDeclaredConstructor( 
Class.class, // Class<T> declaringClass 
Class[].class, // Class<?>[] parameterTypes 
Class[].class, // Class<?>[] checkedExceptions 
int.class, // int modifiers 
int.class, // int slot 
String.class, // String signature 
byte[].class, // byte[] annotations 
byte[].class); // byte[] parameterAnnotations 
constr.setAccessible(true); 
...
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
And Create New Constructor Object 
l This even works on Android Dalvik 
– However, Java 8 core dumps with wrong slot # 
77 
int slot = clazz.getDeclaredConstructors().length + 1; 
return (Constructor<T>) constr.newInstance( 
clazz, 
new Class[0], 
new Class[0], 
Modifier.PUBLIC, 
slot, 
"MyMagicConstructor", 
null, 
null); 
} 
}
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Singletons? 
l Classic approach is private constructor 
– More robust: throw exception if constructed twice 
78 
public class Singleton { 
private final static Singleton instance = new Singleton(); 
private Singleton() { 
if (instance != null) 
throw new IllegalStateException("Duplicate singletons!!!"); 
} 
! 
public static Singleton getInstance() { 
return instance; 
} 
}
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Singletons? 
l Make new Singleton objects 
– My other techniques also work 
79 
Singleton.getInstance(); 
Singleton s = MagicConstructorMaker.make(Singleton.class).newInstance(); 
System.out.println(s == Singleton.getInstance()); 
System.out.println(s); 
System.out.println(Singleton.getInstance());
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Application: Constructing Without Constructor 
l Useful when you need to recreate an object 
– e.g. Copy an object, de-persist it, etc. 
80
Reflection Madness - JAX London 2014 
81 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Externalizable Hack
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Standard Serializing Approach 
l Class implements Serializable 
– Usually good enough 
l Next step is to add writeObject() and readObject() 
– Avoids reflection overhead 
• This is usually not measurable 
– Allows custom optimizations 
l Class implements Externalizable 
– May be a tiny bit faster than Serializable 
– But, opens security hole 
82
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Serializable Vs Externalizable 
lWriting of object 
– Serializable 
• Can convert object to bytes and read that - cumbersome 
– Externalizable 
• pass in a bogus ObjectOutput to gather data 
l Reading of object 
– Serializable 
• cannot change state of an existing object 
– Externalizable 
• use bogus ObjectInput to modify existing object 
83
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Our Moviecharacter Class 
84 
public class MovieCharacter implements Externalizable { 
private String name; 
private boolean hero; 
public MovieCharacter(String name, boolean hero) { 
this.name = name; 
this.hero = hero; 
} 
public void writeExternal(ObjectOutput out) throws IOException { 
out.writeUTF(name); 
out.writeBoolean(hero); 
} 
public void readExternal(ObjectInput in) throws IOException { 
name = in.readUTF(); 
hero = in.readBoolean(); 
} 
public String toString() { 
return name + " is " + (hero ? "" : "not ") + "a hero"; 
} 
}
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Bogus ObjectInput Created 
85 
public class HackAttack { 
public static void hackit(MovieCharacter cc, String 
final boolean hero) throws Exception { 
ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
ObjectOutputStream oos = new ObjectOutputStream(baos); 
oos.writeObject(cc); 
oos.close(); 
! 
ObjectInputStream ois = new ObjectInputStream( 
new ByteArrayInputStream(baos.toByteArray()) 
) { 
public boolean readBoolean() throws IOException { 
return hero; 
} 
public String readUTF() { return name; } 
}; 
cc.readExternal(ois); // no security exception 
} 
}
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Bogus ObjectInput Created 
86 
public class HackAttackTest { 
public static void main(String... args) 
throws Exception { 
System.setSecurityManager(new SecurityManager()); 
MovieCharacter cc = new MovieCharacter("John Hancock", true); 
System.out.println(cc); 
! 
// Field f = MovieCharacter.class.getDeclaredField("name"); 
// f.setAccessible(true); // causes SecurityException 
! 
HackAttack.hackit(cc, "John Hancock the drunkard", false); 
! 
// now the private data of the MovieCharacter has changed! 
System.out.println(cc); 
} 
} John Hancock is a hero 
John Hancock the drunkard is not a hero
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Application: Externalizable Hack 
l Be careful with using Externalizable 
– We can change the state of an existing object 
lWith Serializable, we can create bad objects 
– A lot more effort 
– Should be checked with ObjectInputValidation interface 
l Slight performance gain might not be worth it 
87
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Soft References 
and Reflection 
88
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Reflection and SoftReferences 
l Reflection information stored as soft refs 
– Created lazily on first use 
– Can be turned off with 
-Dsun.reflect.noCaches=true 
l Reflection information costs approximately 24KB 
per class and takes about 362 μs to generate 
89
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Demo 
Effects of not having caches 
90
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Effects On Performance 
l Soft References are cleared when system is under 
memory pressure 
– Cache essential reflection information 
– Otherwise you get noCaches=true performance 
l Danger: SoftReferences cause a quadratic 
degradation of performance during GC 
– Don't use them 
91
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Don't Use Softreference 
l Don't use SoftReference 
l Don't use SoftReference 
l Don't use SoftReference 
l Don't use SoftReference 
l Don't use SoftReference 
l Don't use SoftReference 
l Don't use SoftReference 
92
Reflection Madness - JAX London 2014 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Do Not Use 
Soft 
Reference 
93
Reflection Madness - JAX London 2014 
94 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Conclusion 
l Reflection allows us some neat tricks in Java 
– Great power also means great responsibility 
– Don't overdo it, use sparingly 
l Tons of free articles on JavaSpecialists.EU 
– http://www.javaspecialists.eu/archive
Reflection Madness - JAX London 2014 
95 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
Reflection Madness 
Dr Heinz M. Kabutz 
heinz@javaspecialists.eu 
I would love to hear from you!
Reflection Madness - JAX London 2014 
96 
© 2009-2014 Heinz Kabutz – All Rights Reserved 
The Java Specialists' Newsletter

More Related Content

DOCX
Fundamental classes in java
PDF
Vk.amberfog.com gtug part1_introduction2_javaandroid_gtug
PPTX
01 Java Language And OOP PART I
PPT
java introduction
PPT
Core java
PDF
Garbage
PDF
Bjarne essencegn13
PDF
Building DSLs with Xtext - Eclipse Modeling Day 2009
Fundamental classes in java
Vk.amberfog.com gtug part1_introduction2_javaandroid_gtug
01 Java Language And OOP PART I
java introduction
Core java
Garbage
Bjarne essencegn13
Building DSLs with Xtext - Eclipse Modeling Day 2009

What's hot (9)

PPTX
Millions quotes per second in pure java
PPSX
Strings in Java
PDF
Xtext Webinar
ODP
Best practices in Java
PPT
Reversing JavaScript
PPTX
Session 05 - Strings in Java
PPT
Chapter08
PDF
Priming Java for Speed at Market Open
PPSX
Arrays in Java
Millions quotes per second in pure java
Strings in Java
Xtext Webinar
Best practices in Java
Reversing JavaScript
Session 05 - Strings in Java
Chapter08
Priming Java for Speed at Market Open
Arrays in Java
Ad

Similar to Reflection Madness - Dr. Heinz Kabutz (20)

PDF
Understanding And Using Reflection
PPTX
Reflection in Java
PDF
Java Reflection Explained Simply
PPT
Reflection in java
PPTX
Java Reflection Concept and Working
PPT
Reflection
PDF
JavaOne 2013: Memory Efficient Java
PPTX
Java Hands-On Workshop
PDF
Metaprograms and metadata (as part of the the PTT lecture)
PDF
Java Course 5: Enums, Generics, Assertions
PDF
Terence Barr - jdk7+8 - 24mai2011
PPTX
Cuối cùng cũng đã chuẩn bị slide xong cho seminar ngày mai. Mai seminar đầu t...
PDF
JAVA Collection and generics
PPT
What is Java Technology (An introduction with comparision of .net coding)
PPSX
Introduction to java
PDF
My life as a cyborg
ODP
From Java Code to Java Heap: Understanding the Memory Usage of Your App - Ch...
PPT
Oop lecture7
PDF
JavaOne summary
Understanding And Using Reflection
Reflection in Java
Java Reflection Explained Simply
Reflection in java
Java Reflection Concept and Working
Reflection
JavaOne 2013: Memory Efficient Java
Java Hands-On Workshop
Metaprograms and metadata (as part of the the PTT lecture)
Java Course 5: Enums, Generics, Assertions
Terence Barr - jdk7+8 - 24mai2011
Cuối cùng cũng đã chuẩn bị slide xong cho seminar ngày mai. Mai seminar đầu t...
JAVA Collection and generics
What is Java Technology (An introduction with comparision of .net coding)
Introduction to java
My life as a cyborg
From Java Code to Java Heap: Understanding the Memory Usage of Your App - Ch...
Oop lecture7
JavaOne summary
Ad

More from JAXLondon2014 (20)

PDF
GridGain 6.0: Open Source In-Memory Computing Platform - Nikita Ivanov
PDF
Performance Metrics for your Delivery Pipeline - Wolfgang Gottesheim
PPTX
How to randomly access data in close-to-RAM speeds but a lower cost with SSD’...
PDF
Conditional Logging Considered Harmful - Sean Reilly
PDF
Finding your Way in the Midst of the NoSQL Haze - Abdelmonaim Remani
PPT
API Management - a hands on workshop - Paul Fremantle
PDF
'Bootiful' Code with Spring Boot - Josh Long
PDF
The Full Stack Java Developer - Josh Long
PDF
The Economies of Scaling Software - Josh Long and Abdelmonaim Remani
PDF
Dataflow, the Forgotten Way - Russel Winder
PDF
Habits of Highly Effective Technical Teams - Martijn Verburg
PDF
The Lazy Developer's Guide to Cloud Foundry - Holly Cummins
PPTX
Testing within an Agile Environment - Beyza Sakir and Chris Gollop
PDF
Testing the Enterprise Layers - the A, B, C's of Integration Testing - Aslak ...
PDF
Squeezing Performance of out of In-Memory Data Grids - Fuad Malikov
PDF
Spocktacular Testing - Russel Winder
PDF
Server Side JavaScript on the Java Platform - David Delabassee
PDF
Rapid Web Application Development with MongoDB and the JVM - Trisha Gee
PDF
Pushing Java EE outside of the Enterprise: Home Automation and IoT - David De...
PDF
Personal Retrospectives - Johannes Thönes
GridGain 6.0: Open Source In-Memory Computing Platform - Nikita Ivanov
Performance Metrics for your Delivery Pipeline - Wolfgang Gottesheim
How to randomly access data in close-to-RAM speeds but a lower cost with SSD’...
Conditional Logging Considered Harmful - Sean Reilly
Finding your Way in the Midst of the NoSQL Haze - Abdelmonaim Remani
API Management - a hands on workshop - Paul Fremantle
'Bootiful' Code with Spring Boot - Josh Long
The Full Stack Java Developer - Josh Long
The Economies of Scaling Software - Josh Long and Abdelmonaim Remani
Dataflow, the Forgotten Way - Russel Winder
Habits of Highly Effective Technical Teams - Martijn Verburg
The Lazy Developer's Guide to Cloud Foundry - Holly Cummins
Testing within an Agile Environment - Beyza Sakir and Chris Gollop
Testing the Enterprise Layers - the A, B, C's of Integration Testing - Aslak ...
Squeezing Performance of out of In-Memory Data Grids - Fuad Malikov
Spocktacular Testing - Russel Winder
Server Side JavaScript on the Java Platform - David Delabassee
Rapid Web Application Development with MongoDB and the JVM - Trisha Gee
Pushing Java EE outside of the Enterprise: Home Automation and IoT - David De...
Personal Retrospectives - Johannes Thönes

Recently uploaded (20)

PDF
Building event-driven application with RAP Business Events in ABAP Cloud
PDF
Lessons Learned building a product with clean core abap
PDF
soft skills for kids in India - LearnifyU
PPTX
Special Occasion Speech by NBA YoungBoy.pptx
PPT
Comm.-100W-Writing-a-Convincing-Editorial-slides.ppt
PPTX
Challenges, strengths and prospects of Pakistan in.pptx
PDF
Yoken Capital Network Presentation Slide
PPTX
Ease_of_Paying_Taxes_Act_Presentation.pptx
PPTX
Ruth Week 1 - Hope in Barren Places.pptx
PDF
Pitch Style Data Report Template Preview
PPTX
Basics of Stereotypes and Prejudice(1).pptx
PPTX
export_1a21b709-15ab-43fc-88b3-50ecde18572d.pptx
PDF
Echoes of AccountabilityComputational Analysis of Post-Junta Parliamentary Qu...
PPTX
Presentacion lugares conocidos ingles sena.pptx
PPTX
HRPTA PPT 2024-2025 FOR PTA MEETING STUDENTS
PPTX
All important rules of procedure for any upcoming MUN
PPTX
Brief presentation for multiple products
PDF
The History of COBSI, a Community-based Smallholder Irrigation, and its Regio...
PPTX
Animal Farm powerpointpresentation- Kopie – Kopie.pptx
PDF
Financial Managememt CA1 for Makaut Student
Building event-driven application with RAP Business Events in ABAP Cloud
Lessons Learned building a product with clean core abap
soft skills for kids in India - LearnifyU
Special Occasion Speech by NBA YoungBoy.pptx
Comm.-100W-Writing-a-Convincing-Editorial-slides.ppt
Challenges, strengths and prospects of Pakistan in.pptx
Yoken Capital Network Presentation Slide
Ease_of_Paying_Taxes_Act_Presentation.pptx
Ruth Week 1 - Hope in Barren Places.pptx
Pitch Style Data Report Template Preview
Basics of Stereotypes and Prejudice(1).pptx
export_1a21b709-15ab-43fc-88b3-50ecde18572d.pptx
Echoes of AccountabilityComputational Analysis of Post-Junta Parliamentary Qu...
Presentacion lugares conocidos ingles sena.pptx
HRPTA PPT 2024-2025 FOR PTA MEETING STUDENTS
All important rules of procedure for any upcoming MUN
Brief presentation for multiple products
The History of COBSI, a Community-based Smallholder Irrigation, and its Regio...
Animal Farm powerpointpresentation- Kopie – Kopie.pptx
Financial Managememt CA1 for Makaut Student

Reflection Madness - Dr. Heinz Kabutz

  • 1. Reflection Madness - JAX London 2014 1 © 2009-2014 Heinz Kabutz – All Rights Reserved Reflection Madness Dr Heinz M. Kabutz ! © 2009-2013 Heinz Kabutz – All Rights Reserved
  • 2. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved The Java Painkiller l Reflection is like Opium – A bit too strong for every day use – But can relieve serious pain – Please do not become a Reflection Addict! 2
  • 3. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Heinz Kabutz l Author of The Java Specialists' Newsletter – Articles about advanced core Java programming l http://www.javaspecialists.eu 3
  • 4. Reflection Madness - JAX London 2014 4 © 2009-2014 Heinz Kabutz – All Rights Reserved Introduction to Reflection
  • 5. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Introduction To Reflection l Java Reflection has been with us since Java 1.1 – We can find out what type an object is and what it can do – We can call methods, set fields and make new instances 5 Job interview: "Do you know reflection?" "Yes, I do. You can use it to modify private final fields and call methods dynamically." "This interview is over."
  • 6. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Benefits Of Reflection l Flexibility – Choose at runtime which methods to call l Raw Power – Background work such as reading private data l Magic Solutions – Do things you should not be able to do • Sometimes binds you to JVM implementation 6
  • 7. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Dangers Of Reflection l Static Code Tools l Complex Code l Static compiling does not find typical errors – For example, code is written in XML and converted dynamically to Java objects l Runtime Performance l Limited Applicability – Does not always work in Sandbox 7
  • 8. Reflection Madness - JAX London 2014 8 © 2009-2014 Heinz Kabutz – All Rights Reserved Overview - Reflection Package
  • 9. Reflection Madness - JAX London 2014 9 © 2009-2014 Heinz Kabutz – All Rights Reserved With Class Class Drawn In All classes in reflection refer to java.lang.Class
  • 10. Reflection Madness - JAX London 2014 10 © 2009-2014 Heinz Kabutz – All Rights Reserved Working With Class Objects l Once we have the class object, we can find out information about what its objects can do: – What is the superclass? – What interfaces does it implement? – What accessible methods and fields does it have? • Include methods from parent classes – What are all the methods and fields defined in the class, including private and inaccessible? – What are the inner classes defined? – What constructors are available? – We can cast objects
  • 11. Reflection Madness - JAX London 2014 11 © 2009-2014 Heinz Kabutz – All Rights Reserved More Interesting - What Can't We Do? lWith standard reflection, we cannot find – Names of parameters for a method • Java 8 allows under certain conditions – Anonymous classes declared in methods and classes – Generic type parameters of an object • At runtime ArrayList<String> and ArrayList<Integer> are the same class lWe can find some of them with non-reflection tricks
  • 12. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Accessing Members l From the class, we can get fields, methods and constructors – getField(name), getDeclaredField – getMethod(name, parameters...), getDeclaredMethod – getConstructor(parameters...), getDeclaredConstructor l Private members require setAccessible(true) 12
  • 13. Reflection Madness - JAX London 2014 13 © 2009-2014 Heinz Kabutz – All Rights Reserved Modifying Private State
  • 14. Reflection Madness - JAX London 2014 14 © 2009-2014 Heinz Kabutz – All Rights Reserved Private Members l Can be made "accessible" – member.setAccessible(true) – Requires security manager support ! public class StringDestroyer { public static void main(String... args) throws IllegalAccessException, NoSuchFieldException { Field value = String.class.getDeclaredField("value"); value.setAccessible(true); value.set("hello!", "cheers".toCharArray()); System.out.println("hello!"); } } cheers
  • 15. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Newsletter #014, March '01 l String is a special case – Shared object between classes if the same static content 15 System.out.println("hello!"); StringDestroyer.main(null); System.out.println("hello!".equals("cheers")); hello! cheers true
  • 16. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved String History Lesson l Java 1.0 - 1.2 – String contained char[], offset, count l Java 1.3 - 1.6 – Added a cached hash code – String became a shared, mutable, but thread-safe class l Java 1.7 – Got rid of offset and length and added hash32 l Java 1.8 – Got rid of hash32 again 16
  • 17. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Newsletter #102, January '05 l Integers can also be mangled – Java typically caches auto-boxed Integers -128 to 127 – We can modify these with reflection 17 Field value = Integer.class.getDeclaredField("value"); value.setAccessible(true); value.set(42, 43);
  • 18. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Destroying Integer Integrity l Integers are more vulnerable than Strings 18 Field value = Integer.class.getDeclaredField("value"); value.setAccessible(true); value.set(42, 43); ! System.out.printf("Six times Seven = %d%n", 6 * 7); Six times Seven = 43
  • 19. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Meaning Of Life l Hitchhiker's Guide to the Galaxy – Modifying a field related to hashCode is a very bad idea 19 Field value = Integer.class.getDeclaredField("value"); value.setAccessible(true); value.set(42, 43); ! ! ! Map<Integer, String> meaningOfLife = new HashMap<>(); meaningOfLife.put(42, "The Meaning of Life"); ! System.out.println(meaningOfLife.get(42)); System.out.println(meaningOfLife.get(43)); The Meaning of Life The Meaning of Life
  • 20. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Meaning Of Life l Hitchhiker's Guide to the Galaxy – Now we modify field after using it as a hash value – Newsletter # 031 from Nov '01 20 Map<Integer, String> meaningOfLife = new HashMap<>(); meaningOfLife.put(42, "The Meaning of Life"); ! Field value = Integer.class.getDeclaredField("value"); value.setAccessible(true); value.set(42, 43); ! System.out.println(meaningOfLife.get(42)); System.out.println(meaningOfLife.get(43)); null null
  • 21. Reflection Madness - JAX London 2014 21 © 2009-2014 Heinz Kabutz – All Rights Reserved Size of Objects
  • 22. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Determining Object Size l Object Size is not defined in Java – Differs per platform (Newsletters #029 Aug '01 and #078 Sep '03) • Java 1.0 - 1.3: Each field took at least 4 bytes • 32-bit: Pointer is 4 bytes, minimum object size 8 bytes • 64-bit: Pointer is 8 bytes, minimum object size 16 bytes • All platforms we looked at increase memory usage in 8 byte chunks – Can be measured with the Instrumentation API • Newsletter #142 - March '07 – We traverse object graph using reflection and IdentityHashMap to avoid duplicates • You might need to define your own endpoints 22
  • 23. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Reflection-Based Memory Counting l Find all connected objects and measure size – Count each object only once (IdentityHashMap) – Skip shared objects (Strings, Boxed Primitives, Classes, Enums, etc.) l Result is scary – In "C", "Heinz" was 6 bytes • String "Heinz" uses 80 bytes on a 64-bit JVM – Unless it is an "interned" String, then zero – Empty HashMap uses 216 bytes – List of 100 boolean values set to true – LinkedList uses 6472 bytes – ArrayList uses 3520 bytes – BitSet uses 72 bytes 23
  • 24. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved String Deduplication l Java 1.8.0_20, with G1, char[]s in Strings shared – Happens automatically – Can save substantial memory on some systems – -XX:+UseG1GC -XX:+UseStringDeduplication – Show effect with -XX:+PrintStringDeduplicationStatistics 24
  • 25. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Reified Primitive Types? l Java 7 was going to support ArrayList<int> – Fortunately this was dropped – Each int would use 24 bytes! • Rather use primitive specific collection classes 25
  • 26. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Instrumentation-Based Memory Counting l Implementation-specific estimate of object size ! ! ! ! ! ! ! – Only a shallow size, for deep sizes we still need reflection 26 public class MemoryCounterAgent { private static Instrumentation inst; /** Initializes agent */ public static void premain( String agentArgs, Instrumentation inst) { MemoryCounterAgent.inst = inst; } /** Returns object size. */ public static long sizeOf(Object obj) { return instrumentation.getObjectSize(obj); } }
  • 27. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Application of MemoryCounter l Educational Tool – Explains why Java needs 100 TB of RAM just to boot up l Debugging – One customer used it to discover size of user sessions • Need to define custom end-points in object graph l Ongoing Monitoring – Not that useful, too much overhead 27
  • 28. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Java Caller ID 28
  • 29. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Finding Out Who Called You lWith Sun's JVM, we have sun.reflect.Reflection – Used in Class.forName(String) 29 public class CallerID { public static Class<?> whoAmI() { return sun.reflect.Reflection.getCallerClass(2); } } ! public class CallerIDTest { public static void main(String... args) { class CallerIDTest System.out.println(CallerID.whoAmI()); } }
  • 30. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved @CallerSensitive l Java 8 disabled the call to Reflection.getCallerClass(int) l For finding out direct caller, use ! l However, it doesn't give us classes deeper in stack 30 Class<?> clazz = MethodHandles.lookup().lookupClass();
  • 31. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Finding Out Who Called You #2 l JVM independent using Exception Stack Traces – Does not tell you parameter types, only method name 31 public class CallerID { public static String whoAmI() { Throwable t = new Throwable(); StackTraceElement directCaller = t.getStackTrace()[1]; return directCaller.getClassName() + "." + directCaller.getMethodName() + "()"; } } class CallerIDTest.main()
  • 32. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Application of CallerID l Creating Loggers (Newsletter #137 - Dec '06) – Loggers often created with copy & paste 32 public class Application { private final static Logger logger = Logger.getLogger(Application.class.getName()); }
  • 33. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Avoiding Copy & Paste Bugs lWe can do this instead 33 public class LoggerFactory { public static Logger create() { Throwable t = new Throwable(); StackTraceElement caller = t.getStackTrace()[1]; return Logger.getLogger(caller.getClassName()); } } public class Application { private final static Logger logger = LoggerFactory.create(); }
  • 34. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Cost of Throwable.getStackTrace? l Creating a new Throwable is expeeeennnsssiiivvee – The fillInStackTrace() method is a native method call – However, the actual stack trace objects are empty • During debugging, if you want to see the actual stack trace of an exception, watch the getStackTrace() method (idea by Maik Jäkel) • The getStackTrace() method is even more expensive! l However, you need call it only once per logger 34
  • 35. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Finding Out Who Called You #3 l JVM independent using Security Manager 35 public class CallerID { public static Class<?> whoAmI() { MySecMgr sm = new MySecMgr(); return sm.getClassContext()[2]; } private static class MySecMgr extends SecurityManager { public Class[] getClassContext() { return super.getClassContext(); } } } class CallerIDTest
  • 36. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Application of CallerID for JUnit l Make running unit tests from main() 36 public class UnitTestRunner { public static void run() { MySecMgr sm = new MySecMgr(); Class<?> clazz = sm.getClassContext()[2]; System.out.println("Running unit tests for " + clazz); TestRunner.run(new JUnit4TestAdapter(clazz)); } ! private static class MySecMgr extends SecurityManager { public Class[] getClassContext() { return super.getClassContext(); } } }
  • 37. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Normal Unit Test With JUnit 4 l Cannot be directly invoked from the command line 37 import org.junit.*; import static org.junit.Assert.assertEquals; ! public class MyTest { @Test public void testHello() { assertEquals("HELLO", "hello".toUpperCase()); } }
  • 38. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Augmented Unit Test With JUnit 4 l Context aware method UnitTestRunner.run() 38 import org.junit.*; import static org.junit.Assert.assertEquals; ! public class MyTest { @Test public void testHello() { assertEquals("HELLO", "hello".toUpperCase()); } ! public static void main(String... args) { UnitTestRunner.run(); } }
  • 39. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Tests Automagically Run l Context aware method UnitTestRunner.run() 39 Running unit tests for class MyTest . Time: 0.048 ! OK (1 test)
  • 40. Reflection Madness - JAX London 2014 40 © 2009-2014 Heinz Kabutz – All Rights Reserved The Delegator
  • 41. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Automatic Delegator l MI5 want to see bytes flowing across my sockets – Java provides plugin methods to specify SocketImpl ! ! ! ! ! ! ! ! – Only catch, default SocketImpl classes are package access 41 public class MonitoringSocketFactory implements SocketImplFactory { public SocketImpl createSocketImpl() { return new MonitoringSocketImpl(); } } ! SocketImplFactory socketImplFactory = new MonitoringSocketFactory(); Socket.setSocketImplFactory(socketImplFactory); ServerSocket.setSocketFactory(socketImplFactory);
  • 42. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Delegating To Inaccessible Methods l All methods in SocketImpl are protected lWe cannot call them directly, only with reflection – But how do we know which method to call? lWe want to write ! ! ! ! – Should automatically call correct methods in wrapped object 42 public void close() throws IOException { delegator.invoke(); } public void listen(int backlog) throws IOException { delegator.invoke(backlog); }
  • 43. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Impossible? lWith Stack Trace CallerID, we can get close – If there is a clash, we specify method explicitly – First, we find the method that we are currently in 43 private String extractMethodName() { Throwable t = new Throwable(); return t.getStackTrace()[2].getMethodName(); }
  • 44. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Finding The Correct Method By Parameters 44 l Simple search – Find method with same name and number of parameters • Check that each of the objects are assignable – If not exactly one method is found, throw an exception
  • 45. private Method findMethod(Reflection Madness String methodName, - JAX London Object[] 2014 args) { 45 Class<?> clazz = superclass; if (args.length == 0) © 2009-2014 Heinz Kabutz – All Rights Reserved Finding The Correct Method By Parameters return clazz.getDeclaredMethod(methodName); Method match = null; next: for (Method method : clazz.getDeclaredMethods()) { if (method.getName().equals(methodName)) { Class<?>[] classes = method.getParameterTypes(); if (classes.length == args.length) { for (int i = 0; i < classes.length; i++) { Class<?> argType = classes[i]; argType = convertPrimitiveClass(argType); if (!argType.isInstance(args[i])) continue next; } if (match == null) match = method; else throw new DelegationException("Duplicate"); } } } if (match != null) return match; throw new DelegationException("Not found: " + methodName); }
  • 46. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Manual Override l Delegator allows you to specify method name and parameter types for exact match 46 public void connect(InetAddress address, int port) throws IOException { delegator .delegateTo("connect", InetAddress.class, int.class) .invoke(address, port); }
  • 47. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Invoking The Method l Generics "automagically" casts to return type 47 public final <T> T invoke(Object... args) { try { String methodName = extractMethodName(); Method method = findMethod(methodName, args); @SuppressWarnings("unchecked") T t = (T) invoke0(method, args); return t; } catch (NoSuchMethodException e) { throw new DelegationException(e); } }
  • 48. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved When Generics Fail lWorkaround: Autoboxing causes issues when we convert automatically ! ! lWorkaround: Inlining return type makes it impossible to guess what type it is 48 public int getPort() { Integer result = delegator.invoke(); return result; } public InputStream getInputStream() throws IOException { InputStream real = delegator.invoke(); return new DebuggingInputStream(real, monitor); }
  • 49. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Fixing Broken Encapsulation l Socket implementations modify parent fields directly – Before and after calling methods, we copy field values over 49 writeFields(superclass, source, delegate); method.setAccessible(true); Object result = method.invoke(delegate, args); writeFields(superclass, delegate, source);
  • 50. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Fixing Broken Encapsulation l Method writeFields() uses basic reflection – Obviously only works on fields of common superclass 50 private void writeFields(Class clazz, Object from, Object to) { for (Field field : clazz.getDeclaredFields()) { field.setAccessible(true); field.set(to, field.get(from)); } }
  • 51. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Complete Code l Newsletter #168 - Jan '09 – Includes primitive type mapper – Allows you to delegate to another object • Without hardcoding all the methods lWarning: – Calling delegated methods via reflection is much slower 51
  • 52. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Application Of Delegator lWrapping of SocketImpl object 52 public class MonitoringSocketImpl extends SocketImpl { private final Delegator delegator; ! public InputStream getInputStream() throws IOException { InputStream real = delegator.invoke(); return new SocketMonitoringInputStream(getSocket(), real); } ! public OutputStream getOutputStream() throws IOException { OutputStream real = delegator.invoke(); return new SocketMonitoringOutputStream(getSocket(), real); } ! public void create(boolean stream) throws IOException { delegator.invoke(stream); } ! public void connect(String host, int port) throws IOException { delegator.invoke(host, port); } // etc. }
  • 53. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Alternative To Reflection l Various other options exist: – Modify SocketImpl directly and put into boot class path – Use Aspect Oriented Programming to replace call • Needs to modify all classes that call Socket.getInputStream() and Socket.getOutputStream() 53
  • 54. Reflection Madness - JAX London 2014 54 © 2009-2014 Heinz Kabutz – All Rights Reserved Of "Final" Fields
  • 55. Reflection Madness - JAX London 2014 55 © 2009-2014 Heinz Kabutz – All Rights Reserved Manipulating Objects – Final Fields l Final fields cannot be reassigned l If they are bound at compile time, they will get inlined l However, reflection may allow us to rebind them with some versions of Java – Can introduce dangerous concurrency bugs – Final fields are considered constant and can be inlined at runtime by HotSpot compilers – Only ever do this for debugging or testing purposes
  • 56. Reflection Madness - JAX London 2014 56 © 2009-2014 Heinz Kabutz – All Rights Reserved Setting "Final" Field l Can be set since Java 1.5 – char[] value is actually "final" • We could still modify contents of array public class StringDestroyer { public static void main(String... args) throws IllegalAccessException, NoSuchFieldException { Field value = String.class.getDeclaredField("value"); value.setAccessible(true); value.set("hello!", "cheers".toCharArray()); System.out.println("hello!"); } } cheers
  • 57. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Setting "Static Final" Fields l Should not be possible, according to Lang Spec l However, here is how you can do it (Sun JVM): 1.Find the field using normal reflection 2.Find the "modifiers" field of the Field object 3.Change the "modifiers" field to not be "final" 1. modifiers &= ~Modifier.FINAL; 4.Get the FieldAccessor from the sun.reflect.ReflectionFactory 5.Use the FieldAccessor to set the final static field 57
  • 58. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved ReflectionHelper Class l Now we can set static final fields – Newsletter #161 in May '08 58 import sun.reflect.*; import java.lang.reflect.*; public class ReflectionHelper { private static final ReflectionFactory reflection = ReflectionFactory.getReflectionFactory(); ! public static void setStaticFinalField(Field field, Object value) throws NoSuchFieldException, IllegalAccessException { field.setAccessible(true); Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); int modifiers = modifiersField.getInt(field); modifiers &= ~Modifier.FINAL; modifiersField.setInt(field, modifiers); FieldAccessor fa = reflection.newFieldAccessor(field, false); fa.set(null, value); } }
  • 59. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Example of ReflectionHelper 59 public class StaticFieldTest { private final static Object obj = "Hello world!"; ! public static void main(String... args) throws NoSuchFieldException, IllegalAccessException { ReflectionHelper.setStaticFinalField( StaticFieldTest.class.getDeclaredField("obj"), "Goodbye cruel world!" ); System.out.println("obj = " + obj); } } Goodbye cruel world!
  • 60. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Application Of Setting Final Fields l Create new enum values dynamically for testing 60 public enum HumanState { HAPPY, SAD } ! public class Human { public void sing(HumanState state) { switch (state) { case HAPPY: singHappySong(); break; case SAD: singDirge(); break; default: Any problems? new IllegalStateException("Invalid State: " + state); throw } } private void singHappySong() { System.out.println("When you're happy and you know it ..."); } private void singDirge() { System.out.println("Don't cry for me Argentina, ..."); } }
  • 61. Reflection Madness - JAX London 2014 61 © 2009-2014 Heinz Kabutz – All Rights Reserved New "enum" Values
  • 62. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Most Protected Class l Enums are subclasses of java.lang.Enum l Almost impossible to create a new instance – One hack was to let enum be an anonymous inner class • Newsletter #141 - March '07 • We then subclassed it ourselves • This hack was stopped in Java 6 – We can create a new instance using sun.reflect.Reflection • But the enum switch statements are tricky – Adding a new enum will cause an ArrayIndexOutOfBoundsException 62
  • 63. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Creating New Enum Value lWe use the sun.reflect.ReflectionFactory class – The clazz variable represents the enum's class 63 Constructor cstr = clazz.getDeclaredConstructor( String.class, int.class ); ReflectionFactory reflection = ReflectionFactory.getReflectionFactory(); Enum e = reflection.newConstructorAccessor(cstr). newInstance("BLA",3);
  • 64. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Original Human.Sing() ! ! ! ! ! ! l Let's see how this is converted into byte code 64 public void sing(HumanState state) { switch (state) { case HAPPY: singHappySong(); break; case SAD: singDirge(); break; default: new IllegalStateException( "Invalid State: " + state); } }
  • 65. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved An Inner Class Is Generated l Decompiled with Pavel Kouznetsov's JAD 65 public void sing(HumanState state) { static class _cls1 { static final int $SwitchMap$HumanState[] = new int[HumanState.values().length]; static { try { $SwitchMap$HumanState[HumanState.HAPPY.ordinal()] = 1; } catch(NoSuchFieldError ex) { } try { $SwitchMap$HumanState[HumanState.SAD.ordinal()] = 2; } catch(NoSuchFieldError ex) { } } } ...
  • 66. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Generated Enum Switch 66 switch(_cls1.$SwitchMap$HumanState[state.ordinal()]) { case 1: singHappySong(); break; case 2: singDirge(); break; default: new IllegalStateException( "Invalid State: " + state); break; }
  • 67. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Modifying Enum "Switch" Statements l Follow this procedure: 1.Specify which classes contain enum switch statements 2.For each class, find all fields that follow the pattern $SwitchMap$enum_name 3.Make fields (int[]) larger by one slot 4.Set field values to new int[] 67
  • 68. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Memento Design Pattern l Every time we make a change, first copy the state – Allows us to undo previous change – Useful for testing purposes l EnumBuster class contains stack of undo mementos 68
  • 69. EnumBuster<HumanState> Reflection buster Madness = - JAX London 2014 69 new EnumBuster<>(HumanState.class, Human.class); try { Human heinz = new Human(); heinz.sing(HumanState.HAPPY); heinz.sing(HumanState.SAD); HumanState MELLOW = buster.make("MELLOW"); buster.addByValue(MELLOW); System.out.println(Arrays.toString(HumanState.values())); try { © 2009-2014 Heinz Kabutz – All Rights Reserved Testing Human Class heinz.sing(MELLOW); fail("Should have caused an IllegalStateException"); } catch (IllegalStateException success) { } } finally { System.out.println("Restoring HumanState"); buster.restore(); System.out.println(Arrays.toString(HumanState.values())); }
  • 70. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Test Output lWhen we run it, we should see the following ! ! ! ! ! – Note that when the test run is complete, all the classes have been changed back to what they were before 70 When you're happy and you know it ... Don't cry for me Argentina, ... [HAPPY, SAD, MELLOW] Restoring HumanState [HAPPY, SAD] ! AssertionFailedError: Should have caused an IllegalStateException at HumanTest.testSingingAddingEnum(HumanTest.java:23)
  • 71. Reflection Madness - JAX London 2014 71 © 2009-2014 Heinz Kabutz – All Rights Reserved Constructing without Constructor
  • 72. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Serialization Basics lWhen we serialize an object, fields are read with reflection and written to stream lWhen we deserialize it again, an object is constructed without calling the constructor – We can use the same mechanism to create objects 72
  • 73. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Basic Class lWhenever this object is instantiated, a message is printed to console – Furthermore, i is always 42 73 public class MyClass { private int i = 42; public MyClass(int i) { System.out.println("Constructor called"); } public String toString() { return "MyClass i=" + i; } }
  • 74. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Serialization Mechanism l Serialization can make objects without calling constructor – We can use the same mechanism (JVM specific) 74 ReflectionFactory rf = ReflectionFactory.getReflectionFactory(); Constructor objDef = Object.class.getDeclaredConstructor(); Constructor intConstr = rf.newConstructorForSerialization( MyClass.class, objDef mc = MyClass i=0 class MyClass ); ! MyClass mc = (MyClass) intConstr.newInstance(); System.out.println("mc = " + mc.toString()); System.out.println(mc.getClass());
  • 75. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Unsafe l Alternatively, we can use sun.misc.Unsafe – Again, JVM specific 75 Object o = Unsafe.getUnsafe().allocateInstance( MyClass.class); System.out.println("o = " + o.toString()); System.out.println(o.getClass());
  • 76. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Or Just Make New Constructor l Alternatively, we can use sun.misc.Unsafe – Again, JVM specific 76 public class MagicConstructorMaker { public static <T> Constructor<T> make(Class<T> clazz) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { Constructor<?> constr = Constructor.class.getDeclaredConstructor( Class.class, // Class<T> declaringClass Class[].class, // Class<?>[] parameterTypes Class[].class, // Class<?>[] checkedExceptions int.class, // int modifiers int.class, // int slot String.class, // String signature byte[].class, // byte[] annotations byte[].class); // byte[] parameterAnnotations constr.setAccessible(true); ...
  • 77. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved And Create New Constructor Object l This even works on Android Dalvik – However, Java 8 core dumps with wrong slot # 77 int slot = clazz.getDeclaredConstructors().length + 1; return (Constructor<T>) constr.newInstance( clazz, new Class[0], new Class[0], Modifier.PUBLIC, slot, "MyMagicConstructor", null, null); } }
  • 78. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Singletons? l Classic approach is private constructor – More robust: throw exception if constructed twice 78 public class Singleton { private final static Singleton instance = new Singleton(); private Singleton() { if (instance != null) throw new IllegalStateException("Duplicate singletons!!!"); } ! public static Singleton getInstance() { return instance; } }
  • 79. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Singletons? l Make new Singleton objects – My other techniques also work 79 Singleton.getInstance(); Singleton s = MagicConstructorMaker.make(Singleton.class).newInstance(); System.out.println(s == Singleton.getInstance()); System.out.println(s); System.out.println(Singleton.getInstance());
  • 80. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Application: Constructing Without Constructor l Useful when you need to recreate an object – e.g. Copy an object, de-persist it, etc. 80
  • 81. Reflection Madness - JAX London 2014 81 © 2009-2014 Heinz Kabutz – All Rights Reserved Externalizable Hack
  • 82. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Standard Serializing Approach l Class implements Serializable – Usually good enough l Next step is to add writeObject() and readObject() – Avoids reflection overhead • This is usually not measurable – Allows custom optimizations l Class implements Externalizable – May be a tiny bit faster than Serializable – But, opens security hole 82
  • 83. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Serializable Vs Externalizable lWriting of object – Serializable • Can convert object to bytes and read that - cumbersome – Externalizable • pass in a bogus ObjectOutput to gather data l Reading of object – Serializable • cannot change state of an existing object – Externalizable • use bogus ObjectInput to modify existing object 83
  • 84. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Our Moviecharacter Class 84 public class MovieCharacter implements Externalizable { private String name; private boolean hero; public MovieCharacter(String name, boolean hero) { this.name = name; this.hero = hero; } public void writeExternal(ObjectOutput out) throws IOException { out.writeUTF(name); out.writeBoolean(hero); } public void readExternal(ObjectInput in) throws IOException { name = in.readUTF(); hero = in.readBoolean(); } public String toString() { return name + " is " + (hero ? "" : "not ") + "a hero"; } }
  • 85. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Bogus ObjectInput Created 85 public class HackAttack { public static void hackit(MovieCharacter cc, String final boolean hero) throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(cc); oos.close(); ! ObjectInputStream ois = new ObjectInputStream( new ByteArrayInputStream(baos.toByteArray()) ) { public boolean readBoolean() throws IOException { return hero; } public String readUTF() { return name; } }; cc.readExternal(ois); // no security exception } }
  • 86. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Bogus ObjectInput Created 86 public class HackAttackTest { public static void main(String... args) throws Exception { System.setSecurityManager(new SecurityManager()); MovieCharacter cc = new MovieCharacter("John Hancock", true); System.out.println(cc); ! // Field f = MovieCharacter.class.getDeclaredField("name"); // f.setAccessible(true); // causes SecurityException ! HackAttack.hackit(cc, "John Hancock the drunkard", false); ! // now the private data of the MovieCharacter has changed! System.out.println(cc); } } John Hancock is a hero John Hancock the drunkard is not a hero
  • 87. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Application: Externalizable Hack l Be careful with using Externalizable – We can change the state of an existing object lWith Serializable, we can create bad objects – A lot more effort – Should be checked with ObjectInputValidation interface l Slight performance gain might not be worth it 87
  • 88. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Soft References and Reflection 88
  • 89. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Reflection and SoftReferences l Reflection information stored as soft refs – Created lazily on first use – Can be turned off with -Dsun.reflect.noCaches=true l Reflection information costs approximately 24KB per class and takes about 362 μs to generate 89
  • 90. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Demo Effects of not having caches 90
  • 91. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Effects On Performance l Soft References are cleared when system is under memory pressure – Cache essential reflection information – Otherwise you get noCaches=true performance l Danger: SoftReferences cause a quadratic degradation of performance during GC – Don't use them 91
  • 92. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Don't Use Softreference l Don't use SoftReference l Don't use SoftReference l Don't use SoftReference l Don't use SoftReference l Don't use SoftReference l Don't use SoftReference l Don't use SoftReference 92
  • 93. Reflection Madness - JAX London 2014 © 2009-2014 Heinz Kabutz – All Rights Reserved Do Not Use Soft Reference 93
  • 94. Reflection Madness - JAX London 2014 94 © 2009-2014 Heinz Kabutz – All Rights Reserved Conclusion l Reflection allows us some neat tricks in Java – Great power also means great responsibility – Don't overdo it, use sparingly l Tons of free articles on JavaSpecialists.EU – http://www.javaspecialists.eu/archive
  • 95. Reflection Madness - JAX London 2014 95 © 2009-2014 Heinz Kabutz – All Rights Reserved Reflection Madness Dr Heinz M. Kabutz [email protected] I would love to hear from you!
  • 96. Reflection Madness - JAX London 2014 96 © 2009-2014 Heinz Kabutz – All Rights Reserved The Java Specialists' Newsletter