29
Java Reflection Tutorial Java Reflection makes it possible to inspect classes, interfaces, fields and methods at runtime, without knowing the names of the classes, methods etc. at compile time. It is also possible to instantiate new objects, invoke methods and get/set field values using reflection. Java Reflection is quite powerful and can be very useful. For instance, when mapping objects to tables in a database at runtime, like Butterfly Persistence does. Or, when mapping the statements in a script language to method calls on real objects at runtime, like Butterfly Container does when parsing its configuration scripts. There are already numerous Java Reflection Tutorials on the internet. However, most of them, including Sun's own Java Reflection tutorial, only scratch the surface of Java Reflection and its possibilities. This tutorial will get into Java reflection in more depth than most of the tutorials I have seen. It will explain the basics of Java Reflection including how to work with arrays, annotations, generics and dynamic proxies, and do dynamic class loading and reloading. It will also show you how to do more specific tasks, like reading all getter methods of a class, or accessing private fields and methods of a class. This tutorial will also clear up some of the confusion out there about what Generics information is available at runtime. Some people claim that all Generics information is lost at runtime. This is not true. This tutorial describes the version of Java Reflection found in Java 6. Java Reflection Example Here is a quick Java Reflection example to show you what using reflection looks like: Method[] methods = MyObject.class.getMethods(); for(Method method : methods){ System.out.println("method = " + method.getName()); } This example obtains the Class object from the class called MyObject. Using the class object the example gets a list of the methods in that class, iterates the methods and print out their names. Exactly how all this works is explained in further detail throughout the rest of this tutorial (in other texts).

Java Reflection Tutorial.pdf

Embed Size (px)

Citation preview

Page 1: Java Reflection Tutorial.pdf

Java Reflection Tutorial

Java Reflection makes it possible to inspect classes, interfaces, fields and methods at runtime, without knowing

the names of the classes, methods etc. at compile time. It is also possible to instantiate new objects, invoke

methods and get/set field values using reflection.

Java Reflection is quite powerful and can be very useful. For instance, when mapping objects to tables in a

database at runtime, like Butterfly Persistence does. Or, when mapping the statements in a script language to

method calls on real objects at runtime, like Butterfly Container does when parsing its configuration scripts.

There are already numerous Java Reflection Tutorials on the internet. However, most of them, including Sun's

own Java Reflection tutorial, only scratch the surface of Java Reflection and its possibilities.

This tutorial will get into Java reflection in more depth than most of the tutorials I have seen. It will explain the

basics of Java Reflection including how to work with arrays, annotations, generics and dynamic proxies, and do

dynamic class loading and reloading. It will also show you how to do more specific tasks, like reading all getter

methods of a class, or accessing private fields and methods of a class. This tutorial will also clear up some of

the confusion out there about what Generics information is available at runtime. Some people claim that all

Generics information is lost at runtime. This is not true.

This tutorial describes the version of Java Reflection found in Java 6.

Java Reflection Example

Here is a quick Java Reflection example to show you what using reflection looks like:

Method[] methods = MyObject.class.getMethods();

for(Method method : methods){

System.out.println("method = " + method.getName());

}

This example obtains the Class object from the class called MyObject. Using the class object the example gets

a list of the methods in that class, iterates the methods and print out their names.

Exactly how all this works is explained in further detail throughout the rest of this tutorial (in other texts).

Page 2: Java Reflection Tutorial.pdf

Java Reflection – Classes

Using Java Reflection you can inspect Java classes at runtime. Inspecting classes is often the first thing you do

when using Reflection. From the classes you can obtain information about

Class Name Class Modifies (public, private, synchronized etc.) Package Info Superclass Implemented Interfaces Constructors Methods Fields Annotations

Plus a lot more information related to Java classes. For a full list you should consult the JavaDoc for

java.lang.Class. This text will briefly touch upon all accessing of the above mentioned information. Some of the

topics will also be examined in greater detail in separate texts. For instance, this text will show you how to

obtain all methods or a specific method, but a separate text will show you how to invoke that method, how to

find the method matching a given set of arguments if more than one method exists with the same name, what

exceptions are thrown from method invocation via reflection, how to spot a getter/setter etc. The purpose of this

text is primarily to introduce the Class object and the information you can obtain from it.

The Class Object

Before you can do any inspection on a class you need to obtain its java.lang.Class object. All types in Java

including the primitive types (int, long, float etc.) including arrays have an associated Class object. If you

know the name of the class at compile time you can obtain a Class object like this:

Class myObjectClass = MyObject.class

If you don't know the name at compile time, but have the class name as a string at runtime, you can do like this:

String className = ... //obtain class name as string at runtime Class class = Class.forName(className);

When using the Class.forName() method you must supply the fully qualified class name. That is the class

name including all package names. For instance, if MyObject is located in package com.jenkov.myapp then the

fully qualified class name is com.jenkov.myapp.MyObject

The Class.forName() method may throw a ClassNotFoundException if the class cannot be found on the

classpath at runtime.

Class Name

From a Class object you can obtain its name in two versions. The fully qualified class name (including package

name) is obtained using the getName() method like this:

Class aClass = ... //obtain Class object. See prev. section

String className = aClass.getName();

Page 3: Java Reflection Tutorial.pdf

If you want the class name without the pacakge name you can obtain it using the getSimpleName() method,

like this:

Class aClass = ... //obtain Class object. See prev. section

String simpleClassName = aClass.getSimpleName();

Modifiers

You can access the modifiers of a class via the Class object. The class modifiers are the keywords "public",

"private", "static" etc. You obtain the class modifiers like this:

Class aClass = ... //obtain Class object. See prev. section

int modifiers = aClass.getModifiers();

The modifiers are packed into an int where each modifier is a flag bit that is either set or cleared. You can

