CSC/ECE 517 Fall 2010/ch3 1c AE: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
Line 213: Line 213:


===Method Invocation===
===Method Invocation===
===Reflective Package in Java===
===Java===
With the Java reflection API, we can interrogate an object to get all sorts of information about its class.Lets see the technique how Java helps to invoke a method defined in a class at runtime using reflection API.
With the Java reflection API, we can interrogate an object to get all sorts of information about its class.Lets see the technique how Java helps to invoke a method defined in a class at runtime using reflection API.



Revision as of 00:33, 7 October 2010

Reflective Language Features vs. Reflective Packages

Definition

Reflection is the integral quality of a program to dynamically manipulate its own state. More specifically, the program can infer and modify itself by making use of the representation of its own state. The state of a program can be its implementation aspects like syntax, semantics, structure, etc. The program acts through its self-accessible state and takes itself as its domain to be acted upon. Programming languages that possess this quality are said to be reflective.

Most object-oriented languages support some form of reflection. Smalltalk, Ruby, and Python in particular have very powerful and flexible reflection mechanisms. Java also supports reflection, but not in as flexible and dynamic fashion as the others. C++ does not support reflection as we've defined it here, but it does supported a limited form of run-time type information that allows a program to determine the type of an object at run-time. Eiffel also has support for a limited form of reflection, although it is much improved in the most recent versions of Eiffel, including the ability to determine the features contained in an object.

Consider a simple example of Reflection in Java below :

public class HelloWorld {
  public void printName() {
     System.out.println(this.getClass().getName());
  }
}

The line

(new HelloWorld()).printName();

sends the string 'HelloWorld' to the standard output. Let obj be an object of HelloWorld or one of its subclasses. When the program reaches the line,

obj.printName();

it sends the name of the class to the standard output.

This simple example denotes an effective feature. The printName method looks at the object obj for its class (this.getClass()). It decides what to print by delegating to the object's class in runtime.(i.e.,) the printName method behaves differently for each subclass of HelloWorld. The method is so flexible that it dynamically adapts itself to the class or subclass that inherits it.

Reflection being an effective language feature enables metaprogramming. A reflective system would possess the feature of allowing programmers to design, create make use of the objects to act dynamically based on an existing part of the running system. Thus, reflection can also be defined as a feature where a programming language behaves like its own metalanguage. It contains metadata and associated operations to manipulate it in runtime.

Another important concept that is closely associated with reflection is reification. Reification is the process of packaging the information about the environment suitable so that it can be manipulated(by reflection).

Lets look into the pros and cons of reflection and then the languages that sport and support reflection.

Pros and cons of reflection

  • Simplicity: Generated code is generally more readable and debuggable for developers.
  • Maintenance: With passive code generation, changing the objects to be loaded may require the loading class to be updated or regenerated. If the classes are regenerated, then customizations may be lost.
  • Compile time errors: Reflexive procedures fail more often at runtime than during compilation. For instance, changing the object to be loaded will probably cause the generated loading class to throw a compilation error, but the reflexive procedure won't see any difference until the class is encountered during runtime.
  • Reflection involves dynamic resolving , certain Java virtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications.
  • Compile time errors: Reflexive procedures fail more often at runtime than during compilation. For instance, changing the object to be loaded will probably cause the generated loading class to throw a compilation error, but the reflexive procedure won't see any difference until the class is encountered during runtime.
  • Reflection requires a runtime permission which may not be present when running under a security manager. This is in an important consideration for code which has to run in a restricted security context, such as in an Applet.
Exposure of Internals.
  • Without it, our solutions are messy, cumbersome, and fragile. Consider the following scenarios:
  • Since reflection allows code to perform operations that would be illegal in non-reflective code, such as accessing private fields and methods, the use of reflection can result in unexpected side-effects, which may render code dysfunctional and may destroy portability. Reflective code breaks abstractions and therefore may change behavior with upgrades of the platform.
  • More flexible
  • Performance Overhead & Security Restrictions

Reflective mechanisms

It is a feature that is made available in a language that facilitatates either reification or reflection or both.

Categorizing Reflection

There two primary criteria to categorize reflective systems. These criteria are when reflection happens and what is reflected. Considering what is being reflected, the categories of reflective systems are :

  • Introspection: This is the ability of the program to identify the type of an object and its methods. Here, the structure is identified and accessed but not modified.
  • Intercession: This is another important feature of reflection. It is the ability for dynamic implementation of code. This can take many forms, including object creation and method calling at runtime. Again, in an inherently reflective language, these calls are made directly on the object.

Examples depicting the above categories are dealt in detail, later in the chapter. The above two categories are the general types of reflection. Lets look at other categories of reflection in a different perspective.

  • Structural Reflection: It is a quality of a program to access and modify its own structure. For example, the classes and their members constitute the structure in an object oriented language. This strucural reflection allows the possibility of accessing and modifying them.
  • Computational (Behavioral) Reflection: As the name suggests, it is the quality of the program to dynamically access and modify the runtime behavioral of the program. For example, in object oriented languages, method calls, state of the execution stack of the threads, etc can be accessed and modified.

