Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/java/beans/Statement.java
38829 views
/*1* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/24package java.beans;2526import java.lang.reflect.AccessibleObject;27import java.lang.reflect.Array;28import java.lang.reflect.Constructor;29import java.lang.reflect.InvocationTargetException;30import java.lang.reflect.Method;31import java.security.AccessControlContext;32import java.security.AccessController;33import java.security.PrivilegedActionException;34import java.security.PrivilegedExceptionAction;3536import com.sun.beans.finder.ClassFinder;37import com.sun.beans.finder.ConstructorFinder;38import com.sun.beans.finder.MethodFinder;39import sun.reflect.misc.MethodUtil;4041/**42* A <code>Statement</code> object represents a primitive statement43* in which a single method is applied to a target and44* a set of arguments - as in <code>"a.setFoo(b)"</code>.45* Note that where this example uses names46* to denote the target and its argument, a statement47* object does not require a name space and is constructed with48* the values themselves.49* The statement object associates the named method50* with its environment as a simple set of values:51* the target and an array of argument values.52*53* @since 1.454*55* @author Philip Milne56*/57public class Statement {5859private static Object[] emptyArray = new Object[]{};6061static ExceptionListener defaultExceptionListener = new ExceptionListener() {62public void exceptionThrown(Exception e) {63System.err.println(e);64// e.printStackTrace();65System.err.println("Continuing ...");66}67};6869private final AccessControlContext acc = AccessController.getContext();70private final Object target;71private final String methodName;72private final Object[] arguments;73ClassLoader loader;7475/**76* Creates a new {@link Statement} object77* for the specified target object to invoke the method78* specified by the name and by the array of arguments.79* <p>80* The {@code target} and the {@code methodName} values should not be {@code null}.81* Otherwise an attempt to execute this {@code Expression}82* will result in a {@code NullPointerException}.83* If the {@code arguments} value is {@code null},84* an empty array is used as the value of the {@code arguments} property.85*86* @param target the target object of this statement87* @param methodName the name of the method to invoke on the specified target88* @param arguments the array of arguments to invoke the specified method89*/90@ConstructorProperties({"target", "methodName", "arguments"})91public Statement(Object target, String methodName, Object[] arguments) {92this.target = target;93this.methodName = methodName;94this.arguments = (arguments == null) ? emptyArray : arguments.clone();95}9697/**98* Returns the target object of this statement.99* If this method returns {@code null},100* the {@link #execute} method101* throws a {@code NullPointerException}.102*103* @return the target object of this statement104*/105public Object getTarget() {106return target;107}108109/**110* Returns the name of the method to invoke.111* If this method returns {@code null},112* the {@link #execute} method113* throws a {@code NullPointerException}.114*115* @return the name of the method116*/117public String getMethodName() {118return methodName;119}120121/**122* Returns the arguments for the method to invoke.123* The number of arguments and their types124* must match the method being called.125* {@code null} can be used as a synonym of an empty array.126*127* @return the array of arguments128*/129public Object[] getArguments() {130return this.arguments.clone();131}132133/**134* The {@code execute} method finds a method whose name is the same135* as the {@code methodName} property, and invokes the method on136* the target.137*138* When the target's class defines many methods with the given name139* the implementation should choose the most specific method using140* the algorithm specified in the Java Language Specification141* (15.11). The dynamic class of the target and arguments are used142* in place of the compile-time type information and, like the143* {@link java.lang.reflect.Method} class itself, conversion between144* primitive values and their associated wrapper classes is handled145* internally.146* <p>147* The following method types are handled as special cases:148* <ul>149* <li>150* Static methods may be called by using a class object as the target.151* <li>152* The reserved method name "new" may be used to call a class's constructor153* as if all classes defined static "new" methods. Constructor invocations154* are typically considered {@code Expression}s rather than {@code Statement}s155* as they return a value.156* <li>157* The method names "get" and "set" defined in the {@link java.util.List}158* interface may also be applied to array instances, mapping to159* the static methods of the same name in the {@code Array} class.160* </ul>161*162* @throws NullPointerException if the value of the {@code target} or163* {@code methodName} property is {@code null}164* @throws NoSuchMethodException if a matching method is not found165* @throws SecurityException if a security manager exists and166* it denies the method invocation167* @throws Exception that is thrown by the invoked method168*169* @see java.lang.reflect.Method170*/171public void execute() throws Exception {172invoke();173}174175Object invoke() throws Exception {176AccessControlContext acc = this.acc;177if ((acc == null) && (System.getSecurityManager() != null)) {178throw new SecurityException("AccessControlContext is not set");179}180try {181return AccessController.doPrivileged(182new PrivilegedExceptionAction<Object>() {183public Object run() throws Exception {184return invokeInternal();185}186},187acc188);189}190catch (PrivilegedActionException exception) {191throw exception.getException();192}193}194195private Object invokeInternal() throws Exception {196Object target = getTarget();197String methodName = getMethodName();198199if (target == null || methodName == null) {200throw new NullPointerException((target == null ? "target" :201"methodName") + " should not be null");202}203204Object[] arguments = getArguments();205if (arguments == null) {206arguments = emptyArray;207}208// Class.forName() won't load classes outside209// of core from a class inside core. Special210// case this method.211if (target == Class.class && methodName.equals("forName")) {212return ClassFinder.resolveClass((String)arguments[0], this.loader);213}214Class<?>[] argClasses = new Class<?>[arguments.length];215for(int i = 0; i < arguments.length; i++) {216argClasses[i] = (arguments[i] == null) ? null : arguments[i].getClass();217}218219AccessibleObject m = null;220if (target instanceof Class) {221/*222For class methods, simluate the effect of a meta class223by taking the union of the static methods of the224actual class, with the instance methods of "Class.class"225and the overloaded "newInstance" methods defined by the226constructors.227This way "System.class", for example, will perform both228the static method getProperties() and the instance method229getSuperclass() defined in "Class.class".230*/231if (methodName.equals("new")) {232methodName = "newInstance";233}234// Provide a short form for array instantiation by faking an nary-constructor.235if (methodName.equals("newInstance") && ((Class)target).isArray()) {236Object result = Array.newInstance(((Class)target).getComponentType(), arguments.length);237for(int i = 0; i < arguments.length; i++) {238Array.set(result, i, arguments[i]);239}240return result;241}242if (methodName.equals("newInstance") && arguments.length != 0) {243// The Character class, as of 1.4, does not have a constructor244// which takes a String. All of the other "wrapper" classes245// for Java's primitive types have a String constructor so we246// fake such a constructor here so that this special case can be247// ignored elsewhere.248if (target == Character.class && arguments.length == 1 &&249argClasses[0] == String.class) {250return new Character(((String)arguments[0]).charAt(0));251}252try {253m = ConstructorFinder.findConstructor((Class)target, argClasses);254}255catch (NoSuchMethodException exception) {256m = null;257}258}259if (m == null && target != Class.class) {260m = getMethod((Class)target, methodName, argClasses);261}262if (m == null) {263m = getMethod(Class.class, methodName, argClasses);264}265}266else {267/*268This special casing of arrays is not necessary, but makes files269involving arrays much shorter and simplifies the archiving infrastrcure.270The Array.set() method introduces an unusual idea - that of a static method271changing the state of an instance. Normally statements with side272effects on objects are instance methods of the objects themselves273and we reinstate this rule (perhaps temporarily) by special-casing arrays.274*/275if (target.getClass().isArray() &&276(methodName.equals("set") || methodName.equals("get"))) {277int index = ((Integer)arguments[0]).intValue();278if (methodName.equals("get")) {279return Array.get(target, index);280}281else {282Array.set(target, index, arguments[1]);283return null;284}285}286m = getMethod(target.getClass(), methodName, argClasses);287}288if (m != null) {289try {290if (m instanceof Method) {291return MethodUtil.invoke((Method)m, target, arguments);292}293else {294return ((Constructor)m).newInstance(arguments);295}296}297catch (IllegalAccessException iae) {298throw new Exception("Statement cannot invoke: " +299methodName + " on " + target.getClass(),300iae);301}302catch (InvocationTargetException ite) {303Throwable te = ite.getTargetException();304if (te instanceof Exception) {305throw (Exception)te;306}307else {308throw ite;309}310}311}312throw new NoSuchMethodException(toString());313}314315String instanceName(Object instance) {316if (instance == null) {317return "null";318} else if (instance.getClass() == String.class) {319return "\""+(String)instance + "\"";320} else {321// Note: there is a minor problem with using the non-caching322// NameGenerator method. The return value will not have323// specific information about the inner class name. For example,324// In 1.4.2 an inner class would be represented as JList$1 now325// would be named Class.326327return NameGenerator.unqualifiedClassName(instance.getClass());328}329}330331/**332* Prints the value of this statement using a Java-style syntax.333*/334public String toString() {335// Respect a subclass's implementation here.336Object target = getTarget();337String methodName = getMethodName();338Object[] arguments = getArguments();339if (arguments == null) {340arguments = emptyArray;341}342StringBuffer result = new StringBuffer(instanceName(target) + "." + methodName + "(");343int n = arguments.length;344for(int i = 0; i < n; i++) {345result.append(instanceName(arguments[i]));346if (i != n -1) {347result.append(", ");348}349}350result.append(");");351return result.toString();352}353354static Method getMethod(Class<?> type, String name, Class<?>... args) {355try {356return MethodFinder.findMethod(type, name, args);357}358catch (NoSuchMethodException exception) {359return null;360}361}362}363364365