/* * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ import java.io.*; import java.util.*; import java.net.*; import java.lang.reflect.*; /** * Test MethodParameter attributs by reflection API */ public class ReflectionVisitor extends Tester.Visitor { public ReflectionVisitor(Tester tester) { super(tester); } public void error(String msg) { super.error("reflection: " + msg); } public void warn(String msg) { super.warn("reflection: " + msg); } boolean isEnum; boolean isInterface; boolean isAnon; boolean isLocal; boolean isMember; boolean isStatic; boolean isPublic; Class clazz; StringBuilder sb; /** * Read class using {@code ClassFile}, and generate a list of methods * with parameter names as available in the MethodParameters attribute. */ void visitClass(final String cl, final File cfile, final StringBuilder sb) throws Exception { this.sb = sb; clazz = Class.forName(cl); isEnum = clazz.isEnum(); isInterface = clazz.isInterface(); isAnon = clazz.isAnonymousClass(); isLocal = clazz.isLocalClass(); isMember = clazz.isMemberClass(); isStatic = ((clazz.getModifiers() & Modifier.STATIC) != 0); isPublic = ((clazz.getModifiers() & Modifier.PUBLIC) != 0); sb.append(isStatic ? "static " : "") .append(isPublic ? "public " : "") .append(isEnum ? "enum " : isInterface ? "interface " : "class ") .append(cl).append(" -- ") .append(isMember? "member " : "" ) .append(isLocal? "local " : "" ) .append(isAnon ? "anon" : "") .append("\n"); for (Constructor c : clazz.getDeclaredConstructors()) { testConstructor(c); } for (Method m :clazz.getDeclaredMethods()) { testMethod(m); } } void testConstructor(Constructor c) { String prefix = clazz.getName() + "." + c.getName() + "() - "; // Parameters must match parameter types Parameter params[] = c.getParameters(); int paramTypes = c.getParameterTypes().length; if (paramTypes != params.length) { error(prefix + "number of parameter types (" + paramTypes + ") != number of parameters (" + params.length + ")"); return; } sb.append(clazz.getName()).append(".").append("").append("("); String sep = ""; // Some paramters are expected if (params.length < 2 && isEnum) { error(prefix + "enum constuctor, two arguments expected"); } else if (params.length < 1 && (isAnon || isLocal || (isMember && !isStatic ))) { error(prefix + "class constuctor,expected implicit argument"); } int i = -1; String param = null; for (Parameter p : c.getParameters()) { i++; String pname = p.getName(); sb.append(sep).append(pname); if (p.isImplicit()) sb.append("!"); if (p.isSynthetic()) sb.append("!!"); sep = ", "; // Set expectations String expect = null; boolean allowImplicit = false; boolean allowSynthetic = false; if (isEnum) { if (i == 0) { expect = "\\$enum\\$name"; allowSynthetic = true; } else if(i == 1) { expect = "\\$enum\\$ordinal"; allowSynthetic = true; } } else if (i == 0) { if (isAnon) { allowImplicit = true; } else if (isLocal) { allowImplicit = true; expect = "this\\$[0-n]*"; } else if ((isMember && !isStatic)) { allowImplicit = true; if (!isPublic) { // some but not all non-public inner classes // have synthetic argument. For now we give // the test a bit of slack and allow either. allowSynthetic = true; } expect = "this\\$[0-n]*"; } } else if (isAnon) { // not an implementation gurantee, but okay for now expect = "x[0-n]*"; } // Check expected flags if (p.isSynthetic() && p.isImplicit()) { error(prefix + "param[" + i + "]='" + pname + "' both isImplicit() and isSynthetic()"); break; } if (allowImplicit && allowSynthetic && !(p.isSynthetic() || p.isImplicit())) { error(prefix + "param[" + i + "]='" + pname + "' isImplicit() or isSynthetic() expected"); break; } if (allowImplicit && !allowSynthetic && !p.isImplicit()) { error(prefix + "param[" + i + "]='" + pname + "' isImplicit() expected"); break; } if (!allowImplicit && allowSynthetic && !p.isSynthetic()) { error(prefix + "param[" + i + "]='" + pname + "' isSynthetic() expected"); break; } if (!allowImplicit && p.isImplicit()) { error(prefix + "param[" + i + "]='" + pname + "' isImplicit() unexpected"); break; } if (!allowSynthetic && p.isSynthetic()) { error(prefix + "param[" + i + "]='" + pname + "' isSynthetic() unexpected"); break; } // Check expected names if (expect != null) { if (pname.matches(expect)) continue; error(prefix + "param[" + i + "]='" + pname + "' expected '" + expect + "'"); break; } // Test naming convention for explicit parameters. boolean fidelity = !isAnon; if (param != null && fidelity) { char ch = param.charAt(0); expect = (++ch) + param; } if (pname != null && fidelity) { param = pname; } if (expect != null && !expect.equals(pname)) { error(prefix + "param[" + i + "]='" + pname + "' expected '" + expect + "'"); break; } } if (c.isSynthetic()) { sb.append(")!!\n"); } else { sb.append(")\n"); } } void testMethod(Method m) { String prefix = clazz.getName() + "." + m.getName() + "() - "; // Parameters must match parameter types int paramTypes = m.getParameterTypes().length; int params = m.getParameters().length; if (paramTypes != params) { error(prefix + "number of parameter types (" + paramTypes + ") != number of parameters (" + params + ")"); return; } sb.append(clazz.getName()).append(".").append(m.getName()).append("("); String sep = ""; String param = null; int i = -1; // For methods we expect all parameters to follow // the test-case design pattern, except synthetic methods. for (Parameter p : m.getParameters()) { i++; if (param == null) { param = p.getName(); sb.append(sep).append(param); } else { char c = param.charAt(0); String expect = m.isSynthetic() ? ("arg" + i) : ((++c) + param); param = p.getName(); sb.append(sep).append(param); if (!expect.equals(param)) { error(prefix + "param[" + i + "]='" + param + "' expected '" + expect + "'"); break; } } sep = ", "; } if (m.isSynthetic()) { sb.append(")!!\n"); } else { sb.append(")\n"); } } }