diff options
22 files changed, 400 insertions, 42 deletions
diff --git a/doc/changelog.markdown b/doc/changelog.markdown index 7d784ce6..f46d87db 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -7,7 +7,8 @@ Lombok Changelog * Builder __TODO TODO TODO TODO DO NOT SHIP YET__: * features web page - * The 'I use guava' switch in l.config + * Check if the shadowed localvar names are properly typed; if compatible subtypes, we should cast these to avoid accidentally calling an overload. + * Add support for guava sortedset. * Disable auto-singular in l.config * Review if there are nay potentially breaking changes in the pipeline for builder BEFORE moving it out of experimental. * Make sure you cover the fact that builder has moved on from experimental in this issue, and on the features page /doc! diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java index 301563b8..0fe23d7b 100644 --- a/src/core/lombok/ConfigurationKeys.java +++ b/src/core/lombok/ConfigurationKeys.java @@ -133,9 +133,9 @@ public class ConfigurationKeys { /** * lombok configuration: {@code lombok.equalsAndHashCode.doNotUseGetters} = {@code true} | {@code false}. * - * For any class without an {@code @EqualsAndHashCode} that explicitly defines the {@code doNotUseGetters} option, this value is used. + * For any class without an {@code @EqualsAndHashCode} that explicitly defines the {@code doNotUseGetters} option, this value is used (default = false). */ - public static final ConfigurationKey<Boolean> EQUALS_AND_HASH_CODE_DO_NOT_USE_GETTERS = new ConfigurationKey<Boolean>("lombok.equalsAndHashCode.doNotUseGetters", "Don't call the getters but use the fields directly in the generated equalsAndHashCode method.") {}; + public static final ConfigurationKey<Boolean> EQUALS_AND_HASH_CODE_DO_NOT_USE_GETTERS = new ConfigurationKey<Boolean>("lombok.equalsAndHashCode.doNotUseGetters", "Don't call the getters but use the fields directly in the generated equalsAndHashCode method (default = false).") {}; /** * lombok configuration: {@code lombok.equalsAndHashCode.flagUsage} = {@code WARNING} | {@code ERROR}. @@ -149,9 +149,9 @@ public class ConfigurationKeys { /** * lombok configuration: {@code lombok.toString.doNotUseGetters} = {@code true} | {@code false}. * - * For any class without an {@code @ToString} that explicitly defines the {@code doNotUseGetters} option, this value is used. + * For any class without an {@code @ToString} that explicitly defines the {@code doNotUseGetters} option, this value is used (default = false). */ - public static final ConfigurationKey<Boolean> TO_STRING_DO_NOT_USE_GETTERS = new ConfigurationKey<Boolean>("lombok.toString.doNotUseGetters", "Don't call the getters but use the fields directly in the generated toString method.") {}; + public static final ConfigurationKey<Boolean> TO_STRING_DO_NOT_USE_GETTERS = new ConfigurationKey<Boolean>("lombok.toString.doNotUseGetters", "Don't call the getters but use the fields directly in the generated toString method (default = false).") {}; /** * lombok configuration: {@code lombok.toString.flagUsage} = {@code WARNING} | {@code ERROR}. @@ -163,9 +163,9 @@ public class ConfigurationKeys { /** * lombok configuration: {@code lombok.toString.includeFieldNames} = {@code true} | {@code false}. * - * For any class without an {@code @ToString} that explicitly defines the {@code includeFieldNames} option, this value is used. + * For any class without an {@code @ToString} that explicitly defines the {@code includeFieldNames} option, this value is used (default = true). */ - public static final ConfigurationKey<Boolean> TO_STRING_INCLUDE_FIELD_NAMES = new ConfigurationKey<Boolean>("lombok.toString.includeFieldNames", "Include the field names in the generated toString method.") {}; + public static final ConfigurationKey<Boolean> TO_STRING_INCLUDE_FIELD_NAMES = new ConfigurationKey<Boolean>("lombok.toString.includeFieldNames", "Include the field names in the generated toString method (default = true).") {}; // ##### Standalones ##### @@ -194,7 +194,7 @@ public class ConfigurationKeys { * * Sets the exception to throw if {@code @NonNull} is applied to a method parameter, and a caller passes in {@code null}. */ - public static final ConfigurationKey<NullCheckExceptionType> NON_NULL_EXCEPTION_TYPE = new ConfigurationKey<NullCheckExceptionType>("lombok.nonNull.exceptionType", "The type of the exception to throw if a passed-in argument is null. Default: NullPointerException.") {}; + public static final ConfigurationKey<NullCheckExceptionType> NON_NULL_EXCEPTION_TYPE = new ConfigurationKey<NullCheckExceptionType>("lombok.nonNull.exceptionType", "The type of the exception to throw if a passed-in argument is null (Default: NullPointerException).") {}; /** * lombok configuration: {@code lombok.nonNull.flagUsage} = {@code WARNING} | {@code ERROR}. @@ -289,7 +289,7 @@ public class ConfigurationKeys { * * If set the various log annotations (which make a log field) will use the stated identifier instead of {@code log} as a name. */ - public static final ConfigurationKey<String> LOG_ANY_FIELD_NAME = new ConfigurationKey<String>("lombok.log.fieldName", "Use this name for the generated logger fields (default: 'log')") {}; + public static final ConfigurationKey<String> LOG_ANY_FIELD_NAME = new ConfigurationKey<String>("lombok.log.fieldName", "Use this name for the generated logger fields (default: 'log').") {}; /** * lombok configuration: {@code lombok.log.fieldIsStatic} = {@code true} | {@code false}. @@ -329,16 +329,16 @@ public class ConfigurationKeys { /** * lombok configuration: {@code lombok.accessors.chain} = {@code true} | {@code false}. * - * For any class without an {@code @Accessors} that explicitly defines the {@code chain} option, this value is used. + * For any class without an {@code @Accessors} that explicitly defines the {@code chain} option, this value is used (default = false). */ - public static final ConfigurationKey<Boolean> ACCESSORS_CHAIN = new ConfigurationKey<Boolean>("lombok.accessors.chain", "Generate setters that return 'this' instead of 'void'.") {}; + public static final ConfigurationKey<Boolean> ACCESSORS_CHAIN = new ConfigurationKey<Boolean>("lombok.accessors.chain", "Generate setters that return 'this' instead of 'void' (default: false).") {}; /** * lombok configuration: {@code lombok.accessors.fluent} = {@code true} | {@code false}. * - * For any class without an {@code @Accessors} that explicitly defines the {@code fluent} option, this value is used. + * For any class without an {@code @Accessors} that explicitly defines the {@code fluent} option, this value is used (default = false). */ - public static final ConfigurationKey<Boolean> ACCESSORS_FLUENT = new ConfigurationKey<Boolean>("lombok.accessors.fluent", "Generate getters and setters using only the field name (no get/set prefix).") {}; + public static final ConfigurationKey<Boolean> ACCESSORS_FLUENT = new ConfigurationKey<Boolean>("lombok.accessors.fluent", "Generate getters and setters using only the field name (no get/set prefix) (default: false).") {}; // ----- Builder ----- @@ -349,6 +349,14 @@ public class ConfigurationKeys { */ public static final ConfigurationKey<FlagUsageType> BUILDER_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.builder.flagUsage", "Emit a warning or error if @Builder is used.") {}; + /** + * lombok configuration: {@code lombok.builder.useGuava} = {@code true} | {@code false}. + * + * If explicitly set to {@code true}, guava's {@code ImmutableList} etc are used to implement the immutable collection datatypes generated by @Singular @Builder for fields/parameters of type {@code java.util.List} and such. + * By default, unmodifiable-wrapped versions of {@code java.util} types are used. + */ + public static final ConfigurationKey<Boolean> BUILDER_USE_GUAVA = new ConfigurationKey<Boolean>("lombok.builder.useGuava", "Generate backing immutable implementations for @Singular on java.util.* types by using guava's ImmutableList, etc. Normally java.util's mutable types are used and wrapped to make them immutable.") {}; + // ----- ExtensionMethod ----- /** diff --git a/src/core/lombok/core/GuavaTypeMap.java b/src/core/lombok/core/GuavaTypeMap.java new file mode 100644 index 00000000..900d2b72 --- /dev/null +++ b/src/core/lombok/core/GuavaTypeMap.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2015 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.core; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public final class GuavaTypeMap { + private static final Map<String, String> TYPE_TO_GUAVA_TYPE; static { + Map<String, String> m = new HashMap<String, String>(); + + m.put("java.util.NavigableSet", "ImmutableSortedSet"); + m.put("java.util.NavigableMap", "ImmutableSortedMap"); + m.put("java.util.SortedSet", "ImmutableSortedSet"); + m.put("java.util.SortedMap", "ImmutableSortedMap"); + m.put("java.util.Set", "ImmutableSet"); + m.put("java.util.Map", "ImmutableMap"); + m.put("java.util.Collection", "ImmutableList"); + m.put("java.util.List", "ImmutableList"); + + m.put("com.google.common.collect.ImmutableSet", "ImmutableSet"); + m.put("com.google.common.collect.ImmutableSortedSet", "ImmutableSortedSet"); + m.put("com.google.common.collect.ImmutableMap", "ImmutableMap"); + m.put("com.google.common.collect.ImmutableBiMap", "ImmutableBiMap"); + m.put("com.google.common.collect.ImmutableSortedMap", "ImmutableSortedMap"); + m.put("com.google.common.collect.ImmutableList", "ImmutableList"); + m.put("com.google.common.collect.ImmutableCollection", "ImmutableList"); + + TYPE_TO_GUAVA_TYPE = Collections.unmodifiableMap(m); + } + + public static String getGuavaTypeName(String fqn) { + String target = TYPE_TO_GUAVA_TYPE.get(fqn); + return target != null ? target : "ImmutableList"; + } + + private GuavaTypeMap() {} +} diff --git a/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java b/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java index eca918d7..df8bd665 100644 --- a/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java +++ b/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java @@ -175,7 +175,7 @@ public class EclipseSingularsRecipes { char[] name = fd.name; if (name == null) continue; if (getGeneratedBy(fd) != null) continue; - for (char[] fieldToBeGenerated : listFieldsToBeGenerated(data)) { + for (char[] fieldToBeGenerated : listFieldsToBeGenerated(data, builderType)) { if (!Arrays.equals(name, fieldToBeGenerated)) continue; child.addError("Manually adding a field that @Singular @Builder would generate is not supported. If you want to manually manage the builder aspect for this field/parameter, don't use @Singular."); return true; @@ -187,7 +187,7 @@ public class EclipseSingularsRecipes { char[] name = method.selector; if (name == null) continue; if (getGeneratedBy(method) != null) continue; - for (char[] methodToBeGenerated : listMethodsToBeGenerated(data)) { + for (char[] methodToBeGenerated : listMethodsToBeGenerated(data, builderType)) { if (!Arrays.equals(name, methodToBeGenerated)) continue; child.addError("Manually adding a method that @Singular @Builder would generate is not supported. If you want to manually manage the builder aspect for this field/parameter, don't use @Singular."); return true; @@ -199,11 +199,11 @@ public class EclipseSingularsRecipes { return false; } - public List<char[]> listFieldsToBeGenerated(SingularData data) { + public List<char[]> listFieldsToBeGenerated(SingularData data, EclipseNode builderType) { return Collections.singletonList(data.pluralName); } - public List<char[]> listMethodsToBeGenerated(SingularData data) { + public List<char[]> listMethodsToBeGenerated(SingularData data, EclipseNode builderType) { char[] p = data.pluralName; char[] s = data.singularName; if (Arrays.equals(p, s)) return Collections.singletonList(p); diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java index 775d4ed5..8d54da6f 100644 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java @@ -28,6 +28,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import lombok.core.GuavaTypeMap; import lombok.core.handlers.HandlerUtil; import lombok.eclipse.EclipseNode; import lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer; @@ -64,13 +65,11 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer { }; protected String getSimpleTargetTypeName(SingularData data) { - String simpleTypeName = data.getTargetSimpleType(); - if ("ImmutableCollection".equals(simpleTypeName)) return "ImmutableList"; - return simpleTypeName; + return GuavaTypeMap.getGuavaTypeName(data.getTargetFqn()); } protected char[] getBuilderMethodName(SingularData data) { - String simpleTypeName = data.getTargetSimpleType(); + String simpleTypeName = getSimpleTargetTypeName(data); if ("ImmutableSortedSet".equals(simpleTypeName) || "ImmutableSortedMap".equals(simpleTypeName)) return "naturalOrder".toCharArray(); return "builder".toCharArray(); } diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java index f64748a8..1d1c4dbd 100644 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java @@ -50,7 +50,27 @@ import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; abstract class EclipseJavaUtilListSetSingularizer extends EclipseJavaUtilSingularizer { + @Override public List<char[]> listFieldsToBeGenerated(SingularData data, EclipseNode builderType) { + if (useGuavaInstead(builderType)) { + return guavaListSetSingularizer.listFieldsToBeGenerated(data, builderType); + } + + return super.listFieldsToBeGenerated(data, builderType); + } + + @Override public List<char[]> listMethodsToBeGenerated(SingularData data, EclipseNode builderType) { + if (useGuavaInstead(builderType)) { + return guavaListSetSingularizer.listMethodsToBeGenerated(data, builderType); + } + + return super.listMethodsToBeGenerated(data, builderType); + } + @Override public List<EclipseNode> generateFields(SingularData data, EclipseNode builderType) { + if (useGuavaInstead(builderType)) { + return guavaListSetSingularizer.generateFields(data, builderType); + } + TypeReference type = new QualifiedTypeReference(JAVA_UTIL_ARRAYLIST, NULL_POSS); type = addTypeArgs(1, false, builderType, type, data.getTypeArgs()); @@ -64,6 +84,11 @@ abstract class EclipseJavaUtilListSetSingularizer extends EclipseJavaUtilSingula } @Override public void generateMethods(SingularData data, EclipseNode builderType, boolean fluent, boolean chain) { + if (useGuavaInstead(builderType)) { + guavaListSetSingularizer.generateMethods(data, builderType, fluent, chain); + return; + } + TypeReference returnType = chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0); Statement returnStatement = chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null; generateSingularMethod(returnType, returnStatement, data, builderType, fluent); diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSingularizer.java index 4f67b5c0..0784ac4f 100644 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSingularizer.java @@ -56,6 +56,11 @@ public class EclipseJavaUtilListSingularizer extends EclipseJavaUtilListSetSingu } @Override public void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName) { + if (useGuavaInstead(builderType)) { + guavaListSetSingularizer.appendBuildCode(data, builderType, statements, targetVariableName); + return; + } + List<Statement> switchContents = new ArrayList<Statement>(); /* case 0: (empty) break; */ { diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java index ff23823b..640bd396 100644 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java @@ -61,7 +61,11 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer return LombokImmutableList.of("java.util.Map", "java.util.SortedMap", "java.util.NavigableMap"); } - @Override public List<char[]> listFieldsToBeGenerated(SingularData data) { + @Override public List<char[]> listFieldsToBeGenerated(SingularData data, EclipseNode builderType) { + if (useGuavaInstead(builderType)) { + return guavaMapSingularizer.listFieldsToBeGenerated(data, builderType); + } + char[] p = data.getPluralName(); int len = p.length; char[] k = new char[len + 4]; @@ -81,7 +85,19 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer return Arrays.asList(k, v); } - @Override public java.util.List<EclipseNode> generateFields(SingularData data, EclipseNode builderType) { + @Override public List<char[]> listMethodsToBeGenerated(SingularData data, EclipseNode builderType) { + if (useGuavaInstead(builderType)) { + return guavaMapSingularizer.listFieldsToBeGenerated(data, builderType); + } else { + return super.listMethodsToBeGenerated(data, builderType); + } + } + + @Override public List<EclipseNode> generateFields(SingularData data, EclipseNode builderType) { + if (useGuavaInstead(builderType)) { + return guavaMapSingularizer.generateFields(data, builderType); + } + char[] keyName = (new String(data.getPluralName()) + "$key").toCharArray(); char[] valueName = (new String(data.getPluralName()) + "$value").toCharArray(); FieldDeclaration buildKeyField; { @@ -113,6 +129,11 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer } @Override public void generateMethods(SingularData data, EclipseNode builderType, boolean fluent, boolean chain) { + if (useGuavaInstead(builderType)) { + guavaMapSingularizer.generateMethods(data, builderType, fluent, chain); + return; + } + TypeReference returnType = chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0); Statement returnStatement = chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null; generateSingularMethod(returnType, returnStatement, data, builderType, fluent); @@ -235,6 +256,11 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer } @Override public void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName) { + if (useGuavaInstead(builderType)) { + guavaMapSingularizer.appendBuildCode(data, builderType, statements, targetVariableName); + return; + } + if (data.getTargetFqn().equals("java.util.Map")) { statements.addAll(createJavaUtilSetMapInitialCapacitySwitchStatements(data, builderType, true, "emptyMap", "singletonMap", "LinkedHashMap")); } else { diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilSetSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilSetSingularizer.java index d4d87879..2d16eae0 100644 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilSetSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilSetSingularizer.java @@ -38,6 +38,11 @@ public class EclipseJavaUtilSetSingularizer extends EclipseJavaUtilListSetSingul } @Override public void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName) { + if (useGuavaInstead(builderType)) { + guavaListSetSingularizer.appendBuildCode(data, builderType, statements, targetVariableName); + return; + } + if (data.getTargetFqn().equals("java.util.Set")) { statements.addAll(createJavaUtilSetMapInitialCapacitySwitchStatements(data, builderType, false, "emptySet", "singleton", "LinkedHashSet")); } else { diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilSingularizer.java index 60c0f3ad..e4c399ed 100644 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilSingularizer.java @@ -57,6 +57,7 @@ import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; +import lombok.ConfigurationKeys; import lombok.eclipse.EclipseNode; import lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer; import lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData; @@ -82,6 +83,13 @@ abstract class EclipseJavaUtilSingularizer extends EclipseSingularizer { {'j', 'a', 'v', 'a'}, {'u', 't', 'i', 'l'}, {'C', 'o', 'l', 'l', 'e', 'c', 't', 'i', 'o', 'n', 's'} }; + protected final EclipseSingularizer guavaListSetSingularizer = new EclipseGuavaSetListSingularizer(); + protected final EclipseSingularizer guavaMapSingularizer = new EclipseGuavaMapSingularizer(); + + protected boolean useGuavaInstead(EclipseNode node) { + return Boolean.TRUE.equals(node.getAst().readConfiguration(ConfigurationKeys.BUILDER_USE_GUAVA)); + } + protected List<Statement> createJavaUtilSetMapInitialCapacitySwitchStatements(SingularData data, EclipseNode builderType, boolean mapMode, String emptyCollectionMethod, String singletonCollectionMethod, String targetType) { List<Statement> switchContents = new ArrayList<Statement>(); char[] keyName = mapMode ? (new String(data.getPluralName()) + "$key").toCharArray() : data.getPluralName(); diff --git a/src/core/lombok/javac/handlers/JavacSingularsRecipes.java b/src/core/lombok/javac/handlers/JavacSingularsRecipes.java index 35bd66ed..e60bc247 100644 --- a/src/core/lombok/javac/handlers/JavacSingularsRecipes.java +++ b/src/core/lombok/javac/handlers/JavacSingularsRecipes.java @@ -150,7 +150,7 @@ public class JavacSingularsRecipes { Name name = field.name; if (name == null) break; if (getGeneratedBy(field) != null) continue; - for (Name fieldToBeGenerated : listFieldsToBeGenerated(builderType, data)) { + for (Name fieldToBeGenerated : listFieldsToBeGenerated(data, builderType)) { if (!fieldToBeGenerated.equals(name)) continue; child.addError("Manually adding a field that @Singular @Builder would generate is not supported. If you want to manually manage the builder aspect for this field/parameter, don't use @Singular."); return true; @@ -162,7 +162,7 @@ public class JavacSingularsRecipes { Name name = method.name; if (name == null) break; if (getGeneratedBy(method) != null) continue; - for (Name methodToBeGenerated : listMethodsToBeGenerated(builderType, data)) { + for (Name methodToBeGenerated : listMethodsToBeGenerated(data, builderType)) { if (!methodToBeGenerated.equals(name)) continue; child.addError("Manually adding a method that @Singular @Builder would generate is not supported. If you want to manually manage the builder aspect for this field/parameter, don't use @Singular."); return true; @@ -174,11 +174,11 @@ public class JavacSingularsRecipes { return false; } - public java.util.List<Name> listFieldsToBeGenerated(JavacNode builderType, SingularData data) { + public java.util.List<Name> listFieldsToBeGenerated(SingularData data, JavacNode builderType) { return Collections.singletonList(data.pluralName); } - public java.util.List<Name> listMethodsToBeGenerated(JavacNode builderType, SingularData data) { + public java.util.List<Name> listMethodsToBeGenerated(SingularData data, JavacNode builderType) { Name p = data.pluralName; Name s = data.singularName; if (p.equals(s)) return Collections.singletonList(p); diff --git a/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java index 62cbc98b..a45faae4 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java @@ -26,6 +26,7 @@ import static lombok.javac.handlers.JavacHandlerUtil.*; import java.util.Collections; +import lombok.core.GuavaTypeMap; import lombok.core.handlers.HandlerUtil; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; @@ -48,13 +49,11 @@ import com.sun.tools.javac.util.Name; abstract class JavacGuavaSingularizer extends JavacSingularizer { protected String getSimpleTargetTypeName(SingularData data) { - String simpleTypeName = data.getTargetSimpleType(); - if ("ImmutableCollection".equals(simpleTypeName)) return "ImmutableList"; - return simpleTypeName; + return GuavaTypeMap.getGuavaTypeName(data.getTargetFqn()); } protected String getBuilderMethodName(SingularData data) { - String simpleTypeName = data.getTargetSimpleType(); + String simpleTypeName = getSimpleTargetTypeName(data); if ("ImmutableSortedSet".equals(simpleTypeName) || "ImmutableSortedMap".equals(simpleTypeName)) return "naturalOrder"; return "builder"; } diff --git a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSetSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSetSingularizer.java index 1129f19c..6f8ff705 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSetSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSetSingularizer.java @@ -46,7 +46,27 @@ import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Name; abstract class JavacJavaUtilListSetSingularizer extends JavacJavaUtilSingularizer { + @Override public java.util.List<Name> listFieldsToBeGenerated(SingularData data, JavacNode builderType) { + if (useGuavaInstead(builderType)) { + return guavaListSetSingularizer.listFieldsToBeGenerated(data, builderType); + } + + return super.listFieldsToBeGenerated(data, builderType); + } + + @Override public java.util.List<Name> listMethodsToBeGenerated(SingularData data, JavacNode builderType) { + if (useGuavaInstead(builderType)) { + return guavaListSetSingularizer.listMethodsToBeGenerated(data, builderType); + } + + return super.listMethodsToBeGenerated(data, builderType); + } + @Override public java.util.List<JavacNode> generateFields(SingularData data, JavacNode builderType, JCTree source) { + if (useGuavaInstead(builderType)) { + return guavaListSetSingularizer.generateFields(data, builderType, source); + } + JavacTreeMaker maker = builderType.getTreeMaker(); JCExpression type = JavacHandlerUtil.chainDots(builderType, "java", "util", "ArrayList"); type = addTypeArgs(1, false, builderType, type, data.getTypeArgs(), source); @@ -56,6 +76,11 @@ abstract class JavacJavaUtilListSetSingularizer extends JavacJavaUtilSingularize } @Override public void generateMethods(SingularData data, JavacNode builderType, JCTree source, boolean fluent, boolean chain) { + if (useGuavaInstead(builderType)) { + guavaListSetSingularizer.generateMethods(data, builderType, source, fluent, chain); + return; + } + JavacTreeMaker maker = builderType.getTreeMaker(); Name thisName = builderType.toName("this"); diff --git a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSingularizer.java index abf273e8..2cf34cf7 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSingularizer.java @@ -47,6 +47,11 @@ public class JavacJavaUtilListSingularizer extends JavacJavaUtilListSetSingulari } @Override public void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName) { + if (useGuavaInstead(builderType)) { + guavaListSetSingularizer.appendBuildCode(data, builderType, source, statements, targetVariableName); + return; + } + JavacTreeMaker maker = builderType.getTreeMaker(); List<JCExpression> jceBlank = List.nil(); ListBuffer<JCCase> cases = new ListBuffer<JCCase>(); diff --git a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilMapSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilMapSingularizer.java index 21b25221..ed91698d 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilMapSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilMapSingularizer.java @@ -55,12 +55,28 @@ public class JavacJavaUtilMapSingularizer extends JavacJavaUtilSingularizer { return LombokImmutableList.of("java.util.Map", "java.util.SortedMap", "java.util.NavigableMap"); } - @Override public java.util.List<Name> listFieldsToBeGenerated(JavacNode builderType, SingularData data) { + @Override public java.util.List<Name> listFieldsToBeGenerated(SingularData data, JavacNode builderType) { + if (useGuavaInstead(builderType)) { + return guavaMapSingularizer.listFieldsToBeGenerated(data, builderType); + } + String p = data.getPluralName().toString(); return Arrays.asList(builderType.toName(p + "$key"), builderType.toName(p + "$value")); } + @Override public java.util.List<Name> listMethodsToBeGenerated(SingularData data, JavacNode builderType) { + if (useGuavaInstead(builderType)) { + return guavaMapSingularizer.listMethodsToBeGenerated(data, builderType); + } + + return super.listMethodsToBeGenerated(data, builderType); + } + @Override public java.util.List<JavacNode> generateFields(SingularData data, JavacNode builderType, JCTree source) { + if (useGuavaInstead(builderType)) { + return guavaMapSingularizer.generateFields(data, builderType, source); + } + JavacTreeMaker maker = builderType.getTreeMaker(); JCVariableDecl buildKeyField; { @@ -85,6 +101,11 @@ public class JavacJavaUtilMapSingularizer extends JavacJavaUtilSingularizer { } @Override public void generateMethods(SingularData data, JavacNode builderType, JCTree source, boolean fluent, boolean chain) { + if (useGuavaInstead(builderType)) { + guavaMapSingularizer.generateMethods(data, builderType, source, fluent, chain); + return; + } + JavacTreeMaker maker = builderType.getTreeMaker(); JCExpression returnType = chain ? cloneSelfType(builderType) : maker.Type(createVoidType(maker, CTC_VOID)); @@ -161,6 +182,11 @@ public class JavacJavaUtilMapSingularizer extends JavacJavaUtilSingularizer { } @Override public void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName) { + if (useGuavaInstead(builderType)) { + guavaMapSingularizer.appendBuildCode(data, builderType, source, statements, targetVariableName); + return; + } + JavacTreeMaker maker = builderType.getTreeMaker(); if (data.getTargetFqn().equals("java.util.Map")) { diff --git a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSetSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSetSingularizer.java index ffba0dd8..317233cb 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSetSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSetSingularizer.java @@ -41,6 +41,11 @@ public class JavacJavaUtilSetSingularizer extends JavacJavaUtilListSetSingulariz } @Override public void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName) { + if (useGuavaInstead(builderType)) { + guavaListSetSingularizer.appendBuildCode(data, builderType, source, statements, targetVariableName); + return; + } + JavacTreeMaker maker = builderType.getTreeMaker(); if (data.getTargetFqn().equals("java.util.Set")) { diff --git a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSingularizer.java index f89df80e..6aeadfea 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSingularizer.java @@ -32,12 +32,20 @@ import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Name; +import lombok.ConfigurationKeys; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; import lombok.javac.handlers.JavacSingularsRecipes.JavacSingularizer; import lombok.javac.handlers.JavacSingularsRecipes.SingularData; abstract class JavacJavaUtilSingularizer extends JavacSingularizer { + protected final JavacSingularizer guavaListSetSingularizer = new JavacGuavaSetListSingularizer(); + protected final JavacSingularizer guavaMapSingularizer = new JavacGuavaMapSingularizer(); + + protected boolean useGuavaInstead(JavacNode node) { + return Boolean.TRUE.equals(node.getAst().readConfiguration(ConfigurationKeys.BUILDER_USE_GUAVA)); + } + protected List<JCStatement> createJavaUtilSetMapInitialCapacitySwitchStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, boolean mapMode, String emptyCollectionMethod, String singletonCollectionMethod, String targetType, JCTree source) { List<JCExpression> jceBlank = List.nil(); ListBuffer<JCCase> cases = new ListBuffer<JCCase>(); diff --git a/test/configuration/resource/configurationRoot/out.txt b/test/configuration/resource/configurationRoot/out.txt index 625115a4..de219694 100644 --- a/test/configuration/resource/configurationRoot/out.txt +++ b/test/configuration/resource/configurationRoot/out.txt @@ -8,7 +8,7 @@ lombok.accessors.flagUsage = ERROR # BASE/d1/d11/lombok.config: # 3: lombok.accessors.flagUsage = ERROR -# Generate setters that return 'this' instead of 'void'. +# Generate setters that return 'this' instead of 'void' (default: false). lombok.accessors.chain = false # BASE/d1/lombok.config: # <'lombok.accessors.chain' not mentioned> @@ -24,7 +24,7 @@ lombok.accessors.prefix += f # BASE/d1/d11/lombok.config: # 4: lombok.accessors.prefix += f -# Use this name for the generated logger fields (default: 'log') +# Use this name for the generated logger fields (default: 'log'). clear lombok.log.fieldName @@ -43,7 +43,7 @@ lombok.accessors.flagUsage = ERROR # BASE/d1/d11/d111/lombok.config: # <'lombok.accessors.flagUsage' not mentioned> -# Generate setters that return 'this' instead of 'void'. +# Generate setters that return 'this' instead of 'void' (default: false). clear lombok.accessors.chain # BASE/d1/lombok.config: # <'lombok.accessors.chain' not mentioned> @@ -66,7 +66,7 @@ lombok.accessors.prefix += m_ # BASE/d1/d11/d111/lombok.config: # 2: lombok.accessors.prefix += m_ -# Use this name for the generated logger fields (default: 'log') +# Use this name for the generated logger fields (default: 'log'). clear lombok.log.fieldName @@ -75,7 +75,7 @@ Configuration for 'BASE/d1/d12'. # Emit a warning or error if @Accessors is used. clear lombok.accessors.flagUsage -# Generate setters that return 'this' instead of 'void'. +# Generate setters that return 'this' instead of 'void' (default: false). lombok.accessors.chain = true # BASE/d1/lombok.config: # <'lombok.accessors.chain' not mentioned> @@ -86,5 +86,5 @@ lombok.accessors.chain = true # Strip this field prefix, like 'f' or 'm_', from the names of generated getters and setters. clear lombok.accessors.prefix -# Use this name for the generated logger fields (default: 'log') +# Use this name for the generated logger fields (default: 'log'). clear lombok.log.fieldName
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/BuilderSingletonRedirectToGuava.java b/test/transform/resource/after-delombok/BuilderSingletonRedirectToGuava.java new file mode 100644 index 00000000..a2d230a1 --- /dev/null +++ b/test/transform/resource/after-delombok/BuilderSingletonRedirectToGuava.java @@ -0,0 +1,75 @@ +import java.util.Set; +import java.util.NavigableMap; +import java.util.Collection; +class BuilderSingletonRedirectToGuava { + private Set<String> dangerMice; + private NavigableMap<Integer, Number> things; + private Collection<Class<?>> doohickeys; + @java.lang.SuppressWarnings("all") + BuilderSingletonRedirectToGuava(final Set<String> dangerMice, final NavigableMap<Integer, Number> things, final Collection<Class<?>> doohickeys) { + this.dangerMice = dangerMice; + this.things = things; + this.doohickeys = doohickeys; + } + @java.lang.SuppressWarnings("all") + public static class BuilderSingletonRedirectToGuavaBuilder { + private com.google.common.collect.ImmutableSet.Builder<String> dangerMice; + private com.google.common.collect.ImmutableSortedMap.Builder<Integer, Number> things; + private com.google.common.collect.ImmutableList.Builder<Class<?>> doohickeys; + @java.lang.SuppressWarnings("all") + BuilderSingletonRedirectToGuavaBuilder() { + } + @java.lang.SuppressWarnings("all") + public BuilderSingletonRedirectToGuavaBuilder dangerMouse(final String dangerMouse) { + if (this.dangerMice == null) this.dangerMice = com.google.common.collect.ImmutableSet.builder(); + this.dangerMice.add(dangerMouse); + return this; + } + @java.lang.SuppressWarnings("all") + public BuilderSingletonRedirectToGuavaBuilder dangerMice(final java.lang.Iterable<? extends String> dangerMice) { + if (this.dangerMice == null) this.dangerMice = com.google.common.collect.ImmutableSet.builder(); + this.dangerMice.addAll(dangerMice); + return this; + } + @java.lang.SuppressWarnings("all") + public BuilderSingletonRedirectToGuavaBuilder thing(final Integer thing$key, final Number thing$value) { + if (this.things == null) this.things = com.google.common.collect.ImmutableSortedMap.naturalOrder(); + this.things.put(thing$key, thing$value); + return this; + } + @java.lang.SuppressWarnings("all") + public BuilderSingletonRedirectToGuavaBuilder things(final java.util.Map<? extends Integer, ? extends Number> things) { + if (this.things == null) this.things = com.google.common.collect.ImmutableSortedMap.naturalOrder(); + this.things.putAll(things); + return this; + } + @java.lang.SuppressWarnings("all") + public BuilderSingletonRedirectToGuavaBuilder doohickey(final Class<?> doohickey) { + if (this.doohickeys == null) this.doohickeys = com.google.common.collect.ImmutableList.builder(); + this.doohickeys.add(doohickey); + return this; + } + @java.lang.SuppressWarnings("all") + public BuilderSingletonRedirectToGuavaBuilder doohickeys(final java.lang.Iterable<? extends Class<?>> doohickeys) { + if (this.doohickeys == null) this.doohickeys = com.google.common.collect.ImmutableList.builder(); + this.doohickeys.addAll(doohickeys); + return this; + } + @java.lang.SuppressWarnings("all") + public BuilderSingletonRedirectToGuava build() { + java.util.Set<String> dangerMice = this.dangerMice == null ? com.google.common.collect.ImmutableSet.of() : this.dangerMice.build(); + java.util.NavigableMap<Integer, Number> things = this.things == null ? com.google.common.collect.ImmutableSortedMap.of() : this.things.build(); + java.util.Collection<Class<?>> doohickeys = this.doohickeys == null ? com.google.common.collect.ImmutableList.of() : this.doohickeys.build(); + return new BuilderSingletonRedirectToGuava(dangerMice, things, doohickeys); + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "BuilderSingletonRedirectToGuava.BuilderSingletonRedirectToGuavaBuilder(dangerMice=" + this.dangerMice + ", things=" + this.things + ", doohickeys=" + this.doohickeys + ")"; + } + } + @java.lang.SuppressWarnings("all") + public static BuilderSingletonRedirectToGuavaBuilder builder() { + return new BuilderSingletonRedirectToGuavaBuilder(); + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/BuilderSingletonRedirectToGuava.java b/test/transform/resource/after-ecj/BuilderSingletonRedirectToGuava.java new file mode 100644 index 00000000..ce8fab10 --- /dev/null +++ b/test/transform/resource/after-ecj/BuilderSingletonRedirectToGuava.java @@ -0,0 +1,71 @@ +import java.util.Set; +import java.util.NavigableMap; +import java.util.Collection; +import lombok.Singular; +@lombok.Builder class BuilderSingletonRedirectToGuava { + public static @java.lang.SuppressWarnings("all") class BuilderSingletonRedirectToGuavaBuilder { + private com.google.common.collect.ImmutableSet.Builder<String> dangerMice; + private com.google.common.collect.ImmutableSortedMap.Builder<Integer, Number> things; + private com.google.common.collect.ImmutableList.Builder<Class<?>> doohickeys; + @java.lang.SuppressWarnings("all") BuilderSingletonRedirectToGuavaBuilder() { + super(); + } + public @java.lang.SuppressWarnings("all") BuilderSingletonRedirectToGuavaBuilder dangerMouse(String dangerMouse) { + if ((this.dangerMice == null)) + this.dangerMice = com.google.common.collect.ImmutableSet.builder(); + this.dangerMice.add(dangerMouse); + return this; + } + public @java.lang.SuppressWarnings("all") BuilderSingletonRedirectToGuavaBuilder dangerMice(java.lang.Iterable<? extends String> dangerMice) { + if ((this.dangerMice == null)) + this.dangerMice = com.google.common.collect.ImmutableSet.builder(); + this.dangerMice.addAll(dangerMice); + return this; + } + public @java.lang.SuppressWarnings("all") BuilderSingletonRedirectToGuavaBuilder thing(Integer thing$key, Number thing$value) { + if ((this.things == null)) + this.things = com.google.common.collect.ImmutableSortedMap.naturalOrder(); + this.things.put(thing$key, thing$value); + return this; + } + public @java.lang.SuppressWarnings("all") BuilderSingletonRedirectToGuavaBuilder things(java.util.Map<? extends Integer, ? extends Number> things) { + if ((this.things == null)) + this.things = com.google.common.collect.ImmutableSortedMap.naturalOrder(); + this.things.putAll(things); + return this; + } + public @java.lang.SuppressWarnings("all") BuilderSingletonRedirectToGuavaBuilder doohickey(Class<?> doohickey) { + if ((this.doohickeys == null)) + this.doohickeys = com.google.common.collect.ImmutableList.builder(); + this.doohickeys.add(doohickey); + return this; + } + public @java.lang.SuppressWarnings("all") BuilderSingletonRedirectToGuavaBuilder doohickeys(java.lang.Iterable<? extends Class<?>> doohickeys) { + if ((this.doohickeys == null)) + this.doohickeys = com.google.common.collect.ImmutableList.builder(); + this.doohickeys.addAll(doohickeys); + return this; + } + public @java.lang.SuppressWarnings("all") BuilderSingletonRedirectToGuava build() { + java.util.Set<String> dangerMice = ((this.dangerMice == null) ? com.google.common.collect.ImmutableSet.of() : this.dangerMice.build()); + java.util.NavigableMap<Integer, Number> things = ((this.things == null) ? com.google.common.collect.ImmutableSortedMap.of() : this.things.build()); + java.util.Collection<Class<?>> doohickeys = ((this.doohickeys == null) ? com.google.common.collect.ImmutableList.of() : this.doohickeys.build()); + return new BuilderSingletonRedirectToGuava(dangerMice, things, doohickeys); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (((((("BuilderSingletonRedirectToGuava.BuilderSingletonRedirectToGuavaBuilder(dangerMice=" + this.dangerMice) + ", things=") + this.things) + ", doohickeys=") + this.doohickeys) + ")"); + } + } + private @Singular Set<String> dangerMice; + private @Singular NavigableMap<Integer, Number> things; + private @Singular Collection<Class<?>> doohickeys; + @java.lang.SuppressWarnings("all") BuilderSingletonRedirectToGuava(final Set<String> dangerMice, final NavigableMap<Integer, Number> things, final Collection<Class<?>> doohickeys) { + super(); + this.dangerMice = dangerMice; + this.things = things; + this.doohickeys = doohickeys; + } + public static @java.lang.SuppressWarnings("all") BuilderSingletonRedirectToGuavaBuilder builder() { + return new BuilderSingletonRedirectToGuavaBuilder(); + } +}
\ No newline at end of file diff --git a/test/transform/resource/before/BuilderSingletonRedirectToGuava.java b/test/transform/resource/before/BuilderSingletonRedirectToGuava.java new file mode 100644 index 00000000..0429f0ed --- /dev/null +++ b/test/transform/resource/before/BuilderSingletonRedirectToGuava.java @@ -0,0 +1,13 @@ +//CONF: lombok.builder.useGuava = true +import java.util.Set; +import java.util.NavigableMap; +import java.util.Collection; + +import lombok.Singular; + +@lombok.Builder +class BuilderSingletonRedirectToGuava { + @Singular private Set<String> dangerMice; + @Singular private NavigableMap<Integer, Number> things; + @Singular private Collection<Class<?>> doohickeys; +} diff --git a/test/transform/src/lombok/transform/TestWithEcj.java b/test/transform/src/lombok/transform/TestWithEcj.java index 4c3f6bf8..0a4057dd 100644 --- a/test/transform/src/lombok/transform/TestWithEcj.java +++ b/test/transform/src/lombok/transform/TestWithEcj.java @@ -57,8 +57,4 @@ public class TestWithEcj extends DirectoryRunner.TestParams { public File getMessagesDirectory() { return new File("test/transform/resource/messages-ecj"); } - - @Override public boolean accept(File file) { - return file.getName().startsWith("BuilderSingleton"); - } } |