check the modifiers using these methods in the class java.lang.reflect.Modifier:

Modifier.isAbstract(int modifiers)

Modifier.isFinal(int modifiers)

Modifier.isInterface(int modifiers)

Modifier.isNative(int modifiers)

Modifier.isPrivate(int modifiers)

Modifier.isProtected(int modifiers)

Modifier.isPublic(int modifiers)

Modifier.isStatic(int modifiers)

Modifier.isStrict(int modifiers)

Modifier.isSynchronized(int modifiers)

Modifier.isTransient(int modifiers)

Modifier.isVolatile(int modifiers)

Package Info

You can obtain information about the package from a Class object like this:

Class aClass = ... //obtain Class object. See prev. section

Package package = aClass.getPackage();

From the Package object you have access to information about the package like its name. You can also access

information specified for this package in the Manifest file of the JAR file this package is located in on the

classpath. For instance, you can specify package version numbers in the Manifest file. You can read more

about the Package class here: java.lang.Package

Superclass

From the Class object you can access the superclass of the class. Here is how:

Class superclass = aClass.getSuperclass();

The superclass class object is a Class object like any other, so you can continue doing class reflection on that

too.

Page 4: Java Reflection Tutorial.pdf

Implemented Interfaces

It is possible to get a list of the interfaces implemented by a given class. Here is how:

Class aClass = ... //obtain Class object. See prev. section

Class[] interfaces = aClass.getInterfaces();

A class can implement many interfaces. Therefore an array of Class is returned. Interfaces are also represented

by Class objects in Java Reflection.

NOTE: Only the interfaces specifically declared implemented by a given class is returned. If a superclass of the

class implements an interface, but the class doesn't specifically state that it also implements that interface, that

interface will not be returned in the array. Even if the class in practice implements that interface, because the

superclass does.

To get a complete list of the interfaces implemented by a given class you will have to consult both the class and

its superclasses recursively.

Constructors

You can access the constructors of a class like this:

Constructor[] constructors = aClass.getConstructors();

Constructors are covered in more detail in the text on Constructors.

Methods

You can access the methods of a class like this:

Method[] method = aClass.getMethods();

Methods are covered in more detail in the text on Methods.

Fields

You can access the fields (member variables) of a class like this:

Field[] method = aClass.getFields();

Fields are covered in more detail in the text on Fields.

Annotations

You can access the class annotations of a class like this:

Annotation[] annotations = aClass.getAnnotations();

Annotations are covered in more detail in the text on Annotations.

Page 5: Java Reflection Tutorial.pdf

Java Reflection – Constructors

Using Java Reflection you can inspect the constructors of classes and instantiate objects at runtime. This is done

via the Java class java.lang.reflect.Constructor. This text will get into more detail about the Java

Construcor object. Here is a list of the topics covered:

1. Obtaining Constructor Objects 2. Constructor Parameters 3. Instantiating Objects using Constructor Object

Obtaining Constructor Objects

The Constructor class is obtained from the Class object. Here is an example:

Class aClass = ...//obtain class object

Constructor[] constructors = aClass.getConstructors();

The Constructor[] array will have one Constructor instance for each public constructor declared in the

class.

If you know the precise parameter types of the constructor you want to access, you can do so rather than obtain

the array all constructors. This example returns the public constructor of the given class which takes a String

as parameter:

Class aClass = ...//obtain class object

Constructor constructor =

aClass.getConstructor(new Class[]{String.class});

If no constructor matches the given constructor arguments, in this case String.class, a

NoSuchMethodException is thrown.

Constructor Parameters

You can read what parameters a given constructor takes like this:

Constructor constructor = ... // obtain constructor - see above

Class[] parameterTypes = constructor.getParameterTypes();

Instantiating Objects using Constructor Object

You can instantiate an object like this:

//get constructor that takes a String as argument

Constructor constructor = MyObject.class.getConstructor(String.class);

MyObject myObject = (MyObject)

constructor.newInstance("constructor-arg1");

The Constructor.newInstance() method takes an optional amount of parameters, but you must supply

exactly one parameter per argument in the constructor you are invoking. In this case it was a constructor taking

a String, so one String must be supplied.

Page 6: Java Reflection Tutorial.pdf

Java Reflection - Fields

Using Java Reflection you can inspect the fields (member variables) of classes and get / set them at runtime.

This is done via the Java class java.lang.reflect.Field. This text will get into more detail about the Java

Field object. Remember to check the JavaDoc from Sun out too. Here is a list of the topics covered:

1. Obtaining Field Objects 2. Field Name 3. Field Type 4. Getting and Setting Field Values

Obtaining Field Objects

The Field class is obtained from the Class object. Here is an example:

Class aClass = ...//obtain class object

Field[] methods = aClass.getFields();

The Field[] array will have one Field instance for each public field declared in the class.

If you know the name of the field you want to access, you can access it like this:

Class aClass = MyObject.class

Field field = aClass.getField("someField");

The example above will return the Field instance corresponding to the field someField as declared in the

MyObject below:

public class MyObject{

public String someField = null;

}

If no field exists with the name given as parameter to the getField() method, a NoSuchFieldException is

thrown.

Field Name

Once you have obtained a Field instance, you can get its field name using the Field.getName() method, like

this:

Field field = ... //obtain field object

String fieldName = field.getName();

Field Type

You can determine the field type (String, int etc.) of a field using the Field.getType() method:

Field field = aClass.getField("someField");

Object fieldType = field.getType();

Page 7: Java Reflection Tutorial.pdf

Getting and Setting Field Values

Once you have obtained a Field reference you can get and set its values using the Field.get() and

Field.set()methods, like this:

Class aClass = MyObject.class

Field field = aClass.getField("someField");

MyObject objectInstance = new MyObject();

Object value = field.get(objectInstance);

