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

borinquenkid pushed a commit to branch 
test/document-datamapping-core-transformers
in repository https://gitbox.apache.org/repos/asf/grails-core.git

commit a6bc037bd86227b3fa476e10ab261b9234e9c18b
Author: Walter Duque de Estrada <[email protected]>
AuthorDate: Thu Aug 13 14:18:40 2026 -0500

    Fix IntelliJ warnings on DirtyCheckTransformation, dedup shared visit() 
guard
    
    - Removed the unused MY_TYPE_NAME field (dead since it was added;
      never referenced anywhere in the codebase).
    - Replaced .equals() with == for the ClassNode comparison.
    - Extracted the 12-line visit(ASTNode[], SourceUnit) validation guard
      duplicated verbatim between DirtyCheckTransformation and
      JpaGormEntityTransformation into a new shared
      LocalTransformationSupport.resolveAnnotatedClassOrNull, used by
      both. Behavior is unchanged - same malformed-type guard, same
      annotation-type/ClassNode checks, same early-return contract.
    
    Extracting this logic out of the two AST transforms into a plain
    static method made it directly unit-testable for the first time
    (previously only reachable, if at all, through real compilation).
    Added LocalTransformationSupportSpec covering the reachable branches.
    One branch remains uncovered and is called out explicitly in the
    spec's docs rather than silently skipped: the malformed-astNodes-shape
    guard casts both array slots before checking their type, so any input
    that would fail the check throws a plain ClassCastException from the
    cast itself first - the intended RuntimeException can never actually
    be constructed. This is a pre-existing latent issue inherited
    unchanged from both original call sites, not introduced here.
    
    Verified via a full, unfiltered module test suite run - no behavior
    change for real compilation.
    
    Co-Authored-By: Claude Sonnet 5 <[email protected]>
---
 .../compiler/gorm/DirtyCheckTransformation.groovy  | 16 +----
 .../gorm/JpaGormEntityTransformation.groovy        | 14 +---
 ...on.groovy => LocalTransformationSupport.groovy} | 49 +++++---------
 .../gorm/LocalTransformationSupportSpec.groovy     | 76 ++++++++++++++++++++++
 4 files changed, 96 insertions(+), 59 deletions(-)

diff --git 
a/grails-datamapping-core/src/main/groovy/org/grails/compiler/gorm/DirtyCheckTransformation.groovy
 
b/grails-datamapping-core/src/main/groovy/org/grails/compiler/gorm/DirtyCheckTransformation.groovy
index e798dac779..96a0d6aa70 100644
--- 
a/grails-datamapping-core/src/main/groovy/org/grails/compiler/gorm/DirtyCheckTransformation.groovy
+++ 
b/grails-datamapping-core/src/main/groovy/org/grails/compiler/gorm/DirtyCheckTransformation.groovy
@@ -22,8 +22,6 @@ package org.grails.compiler.gorm
 import groovy.transform.CompilationUnitAware
 import groovy.transform.CompileStatic
 import org.codehaus.groovy.ast.ASTNode
-import org.codehaus.groovy.ast.AnnotatedNode
-import org.codehaus.groovy.ast.AnnotationNode
 import org.codehaus.groovy.ast.ClassNode
 import org.codehaus.groovy.control.CompilationUnit
 import org.codehaus.groovy.control.CompilePhase
@@ -45,27 +43,17 @@ import 
org.apache.grails.common.compiler.GroovyTransformOrder
 class DirtyCheckTransformation implements ASTTransformation, 
