Reflection Madness · – String "Heinz" uses 80 bytes on a 64-bit JVM • Unless it is an...
Transcript of Reflection Madness · – String "Heinz" uses 80 bytes on a 64-bit JVM • Unless it is an...
![Page 1: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/1.jpg)
Reflection Madness 1
Reflection Madness
Dr Heinz M. Kabutz
© 2009 Heinz Kabutz – All Rights Reserved
![Page 2: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/2.jpg)
Reflection Madness
Background
Heinz Kabutz– German-Dutch South African married to an English-Greek South
African, living in Chania on Crete with our 3 children– The Java Specialists’ Newsletter
• 50 000 readers in 120 countries• http://www.javaspecialists.eu
– Java Champion
– Actively code Java
– Teach Java to companies:• Java Specialist Master Course
– Advanced course for experienced Java programmers» Bouvet - Oslo - Norway - 6-9 Oct '09
• Java Design Patterns Course• http://www.javaspecialists.eu/courses
2
![Page 3: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/3.jpg)
Reflection Madness
Why Crete?
Airport 10 minutes from my house
24 mbit/s connection to internet (some areas)
Closer to customers than Cape Town
Great lifestyle, good food, clean air
Super friendly citizens
Wife and children are Greek citizens
And now for the real reason ...
3
![Page 4: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/4.jpg)
Reflection Madness
Why Crete?
Airport 10 minutes from my house
24 mbit/s connection to internet (some areas)
Closer to customers than Cape Town
Great lifestyle, good food, clean air
Super friendly citizens
Wife and children are Greek citizens
And now for the real reason ...
3
![Page 5: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/5.jpg)
Reflection Madness 4
Introduction to Reflection
![Page 6: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/6.jpg)
Reflection Madness
Introduction to Reflection
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
![Page 7: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/7.jpg)
Reflection Madness
Introduction to Reflection
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
Popular interview question: "Do you know reflection?"
![Page 8: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/8.jpg)
Reflection Madness
Introduction to Reflection
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
Popular interview question: "Do you know reflection?"
"Yes, I do. You can use it to modify private final fields and call methods dynamically."
![Page 9: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/9.jpg)
Reflection Madness
Introduction to Reflection
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
Popular interview question: "Do you know reflection?"
"Yes, I do. You can use it to modify private final fields and call methods dynamically."
"This interview is over. Thanks for applying and good luck for your future."
![Page 10: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/10.jpg)
Reflection Madness
Benefits of Reflection
Flexibility– Choose at runtime which methods to call
Raw Power– Background work such as reading private data
Magic Solutions– Do things you should not be able to do
• Sometimes binds you to JVM implementation
6
![Page 11: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/11.jpg)
Reflection Madness
Dangers of Reflection
Static Code Tools
Complex Code
Static compiling does not find typical errors– For example, code is written in XML and converted
dynamically to Java objects
Runtime Performance
Limited Applicability– Does not always work in Sandbox
7
![Page 12: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/12.jpg)
Reflection Madness
Introduction - Examining Classes
Each class is represented by a special class object.
The information for Class is stored in the .class file
It is used to defined the methods and fields of all the objects in the system.
The first time you need it, the JVM finds the .class file and loads it as a Class object
8
![Page 13: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/13.jpg)
Reflection Madness 9
Overview - Reflection Package
![Page 14: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/14.jpg)
Reflection Madness 10
With Class Class Drawn InAll classes inreflection referto java.lang.Class
![Page 15: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/15.jpg)
Reflection Madness 11
Overview – Working with Class Objects
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?– Lastly, we are able to cast objects using the class
![Page 16: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/16.jpg)
Reflection Madness
Accessing Members
From the class, we can get fields, methods and constructors– getField(name), getDeclaredField– getMethod(name, parameters...), getDeclaredMethod
– getConstructor(parameters...), getDeclaredConstructor
Private members require setAccessible(true)
12
![Page 17: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/17.jpg)
Reflection Madness 13
Modifying Private State
![Page 18: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/18.jpg)
Reflection Madness 14
Private Members
Can be made "accessible"– member.setAccessible(true)
– Requires security manager support
![Page 19: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/19.jpg)
Reflection Madness 14
Private Members
Can be made "accessible"– member.setAccessible(true)
– Requires security manager supportpublic class StringDestroyer {
![Page 20: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/20.jpg)
Reflection Madness 14
Private Members
Can be made "accessible"– member.setAccessible(true)
– Requires security manager supportpublic class StringDestroyer { public static void main(String[] args)
![Page 21: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/21.jpg)
Reflection Madness 14
Private Members
Can be made "accessible"– member.setAccessible(true)
– Requires security manager supportpublic class StringDestroyer { public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException {
![Page 22: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/22.jpg)
Reflection Madness 14
Private Members
Can be made "accessible"– member.setAccessible(true)
– Requires security manager supportpublic class StringDestroyer { public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException { Field value = String.class.getDeclaredField("value");
![Page 23: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/23.jpg)
Reflection Madness 14
Private Members
Can be made "accessible"– member.setAccessible(true)
– Requires security manager supportpublic class StringDestroyer { public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException { Field value = String.class.getDeclaredField("value"); value.setAccessible(true);
![Page 24: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/24.jpg)
Reflection Madness 14
Private Members
Can be made "accessible"– member.setAccessible(true)
– Requires security manager supportpublic 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());
![Page 25: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/25.jpg)
Reflection Madness 14
Private Members
Can be made "accessible"– member.setAccessible(true)
– Requires security manager supportpublic 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!");
![Page 26: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/26.jpg)
Reflection Madness 14
Private Members
Can be made "accessible"– member.setAccessible(true)
– Requires security manager supportpublic 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!"); }
![Page 27: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/27.jpg)
Reflection Madness 14
Private Members
Can be made "accessible"– member.setAccessible(true)
– Requires security manager supportpublic 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!"); }}
![Page 28: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/28.jpg)
Reflection Madness 14
Private Members
Can be made "accessible"– member.setAccessible(true)
– Requires security manager support
cheers
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!"); }}
![Page 29: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/29.jpg)
Reflection Madness
Newsletter 014, 2001-03-21
String is a special case– Shared object between classes if the same static content
15
![Page 30: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/30.jpg)
Reflection Madness
Newsletter 014, 2001-03-21
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"));
![Page 31: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/31.jpg)
Reflection Madness
Newsletter 014, 2001-03-21
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!cheerstrue
![Page 32: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/32.jpg)
Reflection Madness
Newsletter 102, 2005-01-31
Integers can also be mangled– Java autoboxing caches Integers -128 to 127
– We can modify these with reflection
16
![Page 33: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/33.jpg)
Reflection Madness
Newsletter 102, 2005-01-31
Integers can also be mangled– Java autoboxing caches Integers -128 to 127
– We can modify these with reflection
16
Field value = Integer.class.getDeclaredField("value");value.setAccessible(true);value.set(42, 43);
![Page 34: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/34.jpg)
Reflection Madness
Destroying Autoboxed Integer Integrity
Integers are more vulnerable than Strings
17
![Page 35: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/35.jpg)
Reflection Madness
Destroying Autoboxed Integer Integrity
Integers are more vulnerable than Strings
17
Field value = Integer.class.getDeclaredField("value");value.setAccessible(true);value.set(42, 43);
System.out.printf("Six times Seven = %d%n", 6 * 7);
![Page 36: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/36.jpg)
Reflection Madness
Destroying Autoboxed Integer Integrity
Integers are more vulnerable than Strings
17
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
![Page 37: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/37.jpg)
Reflection Madness
Meaning of Life
Hitchhiker's Guide to the Galaxy– Modifying a field related to hashCode is a very bad idea
18
![Page 38: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/38.jpg)
Reflection Madness
Meaning of Life
Hitchhiker's Guide to the Galaxy– Modifying a field related to hashCode is a very bad idea
18
Field value = Integer.class.getDeclaredField("value");value.setAccessible(true);value.set(42, 43);
Map<Integer, String> meaningOfLife = new HashMap<Integer, String>();meaningOfLife.put(42, "The Meaning of Life");
System.out.println(meaningOfLife.get(42));System.out.println(meaningOfLife.get(43));
![Page 39: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/39.jpg)
Reflection Madness
Meaning of Life
Hitchhiker's Guide to the Galaxy– Modifying a field related to hashCode is a very bad idea
18
Field value = Integer.class.getDeclaredField("value");value.setAccessible(true);value.set(42, 43);
Map<Integer, String> meaningOfLife = new HashMap<Integer, String>();meaningOfLife.put(42, "The Meaning of Life");
System.out.println(meaningOfLife.get(42));System.out.println(meaningOfLife.get(43));
The Meaning of LifeThe Meaning of Life
![Page 40: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/40.jpg)
Reflection Madness
Meaning of Life
Hitchhiker's Guide to the Galaxy– Now we modify field after using it as a hash value
– Newsletter # 031
19
![Page 41: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/41.jpg)
Reflection Madness
Meaning of Life
Hitchhiker's Guide to the Galaxy– Now we modify field after using it as a hash value
– Newsletter # 031
19
Map<Integer, String> meaningOfLife = new HashMap<Integer, String>();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));
![Page 42: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/42.jpg)
Reflection Madness
Meaning of Life
Hitchhiker's Guide to the Galaxy– Now we modify field after using it as a hash value
– Newsletter # 031
19
Map<Integer, String> meaningOfLife = new HashMap<Integer, String>();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));
nullnull
![Page 43: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/43.jpg)
Reflection Madness 20
Size of Objects
![Page 44: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/44.jpg)
Reflection Madness
Determining Object Size
Object Size is not defined in Java– Differs per platform
• 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– Alternatively, calculate with reflection
• Newsletters #029 and #078
21
![Page 45: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/45.jpg)
Reflection Madness
Reflection-Based Memory Counting
Find all connected objects and measure size– Count each object only once (IdentityHashMap)
– Skip shared objects (Strings, Boxed Primitives, Classes, Enums, etc.)
Result is scary
22
![Page 46: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/46.jpg)
Reflection Madness
Reflection-Based Memory Counting
Find all connected objects and measure size– Count each object only once (IdentityHashMap)
– Skip shared objects (Strings, Boxed Primitives, Classes, Enums, etc.)
Result is scary
22
– In "C", "Heinz" was 6 bytes
![Page 47: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/47.jpg)
Reflection Madness
Reflection-Based Memory Counting
Find all connected objects and measure size– Count each object only once (IdentityHashMap)
– Skip shared objects (Strings, Boxed Primitives, Classes, Enums, etc.)
Result is scary
22
– String "Heinz" uses 80 bytes on a 64-bit JVM• Unless it is an "interned" String, then zero
– In "C", "Heinz" was 6 bytes
![Page 48: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/48.jpg)
Reflection Madness
Reflection-Based Memory Counting
Find all connected objects and measure size– Count each object only once (IdentityHashMap)
– Skip shared objects (Strings, Boxed Primitives, Classes, Enums, etc.)
Result is scary
22
– String "Heinz" uses 80 bytes on a 64-bit JVM• Unless it is an "interned" String, then zero
– Empty HashMap uses 216 bytes
– In "C", "Heinz" was 6 bytes
![Page 49: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/49.jpg)
Reflection Madness
Reflection-Based Memory Counting
Find all connected objects and measure size– Count each object only once (IdentityHashMap)
– Skip shared objects (Strings, Boxed Primitives, Classes, Enums, etc.)
Result is scary
22
– 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
– In "C", "Heinz" was 6 bytes
![Page 50: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/50.jpg)
Reflection Madness
Instrumentation-Based Memory Counting
Returns an implementation-specific estimate of object size– Only a shallow size, for deep sizes we still need reflection
23
![Page 51: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/51.jpg)
Reflection Madness
Instrumentation-Based Memory Counting
Returns an implementation-specific estimate of object size– Only a shallow size, for deep sizes we still need reflection
23
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); }}
![Page 52: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/52.jpg)
Reflection Madness
Application of MemoryCounter
Educational Tool– Explains why Java needs 100 TB of RAM just to boot up
Debugging– One customer used it to discover size of user sessions
• Need to define custom end-points in object graph
Ongoing Monitoring– Not that useful, too much overhead
24
![Page 53: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/53.jpg)
Reflection Madness 25
Java Caller ID
![Page 54: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/54.jpg)
Reflection Madness
Finding Out Who Called You
With Sun's JVM, we have sun.reflect.Reflection– Used in Class.forName(String)
26
![Page 55: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/55.jpg)
Reflection Madness
Finding Out Who Called You
With Sun's JVM, we have sun.reflect.Reflection– Used in Class.forName(String)
26
public class CallerID { public static Class<?> whoAmI() { return sun.reflect.Reflection.getCallerClass(2); }}
public class CallerIDTest { public static void main(String[] args) { System.out.println(CallerID.whoAmI()); }}
![Page 56: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/56.jpg)
Reflection Madness
Finding Out Who Called You
With Sun's JVM, we have sun.reflect.Reflection– Used in Class.forName(String)
26
public class CallerID { public static Class<?> whoAmI() { return sun.reflect.Reflection.getCallerClass(2); }}
public class CallerIDTest { public static void main(String[] args) { System.out.println(CallerID.whoAmI()); }}
class CallerIDTest
![Page 57: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/57.jpg)
Reflection Madness
Finding Out Who Called You #2
JVM independent using Exception Stack Traces– Does not tell you parameters, only method name
27
![Page 58: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/58.jpg)
Reflection Madness
Finding Out Who Called You #2
JVM independent using Exception Stack Traces– Does not tell you parameters, only method name
27
public class CallerID { public static String whoAmI() { Throwable t = new Throwable(); StackTraceElement directCaller = t.getStackTrace()[1]; return directCaller.getClassName() + "." + directCaller.getMethodName() + "()"; }}
![Page 59: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/59.jpg)
Reflection Madness
Finding Out Who Called You #2
JVM independent using Exception Stack Traces– Does not tell you parameters, only method name
27
public class CallerID { public static String whoAmI() { Throwable t = new Throwable(); StackTraceElement directCaller = t.getStackTrace()[1]; return directCaller.getClassName() + "." + directCaller.getMethodName() + "()"; }}
class CallerIDTest.main()
![Page 60: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/60.jpg)
Reflection Madness
Application of CallerID
Creating Loggers (Newsletter #137)– Instead of the typical
– We can do this
28
public class Application { private final static Logger logger = Logger.getLogger(Application.class.getName());}
public class LoggerFactory { public static Logger create() { Throwable t = new Throwable(); StackTraceElement caller = t.getStackTrace()[1]; return Logger.getLogger(caller.getClassName()); }} // in Application private final static Logger logger = LoggerFactory.create();
![Page 61: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/61.jpg)
Reflection Madness 29
The Delegator
![Page 62: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/62.jpg)
Reflection Madness
Automatic Delegator
Use Case– We want to count all the bytes flowing across all the sockets
in our Java virtual machine• Java provides plugin methods to specify SocketImpl
• Only catch, default SocketImpl classes package access
30
public class MonitoringSocketFactory implements SocketImplFactory { public SocketImpl createSocketImpl() { return new MonitoringSocketImpl(); }}
SocketImplFactory socketImplFactory = new MonitoringSocketFactory();Socket.setSocketImplFactory(socketImplFactory);ServerSocket.setSocketFactory(socketImplFactory);
![Page 63: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/63.jpg)
Reflection Madness
Delegating to Inaccessible Methods
All methods in SocketImpl are protected
We cannot call them directly, only with reflection– But how do we know which method to call?
Here is what we want to do:
– This should automatically call the correct methods in the wrapped object
31
public void close() throws IOException { delegator.invoke();}
public void listen(int backlog) throws IOException { delegator.invoke(backlog);}
![Page 64: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/64.jpg)
Reflection Madness
Impossible?
With CallerID, we can get close– If there is a clash, we specify explicitly what method to call
– First, we find the method that we are currently in
32
private String extractMethodName() { Throwable t = new Throwable(); return t.getStackTrace()[2].getMethodName();}
![Page 65: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/65.jpg)
Reflection Madness
Finding the Correct Method by Parameters
33
private Method findMethod(String methodName, Object[] args) { Class<?> clazz = superclass; if (args.length == 0) return clazz.getDeclaredMethod(methodName); Method match = null;
![Page 66: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/66.jpg)
Reflection Madness
Finding the Correct Method by Parameters
33
private Method findMethod(String methodName, Object[] args) { Class<?> clazz = superclass; if (args.length == 0) return clazz.getDeclaredMethod(methodName); Method match = null; next:
![Page 67: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/67.jpg)
Reflection Madness
Finding the Correct Method by Parameters
33
private Method findMethod(String methodName, Object[] args) { Class<?> clazz = superclass; if (args.length == 0) return clazz.getDeclaredMethod(methodName); Method match = null; next: for (Method method : clazz.getDeclaredMethods()) {
![Page 68: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/68.jpg)
Reflection Madness
Finding the Correct Method by Parameters
33
private Method findMethod(String methodName, Object[] args) { Class<?> clazz = superclass; if (args.length == 0) return clazz.getDeclaredMethod(methodName); Method match = null; next: for (Method method : clazz.getDeclaredMethods()) { if (method.getName().equals(methodName)) {
![Page 69: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/69.jpg)
Reflection Madness
Finding the Correct Method by Parameters
33
private Method findMethod(String methodName, Object[] args) { Class<?> clazz = superclass; if (args.length == 0) return clazz.getDeclaredMethod(methodName); Method match = null; next: for (Method method : clazz.getDeclaredMethods()) { if (method.getName().equals(methodName)) { Class<?>[] classes = method.getParameterTypes();
![Page 70: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/70.jpg)
Reflection Madness
Finding the Correct Method by Parameters
33
private Method findMethod(String methodName, Object[] args) { Class<?> clazz = superclass; if (args.length == 0) 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) {
![Page 71: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/71.jpg)
Reflection Madness
Finding the Correct Method by Parameters
33
private Method findMethod(String methodName, Object[] args) { Class<?> clazz = superclass; if (args.length == 0) 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++) {
![Page 72: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/72.jpg)
Reflection Madness
Finding the Correct Method by Parameters
33
private Method findMethod(String methodName, Object[] args) { Class<?> clazz = superclass; if (args.length == 0) 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];
![Page 73: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/73.jpg)
Reflection Madness
Finding the Correct Method by Parameters
33
private Method findMethod(String methodName, Object[] args) { Class<?> clazz = superclass; if (args.length == 0) 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);
![Page 74: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/74.jpg)
Reflection Madness
Finding the Correct Method by Parameters
33
private Method findMethod(String methodName, Object[] args) { Class<?> clazz = superclass; if (args.length == 0) 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;
![Page 75: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/75.jpg)
Reflection Madness
Finding the Correct Method by Parameters
33
private Method findMethod(String methodName, Object[] args) { Class<?> clazz = superclass; if (args.length == 0) 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; }
![Page 76: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/76.jpg)
Reflection Madness
Finding the Correct Method by Parameters
33
private Method findMethod(String methodName, Object[] args) { Class<?> clazz = superclass; if (args.length == 0) 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;
![Page 77: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/77.jpg)
Reflection Madness
Finding the Correct Method by Parameters
33
private Method findMethod(String methodName, Object[] args) { Class<?> clazz = superclass; if (args.length == 0) 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");
![Page 78: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/78.jpg)
Reflection Madness
Finding the Correct Method by Parameters
33
private Method findMethod(String methodName, Object[] args) { Class<?> clazz = superclass; if (args.length == 0) 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"); }
![Page 79: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/79.jpg)
Reflection Madness
Finding the Correct Method by Parameters
33
private Method findMethod(String methodName, Object[] args) { Class<?> clazz = superclass; if (args.length == 0) 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"); } }
![Page 80: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/80.jpg)
Reflection Madness
Finding the Correct Method by Parameters
33
private Method findMethod(String methodName, Object[] args) { Class<?> clazz = superclass; if (args.length == 0) 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"); } } }
![Page 81: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/81.jpg)
Reflection Madness
Finding the Correct Method by Parameters
33
private Method findMethod(String methodName, Object[] args) { Class<?> clazz = superclass; if (args.length == 0) 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;
![Page 82: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/82.jpg)
Reflection Madness
Finding the Correct Method by Parameters
33
private Method findMethod(String methodName, Object[] args) { Class<?> clazz = superclass; if (args.length == 0) 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);
![Page 83: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/83.jpg)
Reflection Madness
Finding the Correct Method by Parameters
33
private Method findMethod(String methodName, Object[] args) { Class<?> clazz = superclass; if (args.length == 0) 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);}
![Page 84: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/84.jpg)
Reflection Madness
Manual Override
Delegator allows you to specify method name and parameter types for exact match
34
public void connect(InetAddress address, int port) throws IOException { delegator .delegateTo("connect", InetAddress.class, int.class) .invoke(address, port);}
![Page 85: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/85.jpg)
Reflection Madness
Invoking the Method
Generics "automagically" casts to correct return type
35
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); }}
![Page 86: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/86.jpg)
Reflection Madness
When Generics Fail
Workaround: Autoboxing causes issues when we convert automatically
Workaround: Inlining return type makes it impossible to guess what type it is
36
public int getPort() { Integer result = delegator.invoke(); return result;}
public InputStream getInputStream() throws IOException {
InputStream real = delegator.invoke(); return new DebuggingInputStream(real, monitor);}
![Page 87: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/87.jpg)
Reflection Madness
Fixing Broken Encapsulation
Socket implementations modify parent fields directly– Before and after calling methods, we copy field values over
– Method writeFields() uses basic reflection
• Obviously only works on fields of common superclass
37
writeFields(superclass, source, delegate);method.setAccessible(true);Object result = method.invoke(delegate, args);writeFields(superclass, delegate, source);
private void writeFields(Class clazz, Object from, Object to) throws Exception { for (Field field : clazz.getDeclaredFields()) { field.setAccessible(true); field.set(to, field.get(from)); }}
![Page 88: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/88.jpg)
Reflection Madness
Complete Code
Newsletter #168– Includes primitive type mapper
– Allows you to delegate to another object• Without hardcoding all the methods
Warning:– Calling delegated methods via reflection is much slower
38
![Page 89: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/89.jpg)
Reflection Madness
Application of Delegator
Wrapping of SocketImpl object
39
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.}
![Page 90: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/90.jpg)
Reflection Madness
Alternative to Reflection
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()
40
![Page 91: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/91.jpg)
Reflection Madness 41
Of "Final" Fields
![Page 92: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/92.jpg)
Reflection Madness 42
Manipulating Objects – Final fields
Final fields cannot be reassigned
If they are bound at compile time, they will get inlined
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
![Page 93: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/93.jpg)
Reflection Madness 43
How Final is “final”?
Sun Microsystems ambivalent:– JDK 1.1:
• Access control (private, etc.) not checked at runtime• Final fields cannot be rebound at runtime
– JDK 1.2:• Access control checked at runtime, setAccessible(true)
overrides• Final fields could be rebound at runtime with reflection
– JDK 1.3 + 1.4:• Final fields cannot be rebound at runtime
– JDK 1.5 + 1.6:• Final fields can be rebound at runtime with reflection• Except when primitive or String fields are set at declaration time• Also, static final fields cannot be reassigned
![Page 94: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/94.jpg)
Reflection Madness 44
Java Versions: When “final” Was Final
Java versions and lifespans
Suggestion: Treat final as if it really was …
– http://www.javaspecialists.eu/archive/Issue096.html
Version Code Name Release Date Lifespan (months)
Final is final
JDK 1.1.4 Sparkler 1997-09-12 15 Yes
J2SE 1.2 Playground 1998-12-04 18 No
J2SE 1.3 Kestrel 2000-05-08 21 Yes
J2SE 1.4 Merlin 2002-02-13 31 Yes
J2SE 5.0 Tiger 2004-09-29 18 No
![Page 95: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/95.jpg)
Reflection Madness 45
Setting "final" Field
Can be set since Java 1.5– char[] value is actually "final"
• If it was not, 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!"); }}
![Page 96: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/96.jpg)
Reflection Madness 45
Setting "final" Field
Can be set since Java 1.5– char[] value is actually "final"
• If it was not, we could still modify contents of array
cheers
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!"); }}
![Page 97: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/97.jpg)
Reflection Madness
Setting "static final" Fields
Should not be possible, according to Lang Spec
However, here is how you can do it (Sun JVM):1. Find the field using normal reflection2. Find the "modifiers" field of the Field object
3. Change the "modifiers" field to not be "final"3.1. modifiers &= ~Modifier.FINAL;
4. Get the FieldAccessor from the sun.reflect.ReflectionFactory5. Use the FieldAccessor to set the final static field
46
![Page 98: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/98.jpg)
Reflection Madness
ReflectionHelper Class
Now we can set static final fields
47
public class ReflectionHelper { private static final ReflectionFactory reflection = ReflectionFactory.getReflectionFactory();
public static void setStaticFinalField( Field field, Object value) throws NoSuchFieldException, IllegalAccessException { field.setAccessible(true);
![Page 99: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/99.jpg)
Reflection Madness
ReflectionHelper Class
Now we can set static final fields
47
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 =
![Page 100: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/100.jpg)
Reflection Madness
ReflectionHelper Class
Now we can set static final fields
47
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");
![Page 101: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/101.jpg)
Reflection Madness
ReflectionHelper Class
Now we can set static final fields
47
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);
![Page 102: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/102.jpg)
Reflection Madness
ReflectionHelper Class
Now we can set static final fields
47
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);
![Page 103: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/103.jpg)
Reflection Madness
ReflectionHelper Class
Now we can set static final fields
47
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;
![Page 104: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/104.jpg)
Reflection Madness
ReflectionHelper Class
Now we can set static final fields
47
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);
![Page 105: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/105.jpg)
Reflection Madness
ReflectionHelper Class
Now we can set static final fields
47
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(
![Page 106: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/106.jpg)
Reflection Madness
ReflectionHelper Class
Now we can set static final fields
47
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
![Page 107: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/107.jpg)
Reflection Madness
ReflectionHelper Class
Now we can set static final fields
47
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 );
![Page 108: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/108.jpg)
Reflection Madness
ReflectionHelper Class
Now we can set static final fields
47
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);
![Page 109: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/109.jpg)
Reflection Madness
ReflectionHelper Class
Now we can set static final fields
47
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); }
![Page 110: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/110.jpg)
Reflection Madness
ReflectionHelper Class
Now we can set static final fields
47
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); }}
![Page 111: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/111.jpg)
Reflection Madness
Application of Setting Final Fields
Create new enum values dynamically for testing
48
public enum HumanState { HAPPY, SAD }
public class Human { public void sing(HumanState state) { switch (state) { case HAPPY: singHappySong(); break; case SAD: singDirge(); break; default: new IllegalStateException("Invalid State: " + state); } } 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, ..."); }}
![Page 112: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/112.jpg)
Reflection Madness
Application of Setting Final Fields
Create new enum values dynamically for testing
48
public enum HumanState { HAPPY, SAD }
public class Human { public void sing(HumanState state) { switch (state) { case HAPPY: singHappySong(); break; case SAD: singDirge(); break; default: new IllegalStateException("Invalid State: " + state); } } 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, ..."); }}
Any problems?
![Page 113: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/113.jpg)
Reflection Madness
Application of Setting Final Fields
Create new enum values dynamically for testing
48
public enum HumanState { HAPPY, SAD }
public class Human { public void sing(HumanState state) { switch (state) { case HAPPY: singHappySong(); break; case SAD: singDirge(); break; default: new IllegalStateException("Invalid State: " + state); } } 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, ..."); }}
Any problems?
throw
![Page 114: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/114.jpg)
Reflection Madness 49
New "enum" Values
![Page 115: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/115.jpg)
Reflection Madness
Most Protected Class
Enums are subclasses of java.lang.Enum
Almost impossible to create a new instance– One hack was to let enum be an anonymous inner class
• Newsletter #141• 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 not straight forward
– Adding a new enum will cause an ArrayIndexOutOfBoundsException
50
![Page 116: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/116.jpg)
Reflection Madness
Creating New Enum Value
We use the sun.reflect.ReflectionFactory class– The clazz variable represents the enum's class
51
Constructor cstr = clazz.getDeclaredConstructor( String.class, int.class);ReflectionFactory reflection = ReflectionFactory.getReflectionFactory();Enum e = reflection.newConstructorAccessor(cstr).newInstance("BLA",3);
![Page 117: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/117.jpg)
Reflection Madness
Generated Enum Switch
Decompiled with Pavel Kouznetsov's JAD– The clazz variable represents the enum's superclass
52
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) { } } } switch(_cls1.$SwitchMap$HumanState[state.ordinal()]) { case 1: singHappySong(); break; case 2: singDirge(); break; default: new IllegalStateException("Invalid State: " + state); break; }}
![Page 118: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/118.jpg)
Reflection Madness
Modifying enum "switch" Statements
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[]
53
![Page 119: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/119.jpg)
Reflection Madness
Memento Design Pattern
Every time we make a change, first copy the state– Allows us to undo previous change
– Useful for testing purposes
EnumBuster class contains stack of undo mementos
54
![Page 120: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/120.jpg)
Reflection Madness
Testing Human Class
55
EnumBuster<HumanState> buster = new EnumBuster<HumanState>(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 { 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()));}
![Page 121: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/121.jpg)
Reflection Madness
Test Output
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
56
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)
![Page 122: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/122.jpg)
Reflection Madness 57
Constructing without Constructor
![Page 123: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/123.jpg)
Reflection Madness
Serialization Basics
When we serialize an object, fields are read with reflection and written to stream
When we deserialize it again, an object is constructed without calling the constructor– We can use the same mechanism to create objects
58
![Page 124: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/124.jpg)
Reflection Madness
Basic Class
Whenever this object is instantiated, a message is printed to console– Furthermore, i is always 42
59
public class MyClass { private int i = 42;
public MyClass(int i) { System.out.println("Constructor called"); }
public String toString() { return "MyClass i=" + i; }}
![Page 125: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/125.jpg)
Reflection Madness
Serialization Mechanism
Serialization can make objects without calling constructor– We can use the same mechanism
• JVM specific
60
ReflectionFactory rf = ReflectionFactory.getReflectionFactory();Constructor objDef =
Object.class.getDeclaredConstructor();Constructor intConstr =
rf.newConstructorForSerialization( MyClass.class, objDef);
MyClass mc = (MyClass) intConstr.newInstance();System.out.println("mc = " + mc.toString());System.out.println(mc.getClass());
![Page 126: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/126.jpg)
Reflection Madness
Serialization Mechanism
Serialization can make objects without calling constructor– We can use the same mechanism
• JVM specific
60
ReflectionFactory rf = ReflectionFactory.getReflectionFactory();Constructor objDef =
Object.class.getDeclaredConstructor();Constructor intConstr =
rf.newConstructorForSerialization( MyClass.class, objDef);
MyClass mc = (MyClass) intConstr.newInstance();System.out.println("mc = " + mc.toString());System.out.println(mc.getClass());
mc = MyClass i=0class MyClass
![Page 127: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/127.jpg)
Reflection Madness
Unsafe
Alternatively, we can use sun.misc.Unsafe– Again, JVM specific
61
Object o = Unsafe.getUnsafe().allocateInstance( MyClass.class);System.out.println("o = " + o.toString());System.out.println(o.getClass());
![Page 128: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/128.jpg)
Reflection Madness
Singletons?
Classic approach is private constructor– More robust: throw exception if constructed twice
With Unsafe and ReflectionFactory we can construct objects without calling constructor!
62
![Page 129: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/129.jpg)
Reflection Madness
Application: Constructing without Constructor
Please don't!
63
![Page 130: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/130.jpg)
Reflection Madness 64
Externalizable Hack
![Page 131: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/131.jpg)
Reflection Madness
Standard Serializing Approach
Class implements Serializable– Usually good enough
Next step is to add writeObject() and readObject()– Avoids reflection overhead
• This is usually not measurable– Allows custom optimizations
Class implements Externalizable– A tiny bit faster than Serializable
– But, opens security hole
65
![Page 132: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/132.jpg)
Reflection Madness
Serializable vs Externalizable
Writing of object– Serializable
• Can convert object to bytes and read that - cumbersome– Externalizable
• pass in a bogus ObjectOutput to gather data
Reading of object– Serializable
• cannot change state of an existing object– Externalizable
• use bogus ObjectInput to modify existing object
66
![Page 133: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/133.jpg)
Reflection Madness
Our MovieCharacter Class
67
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"; }}
![Page 134: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/134.jpg)
Reflection Madness
Bogus ObjectInput Created
68
public class HackAttack { public static void hackit( MovieCharacter cc, final String name, final boolean hero) throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(cc); oos.close();
![Page 135: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/135.jpg)
Reflection Madness
Bogus ObjectInput Created
68
public class HackAttack { public static void hackit( MovieCharacter cc, final String name, final boolean hero) throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(cc); oos.close();
ObjectInputStream ois = new ObjectInputStream(
![Page 136: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/136.jpg)
Reflection Madness
Bogus ObjectInput Created
68
public class HackAttack { public static void hackit( MovieCharacter cc, final String name, 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())
![Page 137: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/137.jpg)
Reflection Madness
Bogus ObjectInput Created
68
public class HackAttack { public static void hackit( MovieCharacter cc, final String name, 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()) ) {
![Page 138: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/138.jpg)
Reflection Madness
Bogus ObjectInput Created
68
public class HackAttack { public static void hackit( MovieCharacter cc, final String name, 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 {
![Page 139: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/139.jpg)
Reflection Madness
Bogus ObjectInput Created
68
public class HackAttack { public static void hackit( MovieCharacter cc, final String name, 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;
![Page 140: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/140.jpg)
Reflection Madness
Bogus ObjectInput Created
68
public class HackAttack { public static void hackit( MovieCharacter cc, final String name, 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; }
![Page 141: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/141.jpg)
Reflection Madness
Bogus ObjectInput Created
68
public class HackAttack { public static void hackit( MovieCharacter cc, final String name, 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() {
![Page 142: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/142.jpg)
Reflection Madness
Bogus ObjectInput Created
68
public class HackAttack { public static void hackit( MovieCharacter cc, final String name, 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;
![Page 143: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/143.jpg)
Reflection Madness
Bogus ObjectInput Created
68
public class HackAttack { public static void hackit( MovieCharacter cc, final String name, 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; }
![Page 144: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/144.jpg)
Reflection Madness
Bogus ObjectInput Created
68
public class HackAttack { public static void hackit( MovieCharacter cc, final String name, 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; } };
![Page 145: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/145.jpg)
Reflection Madness
Bogus ObjectInput Created
68
public class HackAttack { public static void hackit( MovieCharacter cc, final String name, 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
![Page 146: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/146.jpg)
Reflection Madness
Bogus ObjectInput Created
68
public class HackAttack { public static void hackit( MovieCharacter cc, final String name, 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 }
![Page 147: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/147.jpg)
Reflection Madness
Bogus ObjectInput Created
68
public class HackAttack { public static void hackit( MovieCharacter cc, final String name, 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 }}
![Page 148: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/148.jpg)
Reflection Madness
Bogus ObjectInput Created
69
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); }}
![Page 149: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/149.jpg)
Reflection Madness
Bogus ObjectInput Created
69
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
![Page 150: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/150.jpg)
Reflection Madness
Application: Externalizable Hack
Be careful with using Externalizable– We can change the state of an existing object
With Serializable, we can create bad objects– A lot more effort
– Should be checked with ObjectInputValidation interface
Slight performance advantage might not be worth it
70
![Page 151: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/151.jpg)
Reflection Madness 71
Conclusion
Reflection allows us some neat tricks in Java
– Great power also means great responsibility
– Don't overdo it, use sparingly
Tons of free articles on JavaSpecialists.EU– http://www.javaspecialists.eu/archive
Advanced Java Courses available
– http://www.javaspecialists.eu/courses
– Java Specialist Master Course: Oslo - 6-9 Oct '09
![Page 152: Reflection Madness · – 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](https://reader033.fdocuments.net/reader033/viewer/2022042420/5f36d3b73a3a9113713e5cf7/html5/thumbnails/152.jpg)
Reflection Madness 72
Reflection Madness
Dr Heinz M. Kabutzhttp://www.javaspecialists.eu/contact.html
I would love to hear from you!