1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.shardingsphere.infra.expr.espresso;
19
20 import lombok.RequiredArgsConstructor;
21 import lombok.SneakyThrows;
22
23 import java.util.stream.Stream;
24
25 /**
26 * Reflect Value.
27 * Avoid using JDK21 bytecode during compilation. Refer to `org.graalvm.polyglot.Value`.
28 */
29 @RequiredArgsConstructor
30 public class ReflectValue {
31
32 private static final String VALUE_CLASS_NAME = "org.graalvm.polyglot.Value";
33
34 private final Object valueInstance;
35
36 /**
37 * Returns the member with a given identifier or null if the member does not exist.
38 * @param identifier the member identifier
39 * @return {@link org.apache.shardingsphere.infra.expr.espresso.ReflectValue}
40 */
41 @SneakyThrows
42 public ReflectValue getMember(final String identifier) {
43 Object resultValueInstance = Class.forName(VALUE_CLASS_NAME)
44 .getMethod("getMember", String.class)
45 .invoke(valueInstance, identifier);
46 return new ReflectValue(resultValueInstance);
47 }
48
49 /**
50 * Instantiates this value if it can be instantiated.
51 * @param arguments the arguments
52 * @return {@link org.apache.shardingsphere.infra.expr.espresso.ReflectValue}
53 */
54 @SneakyThrows
55 public ReflectValue newInstance(final Object... arguments) {
56 Object resultValueInstance = Class.forName(VALUE_CLASS_NAME)
57 .getMethod("newInstance", Object[].class)
58 .invoke(valueInstance, new Object[]{Stream.of(arguments).toArray()});
59 return new ReflectValue(resultValueInstance);
60 }
61
62 /**
63 * Invokes the given member of this value.
64 * @param identifier the member identifier to invoke
65 * @param arguments the invocation arguments
66 * @return {@link org.apache.shardingsphere.infra.expr.espresso.ReflectValue}
67 */
68 @SneakyThrows
69 public ReflectValue invokeMember(final String identifier, final Object... arguments) {
70 Object resultValueInstance = Class.forName(VALUE_CLASS_NAME)
71 .getMethod("invokeMember", String.class, Object[].class)
72 .invoke(valueInstance, identifier, arguments);
73 return new ReflectValue(resultValueInstance);
74 }
75
76 /**
77 * Returns true if this value represents a string.
78 * @return Returns true if this value represents a string.
79 */
80 @SneakyThrows
81 public boolean isString() {
82 return (boolean) Class.forName(VALUE_CLASS_NAME)
83 .getMethod("isString")
84 .invoke(valueInstance);
85 }
86
87 /**
88 * Maps a polyglot value to a value with a given Java target type.
89 * @param targetType the target Java type to map
90 * @param <T> target type
91 * @return target type
92 */
93 @SneakyThrows
94 @SuppressWarnings("unchecked")
95 public <T> T as(final Class<T> targetType) {
96 return (T) Class.forName(VALUE_CLASS_NAME)
97 .getMethod("as", Class.class)
98 .invoke(valueInstance, targetType);
99 }
100 }