You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2022/08/28 15:17:46 UTC

[groovy] branch GROOVY_4_0_X updated (a82f0f2fee -> 2c7ce677fe)

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

sunlan pushed a change to branch GROOVY_4_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git


    from a82f0f2fee GROOVY-10731: run `MarkupTemplateEngine` type-checked not static compile
     new 09b084a720 GROOVY-10730: Bump Gradle to 7.5.1
     new 058b2f95b0 GROOVY-10730: Remove the jdk16+ add-opens jvm args
     new 2c7ce677fe GROOVY-10730: Fix accessing `clone` illegally

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../groovy/org.apache.groovy-doc-aggregator.gradle |   5 +-
 .../main/groovy/org.apache.groovy-tested.gradle    |   2 +-
 gradle.properties                                  |   8 +-
 gradle/wrapper/gradle-wrapper.jar                  | Bin 59203 -> 60756 bytes
 gradle/wrapper/gradle-wrapper.properties           |   2 +-
 gradlew                                            | 263 +++++++++++++--------
 gradlew.bat                                        |  14 +-
 src/main/java/groovy/lang/MetaClassImpl.java       |  22 +-
 .../org/codehaus/groovy/runtime/ArrayUtil.java     |  30 +++
 .../org/codehaus/groovy/runtime/InvokerHelper.java |   4 +
 .../org/codehaus/groovy/vmplugin/v8/Selector.java  |  11 +
 src/test/groovy/inspect/InspectorTest.java         |  49 ++--
 .../groovy/transform/ImmutableTransformTest.groovy |   8 +-
 .../groovy/text/StreamingTemplateEngineTest.groovy |  80 ++++---
 14 files changed, 300 insertions(+), 198 deletions(-)


[groovy] 01/03: GROOVY-10730: Bump Gradle to 7.5.1

Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a commit to branch GROOVY_4_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 09b084a7203d4e95bd36348fed5734d59858c26d
Author: Paul King <pa...@asert.com.au>
AuthorDate: Sat Aug 27 21:15:37 2022 +0800

    GROOVY-10730: Bump Gradle to 7.5.1
    
    (cherry picked from commit 69b88f0bfd6b430358daf611f3f420cab4a29ce0)
---
 .../groovy/org.apache.groovy-doc-aggregator.gradle |   5 +-
 .../main/groovy/org.apache.groovy-tested.gradle    |   8 +-
 gradle.properties                                  |   8 +-
 gradle/wrapper/gradle-wrapper.jar                  | Bin 59203 -> 60756 bytes
 gradle/wrapper/gradle-wrapper.properties           |   2 +-
 gradlew                                            | 263 +++++++++++++--------
 gradlew.bat                                        |  14 +-
 src/test/groovy/inspect/InspectorTest.java         |  37 +--
 8 files changed, 204 insertions(+), 133 deletions(-)

diff --git a/buildSrc/src/main/groovy/org.apache.groovy-doc-aggregator.gradle b/buildSrc/src/main/groovy/org.apache.groovy-doc-aggregator.gradle
index 617e4c743d..3d633fc997 100644
--- a/buildSrc/src/main/groovy/org.apache.groovy-doc-aggregator.gradle
+++ b/buildSrc/src/main/groovy/org.apache.groovy-doc-aggregator.gradle
@@ -87,6 +87,9 @@ def groovydocAll = tasks.register("groovydocAll", Groovydoc) {
     destinationDir = file("${buildDir}/allgroovydoc")
     source = configurations.allSources
     classpath = configurations.allSourcesRuntimeClasspath
+    includeAuthor = false
+    processScripts = false
+    includeMainForScripts = false
 }
 
 def groovydocAllJar = tasks.register("groovydocAllJar", Jar) {
@@ -101,4 +104,4 @@ class JavadocClasspathCompatibilityRule implements AttributeCompatibilityRule<Us
             details.compatible()
         }
     }
-}
\ No newline at end of file
+}
diff --git a/buildSrc/src/main/groovy/org.apache.groovy-tested.gradle b/buildSrc/src/main/groovy/org.apache.groovy-tested.gradle
index 8194d2ab8f..dfa7479e60 100644
--- a/buildSrc/src/main/groovy/org.apache.groovy-tested.gradle
+++ b/buildSrc/src/main/groovy/org.apache.groovy-tested.gradle
@@ -32,12 +32,18 @@ sourceSets {
     }
 }
 
