You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2023/07/23 00:15:43 UTC

[groovy] branch master updated: GROOVY-10931: fix for array and object `clone()`

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

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


The following commit(s) were added to refs/heads/master by this push:
     new b56ab4f7d2 GROOVY-10931: fix for array and object `clone()`
b56ab4f7d2 is described below

commit b56ab4f7d2d42c4377fe3fccf791a4d7edf24e1e
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sat Jul 22 11:05:57 2023 -0500

    GROOVY-10931: fix for array and object `clone()`
---
 .../main/groovy/org.apache.groovy-tested.gradle    |   9 +-
 .../org/codehaus/groovy/vmplugin/v16/Java16.java   |  38 +---
 .../org/codehaus/groovy/vmplugin/v8/Selector.java  |  53 +++--
 .../org/codehaus/groovy/vmplugin/v9/Java9.java     |  13 +-
 src/test/groovy/CategoryTest.groovy                |  11 +-
 src/test/groovy/IllegalAccessTests.groovy          | 221 ++++++++++++++++++++-
 src/test/groovy/bugs/Groovy8764.groovy             |  10 +-
 src/test/groovy/bugs/Groovy9103.groovy             | 146 --------------
 src/test/groovy/bugs/groovy9081/Groovy9081.groovy  |  95 ---------
 .../groovy9081/somepkg/ProtectedConstructor.java   |  25 ---
 .../groovy/transform/ThreadInterruptTest.groovy    |  53 ++---
 src/test/groovy/ui/GroovyMainTest.groovy           |  32 ++-
 src/test/groovy/util/GroovyScriptEngineTest.groovy |  22 +-
 src/test/groovy/util/logging/CommonsTest.groovy    |   8 +-
 .../antlr4/util/ASTComparatorCategory.groovy       |   3 +-
 .../ArraysAndCollectionsStaticCompileTest.groovy   |  14 +-
 .../codehaus/groovy/reflection/SecurityTest.java   |   2 -
 .../m12n/ExtensionModuleHelperForTests.groovy      |   8 +-
 .../StaticMethodOverloadCompileStaticTest.groovy   |  19 +-
 .../groovy/transform/ImmutableTransformTest.groovy |  25 ++-
 20 files changed, 337 insertions(+), 470 deletions(-)

