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 2018/03/09 06:39:46 UTC
groovy git commit: GROOVY-8501: Switch internal details of
@ImmutableBase existing constructor validation (closes #673)
Repository: groovy
Updated Branches:
refs/heads/master c8446c770 -> 7379d522b
GROOVY-8501: Switch internal details of @ImmutableBase existing constructor validation (closes #673)
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/7379d522
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/7379d522
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/7379d522
Branch: refs/heads/master
Commit: 7379d522b3752a9459d8351fd3d8a970426047b4
Parents: c8446c7
Author: paulk <pa...@asert.com.au>
Authored: Thu Mar 8 23:25:24 2018 +1000
Committer: paulk <pa...@asert.com.au>
Committed: Fri Mar 9 16:39:07 2018 +1000
----------------------------------------------------------------------
.../groovy/transform/builder/Builder.java | 11 +++++
.../transform/builder/DefaultStrategy.java | 1 +
.../transform/builder/ExternalStrategy.java | 1 +
.../transform/builder/InitializerStrategy.java | 20 ++++++----
.../transform/builder/SimpleStrategy.java | 1 +
.../groovy/ast/tools/AnnotatedNodeUtils.java | 42 ++++++++++++++++++++
.../apache/groovy/ast/tools/ClassNodeUtils.java | 28 +++++++++++++
.../transform/ImmutableASTTransformation.java | 19 +--------
.../MapConstructorASTTransformation.java | 16 ++++++--
.../TupleConstructorASTTransformation.java | 13 ++++--
.../transform/BuilderTransformTest.groovy | 20 +++++++++-
11 files changed, 138 insertions(+), 34 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/groovy/blob/7379d522/src/main/groovy/groovy/transform/builder/Builder.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/transform/builder/Builder.java b/src/main/groovy/groovy/transform/builder/Builder.java
index 4389dc4..b72777a 100644
--- a/src/main/groovy/groovy/transform/builder/Builder.java
+++ b/src/main/groovy/groovy/transform/builder/Builder.java
@@ -161,4 +161,15 @@ public @interface Builder {
* @since 2.5.0
*/
boolean allProperties() default true;
+
+ /**
+ * Whether to always include helper constructors. Currently only supported by InitializerStrategy.
+ * By default, the InitializerStrategy only adds a needed helper tuple constructor if no {@code @TupleConstructor}
+ * annotations are present. If such annotations are present, it is assumed they will provide the helper constructor
+ * that this strategy needs. If made true, the helper constructor will be generated and it is up to you to make sure
+ * this doesn't conflict with any other generated constructors.
+ *
+ * @since 2.5.0
+ */
+ boolean force() default false;
}
http://git-wip-us.apache.org/repos/asf/groovy/blob/7379d522/src/main/groovy/groovy/transform/builder/DefaultStrategy.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/transform/builder/DefaultStrategy.java b/src/main/groovy/groovy/transform/builder/DefaultStrategy.java
index 65d90e3..b0dfae4 100644
--- a/src/main/groovy/groovy/transform/builder/DefaultStrategy.java
+++ b/src/main/groovy/groovy/transform/builder/DefaultStrategy.java
@@ -166,6 +166,7 @@ public class DefaultStrategy extends BuilderASTTransformation.AbstractBuilderStr
public void build(BuilderASTTransformation transform, AnnotatedNode annotatedNode, AnnotationNode anno) {
if (unsupportedAttribute(transform, anno, "forClass")) return;
+ if (unsupportedAttribute(transform, anno, "force")) return;
if (annotatedNode instanceof ClassNode) {
buildClass(transform, (ClassNode) annotatedNode, anno);
} else if (annotatedNode instanceof MethodNode) {
http://git-wip-us.apache.org/repos/asf/groovy/blob/7379d522/src/main/groovy/groovy/transform/builder/ExternalStrategy.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/transform/builder/ExternalStrategy.java b/src/main/groovy/groovy/transform/builder/ExternalStrategy.java
index c482bef..cba3b8b 100644
--- a/src/main/groovy/groovy/transform/builder/ExternalStrategy.java
+++ b/src/main/groovy/groovy/transform/builder/ExternalStrategy.java
@@ -109,6 +109,7 @@ public class ExternalStrategy extends BuilderASTTransformation.AbstractBuilderSt
if (includes.size() == 1 && Undefined.isUndefined(includes.get(0))) includes = null;
if (unsupportedAttribute(transform, anno, "builderClassName")) return;
if (unsupportedAttribute(transform, anno, "builderMethodName")) return;
+ if (unsupportedAttribute(transform, anno, "force")) return;
boolean allNames = transform.memberHasValue(anno, "allNames", true);
boolean allProperties = !transform.memberHasValue(anno, "allProperties", false);
List<PropertyInfo> props = getPropertyInfos(transform, anno, buildee, excludes, includes, allNames, allProperties);
http://git-wip-us.apache.org/repos/asf/groovy/blob/7379d522/src/main/groovy/groovy/transform/builder/InitializerStrategy.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/transform/builder/InitializerStrategy.java b/src/main/groovy/groovy/transform/builder/InitializerStrategy.java
index e59dac5..1b7e0be 100644
--- a/src/main/groovy/groovy/transform/builder/InitializerStrategy.java
+++ b/src/main/groovy/groovy/transform/builder/InitializerStrategy.java
@@ -18,6 +18,7 @@
*/
package groovy.transform.builder;
+import groovy.transform.TupleConstructor;
import groovy.transform.Undefined;
import org.codehaus.groovy.ast.AnnotatedNode;
import org.codehaus.groovy.ast.AnnotationNode;
@@ -34,12 +35,12 @@ import org.codehaus.groovy.ast.stmt.BlockStatement;
import org.codehaus.groovy.classgen.Verifier;
import org.codehaus.groovy.transform.AbstractASTTransformation;
import org.codehaus.groovy.transform.BuilderASTTransformation;
-import org.codehaus.groovy.transform.ImmutableASTTransformation;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import static org.apache.groovy.ast.tools.AnnotatedNodeUtils.markAsGenerated;
import static org.codehaus.groovy.ast.ClassHelper.OBJECT_TYPE;
import static org.codehaus.groovy.ast.tools.GeneralUtils.args;
import static org.codehaus.groovy.ast.tools.GeneralUtils.assignX;
@@ -129,20 +130,22 @@ public class InitializerStrategy extends BuilderASTTransformation.AbstractBuilde
private static final int PUBLIC_STATIC = ACC_PUBLIC | ACC_STATIC;
private static final Expression DEFAULT_INITIAL_VALUE = null;
+ private static final ClassNode TUPLECONS_TYPE = ClassHelper.make(TupleConstructor.class);
public void build(BuilderASTTransformation transform, AnnotatedNode annotatedNode, AnnotationNode anno) {
if (unsupportedAttribute(transform, anno, "forClass")) return;
if (unsupportedAttribute(transform, anno, "allProperties")) return;
boolean useSetters = transform.memberHasValue(anno, "useSetters", true);
boolean allNames = transform.memberHasValue(anno, "allNames", true);
+ boolean force = transform.memberHasValue(anno, "force", true);
if (annotatedNode instanceof ClassNode) {
- createBuilderForAnnotatedClass(transform, (ClassNode) annotatedNode, anno, useSetters, allNames);
+ createBuilderForAnnotatedClass(transform, (ClassNode) annotatedNode, anno, useSetters, allNames, force);
} else if (annotatedNode instanceof MethodNode) {
createBuilderForAnnotatedMethod(transform, (MethodNode) annotatedNode, anno, useSetters);
}
}
- private void createBuilderForAnnotatedClass(BuilderASTTransformation transform, ClassNode buildee, AnnotationNode anno, boolean useSetters, boolean allNames) {
+ private void createBuilderForAnnotatedClass(BuilderASTTransformation transform, ClassNode buildee, AnnotationNode anno, boolean useSetters, boolean allNames, boolean force) {
List<String> excludes = new ArrayList<String>();
List<String> includes = new ArrayList<String>();
includes.add(Undefined.STRING);
@@ -158,7 +161,8 @@ public class InitializerStrategy extends BuilderASTTransformation.AbstractBuilde
addFields(buildee, filteredFields, builder);
buildCommon(buildee, anno, filteredFields, builder);
- createBuildeeConstructors(transform, buildee, builder, filteredFields, true, useSetters);
+ boolean needsConstructor = !transform.hasAnnotation(buildee, TUPLECONS_TYPE) || force;
+ createBuildeeConstructors(transform, buildee, builder, filteredFields, needsConstructor, useSetters);
}
private void createBuilderForAnnotatedMethod(BuilderASTTransformation transform, MethodNode mNode, AnnotationNode anno, boolean useSetters) {
@@ -271,13 +275,13 @@ public class InitializerStrategy extends BuilderASTTransformation.AbstractBuilde
private static void createBuildeeConstructors(BuilderASTTransformation transform, ClassNode buildee, ClassNode builder, List<FieldNode> fields, boolean needsConstructor, boolean useSetters) {
ConstructorNode initializer = createInitializerConstructor(buildee, builder, fields);
- if (transform.hasAnnotation(buildee, ImmutableASTTransformation.MY_TYPE)) {
- initializer.putNodeMetaData(ImmutableASTTransformation.IMMUTABLE_SAFE_FLAG, Boolean.TRUE);
- } else if (needsConstructor) {
+ markAsGenerated(buildee, initializer);
+ if (needsConstructor) {
final BlockStatement body = new BlockStatement();
body.addStatement(ctorSuperS());
initializeFields(fields, body, useSetters);
- buildee.addConstructor(ACC_PRIVATE | ACC_SYNTHETIC, getParams(fields, buildee), NO_EXCEPTIONS, body);
+ ConstructorNode helperCons = buildee.addConstructor(ACC_PRIVATE | ACC_SYNTHETIC, getParams(fields, buildee), NO_EXCEPTIONS, body);
+ markAsGenerated(buildee, helperCons);
}
}
http://git-wip-us.apache.org/repos/asf/groovy/blob/7379d522/src/main/groovy/groovy/transform/builder/SimpleStrategy.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/transform/builder/SimpleStrategy.java b/src/main/groovy/groovy/transform/builder/SimpleStrategy.java
index 7956ac6..fd96b7f 100644
--- a/src/main/groovy/groovy/transform/builder/SimpleStrategy.java
+++ b/src/main/groovy/groovy/transform/builder/SimpleStrategy.java
@@ -94,6 +94,7 @@ public class SimpleStrategy extends BuilderASTTransformation.AbstractBuilderStra
if (unsupportedAttribute(transform, anno, "forClass")) return;
if (unsupportedAttribute(transform, anno, "includeSuperProperties")) return;
if (unsupportedAttribute(transform, anno, "allProperties")) return;
+ if (unsupportedAttribute(transform, anno, "force")) return;
boolean useSetters = transform.memberHasValue(anno, "useSetters", true);
boolean allNames = transform.memberHasValue(anno, "allNames", true);
http://git-wip-us.apache.org/repos/asf/groovy/blob/7379d522/src/main/java/org/apache/groovy/ast/tools/AnnotatedNodeUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/groovy/ast/tools/AnnotatedNodeUtils.java b/src/main/java/org/apache/groovy/ast/tools/AnnotatedNodeUtils.java
new file mode 100644
index 0000000..e378f99
--- /dev/null
+++ b/src/main/java/org/apache/groovy/ast/tools/AnnotatedNodeUtils.java
@@ -0,0 +1,42 @@
+/*
+ * 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 org.apache.groovy.ast.tools;
+
+import groovy.transform.Generated;
+import org.codehaus.groovy.ast.AnnotatedNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+
+/**
+ * Utility class for working with AnnotatedNodes
+ */
+public class AnnotatedNodeUtils {
+ private static final ClassNode GENERATED_TYPE = ClassHelper.make(Generated.class);
+
+ private AnnotatedNodeUtils() {
+ }
+
+ public static void markAsGenerated(ClassNode cNode, AnnotatedNode aNode) {
+ boolean shouldAnnotate = cNode.getModule() != null && cNode.getModule().getContext() != null;
+ if (shouldAnnotate) {
+ aNode.addAnnotation(new AnnotationNode(GENERATED_TYPE));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/7379d522/src/main/java/org/apache/groovy/ast/tools/ClassNodeUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/groovy/ast/tools/ClassNodeUtils.java b/src/main/java/org/apache/groovy/ast/tools/ClassNodeUtils.java
index 6d28afc..f78e99d 100644
--- a/src/main/java/org/apache/groovy/ast/tools/ClassNodeUtils.java
+++ b/src/main/java/org/apache/groovy/ast/tools/ClassNodeUtils.java
@@ -18,6 +18,7 @@
*/
package org.apache.groovy.ast.tools;
+import groovy.transform.Generated;
import org.codehaus.groovy.ast.ClassHelper;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.ConstructorNode;
@@ -28,6 +29,7 @@ import org.codehaus.groovy.ast.expr.Expression;
import org.codehaus.groovy.ast.expr.MapExpression;
import org.codehaus.groovy.ast.expr.SpreadExpression;
import org.codehaus.groovy.ast.expr.TupleExpression;
+import org.codehaus.groovy.transform.AbstractASTTransformation;
import java.lang.reflect.Modifier;
import java.util.Arrays;
@@ -41,6 +43,8 @@ import static org.codehaus.groovy.ast.ClassHelper.boolean_TYPE;
* Utility class for working with ClassNodes
*/
public class ClassNodeUtils {
+ private static final ClassNode GENERATED_TYPE = ClassHelper.make(Generated.class);
+
/**
* Formats a type name into a human readable version. For arrays, appends "[]" to the formatted
* type name of the component. For unit class nodes, uses the class node name.
@@ -281,4 +285,28 @@ public class ClassNodeUtils {
}
return false;
}
+
+ /**
+ * Determine if an explicit (non-generated) constructor is in the class.
+ *
+ * @param xform if non null, add an error if an explicit constructor is found
+ * @param cNode the type of the containing class
+ * @return true if an explicit (non-generated) constructor was found
+ */
+ public static boolean hasExplicitConstructor(AbstractASTTransformation xform, ClassNode cNode) {
+ List<ConstructorNode> declaredConstructors = cNode.getDeclaredConstructors();
+ for (ConstructorNode constructorNode : declaredConstructors) {
+ // allow constructors added by other transforms if flagged as Generated
+ if (AbstractASTTransformation.hasAnnotation(constructorNode, GENERATED_TYPE)) {
+ continue;
+ }
+ if (xform != null) {
+ xform.addError("Error during " + xform.getAnnotationName() +
+ " processing. Explicit constructors not allowed for class: " +
+ cNode.getNameWithoutPackage(), constructorNode);
+ }
+ return true;
+ }
+ return false;
+ }
}
http://git-wip-us.apache.org/repos/asf/groovy/blob/7379d522/src/main/java/org/codehaus/groovy/transform/ImmutableASTTransformation.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/transform/ImmutableASTTransformation.java b/src/main/java/org/codehaus/groovy/transform/ImmutableASTTransformation.java
index 1cd79c6..b8cc56c 100644
--- a/src/main/java/org/codehaus/groovy/transform/ImmutableASTTransformation.java
+++ b/src/main/java/org/codehaus/groovy/transform/ImmutableASTTransformation.java
@@ -30,7 +30,6 @@ import org.codehaus.groovy.ast.AnnotatedNode;
import org.codehaus.groovy.ast.AnnotationNode;
import org.codehaus.groovy.ast.ClassHelper;
import org.codehaus.groovy.ast.ClassNode;
-import org.codehaus.groovy.ast.ConstructorNode;
import org.codehaus.groovy.ast.FieldNode;
import org.codehaus.groovy.ast.Parameter;
import org.codehaus.groovy.ast.PropertyNode;
@@ -52,6 +51,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import static org.apache.groovy.ast.tools.ClassNodeUtils.hasExplicitConstructor;
import static org.apache.groovy.ast.tools.ImmutablePropertyUtils.builtinOrMarkedImmutableClass;
import static org.apache.groovy.ast.tools.ImmutablePropertyUtils.createErrorMessage;
import static org.codehaus.groovy.ast.ClassHelper.makeWithoutCaching;
@@ -94,7 +94,6 @@ public class ImmutableASTTransformation extends AbstractASTTransformation implem
private static final String COPY_WITH_METHOD = "copyWith";
private static final ClassNode HMAP_TYPE = makeWithoutCaching(HashMap.class, false);
- public static final String IMMUTABLE_SAFE_FLAG = "Immutable.Safe";
@Override
public String getAnnotationName() {
@@ -147,7 +146,7 @@ public class ImmutableASTTransformation extends AbstractASTTransformation implem
// if (unsupportedTupleAttribute(tupleCons, "useSetters")) return;
if (unsupportedTupleAttribute(tupleCons, "force")) return;
}
- if (!validateConstructors(cNode)) return;
+ if (hasExplicitConstructor(this, cNode)) return;
if (memberHasValue(node, MEMBER_ADD_COPY_WITH, true) && !pList.isEmpty() &&
!hasDeclaredMethod(cNode, COPY_WITH_METHOD, 1)) {
createCopyWith(cNode, pList);
@@ -210,20 +209,6 @@ public class ImmutableASTTransformation extends AbstractASTTransformation implem
cNode.addField(fn);
}
- private boolean validateConstructors(ClassNode cNode) {
- List<ConstructorNode> declaredConstructors = cNode.getDeclaredConstructors();
- for (ConstructorNode constructorNode : declaredConstructors) {
- // allow constructors added by other transforms if flagged as safe
- Object nodeMetaData = constructorNode.getNodeMetaData(IMMUTABLE_SAFE_FLAG);
- if (nodeMetaData != null && ((Boolean) nodeMetaData)) {
- continue;
- }
- addError("Explicit constructors not allowed for " + MY_TYPE_NAME + " class: " + cNode.getNameWithoutPackage(), constructorNode);
- return false;
- }
- return true;
- }
-
static boolean makeImmutable(ClassNode cNode) {
List<AnnotationNode> annotations = cNode.getAnnotations(ImmutablePropertyUtils.IMMUTABLE_OPTIONS_TYPE);
AnnotationNode annoImmutable = annotations.isEmpty() ? null : annotations.get(0);
http://git-wip-us.apache.org/repos/asf/groovy/blob/7379d522/src/main/java/org/codehaus/groovy/transform/MapConstructorASTTransformation.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/transform/MapConstructorASTTransformation.java b/src/main/java/org/codehaus/groovy/transform/MapConstructorASTTransformation.java
index 51de450..a1aa094 100644
--- a/src/main/java/org/codehaus/groovy/transform/MapConstructorASTTransformation.java
+++ b/src/main/java/org/codehaus/groovy/transform/MapConstructorASTTransformation.java
@@ -45,11 +45,13 @@ import org.codehaus.groovy.control.SourceUnit;
import java.util.ArrayList;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import static org.apache.groovy.ast.tools.AnnotatedNodeUtils.markAsGenerated;
import static org.apache.groovy.ast.tools.ClassNodeUtils.hasNoArgConstructor;
import static org.apache.groovy.ast.tools.VisibilityUtils.getVisibility;
import static org.codehaus.groovy.ast.ClassHelper.make;
@@ -138,10 +140,13 @@ public class MapConstructorASTTransformation extends AbstractASTTransformation i
boolean includeSuperProperties, boolean includeSuperFields, boolean noArg,
boolean allNames, boolean allProperties, boolean specialNamedArgHandling, boolean includeStatic,
List<String> excludes, List<String> includes, ClosureExpression pre, ClosureExpression post, SourceUnit source) {
- List<ConstructorNode> constructors = cNode.getDeclaredConstructors();
- boolean foundEmpty = constructors.size() == 1 && constructors.get(0).getFirstStatement() == null;
+
// HACK: JavaStubGenerator could have snuck in a constructor we don't want
- if (foundEmpty) constructors.remove(0);
+ Iterator<ConstructorNode> iterator = cNode.getDeclaredConstructors().iterator();
+ while (iterator.hasNext()) {
+ ConstructorNode next = iterator.next();
+ if (next.getFirstStatement() == null) iterator.remove();
+ }
Set<String> names = new HashSet<String>();
List<PropertyNode> superList;
@@ -182,6 +187,7 @@ public class MapConstructorASTTransformation extends AbstractASTTransformation i
}
private static void doAddConstructor(final ClassNode cNode, final ConstructorNode constructorNode) {
+ markAsGenerated(cNode, constructorNode);
cNode.addConstructor(constructorNode);
// GROOVY-5814: Immutable is not compatible with @CompileStatic
Parameter argsParam = null;
@@ -224,7 +230,9 @@ public class MapConstructorASTTransformation extends AbstractASTTransformation i
private static void createNoArgConstructor(ClassNode cNode, int modifiers) {
Statement body = stmt(ctorX(ClassNode.THIS, args(new MapExpression())));
- cNode.addConstructor(new ConstructorNode(modifiers, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, body));
+ ConstructorNode consNode = new ConstructorNode(modifiers, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, body);
+ markAsGenerated(cNode, consNode);
+ cNode.addConstructor(consNode);
}
private static ClassCodeExpressionTransformer makeMapTypedArgsTransformer() {
http://git-wip-us.apache.org/repos/asf/groovy/blob/7379d522/src/main/java/org/codehaus/groovy/transform/TupleConstructorASTTransformation.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/transform/TupleConstructorASTTransformation.java b/src/main/java/org/codehaus/groovy/transform/TupleConstructorASTTransformation.java
index 9696d15..0d10cac 100644
--- a/src/main/java/org/codehaus/groovy/transform/TupleConstructorASTTransformation.java
+++ b/src/main/java/org/codehaus/groovy/transform/TupleConstructorASTTransformation.java
@@ -55,6 +55,8 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
+import static org.apache.groovy.ast.tools.AnnotatedNodeUtils.markAsGenerated;
+import static org.apache.groovy.ast.tools.ClassNodeUtils.hasExplicitConstructor;
import static org.apache.groovy.ast.tools.VisibilityUtils.getVisibility;
import static org.codehaus.groovy.ast.ClassHelper.make;
import static org.codehaus.groovy.ast.ClassHelper.makeWithoutCaching;
@@ -168,7 +170,6 @@ public class TupleConstructorASTTransformation extends AbstractASTTransformation
boolean callSuper = xform.memberHasValue(anno, "callSuper", true);
boolean force = xform.memberHasValue(anno, "force", true);
boolean defaults = !xform.memberHasValue(anno, "defaults", false);
- boolean useSetters = xform.memberHasValue(anno, "useSetters", true);
Set<String> names = new HashSet<String>();
List<PropertyNode> superList;
if (includeSuperProperties || includeSuperFields) {
@@ -177,14 +178,14 @@ public class TupleConstructorASTTransformation extends AbstractASTTransformation
superList = new ArrayList<PropertyNode>();
}
- List<PropertyNode> list = getAllProperties(names, cNode, true, includeFields, false, allProperties, false, true);
+ List<PropertyNode> list = getAllProperties(names, cNode, includeProperties, includeFields, false, allProperties, false, true);
boolean makeImmutable = makeImmutable(cNode);
boolean specialNamedArgCase = (ImmutableASTTransformation.isSpecialNamedArgCase(list, !defaults) && superList.isEmpty()) ||
(ImmutableASTTransformation.isSpecialNamedArgCase(superList, !defaults) && list.isEmpty());
// no processing if existing constructors found unless forced or ImmutableBase in play
- if (!cNode.getDeclaredConstructors().isEmpty() && !force && !makeImmutable) return;
+ if (hasExplicitConstructor(null, cNode) && !force && !makeImmutable) return;
final List<Parameter> params = new ArrayList<Parameter>();
final List<Expression> superParams = new ArrayList<Expression>();
@@ -254,7 +255,9 @@ public class TupleConstructorASTTransformation extends AbstractASTTransformation
boolean hasMapCons = hasAnnotation(cNode, MapConstructorASTTransformation.MY_TYPE);
int modifiers = getVisibility(anno, cNode, ConstructorNode.class, ACC_PUBLIC);
- cNode.addConstructor(new ConstructorNode(modifiers, params.toArray(new Parameter[params.size()]), ClassNode.EMPTY_ARRAY, body));
+ ConstructorNode consNode = new ConstructorNode(modifiers, params.toArray(new Parameter[params.size()]), ClassNode.EMPTY_ARRAY, body);
+ markAsGenerated(cNode, consNode);
+ cNode.addConstructor(consNode);
if (sourceUnit != null && !body.isEmpty()) {
VariableScopeVisitor scopeVisitor = new VariableScopeVisitor(sourceUnit);
@@ -305,12 +308,14 @@ public class TupleConstructorASTTransformation extends AbstractASTTransformation
illegalArgumentBlock(message),
processArgsBlock(cNode, namedArgs)));
ConstructorNode init = new ConstructorNode(modifiers, parameters, ClassNode.EMPTY_ARRAY, code);
+ markAsGenerated(cNode, init);
cNode.addConstructor(init);
// potentially add a no-arg constructor too
if (addNoArg) {
code = new BlockStatement();
code.addStatement(stmt(ctorX(ClassNode.THIS, ctorX(LHMAP_TYPE))));
init = new ConstructorNode(modifiers, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, code);
+ markAsGenerated(cNode, init);
cNode.addConstructor(init);
}
}
http://git-wip-us.apache.org/repos/asf/groovy/blob/7379d522/src/test/org/codehaus/groovy/transform/BuilderTransformTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/org/codehaus/groovy/transform/BuilderTransformTest.groovy b/src/test/org/codehaus/groovy/transform/BuilderTransformTest.groovy
index 1febfbc..9894752 100644
--- a/src/test/org/codehaus/groovy/transform/BuilderTransformTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/BuilderTransformTest.groovy
@@ -603,8 +603,26 @@ class BuilderTransformTest extends CompilableTestSupport {
import groovy.transform.builder.*
import groovy.transform.*
+ @Canonical(useSetters=true)
+ @Builder(builderStrategy=InitializerStrategy)
+ class Person {
+ String name
+ void setName(String name) { this.name = name?.toUpperCase() }
+ }
+
+ @CompileStatic
+ def make() {
+ assert new Person(Person.createInitializer().name("John")).toString() == 'Person(JOHN)'
+ }
+ make()
+ '''
+ assertScript '''
+ import groovy.transform.builder.*
+ import groovy.transform.*
+
@Canonical
- @Builder(builderStrategy=InitializerStrategy, useSetters=true)
+ @TupleConstructor(includes='')
+ @Builder(builderStrategy=InitializerStrategy, useSetters=true, force=true)
class Person {
String name
void setName(String name) { this.name = name?.toUpperCase() }