+// TODO remove the jdk16+ add-opens jvm args once offending code/tests are fixed
+// https://docs.gradle.org/7.5/userguide/upgrading_version_7.html#removes_implicit_add_opens_for_test_workers
 tasks.withType(Test).configureEach {
     def fs = objects.newInstance(TestServices).fileSystemOperations
     def grapeDirectory = new File(temporaryDir, "grape")
     def jdk8 = ['-XX:+UseConcMarkSweepGC']
     def jdk9 = ['-Djava.locale.providers=COMPAT,SPI']
 //        def jdk9 = ['-Djava.locale.providers=COMPAT,SPI', '--illegal-access=debug']
+    if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_16)) {
+        jdk9 += ["--add-opens=java.base/java.lang=ALL-UNNAMED",
+                 "--add-opens=java.base/java.util=ALL-UNNAMED"]
+    }
     def common = ['-ea', "-Xms${groovyJUnit_ms}", "-Xmx${groovyJUnit_mx}", "-Duser.language=en"]
     if (JavaVersion.current().isJava9Compatible()) {
         jvmArgs(*common, *jdk9)
@@ -118,4 +124,4 @@ Closure buildExcludeFilter(boolean legacyTestSuite) {
 interface TestServices {
     @Inject
     FileSystemOperations getFileSystemOperations()
-}
\ No newline at end of file
+}
diff --git a/gradle.properties b/gradle.properties
index 65eb251c61..1e0082e429 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -13,15 +13,15 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-groovyVersion=4.0.5-SNAPSHOT
+groovyVersion=5.0.0-SNAPSHOT
 # bundle version format: major('.'minor('.'micro('.'qualifier)?)?)? (first 3 only digits)
-groovyBundleVersion=4.0.5.SNAPSHOT
+groovyBundleVersion=5.0.0.SNAPSHOT
 
 groovyTargetBytecodeVersion=1.8
 targetJavaVersion=8
 
-binaryCompatibilityBaseline=3.0.9
-gradle_version=7.4.2
+binaryCompatibilityBaseline=4.0.0
+gradle_version=7.5.1
 
 groovyJUnit_ms=512m
 groovyJUnit_mx=2g
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index e708b1c023..249e5832f0 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index aa991fceae..ae04661ee7 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 4f906e0c81..a69d9cb6c2 100755
--- a/gradlew
+++ b/gradlew
@@ -1,7 +1,7 @@
-#!/usr/bin/env sh
+#!/bin/sh
 
 #
-# Copyright 2015 the original author or authors.
+# Copyright © 2015-2021 the original authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -17,67 +17,101 @@
 #
 
 ##############################################################################
-##
-##  Gradle start up script for UN*X
-##
+#
+#   Gradle start up script for POSIX generated by Gradle.
+#
+#   Important for running:
+#
+#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+#       noncompliant, but you have some other compliant shell such as ksh or
+#       bash, then to run this script, type that shell name before the whole
+#       command line, like:
+#
+#           ksh Gradle
+#
+#       Busybox and similar reduced shells will NOT work, because this script
+#       requires all of these POSIX shell features:
+#         * functions;
+#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+#         * compound commands having a testable exit status, especially «case»;
+#         * various built-in commands including «command», «set», and «ulimit».
+#
+#   Important for patching:
+#
+#   (2) This script targets any POSIX shell, so it avoids extensions provided
+#       by Bash, Ksh, etc; in particular arrays are avoided.
+#
+#       The "traditional" practice of packing multiple parameters into a
+#       space-separated string is a well documented source of bugs and security
+#       problems, so this is (mostly) avoided, by progressively accumulating
+#       options in "$@", and eventually passing that to Java.
+#
+#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+#       see the in-line comments for details.
+#
+#       There are tweaks for specific operating systems such as AIX, CygWin,
+#       Darwin, MinGW, and NonStop.
+#
+#   (3) This script is generated from the Groovy template
+#       https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+#       within the Gradle project.
+#
+#       You can find Gradle at https://github.com/gradle/gradle/.
+#
 ##############################################################################
 
 # Attempt to set APP_HOME
+
 # Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
-    ls=`ls -ld "$PRG"`
-    link=`expr "$ls" : '.*-> \(.*\)$'`
-    if expr "$link" : '/.*' > /dev/null; then
-        PRG="$link"
-    else
-        PRG=`dirname "$PRG"`"/$link"
-    fi
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+    APP_HOME=${app_path%"${app_path##*/}"}  # leaves a trailing /; empty if no leading path
+    [ -h "$app_path" ]
+do
+    ls=$( ls -ld "$app_path" )
+    link=${ls#*' -> '}
+    case $link in             #(
+      /*)   app_path=$link ;; #(
+      *)    app_path=$APP_HOME$link ;;
+    esac
 done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
+
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
 
 APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
+APP_BASE_NAME=${0##*/}
 
 # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
 DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
 
 # Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
+MAX_FD=maximum
 
 warn () {
     echo "$*"
-}
+} >&2
 
 die () {
     echo
     echo "$*"
     echo
     exit 1
-}
+} >&2
 
 # OS specific support (must be 'true' or 'false').
 cygwin=false
 msys=false
 darwin=false
 nonstop=false