diff --git a/build-logic/src/main/groovy/org.apache.groovy-tested.gradle b/build-logic/src/main/groovy/org.apache.groovy-tested.gradle
index 36a82a5430..7ec0b5aea7 100644
--- a/build-logic/src/main/groovy/org.apache.groovy-tested.gradle
+++ b/build-logic/src/main/groovy/org.apache.groovy-tested.gradle
@@ -34,14 +34,13 @@ sourceSets {
 
 tasks.withType(Test).configureEach {
     def fs = objects.newInstance(TestServices).fileSystemOperations
-    def grapeDirectory = new File(temporaryDir, "grape")
+    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']
-    def common = ['-ea', "-Xms${groovyJUnit_ms}", "-Xmx${groovyJUnit_mx}", "-Duser.language=en"]
+    def jdk9 = ['-Djava.locale.providers=COMPAT,SPI'/*, '--illegal-access=debug'*/]
+    def common = ['-ea', "-Xms${groovyJUnit_ms}", "-Xmx${groovyJUnit_mx}", '-Duser.language=en']
     if (JavaVersion.current().isJava9Compatible()) {
         jvmArgs(*common, *jdk9)
-        systemProperty "groovy.force.illegal.access", findProperty("groovy.force.illegal.access")
+        systemProperty 'groovy.force.illegal.access', findProperty('groovy.force.illegal.access')
     } else {
         jvmArgs(*common, *jdk8)
     }
diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v16/Java16.java b/src/main/java/org/codehaus/groovy/vmplugin/v16/Java16.java
index 3dd9be3d27..7de5736085 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v16/Java16.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v16/Java16.java
@@ -27,8 +27,6 @@ import org.codehaus.groovy.ast.RecordComponentNode;
 import org.codehaus.groovy.vmplugin.v10.Java10;
 
 import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
 import java.util.Arrays;
@@ -48,14 +46,15 @@ public class Java16 extends Java10 {
     public Object getInvokeSpecialHandle(final Method method, final Object receiver) {
         try {
             final Class<?> receiverClass = receiver.getClass();
+            // GROOVY-10145, GROOVY-10391: default interface method proxy
             if (method.isDefault() && Proxy.isProxyClass(receiverClass)) {
                 return new ProxyDefaultMethodHandle((Proxy) receiver, method);
             }
-            MethodHandles.Lookup lookup = newLookup(receiverClass);
-            if ((lookup.lookupModes() & MethodHandles.Lookup.PRIVATE) != 0) {
-                return lookup.unreflectSpecial(method, receiverClass).bindTo(receiver);
+            var  lookup = newLookup(receiverClass);
+            if (!lookup.hasFullPrivilegeAccess()) {
+                return lookup.unreflect(method).bindTo(receiver);
             }
-            return lookup.unreflect(method).bindTo(receiver);
+            return lookup.unreflectSpecial(method, receiverClass).bindTo(receiver);
         } catch (ReflectiveOperationException e) {
             return new GroovyRuntimeException(e);
         }
@@ -90,31 +89,4 @@ public class Java16 extends Java10 {
                 })
                 .collect(Collectors.toList()));
     }
-
-    @Override
-    protected MethodHandles.Lookup newLookup(final Class<?> targetClass) {
-        try {
-            final Method privateLookup = getPrivateLookup();
-            if (privateLookup != null) {
-                MethodHandles.Lookup caller = MethodHandles.lookup();
-                Class<?> callerClass = caller.lookupClass();
-                Module callerModule = callerClass.getModule();
-                Module targetModule = targetClass.getModule();
-                if (targetModule != callerModule) {
-                    if (targetModule.isNamed()) {
-                        String pn = targetClass.getPackageName();
-                        if (!targetModule.isOpen(pn, callerModule)) {
-                            return MethodHandles.lookup().in(targetClass);
-                        }
-                    }
-                }
-                return (MethodHandles.Lookup) privateLookup.invoke(null, targetClass, caller);
-            }
-            return getLookupConstructor().newInstance(targetClass, MethodHandles.Lookup.PRIVATE).in(targetClass);
-        } catch (final IllegalAccessException | InstantiationException e) {
-            throw new IllegalArgumentException(e);
-        } catch (final InvocationTargetException e) {
-            throw new GroovyRuntimeException(e);
-        }
-    }
 }
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 73256a17d6..eb1f0d27ad 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java
@@ -341,9 +341,9 @@ public abstract class Selector {
                 Field f = cf.getCachedField();
                 try {
                     handle = LOOKUP.unreflectGetter(f);
-                    if (Modifier.isStatic(f.getModifiers())) {
+                    if (cf.isStatic()) {
                         // normally we would do the following
-                        // handle = MethodHandles.dropArguments(handle,0,Class.class);
+                        // handle = MethodHandles.dropArguments(handle, 0, Class.class);
                         // but because there is a bug in invokedynamic in all jdk7 versions
                         // maybe use Unsafe.ensureClassInitialized
                         handle = META_PROPERTY_GETTER.bindTo(mp);
@@ -620,7 +620,7 @@ public abstract class Selector {
          */
         public void setHandleForMetaMethod() {
             MetaMethod metaMethod = method;
-            isCategoryMethod = method instanceof CategoryMethod;
+            isCategoryMethod = (method instanceof CategoryMethod);
 
             if (metaMethod instanceof NumberNumberMetaMethod
                     || (method instanceof GeneratedMetaMethod && (name.equals("next") || name.equals("previous")))) {
@@ -632,54 +632,47 @@ public abstract class Selector {
                 }
             }
 
-            boolean isCategoryTypeMethod = metaMethod instanceof NewInstanceMetaMethod;
+            boolean isCategoryTypeMethod = (metaMethod instanceof NewInstanceMetaMethod);
             if (LOG_ENABLED) LOG.info("meta method is category type method: " + isCategoryTypeMethod);
-            boolean isStaticCategoryTypeMethod = metaMethod instanceof NewStaticMetaMethod;
+            boolean isStaticCategoryTypeMethod = (metaMethod instanceof NewStaticMetaMethod);
             if (LOG_ENABLED) LOG.info("meta method is static category type method: " + isCategoryTypeMethod);
 
             if (metaMethod instanceof ReflectionMetaMethod) {
                 if (LOG_ENABLED) LOG.info("meta method is reflective method");
-                ReflectionMetaMethod rmm = (ReflectionMetaMethod) metaMethod;
-                metaMethod = rmm.getCachedMethod();
+                metaMethod = ((ReflectionMetaMethod) metaMethod).getCachedMethod();
             }
 
             if (metaMethod instanceof CachedMethod) {
+                isVargs = metaMethod.isVargsMethod();
                 CachedMethod cm = (CachedMethod) metaMethod;
                 VMPlugin vmplugin = VMPluginFactory.getPlugin();
                 cm = (CachedMethod) vmplugin.transformMetaMethod(mc, cm, sender);
-                isVargs = cm.isVargsMethod();
-                Method m = cm.getCachedMethod();
                 try {
-                    String  methodName = m.getName();
-                    int parameterCount = m.getParameterCount();
-                    if (parameterCount == 0 && methodName.equals("clone") && m.getDeclaringClass() == Object.class && args[0].getClass().isArray()) {
-                        handle = MethodHandles.publicLookup().findVirtual(args[0].getClass(), "clone", MethodType.methodType(Object.class));
-                    } else if (parameterCount == 1 && methodName.equals("forName") && m.getDeclaringClass() == Class.class) {
+                    var declaringClass = cm.getDeclaringClass().getTheClass();
+                    int parameterCount = cm.getParamsCount();
+                    if (parameterCount == 0 && name.equals("clone") && declaringClass == Object.class) {
+                        var receiverClass = getCorrectedReceiver().getClass();
+                        if (receiverClass.isArray()) { // GROOVY-10733, et al.
+                            handle = MethodHandles.publicLookup().findVirtual(receiverClass, "clone", MethodType.methodType(Object.class));
+                        } else { // GROOVY-10319
+                            handle = MethodHandles.throwException(Object.class, CloneNotSupportedException.class) // prevent illegal access
+                                                                    .bindTo(new CloneNotSupportedException());
+                            handle = MethodHandles.dropArguments(handle, 0, Object.class); // discard receiver
+                        }
+                    } else if (parameterCount == 1 && name.equals("forName") && declaringClass == Class.class) {
                         handle = MethodHandles.insertArguments(CLASS_FOR_NAME, 1, Boolean.TRUE, sender.getClassLoader());
                     } else {
-                        MethodHandles.Lookup lookup = LOOKUP; Class<?> redirect;
-                        if (parameterCount == 0 && methodName.equals("clone") && m.getDeclaringClass() == Object.class) {
-                            redirect = args[0].getClass();
-                        } else if (!vmplugin.checkAccessible(lookup.lookupClass(), m.getDeclaringClass(), m.getModifiers(), false)) {
-                            redirect = sender;
-                        } else {
-                            redirect = null;
-                        }
-                        if (redirect != null) {
-                            Method newLookup = vmplugin.getClass().getMethod("of", Class.class);
-                            lookup = (MethodHandles.Lookup) newLookup.invoke(null, redirect);
-                        }
-                        handle = lookup.unreflect(m);
+                        MethodHandles.Lookup lookup = cm.isPublic() ? LOOKUP : ((Java8)vmplugin).newLookup(sender); // GROOVY-10070, et al.
+                        handle = lookup.unreflect(cm.getCachedMethod()); // throws if sender cannot invoke method
                     }
                 } catch (ReflectiveOperationException e) {
                     throw new GroovyBugError(e);
                 }
-
                 if (isStaticCategoryTypeMethod) {
                     handle = MethodHandles.insertArguments(handle, 0, SINGLE_NULL_ARRAY);
                     handle = MethodHandles.dropArguments(handle, 0, targetType.parameterType(0));
-                } else if (!isCategoryTypeMethod && Modifier.isStatic(m.getModifiers())) {
-                    // we drop the receiver, which might be a Class (invocation on Class)
+                } else if (!isCategoryTypeMethod && cm.isStatic()) {
+                    // drop the receiver, which might be a Class (invocation on Class)
                     // or it might be an object (static method invocation on instance)
                     // Object.class handles both cases at once
                     handle = MethodHandles.dropArguments(handle, 0, Object.class);
diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v9/Java9.java b/src/main/java/org/codehaus/groovy/vmplugin/v9/Java9.java
index f18e9b9f10..b752009f14 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v9/Java9.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v9/Java9.java
@@ -113,10 +113,10 @@ public class Java9 extends Java8 {
             } finally {
                 result.putAll(javaDefaultImportsFuture.get());
             }
-        } catch (Exception ignore) {
+        } catch (Exception e) {
             Logger logger = Logger.getLogger(getClass().getName());
             if (logger.isLoggable(Level.FINEST)) {
-                logger.finest("[WARNING] Failed to find default imported classes:\n" + DefaultGroovyMethods.asString(ignore));
+                logger.finest("[WARNING] Failed to find default imported classes:\n" + DefaultGroovyMethods.asString(e));
             }
         }
 
@@ -144,11 +144,12 @@ public class Java9 extends Java8 {
     @Override
     protected MethodHandles.Lookup newLookup(final Class<?> targetClass) {
         try {
-            final Method privateLookup = getPrivateLookup();
+            var privateLookup = getPrivateLookup();
             if (privateLookup != null) {
                 return (MethodHandles.Lookup) privateLookup.invoke(null, targetClass, MethodHandles.lookup());
             }
             return getLookupConstructor().newInstance(targetClass, MethodHandles.Lookup.PRIVATE).in(targetClass);
+
         } catch (final IllegalAccessException | InstantiationException e) {
             throw new IllegalArgumentException(e);
         } catch (final InvocationTargetException e) {
@@ -287,14 +288,14 @@ public class Java9 extends Java8 {
         }
 
         Member member = (Member) accessibleObject;
-
         Class<?> declaringClass = member.getDeclaringClass();
-        Module declaringModule = declaringClass.getModule();
+
         Module callerModule = callerClass.getModule();
+        Module declaringModule = declaringClass.getModule();
 
-        if (!declaringModule.isNamed()) return true;
         if (callerModule == declaringModule) return true;
         if (callerModule == Object.class.getModule()) return true;
+        if (!declaringModule.isNamed()) return true;
 
         return checkAccessible(callerClass, declaringClass, member.getModifiers(), true);
     }
diff --git a/src/test/groovy/CategoryTest.groovy b/src/test/groovy/CategoryTest.groovy
index aa5c6851f9..0723180c13 100644
--- a/src/test/groovy/CategoryTest.groovy
+++ b/src/test/groovy/CategoryTest.groovy
@@ -20,8 +20,6 @@ package groovy
 
 import groovy.test.GroovyTestCase
 
-import static groovy.test.GroovyAssert.isAtLeastJdk
-
 final class CategoryTest extends GroovyTestCase {
 
     @Override
@@ -331,12 +329,11 @@ final class CategoryTest extends GroovyTestCase {
 
     // GROOVY-10743
     void testStaticMethodOnInterface() {
-        if(!isAtLeastJdk('9.0')) return
         assertScript '''
-        use(java.util.stream.Stream) {
-            assert [1, 1].iterate(f -> [f[1], f.sum()]).limit(8).toList()*.head() == [1, 1, 2, 3, 5, 8, 13, 21]
-            assert 16.iterate(n -> n < 500, n -> n * 2).toList() == [16, 32, 64, 128, 256]
-        }
+            use(java.util.stream.Stream) {
+                assert [1, 1].iterate(f -> [f[1], f.sum()]).limit(8).toList()*.head() == [1, 1, 2, 3, 5, 8, 13, 21]
+                assert 16.iterate(n -> n < 500, n -> n * 2).toList() == [16, 32, 64, 128, 256]
+            }
         '''
     }
 
diff --git a/src/test/groovy/IllegalAccessTests.groovy b/src/test/groovy/IllegalAccessTests.groovy
index 256bfe00c0..41ecd15c64 100644
--- a/src/test/groovy/IllegalAccessTests.groovy
+++ b/src/test/groovy/IllegalAccessTests.groovy
@@ -18,12 +18,14 @@
  */
 package groovy
 
-import org.junit.Before
 import org.junit.Test
 
+import java.awt.Font
+import java.lang.annotation.RetentionPolicy
+
 import static groovy.test.GroovyAssert.assertScript
 import static groovy.test.GroovyAssert.isAtLeastJdk
-import static org.junit.Assume.assumeTrue
+import static groovy.test.GroovyAssert.shouldFail
 
 /**
  * Tests for permissive member access.  Typically such access is only allowed in
@@ -31,21 +33,174 @@ import static org.junit.Assume.assumeTrue
  *
  * In JDK versions < 9, Groovy supports permissive access and no warnings are given by the JDK.
  * In JDK versions in 9..15, Groovy supports permissive access but the JDK gives illegal access warnings.
- * In JDK versions > 16, permissive access is restricted and Groovy's support for this feature is limited.
+ * In JDK versions >= 16, permissive access is restricted and Groovy's support for this feature is limited.
  */
 final class IllegalAccessTests {
 
-    @Before
-    void setUp() {
-        assumeTrue(!isAtLeastJdk('16.0') && isAtLeastJdk('9.0') && !Boolean.getBoolean('groovy.force.illegal.access'))
+    static class ProtectedConstructor {
+        protected ProtectedConstructor() {}
+        void run() {}
+    }
+
+    //--------------------------------------------------------------------------
+
+    @Test
+    void testClone1() {
+        assertScript '''
+            def broadcastSeq(Object value) {
+                value.clone()
+            }
+
+            assert broadcastSeq(new Tuple1('abc'))
+        '''
+    }
+
+    @Test
+    void testClone2() {
+        assertScript '''
+            class Value {
+                @Override
+                public Value clone() {
+                    return new Value()
+                }
+            }
+            def broadcastSeq(Object value) {
+                value.clone()
+            }
+
+            assert broadcastSeq(new Value())
+        '''
     }
 
     @Test
-    void testReadPrivateField() {
+    void testClone3() {
+        Object obj = new Tuple1('abc')
+        assert obj.clone().getClass() === Tuple1.class
+    }
+
+    @Test
+    void testClone4() {
         assertScript '''
+            int[] nums = new int[] {1,2,3}
+            int[] copy = nums.clone()
+            assert copy !== nums
+            assert copy == nums
+        '''
+    }
+
+    // GROOVY-10747
+    @Test
+    void testClone5() {
+        ['Object', 'Dolly'].each { typeName ->
+            assertScript """
+                class Dolly implements Cloneable {
+                    public ${typeName} clone() {
+                        return super.clone()
+                    }
+                    String name
+                }
+
+                def dolly = new Dolly(name: "The Sheep")
+                def clone = dolly.clone()
+                assert clone instanceof Dolly
+            """
+        }
+    }
+
+    // GROOVY-10747
+    @Test
+    void testClone6() {
+        shouldFail CloneNotSupportedException, '''
+            class Dolly {
+                String name
+            }
+
+            def dolly = new Dolly(name: "The Sheep")
+            dolly.clone()
+        '''
+    }
+
+    @Test
+    void testClone7() {
+        ['Object', 'Dolly'].each { typeName ->
+            assertScript """
+                import static org.codehaus.groovy.runtime.InvokerHelper.*
+                class Dolly implements Cloneable {
+                    public ${typeName} clone() {
+                        return super.clone()
+                    }
+                    String name
+                }
+
+                def dolly = new Dolly(name: "The Sheep")
+                def clone = invokeMethod(dolly, 'clone', EMPTY_ARGS)
+                assert clone instanceof Dolly
+            """
+        }
+    }
+
+    @Test
+    void testClone8() {
+        shouldFail CloneNotSupportedException, '''
+            import static org.codehaus.groovy.runtime.InvokerHelper.*
+            class Dolly {
+                String name
+            }
+
+            def dolly = new Dolly(name: "The Sheep")
+            invokeMethod(dolly, 'clone', EMPTY_ARGS)
+        '''
+    }
+
+    @Test
+    void testAsType1() {
+        [run: {}] as TimerTask
+    }
+
+    @Test
+    void testAsType2() {
+        assertScript """import ${this.class.name}.ProtectedConstructor
+            [run: {}] as ProtectedConstructor
+        """
+    }
+
+    @Test
+    void testGetProperty() {
+        try {
+            java.awt.Toolkit.defaultToolkit.systemClipboard
+        } catch (java.awt.HeadlessException ignore) {
+        }
+    }
+
+    @Test
+    void testGetProperties() {
+        String str = ''
+        assert str.properties
+    }
+
+    @Test
+    void testBigIntegerMultiply1() {
+        assert 2G * 1
+    }
+
+    @Test
+    void testBigIntegerMultiply2() {
+        def a = 333g; int b = 2
+        BigDecimal c = a * b
+        assert c == 666
+    }
+
+    @Test
+    void testReadPrivateJavaField() {
+        String script = '''
             def items = [1, 2, 3]
             assert items.size == 3 // "size" is private
         '''
+        if (isAtLeastJdk('16.0') && !Boolean.getBoolean('groovy.force.illegal.access')) {
+            shouldFail MissingPropertyException, script
+        } else {
+            assertScript script
+        }
     }
 
     @Test
@@ -62,16 +217,28 @@ final class IllegalAccessTests {
         '''
     }
 
-    @Test // GROOVY-9596
-    void testReadProtectedFieldFromSuperClass() {
-        // in is a protected field in FilterReader
+    // GROOVY-9596
+    @Test
+    void testReadProtectedFieldOfSuperClass() {
+        assertScript '''
+            char[] input = '1234567890\\r\\nabcdefghij\\r\\n'.toCharArray()
+
+            def reader = new FilterReader(new BufferedReader(new CharArrayReader(input))) {
+                @Override
+                int read() {
+                    this.in.read() // "in" is protected field of super class
+                }
+            }
+            assert reader.readLine() == '1234567890'
+        '''
+if (!isAtLeastJdk('16.0')) // TODO
         assertScript '''
             class MyFilterReader extends FilterReader {
                 MyFilterReader(Reader reader) {
                     super(new BufferedReader(reader))
                 }
                 String nextLine() {
-                    ((BufferedReader) this.in).readLine()?.trim() // "in" is protected
+                    ((BufferedReader) in).readLine()?.trim()
                 }
             }
 
@@ -85,4 +252,36 @@ final class IllegalAccessTests {
             assert reader.nextLine() == 'works'
         '''
     }
+
+    @Test
+    void testPackagePrivateInnerClassMember() {
+        def m = new HashMap(); m.a = 1
+        m.entrySet().iterator().next().toString()
+    }
+
+    @Test
+    void testAccessPublicMemberOfPrivateClass() {
+        def m = Collections.unmodifiableMap([:])
+        assert m.toString() != null
+        assert m.get(0) == null
+    }
+
+    @Test
+    void testFavorMethodWithExactParameterType() {
+        def em1 = new EnumMap(RetentionPolicy.class)
+        def em2 = new EnumMap(RetentionPolicy.class)
+        assert em1 == em2
+    }
+
+    @Test
+    void testShouldChoosePublicGetterInsteadOfPrivateField1() {
+        def f = Integer.class.getDeclaredField('MIN_VALUE')
+        assert f.modifiers != 0
+    }
+
+    @Test
+    void testShouldChoosePublicGetterInsteadOfPrivateField2() {
+        def f = new Font('Monospaced', Font.PLAIN, 12)
+        assert f.name
+    }
 }
diff --git a/src/test/groovy/bugs/Groovy8764.groovy b/src/test/groovy/bugs/Groovy8764.groovy
index fe9905e9bf..c3c4fd6720 100644
--- a/src/test/groovy/bugs/Groovy8764.groovy
+++ b/src/test/groovy/bugs/Groovy8764.groovy
@@ -53,7 +53,6 @@ final class Groovy8764 {
         assertScript '''
             import groovy.transform.*
             import java.util.function.Function
-            import static groovy.test.GroovyAssert.isAtLeastJdk
 
             @CompileStatic
             class Outer {
@@ -69,13 +68,8 @@ final class Groovy8764 {
             }
 
             def oi = new Outer.Inner()
-            assert !oi.test(0)
-            if (isAtLeastJdk('9.0')) {
-                assert oi.test(1).get() == 1
-            } else {
-                // confirm accessing private field okay on older JDK versions
-                assert oi.test(1).value == 1
-            }
+            assert oi.test(0).isEmpty()
+            assert oi.test(1).get() == 1
         '''
     }
 }
diff --git a/src/test/groovy/bugs/Groovy9103.groovy b/src/test/groovy/bugs/Groovy9103.groovy
deleted file mode 100644
index 6dce5330db..0000000000
--- a/src/test/groovy/bugs/Groovy9103.groovy
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- *  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 groovy.bugs
-
-import org.junit.Test
-
-import static groovy.test.GroovyAssert.assertScript
-import static groovy.test.GroovyAssert.shouldFail
-
-final class Groovy9103 {
-
-    @Test
-    void testProperties() {
-        String str = ''
-        assert str.properties
-    }
-
-    @Test
-    void testBigIntegerMultiply() {
-        assert 2G * 1
-    }
-
-    @Test
-    void testClone() {
-        assertScript '''
-            def broadcastSeq(Object value) {
-                value.clone()
-            }
-
-            assert broadcastSeq(new Tuple1('abc'))
-        '''
-    }
-
-    @Test
-    void testClone2() {
-        assertScript '''
-            class Value {
-                @Override
-                public Value clone() {
-                    return new Value()
-                }
-            }
-            def broadcastSeq(Object value) {
-                value.clone()
-            }
-
-            assert broadcastSeq(new Value())
-        '''
-    }
-
-    @Test
-    void testClone3() {
-        Object obj = new Tuple1('abc')
-        assert obj.clone().getClass() === Tuple1.class
-    }
-
-    @Test
-    void testClone4() {
-        assertScript '''
-            int[] nums = new int[] {1,2,3}
-            int[] copy = nums.clone()
-            assert copy !== nums
-            assert copy == nums
-        '''
-    }
-
-    // GROOVY-10747
-    @Test
-    void testClone5() {
-        ['Object', 'Dolly'].each { typeName ->
-            assertScript """
-                class Dolly implements Cloneable {
-                    public ${typeName} clone() {
-                        return super.clone()
-                    }
-                    String name
-                }
-
-                def dolly = new Dolly(name: "The Sheep")
-                def clone = dolly.clone()
-                assert clone instanceof Dolly
-            """
-        }
-    }
-
-    // GROOVY-10747
-    @Test
-    void testClone6() {
-        shouldFail CloneNotSupportedException, '''
-            class Dolly {
-                String name
-            }
-
-            def dolly = new Dolly(name: "The Sheep")
-            dolly.clone()
-        '''
-    }
-
-    @Test
-    void testClone7() {
-        ['Object', 'Dolly'].each { typeName ->
-            assertScript """
-                import static org.codehaus.groovy.runtime.InvokerHelper.*
-                class Dolly implements Cloneable {
-                    public ${typeName} clone() {
-                        return super.clone()
-                    }
-                    String name
-                }
-
-                def dolly = new Dolly(name: "The Sheep")
-                def clone = invokeMethod(dolly, 'clone', EMPTY_ARGS)
-                assert clone instanceof Dolly
-            """
-        }
-    }
-
-    @Test
-    void testClone8() {
-        shouldFail CloneNotSupportedException, '''
-            import static org.codehaus.groovy.runtime.InvokerHelper.*
-            class Dolly {
-                String name
-            }
-
-            def dolly = new Dolly(name: "The Sheep")
-            invokeMethod(dolly, 'clone', EMPTY_ARGS)
-        '''
-    }
-}
diff --git a/src/test/groovy/bugs/groovy9081/Groovy9081.groovy b/src/test/groovy/bugs/groovy9081/Groovy9081.groovy
deleted file mode 100644
index d9d6587f89..0000000000
--- a/src/test/groovy/bugs/groovy9081/Groovy9081.groovy
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- *  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 groovy.bugs.groovy9081
-
-import groovy.bugs.groovy9081.somepkg.ProtectedConstructor
-import org.junit.Test
-
-import java.awt.Font
-import java.awt.HeadlessException
-import java.lang.annotation.RetentionPolicy
-
-// TODO add JVM option `--illegal-access=deny` when all warnings fixed
-final class Groovy9081 {
-
-    @Test
-    void testAccessPublicMemberOfPrivateClass() {
-        def m = Collections.unmodifiableMap([:])
-        assert null != m.toString()
-        assert null == m.get(0)
-    }
-
-    @Test
-    void testFavorMethodWithExactParameterType() {
-        def em1 = new EnumMap(RetentionPolicy.class)
-        def em2 = new EnumMap(RetentionPolicy.class)
-
-        assert em2 == em1
-    }
-
-    @Test
-    void testShouldChoosePublicGetterInsteadOfPrivateField1() {
-        def f = Integer.class.getDeclaredField("MIN_VALUE")
-        assert 0 != f.modifiers
-    }
-
-    @Test
-    void testShouldChoosePublicGetterInsteadOfPrivateField2() {
-        def f = new Font("Monospaced", Font.PLAIN, 12)
-        assert f.name
-    }
-
-    @Test
-    void testGetPropertiesOfObjects() {
-        assert null != ''.properties
-    }
-
-    @Test
-    void testAsType1() {
-        [run: {}] as TimerTask
-    }
-
-    @Test
-    void testAsType2() {
-        [run: {}] as ProtectedConstructor
-    }
-
-    @Test
-    void testAccessPackagePrivateInnerClassMember() {
-        def m = new HashMap()
-        m.a = 69
-        m.entrySet().iterator().next().toString()
-    }
-
-    @Test
-    void testAccessPackagePrivateMethod() {
-        BigInteger a = 333
-        int b = 2
-        BigDecimal c = a * b
-        assert c == 666
-    }
-
-    @Test
-    void testGetProperty() {
-        try {
-            java.awt.Toolkit.defaultToolkit.systemClipboard
-        } catch (HeadlessException ignore) {
-        }
-    }
-}
diff --git a/src/test/groovy/bugs/groovy9081/somepkg/ProtectedConstructor.java b/src/test/groovy/bugs/groovy9081/somepkg/ProtectedConstructor.java
deleted file mode 100644
index e79fb3cbc7..0000000000
--- a/src/test/groovy/bugs/groovy9081/somepkg/ProtectedConstructor.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- *  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 groovy.bugs.groovy9081.somepkg;
-
-public class ProtectedConstructor {
-    protected ProtectedConstructor() {}
-
-    public void run() {}
-}
diff --git a/src/test/groovy/transform/ThreadInterruptTest.groovy b/src/test/groovy/transform/ThreadInterruptTest.groovy
index 484f87e48e..39672dc74f 100644
--- a/src/test/groovy/transform/ThreadInterruptTest.groovy
+++ b/src/test/groovy/transform/ThreadInterruptTest.groovy
@@ -30,7 +30,7 @@ import java.lang.reflect.Modifier
 import static groovy.test.GroovyAssert.assertScript
 import static groovy.test.GroovyAssert.isAtLeastJdk
 import static groovy.test.GroovyAssert.shouldFail
-import static org.junit.Assume.assumeTrue
+import static org.junit.Assume.assumeFalse
 
 /**
  * Tests for the {@link ThreadInterrupt} AST transform.
@@ -43,41 +43,42 @@ final class ThreadInterruptTest {
             normal 'groovy.mock.interceptor.StubFor'
         }
     }
-    private static final boolean jdk12plus = isAtLeastJdk('12.0')
     private Map<String, MethodNode> oldValues = [:]
 
-    @After
-    void tearDown() {
-        if (jdk12plus) return
-        Thread.metaClass = null
-        ['CURRENTTHREAD_METHOD', 'ISINTERRUPTED_METHOD'].each {
-            def ov = ThreadInterruptibleASTTransformation.getDeclaredField(it)
-            def modifiersField = ov.class.getDeclaredField('modifiers')
-            modifiersField.accessible = true
-            modifiersField.setInt(ov, ov.modifiers & ~Modifier.FINAL)
-            ov.accessible = true
-            ov.set(ThreadInterruptibleASTTransformation, oldValues[it])
-        }
-    }
-
     @Before
     void setUp() {
         // JDK12+ doesn't allow adjusting static final fields even via reflection, so
         // skip all tests on such JDK versions - it is only test code that's affected
         // and currently we have coverage from builds with lower JDK versions.
-        assumeTrue(!jdk12plus)
-
-        ['CURRENTTHREAD_METHOD', 'ISINTERRUPTED_METHOD'].each {
-            def ov = ThreadInterruptibleASTTransformation.getDeclaredField(it)
-            def modifiersField = ov.class.getDeclaredField('modifiers')
-            modifiersField.accessible = true
-            modifiersField.setInt(ov, ov.modifiers & ~Modifier.FINAL)
-            ov.accessible = true
-            oldValues[it] = ov.get(ThreadInterruptibleASTTransformation)
-            ov.set(ThreadInterruptibleASTTransformation, null)
+        assumeFalse(isAtLeastJdk('12.0'))
+
+        ['CURRENTTHREAD_METHOD', 'ISINTERRUPTED_METHOD'].each { name ->
+            oldValues[name] = writeField(name, null)
         }
     }
 
+    @After
+    void tearDown() {
+        Thread.metaClass = null
+        if (isAtLeastJdk('12.0')) return
+        oldValues.each(this.&writeField)
+    }
+
+    private Object writeField(String name, Object value) {
+        def field = ThreadInterruptibleASTTransformation.getDeclaredField(name)
+
+        def modifiers = field.class.getDeclaredField('modifiers')
+        modifiers.accessible = true
+        modifiers.setInt(field, field.modifiers & ~Modifier.FINAL)
+
+        field.accessible = true
+        def v = field.get(ThreadInterruptibleASTTransformation)
+        field.set(ThreadInterruptibleASTTransformation, value)
+        return v
+    }
+
+    //--------------------------------------------------------------------------
+
     @Test
     void testDefaultParameters_Method() {
         assertScript shell, '''
diff --git a/src/test/groovy/ui/GroovyMainTest.groovy b/src/test/groovy/ui/GroovyMainTest.groovy
index c79407c8ac..8272f4d4ec 100644
--- a/src/test/groovy/ui/GroovyMainTest.groovy
+++ b/src/test/groovy/ui/GroovyMainTest.groovy
@@ -18,15 +18,15 @@
  */
 package groovy.ui
 
-import groovy.test.GroovyTestCase
+import org.junit.Ignore
+import org.junit.Test
 
-import static groovy.test.GroovyAssert.isAtLeastJdk
-
-final class GroovyMainTest extends GroovyTestCase {
+final class GroovyMainTest {
 
     private baos = new ByteArrayOutputStream()
     private ps = new PrintStream(baos)
 
+    @Test
     void testHelp() {
         String[] args = ['-h']
         GroovyMain.processArgs(args, ps)
@@ -37,6 +37,7 @@ final class GroovyMainTest extends GroovyTestCase {
         }
     }
 
+    @Test
     void testVersion() {
         String[] args = ['-v']
         GroovyMain.processArgs(args, ps)
@@ -45,6 +46,7 @@ final class GroovyMainTest extends GroovyTestCase {
         assert out.contains('JVM:')
     }
 
+    @Test
     void testNoArgs() {
         String[] args = []
         GroovyMain.processArgs(args, ps)
@@ -52,6 +54,7 @@ final class GroovyMainTest extends GroovyTestCase {
         assert out.contains('error: neither -e or filename provided')
     }
 
+    @Test
     void testAttemptToRunJavaFile() {
         String[] args = ['abc.java']
         GroovyMain.processArgs(args, ps)
@@ -62,6 +65,7 @@ final class GroovyMainTest extends GroovyTestCase {
     /**
      * GROOVY-1512: Add support for begin() and end() methods when processing files by line with -a -ne
      */
+    @Test
     void testAandNEparametersWithBeginEndFunctions() {
         def originalErr = System.err
         System.setErr(ps)
@@ -83,6 +87,7 @@ final class GroovyMainTest extends GroovyTestCase {
      * GROOVY-6561 : Correct handling of scripts from a URI.
      * GROOVY-1642 : Enable a script to get its URI by annotating a field.
      */
+    @Test
     void testURISource() {
         def tempFile = File.createTempFile("groovy-ui-GroovyMainTest-testURISource", ".groovy")
         tempFile.text = """
@@ -108,6 +113,7 @@ print myURI
 
     // Gotta use configscript for this because : separated paths can't have : in them
     // and GroovyMain ignores -cp.
+    @Test
     void testURIClasspath() {
         def tempDir1 = new File("build/tmp/GroovyMainTest1")
         tempDir1.mkdirs()
@@ -143,6 +149,7 @@ assert new MyConcreteClass() != null"""
     }
 
     // GROOVY-10483
+    @Test
     void testSourceEncoding() {
         def configScript = File.createTempFile('config', '.groovy')
         def sourceCoding = System.setProperty('groovy.source.encoding', 'US-ASCII')
@@ -159,10 +166,8 @@ assert new MyConcreteClass() != null"""
         }
     }
 
+    @Test @Ignore('current xstream causes illegal access errors on JDK9+ - skip on those JDK versions, get coverage on older versions')
     void testGroovyASTDump() {
-        // current xstream causes illegal access errors on JDK9+ - skip on those JDK versions, get coverage on older versions
-        if (isAtLeastJdk('9.0')) return
-
         def temporaryDirectory = new File("build/tmp/testGroovyXMLAstGeneration/")
         temporaryDirectory.mkdirs()
 
@@ -183,17 +188,4 @@ assert new MyConcreteClass() != null"""
             System.clearProperty('groovy.ast')
         }
     }
-
-    // This works for a URL in the classpath, but there isn't a way to do this from the command line.
-//    public void testConfigURIClasspath() {
-//        URI baseURI = new URI("https://raw.github.com/jimwhite/groovy-snippets/master/GROOVY-6451/")
-//        GroovyCodeSource codeSource = new GroovyCodeSource(baseURI.resolve("run_from_uri_test.groovy"))
-//        def shell = new GroovyShell()
-//        shell.classLoader.addURL(baseURI.toURL())
-//        // We're testing whether this fails:
-//        def script = shell.parse(codeSource)
-//        script.run()
-//    }
-
-
 }
diff --git a/src/test/groovy/util/GroovyScriptEngineTest.groovy b/src/test/groovy/util/GroovyScriptEngineTest.groovy
index 804a9dd1e9..539d0fb193 100644
--- a/src/test/groovy/util/GroovyScriptEngineTest.groovy
+++ b/src/test/groovy/util/GroovyScriptEngineTest.groovy
@@ -18,35 +18,26 @@
  */
 package groovy.util
 
-import groovy.test.GroovyTestCase
 import org.codehaus.groovy.ast.ClassNode
 import org.codehaus.groovy.classgen.GeneratorContext
 import org.codehaus.groovy.control.CompilePhase
 import org.codehaus.groovy.control.CompilerConfiguration
 import org.codehaus.groovy.control.SourceUnit
 import org.codehaus.groovy.control.customizers.CompilationCustomizer
+import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 import org.junit.rules.TemporaryFolder
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
 
-import static groovy.test.GroovyAssert.isAtLeastJdk
-
-@RunWith(JUnit4)
-class GroovyScriptEngineTest extends GroovyTestCase {
+final class GroovyScriptEngineTest {
 
     @Rule
     public TemporaryFolder temporaryFolder = new TemporaryFolder()
 
-    @Test
+    @Test @Ignore('current xstream causes illegal access errors on JDK9+ - skip on those JDK versions, get coverage on older versions')
     void createASTDumpWhenScriptIsLoadedByName() {
-        // current xstream causes illegal access errors on JDK9+ - skip on those JDK versions, get coverage on older versions
-        if (isAtLeastJdk('9.0')) return
-
         def scriptFile = temporaryFolder.newFile('Script1.groovy')
         scriptFile << "assert 1 + 1 == 2" // the script just has to have _some_ content
-
         try {
             System.setProperty('groovy.ast', 'xml')
 
@@ -54,7 +45,6 @@ class GroovyScriptEngineTest extends GroovyTestCase {
 
             assert new File(temporaryFolder.root, scriptFile.name + '.xml').exists()
             assert clazz != null
-
         } finally {
             System.clearProperty('groovy.ast')
         }
@@ -76,11 +66,11 @@ class GroovyScriptEngineTest extends GroovyTestCase {
     }
 
     @Test
-    void testCustomizersAppliedOncePerClassNode_GROOVY_8402() {
+    void customizersAppliedOncePerClassNode_GROOVY_8402() {
         def scriptFile = temporaryFolder.newFile('Script1.groovy')
         scriptFile << '''
             class Foo {}
-            assert 1 + 1 == 2 
+            assert 1 + 1 == 2
         '''
         def counts = [:].withDefault { 0 }
 
@@ -97,4 +87,4 @@ class GroovyScriptEngineTest extends GroovyTestCase {
         assert counts['Script1'] == 1
         assert counts['Foo'] == 1
     }
-}
\ No newline at end of file
+}
diff --git a/src/test/groovy/util/logging/CommonsTest.groovy b/src/test/groovy/util/logging/CommonsTest.groovy
index 2b84924f24..6a17e11fe5 100644
--- a/src/test/groovy/util/logging/CommonsTest.groovy
+++ b/src/test/groovy/util/logging/CommonsTest.groovy
@@ -239,9 +239,9 @@ class CommonsTest extends GroovyTestCase {
         // JDK12+ doesn't allow adjusting static final fields even via reflection
         // so skip this test on such JDK versions - it is only this test which is affected
         // and currently we have coverage from builds with lower JDK versions.
-        if (isAtLeastJdk('12')) return
+        if (isAtLeastJdk('12.0')) return
 
-        Class clazz = new GroovyClassLoader().parseClass('''
+        Class clazz = new GroovyClassLoader().parseClass '''
             class LogDecorator extends groovy.util.Proxy {
                 boolean isTraceEnabled() { false }
             }
@@ -266,8 +266,8 @@ class CommonsTest extends GroovyTestCase {
             }
             def o = new MyClass()
             o.loggingMethod()
-            o.traceCalled''')
-
+            o.traceCalled
+        '''
         Script s = (Script) clazz.newInstance()
         def result = s.run()
         assert !result
diff --git a/src/test/org/apache/groovy/parser/antlr4/util/ASTComparatorCategory.groovy b/src/test/org/apache/groovy/parser/antlr4/util/ASTComparatorCategory.groovy
index e69f5ffd0a..23c9c8803f 100644
--- a/src/test/org/apache/groovy/parser/antlr4/util/ASTComparatorCategory.groovy
+++ b/src/test/org/apache/groovy/parser/antlr4/util/ASTComparatorCategory.groovy
@@ -259,8 +259,7 @@ class ASTComparatorCategory {
                         new LinkedList(bValue?.getClass()?.isArray() ? Arrays.asList(bValue) : (bValue ?: [])).sort {c1, c2 -> c1."${orderName}" <=> c2."${orderName}"}
             }
 
-
-            !(name in ignore) && (name != 'nodeMetaData' && name != 'metaDataMap' && name != 'groovydoc') && a."$name" != b."$name"
+            !(name in ignore) && (name != 'groovydoc' && name != 'metaDataMap' && name != 'nodeMetaData') && !a."$name".equals(b."$name")
         }
 
         if (difference)
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/ArraysAndCollectionsStaticCompileTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/ArraysAndCollectionsStaticCompileTest.groovy
index 21dda06583..db6f9a5f55 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/ArraysAndCollectionsStaticCompileTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/ArraysAndCollectionsStaticCompileTest.groovy
@@ -61,14 +61,14 @@ class ArraysAndCollectionsStaticCompileTest extends ArraysAndCollectionsSTCTest
 
     // GROOVY-5988
     void testMapArraySetPropertyAssignment() {
-        assertScript '''
-            Map<String, Object> props(Object p) {
+        assertScript '''import static java.lang.reflect.Modifier.isPrivate
+            Map<String, Object> props(Object o) {
                 Map<String, Object> props = [:]
-
-                for(String property in p.properties.keySet()){
-                    props[property] = 'TEST'
-                    // I need to use calling put directly to make it work
-                    // props.put property, 'TEST'
+                for (property in o.metaClass.properties) {
+                    if (!isPrivate(property.modifiers)) {
+                        props[property.name] = 'TEST'
+                        //props.put(property, 'TEST')
+                    }
                 }
                 props
             }
diff --git a/src/test/org/codehaus/groovy/reflection/SecurityTest.java b/src/test/org/codehaus/groovy/reflection/SecurityTest.java
index 3d42d0f78b..7b9cb765c0 100644
--- a/src/test/org/codehaus/groovy/reflection/SecurityTest.java
+++ b/src/test/org/codehaus/groovy/reflection/SecurityTest.java
@@ -277,7 +277,6 @@ public class SecurityTest extends GroovyTestCase {
         assertTrue(invokesCachedMethod());
     }
 
-
     @SuppressWarnings("removal") // TODO in a future Groovy version remove reference to SecurityManager, for now not run for JDK16+
     public void testChecksCreateClassLoaderPermissionForClassLoaderProtectedMethodAccess() throws Exception {
         // Illegal access to java.lang.ClassLoader.defineClass(java.lang.String,java.nio.ByteBuffer,java.security.ProtectionDomain)
@@ -320,5 +319,4 @@ public class SecurityTest extends GroovyTestCase {
         cachedFieldUnderTest.setProperty(object, "value");
         assertEquals("value", cachedFieldUnderTest.getProperty(object));
     }
-
 }
diff --git a/src/test/org/codehaus/groovy/runtime/m12n/ExtensionModuleHelperForTests.groovy b/src/test/org/codehaus/groovy/runtime/m12n/ExtensionModuleHelperForTests.groovy
index 8d382d8e9a..593a0c4b36 100644
--- a/src/test/org/codehaus/groovy/runtime/m12n/ExtensionModuleHelperForTests.groovy
+++ b/src/test/org/codehaus/groovy/runtime/m12n/ExtensionModuleHelperForTests.groovy
@@ -20,8 +20,6 @@ package org.codehaus.groovy.runtime.m12n
 
 import groovy.ant.AntBuilder
 
-import static groovy.test.GroovyAssert.isAtLeastJdk
-
 class ExtensionModuleHelperForTests {
 
     static void doInFork(String baseTestClass = 'groovy.test.GroovyTestCase', String code) {
@@ -57,13 +55,9 @@ class ExtensionModuleHelperForTests {
                 }
             }
         } finally {
+            baseDir.deleteDir()
             String out = ant.project.properties.out
             String err = ant.project.properties.err
-            baseDir.deleteDir()
-            // FIX_JDK9: remove once we have no warnings when running Groovy
-            if (isAtLeastJdk('9.0')) {
-                err = err?.replaceAll(/WARNING: .*/, '')?.trim()
-            }
             if (err && !allowed.any{ err.trim().matches(it) }) {
                 throw new RuntimeException("$err\nClasspath: ${cp.join('\n')}")
             }
diff --git a/src/test/org/codehaus/groovy/runtime/methoddispatching/vm8/StaticMethodOverloadCompileStaticTest.groovy b/src/test/org/codehaus/groovy/runtime/methoddispatching/vm8/StaticMethodOverloadCompileStaticTest.groovy
index 1c750891c7..9512bd2acd 100644
--- a/src/test/org/codehaus/groovy/runtime/methoddispatching/vm8/StaticMethodOverloadCompileStaticTest.groovy
+++ b/src/test/org/codehaus/groovy/runtime/methoddispatching/vm8/StaticMethodOverloadCompileStaticTest.groovy
@@ -18,29 +18,28 @@
  */
 package org.codehaus.groovy.runtime.methoddispatching.vm8
 
-import groovy.test.GroovyTestCase
 import groovy.transform.CompileStatic
-
-import static groovy.test.GroovyAssert.isAtLeastJdk
+import org.junit.Test
 
 @CompileStatic
-class StaticMethodOverloadCompileStaticTest extends GroovyTestCase {
+final class StaticMethodOverloadCompileStaticTest {
+
+    @Test
     void testOneStaticMethod() {
-        if (isJdk9()) return
         assert FooOne.foo() == "FooOne.foo()"
         assert BarOne.foo() == "BarOne.foo()"
     }
 
+    @Test
     void testTwoStaticMethods() {
-        if (isJdk9()) return
         assert FooTwo.foo() == "FooTwo.foo()"
         assert FooTwo.foo(0) == "FooTwo.foo(0)"
         assert BarTwo.foo() == "BarTwo.foo()"
         assert BarTwo.foo(0) == "BarTwo.foo(0)"
     }
 
+    @Test
     void testMoreThanTwoStaticMethods() {
-        if (isJdk9()) return
         assert FooThree.foo() == "FooThree.foo()"
         assert FooThree.foo(0) == "FooThree.foo(0)"
         assert FooThree.foo(0, 1) == "FooThree.foo(0, 1)"
@@ -48,10 +47,4 @@ class StaticMethodOverloadCompileStaticTest extends GroovyTestCase {
         assert BarThree.foo(0) == "BarThree.foo(0)"
         assert BarThree.foo(0, 1) == "BarThree.foo(0, 1)"
     }
-
-    // FIX_JDK9 JDK9 (and presumably 10+) doesn't like the way we do static methods in interfaces - remove this version
-    // check once we fix the problem
-    boolean isJdk9() {
-        isAtLeastJdk('9.0')
-    }
 }
diff --git a/src/test/org/codehaus/groovy/transform/ImmutableTransformTest.groovy b/src/test/org/codehaus/groovy/transform/ImmutableTransformTest.groovy
index fa8a41bad9..32cb6929d5 100644
--- a/src/test/org/codehaus/groovy/transform/ImmutableTransformTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/ImmutableTransformTest.groovy
@@ -127,20 +127,31 @@ final class ImmutableTransformTest {
     }
 
     @Test
-    void testImmutableListProp() {
+    void testImmutableArrayProp() {
         def objects = shell.evaluate '''
-            @Immutable class HasList {
+            @Immutable class HasArray {
                 String[] letters
-                List nums
             }
             def letters = 'A,B,C'.split(',')
-            def nums = [1, 2]
-            [new HasList(letters:letters, nums:nums), new HasList(letters, nums)]
+            [new HasArray(letters:letters), new HasArray(letters)]
         '''
         assert objects[0].hashCode() == objects[1].hashCode()
-        assert objects[0] == objects[1]
+        assert objects[0].equals( objects[1] )
         assert objects[0].letters.size() == 3
-        assert objects[0].nums.size() == 2
+    }
+
+    @Test
+    void testImmutableListProp() {
+        def objects = shell.evaluate '''
+            @Immutable class HasList {
+                List numbers
+            }
+            def numbers = [1,2,3]
+            [new HasList(numbers:numbers), new HasList(numbers)]
+        '''
+        assert objects[0].hashCode() == objects[1].hashCode()
+        assert objects[0].equals( objects[1] )
+        assert objects[0].numbers.size() == 3
     }
 
     @Test