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

paulk 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 022b14b  GROOVY-10252: @Final should have a boolean attribute to 
disable
022b14b is described below

commit 022b14bfc6683f4ad45a5bd49bc3112cf3a09d75
Author: Paul King <[email protected]>
AuthorDate: Thu Sep 23 00:02:50 2021 +1000

    GROOVY-10252: @Final should have a boolean attribute to disable
---
 src/main/java/groovy/transform/Final.java          | 10 +++++++
 .../groovy/transform/FinalASTTransformation.java   |  1 +
 .../groovy/transform/FinalTransformTest.groovy     | 32 ++++++++++++++++++++++
 3 files changed, 43 insertions(+)

diff --git a/src/main/java/groovy/transform/Final.java 
b/src/main/java/groovy/transform/Final.java
index 577ac4f..911744d 100644
--- a/src/main/java/groovy/transform/Final.java
+++ b/src/main/java/groovy/transform/Final.java
@@ -60,6 +60,10 @@ import java.lang.annotation.Target;
  * would have all parameters marked final (from &#64;AutoFinal), and
  * would have all parameters checked against {@code null} (from 
&#64;NullCheck).
  * </p>
+ * In general, it would be bad style to have an explicit {@code final} 
modifier and a {@code @Final} annotation
+ * (or more than one {@code @Final} annotation),
+ * but in that scenario if there is an explicit {@code final} or at least one 
enabled {@code @Final},
+ * then the annotated class or member will be final.
  *
  * @since 4.0.0
  */
@@ -68,4 +72,10 @@ import java.lang.annotation.Target;
 @Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, 
ElementType.FIELD})
 
@GroovyASTTransformationClass("org.codehaus.groovy.transform.FinalASTTransformation")
 public @interface Final {
+    /**
+     * When disabled, this annotation effectively becomes a no-op.
+     * Typically only used to override an annotation collector already 
containing an enabled {@code @Final} annotation.
+     * Care must be taken when disabling final in this way since the 
annotation collector probably had good reason for enabling final.
+     */
+    boolean enabled() default true;
 }
diff --git 
a/src/main/java/org/codehaus/groovy/transform/FinalASTTransformation.java 
b/src/main/java/org/codehaus/groovy/transform/FinalASTTransformation.java
index 5f610b0..65f6ca2 100644
--- a/src/main/java/org/codehaus/groovy/transform/FinalASTTransformation.java
+++ b/src/main/java/org/codehaus/groovy/transform/FinalASTTransformation.java
@@ -47,6 +47,7 @@ public class FinalASTTransformation extends 
AbstractASTTransformation {
         AnnotatedNode candidate = (AnnotatedNode) nodes[1];
         AnnotationNode node = (AnnotationNode) nodes[0];
         if (!MY_TYPE.equals(node.getClassNode())) return;
+        if (memberHasValue(node, "enabled", false)) return;
 
         if (candidate instanceof ClassNode) {
             ClassNode cNode = (ClassNode) candidate;
diff --git a/src/test/org/codehaus/groovy/transform/FinalTransformTest.groovy 
b/src/test/org/codehaus/groovy/transform/FinalTransformTest.groovy
index 53db5c7..81ced8f 100644
--- a/src/test/org/codehaus/groovy/transform/FinalTransformTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/FinalTransformTest.groovy
@@ -47,6 +47,38 @@ class FinalTransformTest {
     }
 
     @Test
+    void testUsageDirectDisabled() {
+        assertScript """
+            import groovy.transform.*
+            import static java.lang.reflect.Modifier.isFinal
+
+            @Final(enabled=false)
+            class Foo {}
+
+            assert !isFinal(Foo.modifiers)
+        """
+    }
+
+    @Test
+    void testUsageInAnnoationCollectorForClassDisabled() {
+        assertScript """
+            import groovy.transform.*
+            import static java.lang.reflect.Modifier.isFinal
+
+            
@AnnotationCollector(mode=AnnotationCollectorMode.PREFER_EXPLICIT_MERGED)
+            @Canonical
+            @Final
+            @interface MyCanonical {}
+
+            @MyCanonical
+            @Final(enabled=false)
+            class Foo {}
+
+            assert !isFinal(Foo.modifiers)
+        """
+    }
+
+    @Test
     void testUsageInAnnoationCollectorForMethod() {
         assertScript """
             import groovy.transform.*

Reply via email to