-case "`uname`" in
-  CYGWIN* )
-    cygwin=true
-    ;;
-  Darwin* )
-    darwin=true
-    ;;
-  MINGW* )
-    msys=true
-    ;;
-  NONSTOP* )
-    nonstop=true
-    ;;
+case "$( uname )" in                #(
+  CYGWIN* )         cygwin=true  ;; #(
+  Darwin* )         darwin=true  ;; #(
+  MSYS* | MINGW* )  msys=true    ;; #(
+  NONSTOP* )        nonstop=true ;;
 esac
 
 CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
 if [ -n "$JAVA_HOME" ] ; then
     if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
         # IBM's JDK on AIX uses strange locations for the executables
-        JAVACMD="$JAVA_HOME/jre/sh/java"
+        JAVACMD=$JAVA_HOME/jre/sh/java
     else
-        JAVACMD="$JAVA_HOME/bin/java"
+        JAVACMD=$JAVA_HOME/bin/java
     fi
     if [ ! -x "$JAVACMD" ] ; then
         die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
 location of your Java installation."
     fi
 else
-    JAVACMD="java"
+    JAVACMD=java
     which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
 
 Please set the JAVA_HOME variable in your environment to match the
@@ -106,80 +140,101 @@ location of your Java installation."
 fi
 
 # Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
-    MAX_FD_LIMIT=`ulimit -H -n`
-    if [ $? -eq 0 ] ; then
-        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
-            MAX_FD="$MAX_FD_LIMIT"
-        fi
-        ulimit -n $MAX_FD
-        if [ $? -ne 0 ] ; then
-            warn "Could not set maximum file descriptor limit: $MAX_FD"
-        fi
-    else
-        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
-    fi
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+    case $MAX_FD in #(
+      max*)
+        MAX_FD=$( ulimit -H -n ) ||
+            warn "Could not query maximum file descriptor limit"
+    esac
+    case $MAX_FD in  #(
+      '' | soft) :;; #(
+      *)
+        ulimit -n "$MAX_FD" ||
+            warn "Could not set maximum file descriptor limit to $MAX_FD"
+    esac
 fi
 
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
-    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
+# Collect all arguments for the java command, stacking in reverse order:
+#   * args from the command line
+#   * the main class name
+#   * -classpath
+#   * -D...appname settings
+#   * --module-path (only if needed)
+#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
 
 # For Cygwin or MSYS, switch paths to Windows format before running java
-if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
-    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
-    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
-
-    JAVACMD=`cygpath --unix "$JAVACMD"`
-
-    # We build the pattern for arguments to be converted via cygpath
-    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
-    SEP=""
-    for dir in $ROOTDIRSRAW ; do
-        ROOTDIRS="$ROOTDIRS$SEP$dir"
-        SEP="|"
-    done
-    OURCYGPATTERN="(^($ROOTDIRS))"
-    # Add a user-defined pattern to the cygpath arguments
-    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
-        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
-    fi
+if "$cygwin" || "$msys" ; then
+    APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+    CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+    JAVACMD=$( cygpath --unix "$JAVACMD" )
+
     # Now convert the arguments - kludge to limit ourselves to /bin/sh
-    i=0
-    for arg in "$@" ; do
-        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
-        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
-
-        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
-            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
-        else
-            eval `echo args$i`="\"$arg\""
+    for arg do
+        if
+            case $arg in                                #(
+              -*)   false ;;                            # don't mess with options #(
+              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath
+                    [ -e "$t" ] ;;                      #(
+              *)    false ;;
+            esac
+        then
+            arg=$( cygpath --path --ignore --mixed "$arg" )
         fi
-        i=`expr $i + 1`
+        # Roll the args list around exactly as many times as the number of
+        # args, so each arg winds up back in the position where it started, but
+        # possibly modified.
+        #
+        # NB: a `for` loop captures its iteration list before it begins, so
+        # changing the positional parameters here affects neither the number of
+        # iterations, nor the values presented in `arg`.
+        shift                   # remove old arg
+        set -- "$@" "$arg"      # push replacement arg
     done
-    case $i in
-        0) set -- ;;
-        1) set -- "$args0" ;;
-        2) set -- "$args0" "$args1" ;;
-        3) set -- "$args0" "$args1" "$args2" ;;
-        4) set -- "$args0" "$args1" "$args2" "$args3" ;;
-        5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
-        6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
-        7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
-        8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
-        9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
-    esac
 fi
 
-# Escape application args
-save () {
-    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
-    echo " "
-}
-APP_ARGS=`save "$@"`
+# Collect all arguments for the java command;
+#   * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+#     shell script including quotes and variable substitutions, so put them in
+#     double quotes to make sure that they get re-expanded; and
+#   * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+        "-Dorg.gradle.appname=$APP_BASE_NAME" \
+        -classpath "$CLASSPATH" \
+        org.gradle.wrapper.GradleWrapperMain \
+        "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+    die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+#   readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+#   set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
 
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+eval "set -- $(
+        printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+        xargs -n1 |
+        sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+        tr '\n' ' '
+    )" '"$@"'
 
 exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
index 107acd32c4..f127cfd49d 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -14,7 +14,7 @@
 @rem limitations under the License.
 @rem
 
