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 fc06b784c3a39ab821c1f1615492d85853386b62
Author: Walter Duque de Estrada <[email protected]>
AuthorDate: Thu Aug 13 12:20:22 2026 -0500

    Fix compiler crash in OrderedGormTransformation's error path and add 
coverage
    
    OrderedGormTransformation is the shared dispatcher every GORM
    annotation-driven transform routes through (@Tenant, @CurrentTenant,
    @WithoutTenant, @Transactional, @Rollback, @ReadOnly), but it was only
    ever exercised via real transforms that are all CompilationUnitAware -
    so the branch of collectAndOrderGormTransformations taken for a
    discovered transform that ISN'T CompilationUnitAware, and the catch
    block that runs when a transform's GormASTTransformationClass name
    can't be loaded, were both untested.
    
    Writing a test for the unloadable-transform-name path surfaced the
    same bug fixed earlier in TenantTransform: the catch block calls the
    inherited AbstractASTTransformation#addError(String, ASTNode), which
    reads that class's own sourceUnit field - never populated here, since
    visit() never called init() to set it. Any misconfigured or broken
    custom GORM transform reference would crash the compiler with an
    internal NullPointerException instead of a clean error message. Fixed
    with a one-line call to the inherited init(astNodes, source), the
    idiomatic way AbstractASTTransformation subclasses are meant to
    populate that field.
    
    Add a spec covering both previously-unexercised branches plus
    priority(), using test-only marker annotations/transforms following
    the same local-transform-testing pattern used elsewhere in this
    branch.
    
    Coverage moves 70% -> 82% instruction, 71% -> 73% branch.
    
    Co-Authored-By: Claude Sonnet 5 <[email protected]>
---
 .../transform/OrderedGormTransformation.groovy     |  2 +
 .../ApplyNonCompilationUnitAwareTransform.java     | 40 +++++++++++++
 .../transform/ApplyUnloadableGormTransform.java    | 39 ++++++++++++
 ...onCompilationUnitAwareTestTransformation.groovy | 39 ++++++++++++
 .../transform/OrderedGormTransformationSpec.groovy | 69 ++++++++++++++++++++++
 5 files changed, 189 insertions(+)

diff --git 
a/grails-datamapping-core/src/main/groovy/org/grails/datastore/gorm/transform/OrderedGormTransformation.groovy
 
b/grails-datamapping-core/src/main/groovy/org/grails/datastore/gorm/transform/OrderedGormTransformation.groovy
index 4268096780..a0a30fea93 100644
--- 
a/grails-datamapping-core/src/main/groovy/org/grails/datastore/gorm/transform/OrderedGormTransformation.groovy
+++ 
b/grails-datamapping-core/src/main/groovy/org/grails/datastore/gorm/transform/OrderedGormTransformation.groovy
@@ -60,6 +60,8 @@ class OrderedGormTransformation extends 
AbstractASTTransformation implements Com
             throw new RuntimeException("Internal error: wrong types: 
${astNodes[0].getClass()} / ${astNodes[1].getClass()}")
         }
 
+        init(astNodes, source)
+
         AnnotatedNode annotatedNode = (AnnotatedNode) astNodes[1]
         Iterable<TransformationInvocation> astTransformations = 
