This is an automated email from the ASF dual-hosted git repository.

jianglongtao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git


The following commit(s) were added to refs/heads/master by this push:
     new b317330722f Bump GraalVM SDK version to 23.1.2 to allow 
`infra-expr-espresso` to be used under Hotspot JDK 21 (#30026)
b317330722f is described below

commit b317330722f92b18702f7e46f4749fbebe62b859
Author: Ling Hengqian <[email protected]>
AuthorDate: Tue Feb 6 22:26:55 2024 +0800

    Bump GraalVM SDK version to 23.1.2 to allow `infra-expr-espresso` to be 
used under Hotspot JDK 21 (#30026)
---
 .../common-config/builtin-algorithm/expr.cn.md     |  19 ++--
 .../common-config/builtin-algorithm/expr.en.md     |  21 ++--
 infra/expr/type/espresso/pom.xml                   |  14 ++-
 .../espresso/EspressoInlineExpressionParser.java   |  63 +++++++-----
 .../infra/expr/espresso/ReflectContext.java        |  76 ++++++++++++++
 .../infra/expr/espresso/ReflectValue.java          | 111 +++++++++++++++++++++
 .../EspressoInlineExpressionParserTest.java        |   5 +-
 pom.xml                                            |   2 +-
 8 files changed, 266 insertions(+), 45 deletions(-)

diff --git 
a/docs/document/content/user-manual/common-config/builtin-algorithm/expr.cn.md 
b/docs/document/content/user-manual/common-config/builtin-algorithm/expr.cn.md
index 8afb23e8319..ddc72556c96 100644
--- 
a/docs/document/content/user-manual/common-config/builtin-algorithm/expr.cn.md
+++ 
b/docs/document/content/user-manual/common-config/builtin-algorithm/expr.cn.md
@@ -73,7 +73,7 @@ weight = 10
 
 ## 基于 GraalVM Truffle 的 Espresso 实现的使用 Groovy 语法的行表达式
 
-此为可选实现,你需要在自有项目的 `pom.xml` 主动声明如下依赖。并且请确保自有项目通过 GraalVM CE 23.0.1 For JDK 
17.0.9 编译。
+此为可选实现,你需要在自有项目的 `pom.xml` 主动声明如下依赖。并且请确保自有项目通过 OpenJDK 21+ 或其下游发行版编译。
 
 ```xml
 <dependencies>
@@ -82,15 +82,20 @@ weight = 10
         <artifactId>shardingsphere-infra-expr-espresso</artifactId>
         <version>${shardingsphere.version}</version>
     </dependency>
+    <dependency>
+        <groupId>org.graalvm.polyglot</groupId>
+        <artifactId>polyglot</artifactId>
+        <version>23.1.2</version>
+    </dependency>
+    <dependency>
+        <groupId>org.graalvm.polyglot</groupId>
+        <artifactId>java-community</artifactId>
+        <version>23.1.2</version>
+        <type>pom</type>
+    </dependency>
 </dependencies>
 ```
 
-用户必须通过 GraalVM Updater 安装 Espresso 组件,即在 bash 执行如下命令
-
-```bash
-gu install espresso
-```
-
 `ESPRESSO` 仍为实验性模块,其允许在 GraalVM Native Image 下通过 GraalVM Truffle 的 Espresso 
实现来使用带 Groovy 语法的行表达式。
 
 语法部分与 `GROOVY` 实现规则相同。
diff --git 
a/docs/document/content/user-manual/common-config/builtin-algorithm/expr.en.md 
b/docs/document/content/user-manual/common-config/builtin-algorithm/expr.en.md
index 16dc74a236f..4b9bf2fa800 100644
--- 
a/docs/document/content/user-manual/common-config/builtin-algorithm/expr.en.md
+++ 
b/docs/document/content/user-manual/common-config/builtin-algorithm/expr.en.md
@@ -82,8 +82,8 @@ Example:
 
 ## Row Value Expressions that uses the Groovy syntax based on GraalVM 
Truffle's Espresso implementation
 
-This is an optional implementation, and you need to actively declare the 
following dependencies in the `pom.xml` of your own project.
-And make sure your own project is compiled with GraalVM CE 23.0.1 For JDK 
17.0.9.
+This is an optional implementation. You need to actively declare the following 
dependencies in the `pom.xml` of your own project. 
+And please make sure your own projects are compiled with OpenJDK 21+ or its 
downstream distribution.
 
 ```xml
 <dependencies>
@@ -92,15 +92,20 @@ And make sure your own project is compiled with GraalVM CE 
23.0.1 For JDK 17.0.9
         <artifactId>shardingsphere-infra-expr-espresso</artifactId>
         <version>${shardingsphere.version}</version>
     </dependency>
+    <dependency>
+        <groupId>org.graalvm.polyglot</groupId>
+        <artifactId>polyglot</artifactId>
+        <version>23.1.2</version>
+    </dependency>
+    <dependency>
+        <groupId>org.graalvm.polyglot</groupId>
+        <artifactId>java-community</artifactId>
+        <version>23.1.2</version>
+        <type>pom</type>
+    </dependency>
 </dependencies>
 ```
 
-The user must install the Espresso component via GraalVM Updater, i.e. execute 
the following command in bash
-
-```bash
-gu install espresso
-```
-
 `ESPRESSO` is still an experimental module that allows the use of Row Value 
Expressions with Groovy syntax under GraalVM
 Native Image through the Espresso implementation of GraalVM Truffle.
 
diff --git a/infra/expr/type/espresso/pom.xml b/infra/expr/type/espresso/pom.xml
index 4b04bfdb79f..d3681f30bbd 100644
--- a/infra/expr/type/espresso/pom.xml
+++ b/infra/expr/type/espresso/pom.xml
@@ -50,9 +50,17 @@
         </dependency>
         
         <dependency>
-            <groupId>org.graalvm.truffle</groupId>
-            <artifactId>truffle-api</artifactId>
+            <groupId>org.graalvm.polyglot</groupId>
+            <artifactId>polyglot</artifactId>
             <version>${graal-sdk.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.graalvm.polyglot</groupId>
+            <artifactId>java-community</artifactId>
+            <version>${graal-sdk.version}</version>
+            <type>pom</type>
+            <scope>test</scope>
         </dependency>
     </dependencies>
     
@@ -69,7 +77,7 @@
                         </goals>
                         <phase>process-resources</phase>
                         <configuration>
-                            
<outputDirectory>${project.build.directory}/classes/espresso-need-libs</outputDirectory>
+                            
<outputDirectory>${project.build.directory}/classes/build/libs/</outputDirectory>
                             <artifactItems>
                                 <artifactItem>
                                     <groupId>org.apache.groovy</groupId>
diff --git 
a/infra/expr/type/espresso/src/main/java/org/apache/shardingsphere/infra/expr/espresso/EspressoInlineExpressionParser.java
 
b/infra/expr/type/espresso/src/main/java/org/apache/shardingsphere/infra/expr/espresso/EspressoInlineExpressionParser.java
index 4aa6871d354..748d79d151a 100644
--- 
a/infra/expr/type/espresso/src/main/java/org/apache/shardingsphere/infra/expr/espresso/EspressoInlineExpressionParser.java
+++ 
b/infra/expr/type/espresso/src/main/java/org/apache/shardingsphere/infra/expr/espresso/EspressoInlineExpressionParser.java
@@ -22,8 +22,6 @@ import com.google.common.collect.Sets;
 import groovy.lang.GroovyShell;
 import org.apache.shardingsphere.infra.expr.spi.InlineExpressionParser;
 import org.apache.shardingsphere.infra.util.groovy.GroovyUtils;
-import org.graalvm.polyglot.Context;
-import org.graalvm.polyglot.Value;
 
 import java.io.File;
 import java.net.URL;
@@ -45,19 +43,10 @@ public final class EspressoInlineExpressionParser 
implements InlineExpressionPar
     
     private String inlineExpression;
     
-    /**
-     * TODO <a href="https://github.com/oracle/graal/issues/4555";>espressoHome 
not defined</a> not yet closed.
-     * Maybe sometimes we need `.option("java.Properties.org.graalvm.home", 
System.getenv("JAVA_HOME"))`
-     *
-     * @see org.graalvm.polyglot.Context
-     */
-    private final Context context = Context.newBuilder()
-            .allowAllAccess(true)
-            .option("java.Classpath", JAVA_CLASSPATH)
-            .build();
+    private final ReflectContext context = new ReflectContext(JAVA_CLASSPATH);
     
     static {
-        URL resource = 
EspressoInlineExpressionParser.class.getClassLoader().getResource("espresso-need-libs");
+        URL resource = ClassLoader.getSystemResource("build" + File.separator 
+ "libs");
         String dir = null == resource ? null : resource.getPath();
         JAVA_CLASSPATH = dir + File.separator + "groovy.jar";
     }
@@ -84,11 +73,11 @@ public final class EspressoInlineExpressionParser 
implements InlineExpressionPar
     
     @Override
     public List<String> splitAndEvaluate() {
-        return Strings.isNullOrEmpty(inlineExpression) ? 
Collections.emptyList() : 
flatten(evaluate(GroovyUtils.split(handlePlaceHolder(inlineExpression)), 
context));
+        return Strings.isNullOrEmpty(inlineExpression) ? 
Collections.emptyList() : 
flatten(evaluate(GroovyUtils.split(handlePlaceHolder(inlineExpression))));
     }
     
-    private List<Value> evaluate(final List<String> inlineExpressions, final 
Context context) {
-        List<Value> result = new ArrayList<>(inlineExpressions.size());
+    private List<ReflectValue> evaluate(final List<String> inlineExpressions) {
+        List<ReflectValue> result = new ArrayList<>(inlineExpressions.size());
         for (String each : inlineExpressions) {
             StringBuilder expression = new 
StringBuilder(handlePlaceHolder(each));
             if (!each.startsWith("\"")) {
@@ -97,12 +86,12 @@ public final class EspressoInlineExpressionParser 
implements InlineExpressionPar
             if (!each.endsWith("\"")) {
                 expression.append('"');
             }
-            result.add(evaluate(expression.toString(), context));
+            result.add(evaluate(expression.toString()));
         }
         return result;
     }
     
-    private Value evaluate(final String expression, final Context context) {
+    private ReflectValue evaluate(final String expression) {
         return context.getBindings("java")
                 .getMember(GroovyShell.class.getName())
                 .newInstance()
@@ -110,19 +99,32 @@ public final class EspressoInlineExpressionParser 
implements InlineExpressionPar
                 .invokeMember("run");
     }
     
-    private List<String> flatten(final List<Value> segments) {
+    /**
+     * Flatten.
+     *
+     * @param segments Actually corresponds to some class instance of {@link 
java.lang.Object}.
+     *                 This Object may or may not correspond to a class 
instance of {@link groovy.lang.GString}.
+     * @return List of String
+     */
+    private List<String> flatten(final List<ReflectValue> segments) {
         List<String> result = new ArrayList<>();
-        for (Value each : segments) {
+        for (ReflectValue each : segments) {
             if (!each.isString()) {
                 result.addAll(assemblyCartesianSegments(each));
             } else {
-                result.add(each.toString());
+                result.add(each.toStringForValue());
             }
         }
         return result;
     }
     
-    private List<String> assemblyCartesianSegments(final Value segment) {
+    /**
+     * Assembly cartesian segments.
+     *
+     * @param segment Actually corresponds to a class instance of {@link 
groovy.lang.GString}.
+     * @return List of String
+     */
+    private List<String> assemblyCartesianSegments(final ReflectValue segment) 
{
         Set<List<String>> cartesianValues = getCartesianValues(segment);
         List<String> result = new ArrayList<>(cartesianValues.size());
         for (List<String> each : cartesianValues) {
@@ -131,8 +133,14 @@ public final class EspressoInlineExpressionParser 
implements InlineExpressionPar
         return result;
     }
     
+    /**
+     * Get cartesian values.
+     *
+     * @param segment Actually corresponds to a class instance of {@link 
groovy.lang.GString}.
+     * @return A Set consisting of a List of Strings
+     */
     @SuppressWarnings("unchecked")
-    private Set<List<String>> getCartesianValues(final Value segment) {
+    private Set<List<String>> getCartesianValues(final ReflectValue segment) {
         Object[] temp = segment.invokeMember("getValues").as(Object[].class);
         List<Set<String>> result = new ArrayList<>(temp.length);
         for (Object each : temp) {
@@ -148,7 +156,14 @@ public final class EspressoInlineExpressionParser 
implements InlineExpressionPar
         return Sets.cartesianProduct(result);
     }
     
-    private String assemblySegment(final List<String> cartesianValue, final 
Value segment) {
+    /**
+     * Assembly segment.
+     *
+     * @param cartesianValue List of String
+     * @param segment        Actually corresponds to a class instance of 
{@link groovy.lang.GString}.
+     * @return {@link java.lang.String}
+     */
+    private String assemblySegment(final List<String> cartesianValue, final 
ReflectValue segment) {
         String[] temp = segment.invokeMember("getStrings").as(String[].class);
         StringBuilder result = new StringBuilder();
         for (int i = 0; i < temp.length; i++) {
diff --git 
a/infra/expr/type/espresso/src/main/java/org/apache/shardingsphere/infra/expr/espresso/ReflectContext.java
 
b/infra/expr/type/espresso/src/main/java/org/apache/shardingsphere/infra/expr/espresso/ReflectContext.java
new file mode 100644
index 00000000000..a187382d943
--- /dev/null
+++ 
b/infra/expr/type/espresso/src/main/java/org/apache/shardingsphere/infra/expr/espresso/ReflectContext.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.infra.expr.espresso;
+
+import lombok.SneakyThrows;
+
+/**
+ * Reflect Context.
+ * Avoid using JDK21 bytecode during compilation. Refer to 
`org.graalvm.polyglot.Context`.
+ */
+public final class ReflectContext {
+    
+    private static final String CONTEXT_CLASS_NAME = 
"org.graalvm.polyglot.Context";
+    
+    private final Object contextInstance;
+    
+    /**
+     * This method is a simulation of the following operation.
+     * // CHECKSTYLE:OFF
+     * <pre class="code">
+     * private final Context context = Context.newBuilder()
+     *             .allowAllAccess(true)
+     *             .option("java.Classpath", JAVA_CLASSPATH)
+     *             .build();
+     * </pre>
+     * // CHECKSTYLE:ON
+     * TODO <a 
href="https://github.com/oracle/graal/issues/4555";>oracle/graal#4555</a> not 
yet closed.
+     * Maybe sometimes shardingsphere need 
`.option("java.Properties.org.graalvm.home", System.getenv("JAVA_HOME")).
+     *
+     * @param javaClassPath java class path
+     */
+    @SneakyThrows
+    public ReflectContext(final String javaClassPath) {
+        Object builderInstance = Class.forName(CONTEXT_CLASS_NAME)
+                .getMethod("newBuilder", String[].class)
+                .invoke(null, (Object) new String[]{});
+        builderInstance = builderInstance.getClass()
+                .getMethod("allowAllAccess", boolean.class)
+                .invoke(builderInstance, true);
+        builderInstance = builderInstance.getClass()
+                .getMethod("option", String.class, String.class)
+                .invoke(builderInstance, "java.Classpath", javaClassPath);
+        contextInstance = builderInstance.getClass()
+                .getMethod("build")
+                .invoke(builderInstance);
+    }
+    
+    /**
+     * Returns a value that represents the top-most bindings of a language.
+     *
+     * @param languageId languageId
+     * @return {@link 
org.apache.shardingsphere.infra.expr.espresso.ReflectValue}
+     */
+    @SneakyThrows
+    public ReflectValue getBindings(final String languageId) {
+        Object valueInstance = Class.forName(CONTEXT_CLASS_NAME)
+                .getMethod("getBindings", String.class)
+                .invoke(contextInstance, languageId);
+        return new ReflectValue(valueInstance);
+    }
+}
diff --git 
a/infra/expr/type/espresso/src/main/java/org/apache/shardingsphere/infra/expr/espresso/ReflectValue.java
 
b/infra/expr/type/espresso/src/main/java/org/apache/shardingsphere/infra/expr/espresso/ReflectValue.java
new file mode 100644
index 00000000000..e2290e6e598
--- /dev/null
+++ 
b/infra/expr/type/espresso/src/main/java/org/apache/shardingsphere/infra/expr/espresso/ReflectValue.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.infra.expr.espresso;
+
+import lombok.SneakyThrows;
+
+/**
+ * Reflect Value.
+ * Avoid using JDK21 bytecode during compilation. Refer to 
`org.graalvm.polyglot.Value`.
+ */
+public class ReflectValue {
+    
+    private static final String VALUE_CLASS_NAME = 
"org.graalvm.polyglot.Value";
+    
+    private final Object valueInstance;
+    
+    public ReflectValue(final Object valueInstance) {
+        this.valueInstance = valueInstance;
+    }
+    
+    /**
+     * Returns the member with a given identifier or null if the member does 
not exist.
+     * @param identifier the member identifier
+     * @return {@link 
org.apache.shardingsphere.infra.expr.espresso.ReflectValue}
+     */
+    @SneakyThrows
+    public ReflectValue getMember(final String identifier) {
+        Object resultValueInstance = Class.forName(VALUE_CLASS_NAME)
+                .getMethod("getMember", String.class)
+                .invoke(valueInstance, identifier);
+        return new ReflectValue(resultValueInstance);
+    }
+    
+    /**
+     * Instantiates this value if it can be instantiated.
+     * @param arguments the arguments
+     * @return {@link 
org.apache.shardingsphere.infra.expr.espresso.ReflectValue}
+     */
+    @SneakyThrows
+    public ReflectValue newInstance(final Object... arguments) {
+        Object resultValueInstance = Class.forName(VALUE_CLASS_NAME)
+                .getMethod("newInstance", Object[].class)
+                .invoke(valueInstance, (Object) arguments);
+        return new ReflectValue(resultValueInstance);
+    }
+    
+    /**
+     * Invokes the given member of this value.
+     * @param identifier the member identifier to invoke
+     * @param arguments the invocation arguments
+     * @return {@link 
org.apache.shardingsphere.infra.expr.espresso.ReflectValue}
+     */
+    @SneakyThrows
+    public ReflectValue invokeMember(final String identifier, final Object... 
arguments) {
+        Object resultValueInstance = Class.forName(VALUE_CLASS_NAME)
+                .getMethod("invokeMember", String.class, Object[].class)
+                .invoke(valueInstance, identifier, arguments);
+        return new ReflectValue(resultValueInstance);
+    }
+    
+    /**
+     * Returns true if this value represents a string.
+     * @return Returns true if this value represents a string.
+     */
+    @SneakyThrows
+    public boolean isString() {
+        return (boolean) Class.forName(VALUE_CLASS_NAME)
+                .getMethod("isString")
+                .invoke(valueInstance);
+    }
+    
+    /**
+     * Maps a polyglot value to a value with a given Java target type.
+     * @param targetType the target Java type to map
+     * @param <T> target type
+     * @return target type
+     */
+    @SneakyThrows
+    @SuppressWarnings("unchecked")
+    public <T> T as(final Class<T> targetType) {
+        return (T) Class.forName(VALUE_CLASS_NAME)
+                .getMethod("as", Class.class)
+                .invoke(valueInstance, targetType);
+    }
+    
+    /**
+     * Converts this value to a human-readable string.
+     * @return {@link String}
+     */
+    @SneakyThrows
+    public String toStringForValue() {
+        return (String) Class.forName(VALUE_CLASS_NAME)
+                .getMethod("toString")
+                .invoke(valueInstance);
+    }
+}
diff --git 
a/infra/expr/type/espresso/src/test/java/org/apache/shardingsphere/infra/expr/espresso/EspressoInlineExpressionParserTest.java
 
b/infra/expr/type/espresso/src/test/java/org/apache/shardingsphere/infra/expr/espresso/EspressoInlineExpressionParserTest.java
index 594e58b51da..325bdbf7f00 100644
--- 
a/infra/expr/type/espresso/src/test/java/org/apache/shardingsphere/infra/expr/espresso/EspressoInlineExpressionParserTest.java
+++ 
b/infra/expr/type/espresso/src/test/java/org/apache/shardingsphere/infra/expr/espresso/EspressoInlineExpressionParserTest.java
@@ -20,8 +20,9 @@ package org.apache.shardingsphere.infra.expr.espresso;
 import org.apache.shardingsphere.infra.expr.spi.InlineExpressionParser;
 import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
 import org.apache.shardingsphere.test.util.PropertiesBuilder;
-import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledForJreRange;
+import org.junit.jupiter.api.condition.JRE;
 
 import java.util.Collections;
 import java.util.List;
@@ -32,7 +33,7 @@ import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
-@Disabled("Unit tests for this class only run on GraalVM CE 23.0.1 For JDK17. 
Wait for https://github.com/oracle/graal/issues/7500 .")
+@EnabledForJreRange(min = JRE.JAVA_21)
 class EspressoInlineExpressionParserTest {
     
     @Test
diff --git a/pom.xml b/pom.xml
index 14523adb04a..a6978378cf0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -146,7 +146,7 @@
         <testcontainers.version>1.19.3</testcontainers.version>
         <commons-csv.version>1.9.0</commons-csv.version>
         
-        <graal-sdk.version>21.2.0</graal-sdk.version>
+        <graal-sdk.version>23.1.2</graal-sdk.version>
         
         <!-- 3rd party library plugin versions -->
         <protobuf-maven-plugin.version>0.6.1</protobuf-maven-plugin.version>

Reply via email to