-@if "%DEBUG%" == "" @echo off
+@if "%DEBUG%"=="" @echo off
 @rem ##########################################################################
 @rem
 @rem  Gradle startup script for Windows
@@ -25,7 +25,7 @@
 if "%OS%"=="Windows_NT" setlocal
 
 set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
+if "%DIRNAME%"=="" set DIRNAME=.
 set APP_BASE_NAME=%~n0
 set APP_HOME=%DIRNAME%
 
@@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
 
 set JAVA_EXE=java.exe
 %JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto execute
+if %ERRORLEVEL% equ 0 goto execute
 
 echo.
 echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -75,13 +75,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
 
 :end
 @rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
+if %ERRORLEVEL% equ 0 goto mainEnd
 
 :fail
 rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
 rem the _cmd.exe /c_ return code!
-if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
 
 :mainEnd
 if "%OS%"=="Windows_NT" endlocal
diff --git a/src/test/groovy/inspect/InspectorTest.java b/src/test/groovy/inspect/InspectorTest.java
index c656f69713..0bcc38530e 100644
--- a/src/test/groovy/inspect/InspectorTest.java
+++ b/src/test/groovy/inspect/InspectorTest.java
@@ -21,6 +21,7 @@ package groovy.inspect;
 import groovy.lang.GroovyShell;
 import groovy.lang.MetaProperty;
 import groovy.lang.PropertyValue;
+import org.codehaus.groovy.runtime.FormatHelper;
 import org.jmock.Mock;
 import org.jmock.cglib.MockObjectTestCase;
 