field.set(objetInstance, value);

The objectInstance parameter passed to the get and set method should be an instance of the class that owns

the field. In the above example an instance of MyObject is used, because the someField is an instance member

of the MyObject class.

It the field is a static field (public static ...) pass null as parameter to the get and set methods, instead of the

objectInstance parameter passed above.

Page 8: Java Reflection Tutorial.pdf

Java Reflection – Methods

Using Java Reflection you can inspect the methods of classes and invoke them at runtime. This is done via the

Java class java.lang.reflect.Method. This text will get into more detail about the Java Method object. Here

is a list of the topics covered:

1. Obtaining Method Objects 2. Method Parameters and Return Types 3. Instantiating Objects using Constructor Object

Obtaining Method Objects

The Method class is obtained from the Class object. Here is an example:

Class aClass = ...//obtain class object

Method[] methods = aClass.getMethods();

The Method[] array will have one Method instance for each public method declared in the class.

If you know the precise parameter types of the method you want to access, you can do so rather than obtain the

array all methods. This example returns the public method named "doSomething", in the given class which

takes a String as parameter:

Class aClass = ...//obtain class object

Method method =

aClass.getMethod("doSomething", new Class[]{String.class});

If no method matches the given method name and arguments, in this case String.class, a

NoSuchMethodException is thrown.

If the method you are trying to access takes no parameters, pass null as the parameter type array, like this:

Class aClass = ...//obtain class object

Method method =

aClass.getMethod("doSomething", null);

Method Parameters and Return Types

You can read what parameters a given method takes like this:

Method method = ... // obtain method - see above

Class[] parameterTypes = method.getParameterTypes();

You can access the return type of a method like this:

Method method = ... // obtain method - see above

Class returnType = method.getReturnType();

Page 9: Java Reflection Tutorial.pdf

Invoking Methods using Method Object

You can invoke a method like this:

//get method that takes a String as argument

Method method = MyObject.class.getMethod("doSomething", String.class);

Object returnValue = method.invoke(null, "parameter-value1");

The null parameter is the object you want to invoke the method on. If the method is static you supply null

instead of an object instance. In this example, if doSomething(String.class) is not static, you need to supply

a valid MyObject instance instead of null;

The Method.invoke(Object target, Object ... parameters) method takes an optional amount of

parameters, but you must supply exactly one parameter per argument in the method you are invoking. In this

case it was a method taking a String, so one String must be supplied.

Page 10: Java Reflection Tutorial.pdf

Java Reflection - Getters and Setters

Using Java Reflection you can inspect the methods of classes and invoke them at runtime. This can be used to

detect what getters and setters a given class has. You cannot ask for getters and setters explicitly, so you will

have to scan through all the methods of a class and check if each method is a getter or setter.

First let's establish the rules that characterizes getters and setters:

Getter A getter method have its name start with "get", take 0 parameters, and returns a value.

Setter A setter method have its name start with "set", and takes 1 parameter.

Setters may or may not return a value. Some setters return void, some the value set, others the object the setter

were called on for use in method chaining. Therefore you should make no assumptions about the return type of

a setter.

Here is a code example that finds getter and setters of a class: public static void printGettersSetters(Class aClass){

Method[] methods = aClass.getMethods();

for(Method method : methods){

if(isGetter(method)) System.out.println("getter: " + method);

if(isSetter(method)) System.out.println("setter: " + method);

}

}

public static boolean isGetter(Method method){

if(!method.getName().startsWith("get")) return false;

if(method.getParameterTypes().length != 0) return false;

if(void.class.equals(method.getReturnType()) return false;

return true;

}

public static boolean isSetter(Method method){

if(!method.getName().startsWith("set")) return false;

if(method.getParameterTypes().length != 1) return false;

return true;

}

Page 11: Java Reflection Tutorial.pdf

Java Reflection - Private Fields and Methods

Despite the common belief it is actually possible to access private fields and methods of other classes via Java

Reflection. It is not even that difficult. This can be very handy during unit testing. This text will show you how.

Note: This only works when running the code as a standalone Java application, like you do with unit tests and

regular applications. If you try to do this inside a Java Applet, you will need to fiddle around with the

SecurityManager. But, since that is not something you need to do very often, it is left out of this text so far.

Here is a list of the topics covered in this text:

1. Accessing Private Fields 2. Accessing Private Methods

Accessing Private Fields

To access a private field you will need to call the Class.getDeclaredField(String name) or

Class.getDeclaredFields() method. The methods Class.getField(String name) and

Class.getFields() methods only return public fields, so they won't work. Here is a simple example of a class

with a private field, and below that the code to access that field via Java Reflection:

public class PrivateObject {

private String privateString = null;

public PrivateObject(String privateString) {

this.privateString = privateString;

}

}

PrivateObject privateObject = new PrivateObject("The Private Value");

Field privateStringField = PrivateObject.class.

getDeclaredField("privateString");

privateStringField.setAccessible(true);

String fieldValue = (String) privateStringField.get(privateObject);

System.out.println("fieldValue = " + fieldValue);

This code example will print out the text "fieldValue = The Private Value", which is the value of the private

field privateString of the PrivateObject instance created at the beginning of the code sample.

Notice the use of the method PrivateObject.class.getDeclaredField("privateString"). It is this

method call that returns the private field. This method only returns fields declared in that particular class, not

fields declared in any superclasses.

Notice the line in bold too. By calling Field.setAcessible(true) you turn off the access checks for this

particular Field instance, for reflection only. Now you can access it even if it is private, protected or package

scope, even if the caller is not part of those scopes. You still can't access the field using normal code. The

compiler won't allow it.

Page 12: Java Reflection Tutorial.pdf

Accessing Private Methods

To access a private method you will need to call the Class.getDeclaredMethod(String name, Class[]

parameterTypes) or Class.getDeclaredMethods() method. The methods Class.getMethod(String

name, Class[] parameterTypes) and Class.getMethods() methods only return public methods, so they

won't work. Here is a simple example of a class with a private method, and below that the code to access that

method via Java Reflection:

public class PrivateObject {

private String privateString = null;

public PrivateObject(String privateString) {

this.privateString = privateString;

}

private String getPrivateString(){

return this.privateString;

}

}

PrivateObject privateObject = new PrivateObject("The Private Value");

Method privateStringMethod = PrivateObject.class.

getDeclaredMethod("getPrivateString", null);

privateStringMethod.setAccessible(true);

String returnValue = (String)

privateStringMethod.invoke(privateObject, null);

System.out.println("returnValue = " + returnValue);

This code example will print out the text "returnValue = The Private Value", which is the value returned by the

method getPrivateString() when invoked on the PrivateObject instance created at the beginning of the

code sample.

Notice the use of the method PrivateObject.class.getDeclaredMethod("privateString"). It is this

method call that returns the private method. This method only returns methods declared in that particular class,

not methods declared in any superclasses.

Notice the line in bold too. By calling Method.setAcessible(true) you turn off the access checks for this

particular Method instance, for reflection only. Now you can access it even if it is private, protected or package

scope, even if the caller is not part of those scopes. You still can't access the method using normal code. The

compiler won't allow it.

Page 13: Java Reflection Tutorial.pdf

Java Reflection – Annotations

Using Java Reflection you can access the annotations attached to Java classes at runtime. Here is a list of the

topics covered in this text:

What are Java Annotations? Class Annotations Method Annotations Parameter Annotations Field Annotations

What are Java Annotations? Annotations is a new feature from Java 5. Annotations are a kind of comment or meta data you can insert in

your Java code. These annotations can then be processed at compile time by pre-compiler tools, or at runtime

via Java Reflection. Here is an example of class annotation:

@MyAnnotation(name="someName", value = "Hello World")

public class TheClass {

}

The class TheClass has the annotation @MyAnnotation written ontop. Annotations are defined like interfaces.

Here is the MyAnnotation definition:

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.TYPE)

