Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/share/classes/java/beans/Statement.java
41152 views
1
/*
2
* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
package java.beans;
26
27
import java.lang.reflect.AccessibleObject;
28
import java.lang.reflect.Array;
29
import java.lang.reflect.Constructor;
30
import java.lang.reflect.InvocationTargetException;
31
import java.lang.reflect.Method;
32
import java.security.AccessControlContext;
33
import java.security.AccessController;
34
import java.security.PrivilegedActionException;
35
import java.security.PrivilegedExceptionAction;
36
37
import com.sun.beans.finder.ClassFinder;
38
import com.sun.beans.finder.ConstructorFinder;
39
import com.sun.beans.finder.MethodFinder;
40
import sun.reflect.misc.MethodUtil;
41
42
import static sun.reflect.misc.ReflectUtil.checkPackageAccess;
43
44
/**
45
* A {@code Statement} object represents a primitive statement
46
* in which a single method is applied to a target and
47
* a set of arguments - as in {@code "a.setFoo(b)"}.
48
* Note that where this example uses names
49
* to denote the target and its argument, a statement
50
* object does not require a name space and is constructed with
51
* the values themselves.
52
* The statement object associates the named method
53
* with its environment as a simple set of values:
54
* the target and an array of argument values.
55
*
56
* @since 1.4
57
*
58
* @author Philip Milne
59
*/
60
public class Statement {
61
62
private static Object[] emptyArray = new Object[]{};
63
64
static ExceptionListener defaultExceptionListener = new ExceptionListener() {
65
public void exceptionThrown(Exception e) {
66
System.err.println(e);
67
// e.printStackTrace();
68
System.err.println("Continuing ...");
69
}
70
};
71
72
@SuppressWarnings("removal")
73
private final AccessControlContext acc = AccessController.getContext();
74
private final Object target;
75
private final String methodName;
76
private final Object[] arguments;
77
ClassLoader loader;
78
79
/**
80
* Creates a new {@link Statement} object
81
* for the specified target object to invoke the method
82
* specified by the name and by the array of arguments.
83
* <p>
84
* The {@code target} and the {@code methodName} values should not be {@code null}.
85
* Otherwise an attempt to execute this {@code Expression}
86
* will result in a {@code NullPointerException}.
87
* If the {@code arguments} value is {@code null},
88
* an empty array is used as the value of the {@code arguments} property.
89
*
90
* @param target the target object of this statement
91
* @param methodName the name of the method to invoke on the specified target
92
* @param arguments the array of arguments to invoke the specified method
93
*/
94
@ConstructorProperties({"target", "methodName", "arguments"})
95
public Statement(Object target, String methodName, Object[] arguments) {
96
this.target = target;
97
this.methodName = methodName;
98
this.arguments = (arguments == null) ? emptyArray : arguments.clone();
99
}
100
101
/**
102
* Returns the target object of this statement.
103
* If this method returns {@code null},
104
* the {@link #execute} method
105
* throws a {@code NullPointerException}.
106
*
107
* @return the target object of this statement
108
*/
109
public Object getTarget() {
110
return target;
111
}
112
113
/**
114
* Returns the name of the method to invoke.
115
* If this method returns {@code null},
116
* the {@link #execute} method
117
* throws a {@code NullPointerException}.
118
*
119
* @return the name of the method
120
*/
121
public String getMethodName() {
122
return methodName;
123
}
124
125
/**
126
* Returns the arguments for the method to invoke.
127
* The number of arguments and their types
128
* must match the method being called.
129
* {@code null} can be used as a synonym of an empty array.
130
*
131
* @return the array of arguments
132
*/
133
public Object[] getArguments() {
134
return this.arguments.clone();
135
}
136
137
/**
138
* The {@code execute} method finds a method whose name is the same
139
* as the {@code methodName} property, and invokes the method on
140
* the target.
141
*
142
* When the target's class defines many methods with the given name
143
* the implementation should choose the most specific method using
144
* the algorithm specified in the Java Language Specification
145
* (15.11). The dynamic class of the target and arguments are used
146
* in place of the compile-time type information and, like the
147
* {@link java.lang.reflect.Method} class itself, conversion between
148
* primitive values and their associated wrapper classes is handled
149
* internally.
150
* <p>
151
* The following method types are handled as special cases:
152
* <ul>
153
* <li>
154
* Static methods may be called by using a class object as the target.
155
* <li>
156
* The reserved method name "new" may be used to call a class's constructor
157
* as if all classes defined static "new" methods. Constructor invocations
158
* are typically considered {@code Expression}s rather than {@code Statement}s
159
* as they return a value.
160
* <li>
161
* The method names "get" and "set" defined in the {@link java.util.List}
162
* interface may also be applied to array instances, mapping to
163
* the static methods of the same name in the {@code Array} class.
164
* </ul>
165
*
166
* @throws NullPointerException if the value of the {@code target} or
167
* {@code methodName} property is {@code null}
168
* @throws NoSuchMethodException if a matching method is not found
169
* @throws SecurityException if a security manager exists and
170
* it denies the method invocation
171
* @throws Exception that is thrown by the invoked method
172
*
173
* @see java.lang.reflect.Method
174
*/
175
public void execute() throws Exception {
176
invoke();
177
}
178
179
@SuppressWarnings("removal")
180
Object invoke() throws Exception {
181
AccessControlContext acc = this.acc;
182
if ((acc == null) && (System.getSecurityManager() != null)) {
183
throw new SecurityException("AccessControlContext is not set");
184
}
185
try {
186
return AccessController.doPrivileged(
187
new PrivilegedExceptionAction<Object>() {
188
public Object run() throws Exception {
189
return invokeInternal();
190
}
191
},
192
acc
193
);
194
}
195
catch (PrivilegedActionException exception) {
196
throw exception.getException();
197
}
198
}
199
200
private Object invokeInternal() throws Exception {
201
Object target = getTarget();
202
String methodName = getMethodName();
203
204
if (target == null || methodName == null) {
205
throw new NullPointerException((target == null ? "target" :
206
"methodName") + " should not be null");
207
}
208
209
Object[] arguments = getArguments();
210
if (arguments == null) {
211
arguments = emptyArray;
212
} else {
213
arguments = arguments.clone();
214
}
215
if (target == Class.class && methodName.equals("forName")) {
216
final String name = (String) arguments[0];
217
if (arguments.length == 1) {
218
// Class.forName(String className) won't load classes outside
219
// of core from a class inside core. Special
220
// case this method.
221
// checkPackageAccess(name) will be called by ClassFinder
222
return ClassFinder.resolveClass(name, this.loader);
223
}
224
// The 3 args Class.forName(String className, boolean, classloader)
225
// requires getClassLoader permission, but we will be stricter and
226
// will require access to the package as well.
227
checkPackageAccess(name);
228
}
229
Class<?>[] argClasses = new Class<?>[arguments.length];
230
for(int i = 0; i < arguments.length; i++) {
231
argClasses[i] = (arguments[i] == null) ? null : arguments[i].getClass();
232
}
233
234
AccessibleObject m = null;
235
if (target instanceof Class) {
236
/*
237
For class methods, simluate the effect of a meta class
238
by taking the union of the static methods of the
239
actual class, with the instance methods of "Class.class"
240
and the overloaded "newInstance" methods defined by the
241
constructors.
242
This way "System.class", for example, will perform both
243
the static method getProperties() and the instance method
244
getSuperclass() defined in "Class.class".
245
*/
246
if (methodName.equals("new")) {
247
methodName = "newInstance";
248
}
249
// Provide a short form for array instantiation by faking an nary-constructor.
250
if (methodName.equals("newInstance") && ((Class)target).isArray()) {
251
Object result = Array.newInstance(((Class)target).getComponentType(), arguments.length);
252
for(int i = 0; i < arguments.length; i++) {
253
Array.set(result, i, arguments[i]);
254
}
255
return result;
256
}
257
if (methodName.equals("newInstance") && arguments.length != 0) {
258
// The Character class, as of 1.4, does not have a constructor
259
// which takes a String. All of the other "wrapper" classes
260
// for Java's primitive types have a String constructor so we
261
// fake such a constructor here so that this special case can be
262
// ignored elsewhere.
263
if (target == Character.class && arguments.length == 1 &&
264
argClasses[0] == String.class) {
265
return ((String)arguments[0]).charAt(0);
266
}
267
try {
268
m = ConstructorFinder.findConstructor((Class)target, argClasses);
269
}
270
catch (NoSuchMethodException exception) {
271
m = null;
272
}
273
}
274
if (m == null && target != Class.class) {
275
m = getMethod((Class)target, methodName, argClasses);
276
}
277
if (m == null) {
278
m = getMethod(Class.class, methodName, argClasses);
279
}
280
}
281
else {
282
/*
283
This special casing of arrays is not necessary, but makes files
284
involving arrays much shorter and simplifies the archiving infrastrcure.
285
The Array.set() method introduces an unusual idea - that of a static method
286
changing the state of an instance. Normally statements with side
287
effects on objects are instance methods of the objects themselves
288
and we reinstate this rule (perhaps temporarily) by special-casing arrays.
289
*/
290
if (target.getClass().isArray() &&
291
(methodName.equals("set") || methodName.equals("get"))) {
292
int index = ((Integer)arguments[0]).intValue();
293
if (methodName.equals("get")) {
294
return Array.get(target, index);
295
}
296
else {
297
Array.set(target, index, arguments[1]);
298
return null;
299
}
300
}
301
m = getMethod(target.getClass(), methodName, argClasses);
302
}
303
if (m != null) {
304
try {
305
if (m instanceof Method) {
306
return MethodUtil.invoke((Method)m, target, arguments);
307
}
308
else {
309
return ((Constructor)m).newInstance(arguments);
310
}
311
}
312
catch (IllegalAccessException iae) {
313
throw new Exception("Statement cannot invoke: " +
314
methodName + " on " + target.getClass(),
315
iae);
316
}
317
catch (InvocationTargetException ite) {
318
Throwable te = ite.getCause();
319
if (te instanceof Exception) {
320
throw (Exception)te;
321
}
322
else {
323
throw ite;
324
}
325
}
326
}
327
throw new NoSuchMethodException(toString());
328
}
329
330
String instanceName(Object instance) {
331
if (instance == null) {
332
return "null";
333
} else if (instance.getClass() == String.class) {
334
return "\""+(String)instance + "\"";
335
} else {
336
// Note: there is a minor problem with using the non-caching
337
// NameGenerator method. The return value will not have
338
// specific information about the inner class name. For example,
339
// In 1.4.2 an inner class would be represented as JList$1 now
340
// would be named Class.
341
342
return NameGenerator.unqualifiedClassName(instance.getClass());
343
}
344
}
345
346
/**
347
* Prints the value of this statement using a Java-style syntax.
348
*/
349
public String toString() {
350
// Respect a subclass's implementation here.
351
Object target = getTarget();
352
String methodName = getMethodName();
353
Object[] arguments = getArguments();
354
if (arguments == null) {
355
arguments = emptyArray;
356
}
357
StringBuilder result = new StringBuilder(instanceName(target) + "." + methodName + "(");
358
int n = arguments.length;
359
for(int i = 0; i < n; i++) {
360
result.append(instanceName(arguments[i]));
361
if (i != n -1) {
362
result.append(", ");
363
}
364
}
365
result.append(");");
366
return result.toString();
367
}
368
369
static Method getMethod(Class<?> type, String name, Class<?>... args) {
370
try {
371
return MethodFinder.findMethod(type, name, args);
372
}
373
catch (NoSuchMethodException exception) {
374
return null;
375
}
376
}
377
}
378
379