ReflectionBlerta HaxhijahaI. IntroductionReflection is a dynamic languagefeature which allows programs to inspect objects at runtime, thus determine thecharacteristics and capabilities they poses.
Reflection provides informationabout the class that the object belongs to, the class’ constructors, methodsand fields, interfaces that the class implements and any superclass available.Reflection then gives the possibility to act upon the retrieved information,namely to create instances of the class types discovered, to invoke theretrieved methods, and even to set fields that were discovered to belong to theexamined object’s class. Via reflection, it is also possible to access fieldsand methods that are declared private. Java comes with its own reflection API,which enables programmers to make use of the capabilities mentioned above.One ofthe most common uses of reflection is in the development of programming tools –it is what enables the integrated development environments such as BlueJ, to list us the methods availablein a class the moment that we type the class name. Schema generation is alsosomething that benefits from reflection, i.e., it is possible to generate theschema for any type by inspecting every field or property of that type withreflection.
Again thanks to reflection, JUnitis able to dynamically invoke all methods of a class under test whose namesstart with the literal “test”.However,the powerful features of reflection come with certain implications. Firstly,there is some performance overhead associated with reflection. This performanceoverhead results from the need to dynamically resolve types when usingreflection, which implies that the Java virtual machine is unable to performcertain optimizations. Consequently, it is advised that reflection be avoidedwhenever possible in performance-sensitive programs. Secondly, code usingreflection breaks abstractions, due to the possibility of accessing privatefields and invoking private methods. This can result in unexpected andunpredictable side-effects, eventually rendering the code dysfunctional.
II. RelatedWorkThere has been an extensive amountof both research papers and published books, which explore the idea,application and power related to reflection, as well as its limitations andperformance overhead. I have made a selection of a few research papers thathave examined reflection from different perspectives, and will provide a shortsummary of each below.
In their paper Reflection in logic, functional andobject-oriented programming: a Short ComparativeStudy 1, F.N. Demers and J.Malenfantargue that even though reflection as a concept has been around for quite sometime, its exploration in the different programming paradigms – logic,functional and object oriented programming– has been quite isolated, withlittle interaction between the experts of these sub-domains. The authors arguethat this has contributed to a reduced cross-fertilization of advances madewithin each paradigm. They hence provide a historic perspective of thedevelopment of reflection in each paradigm, specifying the similarities anddifferences when compared to the other two, in an attempt to encourage a closercollaboration between the actors of the separate sub-domains.
In Code Reuse Through Reflection: An EmpiricalPerspective 2, authors Y. Hassoun, R. Johnson, S. Counsell have exploredthe potential of reflection in enabling the much desired possibility of codereuse.
They stipulate that it is possible to decompose object-oriented systemsinto two parts: an application part, and a reusable part. Their work focuses onhow to identify the reusable part, and refactor it using reflection techniques.This refactored part is then re-integrated in the initial system.
The authorsuse well-established metrics that measure the degree of reusability, proposedby Y. Chen more than 2 decades ago, in order to measure the increase inreusability after introducing reflection in the system. However, the describedprocess is a rather costly undertake, which requires heavy resources in orderto transform the object-oriented systems in the manner proposed.Anotherpaper, titled Reflection Support: JavaReflection Made Easy 3, by authors Z. Shams and S. H. Edwards, tries tosolve the issue of the programming overhead involved when using reflection incode development. They recognize the power associated with reflection and thepossibilities it brings, but are concerned with the end result of a code thatis difficult to read, bulky to write and not very intuitive to maintain.
Theauthors have used a representative class of programs in order to measure theincrease in code size that is a direct result of using reflection (sincereflection requires numerous try-catch blocks of checked exceptions, explicitcasts, and multiple lines of code for basic actions). They have found that thecode size increases by a factor of three when using Java’s reflection API, incomparison to the non-reflective Java code counterpart. In order to overcomethis issue, they propose the usage of another library, called ReflectionSupport, which is a simplifiedAPI that also enables reflection. This library uses similar method names as thenative Java reflection API, but it internally takes care of exception handling,explicit casts and some other declarations required in reflection. The resultof using the ReflectionSupport libraryis code reduced in size, less error-prone and easier to maintain.The nextpaper, Challenges for Static Analysis ofJava Reflection – Literature Review and Empirical Study 4, by authors D.
Landman, A. Serebrenik and J. J. Vinju, discusses reflection from anotherinteresting perspective – the difficulties it causes to static code analyzers.Developers are used to exploiting the benefits of static code analyzers as partof their integrated development environments, which are apt at discovering bugsand issuing warnings, detecting repetitive code, validating code syntax andsuggesting appropriate refactoring. However, dynamic language features such asreflection, pose significant challenges even to state-of-the-are static codeanalyzers, due to their unpredictability.
The paper explores the advances thatare made in recent years, in the efforts to make static code analyzers morereflection-aware. For the needs of this paper, the authors have examined a poolof 461 Java open-source projects, and have found that no less than 78% of themuse some form of reflection as a dynamic language feature.The lastpaper, Exploiting Reflection in ObjectOriented Genetic Programming 5, by author S.M.
Lucas, explores theprospects of using reflection in genetic programming. Genetic programming is apromising technique in the artificial intelligence domain, which seeks toautomatically solve a problem by starting with a large base of simple computerprograms, and evolve them into a sophisticated computer program that solves thehigh-level task. It tries to do this by using methods analogous to the naturallyoccurring genetic processes, such as the genetic crossover (recombination)process, in order to produce a resulting computer program, which contains thebest traits from the computer programs of the entry pool.
The author arguesthat object oriented genetic programming is an under-explored area, yieldingonly 32 pages of Google search results, as opposed to 75,900 result pages whensearching for the “Genetic Programming” term. He then proceeds toexplaining that, for the needs of genetic programming, it is relativelystraightforward to generate random computer programs as a sequence of methodinvocations on a set of objects, with the help of reflection. However, he warnsagainst the fact that using reflection to make method invocations is slower thanmaking a direct method call.III. TheJava Reflection APIThe Java platform enablesreflection through the java.lang.reflect package,which has been available since JDK1.
1 edition. The 6 classes found in thispackage (Array, Constructor, Field,Package, Method, Proxy) along with the two classes from java.lang (Class and ClassLoader), provide a solid foundation for exploiting thepossibilities that come with reflection. The API contains several other classestoo, and a total set of 181 public methods.
Figure (1) gives a preview of themost important classes from the Java reflection API.The Class class from the Java Reflection API provides a wealth ofinformation related to a given object’s class. From the interfaces itimplements, to the superclass it inherits from; all the methods, constructorsand fields of the class, as well as the ones belonging to the superclass andinterfaces; can be retrieved from the java.lang.Class.The information that this class provides, as well as the methods used to obtaineach piece of information, are shown in Figure (2).Reflectionenables dynamic operations with objects as well, through object instantiations,method invocations, as well as direct field modifications.
In order toinstantiate new objects, dedicated methods from the reflection API are used,depending on the intention to invoke the default class constructor, or someother custom constructor with parameters.When itcomes to method calls, it is enough to supply the name of the method as astring literal, and the method can subsequently be invoked. Care needs to betaken, however, to supply the necessary entry parameters of the method to beinvoked as well, if that method has any. This is required in order to avoidconfusion in cases when several overloads of the same method are present in theclass.
The object fields can be modified as well, via special getter and settermethods of the API. It is possible even to ignore the security restriction ofnon-public methods and fields,viaspecial directives of the API which set these members as accessible.Next, we move to showing all thereflection possibilities via two example Java projects. The first project willdemonstrate the power of reflection to dynamically retrieve information about agiven object’s class. The second project will show how reflection can be usedto dynamically manipulate and change the state of objects.
Figure (3) shows the code for classCar, which contains three privatefields of different types, a default constructor and one constructor with aninteger entry parameter, three instance methods, and one static method.The Main class in figure (4) is used toinspect the features of the Car classvia reflection. It does so by primarily retrieving the class of the givenobject, via the getClass() directive.Afterobtaining the object’s class in a Class reference,it proceeds with inspecting the class’ methods, with the getDeclaredMethods() directive.
This method returns all the publicand non-public methods of the class under inspection. It is also possible toretrieve the public methods of the direct and indirect superclasses of theclass as well, via method getMethods().Next, the parameter counts of the retrieved methods are inspected with getParameterCount(). Further in thecode, the interfaces that the class implements, and the superclass it inheritsfrom, are retrieved, with methods getInterfaces()and getSuperclass(),respectively.
The class constructors are then inspected with getDeclaredConstructors(), which returnsan array of Constructor objects. The array is iteratedin order to get the constructorparameter types and count (getType() andgetParameterCount()). The main methodfinishes by retrieving the class fields (getDeclaredFields())which are returned as an array of Fieldobjects.
Finally, a specific field is retrieved by providing its name as astring literal in method getDeclaredField(“fieldName”).Next, we proceed with the secondexample, which demonstrates how reflection can enable the manipulation ofobjects. For this purpose, we use class RentCar,which contains several private fields, two constructors, a static method and acollection of private and public instance methods, as shown in Figure (5). Theclass used to work with objects of this class via reflection is shown in Figure(6). Note that, just like in the previous example, the java.
lang.reflect.* package is imported, because this is where theJava Reflection API is found.The mainmethod begins by retrieving the class of the object we want to work with.
Asshown in the previous example, this is done by using the getClass() directive. The retrieved class is then places in a Class reference. Next, we instantiate anew instance of the retrieved class, by using the newInstance() method. This method creates the object by using thedefault (or parameterless) constructor. Note that if a parameterlessconstructor does not exist in the class, the method will generate an exception.
It is also possible to create an object of the class by using any oftheconstructors available, as shown in the following section of the code, whereall the class’ constructors are first retrieved, and then the secondconstructor is used to create a new object (ctors1.newInstance(parameterValue)).In case the input parameters are incorrect for the constructor in use, an IllegalArgumentException is thrown.Next,we show how methods are invoked. We saw in the previous example that reflectionenables us to retrieve the methods of the given class. Now we use the nameliteral of anyofthe retrieved methods in order to retrieve the Method object corresponding to that method (getDeclaredMethod(“methodName”)). Then we use the directive invoke(objectName, methodParams) uponthe method object, by providing as input parameters the class object upon whichwe wanttocall the method, as well as any input parameters of the method to be invoked.We show that private methods can also be invoked, by first setting theiraccessibility to true (setAccessible()).
Static methods are called in a similar fashion, with null as the value for the object-to-be-called-uponparameter. Finally, we show that the class fields can be modified directlywith the set() method of the Field class.IV. ConclusionReflection is a powerful mechanismin the programming world, and the Java programming language comes with its ownpotent reflection API.
Reflection enables the retrieval of information on typesand methods we use at runtime. This is especially useful on cases when atcompile time, we do not have information on these types and methods, and weneed to resolve them dynamically. Reflection also enables us to act upon theretrieved information, namely to instantiate new objects of the retrievedtypes, and to invoke the retrieved methods.In thispaper, the possibilities that come with reflection were explored, its uses inreal-world applications, as well as the limitations associated with it.
Asection looking at some related research work on reflection was also provided,along with a summary of several papers which looked at reflection from verydifferent perspectives.Finally,it is crucial to point out that reflection is a rather advanced feature, andthat it should be used sparingly. Even the Oracle Java documentation 7advises that reflection should be used only by developers who have a solidunderstanding of the language, and only in cases when using direct method callsand object instantiation is simply not possible. Having said that, reflectionremains to be categorized as a powerful technique that enables developers toprovide solutions to tasks, which would otherwise be impossible to complete.