public @interface MyAnnotation {

public String name();

public String value();

}

The @ in front of the interface marks it as an annotation. Once you have defined the annotation you can use it

in your code, as shown in the earlier examples.

The two directives in the annotation definition, @Retention(RetentionPolicy.RUNTIME) and

@Target(ElementType.TYPE), specifies how the annotation is to be used.

@Retention(RetentionPolicy.RUNTIME) means that the annotation can be accessed via reflection at runtime.

If you do not set this directive, the annotation will not be preserved at runtime, and thus not available via

reflection.

@Target(ElementType.TYPE) means that the annotation can only be used ontop of types (classes and

interfaces typically). You can also specify METHOD or FIELD, or you can leave the target out alltogether so the

annotation can be used for both classes, methods and fields.

Java annotations are explained in more detail in my Java Annotations tutorial.

Class Annotations You can access the annotations of a class, method or field at runtime. Here is an example that accesses the class

annotations:

Class aClass = TheClass.class; Annotation[] annotations = aClass.getAnnotations();

Page 14: Java Reflection Tutorial.pdf

for(Annotation annotation : annotations){ if(annotation instanceof MyAnnotation){ MyAnnotation myAnnotation = (MyAnnotation) annotation; System.out.println("name: " + myAnnotation.name()); System.out.println("value: " + myAnnotation.value()); } }

You can also access a specific class annotation like this:

Class aClass = TheClass.class;

Annotation annotation = aClass.getAnnotation(MyAnnotation.class);

if(annotation instanceof MyAnnotation){

MyAnnotation myAnnotation = (MyAnnotation) annotation;

System.out.println("name: " + myAnnotation.name());

System.out.println("value: " + myAnnotation.value());

}

Method Annotations Here is an example of a method with annotations:

public class TheClass {

@MyAnnotation(name="someName", value = "Hello World")

public void doSomething(){}

}

You can access method annotations like this:

Method method = ... //obtain method object

Annotation[] annotations = method.getDeclaredAnnotations();

for(Annotation annotation : annotations){

if(annotation instanceof MyAnnotation){

MyAnnotation myAnnotation = (MyAnnotation) annotation;

System.out.println("name: " + myAnnotation.name());

System.out.println("value: " + myAnnotation.value());

}

}

You can also access a specific method annotation like this:

Method method = ... // obtain method object

Annotation annotation = method.getAnnotation(MyAnnotation.class);

if(annotation instanceof MyAnnotation){

MyAnnotation myAnnotation = (MyAnnotation) annotation;

System.out.println("name: " + myAnnotation.name());

System.out.println("value: " + myAnnotation.value());

}

Parameter Annotations

It is possible to add annotations to method parameter declarations too. Here is how that looks:

public class TheClass {

public static void doSomethingElse(

Page 15: Java Reflection Tutorial.pdf

@MyAnnotation(name="aName", value="aValue") String parameter){

}

}

You can access parameter annotations from the Method object like this:

Method method = ... //obtain method object

Annotation[][] parameterAnnotations = method.getParameterAnnotations();

Class[] parameterTypes = method.getParameterTypes();

int i=0;

for(Annotation[] annotations : parameterAnnotations){

Class parameterType = parameterTypes[i++];

for(Annotation annotation : annotations){

if(annotation instanceof MyAnnotation){

MyAnnotation myAnnotation = (MyAnnotation) annotation;

System.out.println("param: " + parameterType.getName());

System.out.println("name : " + myAnnotation.name());

System.out.println("value: " + myAnnotation.value());

}

}

}

Notice how the Method.getParameterAnnotations() method returns a two-dimensional Annotation array,

containing an array of annotations for each method parameter.