We are concentrating on the introspection and intercession aspects of reflection in this chapter.

Reflective languages

Defining reflective language more precisely, a language is said to be a reflective language if it could understand reflection and possess features or tools to handle reflection explicitly. An important requirement for a reflective language is, it must have the necessary features to let access some of its features by itself (like being self-recursive). Languages like Smalltalk, Ruby, Python, LISP, CLOS, etc. are reflective.

Languages that are not reflective could support reflection through reflective packages. For example, languages like Java support reflection through the Java.lang.reflect package.

Reflective Language Features vs. Reflective Packages

Lets look how the general type of reflection, that is introspection and intercession is represented in reflective languages and in languages supporting reflective packages.

Introspective Feature

Class Based Reflection

Java

Java is so well crafted and its reflection API so carefully constrained that security is controlled simply. By learning when to use reflection and when not to, we will avoid unnecessarily complex code that can often be the result of amateurish use of reflection. In addition, you will learn to evaluate the performance of your designs, thereby ensuring the resulting code satisfies its performance requirements.

This introduction describes reflection, but scarcely reveals its value in this limited space. In Java, reflection enables to discover information about the loaded classes specifically about the Fields,Methods and constructors,Generics information,Metadata annotations.The forcoming section will cover:

Basically reflection in programming is an introspect upon itself and manipulate internal properties of the program. It also creates a way to obtain properties of Java components as they are dynamically loaded. Using the concept we can have all the information related with a class i.e. its public,private methods,fields,constructors and can create new objects ,arrays and invoke methods. We shall see these methods below and for these to work Java needs reflect package. Hence Java has reflection through package features.

 Listing methods in a class (Class fundamentals)
 import java.lang.reflect.*;
 public class ClassDisplay{
       public static void main(String args[]){
            try{
                Class c=Class.forName("java.util.Stack");
                Method m[]=c.getDeclaredMethods();
                for(int i=0;i<m.length ;i++)
                    System.out.println(m[i].toString());
               }catch(Throwable e){System.err.println(e); }
       }
 }
  Output displays the return object type and parameter object type together with the method name
  public synchronized java.lang.Object java.util.Stack.pop()
  public java.lang.Object java.util.Stack.push(java.lang.Object)
  public boolean java.util.Stack.empty()
  public synchronized java.lang.Object java.util.Stack.peek()
  public synchronized int java.util.Stack.search(java.lang.Object)

Ruby

Ruby has reflective feature in built in its language. There are no extra packages needed to explore its reflective feature. Below are some code which explains about the introspective behaviour of Ruby.

 puts Fixnum.ancestors 
 The output of this is :
 Fixnum ,Integer ,Precision ,Numeric ,Comparable ,Object ,Kernel which displays all its ancestors

To know about the various methods defined in a class the following lines are used in the code

 class Demo
     private
        def privMethod
     end
     protected
        def protMethod
     end
     public
        def pubMethod
     end
    def Demo.classMethod
    end
    CONST = 1.23
 end
 puts Demo.private_instance_methods                    => give output as privMethod
 puts Demo.public_instance_methods                     => protMethod
 puts Demo.protected_instance_methods                  => pubMethod
 puts Demo.singleton_methods                           => classMethod
 puts Demo.constants                                   => CONST

Methods reflection

Java

