Advanced Java Course Reflection
Reflection API What if you want to access information not just about the Object, but about that Object’s Class? What if you want to access a method, field, or constructor whose name you don’t know at compile time?
Example: WebCrawler timer To optimize your WebCrawler, first find out how long each big operation is taking. –Getting content from URLs –Parsing pages –Setting up Database Connection & Statement –Deleting from the Database –Inserting into the Database –Other?
How to time an operation? Without reflection: int startTime = System.currentTimeMillis(); doOperation(...); int endTime = System.currentTimeMillis(); int duration = endTime – startTime; Problem: Code is repeated every place you want to time an operation! Not clean at all...
A better way to time an operation Object timeMethod(String methodToCall, Class[] argTypes, Object[] args, String timeToUpdateField) {...} timeMethod(“methodName”, new Class[] {...}, new Object[] {...}, “timeStoringField”); No code repetition, less clutter!
Classes in the Reflection API Class Class Constructor Class Field Class Method
Getting an Object of type Class If you have an instance of the class: –Class classObject = instanceObject.getClass(); If you know the name of the class at compile time: –Class classObject = ClassName.class If you know the name of the class at run time: –Class.forName(“...”); If you want a primitive type class, and you know the name of the wrapper class at compile time; –Integer.TYPE, Long.TYPE, etc
some methods in the Class class getName() getSuperClass() getComponentType() – [null if !isArray()] isArray() isInterface() isPrimitive() isInstance(Object o) Object newInstance()
Getting Constructors/Methods/Fields ask the Class Object for them –classObject.getConstructors() –classObject.getConstructor( Class[] argTypes) –classObject.getDeclaredConstructors() –classObject.getDeclaredConstructors( Class[] argTypes) Methods and Fields have analogous getters in class Class. you can get an array of all the c/m/f in the class, or just one by name, and if you ask for “Declared” it gives you the non-public ones as well.
Objects of Type Method calling a method dynamically: –Object methodObject.invoke(Object o, Object[] args); getting info about it: –Class[] getParameterTypes() –Class getReturnType() –Class[] getExceptionTypes()
Objects of type Field Object fieldObject.get( Object o ); –also getInt(Object), getBoolean(Object), etc. void fieldObject.set( Object o, Object value ); –also setInt(Object o, int i), etc. Class fieldObject.getType() [compile time, of course] Fields of type int will have Integer.TYPE as the result of getType(), and it’s a Class Object.
Objects of type Constructor Object constructorObject.newInstance( Object[] args ) Class[] constructorObject.getExceptionTypes() Class[] constructorObject.getParameterTypes()
Member Interface Method, Field, and Constructor classes all extend the Member Interface Class getDeclaringClass() String getName() int getModifiers()
Modifier class (static methods) How do you know if something is static, final, etc.? int getModifiers() [from Member Interface] Modifer.isStatic(int) Modifer.isFinal(int) Modifier.isProtected(int) etc.
Array class (static methods) Object Array.get(Object arrayObject, int i); void Array.set(Object arrayObject, int index, Object value) int Array.getLength(Object arrayObject); Object newInstance(Class type, int length) Object newInstance(Class type, int[] dimensions)
Reflection Group Task #1 Fill in example from beginning of lecture: Object timeMethod(String methodToCall, Class[] argTypes, Object[] args, String timeToUpdateField) {... Please fill this in!... }
Solution to Reflection Group Task 1 Object timeMethod(String methodToCall, Class[] argTypes, Object[] args, String timeToUpdateField) throws NoSuchMethodException, NoSuchFieldException, InvocationTargetException, IllegalAccessException { Class c = this.getClass(); long startTime = System.currentTimeMillis(); Method m = c.getMethod(methodToCall, argTypes); Object returnValue = m.invoke(this, args); long endTime = System.currentTimeMillis(); Field f = c.getField(timeToUpdateField); f.setLong(this, f.getLong(this) + (endTime - startTime)); return returnValue; }
Reflection Group Task #2 Fill in the class definition to call all getX methods and print their values in the form: ClassName propertyName = value import java.lang.reflect.*; public class PropertyValueFinder { final String GET = "get"; public void printProperties(Object o) { /*fill this in*/ } private Property propertyGottenBy(Method method) { /*fill this in*/} private boolean isGetter(Method method) { /*fill this in*/ } public class Property { String name; Class type; Object value; public Property(String name, Class type) { this.name = name; this.type = type; } public void setValue(Object value) { this.value = value; } public String toString() { return type+" "+name+" = "+value; } }
Group Task #2 Solutions private boolean isGetter(Method m) { boolean nameOK = m.getName().startsWith(GET); boolean noArgs = m.getParameterTypes().length == 0; boolean nonVOID = m.getReturnType() != Void.TYPE; return nameOK && noArgs && nonVOID; } private Property propertyGottenBy(Method m) { if (!isGetter(m)) return null; Class propertyType = m.getReturnType(); String propertyName = m.getName().substring(GET.length()); return new Property(propertyName, propertyType); }
Group Task #2 Solutions public void printProperties(Object o) { Class oClass = o.getClass(); Method[] methods = oClass.getMethods(); for (int i = 0; i < methods.length; i++) { Method m = methods[i]; if (isGetter(m)) { try { Object value = m.invoke(o, new Object[0]); Property p = propertyGottenBy(m); p.setValue(value); System.out.println(p); } catch (IllegalAccessException e) { throw new RuntimeException(); //programmer error } catch (IllegalArgumentException e) { throw new RuntimeException(); //programmer error } catch (InvocationTargetException e) { throw new RuntimeException(); //programmer error }
Discussion Topic Restriction to Serializer project: I must promise that the Objects I test your code on will have a no-args constructor that: –sets the value of any final variables that are not set in the class definition –does not throw any exceptions. If you could add functionality to the Reflection API, how would you fix this without compromising the integrity of the keyword final? Work in teams, and then we’ll exchange ideas. Great, now go start a JSR (Java Specification Request)! –