Java Reflection, Introspection and Customization – Simplified

Java Reflection

Java Reflection

Overview: In this document we will talk about reflection, introspection and customization in Java beans. These are the important aspects of Java programming language using which we achieve the dynamism at runtime.







Introduction:
Reflection and introspection are two important features of Java programming. These have been included in the JDK 1.1 to allow the developers to dynamically generate and re-use the code. These features allow an object to discover its own information and about other objects at runtime. Reflection allows the developer to create objects which can:

  • Construct new instances of classes and their arrays.
  • Access the fields of objects or classes and modify them if required.
  • Invoke methods on objects or classes.
  • Access the elements of the arrays and modify them if required.

One can argue that all of the above facilities are available in any object oriented programming language. However in java with the help of reflection we can achieve these without knowing the name of the class or object on which these actions would be performed at compile time the state and behavior of the class or object is determined at runtime. The following picture shows the role of reflection in Java programming:

Java Reflection

Java Reflection

Figure 1: Reflection in Java programming 

Introspection in java is used in the context of Java beans which defines the component model of java. Introspection feature enables a java bean to get the properties, methods and events of other beans at runtime. This helps the developers to design and develop their beans without knowing the details of other beans.

Introspection and reflection are interrelated. Reflection is low level feature which allows our code to check the internals of other classes or objects at runtime. Introspection is based on this feature and provides a more convenient interface to check the beans at runtime. In fact introspection feature uses the low level reflection to check the objects internal attributes.

The Reflection API:
Java 1.1 introduced the reflection framework. Reflection is commonly used in programs which require checking or updating the runtime behavior of the application running in the Java virtual machine. This is a relatively an advanced feature and should be used with utmost care. With this fact in mind, we can say that reflection is a powerful technique and enable applications to perform operations which would otherwise be impossible. Let us look into the following code base which shows the usage of reflection:

Listing 1: A Sample class implementing reflection

[Code]

package com.home.reflect;

import java.lang.reflect.Array;

import java.lang.reflect.Field;

import com.home.VO.EMPVO;

public class DemoReflect {

public static String dump(Object obj, int callCount) {

callCount++;

StringBuffer tabs = new StringBuffer();

for (int k = 0; k < callCount; k++) {

tabs.append(“\t”);

}

StringBuffer buffer = new StringBuffer();

Class clazz = obj.getClass();

if (clazz.isArray()) {

buffer.append(“\n”);

buffer.append(tabs.toString());

buffer.append(“[“);

for (int i = 0; i < Array.getLength(obj); i++) {

if (i < 0)

buffer.append(“,”);

Object value = Array.get(obj, i);

if (value.getClass().isPrimitive() ||

value.getClass() == java.lang.Long.class ||

value.getClass() == java.lang.String.class ||

value.getClass() == java.lang.Integer.class ||

value.getClass() == java.lang.Boolean.class

) {

buffer.append(value);

} else {

buffer.append(dump(value, callCount));

}

}

buffer.append(tabs.toString());

buffer.append(“]\n”);

} else {

buffer.append(“\n”);

buffer.append(tabs.toString());

buffer.append(“{\n”);

while (clazz != null) {

Field[] fields = clazz.getDeclaredFields();

for (int i = 0; i < fields.length; i++) {

buffer.append(tabs.toString());

fields[i].setAccessible(true);

buffer.append(fields[i].getName());

buffer.append(“=”);

try {

Object objVal = fields[i].get(obj);

if (objVal != null) {

if (objVal.getClass().isPrimitive() ||

objVal.getClass() == java.lang.Long.class ||

objVal.getClass() == java.lang.String.class ||

objVal.getClass() == java.lang.Integer.class ||

objVal.getClass() == java.lang.Boolean.class

) {

buffer.append(objVal);

} else {

buffer.append(dump(objVal, callCount));

}

}

} catch (IllegalAccessException e) {

buffer.append(e.getMessage());

}

buffer.append(“\n”);

}

clazz = clazz.getSuperclass();

}

buffer.append(tabs.toString());

buffer.append(“}\n”);

}

return buffer.toString();

}

public static void main(String[] args) {

EMPVO emp = new EMPVO();

emp.setEmpNo(1);

emp.setEmpName(“John”);

System.out.println(DemoReflect.dump(emp, 5));

}

}

[/Code]

Listing 2: The EMP VO class

[Code]

package com.home.VO;

public class EMPVO {

private int empNo;

private String empName;

/**

* @return the empNo

*/

public int getEmpNo() {

return empNo;

}

/**

* @param empNo the empNo to set

*/

public void setEmpNo(int empNo) {

this.empNo = empNo;

}

/**

* @return the empName

*/

public String getEmpName() {

return empName;

}

/**

* @param empName the empName to set

*/

public void setEmpName(String empName) {

this.empName = empName;

}

}

[/Code]

The reflection API consists of the following classes from the java.lang and java.lang.reflect package:

  • Class
  • Array
  • Constructor
  • Field
  • Member
  • Method
  • Modifier








Limitations of Reflection:
Reflection is powerful and should be used with utmost care. It should be used only in the situation when there is no other option left as it has the following limitations:

  • Performance overhead: Since reflection uses the types which are dynamically resolved, some of the JVM optimizations are not performed. As a consequence, reflective operations are slower than the not reflective ones.
  • Security restrictions: Reflection requires a runtime permission which may not be available while running within a security manager. E.g. an applet which runs under a restricted security context.
  • Exposure of internals: Since reflection allows the code to perform operations which would illegal for a non reflective code e.g. accessing the private fields and methods, use of reflection may result in some unwanted side effects.

The Introspection API:
Introspection is an automatic process in which the bean’s design patterns are analyzed to extract the bean’s properties, events, and methods. Introspection has some great advantages as under:

  • Re-usability.

The introspection API consists of the following classes from the java. Bean package:

  • BeanDescriptor
  • BeanInfo
  • FeatureDescriptor
  • EventSetDescriptor
  • MethodDescriptor
  • PropertyDescriptor
  • IndexedPropertyDescriptor
  • Introspector
  • SimpleBeanInfo

Both reflection and introspection are important aspects of Java programming and should be used only when absolutely necessary. The following code snippet shows a combination of reflection and introspection:

Listing 3: Sample code showing introspection

[Code]

package com.home.reflect;

import java.lang.reflect.Method;

public class DemoIntroSpect {

public static void main(String[] args) {

try {

Class clazz = Class.forName(“com.home.VO.EMPVO”);

Method [] methods = clazz.getMethods();

for (Method method : methods) {

System.out.println(“Method Name = ” +method.getName());

}

} catch (ClassNotFoundException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

[/Code]

Customization:
Customization provides the feature to visually modify the java beans properties as per the requirement of the situation. Once the beans are designed so that reflection and introspection can happen, we should test our code to check whether these features actually happen or not. E.g. let us consider a clock bean. The user should have the power to customize it to digital or analog based on some property. Some visual builders e.g. the netbeans IDE use property sheets in order to customize the beans.








Summary:

Reflection, introspection and customization all three are dependent on each other. To conclude this topic let us summarize what we discussed above in the following bullets as under:

  • Reflection was introduced in Java 1.1.
  • Reflection allows the developer to create objects at runtime which can :
    • Construct new instances of classes and their arrays.
    • Access the fields of objects or classes and modify them if required.
    • Invoke methods on objects or classes.
    • Access the elements of the arrays and modify them if required.
  • Reflection and Introspection has got some drawbacks as under :
    • Using these features degrades the performance of the program.
    • The code becomes more open as the internals are exposed.
    • Errors in method invocation are discovered at run time. In normal exercise these are caught by the compiler at compile time.
    • The code becomes more complicated and it becomes difficult to maintain it.
============================================= ============================================== Buy best TechAlpine Books on Amazon
============================================== ---------------------------------------------------------------- electrician ct chestnutelectric
error

Enjoy this blog? Please spread the word :)

Follow by Email
LinkedIn
LinkedIn
Share