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 • 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)! – http://www.jcp.org/en/participation/membership
Recommend
More recommend