Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java
41161 views
1
/*
2
* Copyright (c) 2010, 2013, 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
26
/*
27
* This file is available under and governed by the GNU General Public
28
* License version 2 only, as published by the Free Software Foundation.
29
* However, the following notice accompanied the original version of this
30
* file, and Oracle licenses the original version of this file under the BSD
31
* license:
32
*/
33
/*
34
Copyright 2009-2013 Attila Szegedi
35
36
Redistribution and use in source and binary forms, with or without
37
modification, are permitted provided that the following conditions are
38
met:
39
* Redistributions of source code must retain the above copyright
40
notice, this list of conditions and the following disclaimer.
41
* Redistributions in binary form must reproduce the above copyright
42
notice, this list of conditions and the following disclaimer in the
43
documentation and/or other materials provided with the distribution.
44
* Neither the name of the copyright holder nor the names of
45
contributors may be used to endorse or promote products derived from
46
this software without specific prior written permission.
47
48
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
49
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
50
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
51
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
52
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
53
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
54
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
55
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
56
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
57
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
58
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
59
*/
60
61
package jdk.dynalink.beans;
62
63
import java.lang.invoke.MethodHandles.Lookup;
64
import java.util.Collections;
65
import java.util.Set;
66
import jdk.dynalink.DynamicLinkerFactory;
67
import jdk.dynalink.StandardNamespace;
68
import jdk.dynalink.StandardOperation;
69
import jdk.dynalink.linker.GuardedInvocation;
70
import jdk.dynalink.linker.GuardingDynamicLinker;
71
import jdk.dynalink.linker.LinkRequest;
72
import jdk.dynalink.linker.LinkerServices;
73
import jdk.dynalink.linker.TypeBasedGuardingDynamicLinker;
74
75
/**
76
* A linker for ordinary Java objects. Normally used as the ultimate fallback
77
* linker by the {@link DynamicLinkerFactory} so it is given the chance to link
78
* calls to all objects that no other linker recognized. Specifically, this
79
* linker will:
80
* <ul>
81
* <li>if the object is a {@link java.lang.Record record}, expose all public accessors of
82
* record components as property getters for {@link StandardOperation#GET} operations
83
* in the {@link StandardNamespace#PROPERTY} namespace;</li>
84
* <li>expose all public methods of form {@code setXxx()}, {@code getXxx()},
85
* and {@code isXxx()} as property setters and getters for
86
* {@link StandardOperation#SET} and {@link StandardOperation#GET} operations in the
87
* {@link StandardNamespace#PROPERTY} namespace, except for getters for properties
88
* with names already handled by record component getters;</li>
89
* <li>expose all public methods for retrieval for
90
* {@link StandardOperation#GET} operation in the {@link StandardNamespace#METHOD} namespace;
91
* the methods thus retrieved can then be invoked using {@link StandardOperation#CALL}.</li>
92
* <li>expose all public fields as properties, unless there are getters or
93
* setters for the properties of the same name;</li>
94
* <li> expose elements of native Java arrays, {@link java.util.List} and {@link java.util.Map} objects as
95
* {@link StandardOperation#GET} and {@link StandardOperation#SET} operations in the
96
* {@link StandardNamespace#ELEMENT} namespace;</li>
97
* <li> expose removal of elements of {@link java.util.List} and {@link java.util.Map} objects as
98
* {@link StandardOperation#REMOVE} operation in the {@link StandardNamespace#ELEMENT} namespace;</li>
99
* <li>expose a virtual property named {@code length} on Java arrays, {@link java.util.Collection} and
100
* {@link java.util.Map} objects;</li>
101
* <li>expose {@link StandardOperation#NEW} on instances of {@link StaticClass}
102
* as calls to constructors, including those static class objects that represent
103
* Java arrays (their constructors take a single {@code int} parameter
104
* representing the length of the array to create);</li>
105
* <li>expose static methods, fields, and properties of classes in a similar
106
* manner to how instance method, fields, and properties are exposed, on
107
* {@link StaticClass} objects.</li>
108
* <li>expose a virtual property named {@code static} on instances of
109
* {@link java.lang.Class} to access their {@link StaticClass}.</li>
110
* </ul>
111
* <p><strong>Overloaded method resolution</strong> is performed automatically
112
* for property setters, methods, and constructors. Additionally, manual
113
* overloaded method selection is supported by having a call site specify a name
114
* for a method that contains an explicit signature, e.g.
115
* {@code StandardOperation.GET.withNamespace(METHOD).named("parseInt(String,int)")}
116
* You can use non-qualified class names in such signatures regardless of those
117
* classes' packages, they will match any class with the same non-qualified name. You
118
* only have to use a fully qualified class name in case non-qualified class
119
* names would cause selection ambiguity (that is extremely rare). Overloaded
120
* resolution for constructors is not automatic as there is no logical place to
121
* attach that functionality to but if a language wishes to provide this
122
* functionality, it can use {@link #getConstructorMethod(Class, String)} as a
123
* useful building block for it.</p>
124
* <p><strong>Variable argument invocation</strong> is handled for both methods
125
* and constructors.</p>
126
* <p><strong>Caller sensitive methods</strong> can be linked as long as they
127
* are otherwise public and link requests have call site descriptors carrying
128
* full-strength {@link Lookup} objects and not weakened lookups or the public
129
* lookup.</p>
130
* <p><strong>The behavior for handling missing members</strong> can be
131
* customized by passing a {@link MissingMemberHandlerFactory} to the
132
* {@link BeansLinker#BeansLinker(MissingMemberHandlerFactory) constructor}.
133
* </p>
134
* <p>The class also exposes various methods for discovery of available
135
* property and method names on classes and class instances, as well as access
136
* to per-class linkers using the {@link #getLinkerForClass(Class)}
137
* method.</p>
138
*/
139
public class BeansLinker implements GuardingDynamicLinker {
140
private static final ClassValue<TypeBasedGuardingDynamicLinker> linkers = new ClassValue<>() {
141
@Override
142
protected TypeBasedGuardingDynamicLinker computeValue(final Class<?> clazz) {
143
// If ClassValue.put() were public, we could just pre-populate with these known mappings...
144
return
145
clazz == Class.class ? new ClassLinker() :
146
clazz == StaticClass.class ? new StaticClassLinker() :
147
DynamicMethod.class.isAssignableFrom(clazz) ? new DynamicMethodLinker() :
148
new BeanLinker(clazz);
149
}
150
};
151
152
private final MissingMemberHandlerFactory missingMemberHandlerFactory;
153
154
/**
155
* Creates a new beans linker. Equivalent to
156
* {@link BeansLinker#BeansLinker(MissingMemberHandlerFactory)} with
157
* {@code null} passed as the missing member handler factory, resulting in
158
* the default behavior for linking and evaluating missing members.
159
*/
160
public BeansLinker() {
161
this(null);
162
}
163
164
/**
165
* Creates a new beans linker with the specified factory for creating
166
* missing member handlers. The passed factory can be null if the default
167
* behavior is adequate. See {@link MissingMemberHandlerFactory} for details.
168
* @param missingMemberHandlerFactory a factory for creating handlers for
169
* operations on missing members.
170
*/
171
public BeansLinker(final MissingMemberHandlerFactory missingMemberHandlerFactory) {
172
this.missingMemberHandlerFactory = missingMemberHandlerFactory;
173
}
174
175
/**
176
* Returns a bean linker for a particular single class. Useful when you need
177
* to override or extend the behavior of linking for some classes in your
178
* language runtime's linker, but still want to delegate to the default
179
* behavior in some cases.
180
* @param clazz the class
181
* @return a bean linker for that class
182
*/
183
public TypeBasedGuardingDynamicLinker getLinkerForClass(final Class<?> clazz) {
184
final TypeBasedGuardingDynamicLinker staticLinker = getStaticLinkerForClass(clazz);
185
if (missingMemberHandlerFactory == null) {
186
return staticLinker;
187
}
188
return new NoSuchMemberHandlerBindingLinker(staticLinker, missingMemberHandlerFactory);
189
}
190
191
private static class NoSuchMemberHandlerBindingLinker implements TypeBasedGuardingDynamicLinker {
192
private final TypeBasedGuardingDynamicLinker linker;
193
private final MissingMemberHandlerFactory missingMemberHandlerFactory;
194
195
NoSuchMemberHandlerBindingLinker(final TypeBasedGuardingDynamicLinker linker, final MissingMemberHandlerFactory missingMemberHandlerFactory) {
196
this.linker = linker;
197
this.missingMemberHandlerFactory = missingMemberHandlerFactory;
198
}
199
200
@Override
201
public boolean canLinkType(final Class<?> type) {
202
return linker.canLinkType(type);
203
}
204
205
@Override
206
public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
207
return linker.getGuardedInvocation(linkRequest,
208
LinkerServicesWithMissingMemberHandlerFactory.get(
209
linkerServices, missingMemberHandlerFactory));
210
}
211
}
212
213
static TypeBasedGuardingDynamicLinker getStaticLinkerForClass(final Class<?> clazz) {
214
return linkers.get(clazz);
215
}
216
217
/**
218
* Returns true if the object is a Java dynamic method (e.g., one
219
* obtained through a {@code GET:METHOD} operation on a Java object or
220
* {@link StaticClass} or through
221
* {@link #getConstructorMethod(Class, String)}.
222
*
223
* @param obj the object we want to test for being a Java dynamic method.
224
* @return true if it is a dynamic method, false otherwise.
225
*/
226
public static boolean isDynamicMethod(final Object obj) {
227
return obj instanceof DynamicMethod;
228
}
229
230
/**
231
* Returns true if the object is a Java constructor (obtained through
232
* {@link #getConstructorMethod(Class, String)}}.
233
*
234
* @param obj the object we want to test for being a Java constructor.
235
* @return true if it is a constructor, false otherwise.
236
*/
237
public static boolean isDynamicConstructor(final Object obj) {
238
return obj instanceof DynamicMethod && ((DynamicMethod)obj).isConstructor();
239
}
240
241
/**
242
* Return the dynamic method of constructor of the given class and the given
243
* signature. This method is useful for exposing a functionality for
244
* selecting an overloaded constructor based on an explicit signature, as
245
* this functionality is not otherwise exposed by Dynalink as
246
* {@link StaticClass} objects act as overloaded constructors without
247
* explicit signature selection. Example usage would be:
248
* {@code getConstructorMethod(java.awt.Color.class, "int, int, int")}.
249
* @param clazz the class
250
* @param signature full signature of the constructor. Note how you can use
251
* names of primitive types, array names with normal Java notation (e.g.
252
* {@code "int[]"}), and normally you can even use unqualified class names
253
* (e.g. {@code "String, List"} instead of
254
* {@code "java.lang.String, java.util.List"} as long as they don't cause
255
* ambiguity in the specific parameter position.
256
* @return dynamic method for the constructor or null if no constructor with
257
* the specified signature exists.
258
*/
259
public static Object getConstructorMethod(final Class<?> clazz, final String signature) {
260
return StaticClassLinker.getConstructorMethod(clazz, signature);
261
}
262
263
/**
264
* Returns a set of names of all readable instance properties of a class.
265
* @param clazz the class
266
* @return a set of names of all readable instance properties of a class.
267
*/
268
public static Set<String> getReadableInstancePropertyNames(final Class<?> clazz) {
269
final TypeBasedGuardingDynamicLinker linker = getStaticLinkerForClass(clazz);
270
if(linker instanceof BeanLinker) {
271
return ((BeanLinker)linker).getReadablePropertyNames();
272
}
273
return Collections.emptySet();
274
}
275
276
/**
277
* Returns a set of names of all writable instance properties of a class.
278
* @param clazz the class
279
* @return a set of names of all writable instance properties of a class.
280
*/
281
public static Set<String> getWritableInstancePropertyNames(final Class<?> clazz) {
282
final TypeBasedGuardingDynamicLinker linker = getStaticLinkerForClass(clazz);
283
if(linker instanceof BeanLinker) {
284
return ((BeanLinker)linker).getWritablePropertyNames();
285
}
286
return Collections.emptySet();
287
}
288
289
/**
290
* Returns a set of names of all instance methods of a class.
291
* @param clazz the class
292
* @return a set of names of all instance methods of a class.
293
*/
294
public static Set<String> getInstanceMethodNames(final Class<?> clazz) {
295
final TypeBasedGuardingDynamicLinker linker = getStaticLinkerForClass(clazz);
296
if(linker instanceof BeanLinker) {
297
return ((BeanLinker)linker).getMethodNames();
298
}
299
return Collections.emptySet();
300
}
301
302
/**
303
* Returns a set of names of all readable static properties of a class.
304
* @param clazz the class
305
* @return a set of names of all readable static properties of a class.
306
*/
307
public static Set<String> getReadableStaticPropertyNames(final Class<?> clazz) {
308
return StaticClassLinker.getReadableStaticPropertyNames(clazz);
309
}
310
311
/**
312
* Returns a set of names of all writable static properties of a class.
313
* @param clazz the class
314
* @return a set of names of all writable static properties of a class.
315
*/
316
public static Set<String> getWritableStaticPropertyNames(final Class<?> clazz) {
317
return StaticClassLinker.getWritableStaticPropertyNames(clazz);
318
}
319
320
/**
321
* Returns a set of names of all static methods of a class.
322
* @param clazz the class
323
* @return a set of names of all static methods of a class.
324
*/
325
public static Set<String> getStaticMethodNames(final Class<?> clazz) {
326
return StaticClassLinker.getStaticMethodNames(clazz);
327
}
328
329
@Override
330
public GuardedInvocation getGuardedInvocation(final LinkRequest request, final LinkerServices linkerServices)
331
throws Exception {
332
final Object receiver = request.getReceiver();
333
if(receiver == null) {
334
// Can't operate on null
335
return null;
336
}
337
return getLinkerForClass(receiver.getClass()).getGuardedInvocation(request,
338
LinkerServicesWithMissingMemberHandlerFactory.get(linkerServices,
339
missingMemberHandlerFactory));
340
}
341
}
342
343