diff options
9 files changed, 272 insertions, 26 deletions
diff --git a/doc/changelog.markdown b/doc/changelog.markdown index f46d87db..fbe8e0ad 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -8,8 +8,6 @@ Lombok Changelog * features web page * 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 0fe23d7b..9b7c6c0a 100644 --- a/src/core/lombok/ConfigurationKeys.java +++ b/src/core/lombok/ConfigurationKeys.java @@ -167,6 +167,32 @@ public class ConfigurationKeys { */ 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).") {}; + // ----- Builder ----- + + /** + * lombok configuration: {@code lombok.builder.flagUsage} = {@code WARNING} | {@code ERROR}. + * + * If set, <em>any</em> usage of {@code @Builder} results in a warning / error. + */ + 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.") {}; + + // ----- Singular ----- + + /** + * lombok configuration: {@code lombok.singular.auto} = {@code true} | {@code false}. + * + * By default or if explicitly set to {@code true}, lombok will attempt to automatically singularize the name of your variable/parameter when using {@code @Singular}; the name is assumed to be written in english, and a plural. If explicitly to {@code false}, you must always specify the singular form; this is especially useful if your identifiers are in a foreign language. + */ + public static final ConfigurationKey<Boolean> SINGULAR_AUTO = new ConfigurationKey<Boolean>("lombok.singular.auto", "If true (default): Automatically singularize the assumed-to-be-plural name of your variable/parameter when using {@code @Singular}.") {}; + // ##### Standalones ##### // ----- Cleanup ----- @@ -340,23 +366,6 @@ public class ConfigurationKeys { */ 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 ----- - - /** - * lombok configuration: {@code lombok.builder.flagUsage} = {@code WARNING} | {@code ERROR}. - * - * If set, <em>any</em> usage of {@code @Builder} results in a warning / error. - */ - 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/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java index 91aa3f93..498808bc 100644 --- a/src/core/lombok/eclipse/handlers/HandleBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java @@ -516,10 +516,15 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { AnnotationValues<Singular> ann = createAnnotation(Singular.class, child); String explicitSingular = ann.getInstance().value(); if (explicitSingular.isEmpty()) { - explicitSingular = autoSingularize(node.getName()); - if (explicitSingular == null) { - node.addError("Can't singularize this name; please specify the singular explicitly (i.e. @Singular(\"sheep\"))"); - explicitSingular = pluralName.toString(); + if (Boolean.FALSE.equals(node.getAst().readConfiguration(ConfigurationKeys.SINGULAR_AUTO))) { + node.addError("The singular must be specified explicitly (e.g. @Singular(\"task\")) because auto singularization is disabled."); + explicitSingular = new String(pluralName); + } else { + explicitSingular = autoSingularize(node.getName()); + if (explicitSingular == null) { + node.addError("Can't singularize this name; please specify the singular explicitly (i.e. @Singular(\"sheep\"))"); + explicitSingular = new String(pluralName); + } } } char[] singularName = explicitSingular.toCharArray(); diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java index 7bb0619f..e251e0ce 100644 --- a/src/core/lombok/javac/handlers/HandleBuilder.java +++ b/src/core/lombok/javac/handlers/HandleBuilder.java @@ -466,10 +466,15 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { deleteAnnotationIfNeccessary(child, Singular.class); String explicitSingular = ann.getInstance().value(); if (explicitSingular.isEmpty()) { - explicitSingular = autoSingularize(node.getName()); - if (explicitSingular == null) { - node.addError("Can't singularize this name; please specify the singular explicitly (i.e. @Singular(\"sheep\"))"); + if (Boolean.FALSE.equals(node.getAst().readConfiguration(ConfigurationKeys.SINGULAR_AUTO))) { + node.addError("The singular must be specified explicitly (e.g. @Singular(\"task\")) because auto singularization is disabled."); explicitSingular = pluralName.toString(); + } else { + explicitSingular = autoSingularize(node.getName()); + if (explicitSingular == null) { + node.addError("Can't singularize this name; please specify the singular explicitly (i.e. @Singular(\"sheep\"))"); + explicitSingular = pluralName.toString(); + } } } Name singularName = node.toName(explicitSingular); diff --git a/test/transform/resource/after-delombok/BuilderSingularNoAutosingularize.java b/test/transform/resource/after-delombok/BuilderSingularNoAutosingularize.java new file mode 100644 index 00000000..07bbef9c --- /dev/null +++ b/test/transform/resource/after-delombok/BuilderSingularNoAutosingularize.java @@ -0,0 +1,109 @@ +import java.util.List; +class BuilderSingularNoAutosingularize { + private List<String> things; + private List<String> widgets; + private List<String> items; + @java.lang.SuppressWarnings("all") + BuilderSingularNoAutosingularize(final List<String> things, final List<String> widgets, final List<String> items) { + this.things = things; + this.widgets = widgets; + this.items = items; + } + @java.lang.SuppressWarnings("all") + public static class BuilderSingularNoAutosingularizeBuilder { + private java.util.ArrayList<String> things; + private java.util.ArrayList<String> widgets; + private java.util.ArrayList<String> items; + @java.lang.SuppressWarnings("all") + BuilderSingularNoAutosingularizeBuilder() { + } + @java.lang.SuppressWarnings("all") + public BuilderSingularNoAutosingularizeBuilder things(final String things) { + if (this.things == null) this.things = new java.util.ArrayList<String>(); + this.things.add(things); + return this; + } + @java.lang.SuppressWarnings("all") + public BuilderSingularNoAutosingularizeBuilder things(final java.util.Collection<? extends String> things) { + if (this.things == null) this.things = new java.util.ArrayList<String>(); + this.things.addAll(things); + return this; + } + @java.lang.SuppressWarnings("all") + public BuilderSingularNoAutosingularizeBuilder widget(final String widget) { + if (this.widgets == null) this.widgets = new java.util.ArrayList<String>(); + this.widgets.add(widget); + return this; + } + @java.lang.SuppressWarnings("all") + public BuilderSingularNoAutosingularizeBuilder widgets(final java.util.Collection<? extends String> widgets) { + if (this.widgets == null) this.widgets = new java.util.ArrayList<String>(); + this.widgets.addAll(widgets); + return this; + } + @java.lang.SuppressWarnings("all") + public BuilderSingularNoAutosingularizeBuilder items(final String items) { + if (this.items == null) this.items = new java.util.ArrayList<String>(); + this.items.add(items); + return this; + } + @java.lang.SuppressWarnings("all") + public BuilderSingularNoAutosingularizeBuilder items(final java.util.Collection<? extends String> items) { + if (this.items == null) this.items = new java.util.ArrayList<String>(); + this.items.addAll(items); + return this; + } + @java.lang.SuppressWarnings("all") + public BuilderSingularNoAutosingularize build() { + java.util.List<String> things; + switch (this.things == null ? 0 : this.things.size()) { + case 0: + things = java.util.Collections.emptyList(); + break; + case 1: + things = java.util.Collections.singletonList(this.things.get(0)); + break; + default: + things = new java.util.ArrayList<String>(this.things.size()); + things.addAll(this.things); + things = java.util.Collections.unmodifiableList(things); + } + java.util.List<String> widgets; + switch (this.widgets == null ? 0 : this.widgets.size()) { + case 0: + widgets = java.util.Collections.emptyList(); + break; + case 1: + widgets = java.util.Collections.singletonList(this.widgets.get(0)); + break; + default: + widgets = new java.util.ArrayList<String>(this.widgets.size()); + widgets.addAll(this.widgets); + widgets = java.util.Collections.unmodifiableList(widgets); + } + java.util.List<String> items; + switch (this.items == null ? 0 : this.items.size()) { + case 0: + items = java.util.Collections.emptyList(); + break; + case 1: + items = java.util.Collections.singletonList(this.items.get(0)); + break; + default: + items = new java.util.ArrayList<String>(this.items.size()); + items.addAll(this.items); + items = java.util.Collections.unmodifiableList(items); + } + return new BuilderSingularNoAutosingularize(things, widgets, items); + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "BuilderSingularNoAutosingularize.BuilderSingularNoAutosingularizeBuilder(things=" + this.things + ", widgets=" + this.widgets + ", items=" + this.items + ")"; + } + } + @java.lang.SuppressWarnings("all") + public static BuilderSingularNoAutosingularizeBuilder builder() { + return new BuilderSingularNoAutosingularizeBuilder(); + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/BuilderSingularNoAutosingularize.java b/test/transform/resource/after-ecj/BuilderSingularNoAutosingularize.java new file mode 100644 index 00000000..53bed757 --- /dev/null +++ b/test/transform/resource/after-ecj/BuilderSingularNoAutosingularize.java @@ -0,0 +1,105 @@ +import java.util.List; +import lombok.Singular; +@lombok.Builder class BuilderSingularNoAutosingularize { + public static @java.lang.SuppressWarnings("all") class BuilderSingularNoAutosingularizeBuilder { + private java.util.ArrayList<String> things; + private java.util.ArrayList<String> widgets; + private java.util.ArrayList<String> items; + @java.lang.SuppressWarnings("all") BuilderSingularNoAutosingularizeBuilder() { + super(); + } + public @java.lang.SuppressWarnings("all") BuilderSingularNoAutosingularizeBuilder things(String things) { + if ((this.things == null)) + this.things = new java.util.ArrayList<String>(); + this.things.add(things); + return this; + } + public @java.lang.SuppressWarnings("all") BuilderSingularNoAutosingularizeBuilder things(java.util.Collection<? extends String> things) { + if ((this.things == null)) + this.things = new java.util.ArrayList<String>(); + this.things.addAll(things); + return this; + } + public @java.lang.SuppressWarnings("all") BuilderSingularNoAutosingularizeBuilder widget(String widget) { + if ((this.widgets == null)) + this.widgets = new java.util.ArrayList<String>(); + this.widgets.add(widget); + return this; + } + public @java.lang.SuppressWarnings("all") BuilderSingularNoAutosingularizeBuilder widgets(java.util.Collection<? extends String> widgets) { + if ((this.widgets == null)) + this.widgets = new java.util.ArrayList<String>(); + this.widgets.addAll(widgets); + return this; + } + public @java.lang.SuppressWarnings("all") BuilderSingularNoAutosingularizeBuilder items(String items) { + if ((this.items == null)) + this.items = new java.util.ArrayList<String>(); + this.items.add(items); + return this; + } + public @java.lang.SuppressWarnings("all") BuilderSingularNoAutosingularizeBuilder items(java.util.Collection<? extends String> items) { + if ((this.items == null)) + this.items = new java.util.ArrayList<String>(); + this.items.addAll(items); + return this; + } + public @java.lang.SuppressWarnings("all") BuilderSingularNoAutosingularize build() { + java.util.List<String> things; + switch (((this.things == null) ? 0 : this.things.size())) { + case 0 : + things = java.util.Collections.emptyList(); + break; + case 1 : + things = java.util.Collections.singletonList(this.things.get(0)); + break; + default : + things = new java.util.ArrayList<String>(this.things.size()); + things.addAll(this.things); + things = java.util.Collections.unmodifiableList(things); + } + java.util.List<String> widgets; + switch (((this.widgets == null) ? 0 : this.widgets.size())) { + case 0 : + widgets = java.util.Collections.emptyList(); + break; + case 1 : + widgets = java.util.Collections.singletonList(this.widgets.get(0)); + break; + default : + widgets = new java.util.ArrayList<String>(this.widgets.size()); + widgets.addAll(this.widgets); + widgets = java.util.Collections.unmodifiableList(widgets); + } + java.util.List<String> items; + switch (((this.items == null) ? 0 : this.items.size())) { + case 0 : + items = java.util.Collections.emptyList(); + break; + case 1 : + items = java.util.Collections.singletonList(this.items.get(0)); + break; + default : + items = new java.util.ArrayList<String>(this.items.size()); + items.addAll(this.items); + items = java.util.Collections.unmodifiableList(items); + } + return new BuilderSingularNoAutosingularize(things, widgets, items); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (((((("BuilderSingularNoAutosingularize.BuilderSingularNoAutosingularizeBuilder(things=" + this.things) + ", widgets=") + this.widgets) + ", items=") + this.items) + ")"); + } + } + private @Singular List<String> things; + private @Singular("widget") List<String> widgets; + private @Singular List<String> items; + @java.lang.SuppressWarnings("all") BuilderSingularNoAutosingularize(final List<String> things, final List<String> widgets, final List<String> items) { + super(); + this.things = things; + this.widgets = widgets; + this.items = items; + } + public static @java.lang.SuppressWarnings("all") BuilderSingularNoAutosingularizeBuilder builder() { + return new BuilderSingularNoAutosingularizeBuilder(); + } +} diff --git a/test/transform/resource/before/BuilderSingularNoAutoSingularize.java b/test/transform/resource/before/BuilderSingularNoAutoSingularize.java new file mode 100644 index 00000000..31e2c3ca --- /dev/null +++ b/test/transform/resource/before/BuilderSingularNoAutoSingularize.java @@ -0,0 +1,11 @@ +//CONF: lombok.singular.auto = false +import java.util.List; + +import lombok.Singular; + +@lombok.Builder +class BuilderSingularNoAutosingularize { + @Singular private List<String> things; + @Singular("widget") private List<String> widgets; + @Singular private List<String> items; +} diff --git a/test/transform/resource/messages-delombok/BuilderSingularNoAutosingularize.java.messages b/test/transform/resource/messages-delombok/BuilderSingularNoAutosingularize.java.messages new file mode 100644 index 00000000..8719789b --- /dev/null +++ b/test/transform/resource/messages-delombok/BuilderSingularNoAutosingularize.java.messages @@ -0,0 +1,2 @@ +8 The singular must be specified explicitly (e.g. @Singular("task")) because auto singularization is disabled. +10 The singular must be specified explicitly (e.g. @Singular("task")) because auto singularization is disabled. diff --git a/test/transform/resource/messages-ecj/BuilderSingularNoAutosingularize.java.messages b/test/transform/resource/messages-ecj/BuilderSingularNoAutosingularize.java.messages new file mode 100644 index 00000000..8719789b --- /dev/null +++ b/test/transform/resource/messages-ecj/BuilderSingularNoAutosingularize.java.messages @@ -0,0 +1,2 @@ +8 The singular must be specified explicitly (e.g. @Singular("task")) because auto singularization is disabled. +10 The singular must be specified explicitly (e.g. @Singular("task")) because auto singularization is disabled. |