Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4810162

Make reflection more convenient to use



    • Type: Enhancement
    • Status: Closed
    • Priority: P4
    • Resolution: Duplicate
    • Affects Version/s: 1.4.1
    • Fix Version/s: None
    • Component/s: specification
    • Subcomponent:
    • CPU:
    • OS:


      Name: nt126004 Date: 01/29/2003

      Java(TM) 2 Runtime Environment, Standard Edition (build
      Java HotSpot(TM) Client VM (build 1.3.1_03-69, mixed mode)

      Reflection is a powerful tool which makes Java into a far
      more dynamic language than it would be without it. It makes
      possible an entirely different style of programming, in
      which Field and Method objects are widely passed around
      between methods, serving a function analogous to that of
      pointers and function pointers in other languages.

      Unfortunately, it only makes this possible, not convenient.
       The current reflection API is far more cumbersome than it
      has any reason to be, and this has prevented it from being
      used nearly as heavily as such a powerful tool really ought
      to be.

      I therefore recommend that the reflection API be revised to
      make it far more convenient to use. This involves four
      specific recommendations. In describing the
      recommendations, the following code will be used as an example:

      public class UsefulObject
        public int aField;
        public static int staticField;
        public void greet(String name)
          System.out.println("Hello "+name);
      UsefulObject obj = new UsefulObject();

      Here are my recommendations.

      1. Create a simple syntax for obtaining and using Field and
      Method objects.

      This requires the compiler to automatically convert the new
      syntax into the equivalent method calls. The following
      pairs of lines show a line in the suggested syntax, and the
      equivalent code it would be converted to.

      Field f = UsefulObject::aField;
      Field f = UsefulObject.class.getField("aField");

      Method m = UsefulObject::greet(String);
      Method m = UsefulObject.class.getMethod("greet", new Object
      [] {String.class});

      int i = obj->f;
      int i = f.get(obj);

      obj->f = 5;
      f.setInt(obj, 5);

      m.invoke(obj, new Object [] {"Fred"});

      This would require changes to the compiler, but should not
      involve any significant changes to the JVM itself.

      2. Define classes to represent fields and methods of
      specific objects.

      Field and Method objects are generic: they are not tied to
      any particular object, and you must specify a target object
      in order to evaluate or invoke them. I suggest that new
      classes be defined which represent specific fields and
      methods of specific objects. I will refer to these classes
      as "FieldInstance" and "MethodInstance", although there are
      probably better names for them.

      The list of methods for the FieldInstance class would be
      something like this:

      public FieldInstance(Field field, Object object);
      public Object get();
      public void set(Object value);
      public Field getField();
      public Object getObject();

      The MethodInstance class would be analogous, but with an
      invoke() method in place of get() and set().

      Of course, these classes would be trivial to implement in
      pure Java. To be really convenient, however, there should
      be a simplified syntax for using them similar to the one
      described above:

      FieldInstance fi = obj::aField;
      MethodInstance mi = obj::greet(String);
      FieldInstance fi2 = UsefulObject::staticField;

      The third line is a debatable case. Static fields and
      methods do not require you to provide an object to access or
      invoke them. Semantically, it therefore makes more sense to
      represent them with FieldInstances instead of Fields. From
      a syntactic point of view, one could argue that it is less
      confusing if the :: operator always produces a Field when
      applied to a class, whether or not the field is static.

      3. Relax the access controls for reflection.

      Once you start passing around Field and Method objects
      between methods, you soon find yourself wanting to pass
      references to the methods of anonymous inner classes. When
      the receiving code tries to invoke the method, however, it
      receives an IllegalAccessException. Method.invoke() throws
      an exception if either of the following conditions is met:

      The method being invoked is not public


      The method belongs to a non-public class

      The latter condition is excessive and unnecessary.
      Presumably it was put there based on the philosophy that if
      you cannot invoke a method without reflection, you should
      not be able to invoke it with reflection either. That is a
      very poor reason: the whole point of reflection is to let
      you do things you could not do otherwise. As long as a
      method is public, any piece of code which has obtained a
      reference to it should be free to invoke it.

      A much more reasonable place to enforce class level access
      restrictions would be at Class.getMethod(). It could throw
      an exception if the invoking code did not have permission to
      access the class. Or it could be enforced by
      Class.forName() to prevent the Class object from being
      obtained in the first place. Either way, if a class which
      *does* have access to the method in question chooses to give
      the Method object to another class, that other class should
      be free to invoke it so long as the method itself is public.
       Otherwise, it is impossible to use anonymous inner classes
      as function callbacks in this way.

      4. Make reflection related exceptions be RuntimeExceptions.

      When used to its fullest potential, reflection will become
      pervasive. I therefore recommend that the following
      exceptions become subclasses of RuntimeException so they
      will not need to be explicitly thrown by nearly every method:


      This bug can be reproduced always.
      (Review ID: 180506)


          Issue Links



              abuckley Alex Buckley
              nthompsosunw Nathanael Thompson (Inactive)
              0 Vote for this issue
              0 Start watching this issue