View Javadoc
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 }