Field Annotations Here is an example of a field with annotations:

public class TheClass {

@MyAnnotation(name="someName", value = "Hello World")

public String myField = null;

}

You can access field annotations like this:

Field field = ... //obtain field object

Annotation[] annotations = field.getDeclaredAnnotations();

for(Annotation annotation : annotations){

if(annotation instanceof MyAnnotation){

MyAnnotation myAnnotation = (MyAnnotation) annotation;

System.out.println("name: " + myAnnotation.name());

System.out.println("value: " + myAnnotation.value());

}

}

You can also access a specific field annotation like this:

Field field = ... // obtain method object

Annotation annotation = field.getAnnotation(MyAnnotation.class);

if(annotation instanceof MyAnnotation){

MyAnnotation myAnnotation = (MyAnnotation) annotation;

System.out.println("name: " + myAnnotation.name());

System.out.println("value: " + myAnnotation.value());

}

Page 16: Java Reflection Tutorial.pdf

Java Reflection – Generics

I have often read in articles and forums that all Java Generics information is erased at compile time so that you

cannot access any of that information at runtime. This is not entirely true though. It is possible to access

generics information at runtime in a handful of cases. These cases actually cover several of our needs for Java

Generics information. This text explains these cases.

Here is a list of the topics covered in this text:

1. The Generics Reflection Rule of Thumb 2. Generic Method Return Type 3. Generic Method Parameter Types 4. Generic Field Types

The Generics Reflection Rule of Thumb

Using Java Generics typically falls into one of two different situations:

1. Declaring a class/interface as being parameterizable. 2. Using a parameterizable class.

When you write a class or interface you can specify that it should be paramerizable. This is the case with the

java.util.List interface. Rather than create a list of Object you can parameterize java.util.List to create

a list of say String.

When runtime inspecting a parameterizable type itself, like java.util.List, there is no way of knowing what

type is has been parameterized to. This makes sense since the type can be parameterized to all kinds of types in

the same application. But, when you inspect the method or field that declares the use of a parameterized type,

you can see at runtime what type the paramerizable type was parameterized to. In short:

You cannot see on a type itself what type it is parameterized to a runtime, but you can see it in fields and

methods where it is used and parameterized. Its concrete parameterizations in other words.

The following sections take a closer look at these situations.

Generic Method Return Types

If you have obtained a java.lang.reflect.Method object it is possible to obtain information about its generic

return type. This cannot be any of the Method objects in the parameterized type, but in the class that uses the

parameterized type. You can read how to obtain Method objects in the text "Java Generics: Methods". Here is

an example class with a method having a parameterized return type:

public class MyClass {

protected List<String> stringList = ...;

public List<String> getStringList(){

return this.stringList;

}

}

Page 17: Java Reflection Tutorial.pdf

In this class it is possible to obtain the generic return type of the getStringList() method. In other words, it is

possible to detect that getStringList() returns a List<String> and not just a List. Here is how:

Method method = MyClass.class.getMethod("getStringList", null);

Type returnType = method.getGenericReturnType();

if(returnType instanceof ParameterizedType){

ParameterizedType type = (ParameterizedType) returnType;

Type[] typeArguments = type.getActualTypeArguments();

for(Type typeArgument : typeArguments){

Class typeArgClass = (Class) typeArgument;

System.out.println("typeArgClass = " + typeArgClass);

}

}

This piece of code will print out the text "typeArgClass = java.lang.String". The Type[] array typeArguments

array will contain one item - a Class instance representing the class java.lang.String. Class implements the

Type interface.

Generic Method Parameter Types

You can also access the generic types of parameter types at runtime via Java Reflection. Here is an example

class with a method taking a parameterized List as parameter:

public class MyClass {

protected List<String> stringList = ...;

public void setStringList(List<String> list){

this.stringList = list;

}

}

You can access the generic parameter types of the method parameters like this:

method = Myclass.class.getMethod("setStringList", List.class);

Type[] genericParameterTypes = method.getGenericParameterTypes();

for(Type genericParameterType : genericParameterTypes){

if(genericParameterType instanceof ParameterizedType){

ParameterizedType aType = (ParameterizedType) genericParameterType;

Type[] parameterArgTypes = aType.getActualTypeArguments();

for(Type parameterArgType : parameterArgTypes){

Class parameterArgClass = (Class) parameterArgType;

System.out.println("parameterArgClass = " + parameterArgClass);

}

}

}

This code will print out the text "parameterArgType = java.lang.String". The Type[] array

parameterArgTypes array will contain one item - a Class instance representing the class java.lang.String.

Class implements the Type interface.

Page 18: Java Reflection Tutorial.pdf

Generic Field Types

It is also possible to access the generic types of public fields. Fields are class member variables - either static or

instance variables. You can read about obtaining Field objects in the text "Java Generics: Fields". Here is the

example from earlier, with an instance field called stringList.

public class MyClass {

public List<String> stringList = ...;

}

Field field = MyClass.class.getField("stringList");

Type genericFieldType = field.getGenericType();

if(genericFieldType instanceof ParameterizedType){

ParameterizedType aType = (ParameterizedType) genericFieldType;

Type[] fieldArgTypes = aType.getActualTypeArguments();

for(Type fieldArgType : fieldArgTypes){

Class fieldArgClass = (Class) fieldArgType;

System.out.println("fieldArgClass = " + fieldArgClass);

}

}

This code will print out the text "fieldArgClass = java.lang.String". The Type[] array fieldArgTypes array

will contain one item - a Class instance representing the class java.lang.String. Class implements the Type

interface.

Page 19: Java Reflection Tutorial.pdf

Java Reflection – Arrays

Working with arrays in Java Reflection can be a bit tricky at times. Especially if you need to obtain the Class

object for a certain type of array, like int[] etc. This text will discuss how to both create arrays and get their

