JavaBlog.fr / Java.lu DEVELOPMENT,Java,Tools Java: Reflection, javap

Java: Reflection, javap

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,

java_reflexion.zip

Best regards,

Huseyin OZVEREN

Leave a Reply

Your email address will not be published.

Time limit is exhausted. Please reload CAPTCHA.

Related Post