collectAndOrderGormTransformations(annotatedNode)
         for (transform in astTransformations) {
diff --git 
a/grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/transform/ApplyNonCompilationUnitAwareTransform.java
 
b/grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/transform/ApplyNonCompilationUnitAwareTransform.java
new file mode 100644
index 0000000000..68bef89294
--- /dev/null
+++ 
b/grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/transform/ApplyNonCompilationUnitAwareTransform.java
@@ -0,0 +1,40 @@
+/*
+ *  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.datastore.gorm.transform;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.codehaus.groovy.transform.GroovyASTTransformationClass;
+
+/**
+ * Local marker annotation used only for testing {@link 
OrderedGormTransformation} - it routes
+ * through {@code OrderedGormTransformation} (like every real GORM annotation 
does) but resolves,
+ * via {@link GormASTTransformationClass}, to {@link 
NonCompilationUnitAwareTestTransformation},
+ * which is not {@code CompilationUnitAware}.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+@GroovyASTTransformationClass("org.grails.datastore.gorm.transform.OrderedGormTransformation")
+@GormASTTransformationClass("org.grails.datastore.gorm.transform.NonCompilationUnitAwareTestTransformation")
+public @interface ApplyNonCompilationUnitAwareTransform {
+}
diff --git 
a/grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/transform/ApplyUnloadableGormTransform.java
 
b/grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/transform/ApplyUnloadableGormTransform.java
new file mode 100644
index 0000000000..2f1c7ba426
--- /dev/null
+++ 
b/grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/transform/ApplyUnloadableGormTransform.java
@@ -0,0 +1,39 @@
+/*
+ *  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.datastore.gorm.transform;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.codehaus.groovy.transform.GroovyASTTransformationClass;
+
+/**
+ * Local marker annotation used only for testing {@link 
OrderedGormTransformation}'s error path in
+ * {@code collectAndOrderGormTransformations}: the {@link 
GormASTTransformationClass} value
+ * deliberately names a class that does not exist, so loading it throws and 
the catch block runs.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+@GroovyASTTransformationClass("org.grails.datastore.gorm.transform.OrderedGormTransformation")
+@GormASTTransformationClass("org.grails.datastore.gorm.transform.ThisClassDoesNotExist")
+public @interface ApplyUnloadableGormTransform {
+}
diff --git 
a/grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/transform/NonCompilationUnitAwareTestTransformation.groovy
 
b/grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/transform/NonCompilationUnitAwareTestTransformation.groovy
new file mode 100644
index 0000000000..b04be1fc78
--- /dev/null
+++ 
b/grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/transform/NonCompilationUnitAwareTestTransformation.groovy
@@ -0,0 +1,39 @@
+/*
+ *  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.datastore.gorm.transform
+
+import org.codehaus.groovy.ast.ASTNode
+import org.codehaus.groovy.control.SourceUnit
+import org.codehaus.groovy.transform.ASTTransformation
+
+/**
+ * A minimal {@link ASTTransformation} that deliberately does NOT implement
+ * {@code groovy.transform.CompilationUnitAware}, used only to exercise the 
branch of
+ * {@link OrderedGormTransformation#collectAndOrderGormTransformations} taken 
for a discovered
+ * transform that isn't compilation-unit-aware (every other GORM transform in 
this codebase is,
+ * via {@link AbstractGormASTTransformation}, so that branch is otherwise 
unexercised).
+ *
+ * @see OrderedGormTransformationSpec
+ */
+class NonCompilationUnitAwareTestTransformation implements ASTTransformation {
+
+    @Override
+    void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {
+    }
+}
diff --git 
a/grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/transform/OrderedGormTransformationSpec.groovy
 
b/grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/transform/OrderedGormTransformationSpec.groovy
new file mode 100644
index 0000000000..b0a00632aa
--- /dev/null
+++ 
b/grails-datamapping-core/src/test/groovy/org/grails/datastore/gorm/transform/OrderedGormTransformationSpec.groovy
@@ -0,0 +1,69 @@
+/*
+ *  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.datastore.gorm.transform
+
+import org.apache.grails.common.compiler.GroovyTransformOrder
+
+import spock.lang.Specification
+
+/**
+ * {@code OrderedGormTransformation} is the shared dispatcher every GORM 
annotation-driven
+ * transform routes through ({@code @Tenant}, {@code @CurrentTenant}, {@code 
@WithoutTenant},
+ * {@code @Transactional}, {@code @Rollback}, {@code @ReadOnly}), but every 
one of those real
+ * transforms is {@code CompilationUnitAware} - so the branch of
+ * {@code collectAndOrderGormTransformations} taken for a discovered transform 
that is NOT
+ * {@code CompilationUnitAware} was never exercised. Neither was the catch 
block that runs when a
+ * transform's {@code GormASTTransformationClass} name can't be loaded at all.
+ */
+class OrderedGormTransformationSpec extends Specification {
+
+    void "a discovered transform that is not CompilationUnitAware is still 
collected and invoked"() {
+        when: 'a class is annotated with a marker that resolves to a plain, 
non-CompilationUnitAware transform'
+        new GroovyClassLoader().parseClass('''
+            package org.grails.datastore.gorm.transform.fixture
+
+            
@org.grails.datastore.gorm.transform.ApplyNonCompilationUnitAwareTransform
+            class NonCompilationUnitAwareTarget {
+            }
+        ''')
+
+        then: 'the class compiles cleanly, proving the transform was collected 
and invoked without attempting an invalid CompilationUnitAware cast'
+        noExceptionThrown()
+    }
+
+    void "a transform whose class name cannot be loaded is reported as a 
compile error instead of crashing"() {
+        when: 'a class is annotated with a marker whose 
GormASTTransformationClass names a nonexistent class'
+        new GroovyClassLoader().parseClass('''
+            package org.grails.datastore.gorm.transform.fixture
+
+            @org.grails.datastore.gorm.transform.ApplyUnloadableGormTransform
+            class UnloadableTransformTarget {
+            }
+        ''')
+
+        then: 'a normal compile error is reported rather than an internal 
compiler crash'
+        org.codehaus.groovy.control.MultipleCompilationErrorsException e = 
thrown()
+        e.message.contains('Could not load GORM transform')
+    }
+
+    void "priority orders the transform via GORM_TRANSFORMS_ORDER"() {
+        expect:
+        new OrderedGormTransformation().priority() == 
GroovyTransformOrder.GORM_TRANSFORMS_ORDER
+    }
+}

Reply via email to