# HG changeset patch # User Jaroslav Tulach # Date 1380362639 -7200 # Node ID 7a78a84ab5830006bc9a5d150cc71ec212dccb4b # Parent e49c4c2c3737618b35431dce5812d6977008252a Can use Constructor.newInstance with parameters diff -r e49c4c2c3737 -r 7a78a84ab583 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionTest.java --- a/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionTest.java Sat Sep 28 02:45:17 2013 +0200 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionTest.java Sat Sep 28 12:03:59 2013 +0200 @@ -19,6 +19,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collections; @@ -77,6 +78,10 @@ return Runnable.class.getDeclaredMethod("run").getName(); } + @Compare public String intValue() throws Exception { + return Integer.class.getConstructor(int.class).newInstance(10).toString(); + } + @Compare public String namesOfMethods() { StringBuilder sb = new StringBuilder(); String[] arr = new String[20]; @@ -90,6 +95,19 @@ return sb.toString(); } + @Compare public String paramsOfConstructors() { + StringBuilder sb = new StringBuilder(); + String[] arr = new String[20]; + int i = 0; + for (Constructor m : StaticUse.class.getConstructors()) { + arr[i++] = m.getName(); + } + for (String s : sort(arr, i)) { + sb.append(s).append("\n"); + } + return sb.toString(); + } + @Compare public String namesOfDeclaringClassesOfMethods() { StringBuilder sb = new StringBuilder(); String[] arr = new String[20]; diff -r e49c4c2c3737 -r 7a78a84ab583 rt/emul/mini/src/main/java/java/lang/Class.java --- a/rt/emul/mini/src/main/java/java/lang/Class.java Sat Sep 28 02:45:17 2013 +0200 +++ b/rt/emul/mini/src/main/java/java/lang/Class.java Sat Sep 28 12:03:59 2013 +0200 @@ -29,6 +29,7 @@ import org.apidesign.bck2brwsr.emul.reflect.AnnotationImpl; import java.io.InputStream; import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.TypeVariable; @@ -1106,6 +1107,188 @@ } /** + * Returns an array containing {@code Constructor} objects reflecting + * all the public constructors of the class represented by this + * {@code Class} object. An array of length 0 is returned if the + * class has no public constructors, or if the class is an array class, or + * if the class reflects a primitive type or void. + * + * Note that while this method returns an array of {@code + * Constructor} objects (that is an array of constructors from + * this class), the return type of this method is {@code + * Constructor[]} and not {@code Constructor[]} as + * might be expected. This less informative return type is + * necessary since after being returned from this method, the + * array could be modified to hold {@code Constructor} objects for + * different classes, which would violate the type guarantees of + * {@code Constructor[]}. + * + * @return the array of {@code Constructor} objects representing the + * public constructors of this class + * @exception SecurityException + * If a security manager, s, is present and any of the + * following conditions is met: + * + *
    + * + *
  • invocation of + * {@link SecurityManager#checkMemberAccess + * s.checkMemberAccess(this, Member.PUBLIC)} denies + * access to the constructors within this class + * + *
  • the caller's class loader is not the same as or an + * ancestor of the class loader for the current class and + * invocation of {@link SecurityManager#checkPackageAccess + * s.checkPackageAccess()} denies access to the package + * of this class + * + *
+ * + * @since JDK1.1 + */ + public Constructor[] getConstructors() throws SecurityException { + return MethodImpl.findConstructors(this, 0x01); + } + + /** + * Returns a {@code Constructor} object that reflects the specified + * public constructor of the class represented by this {@code Class} + * object. The {@code parameterTypes} parameter is an array of + * {@code Class} objects that identify the constructor's formal + * parameter types, in declared order. + * + * If this {@code Class} object represents an inner class + * declared in a non-static context, the formal parameter types + * include the explicit enclosing instance as the first parameter. + * + *

The constructor to reflect is the public constructor of the class + * represented by this {@code Class} object whose formal parameter + * types match those specified by {@code parameterTypes}. + * + * @param parameterTypes the parameter array + * @return the {@code Constructor} object of the public constructor that + * matches the specified {@code parameterTypes} + * @exception NoSuchMethodException if a matching method is not found. + * @exception SecurityException + * If a security manager, s, is present and any of the + * following conditions is met: + * + *

    + * + *
  • invocation of + * {@link SecurityManager#checkMemberAccess + * s.checkMemberAccess(this, Member.PUBLIC)} denies + * access to the constructor + * + *
  • the caller's class loader is not the same as or an + * ancestor of the class loader for the current class and + * invocation of {@link SecurityManager#checkPackageAccess + * s.checkPackageAccess()} denies access to the package + * of this class + * + *
+ * + * @since JDK1.1 + */ + public Constructor getConstructor(Class... parameterTypes) + throws NoSuchMethodException, SecurityException { + Constructor c = MethodImpl.findConstructor(this, parameterTypes); + if (c == null) { + StringBuilder sb = new StringBuilder(); + sb.append(getName()).append('('); + String sep = ""; + for (int i = 0; i < parameterTypes.length; i++) { + sb.append(sep).append(parameterTypes[i].getName()); + sep = ", "; + } + sb.append(')'); + throw new NoSuchMethodException(sb.toString()); + } + return c; + } + + /** + * Returns an array of {@code Constructor} objects reflecting all the + * constructors declared by the class represented by this + * {@code Class} object. These are public, protected, default + * (package) access, and private constructors. The elements in the array + * returned are not sorted and are not in any particular order. If the + * class has a default constructor, it is included in the returned array. + * This method returns an array of length 0 if this {@code Class} + * object represents an interface, a primitive type, an array class, or + * void. + * + *

See The Java Language Specification, section 8.2. + * + * @return the array of {@code Constructor} objects representing all the + * declared constructors of this class + * @exception SecurityException + * If a security manager, s, is present and any of the + * following conditions is met: + * + *

    + * + *
  • invocation of + * {@link SecurityManager#checkMemberAccess + * s.checkMemberAccess(this, Member.DECLARED)} denies + * access to the declared constructors within this class + * + *
  • the caller's class loader is not the same as or an + * ancestor of the class loader for the current class and + * invocation of {@link SecurityManager#checkPackageAccess + * s.checkPackageAccess()} denies access to the package + * of this class + * + *
+ * + * @since JDK1.1 + */ + public Constructor[] getDeclaredConstructors() throws SecurityException { + throw new SecurityException(); + } + /** + * Returns a {@code Constructor} object that reflects the specified + * constructor of the class or interface represented by this + * {@code Class} object. The {@code parameterTypes} parameter is + * an array of {@code Class} objects that identify the constructor's + * formal parameter types, in declared order. + * + * If this {@code Class} object represents an inner class + * declared in a non-static context, the formal parameter types + * include the explicit enclosing instance as the first parameter. + * + * @param parameterTypes the parameter array + * @return The {@code Constructor} object for the constructor with the + * specified parameter list + * @exception NoSuchMethodException if a matching method is not found. + * @exception SecurityException + * If a security manager, s, is present and any of the + * following conditions is met: + * + *
    + * + *
  • invocation of + * {@link SecurityManager#checkMemberAccess + * s.checkMemberAccess(this, Member.DECLARED)} denies + * access to the declared constructor + * + *
  • the caller's class loader is not the same as or an + * ancestor of the class loader for the current class and + * invocation of {@link SecurityManager#checkPackageAccess + * s.checkPackageAccess()} denies access to the package + * of this class + * + *
+ * + * @since JDK1.1 + */ + public Constructor getDeclaredConstructor(Class... parameterTypes) + throws NoSuchMethodException, SecurityException { + return getConstructor(parameterTypes); + } + + + /** * Character.isDigit answers {@code true} to some non-ascii * digits. This one does not. */ diff -r e49c4c2c3737 -r 7a78a84ab583 rt/emul/mini/src/main/java/java/lang/reflect/Constructor.java --- a/rt/emul/mini/src/main/java/java/lang/reflect/Constructor.java Sat Sep 28 02:45:17 2013 +0200 +++ b/rt/emul/mini/src/main/java/java/lang/reflect/Constructor.java Sat Sep 28 12:03:59 2013 +0200 @@ -26,6 +26,10 @@ package java.lang.reflect; import java.lang.annotation.Annotation; +import static java.lang.reflect.Method.fromPrimitive; +import static java.lang.reflect.Method.getAccess; +import static java.lang.reflect.Method.getParameterTypes; +import org.apidesign.bck2brwsr.core.JavaScriptBody; import org.apidesign.bck2brwsr.emul.reflect.TypeProvider; /** @@ -53,44 +57,20 @@ GenericDeclaration, Member { - private Class clazz; - private int slot; - private Class[] parameterTypes; - private Class[] exceptionTypes; - private int modifiers; - // Generics and annotations support - private transient String signature; - private byte[] annotations; - private byte[] parameterAnnotations; - - - // For sharing of ConstructorAccessors. This branching structure - // is currently only two levels deep (i.e., one root Constructor - // and potentially many Constructor objects pointing to it.) - private Constructor root; + private final Class clazz; + private final Object data; + private final String sig; /** * Package-private constructor used by ReflectAccess to enable * instantiation of these objects in Java code from the java.lang * package via sun.reflect.LangReflectAccess. */ - Constructor(Class declaringClass, - Class[] parameterTypes, - Class[] checkedExceptions, - int modifiers, - int slot, - String signature, - byte[] annotations, - byte[] parameterAnnotations) + Constructor(Class declaringClass, Object data, String sig) { this.clazz = declaringClass; - this.parameterTypes = parameterTypes; - this.exceptionTypes = checkedExceptions; - this.modifiers = modifiers; - this.slot = slot; - this.signature = signature; - this.annotations = annotations; - this.parameterAnnotations = parameterAnnotations; + this.data = data; + this.sig = sig; } /** @@ -126,7 +106,7 @@ * @see Modifier */ public int getModifiers() { - return modifiers; + return getAccess(data); } /** @@ -159,7 +139,7 @@ * represents */ public Class[] getParameterTypes() { - return (Class[]) parameterTypes.clone(); + return Method.getParameterTypes(sig); } @@ -205,7 +185,7 @@ * constructor this object represents */ public Class[] getExceptionTypes() { - return (Class[])exceptionTypes.clone(); + throw new UnsupportedOperationException(); } @@ -242,20 +222,9 @@ * same formal parameter types. */ public boolean equals(Object obj) { - if (obj != null && obj instanceof Constructor) { - Constructor other = (Constructor)obj; - if (getDeclaringClass() == other.getDeclaringClass()) { - /* Avoid unnecessary cloning */ - Class[] params1 = parameterTypes; - Class[] params2 = other.parameterTypes; - if (params1.length == params2.length) { - for (int i = 0; i < params1.length; i++) { - if (params1[i] != params2[i]) - return false; - } - return true; - } - } + if (obj instanceof Constructor) { + Constructor other = (Constructor)obj; + return data == other.data; } return false; } @@ -293,13 +262,14 @@ } sb.append(Field.getTypeName(getDeclaringClass())); sb.append("("); - Class[] params = parameterTypes; // avoid clone + Class[] params = getParameterTypes(); // avoid clone for (int j = 0; j < params.length; j++) { sb.append(Field.getTypeName(params[j])); if (j < (params.length - 1)) sb.append(","); } sb.append(")"); + /* Class[] exceptions = exceptionTypes; // avoid clone if (exceptions.length > 0) { sb.append(" throws "); @@ -309,6 +279,7 @@ sb.append(","); } } + */ return sb.toString(); } catch (Exception e) { return "<" + e + ">"; @@ -452,9 +423,29 @@ throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { - throw new SecurityException(); + Class[] types = getParameterTypes(); + if (types.length != initargs.length) { + throw new IllegalArgumentException("Types len " + types.length + " args: " + initargs.length); + } else { + initargs = initargs.clone(); + for (int i = 0; i < types.length; i++) { + Class c = types[i]; + if (c.isPrimitive() && initargs[i] != null) { + initargs[i] = Method.toPrimitive(initargs[i]); + } + } + } + return (T) newInstance0(this.getDeclaringClass(), "cons__" + sig, initargs); } + @JavaScriptBody(args = { "self", "sig", "args" }, body = + "\nvar c = self.cnstr;" + + "\nvar inst = c();" + + "\nc[sig].apply(inst, args);" + + "\nreturn inst;" + ) + private static native Object newInstance0(Class self, String sig, Object[] args); + /** * Returns {@code true} if this constructor was declared to take * a variable number of arguments; returns {@code false} @@ -481,22 +472,6 @@ return Modifier.isSynthetic(getModifiers()); } - int getSlot() { - return slot; - } - - String getSignature() { - return signature; - } - - byte[] getRawAnnotations() { - return annotations; - } - - byte[] getRawParameterAnnotations() { - return parameterAnnotations; - } - /** * @throws NullPointerException {@inheritDoc} * @since 1.5 @@ -532,11 +507,11 @@ * @since 1.5 */ public Annotation[][] getParameterAnnotations() { - int numParameters = parameterTypes.length; - if (parameterAnnotations == null) - return new Annotation[numParameters][0]; +// int numParameters = parameterTypes.length; +// if (parameterAnnotations == null) +// return new Annotation[numParameters][0]; - return new Annotation[numParameters][0]; // XXX + return new Annotation[0][0]; // XXX /* Annotation[][] result = AnnotationParser.parseParameterAnnotations( parameterAnnotations, diff -r e49c4c2c3737 -r 7a78a84ab583 rt/emul/mini/src/main/java/java/lang/reflect/Method.java --- a/rt/emul/mini/src/main/java/java/lang/reflect/Method.java Sat Sep 28 02:45:17 2013 +0200 +++ b/rt/emul/mini/src/main/java/java/lang/reflect/Method.java Sat Sep 28 12:03:59 2013 +0200 @@ -113,7 +113,7 @@ } @JavaScriptBody(args = "self", body = "return self.access;") - private static native int getAccess(Object self); + static native int getAccess(Object self); /** * Returns an array of {@code TypeVariable} objects that represent the @@ -183,6 +183,10 @@ * represents */ public Class[] getParameterTypes() { + return getParameterTypes(sig); + } + + static Class[] getParameterTypes(String sig) { Class[] arr = new Class[MethodImpl.signatureElements(sig) - 1]; Enumeration en = MethodImpl.signatureParser(sig); en.nextElement(); // return type @@ -583,7 +587,7 @@ private static native Integer fromRaw(Class cls, String m, Object o); @JavaScriptBody(args = { "o" }, body = "return o.valueOf();") - private static native Object toPrimitive(Object o); + static native Object toPrimitive(Object o); /** * Returns {@code true} if this method is a bridge @@ -692,6 +696,11 @@ protected Method create(Class declaringClass, String name, Object data, String sig) { return new Method(declaringClass, name, data, sig); } + + @Override + protected Constructor create(Class declaringClass, Object data, String sig) { + return new Constructor(declaringClass, data, sig); + } }; } } diff -r e49c4c2c3737 -r 7a78a84ab583 rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/MethodImpl.java --- a/rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/MethodImpl.java Sat Sep 28 02:45:17 2013 +0200 +++ b/rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/MethodImpl.java Sat Sep 28 12:03:59 2013 +0200 @@ -18,6 +18,7 @@ package org.apidesign.bck2brwsr.emul.reflect; import java.lang.reflect.Array; +import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.Enumeration; import org.apidesign.bck2brwsr.core.JavaScriptBody; @@ -37,15 +38,17 @@ } protected abstract Method create(Class declaringClass, String name, Object data, String sig); + protected abstract Constructor create(Class declaringClass, Object data, String sig); // // bck2brwsr implementation // - @JavaScriptBody(args = {"clazz", "prefix"}, + @JavaScriptBody(args = {"clazz", "prefix", "cnstr"}, body = "" - + "var c = clazz.cnstr.prototype;" + + "var c = clazz.cnstr;\n" + + "if (!cnstr) c = c.prototype;" + "var arr = new Array();\n" + "for (m in c) {\n" + " if (m.indexOf(prefix) === 0) {\n" @@ -57,11 +60,55 @@ + "}\n" + "return arr;") private static native Object[] findMethodData( - Class clazz, String prefix); + Class clazz, String prefix, boolean cnstr); + public static Constructor findConstructor( + Class clazz, Class... parameterTypes) { + Object[] data = findMethodData(clazz, "cons__", true); + BIG: for (int i = 0; i < data.length; i += 3) { + String sig = ((String) data[i]).substring(6); + Class cls = (Class) data[i + 2]; + Constructor tmp = INSTANCE.create(cls, data[i + 1], sig); + Class[] tmpParms = tmp.getParameterTypes(); + if (parameterTypes.length != tmpParms.length) { + continue; + } + for (int j = 0; j < tmpParms.length; j++) { + if (!parameterTypes[j].equals(tmpParms[j])) { + continue BIG; + } + } + return tmp; + } + return null; + } + + public static Constructor[] findConstructors(Class clazz, int mask) { + Object[] namesAndData = findMethodData(clazz, "", true); + int cnt = 0; + for (int i = 0; i < namesAndData.length; i += 3) { + String sig = (String) namesAndData[i]; + Object data = namesAndData[i + 1]; + if (!sig.startsWith("cons__")) { + continue; + } + sig = sig.substring(6); + Class cls = (Class) namesAndData[i + 2]; + final Constructor m = INSTANCE.create(cls, data, sig); + if ((m.getModifiers() & mask) == 0) { + continue; + } + namesAndData[cnt++] = m; + } + Constructor[] arr = new Constructor[cnt]; + for (int i = 0; i < cnt; i++) { + arr[i] = (Constructor) namesAndData[i]; + } + return arr; + } public static Method findMethod( Class clazz, String name, Class... parameterTypes) { - Object[] data = findMethodData(clazz, name + "__"); + Object[] data = findMethodData(clazz, name + "__", false); BIG: for (int i = 0; i < data.length; i += 3) { String sig = ((String) data[i]).substring(name.length() + 2); Class cls = (Class) data[i + 2]; @@ -81,7 +128,7 @@ } public static Method[] findMethods(Class clazz, int mask) { - Object[] namesAndData = findMethodData(clazz, ""); + Object[] namesAndData = findMethodData(clazz, "", false); int cnt = 0; for (int i = 0; i < namesAndData.length; i += 3) { String sig = (String) namesAndData[i];