class objects via Java Reflection.

Note: This text has been updated after reading Eyal Lupu's blog post

"Two Side Notes About Arrays and Reflection" which commented on the first edition of this text. The current

edition takes his comments into consideration.

Here is a list of the topics covered:

1. java.lang.reflect.Array 2. Creating Arrays 3. Accessing Arrays 4. Obtaining the Class Object of an Array 5. Obtaining the Component Type of an Array

java.lang.reflect.Array

Working with arrays via Java Reflection is done using the java.lang.reflect.Array class. Do not confuse

this class with the java.util.Arrays class in the Java Collections suite, which contains utility methods for

sorting arrays, converting them to collections etc.

Creating Arrays Creating arrays via Java Reflection is done using the java.lang.reflect.Array class. Here is an example showing

how to create an array:

int[] intArray = (int[]) Array.newInstance(int.class, 3);

This code sample creates an array of int. The first parameter int.class given to the Array.newInstance() method

tells what type each element in the array should be of. The second parameter states how many elements the

array should have space for.

Accessing Arrays It is also possible to access the elements of an array using Java Reflection. This is done via the Array.get(...) and

Array.set(...) methods. Here is an example: int[] intArray = (int[]) Array.newInstance(int.class, 3);

Array.set(intArray, 0, 123);

Array.set(intArray, 1, 456);

Array.set(intArray, 2, 789);

System.out.println("intArray[0] = " + Array.get(intArray, 0));

System.out.println("intArray[1] = " + Array.get(intArray, 1));

System.out.println("intArray[2] = " + Array.get(intArray, 2));

This code sample will print out this:

intArray[0] = 123

intArray[1] = 456

intArray[2] = 789

Page 20: Java Reflection Tutorial.pdf

Obtaining the Class Object of an Array

One of the problems I ran into when implementing the script language in Butterfly DI Container was how to

obtain the Class object for arrays via Java Reflection. Using non-reflection code you can do like this:

Class stringArrayClass = String[].class;

Doing this using Class.forName() is not quite straightforward. For instance, you can access the primitive int

array class object like this:

Class intArray = Class.forName("[I");

The JVM represents an int via the letter I. The [ on the left means it is the class of an int array I am interested

in. This works for all other primitives too.

For objects you need to use a slightly different notation:

Class stringArrayClass = Class.forName("[Ljava.lang.String;");

Notice the [L to the left of the class name, and the ; to the right. This means an array of objects with the given

type.

As a side note, you cannot obtain the class object of primitives using Class.forName(). Both of the examples

below result in a ClassNotFoundException:

Class intClass1 = Class.forName("I");

Class intClass2 = Class.forName("int");

I usually do something like this to obtain the class name for primitives as well as objects:

public Class getClass(String className){

if("int" .equals(className)) return int .class;

if("long".equals(className)) return long.class;

...

return Class.forName(className);

}

Once you have obtained the Class object of a type there is a simple way to obtain the Class of an array of that

type. The solution, or workaround as you might call it, is to create an empty array of the desired type and obtain

the class object from that empty array. It's a bit of a cheat, but it works. Here is how that looks:

Class theClass = getClass(theClassName);

Class stringArrayClass = Array.newInstance(theClass, 0).getClass();

This presents a single, uniform method to access the array class of arrays of any type. No fiddling with class

names etc.

To make sure that the Class object really is an array, you can call the Class.isArray() method to check:

Class stringArrayClass = Array.newInstance(String.class, 0).getClass();

System.out.println("is array: " + stringArrayClass.isArray());

Page 21: Java Reflection Tutorial.pdf

Obtaining the Component Type of an Array

Once you have obtained the Class object for an array you can access its component type via the

Class.getComponentType() method. The component type is the type of the items in the array. For instance,

the component type of an int[] array is the int.class Class object. The component type of a String[] array

is the java.lang.String Class object.

Here is an example of accessing the component type array:

String[] strings = new String[3];

Class stringArrayClass = strings.getClass();

Class stringArrayComponentType = stringArrayClass.getComponentType();

System.out.println(stringArrayComponentType);

This example will print out the text "java.lang.String" which is the component type of the String array.

Page 22: Java Reflection Tutorial.pdf

Java Reflection - Dynamic Proxies

Using Java Reflection you create dynamic implementations of interfaces at runtime. You do so using the class

java.lang.reflect.Proxy. The name of this class is why I refer to these dynamic interface implementations

as dynamic proxies. Dynamic proxies can be used for many different purposes, e.g. database connection and

transaction management, dynamic mock objects for unit testing, and other AOP-like method intercepting

purposes.

Here is a list of topics covered in this text on dynamic proxies:

1. Creating Proxies 2. InvocationHandler's 3. Known Use Cases

Creating Proxies

You create dynamic proxies using the Proxy.newProxyInstance() method. The newProxyInstance()

methods takes 3 parameters:

1. The ClassLoader that is to "load" the dynamic proxy class. 2. An array of interfaces to implement. 3. An InvocationHandler to forward all methods calls on the proxy to.

Here is an example:

InvocationHandler handler = new MyInvocationHandler();

MyInterface proxy = (MyInterface) Proxy.newProxyInstance(

MyInterface.class.getClassLoader(),

new Class[] { MyInterface.class },

handler);

After running this code the proxy variable contains a dynamic implementation of the MyInterface interface. All

calls to the proxy will be forwarded to the handler implementation of the general InvocationHandler interface.

InvocationHandler's are covered i the next section.

InvocationHandler's

As mentioned earlier you must pass an InvocationHandler implementation to the

Proxy.newProxyInstance() method. All method calls to the dynamic proxy are forwarded to this

InvocationHandler implementation. Here is how the InvocationHandler interface looks:

public interface InvocationHandler{

Object invoke(Object proxy, Method method, Object[] args)

throws Throwable;

}

Here is an example implementation:

public class MyInvocationHandler implements InvocationHandler{

public Object invoke(Object proxy, Method method, Object[] args)

throws Throwable {

//do something "dynamic"

}

}

Page 23: Java Reflection Tutorial.pdf

The proxy parameter passed to the invoke() method is the dynamic proxy object implementing the interface.

Most often you don't need this object.

The Method object passed into the invoke() method represents the method called on the interface the dynamic

proxy implements. From the Method object you can obtain the method name, parameter types, return type, etc.

See the text on Methods for more information.

The Object[] args array contains the parameter values passed to the proxy when the method in the interface

implemented was called. Note: Primitives (int, long etc) in the implemented interface are wrapped in their

object counterparts (Integer, Long etc.).

Known Use Cases

Dynamic proxies are known to be used for at least the following purposes:

Database Connection and Transaction Management Dynamic Mock Objects for Unit Testing Adaptation of DI Container to Custom Factory Interfaces AOP-like Method Interception

Database Connection and Transaction Management

The Spring framework has a transaction proxy that can start and commit / rollback a transaction for you. How

this works is described in more detail in the text Advanced Connection and Transaction Demarcation and

Propagation , so I'll only describe it briefly. The call sequence becomes something along this:

web controller --> proxy.execute(...);

proxy --> connection.setAutoCommit(false);

proxy --> realAction.execute();

realAction does database work

proxy --> connection.commit();

Dynamic Mock Objects for Unit Testing

The Butterfly Testing Tools makes use of dynamic proxies to implement dynamic stubs, mocks and proxies for

unit testing. When testing a class A that uses another class B (interface really), you can pass a mock

implementation of B into A instead of a real B. All method calls on B are now recorded, and you can set what

return values the mock B is to return.

Furthermore Butterfly Testing Tools allow you to wrap a real B in a mock B, so that all method calls on the

mock are recorded, and then forwarded to the real B. This makes it possible to check what methods were called

on a real functioning B. For instance, if testing a DAO you can wrap the database connection in a mock. The

DAO will not see the difference, and the DAO can read/write data to the database as usual since the mock

forwards all calls to the database. But now you can check via the mock if the DAO uses the connection

properly, for instance if the connection.close() is called (or NOT called), if you expected that. This is

normally not possible to determine from the return value of a DAO.

Page 24: Java Reflection Tutorial.pdf

Adaptation of DI Container to Custom Factory Interfaces

The dependency injection container Butterfly Container has a powerful feature that allows you to inject the

whole container into beans produced by it. But, since you don't want a dependency on the container interface,

the container is capable of adapting itself to a custom factory interface of your design. You only need the

interface. No implementation. Thus the factory interface and your class could look something like this:

public interface IMyFactory {

Bean bean1();

Person person();

...

}

public class MyAction{

protected IMyFactory myFactory= null;

public MyAction(IMyFactory factory){

this.myFactory = factory;

}

public void execute(){

Bean bean = this.myFactory.bean();

Person person = this.myFactory.person();

}

}

When the MyAction class calls methods on the IMyFactory instance injected into its constructor by the

container, the method calls are translated into calls to the IContainer.instance() method, which is the

method you use to obtain instances from the container. That way an object can use Butterfly Container as a

factory at runtime, rather than only to have dependencies injected into itself at creation time. And this without

having any dependencies on any Butterfly Container specific interfaces.

AOP-like Method Interception

The Spring framework makes it possible to intercept method calls to a given bean, provided that bean

implements some interface. The spring framework wraps the bean in a dynamic proxy. All calls to the bean are

then intercepted by the proxy. The proxy can decide to call other methods on other objects either before, instead

of, or after delegating the method call to the bean wrapped.

Page 25: Java Reflection Tutorial.pdf

Java Reflection - Dynamic Class Loading and Reloading

It is possible to load and reload classes at runtime in Java, though it is not as straightforward as one might have

hoped. This text will explain when and how you can load and reload classes in Java.

You can argue whether Java's dynamic class loading features are really part of Java Reflection, or a part of the

core Java platform. Anyways, the article has been put in the Java Reflection trail in lack of a better place to put

it.

Here is a list of the topics covered in this text:

1. The ClassLoader 2. The ClassLoader Hierarchy 3. Class Loading 4. Dynamic Class Loading 5. Dynamic Class Reloading 6. Designing your Code for Class Reloading 7. ClassLoader Load / Reload Example

The ClassLoader

All classes in a Java application are loaded using some subclass of java.lang.ClassLoader. Loading classes

dynamically must therefore also be done using a java.lang.ClassLoader subclass.

When a class is loaded, all classes it references are loaded too. This class loading pattern happens recursively,

until all classes needed are loaded. This may not be all classes in the application. Unreferenced classes are not

loaded until the time they are referenced.

The ClassLoader Hierarchy

Class loaders in Java are organized into a hierarchy. When you create a new standard Java ClassLoader you

must provide it with a parent ClassLoader. If a ClassLoader is asked to load a class, it will ask its parent class

loader to load it. If the parent class loader can't find the class, the child class loader then tries to load it itself.

Class Loading

The steps a given class loader uses when loading classes are:

1. Check if the class was already loaded. 2. If not loaded, ask parent class loader to load the class. 3. If parent class loader cannot load class, attempt to load it in this class loader.

When you implement a class loader that is capable of reloading classes you will need to deviate a bit from this

sequence. The classes to reload should not be requested loaded by the parent class loader. More on that later.

Page 26: Java Reflection Tutorial.pdf

Dynamic Class Loading

Loading a class dynamically is easy. All you need to do is to obtain a ClassLoader and call its loadClass()

method. Here is an example:

public class MainClass {

public static void main(String[] args){

ClassLoader classLoader = MainClass.class.getClassLoader();

try {

Class aClass = classLoader.loadClass("com.jenkov.MyClass");

System.out.println("aClass.getName() = " + aClass.getName());

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

}

Dynamic Class Reloading

Dynamic class reloading is a bit more challenging. Java's builtin Class loaders always checks if a class is

already loaded before loading it. Reloading the class is therefore not possible using Java's builtin class loaders.

To reload a class you will have to implement your own ClassLoader subclass.

Even with a custom subclass of ClassLoader you have a challenge. Every loaded class needs to be linked. This

is done using the ClassLoader.resolve() method. This method is final, and thus cannot be overridden in your

ClassLoader subclass. The resolve() method will not allow any given ClassLoader instance to link the same

class twice. Therefore, everytime you want to reload a class you must use a new instance of your ClassLoader

subclass. This is not impossible, but necessary to know when designing for class reloading.

Designing your Code for Class Reloading

As stated earlier you cannot reload a class using a ClassLoader that has already loaded that class once.

Therefore you will have to reload the class using a different ClassLoader instance. But this poses som new

challenges.

Every class loaded in a Java application is identified by its fully qualified name (package name + class name),

and the ClassLoader instance that loaded it. That means, that a class MyObject loaded by class loader A, is not

the same class as the MyObject class loaded with class loader B. Look at this code:

MyObject object = (MyObject)

myClassReloadingFactory.newInstance("com.jenkov.MyObject");

Notice how the MyObject class is referenced in the code, as the type of the object variable. This causes the

MyObject class to be loaded by the same class loader that loaded the class this code is residing in.

If the myClassReloadingFactory object factory reloads the MyObject class using a different class loader than

the class the above code resides in, you cannot cast the instance of the reloaded MyObject class to the MyObject

type of the object variable. Since the two MyObject classes were loaded with different class loaders, the are

regarded as different classes, even if they have the same fully qualified class name. Trying to cast an object of

the one class to a reference of the other will result in a ClassCastException.

Page 27: Java Reflection Tutorial.pdf

It is possible to work around this limitation but you will have to change your code in either of two ways:

1. Use an interface as the variable type, and just reload the implementing class. 2. Use a superclass as the variable type, and just reload a subclass.

Here are two coresponding code examples:

MyObjectInterface object = (MyObjectInterface)

myClassReloadingFactory.newInstance("com.jenkov.MyObject");

MyObjectSuperclass object = (MyObjectSuperclass)

myClassReloadingFactory.newInstance("com.jenkov.MyObject");

Either of these two methods will work if the type of the variable, the interface or superclass, is not reloaded

when the implementing class or subclass is reloaded.

To make this work you will of course need to implement your class loader to let the interface or superclass be

loaded by its parent. When your class loader is asked to load the MyObject class, it will also be asked to load

the MyObjectInterface class, or the MyObjectSuperclass class, since these are referenced from within the

MyObject class. Your class loader must delegate the loading of those classes to the same class loader that

loaded the class containing the interface or superclass typed variables.

ClassLoader Load / Reload Example

The text above has contained a lot of talk. Let's look at a simple example. Below is an example of a simple

ClassLoader subclass. Notice how it delegates class loading to its parent except for the one class it is intended

to be able to reload. If the loading of this class is delegated to the parent class loader, it cannot be reloaded later.

Remember, a class can only be loaded once by the same ClassLoader instance.

As said earlier, this is just an example that serves to show you the basics of a ClassLoader's behaviour. It is not

a production ready template for your own class loaders. Your own class loaders should probably not be limited

to a single class, but a collection of classes that you know you will need to reload. In addition, you should

probably not hardcode the class paths either.

public class MyClassLoader extends ClassLoader{

public MyClassLoader(ClassLoader parent) {

super(parent);

}

public Class loadClass(String name) throws ClassNotFoundException {

if(!"reflection.MyObject".equals(name))

return super.loadClass(name);

try {

String url = "file:C:/data/projects/tutorials/web/WEB-INF/" +

"classes/reflection/MyObject.class";

URL myUrl = new URL(url);

URLConnection connection = myUrl.openConnection();

InputStream input = connection.getInputStream();

ByteArrayOutputStream buffer = new ByteArrayOutputStream();

int data = input.read();

while(data != -1){

buffer.write(data);

data = input.read();

}

Page 28: Java Reflection Tutorial.pdf

input.close();

byte[] classData = buffer.toByteArray();

return defineClass("reflection.MyObject",

classData, 0, classData.length);

} catch (MalformedURLException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

return null;

}

}

Below is an example use of the MyClassLoader.

public static void main(String[] args) throws

ClassNotFoundException,

IllegalAccessException,

InstantiationException {

ClassLoader parentClassLoader = MyClassLoader.class.getClassLoader();

MyClassLoader classLoader = new MyClassLoader(parentClassLoader);

Class myObjectClass = classLoader.loadClass("reflection.MyObject");

AnInterface2 object1 =

(AnInterface2) myObjectClass.newInstance();

MyObjectSuperClass object2 =

(MyObjectSuperClass) myObjectClass.newInstance();

//create new class loader so classes can be reloaded.

classLoader = new MyClassLoader(parentClassLoader);

myObjectClass = classLoader.loadClass("reflection.MyObject");

object1 = (AnInterface2) myObjectClass.newInstance();

object2 = (MyObjectSuperClass) myObjectClass.newInstance();

}

Here is the reflection.MyObject class that is loaded using the class loader. Notice how it both extends a

superclass and implements an interface. This is just for the sake of the example. In your own code you would

only have to one of the two - extend or implement.

public class MyObject extends MyObjectSuperClass implements AnInterface2{

//... body of class ... override superclass methods

// or implement interface methods

}

Page 29: Java Reflection Tutorial.pdf