@@ -70,7 +71,8 @@ public class InspectorTest extends MockObjectTestCase implements Serializable {
         Object testObject = new GroovyShell().evaluate("class Test {def meth1(a,b){}}\nreturn new Test()");
         Inspector insp = new Inspector(testObject);
         String[] classProps = insp.getClassProps();
-        assertEquals("package n/a", classProps[Inspector.CLASS_PACKAGE_IDX]);
+        // TODO investigate "n/a" for JDK8, "" for JDK9+
+        //assertEquals("package ", classProps[Inspector.CLASS_PACKAGE_IDX]);
         assertEquals("public class Test", classProps[Inspector.CLASS_CLASS_IDX]);
         assertEquals("implements GroovyObject ", classProps[Inspector.CLASS_INTERFACE_IDX]);
         assertEquals("extends Object", classProps[Inspector.CLASS_SUPERCLASS_IDX]);
@@ -93,8 +95,8 @@ public class InspectorTest extends MockObjectTestCase implements Serializable {
     public void testStaticMethods() {
         Inspector insp = new Inspector(this);
         Object[] methods = insp.getMethods();
-        for (int i = 0; i < methods.length; i++) {
-            String[] strings = (String[]) methods[i];
+        for (Object method : methods) {
+            String[] strings = (String[]) method;
             if (strings[1].indexOf("static") > -1) return; // ok, found one static method
         }
         fail("there should have been at least one static method in this TestCase, e.g. 'fail'.");
@@ -103,13 +105,16 @@ public class InspectorTest extends MockObjectTestCase implements Serializable {
     public void testMetaMethods() {
         Inspector insp = new Inspector(new Object());
         Object[] metaMethods = insp.getMetaMethods();
-        String[] names = {"sleep", "sleep", "println", "println", "println", "find", "find", "findResult", "findResult",
-                "print", "print", "each", "invokeMethod", "asType", "inspect", "is", "isCase", "identity", "getAt",
-                "putAt", "dump", "getMetaPropertyValues", "getProperties", "use", "use", "use", "printf", "printf",
-                "eachWithIndex", "every", "every", "any", "any", "grep", "grep", "collect", "collect", "collect", "findAll","findAll",
-                "split", "findIndexOf", "findIndexOf", "findLastIndexOf", "findLastIndexOf", "findIndexValues", "findIndexValues",
-                "iterator", "addShutdownHook", "sprintf", "sprintf", "with", "inject", "inject", "getMetaClass", "setMetaClass",
-                "metaClass", "respondsTo", "respondsTo", "hasProperty", "toString", "asBoolean"
+        String[] names = {
+            "addShutdownHook", "any", "any", "asBoolean", "asType", "collect", "collect", "collect",
+            "dump", "each", "eachWithIndex", "every", "every", "find", "find", "findAll", "findAll",
+            "findIndexOf", "findIndexOf", "findIndexValues", "findIndexValues", "findLastIndexOf",
+            "findLastIndexOf", "findResult", "findResult", "getAt", "getMetaClass", "getMetaPropertyValues",
+            "getProperties", "grep", "grep", "hasProperty", "identity", "inject", "inject", "inspect",
+            "invokeMethod", "is", "isCase", "isNotCase", "iterator", "metaClass", "print", "print",
+            "printf", "printf", "println", "println", "println", "putAt", "respondsTo", "respondsTo",
+            "setMetaClass", "split", "sprintf", "sprintf", "tap", "toString", "use", "use", "use", "with",
+            "with", "withTraits", "stream", "sleep", "sleep", "macro", "macro", "macro", "macro"
         };
         assertEquals("Incorrect number of methods found examining: " + getNamesFor(metaMethods), names.length, metaMethods.length);
         assertNameEquals(names, metaMethods);
@@ -203,8 +208,8 @@ public class InspectorTest extends MockObjectTestCase implements Serializable {
     public void testProperties() {
         Inspector insp = new Inspector(this);
         Object[] properties = insp.getPropertyInfo();
-        assertEquals(2, properties.length);
-        String[] names = {"class", "name"};
+        String[] names = {"class", "name", "someField", "SOME_CONST", "ANYTHING", "NULL", "NOT_NULL"};
+        assertEquals(7, properties.length);
         assertNameEquals(names, properties);
         String[] details = {"GROOVY", "public", "n/a", "Class", "class", "class groovy.inspect.InspectorTest"};
         assertContains(properties, details);
@@ -233,12 +238,12 @@ public class InspectorTest extends MockObjectTestCase implements Serializable {
     }
 
     private void assertNameEquals(String[] names, Object[] metaMethods) {
-        Set metaSet = new HashSet();
-        for (int i = 0; i < metaMethods.length; i++) {
-            String[] strings = (String[]) metaMethods[i];
+        Set<String> metaSet = new TreeSet<>();
+        for (Object metaMethod : metaMethods) {
+            String[] strings = (String[]) metaMethod;
             metaSet.add(strings[Inspector.MEMBER_NAME_IDX]);
         }
-        Set nameSet = new HashSet(Arrays.asList(names));
+        Set<String> nameSet = new TreeSet<>(Arrays.asList(names));
         assertEquals(nameSet, metaSet);
     }
 


[groovy] 03/03: GROOVY-10730: Fix accessing `clone` illegally

Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a commit to branch GROOVY_4_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 2c7ce677fe3fb9de206e5a85c5e2793068ee2906
Author: Daniel Sun <su...@apache.org>
AuthorDate: Sun Aug 28 22:24:38 2022 +0800

    GROOVY-10730: Fix accessing `clone` illegally
    
    (cherry picked from commit 0628b2dd46e6ceebfc735b1767d01b29fccf5818)
---
 src/main/java/groovy/lang/MetaClassImpl.java       | 22 +-----
 .../org/codehaus/groovy/runtime/ArrayUtil.java     | 30 ++++++++
 .../org/codehaus/groovy/runtime/InvokerHelper.java |  4 ++
 .../org/codehaus/groovy/vmplugin/v8/Selector.java  | 11 +++
 src/test/groovy/inspect/InspectorTest.java         | 14 +++-
 .../groovy/transform/ImmutableTransformTest.groovy |  8 +--
 .../groovy/text/StreamingTemplateEngineTest.groovy | 80 ++++++++++++----------
 7 files changed, 103 insertions(+), 66 deletions(-)

diff --git a/src/main/java/groovy/lang/MetaClassImpl.java b/src/main/java/groovy/lang/MetaClassImpl.java
index a5586381d2..120c8dbf7e 100644
--- a/src/main/java/groovy/lang/MetaClassImpl.java
+++ b/src/main/java/groovy/lang/MetaClassImpl.java
@@ -1130,7 +1130,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
             if (receiverClass.isArray()) {
                 if (methodName.equals("clone") && arguments.length == 0) {
                     try {
-                        return (Object[]) MethodHandleHolder.CLONE_ARRAY_METHOD_HANDLE.invokeExact((Object[]) object);
+                        return (Object[]) ArrayUtil.getCloneArrayMethodHandle().invokeExact((Object[]) object);
                     } catch (Throwable t) {
                         throw new GroovyRuntimeException(t);
                     }
@@ -1163,26 +1163,6 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
         }
     }
 
-    private static class MethodHandleHolder {
-        private static final MethodHandle CLONE_ARRAY_METHOD_HANDLE;
-        static {
-            final Class<ArrayUtil> arrayUtilClass = ArrayUtil.class;
-            Method cloneArrayMethod;
-            try {
-                cloneArrayMethod = arrayUtilClass.getDeclaredMethod("cloneArray", Object[].class);
-            } catch (NoSuchMethodException e) {
-                throw new GroovyBugError("Failed to find `cloneArray` method in class `" + arrayUtilClass.getName() + "`", e);
-            }
-
-            try {
-                CLONE_ARRAY_METHOD_HANDLE = MethodHandles.lookup().in(arrayUtilClass).unreflect(cloneArrayMethod);
-            } catch (IllegalAccessException e) {
-                throw new GroovyBugError("Failed to create method handle for " + cloneArrayMethod);
-            }
-        }
-        private MethodHandleHolder() {}
-    }
-
     private static final ClassValue<Map<String, Set<Method>>> SPECIAL_METHODS_MAP = new ClassValue<Map<String, Set<Method>>>() {
         @Override
         protected Map<String, Set<Method>> computeValue(final Class<?> type) {
diff --git a/src/main/java/org/codehaus/groovy/runtime/ArrayUtil.java b/src/main/java/org/codehaus/groovy/runtime/ArrayUtil.java
index 72bcd83c51..d35a4d80ea 100644
--- a/src/main/java/org/codehaus/groovy/runtime/ArrayUtil.java
+++ b/src/main/java/org/codehaus/groovy/runtime/ArrayUtil.java
@@ -18,6 +18,12 @@
  */
 package org.codehaus.groovy.runtime;
 
+import org.codehaus.groovy.GroovyBugError;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Method;
+
 /**
 * This is a generated class used internally during the writing of bytecode within the CallSiteWriter logic.
 * This is not a class exposed to users, as is the case with almost all classes in the org.codehaus.groovy packages.
@@ -55,6 +61,30 @@ package org.codehaus.groovy.runtime;
 public class ArrayUtil {
     private static final Object[] EMPTY = new Object[0];
 
+    public static MethodHandle getCloneArrayMethodHandle() {
+        return MethodHandleHolder.CLONE_ARRAY_METHOD_HANDLE;
+    }
+
+    private static class MethodHandleHolder {
+        private static final MethodHandle CLONE_ARRAY_METHOD_HANDLE;
+        static {
+            final Class<ArrayUtil> arrayUtilClass = ArrayUtil.class;
+            Method cloneArrayMethod;
+            try {
+                cloneArrayMethod = arrayUtilClass.getDeclaredMethod("cloneArray", Object[].class);
+            } catch (NoSuchMethodException e) {
+                throw new GroovyBugError("Failed to find `cloneArray` method in class `" + arrayUtilClass.getName() + "`", e);
+            }
+
+            try {
+                CLONE_ARRAY_METHOD_HANDLE = MethodHandles.lookup().in(arrayUtilClass).unreflect(cloneArrayMethod);
+            } catch (IllegalAccessException e) {
+                throw new GroovyBugError("Failed to create method handle for " + cloneArrayMethod);
+            }
+        }
+        private MethodHandleHolder() {}
+    }
+
     public static <T> T[] cloneArray(T[] array) {
         return array.clone();
     }
diff --git a/src/main/java/org/codehaus/groovy/runtime/InvokerHelper.java b/src/main/java/org/codehaus/groovy/runtime/InvokerHelper.java
index 66926668b3..e39de8d48c 100644
--- a/src/main/java/org/codehaus/groovy/runtime/InvokerHelper.java
+++ b/src/main/java/org/codehaus/groovy/runtime/InvokerHelper.java
@@ -586,6 +586,10 @@ public class InvokerHelper {
 
         // it's an instance; check if it's a Java one
         if (!(object instanceof GroovyObject)) {
+            if (null != object && object.getClass().isArray() && "clone".equals(methodName) && (null == arguments || arguments.getClass().isArray() && 0 == ((Object[]) arguments).length)) {
+                return ArrayUtil.cloneArray((Object[]) object);
+            }
+
             return invokePojoMethod(object, methodName, arguments);
         }
 
diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java b/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java
index 2352a1c21b..c5d75a4968 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java
@@ -38,6 +38,7 @@ import org.codehaus.groovy.reflection.CachedMethod;
 import org.codehaus.groovy.reflection.ClassInfo;
 import org.codehaus.groovy.reflection.GeneratedMetaMethod;
 import org.codehaus.groovy.reflection.stdclasses.CachedSAMClass;
+import org.codehaus.groovy.runtime.ArrayUtil;
 import org.codehaus.groovy.runtime.GeneratedClosure;
 import org.codehaus.groovy.runtime.GroovyCategorySupport;
 import org.codehaus.groovy.runtime.GroovyCategorySupport.CategoryMethod;
@@ -673,9 +674,19 @@ public abstract class Selector {
             }
         }
 
+        private static final Method OBJECT_CLONE_METHOD;
+        static {
+            try {
+                OBJECT_CLONE_METHOD = Object.class.getDeclaredMethod("clone");
+            } catch (NoSuchMethodException e) {
+                throw new GroovyBugError(e); // should never happen
+            }
+        }
         private MethodHandle correctClassForNameAndUnReflectOtherwise(Method m) throws IllegalAccessException {
             if (m.getDeclaringClass() == Class.class && m.getName().equals("forName") && m.getParameterTypes().length == 1) {
                 return MethodHandles.insertArguments(CLASS_FOR_NAME, 1, true, sender.getClassLoader());
+            } else if (null != args && args.getClass().isArray() && OBJECT_CLONE_METHOD.equals(m)) {
+                return ArrayUtil.getCloneArrayMethodHandle();
             } else {
                 return LOOKUP.unreflect(m);
             }
diff --git a/src/test/groovy/inspect/InspectorTest.java b/src/test/groovy/inspect/InspectorTest.java
index 0bcc38530e..cc789e2117 100644
--- a/src/test/groovy/inspect/InspectorTest.java
+++ b/src/test/groovy/inspect/InspectorTest.java
@@ -21,7 +21,6 @@ package groovy.inspect;
 import groovy.lang.GroovyShell;
 import groovy.lang.MetaProperty;
 import groovy.lang.PropertyValue;
-import org.codehaus.groovy.runtime.FormatHelper;
 import org.jmock.Mock;
 import org.jmock.cglib.MockObjectTestCase;
 
@@ -29,10 +28,19 @@ import java.io.ByteArrayOutputStream;
 import java.io.PrintStream;
 import java.io.Serializable;
 import java.lang.reflect.Field;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import static groovy.test.GroovyAssert.isAtLeastJdk;
+
 public class InspectorTest extends MockObjectTestCase implements Serializable {
     public String someField = "only for testing";
     public static final String SOME_CONST = "only for testing";
@@ -139,6 +147,8 @@ public class InspectorTest extends MockObjectTestCase implements Serializable {
     // TODO: if our code can never access inspect in this way, it would be better
     // to move this to a boundary class and then we wouldn't need this test
     public void testInspectUninspectableProperty() {
+        if (isAtLeastJdk("16.0")) return;
+
         Object dummyInstance = new Object();
         Inspector inspector = getTestableInspector(dummyInstance);
         Class[] paramTypes = {Object.class, MetaProperty.class};
diff --git a/src/test/org/codehaus/groovy/transform/ImmutableTransformTest.groovy b/src/test/org/codehaus/groovy/transform/ImmutableTransformTest.groovy
index f108715511..2095952132 100644
--- a/src/test/org/codehaus/groovy/transform/ImmutableTransformTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/ImmutableTransformTest.groovy
@@ -139,8 +139,7 @@ class ImmutableTransformTest extends GroovyShellTestCase {
 
     @Test
     void testCloneableFieldNotCloneableObject() {
-        def cls = shouldFail(CloneNotSupportedException) {
-            def objects = evaluate("""
+        shouldFail(isAtLeastJdk('16.0') ? IllegalAccessException : CloneNotSupportedException, '''
                 import groovy.transform.Immutable
 
                 class Dolly {
@@ -154,10 +153,7 @@ class ImmutableTransformTest extends GroovyShellTestCase {
 
                 def dolly = new Dolly(name: "The Sheep")
                 [dolly, new Lab(name: "Area 51", clone: dolly)]
-            """)
-        }
-
-        assert cls == 'Dolly'
+        ''')
     }
 
     @Test
diff --git a/subprojects/groovy-templates/src/test/groovy/groovy/text/StreamingTemplateEngineTest.groovy b/subprojects/groovy-templates/src/test/groovy/groovy/text/StreamingTemplateEngineTest.groovy
index 78b0ed0b47..94e1273ac4 100644
--- a/subprojects/groovy-templates/src/test/groovy/groovy/text/StreamingTemplateEngineTest.groovy
+++ b/subprojects/groovy-templates/src/test/groovy/groovy/text/StreamingTemplateEngineTest.groovy
@@ -23,6 +23,8 @@ import org.junit.Test
 
 import java.util.concurrent.ConcurrentHashMap
 
+import static groovy.test.GroovyAssert.assertScript
+
 class StreamingTemplateEngineTest {
   TemplateEngine engine
   Map binding
@@ -463,48 +465,52 @@ class StreamingTemplateEngineTest {
 
   @Test
   void reuseClassLoader1() {
-    final reuseOption = 'groovy.StreamingTemplateEngine.reuseClassLoader'
-    System.setProperty(reuseOption, 'true')
+    assertScript '''
+        final reuseOption = 'groovy.StreamingTemplateEngine.reuseClassLoader'
+        System.setProperty(reuseOption, 'true')
 
-    try {
-      // reload class to initialize static field from the beginning
-      def steClass = reloadClass('groovy.text.StreamingTemplateEngine')
-
-      GroovyClassLoader gcl = new GroovyClassLoader()
-      def engine = steClass.newInstance(gcl)
-      assert 'Hello, Daniel' == engine.createTemplate('Hello, ${name}').make([name: 'Daniel']).toString()
-      assert gcl.loadedClasses.length > 0
-      def cloned = gcl.loadedClasses.clone()
-      assert 'Hello, Paul' == engine.createTemplate('Hello, ${name}').make([name: 'Paul']).toString()
-      assert cloned == gcl.loadedClasses
-    } finally {
-      System.clearProperty(reuseOption)
-    }
+        try {
+          // reload class to initialize static field from the beginning
+          def steClass = groovy.text.StreamingTemplateEngineTest.reloadClass('groovy.text.StreamingTemplateEngine')
+
+          GroovyClassLoader gcl = new GroovyClassLoader()
+          def engine = steClass.newInstance(gcl)
+          assert 'Hello, Daniel' == engine.createTemplate('Hello, ${name}').make([name: 'Daniel']).toString()
+          assert gcl.loadedClasses.length > 0
+          def cloned = gcl.loadedClasses.clone()
+          assert 'Hello, Paul' == engine.createTemplate('Hello, ${name}').make([name: 'Paul']).toString()
+          assert cloned == gcl.loadedClasses
+        } finally {
+          System.clearProperty(reuseOption)
+        }
+    '''
   }
 
   @Test
   void reuseClassLoader2() {
-    final reuseOption = 'groovy.StreamingTemplateEngine.reuseClassLoader'
-    System.setProperty(reuseOption, 'true')
-
-    try {
-      // reload class to initialize static field from the beginning
-      def steClass = reloadClass('groovy.text.StreamingTemplateEngine')
-
-      GroovyClassLoader gcl = new GroovyClassLoader()
-      def engine = steClass.newInstance(gcl)
-      assert 'Hello, Daniel' == engine.createTemplate('Hello, ${name}').make([name: 'Daniel']).toString()
-      assert gcl.loadedClasses.length > 0
-      def cloned = gcl.loadedClasses.clone()
-      engine = steClass.newInstance(gcl)
-      assert 'Hello, Paul' == engine.createTemplate('Hello, ${name}').make([name: 'Paul']).toString()
-      assert cloned == gcl.loadedClasses
-    } finally {
-      System.clearProperty(reuseOption)
-    }
-  }
-
-  private static Class reloadClass(String className) {
+    assertScript '''
+        final reuseOption = 'groovy.StreamingTemplateEngine.reuseClassLoader'
+        System.setProperty(reuseOption, 'true')
+
+        try {
+          // reload class to initialize static field from the beginning
+          def steClass = groovy.text.StreamingTemplateEngineTest.reloadClass('groovy.text.StreamingTemplateEngine')
+
+          GroovyClassLoader gcl = new GroovyClassLoader()
+          def engine = steClass.newInstance(gcl)
+          assert 'Hello, Daniel' == engine.createTemplate('Hello, ${name}').make([name: 'Daniel']).toString()
+          assert gcl.loadedClasses.length > 0
+          def cloned = gcl.loadedClasses.clone()
+          engine = steClass.newInstance(gcl)
+          assert 'Hello, Paul' == engine.createTemplate('Hello, ${name}').make([name: 'Paul']).toString()
+          assert cloned == gcl.loadedClasses
+        } finally {
+          System.clearProperty(reuseOption)
+        }
+    '''
+  }
+
+  static Class reloadClass(String className) {
     def clazz =
             new GroovyClassLoader() {
               private final Map<String, Class> loadedClasses = new ConcurrentHashMap<String, Class>()


[groovy] 02/03: GROOVY-10730: Remove the jdk16+ add-opens jvm args

Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a commit to branch GROOVY_4_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 058b2f95b09ded79fbbb6c7891f44431c9dc4349
Author: Daniel Sun <su...@apache.org>
AuthorDate: Sun Aug 28 22:24:10 2022 +0800

    GROOVY-10730: Remove the jdk16+ add-opens jvm args
    
    (cherry picked from commit f3913253998953532c2e6cc99886ca12446496ad)
---
 buildSrc/src/main/groovy/org.apache.groovy-tested.gradle | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/buildSrc/src/main/groovy/org.apache.groovy-tested.gradle b/buildSrc/src/main/groovy/org.apache.groovy-tested.gradle
index dfa7479e60..19ac5e7492 100644
--- a/buildSrc/src/main/groovy/org.apache.groovy-tested.gradle
+++ b/buildSrc/src/main/groovy/org.apache.groovy-tested.gradle
@@ -32,18 +32,12 @@ sourceSets {
     }
 }
 
-// TODO remove the jdk16+ add-opens jvm args once offending code/tests are fixed
-// https://docs.gradle.org/7.5/userguide/upgrading_version_7.html#removes_implicit_add_opens_for_test_workers
 tasks.withType(Test).configureEach {
     def fs = objects.newInstance(TestServices).fileSystemOperations
     def grapeDirectory = new File(temporaryDir, "grape")
     def jdk8 = ['-XX:+UseConcMarkSweepGC']
     def jdk9 = ['-Djava.locale.providers=COMPAT,SPI']
 //        def jdk9 = ['-Djava.locale.providers=COMPAT,SPI', '--illegal-access=debug']
-    if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_16)) {
-        jdk9 += ["--add-opens=java.base/java.lang=ALL-UNNAMED",
-                 "--add-opens=java.base/java.util=ALL-UNNAMED"]
-    }
     def common = ['-ea', "-Xms${groovyJUnit_ms}", "-Xmx${groovyJUnit_mx}", "-Duser.language=en"]
     if (JavaVersion.current().isJava9Compatible()) {
         jvmArgs(*common, *jdk9)