Test to verify reflective call on a method of a class reflection
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 04 Dec 2012 14:49:01 +0100
branchreflection
changeset 2615d1e20215d12
parent 260 1d03cb35fbda
child 262 683719ffcfe7
Test to verify reflective call on a method of a class
emul/src/main/java/java/lang/Class.java
vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java
vm/src/test/java/org/apidesign/vm4brwsr/Classes.java
     1.1 --- a/emul/src/main/java/java/lang/Class.java	Tue Dec 04 14:31:11 2012 +0100
     1.2 +++ b/emul/src/main/java/java/lang/Class.java	Tue Dec 04 14:49:01 2012 +0100
     1.3 @@ -27,6 +27,8 @@
     1.4  
     1.5  import java.io.InputStream;
     1.6  import java.lang.annotation.Annotation;
     1.7 +import java.lang.reflect.Field;
     1.8 +import java.lang.reflect.Method;
     1.9  import java.lang.reflect.TypeVariable;
    1.10  import org.apidesign.bck2brwsr.core.JavaScriptBody;
    1.11  
    1.12 @@ -523,7 +525,231 @@
    1.13              throw new IllegalStateException("Malformed class name");
    1.14          }
    1.15      }
    1.16 +
    1.17 +    /**
    1.18 +     * Returns an array containing {@code Field} objects reflecting all
    1.19 +     * the accessible public fields of the class or interface represented by
    1.20 +     * this {@code Class} object.  The elements in the array returned are
    1.21 +     * not sorted and are not in any particular order.  This method returns an
    1.22 +     * array of length 0 if the class or interface has no accessible public
    1.23 +     * fields, or if it represents an array class, a primitive type, or void.
    1.24 +     *
    1.25 +     * <p> Specifically, if this {@code Class} object represents a class,
    1.26 +     * this method returns the public fields of this class and of all its
    1.27 +     * superclasses.  If this {@code Class} object represents an
    1.28 +     * interface, this method returns the fields of this interface and of all
    1.29 +     * its superinterfaces.
    1.30 +     *
    1.31 +     * <p> The implicit length field for array class is not reflected by this
    1.32 +     * method. User code should use the methods of class {@code Array} to
    1.33 +     * manipulate arrays.
    1.34 +     *
    1.35 +     * <p> See <em>The Java Language Specification</em>, sections 8.2 and 8.3.
    1.36 +     *
    1.37 +     * @return the array of {@code Field} objects representing the
    1.38 +     * public fields
    1.39 +     * @exception  SecurityException
    1.40 +     *             If a security manager, <i>s</i>, is present and any of the
    1.41 +     *             following conditions is met:
    1.42 +     *
    1.43 +     *             <ul>
    1.44 +     *
    1.45 +     *             <li> invocation of
    1.46 +     *             {@link SecurityManager#checkMemberAccess
    1.47 +     *             s.checkMemberAccess(this, Member.PUBLIC)} denies
    1.48 +     *             access to the fields within this class
    1.49 +     *
    1.50 +     *             <li> the caller's class loader is not the same as or an
    1.51 +     *             ancestor of the class loader for the current class and
    1.52 +     *             invocation of {@link SecurityManager#checkPackageAccess
    1.53 +     *             s.checkPackageAccess()} denies access to the package
    1.54 +     *             of this class
    1.55 +     *
    1.56 +     *             </ul>
    1.57 +     *
    1.58 +     * @since JDK1.1
    1.59 +     */
    1.60 +    public Field[] getFields() throws SecurityException {
    1.61 +        throw new SecurityException();
    1.62 +    }
    1.63 +
    1.64 +    /**
    1.65 +     * Returns an array containing {@code Method} objects reflecting all
    1.66 +     * the public <em>member</em> methods of the class or interface represented
    1.67 +     * by this {@code Class} object, including those declared by the class
    1.68 +     * or interface and those inherited from superclasses and
    1.69 +     * superinterfaces.  Array classes return all the (public) member methods
    1.70 +     * inherited from the {@code Object} class.  The elements in the array
    1.71 +     * returned are not sorted and are not in any particular order.  This
    1.72 +     * method returns an array of length 0 if this {@code Class} object
    1.73 +     * represents a class or interface that has no public member methods, or if
    1.74 +     * this {@code Class} object represents a primitive type or void.
    1.75 +     *
    1.76 +     * <p> The class initialization method {@code <clinit>} is not
    1.77 +     * included in the returned array. If the class declares multiple public
    1.78 +     * member methods with the same parameter types, they are all included in
    1.79 +     * the returned array.
    1.80 +     *
    1.81 +     * <p> See <em>The Java Language Specification</em>, sections 8.2 and 8.4.
    1.82 +     *
    1.83 +     * @return the array of {@code Method} objects representing the
    1.84 +     * public methods of this class
    1.85 +     * @exception  SecurityException
    1.86 +     *             If a security manager, <i>s</i>, is present and any of the
    1.87 +     *             following conditions is met:
    1.88 +     *
    1.89 +     *             <ul>
    1.90 +     *
    1.91 +     *             <li> invocation of
    1.92 +     *             {@link SecurityManager#checkMemberAccess
    1.93 +     *             s.checkMemberAccess(this, Member.PUBLIC)} denies
    1.94 +     *             access to the methods within this class
    1.95 +     *
    1.96 +     *             <li> the caller's class loader is not the same as or an
    1.97 +     *             ancestor of the class loader for the current class and
    1.98 +     *             invocation of {@link SecurityManager#checkPackageAccess
    1.99 +     *             s.checkPackageAccess()} denies access to the package
   1.100 +     *             of this class
   1.101 +     *
   1.102 +     *             </ul>
   1.103 +     *
   1.104 +     * @since JDK1.1
   1.105 +     */
   1.106 +    public Method[] getMethods() throws SecurityException {
   1.107 +        throw new SecurityException();
   1.108 +    }
   1.109 +
   1.110 +    /**
   1.111 +     * Returns a {@code Field} object that reflects the specified public
   1.112 +     * member field of the class or interface represented by this
   1.113 +     * {@code Class} object. The {@code name} parameter is a
   1.114 +     * {@code String} specifying the simple name of the desired field.
   1.115 +     *
   1.116 +     * <p> The field to be reflected is determined by the algorithm that
   1.117 +     * follows.  Let C be the class represented by this object:
   1.118 +     * <OL>
   1.119 +     * <LI> If C declares a public field with the name specified, that is the
   1.120 +     *      field to be reflected.</LI>
   1.121 +     * <LI> If no field was found in step 1 above, this algorithm is applied
   1.122 +     *      recursively to each direct superinterface of C. The direct
   1.123 +     *      superinterfaces are searched in the order they were declared.</LI>
   1.124 +     * <LI> If no field was found in steps 1 and 2 above, and C has a
   1.125 +     *      superclass S, then this algorithm is invoked recursively upon S.
   1.126 +     *      If C has no superclass, then a {@code NoSuchFieldException}
   1.127 +     *      is thrown.</LI>
   1.128 +     * </OL>
   1.129 +     *
   1.130 +     * <p> See <em>The Java Language Specification</em>, sections 8.2 and 8.3.
   1.131 +     *
   1.132 +     * @param name the field name
   1.133 +     * @return  the {@code Field} object of this class specified by
   1.134 +     * {@code name}
   1.135 +     * @exception NoSuchFieldException if a field with the specified name is
   1.136 +     *              not found.
   1.137 +     * @exception NullPointerException if {@code name} is {@code null}
   1.138 +     * @exception  SecurityException
   1.139 +     *             If a security manager, <i>s</i>, is present and any of the
   1.140 +     *             following conditions is met:
   1.141 +     *
   1.142 +     *             <ul>
   1.143 +     *
   1.144 +     *             <li> invocation of
   1.145 +     *             {@link SecurityManager#checkMemberAccess
   1.146 +     *             s.checkMemberAccess(this, Member.PUBLIC)} denies
   1.147 +     *             access to the field
   1.148 +     *
   1.149 +     *             <li> the caller's class loader is not the same as or an
   1.150 +     *             ancestor of the class loader for the current class and
   1.151 +     *             invocation of {@link SecurityManager#checkPackageAccess
   1.152 +     *             s.checkPackageAccess()} denies access to the package
   1.153 +     *             of this class
   1.154 +     *
   1.155 +     *             </ul>
   1.156 +     *
   1.157 +     * @since JDK1.1
   1.158 +     */
   1.159 +    public Field getField(String name)
   1.160 +        throws SecurityException {
   1.161 +        throw new SecurityException();
   1.162 +    }
   1.163      
   1.164 +    
   1.165 +    /**
   1.166 +     * Returns a {@code Method} object that reflects the specified public
   1.167 +     * member method of the class or interface represented by this
   1.168 +     * {@code Class} object. The {@code name} parameter is a
   1.169 +     * {@code String} specifying the simple name of the desired method. The
   1.170 +     * {@code parameterTypes} parameter is an array of {@code Class}
   1.171 +     * objects that identify the method's formal parameter types, in declared
   1.172 +     * order. If {@code parameterTypes} is {@code null}, it is
   1.173 +     * treated as if it were an empty array.
   1.174 +     *
   1.175 +     * <p> If the {@code name} is "{@code <init>};"or "{@code <clinit>}" a
   1.176 +     * {@code NoSuchMethodException} is raised. Otherwise, the method to
   1.177 +     * be reflected is determined by the algorithm that follows.  Let C be the
   1.178 +     * class represented by this object:
   1.179 +     * <OL>
   1.180 +     * <LI> C is searched for any <I>matching methods</I>. If no matching
   1.181 +     *      method is found, the algorithm of step 1 is invoked recursively on
   1.182 +     *      the superclass of C.</LI>
   1.183 +     * <LI> If no method was found in step 1 above, the superinterfaces of C
   1.184 +     *      are searched for a matching method. If any such method is found, it
   1.185 +     *      is reflected.</LI>
   1.186 +     * </OL>
   1.187 +     *
   1.188 +     * To find a matching method in a class C:&nbsp; If C declares exactly one
   1.189 +     * public method with the specified name and exactly the same formal
   1.190 +     * parameter types, that is the method reflected. If more than one such
   1.191 +     * method is found in C, and one of these methods has a return type that is
   1.192 +     * more specific than any of the others, that method is reflected;
   1.193 +     * otherwise one of the methods is chosen arbitrarily.
   1.194 +     *
   1.195 +     * <p>Note that there may be more than one matching method in a
   1.196 +     * class because while the Java language forbids a class to
   1.197 +     * declare multiple methods with the same signature but different
   1.198 +     * return types, the Java virtual machine does not.  This
   1.199 +     * increased flexibility in the virtual machine can be used to
   1.200 +     * implement various language features.  For example, covariant
   1.201 +     * returns can be implemented with {@linkplain
   1.202 +     * java.lang.reflect.Method#isBridge bridge methods}; the bridge
   1.203 +     * method and the method being overridden would have the same
   1.204 +     * signature but different return types.
   1.205 +     *
   1.206 +     * <p> See <em>The Java Language Specification</em>, sections 8.2 and 8.4.
   1.207 +     *
   1.208 +     * @param name the name of the method
   1.209 +     * @param parameterTypes the list of parameters
   1.210 +     * @return the {@code Method} object that matches the specified
   1.211 +     * {@code name} and {@code parameterTypes}
   1.212 +     * @exception NoSuchMethodException if a matching method is not found
   1.213 +     *            or if the name is "&lt;init&gt;"or "&lt;clinit&gt;".
   1.214 +     * @exception NullPointerException if {@code name} is {@code null}
   1.215 +     * @exception  SecurityException
   1.216 +     *             If a security manager, <i>s</i>, is present and any of the
   1.217 +     *             following conditions is met:
   1.218 +     *
   1.219 +     *             <ul>
   1.220 +     *
   1.221 +     *             <li> invocation of
   1.222 +     *             {@link SecurityManager#checkMemberAccess
   1.223 +     *             s.checkMemberAccess(this, Member.PUBLIC)} denies
   1.224 +     *             access to the method
   1.225 +     *
   1.226 +     *             <li> the caller's class loader is not the same as or an
   1.227 +     *             ancestor of the class loader for the current class and
   1.228 +     *             invocation of {@link SecurityManager#checkPackageAccess
   1.229 +     *             s.checkPackageAccess()} denies access to the package
   1.230 +     *             of this class
   1.231 +     *
   1.232 +     *             </ul>
   1.233 +     *
   1.234 +     * @since JDK1.1
   1.235 +     */
   1.236 +    public Method getMethod(String name, Class<?>... parameterTypes)
   1.237 +        throws SecurityException {
   1.238 +        throw new SecurityException();
   1.239 +    }
   1.240 +
   1.241      /**
   1.242       * Character.isDigit answers {@code true} to some non-ascii
   1.243       * digits.  This one does not.
     2.1 --- a/vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java	Tue Dec 04 14:31:11 2012 +0100
     2.2 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java	Tue Dec 04 14:49:01 2012 +0100
     2.3 @@ -83,6 +83,15 @@
     2.4      @Test public void jsStringAnnotationFromArray() throws Exception {
     2.5          assertExec("Check class annotation", Classes.class, "getNamer__Ljava_lang_String_2Z", "my text", false);
     2.6      }
     2.7 +    @Test public void javaInvokeMethod() throws Exception {
     2.8 +        assertEquals(Classes.reflectiveMethodCall(true), "java.io.IOException", "Calls the name() method via reflection");
     2.9 +    }
    2.10 +    @Test public void jsInvokeMethod() throws Exception {
    2.11 +        assertExec("Calls the name() method via reflection", Classes.class, 
    2.12 +            "reflectiveMethodCall__Ljava_lang_Object_2Z", 
    2.13 +            "java.io.IOException"
    2.14 +        );
    2.15 +    }
    2.16      
    2.17      private static CharSequence codeSeq;
    2.18      private static Invocable code;
     3.1 --- a/vm/src/test/java/org/apidesign/vm4brwsr/Classes.java	Tue Dec 04 14:31:11 2012 +0100
     3.2 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/Classes.java	Tue Dec 04 14:49:01 2012 +0100
     3.3 @@ -19,6 +19,7 @@
     3.4  
     3.5  import java.io.IOException;
     3.6  import java.lang.annotation.Annotation;
     3.7 +import java.lang.reflect.Method;
     3.8  import java.net.MalformedURLException;
     3.9  
    3.10  /**
    3.11 @@ -41,6 +42,7 @@
    3.12          return new IOException().getClass().getName().toString();
    3.13      }
    3.14      
    3.15 +    @ClassesMarker(number = 1)
    3.16      public static String name() {
    3.17          return IOException.class.getName().toString();
    3.18      }
    3.19 @@ -76,4 +78,21 @@
    3.20          }
    3.21          return null;
    3.22      }
    3.23 +    
    3.24 +    public static Object reflectiveMethodCall(boolean direct) throws Exception {
    3.25 +        Method m;
    3.26 +        /*
    3.27 +        if (!direct) {
    3.28 +            final Class<? extends Annotation> v = ClassesMarker.class;
    3.29 +            for (Method single : Classes.class.getMethods()) {
    3.30 +                if (single.getAnnotation(v)) {
    3.31 +                    m = single;
    3.32 +                    break;
    3.33 +                }
    3.34 +            }
    3.35 +        } else*/ {
    3.36 +            m = Classes.class.getMethod("name");
    3.37 +        }
    3.38 +        return m.invoke(null);
    3.39 +    }
    3.40  }