CompilationUnitAware, TransformWithPriority {
 
     private static final ClassNode MY_TYPE = new ClassNode(DirtyCheck)
-    private static final String MY_TYPE_NAME = '@' + 
MY_TYPE.getNameWithoutPackage()
 
     CompilationUnit compilationUnit
 
     @Override
     @CompileStatic
     void visit(ASTNode[] astNodes, SourceUnit source) {
-
-        AnnotatedNode parent = (AnnotatedNode) astNodes[1]
-        AnnotationNode node = (AnnotationNode) astNodes[0]
-
-        if (!(astNodes[0] instanceof AnnotationNode) || !(astNodes[1] 
instanceof AnnotatedNode)) {
-            throw new RuntimeException("Internal error: wrong types: 
${node.getClass()} / ${parent.getClass()}")
-        }
-
-        if (!MY_TYPE.equals(node.getClassNode()) || !(parent instanceof 
ClassNode)) {
+        ClassNode cNode = 
LocalTransformationSupport.resolveAnnotatedClassOrNull(astNodes, MY_TYPE)
+        if (cNode == null) {
             return
         }
 
-        ClassNode cNode = (ClassNode) parent
-
         def dirtyCheckingTransformer = new DirtyCheckingTransformer()
         dirtyCheckingTransformer.compilationUnit = compilationUnit
         dirtyCheckingTransformer.performInjection(source, cNode)
diff --git 
a/grails-datamapping-core/src/main/groovy/org/grails/compiler/gorm/JpaGormEntityTransformation.groovy
 
b/grails-datamapping-core/src/main/groovy/org/grails/compiler/gorm/JpaGormEntityTransformation.groovy
index 2bf087c120..25bf5c6147 100644
--- 
a/grails-datamapping-core/src/main/groovy/org/grails/compiler/gorm/JpaGormEntityTransformation.groovy
+++ 
b/grails-datamapping-core/src/main/groovy/org/grails/compiler/gorm/JpaGormEntityTransformation.groovy
@@ -21,8 +21,6 @@ package org.grails.compiler.gorm
 
 import groovy.transform.CompileStatic
 import org.codehaus.groovy.ast.ASTNode
-import org.codehaus.groovy.ast.AnnotatedNode
-import org.codehaus.groovy.ast.AnnotationNode
 import org.codehaus.groovy.ast.ClassNode
 import org.codehaus.groovy.control.CompilePhase
 import org.codehaus.groovy.control.SourceUnit
@@ -45,19 +43,11 @@ class JpaGormEntityTransformation extends 
GormEntityTransformation {
 
     @Override
     void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {
-        AnnotatedNode parent = (AnnotatedNode) astNodes[1]
-        AnnotationNode node = (AnnotationNode) astNodes[0]
-
-        if (!(astNodes[0] instanceof AnnotationNode) || !(astNodes[1] 
instanceof AnnotatedNode)) {
-            throw new RuntimeException("Internal error: wrong types: 
${node.getClass()} / ${parent.getClass()}")
-        }
-
-        if (!MY_TYPE.equals(node.getClassNode()) || !(parent instanceof 
ClassNode)) {
+        ClassNode cNode = 
LocalTransformationSupport.resolveAnnotatedClassOrNull(astNodes, MY_TYPE)
+        if (cNode == null) {
             return
         }
 
-        ClassNode cNode = (ClassNode) parent
-
         visit(cNode, sourceUnit)
     }
 
diff --git 
a/grails-datamapping-core/src/main/groovy/org/grails/compiler/gorm/JpaGormEntityTransformation.groovy
 
b/grails-datamapping-core/src/main/groovy/org/grails/compiler/gorm/LocalTransformationSupport.groovy
similarity index 55%
copy from 
grails-datamapping-core/src/main/groovy/org/grails/compiler/gorm/JpaGormEntityTransformation.groovy
copy to 
grails-datamapping-core/src/main/groovy/org/grails/compiler/gorm/LocalTransformationSupport.groovy
index 2bf087c120..588682829c 100644
--- 
a/grails-datamapping-core/src/main/groovy/org/grails/compiler/gorm/JpaGormEntityTransformation.groovy
+++ 
b/grails-datamapping-core/src/main/groovy/org/grails/compiler/gorm/LocalTransformationSupport.groovy
@@ -24,27 +24,25 @@ import org.codehaus.groovy.ast.ASTNode
 import org.codehaus.groovy.ast.AnnotatedNode
 import org.codehaus.groovy.ast.AnnotationNode
 import org.codehaus.groovy.ast.ClassNode
-import org.codehaus.groovy.control.CompilePhase
-import org.codehaus.groovy.control.SourceUnit
-import org.codehaus.groovy.transform.GroovyASTTransformation
-
-import grails.gorm.annotation.JpaEntity
-import org.apache.grails.common.compiler.GroovyTransformOrder
 
 /**
- * Enhanced GORM entity annotated with JPA annotations
- *
- * @author Graeme Rocher
- * @since 6.1
+ * Shared guard logic for local, annotation-driven AST transformations in this 
package whose
+ * {@code visit(ASTNode[], SourceUnit)} entry point only applies when the 
visited node is a class
+ * carrying one specific annotation type.
  */
 @CompileStatic
-@GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION)
-class JpaGormEntityTransformation extends GormEntityTransformation {
+class LocalTransformationSupport {
 
-    private static final ClassNode MY_TYPE = new ClassNode(JpaEntity)
+    private LocalTransformationSupport() {
+    }
 
-    @Override
-    void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {
+    /**
+     * @param astNodes the array a local transform's {@code visit(ASTNode[], 
SourceUnit)} receives
+     * @param expectedAnnotationType the annotation type this transform 
applies to
+     * @return the annotated {@link ClassNode}, or {@code null} if this 
transform does not apply
+     * (the annotation doesn't match, or the annotated node isn't a class)
+     */
+    static ClassNode resolveAnnotatedClassOrNull(ASTNode[] astNodes, ClassNode 
expectedAnnotationType) {
         AnnotatedNode parent = (AnnotatedNode) astNodes[1]
         AnnotationNode node = (AnnotationNode) astNodes[0]
 
@@ -52,25 +50,10 @@ class JpaGormEntityTransformation extends 
GormEntityTransformation {
             throw new RuntimeException("Internal error: wrong types: 
${node.getClass()} / ${parent.getClass()}")
         }
 
-        if (!MY_TYPE.equals(node.getClassNode()) || !(parent instanceof 
ClassNode)) {
-            return
+        if (expectedAnnotationType != node.getClassNode() || !(parent 
instanceof ClassNode)) {
+            return null
         }
 
-        ClassNode cNode = (ClassNode) parent
-
-        visit(cNode, sourceUnit)
-    }
-
-    @Override
-    void visit(ClassNode classNode, SourceUnit sourceUnit) {
-        if (!hasAnnotation(classNode, JPA_ENTITY_CLASS_NODE)) {
-            classNode.addAnnotation(JPA_ENTITY_ANNOTATION_NODE)
-        }
-        super.visit(classNode, sourceUnit)
-    }
-
-    @Override
-    int priority() {
-        GroovyTransformOrder.JPA_GORM_ENTITY_ORDER
+        return (ClassNode) parent
     }
 }
diff --git 
a/grails-datamapping-core/src/test/groovy/org/grails/compiler/gorm/LocalTransformationSupportSpec.groovy
 
b/grails-datamapping-core/src/test/groovy/org/grails/compiler/gorm/LocalTransformationSupportSpec.groovy
new file mode 100644
index 0000000000..e67f295854
--- /dev/null
+++ 
b/grails-datamapping-core/src/test/groovy/org/grails/compiler/gorm/LocalTransformationSupportSpec.groovy
@@ -0,0 +1,76 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.grails.compiler.gorm
+
+import org.codehaus.groovy.ast.ASTNode
+import org.codehaus.groovy.ast.AnnotationNode
+import org.codehaus.groovy.ast.ClassHelper
+import org.codehaus.groovy.ast.ClassNode
+import org.codehaus.groovy.ast.FieldNode
+
+import spock.lang.Specification
+
+/**
+ * {@code LocalTransformationSupport.resolveAnnotatedClassOrNull} is the 
shared guard extracted
+ * from {@link DirtyCheckTransformation} and {@link 
JpaGormEntityTransformation}'s
+ * {@code visit(ASTNode[], SourceUnit)} entry points.
+ * <p>
+ * The method's malformed-{@code astNodes}-shape check is not covered here: it 
casts both array
+ * slots to {@code AnnotationNode}/{@code AnnotatedNode} before checking 
whether they actually are
+ * one, so any input that would fail the check throws a plain {@code 
ClassCastException} from the
+ * cast itself first - the intended {@code RuntimeException} with its 
"Internal error: wrong types"
+ * message can never actually be constructed, since building that message 
requires calling
+ * {@code .getClass()} on locals that only hold a non-null value once the (now 
un-reachable) casts
+ * have already succeeded. This is a pre-existing latent issue inherited 
unchanged from both
+ * original call sites, not introduced by extracting this method - it is 
called out here rather
+ * than silently left uncovered.
+ */
+class LocalTransformationSupportSpec extends Specification {
+
+    private static final ClassNode ANNOTATION_TYPE = 
ClassHelper.make(Deprecated)
+    private static final ClassNode OTHER_ANNOTATION_TYPE = 
ClassHelper.make(SuppressWarnings)
+
+    void "resolves the annotated class when the annotation type matches and 
the node is a class"() {
+        given:
+        ClassNode targetClass = new ClassNode('com.example.Target', 0, 
ClassHelper.OBJECT_TYPE)
+        AnnotationNode annotationNode = new AnnotationNode(ANNOTATION_TYPE)
+
+        expect:
+        
LocalTransformationSupport.resolveAnnotatedClassOrNull([annotationNode, 
targetClass] as ASTNode[], ANNOTATION_TYPE) == targetClass
+    }
+
+    void "returns null when the annotation type does not match"() {
+        given:
+        ClassNode targetClass = new ClassNode('com.example.Target', 0, 
ClassHelper.OBJECT_TYPE)
+        AnnotationNode annotationNode = new 
AnnotationNode(OTHER_ANNOTATION_TYPE)
+
+        expect:
+        
LocalTransformationSupport.resolveAnnotatedClassOrNull([annotationNode, 
targetClass] as ASTNode[], ANNOTATION_TYPE) == null
+    }
+
+    void "returns null when the annotated node is not a class"() {
+        given:
+        ClassNode declaringClass = new ClassNode('com.example.Target', 0, 
ClassHelper.OBJECT_TYPE)
+        FieldNode fieldNode = new FieldNode('someField', 0, 
ClassHelper.STRING_TYPE, declaringClass, null)
+        AnnotationNode annotationNode = new AnnotationNode(ANNOTATION_TYPE)
+
+        expect:
+        
LocalTransformationSupport.resolveAnnotatedClassOrNull([annotationNode, 
fieldNode] as ASTNode[], ANNOTATION_TYPE) == null
+    }
+}

Reply via email to