Hello,
In this article, I want present you the concept of reflection, especially in JAVA world.
First, what is Reflection?
In computer programming, reflection is the ability of a program to review and possibly modify, the internal structures of high-level (eg objects) at runtime.
In OO programming, the reflection allows the introspection of classes i.e. loading a class, creation of an instance and access to the members (static or not), for example the methods’ calls, reading and writing of attributes without knowing the class in advance. Java has an API for reflection which is used mainly to manage extensions/plugins in an application.
I invite you to read the Wikipedia definition http://en.wikipedia.org/wiki/Reflection_(computer_programming).
Use of Reflection
While at first glance, the reflection appears to be reserved for a top-flight programming, but what are the cases of application of reflection?
Following, some concret use cases of reflection:
- Use reflection to discovery of attributs of a object, to initialize its member variables or instanciate an object from its “definition” at runtime. For example, Spring framework whose the success demonstrates the viability of reflection in this use case.
- Use reflection to write a generic code generator for a set of classes (like JAXB-XJC).
- Automatically process the content objects. For example, to display all informations of an object in a page automatically (ie without access to all fields of the object), the use of reflection can be very handy and save a lot time. Indeed, by browsing the contents of an object by reflection, in a nutshell, any structural modification of the object (such as adding a field in the object) is automatically passed effortlessly to all points using this object.
- The JVM uses reflection to introspect a class of a external library and in error cases, returns with precision a error message allowing its location in code source. For example, a missing method:
Java.lang.NoSuchMethodError At MyOwnClass.main(MyOwnClass.java:123)
- The dynamic programming of reflection allows to ignore the content of classes and write generic code that can handle any class. This type of programming is typically used by IDEs in the aid in programming or code completion without building of a bank of informations concerning the definition of used services.
- Reflection is used in the serialization process in the calls and exchanges on networks.
- …in the development of logging tools, in the SQL script generation for the persistence of an object…etc.
Javap Utility
There are some utilities to make the information available: convert the compiled code (byte code in Java) to a understood language by a human. One such tool is javap, which is available in the SDK and consists of a basic decompiler. In Windows the tools is named Javap.exe, which is present in the directory jdk\bin and its basic syntax is:
javap com.ho.test.my.own.package.MyOwnClass
For example, below, the description of java.lang.String:
C:\Program Files (x86)\Java\jdk1.6.0_26\bin>javap java.lang.String Compiled from "String.java" public final class java.lang.String extends java.lang.Object implements java.io. Serializable,java.lang.Comparable,java.lang.CharSequence{ public static final java.util.Comparator CASE_INSENSITIVE_ORDER; public java.lang.String(); public java.lang.String(java.lang.String); public java.lang.String(char[]); public java.lang.String(char[], int, int); [...] public static java.lang.String valueOf(char[], int, int); public static java.lang.String copyValueOf(char[], int, int); public static java.lang.String copyValueOf(char[]); public static java.lang.String valueOf(boolean); public static java.lang.String valueOf(char); public static java.lang.String valueOf(int); public static java.lang.String valueOf(long); public static java.lang.String valueOf(float); public static java.lang.String valueOf(double); public native java.lang.String intern(); public int compareTo(java.lang.Object); static {}; }
For help:
javap -help
Implementation of reflection in JAVA
The java.lang.reflect package is devoted to reflection. But the classes java.lang.Class and java.lang.Package are used a lot in the reflection programming. After the compiling of a Java source code, the byte code created contains the meta data including the parent class, implemented interface, constructors, fields, methods,… of compiled code. The characteristics of the object are represented formally by the following main classes:
Java Class | Description |
---|---|
Class | A class |
Package | A Package |
Method | A method of class |
Constructor | A constructor of class |
Field | A field/variable of class |
… | … |
This list is not exhaustive because the purpose of this article is to give a first approach of reflection. You could find expressly, some examples of reflection API use (where the ‘o’ variable is ‘Object’):
- get the classname of an Object,
Class c = o.getClass(); String name = c.getName();
- get the Field Object corresponding to a specific public field,
Class c = o.getClass(); Field f = c.getField(name);
- get the public fields of an Object,
Class c = o.getClass(); Field[] ftab = c.getFields();
- get a method Object corresponding to a specific public method with the defined parameters by the parameterTypes tables
Class c = o.getClass(); Method m = c.getMethod(name, parameterTypes);
- get the public methods of an Object
Class c = o.getClass(); Method[] mtab = c.getMethods();
- get a Constructor object corresponding to a specific public constructor with the defined parameters by the parameterTypes table
Class c = o.getClass(); Constructor cons = c.getConstructor(parameterTypes);
- get the public Constructors of an Object
Class c = o.getClass(); Constructor[] constab = c.getConstructors();
- get the implemented interfaces of an Object
Class c = o.getClass(); Class[] itab = c.getInterfaces();
- get the super classes of an Object
Class c = o.getClass(); Class superclass = c.getSuperclass();
- get the Package object corresponding of an Object
Class c = o.getClass(); Package pck = c.getPackage();
- change the value of a public field
Class c = o.getClass(); Field f = c.getField(name); f.set(o,val);
- return a public field
Class c = o.getClass(); Field f = c.getField(name); f.get(o);
- Invoke a public method
Class c = o.getClass(); Method m = c.getMethod(name, parameterTypes); m.invoke(o,args);
Reflection and Encapsulation: private, protected, package scopes
So, the methods “getField”, “getFields”, “getMethod” and “getMethods” allow the retrieve the publics fields and methods. However, there are others methods named “getDeclaredFields” and “getDeclaredMethods” which give the possibilities to violate the rules of encapsulation, in being able to see the characteristics of private, protected fields and methods. The Reflection API allows thus, the virtual machine to be able to explore all elements of a class, but especially the necessity to dispose of all meta data in order to detect errors in running.
- get a specific Field object corresponding to public, private or protected field,
Class c = o.getClass(); Field f = c.getDeclaredField(name); f.setAccessible(true);
- get the Public, private and protected fields of an Object,
Class c = o.getClass(); Field[] ftab = c.getDeclaredFields(); for (int i = 0; i < ftab.length; i++) { ftab[i].setAccessible(true); }
- get a Method object corresponding to a specific public, private or protected method with the defined parameters by the parameterTypes table,
Class c = o.getClass(); Method m = c.getDeclaredMethod(name, parameterTypes); m.setAccessible(true);
- get the Public, private or protected methods of an Object,
Class c = o.getClass(); Method[] mtab = c.getDeclaredMethods(); for (int i = 0; i < mtab.length; i++) { mtab[i].setAccessible(true); }
- get a Constructor object corresponding to public, private or protected constructor with the defined parameters by the parameterTypes table,
Class c = o.getClass(); Constructor cons = c.getDeclaredConstructor(parameterTypes); cons.setAccessible(true);
- get the Public, private or protected constructors of an Object,
Class c = o.getClass(); Constructor[] constab = c.getDeclaredConstructors(); for (int i = 0; i < constab.length; i++) { constab[i].setAccessible(true); }
- modify a public, private or protected field,
Field f = this.getDeclaredField(o, name); f.setAccessible(true); f.set(o,val);
- return a specific public, private or protected field,
Field f = this.getDeclaredField(o, name); f.setAccessible(true); f.get(o);
- invoke a specific public, private or protected method,
Class[] paramTypes = null; paramTypes = new Class[args.length]; for(int i=0;i<args.length;++i){ paramTypes[i] = args[i].getClass(); } Method m = this.getDeclaredMethod(o, name, paramTypes); m.setAccessible(true); m.invoke(o,args);
By calling the setAcessible(true) method on Field or Method objects, the access checks are turned off for the particular Field or Method instance, for reflection only.
So, the access of private, protected or package scoped fields or methods are possible, and even, its value can be modified.
Reflection Tools Class
In order to benefit of above reflection concepts, I propose a tools class:
package com.ho.test.reflexion; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * Reflection Tools Class * @author Huseyin OZVEREN * */ public class ReflectionTools { public ReflectionTools() { } // Classname public String getName(Object o) throws Exception { Class c = o.getClass(); String name = c.getName(); System.out.println("getName=" + name); return name; } // Field Object corresponding to a specific public field public Field getField(Object o, String name) throws Exception { Class c = o.getClass(); Field f = c.getField(name); System.out.println("getField=" + f.toString()); return f; } // Public fields of an Object public Field[] getFields(Object o) throws Exception { Class c = o.getClass(); Field[] ftab = c.getFields(); for (int i = 0; i < ftab.length; i++) { System.out.println("getFields ftab[" + i + "]=" + ftab[i].toString()); } return ftab; } // Method Object corresponding to a specific public method with the defined parameters by the parameterTypes tables public Method getMethod(Object o, String name, Class... parameterTypes)throws Exception { Class c = o.getClass(); Method m = c.getMethod(name, parameterTypes); System.out.println("getMethod=" + m.toString()); return m; } // Public methods of an Object public Method[] getMethods(Object o) throws Exception { Class c = o.getClass(); Method[] mtab = c.getMethods(); for (int i = 0; i < mtab.length; i++) { System.out.println("getMethods mtab[" + i + "]=" + mtab[i].toString()); } return mtab; } // Constructor object corresponding to a specific public constructor with the defined parameters by the parameterTypes table public Constructor getConstructor(Object o, Class... parameterTypes) throws Exception { Class c = o.getClass(); Constructor cons = c.getConstructor(parameterTypes); System.out.println("getConstructor=" + cons.toString()); return cons; } // Public Constructors of an Object public Constructor[] getConstructors(Object o) throws Exception { Class c = o.getClass(); Constructor[] constab = c.getConstructors(); for (int i = 0; i < constab.length; i++) { System.out.println("getConstructors constab[" + i + "]=" + constab[i].toString()); } return constab; } // Implemented interfaces of an Object public Class[] getInterfaces(Object o) throws Exception { Class c = o.getClass(); Class[] itab = c.getInterfaces(); for (int i = 0; i < itab.length; i++) { System.out.println("getInterfaces itab[" + i + "]=" + itab[i].toString()); } return itab; } // Super classes of an Object public Class getSuperclass(Object o) throws Exception { Class c = o.getClass(); Class superclass = c.getSuperclass(); System.out.println("getSuperclass=" + superclass.toString()); return superclass; } // Package object corresponding of an Object public Package getPackage(Object o) throws Exception { Class c = o.getClass(); Package pck = c.getPackage(); System.out.println("getPackage=" + pck.toString()); return pck; } // Change the value of a public field public void changeFieldValue(Object o, String name, Object val) throws Exception { Field f = this.getField(o, name); f.set(o,val); } // Return a public field public Object getFieldValue(Object o, String name) throws Exception { Field f = this.getField(o, name); return f.get(o); } // Invoke a public method public Object invokeMethod(Object o, String name, Object[] args) throws Exception { Class[] paramTypes = null; if(args != null) { paramTypes = new Class[args.length]; for(int i=0;i<args.length;++i){ paramTypes[i] = args[i].getClass(); } } Method m = this.getMethod(o, name, paramTypes); return m.invoke(o,args); } //############################################## // Important Note: unlike "getFields" and "getMethods" methods, the methods "getDeclaredFields" and "getDeclaredMethods" // do not return the information inherited. In this case, it is necessary to go ask the parent class. //############################################## // Get a specific Field object corresponding to public, private or protected field public Field getDeclaredField(Object o, String name) throws Exception { Class c = o.getClass(); Field f = c.getDeclaredField(name); f.setAccessible(true); System.out.println("getDeclaredField=" + f.toString()); return f; } // Public, private and protected fields of an Object public Field[] getDeclaredFields(Object o) throws Exception { Class c = o.getClass(); Field[] ftab = c.getDeclaredFields(); for (int i = 0; i < ftab.length; i++) { ftab[i].setAccessible(true); System.out.println("getDeclaredFields ftab[" + i + "]=" + ftab[i].toString()); } return ftab; } // Method object corresponding to a specific public, private or protected method with the defined parameters by the parameterTypes table public Method getDeclaredMethod(Object o, String name, Class... parameterTypes)throws Exception { Class c = o.getClass(); Method m = c.getDeclaredMethod(name, parameterTypes); m.setAccessible(true); System.out.println("getDeclaredMethod=" + m.toString()); return m; } // Public, private or protected methods of an Object public Method[] getDeclaredMethods(Object o) throws Exception { Class c = o.getClass(); Method[] mtab = c.getDeclaredMethods(); for (int i = 0; i < mtab.length; i++) { mtab[i].setAccessible(true); System.out.println("getDeclaredMethods mtab[" + i + "]=" + mtab[i].toString()); } return mtab; } // Constructor object corresponding to public, private or protected constructor // with the defined parameters by the parameterTypes table public Constructor getDeclaredConstructor(Object o, Class... parameterTypes) throws Exception { Class c = o.getClass(); Constructor cons = c.getDeclaredConstructor(parameterTypes); cons.setAccessible(true); System.out.println("getDeclaredConstructor=" + cons.toString()); return cons; } // Public, private or protected constructors of an Object public Constructor[] getDeclaredConstructors(Object o) throws Exception { Class c = o.getClass(); Constructor[] constab = c.getDeclaredConstructors(); for (int i = 0; i < constab.length; i++) { constab[i].setAccessible(true); System.out.println("getDeclaredConstructors constab[" + i + "]=" + constab[i].toString()); } return constab; } // Modify a public, private or protected field public void changeDeclaredFieldValue(Object o, String name, Object val) throws Exception { Field f = this.getDeclaredField(o, name); f.setAccessible(true); f.set(o,val); } // Return a specific public, private or protected field public Object getDeclaredFieldValue(Object o, String name) throws Exception { Field f = this.getDeclaredField(o, name); f.setAccessible(true); return f.get(o); } // Invoke a specific public, private or protected method public Object invokeDeclaredMethod(Object o, String name, Object[] args) throws Exception { Class[] paramTypes = null; if(args != null) { paramTypes = new Class[args.length]; for(int i=0;i<args.length;++i){ paramTypes[i] = args[i].getClass(); } } Method m = this.getDeclaredMethod(o, name, paramTypes); m.setAccessible(true); return m.invoke(o,args); } }
Download
The attachment java_reflexion.zip contains a project with:
+ TestClassInstance extends SuperTestClassInstance implements Serializable, ITestClassInstance: Class to check via reflection,
+ ITestClassInstance: Interface of class to check via reflection,
+ SuperTestClassInstance: Super class of class to check via reflection,
+ ReflectionTools: ReflectionTools,
+ JUClassToolsWithTestClassInstance: JUNIT testcase to test the reflection,
Best regards,
Huseyin OZVEREN