Use reflection wisely
Reflection gives your code access to internal information for classes loaded into the JVM and allows you to write code that works with classes selected during execution, not in the source code. This makes reflection a great tool for building flexible applications. But watch out — if used inappropriately, reflection can be costly.The following article describes a fraction of the functionality which you can achieve with the use of reflection and I will describe how you can use reflection to modify and read otherwise not-accessible field-attributes of classes.
Using reflection is different from normal Java programming in that it works with metadata — data that describes other data. The particular type of metadata accessed by Java language reflection is the description of classes and objects within the JVM. Reflection gives you run-time access to a variety of class information. It even lets you read and write fields and call methods of a class selected at run time.
Reflection is a powerful tool. It lets you build flexible code that can be assembled at run time without requiring source code links between components. But some aspects of reflection can be problematic. In this article, I’ll go into the reasons why you might not want to use reflection in your programs, as well as the reasons why you would. After you know the trade-offs, you can decide for yourself when the benefits outweigh the drawbacks.
Security and reflection: Security can be a complex issue when dealing with reflection. Reflection is often used by framework-type code, and for this you may want the framework to have full access to your code without concern for normal access restrictions. Yet uncontrolled access can create major security risks in other cases, such as when code is executed in an environment shared by untrusted code.
Because of these conflicting needs, the Java programming language defines a multi-level approach to handling reflection security. The basic mode is to enforce the same restrictions on reflection as would apply for source code access:
- Access from anywhere to public components of the class
- No access outside the class itself to private components
- Limited access to protected and package (default access) components
There’s a simple way around these restrictions, though — at least sometimes. The Constructor, Field, and Method classes all extend a common base class — the java.lang.reflect.AccessibleObject class. This class defines a setAccessible method that lets you turn the access checks on or off for an instance of one of these classes. The only catch is that if a security manager is present, it will check that the code turning off access checks has permission to do so. If there’s no permission, the security manager throws an exception.
Let’s see how we can use this to access private field-attributes. The class below defines two private Strings and one public String. We will attempt to access and modify all Strings. The attempt to access or modify strStringPrivate will fail, but setting strStringWillModifyPrivate to accessible allows us to access and modify the attribute:
public class TestAccessibleClass { private String strStringPrivate = "MyPrivateString"; private String strStringWillModifyPrivate = "WillModifyString"; public String strStringPublic = "MyPublicString"; } public class TestAccessible { public static void main(String[] args) { final Field fields[] = TestAccessibleClass.class.getDeclaredFields(); for (int i = 0; i < fields.length; ++i) { TestAccessibleClass test = new TestAccessibleClass(); Field f = fields[i]; if (fields[i].getName().startsWith("strString")) { System.out.println ("The field " + f.getName() + " is " + (f.isAccessible() == true ? "accessible" : "not accessible")); if ("strStringWillModifyPrivate".equals(fields[i].getName())) { f.setAccessible(true); } try { System.out.println("Value of field=" + f.get(test)); f.set(test, "Modified Field"); System.out.println("Modified value=" + f.get(test)); } catch (IllegalAccessException iae) { System.out.println ("The field can not be modified"); } } } } }
If you compile this code and run it directly from the command line without any special parameters, it’ll throw oe IllegalAccessException when trying to access strStringPrivate. Finally, if you add the JVM parameter -Djava.security.manager on the command line to enable a security manager, it will again fail, unless you define permissions for the TestAccessible class.
The field strStringPrivate is not accessible
The field can not be modified ==>>> IllegalAccessException
The field strStringWillModifyPrivate is not accessible
Value of field=WillModifyString
Modified value=Modified Field
The field strStringPublic is not accessible
Value of field=MyPublicString
Modified value=Modified Field
As you can see from the above example, using reflection is a very powerful (but also dangerous) way of accessing attributes, which you would not be able to access or modify in any other way.
Reflection is a powerful tool, but suffers from a few drawbacks. One of the main drawbacks is the effect on performance. Using reflection is basically an interpreted operation, where you tell the JVM what you want to do and it does it for you. This type of operation is always going to be slower than just doing the same operation directly.
Java language reflection provides a very versatile way of dynamically linking program components. It allows your program to create and manipulate objects of any classes (subject to security restrictions) without the need to hardcode the target classes ahead of time. These features make reflection especially useful for creating libraries that work with objects in very general ways. For example, reflection is often used in frameworks that persist objects to databases, XML, or other external formats.
Reflection also has a couple of drawbacks. One is the performance issue. Reflection is much slower than direct code when used for field and method access. To what extent that matters depends on how reflection is used in a program. If it’s used as a relatively infrequent part of the program’s operation, the slow performance won’t be a concern. The performance issues only become a serious concern if reflection is used in the core logic of performance-critical applications.
A more serious drawback for many applications is that using reflection can obscure what’s actually going on inside your code. Programmers expect to see the logic of a program in the source code, and techniques such as reflection that bypass the source code can create maintenance problems. Reflection code is also more complex than the corresponding direct code, as can be seen in the code samples from the performance comparisons. The best ways to deal with these issues are to use reflection sparingly — only in the places where it really adds useful flexibility — and document its use within the target classes.
Recent Comments