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

(reflect) Class getConstructor(Class[]) doesn't work with abstract cls or intf

XMLWordPrintable

    • Icon: Enhancement Enhancement
    • Resolution: Duplicate
    • Icon: P4 P4
    • None
    • 1.3.0
    • core-libs



      Name: boT120536 Date: 01/02/2001


      java version "1.3.0"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0)
      Java HotSpot(TM) Client VM (build 1.3.0, mixed mode)


      The lookup table used by Class's getConstructor(Class[] paramClasses) doesn't
      find the constructor if any of the paramClasses are concrete implementations of
      interfaces in the constructor.

      Here's two classes that demonstrate the problem. Get the output by running "java
      Invoker"

      --------------

      import java.io.Serializable;

      import java.lang.reflect.Constructor;
      import java.lang.reflect.InvocationTargetException;

      public class Invoker
      {
          public Invoker()
          {}

          private static void printArray(Object[] array)
          {
              System.out.print("[ ");
              for(int i=0;i<array.length;i++)
                  {
                      System.out.print(array[i].toString()+" ");
                  }
              System.out.println(" ]");
          }

          public static Victem works()
              throws
      NoSuchMethodException,InstantiationException,IllegalAccessException,InvocationTargetException
          {
              System.out.println("Inside works");

              Class concrete = Victem.class;
              Serializable id = new Long(0);
              Object[] params = new Object[1];
              
              params[params.length-1] = id;
              System.out.println("params are "+params);
              printArray(params);

              //get the classes of the parameters
              Class[] paramClasses = new Class[params.length];
              for(int i=0;i<params.length;i++)
                  {
                      paramClasses[i] = params[i].getClass();
                  }

              //I added this line to make the method work
              paramClasses[paramClasses.length-1]=Serializable.class;

              System.out.println("paramClasses are "+paramClasses);
              printArray(paramClasses);

              //Get the right constructor
              Constructor constructor = concrete.getConstructor(paramClasses);
              
              //create a new instance of the concrete class
              Victem result = (Victem)constructor.newInstance(params);
              
              System.out.println("-------------");
              //return the concrete class
              return result;
          }

          public static Victem broken()
              throws
      NoSuchMethodException,InstantiationException,IllegalAccessException,InvocationTargetException
          {
              System.out.println("Inside broken");

              Class concrete = Victem.class;
              Serializable id = new Long(0);
              Object[] params = new Object[1];
              
              params[params.length-1] = id;
              System.out.println("params are "+params);
              printArray(params);

              //get the classes of the parameters
              Class[] paramClasses = new Class[params.length];
              for(int i=0;i<params.length;i++)
                  {
                      paramClasses[i] = params[i].getClass();
                  }

              System.out.println("paramClasses are "+paramClasses);
              printArray(paramClasses);

              //Get the right constructor
              Constructor constructor = concrete.getConstructor(paramClasses);
              
              //create a new instance of the concrete class
              Victem result = (Victem)constructor.newInstance(params);
              
              //return the concrete class
              return result;
          }

          public static void main(String args[])
          {
              try
                  {
                      works();
                      broken();
                  }
              catch(Exception ex)
                  {
                      ex.printStackTrace();
                  }
          }
      }
      --------------------------

      import java.io.Serializable;

      public class Victem
      {
          private Serializable id;

          public Victem(Serializable identifier)
          {
              id = identifier;
          }
      }
      ------------------------
      System.out gets
      Inside works
      params are [Ljava.lang.Object;@310d42
      [ 0 ]
      paramClasses are [Ljava.lang.Class;@5d87b2
      [ interface java.io.Serializable ]
      -------------
      Inside broken
      params are [Ljava.lang.Object;@20c10f
      [ 0 ]
      paramClasses are [Ljava.lang.Class;@62eec8
      [ class java.lang.Long ]
      java.lang.NoSuchMethodException
              at java.lang.Class.getConstructor0(Native Method)
              at java.lang.Class.getConstructor(Class.java:927)
              at Invoker.broken(Invoker.java:82)
              at Invoker.main(Invoker.java:96)

      -----------------------------------------

      I realize that the bug involves an ambiguous case: if a paramClass implements
      two different interfaces and the class to be constructed has two constructors,
      each of which takes one interface as a parameter, then the getConstructor()
      method won't be able to figure out which constructor to choose. However, this
      problem is not unique to the getConstructor() method. The javac compiler won't
      compile a class if it detects this problem. You could change the
      getConstructor() (and the getDeclaredMethod() method) to throw either a runtime
      exception or a subclass of NoSuchMethodException. An
      AmbiguousMethodMatchException could include a list of possible matching methods.

      Try and compile this code to see what javac does:
      ------------------

      import java.io.Serializable;

      public class Ambiguous
      {
          private Serializable id;

          public Ambiguous(Serializable identifier)
          {
              id = identifier;
          }

          public Ambiguous(Comparable compit)
          {

          }

          public static void main(String args[])
          {
              try
                  {
                      new Ambiguous(new Long(2));
                  }
              catch(Exception ex)
                  {
                      ex.printStackTrace();
                  }
          }
      }
      (Review ID: 114421)
      ======================================================================

            iris Iris Clark
            bonealsunw Bret O'neal (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: