You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2022/07/22 04:29:57 UTC

[groovy] branch master updated: GROOVY-10697: @ToString throws an NPE for POJO with null field

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 b29512397d GROOVY-10697: @ToString throws an NPE for POJO with null field
b29512397d is described below

commit b29512397d6ff199976dfb8709c5950e525ac8d6
Author: Paul King <pa...@asert.com.au>
AuthorDate: Thu Jul 21 16:42:59 2022 +1000

    GROOVY-10697: @ToString throws an NPE for POJO with null field
---
 .../java/org/apache/groovy/ast/tools/MethodCallUtils.java |  7 +++++++
 .../groovy/transform/ToStringASTTransformation.java       |  7 ++++---
 .../groovy/transform/ToStringTransformTest.groovy         | 15 +++++++++++++++
 .../groovy/console/ui/AstNodeToScriptAdapterTest.groovy   |  2 +-
 4 files changed, 27 insertions(+), 4 deletions(-)

diff --git a/src/main/java/org/apache/groovy/ast/tools/MethodCallUtils.java b/src/main/java/org/apache/groovy/ast/tools/MethodCallUtils.java
index 6b06eb1136..820cbc6a4e 100644
--- a/src/main/java/org/apache/groovy/ast/tools/MethodCallUtils.java
+++ b/src/main/java/org/apache/groovy/ast/tools/MethodCallUtils.java
@@ -23,7 +23,10 @@ import org.codehaus.groovy.ast.expr.MethodCallExpression;
 import org.codehaus.groovy.ast.stmt.Statement;
 
 import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.constX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.isNullX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.ternaryX;
 
 /**
  * Utility class for commonly called methods
@@ -43,4 +46,8 @@ public class MethodCallUtils {
         toString.setImplicitThis(false);
         return toString;
     }
+
+    public static Expression maybeNullToStringX(final Expression object) {
+        return ternaryX(isNullX(object), constX("null"), toStringX(object));
+    }
 }
diff --git a/src/main/java/org/codehaus/groovy/transform/ToStringASTTransformation.java b/src/main/java/org/codehaus/groovy/transform/ToStringASTTransformation.java
index 1924ea6864..759201e10d 100644
--- a/src/main/java/org/codehaus/groovy/transform/ToStringASTTransformation.java
+++ b/src/main/java/org/codehaus/groovy/transform/ToStringASTTransformation.java
@@ -38,7 +38,7 @@ import org.codehaus.groovy.ast.stmt.Statement;
 import org.codehaus.groovy.control.CompilePhase;
 import org.codehaus.groovy.control.SourceUnit;
 import org.codehaus.groovy.runtime.DefaultGroovyMethods;
-import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.FormatHelper;
 import org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport;
 
 import java.util.ArrayList;
@@ -49,6 +49,7 @@ import java.util.Set;
 
 import static org.apache.groovy.ast.tools.ClassNodeUtils.addGeneratedMethod;
 import static org.apache.groovy.ast.tools.MethodCallUtils.appendS;
+import static org.apache.groovy.ast.tools.MethodCallUtils.maybeNullToStringX;
 import static org.apache.groovy.ast.tools.MethodCallUtils.toStringX;
 import static org.codehaus.groovy.ast.ClassHelper.make;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.assignS;
@@ -82,7 +83,7 @@ public class ToStringASTTransformation extends AbstractASTTransformation {
     static final ClassNode MY_TYPE = make(MY_CLASS);
     static final String MY_TYPE_NAME = "@" + MY_TYPE.getNameWithoutPackage();
     private static final ClassNode STRINGBUILDER_TYPE = make(StringBuilder.class);
-    private static final ClassNode INVOKER_TYPE = make(InvokerHelper.class);
+    private static final ClassNode FORMAT_TYPE = make(FormatHelper.class);
     private static final ClassNode POJO_TYPE = make(POJO.class);
     private static final String TO_STRING = "toString";
     private static final String UNDER_TO_STRING = "_toString";
@@ -272,7 +273,7 @@ public class ToStringASTTransformation extends AbstractASTTransformation {
         final Statement appendValue = ignoreNulls ? ifS(notNullX(value), thenBlock) : thenBlock;
         appendCommaIfNotFirst(thenBlock, result, first, delims);
         appendPrefix(thenBlock, result, name, includeNames, delims);
-        Expression toString = pojo ? toStringX(value) : callX(INVOKER_TYPE, TO_STRING, value);
+        Expression toString = pojo ? maybeNullToStringX(value) : callX(FORMAT_TYPE, TO_STRING, value);
         if (canBeSelf) {
             thenBlock.addStatement(ifElseS(
                     sameX(value, varX("this")),
diff --git a/src/test/org/codehaus/groovy/transform/ToStringTransformTest.groovy b/src/test/org/codehaus/groovy/transform/ToStringTransformTest.groovy
index 12eb461640..9625ab5cdf 100644
--- a/src/test/org/codehaus/groovy/transform/ToStringTransformTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/ToStringTransformTest.groovy
@@ -514,4 +514,19 @@ class ToStringTransformTest extends GroovyShellTestCase {
         """
     }
 
+    // GROOVY-10697
+    void testToStringOnPojoWithNullField() {
+        assertScript '''
+            import groovy.transform.*
+
+            @ToString(pojo=true)
+            @CompileStatic
+            class Clazz {
+                String field = null
+            }
+
+            assert new Clazz().toString() == 'Clazz(null)'
+        '''
+    }
+
 }
diff --git a/subprojects/groovy-console/src/test/groovy/groovy/console/ui/AstNodeToScriptAdapterTest.groovy b/subprojects/groovy-console/src/test/groovy/groovy/console/ui/AstNodeToScriptAdapterTest.groovy
index b8a9cec72b..136862307a 100644
--- a/subprojects/groovy-console/src/test/groovy/groovy/console/ui/AstNodeToScriptAdapterTest.groovy
+++ b/subprojects/groovy-console/src/test/groovy/groovy/console/ui/AstNodeToScriptAdapterTest.groovy
@@ -579,7 +579,7 @@ final class AstNodeToScriptAdapterTest extends GroovyTestCase {
 
         String result = compileToScript(script, CompilePhase.CANONICALIZATION)
         // we had problems with the ast transform passing a VariableExpression as StaticMethodCallExpression arguments
-        assert result.contains("_result.append(org.codehaus.groovy.runtime.InvokerHelper.toString(this.getWhen())")
+        assert result.contains("_result.append(org.codehaus.groovy.runtime.FormatHelper.toString(this.getWhen())")
     }
 
     void testAtImmutableClassWithProperties() {