-
Enhancement
-
Resolution: Duplicate
-
P4
-
None
-
1.3.0
-
generic
-
generic
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)
======================================================================
- duplicates
-
JDK-4287725 (reflect) Allow subclasses of stated argument types in Class.getMethod()
-
- Open
-
- relates to
-
JDK-4651775 (reflect spec) Class.get(Declared)+{Method,Constructor} does not define "match"
-
- Open
-