Advertisment

Breaching Java rules with reflection

author-image
CIOL Bureau
Updated On
New Update

Kunal Jaggi

Advertisment

Have you ever wondered how your favorite IDE manages auto-completion of method and field names? Even better, how does an object relational (OR) mapping framework like Hibernate support default fields while persisting entity classes? If all these questions sound geek, you must give the Reflection API a spin. Much of the sizzle that has been caused by Java is because of power added by the Reflection API to change the runtime behavior of an application that's running inside a Java Virtual Machine (JVM). In this article, we'll look at the runtime magic that Reflection provides to Hibernate O/R mapping framework and then we'll use the Java Reflection API to break one of the fundamental rules of the Java programming language--we'll access a method marked with the private access modifier from the client code.

Hibernate mapping

To begin with, we'll look at Hibernate OR mapping framework. As an illustration, consider the following mapping file which declares the persistent properties of an entity class:

Direct Hit!

Advertisment

Applies To: Advanced Java SE and Java EE developers

USP: Use Reflection to access a method marked with private access modifier

Primary Link: http://java.sun.com/docs/ books/tutorial/reflect/index.html

Google Keywords: Java Reflection API

On PCQ Xtreme DVD: \system\Labs\ Reflection

Advertisment

Advertisment

...
Advertisment

How does Hibernate get to know the Java type of the name and address properties? How does Hibernate instantiate the Patient Plain Old Java Objects (POJO) entity class? What's the significance of the default-access=field element? All this and much more are possible through Reflection. Hibernate can access the fields (including private) directly. Hibernate will try to determine the correct conversion and mapping type itself without specifying the type attribute in the mapping. Further, Hibernate recommends that the access of the default 'no argument' constructor should be at least package level, as Hibernate needs to instantiate the class through Reflection.

Advertisment

 

Jargon watch

  •  Hibernate – A framework for mapping an object-oriented domain model to a traditional relational database. Its purpose is to relieve the developer from a significant amount of relational data persistence-related programming tasks.
  •  Plain Old Java Object (POJO) – A Java object without any runtime dependencies other than Java Standard Edition (SE) classes. The name is used to emphasize that the object in question is an ordinary Java object and not a special object.
  •  Reflection – An API that enables you to discover information about fields, methods and constructors of loaded Java classes and even modify this information.
Advertisment

Accessing private method using Reflection

According to Java Language Specification (JLS), 'A private class member or constructor is accessible only within the body of the top level class that encloses the declaration of the member or constructor.' This is a well known Java rule that once a method or a field is declared with the private modifier, it can't be accessed by any other class. But with Reflection, breaking this fundamental rule is simple. Reflection provides a convenient handle to all fields and methods irrespective of their accessibility.

We'll design a simple Java stack of patients as a part of our MedTracker application to provide a LIFO implementation. Apart from the conventional push() and pop() methods we'll provide an overloaded version of pop() method which accepts an integer argument. The integral value specifies the number of elements to be popped from the stack. As an illustration, consider the following code listing which presents the patient stack:

private Patient<> pop(int elementCount) {

System.out.println("Inside private method pop(int)");

if (elementCount < 0)

throw new IndexOutOfBoundsException();

Patient newPatients<>=new Patient;

for(int i=0;i

return newPatients;

}

This code fragment is pretty straight forward. Inside the pop(int elementCount) method, we've put a simple check for the elementCount argument; for any negative value passed to this method, we propagate an IndexOutOfBoundsException (an unchecked exception). For any positive value, we populate a local array of Patient objects and return the same. Next, we'll call the private pop(int elementCount) method from a standalone Java client through Reflection.

Java Reflection API lets you hook on to private objects and tweak their behavior at run time. The pop() method appears to remove the given range of items from the stack

 

Putting Reflection in action

It's time to hit the ground running! We'll write a simple standalone Java client which will use the reflection API to call the private pop(int elementCount) method on the stack class. The following code fragment presents the Stackmain.java class:

package com.pcquest.medtracker.client;

import com.pcquest.medtracker.model.Patient;

import com.pcquest.medtracker.model.Stack;

import java.lang.reflect.*;

public class Stackmain {

public static void main(String<> args)throws Exception {

Stack s=new Stack(10);

s.push(new Patient("Samuel","Hoffman"));

s.push(new Patient("Richard","Ryan"));

s.push(new Patient("Steve","Beytel"));

System.out.println("The original list is: " + s);

Class klass = s.getClass();

Class<> paramTypes = { Integer.TYPE };

Method m = klass.getDeclaredMethod("pop", paramTypes);

Object<> arguments = { new Integer(2) };

m.setAccessible(true);

m.invoke(s, arguments);

System.out.println("The new list is: "

+ s);

}

}

In the Stackmain class we begin by instantiating the stack initially with 10 elements. Next, we get a Class object. The arguments to any method that is invoked through reflection is passed as an array of Class object. The getDeclaredMethod returns all methods declared by one class. In the above code fragment, we get the private pop(int elementCount) method handler. Then we call the setAccessible() method, passing 'true' to make it available to the caller program. Finally, the invoke() method invokes the underlying method represented by the Method object, on the specified object with specified parameters. The following screenshot depicts the output.

Conclusion

Reflection is a powerful tool in the hands of a developer with which she can modify the runtime behavior of applications running in the Java virtual machine. That said; reflection should only be used by experienced developers. According to the Sun Java Tutorial, “Reflection is powerful, but should not be used indiscriminately”. Reflection comes at a cost--non-reflective programs are more responsive. A security manager can prevent reflexive behavior at runtime. As a thumb rule, Reflection should only be used by experienced developers as indiscriminate usage could change semantics of a running application and introduce side effects.

tech-news