Java's method can be accessed via the same reflection package as above. Below explains the way to access methods in Java.

   import java.lang.reflect.*;
   public class MethodDisplay{
       private int f1(Object p,int x) throws NullPointerException {
           if(p==null){
                 throw new NullPointerException();}
             return x;
       }  
        
       public static void main(String args[]){
           try{
                  Class cls= Class.forName("MethodDisplay");
                  Method meth[]= cls.getDeclaredMethods();
                  for(int i=0;i<meth.length;i++)
                     {
                         Method m=meth[i];
                         System.out.println("Method Name: "+m.getName());
                         System.out.println("Method Declared class : "+m.getDeclaringClass());
                         Class prec[]=m.getParameterTypes();
                         System.out.println("Method Exception Types : "+m.getExceptionTypes());
                         System.out.println("Method Return Type : "+ m.getReturnType());
                     }
              }catch(Throwable e){System.err.println(e);}
        }   
    }        
       
  Output for above code which displays the methods declared :
  Method Name: f1
  Method Declared class : class MethodDisplay
  Method Exception Types : [Ljava.lang.Class;@3e25a5
  Method Return Type : int
  Method Name: main
  Method Declared class : class MethodDisplay
  Method Exception Types : [Ljava.lang.Class;@19821f
  Method Return Type : void         


Similarly we can get information about the fields declared in a class with the help of methods like getField(String name),getFields(),getDeclaredField(String name),getDeclaredFields().The same technique used for Constructor infomration retrieval.

Ruby

Ruby supports liberated objects. We really cannot tell exactly what an object can do until you look under its hood.For instance, we can get a list of all the methods to which an object will respond.

   r = 1..10   // r is a range object 
   list = r.methods // this is a way to get all the methods in an array that can be invoked in the object.

We can also determine the object's class from it by using the kind_of? method.

  num = 1
  num.class     =>  Fixnum
  num.kind_of?  =>  Fixnum

Intercessive Feature

Intercessive is process of invoking dynamically on a class at run time. The previous section just talked about the ways to get information about a class. It enables to use the metaobjects to their instances in run time environment. E.g. Method.invoke(Object o, Object… args)

Method Invocation

Java

With the Java reflection API, we can interrogate an object to get all sorts of information about its class.Lets see the technique how Java helps to invoke a method defined in a class at runtime using reflection API.

 import java.lang.reflect.*;
 public class MethodInvoke{
       public int add(int a,int b){
             return a+b;
       }
       
       public static void main(String args[]){
            try{
                  Class cls= Class.forName("MethodInvoke");
                  Class partypes[]= new Class[2];
                  partypes[0]= Integer.TYPE;
                  partypes[1]=Integer.TYPE;
                  Method meth=cls.getDeclaredMethod("add",partypes);
                  MethodInvoke MI = new MethodInvoke();
                  Object arglist[]=new Object [2];
                  arglist[0]=new Integer(37);
                  arglist[1]=new Integer(47);
                  Object retobj = meth.invoke(MI, arglist);
                  Integer retval = (Integer)retobj ;
                  System.out.println("Value :"+ retval);
            }catch (Exception e){}
       }
 }

First we get the method declared and then we invoke the method by calling Method.invoke(*) . This accepts a class object where the method is declared along with the parameter list defined in an array.

Ruby

Dynamic array Manipulation

 import java.lang.reflect.*;
 public class ArrayManipulation {
     public static void main(String args[]){
   	  try{    		  
                 Class cls= Class.forName("java.lang.String");
       	  Object arr= Array.newInstance(cls, 10);
       	  Array.set(arr,5,"this is a reflection test");
       	  String s =(String)Array.get(arr,5);
       	  System.out.println("Returned String :" + s);   		  
   	     }catch (Exception e){}    	     	  
     }
 }

Arrays are declared and initiliazed dynamically with the help of Reflection. An new array instance cannot be created till we know the size of the array. But this is not the case with reflection. It helps us to dynamically create arrays. Reflection package provides with Array class which has newInstance method that allows to create arrays for a particular class and size. This is one of the major merits of reflection in Java.

Security in Reflection

Java

Security can be a complex issue when dealing with reflection.Uncontrolled access can create major security risks in other cases, such as when code is executed in an environment shared by untrusted code.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 i.e public components can be accessed anywhere, and accessing of private components is limited or allowed with permission and limited access to protected and package (default access) components can be done by the java.lang.reflect.AccessibleObject class. This class defines a setAccessible method that lets 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.

 import java.lang.reflect.*;
 class Securityclass {
   private String m_s1, m_s2;
   public Securityclass(String s1, String s2) {
       m_s1 = s1;
       m_s2 = s2;
   }
 }
 public class SecurityReflection{  
   public static void main(String[] args) {
       try {
           Securityclass ts = new Securityclass("a", "b");
           Class clas=Class.forName("Securityclass");
           Field field = clas.getDeclaredField("m_s1");
           field.setAccessible(true);
           System.out.println("Retrieved value is " + field.get(ts));
       } catch (Exception ex) {
           ex.printStackTrace(System.out);
       }
   }
 }

In the above example if the line field.setAccessible(true) is commented out then the program will not be able to access the private string in other class. By giving access permission the private member can be accessed.

Performance Issues

Eventhough Java provides Reflection package which is a powerful tool some issues need to be considered which are a few drawbacks. One of the main drawbacks is the effect on performance. Using reflection is basically an interpreted operation, where we tell the JVM what we want to do and it does it for us. This type of operation is always going to be slower than just doing the same operation directly.

References

http://www.springerlink.com/content/6l63883r9224q186/ http://www.cs.indiana.edu/~jsobel/rop.html http://publications.csail.mit.edu/lcs/pubs/pdf/MIT-LCS-TR-272.pdf http://www.di.uniovi.es/ooosws2001/papers/ortin_final.pdf http://download.oracle.com/javase/1.4.2/docs/api/java/lang/reflect/package-summary.html http://scg.unibe.ch/archive/papers/Duca06dMOOSEMODELS2006.pdf file:///C:/Users/Summer/Downloads/10.1.1.158.2012.pdf - good link .. http://www.ub.uni-konstanz.de/kops/volltexte/2002/803/pdf/DissertationEgbertAlthammer.pdf http://www.laputan.org/reflection/ooffrmla.html