aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReinier Zwitserloot <r.zwitserloot@projectlombok.org>2020-01-31 06:33:33 +0100
committerReinier Zwitserloot <r.zwitserloot@projectlombok.org>2020-01-31 06:33:33 +0100
commitc42bfbae39990b365a5f05eb23895da6203023bc (patch)
tree6bbebbff773571debc5709072e735f2f42469d46
parentd31182c4383a5ccc499862d2a8035d49e5202319 (diff)
downloadlombok-c42bfbae39990b365a5f05eb23895da6203023bc.tar.gz
lombok-c42bfbae39990b365a5f05eb23895da6203023bc.tar.bz2
lombok-c42bfbae39990b365a5f05eb23895da6203023bc.zip
[issue #2221] simplified configuration for `@Singular`-generated plural form nullchecks.
-rw-r--r--doc/changelog.markdown2
-rw-r--r--src/core/lombok/ConfigurationKeys.java14
-rw-r--r--src/core/lombok/Singular.java67
-rw-r--r--src/core/lombok/core/configuration/NullCheckExceptionType.java5
-rw-r--r--src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java10
-rwxr-xr-xsrc/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java52
-rwxr-xr-xsrc/core/lombok/eclipse/handlers/HandleBuilder.java15
-rwxr-xr-xsrc/core/lombok/eclipse/handlers/HandleConstructor.java2
-rw-r--r--src/core/lombok/eclipse/handlers/HandleNonNull.java2
-rw-r--r--src/core/lombok/eclipse/handlers/HandleSetter.java2
-rwxr-xr-xsrc/core/lombok/eclipse/handlers/HandleSuperBuilder.java6
-rw-r--r--src/core/lombok/eclipse/handlers/HandleWith.java2
-rw-r--r--src/core/lombok/javac/handlers/HandleBuilder.java16
-rw-r--r--src/core/lombok/javac/handlers/HandleSetter.java2
-rw-r--r--src/core/lombok/javac/handlers/HandleSuperBuilder.java4
-rw-r--r--src/core/lombok/javac/handlers/JavacHandlerUtil.java8
-rw-r--r--src/core/lombok/javac/handlers/JavacSingularsRecipes.java48
-rw-r--r--test/transform/resource/after-delombok/BuilderDefaultsWarnings.java4
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularAnnotatedTypes.java8
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularAnnotatedTypesWithSetterPrefix.java8
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularGuavaListsSets.java20
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularGuavaMaps.java12
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularLists.java12
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularMaps.java16
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularMapsWithSetterPrefix.java57
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularNoAuto.java12
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularNoAutoWithSetterPrefix.java12
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularNullBehavior1.java91
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularNullBehavior2.java52
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularRedirectToGuava.java12
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularSets.java16
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularSetsWithSetterPrefix.java16
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularToBuilderWithNull.java4
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularToBuilderWithNullWithSetterPrefix.java4
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularWildcardListsWithToBuilder.java8
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularWithPrefixes.java4
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularWithPrefixesWithSetterPrefix.java4
-rw-r--r--test/transform/resource/after-delombok/BuilderWithDeprecated.java8
-rw-r--r--test/transform/resource/after-delombok/BuilderWithToBuilder.java4
-rw-r--r--test/transform/resource/after-delombok/CheckerFrameworkBuilder.java4
-rw-r--r--test/transform/resource/after-delombok/CheckerFrameworkSuperBuilder.java4
-rw-r--r--test/transform/resource/after-delombok/SuperBuilderBasic.java4
-rw-r--r--test/transform/resource/after-delombok/SuperBuilderBasicToBuilder.java4
-rw-r--r--test/transform/resource/after-delombok/SuperBuilderSingularAnnotatedTypes.java8
-rw-r--r--test/transform/resource/after-delombok/SuperBuilderWithCustomBuilderMethod.java4
-rw-r--r--test/transform/resource/after-delombok/SuperBuilderWithGenerics.java4
-rw-r--r--test/transform/resource/after-delombok/SuperBuilderWithGenerics2.java4
-rw-r--r--test/transform/resource/after-delombok/SuperBuilderWithGenericsAndToBuilder.java4
-rw-r--r--test/transform/resource/after-delombok/SuperBuilderWithPrefixes.java4
-rw-r--r--test/transform/resource/after-ecj/BuilderDefaultsWarnings.java4
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularAnnotatedTypes.java8
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularAnnotatedTypesWithSetterPrefix.java8
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularGuavaListsSets.java20
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularGuavaMaps.java12
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularLists.java12
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularMaps.java16
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularMapsWithSetterPrefix.java71
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularNoAuto.java12
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularNoAutoWithSetterPrefix.java12
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularNullBehavior1.java94
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularNullBehavior2.java49
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularRedirectToGuava.java12
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularSets.java16
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularSetsWithSetterPrefix.java16
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularToBuilderWithNull.java4
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularToBuilderWithNullWithSetterPrefix.java4
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularWildcardListsWithToBuilder.java8
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularWithPrefixes.java4
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularWithPrefixesWithSetterPrefix.java4
-rw-r--r--test/transform/resource/after-ecj/BuilderWithDeprecated.java8
-rw-r--r--test/transform/resource/after-ecj/BuilderWithToBuilder.java4
-rw-r--r--test/transform/resource/after-ecj/CheckerFrameworkBuilder.java4
-rw-r--r--test/transform/resource/after-ecj/CheckerFrameworkSuperBuilder.java4
-rw-r--r--test/transform/resource/after-ecj/SuperBuilderBasic.java4
-rw-r--r--test/transform/resource/after-ecj/SuperBuilderBasicToBuilder.java4
-rw-r--r--test/transform/resource/after-ecj/SuperBuilderSingularAnnotatedTypes.java8
-rw-r--r--test/transform/resource/after-ecj/SuperBuilderWithCustomBuilderMethod.java4
-rw-r--r--test/transform/resource/after-ecj/SuperBuilderWithGenerics.java4
-rw-r--r--test/transform/resource/after-ecj/SuperBuilderWithGenerics2.java4
-rw-r--r--test/transform/resource/after-ecj/SuperBuilderWithGenericsAndToBuilder.java4
-rw-r--r--test/transform/resource/after-ecj/SuperBuilderWithPrefixes.java4
-rw-r--r--test/transform/resource/before/BuilderSingularMapsWithSetterPrefix.java3
-rw-r--r--test/transform/resource/before/BuilderSingularNullBehavior1.java7
-rw-r--r--test/transform/resource/before/BuilderSingularNullBehavior2.java7
-rw-r--r--website/templates/features/Builder.html16
85 files changed, 517 insertions, 643 deletions
diff --git a/doc/changelog.markdown b/doc/changelog.markdown
index 1a549866..f1980523 100644
--- a/doc/changelog.markdown
+++ b/doc/changelog.markdown
@@ -6,7 +6,7 @@ Lombok Changelog
* PLATFORM: Support for JDK14 (including `pattern match` instanceof expressions).
* FEATURE: In [`lombok.config`](https://projectlombok.org/features/configuration) it is possible to import other config files, even from a `.zip` or `.jar`.
* FEATURE: You can now configure a builder's 'setter' prefixes via `@Builder(setterPrefix = "set")` for example. We discourage doing this, but if some library you use requires them, have at it. [Pull Request #2174](https://github.com/rzwitserloot/lombok/pull/2174], [Issue #1805](https://github.com/rzwitserloot/lombok/issues/1805).
-* FEATURE: If you use `@Builder`'s `@Singular`, a plural form is also generated, which has the effect of adding all elements in the passed collection. If you pass a null reference, this would result in a message-less `NullPointerException`. Now, it results in that exception but with a useful message attached, and you can choose other behaviors as well via a parameter on the `@Singular` annotation and via `lombok.config`; you can even choose treat them as empty collections; this can be useful when deserializing (e.g. Jackson JSON) and JPA/Hibernate code. [Issue #2221](https://github.com/rzwitserloot/lombok/issues/2221]. [singular documentation](https://projectlombok.org/features/Builder).
+* FEATURE: If you use `@Builder`'s `@Singular`, a plural form is also generated, which has the effect of adding all elements in the passed collection. If you pass a null reference, this would result in a message-less `NullPointerException`. Now, it results in that exception but with a useful message attached (uses the same config as `@NonNull`), or alternatively via a parameter on `@Singular`, you can choose to ignore such a call (add nothing, return immediately); this can be useful when deserializing (e.g. Jackson JSON) and JPA/Hibernate code. [Issue #2221](https://github.com/rzwitserloot/lombok/issues/2221]. [singular documentation](https://projectlombok.org/features/Builder).
* FEATURE: Tired of being unable to use `@javax.annotation.ParametersAreNonnullByDefault` or `@org.eclipse.jdt.annotation.NonNullByDefault` because then the equals method that lombok generates isn't valid? Fret no more; lombok can now add nullity annotations where relevant. Set the flavour of nullity annotation you prefer in your `lombok.config`. Applies to the return value of `toString` and `withX` methods, and the parameter of `equals`, `canEqual`, and the plural form of `@Singular` marked fields for builder classes. [Issue #788](https://github.com/rzwitserloot/lombok/issues/788)
* BUGFIX: `lombok.experimental.Wither` has been deprecated (it has been renamed to `lombok.With`). However, the intent is that lombok still handles the old annotation in case you haven't updated your lombok dep yet. However, only a star import on `lombok.experimental.*` worked; an explicit one would cause lombok to not generate any with method. [Issue #2235](https://github.com/rzwitserloot/lombok/issues/2235)
* BUGFIX: Referring to an inner class inside the generics on a class marked with `@SuperBuilder` would cause the error `wrong number of type arguments; required 3` [Issue #2262](https://github.com/rzwitserloot/lombok/issues/2262); fixed by github user [`@Lekanich`](https://github.com/rzwitserloot/lombok/issues/2262) - thank you!
diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java
index 86cb4650..49613fc4 100644
--- a/src/core/lombok/ConfigurationKeys.java
+++ b/src/core/lombok/ConfigurationKeys.java
@@ -23,7 +23,6 @@ package lombok;
import java.util.List;
-import lombok.Singular.NullCollectionBehavior;
import lombok.core.configuration.CallSuperType;
import lombok.core.configuration.CheckerFrameworkVersion;
import lombok.core.configuration.ConfigurationKey;
@@ -317,18 +316,6 @@ public class ConfigurationKeys {
*/
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 @Singular.") {};
- /**
- * lombok configuration: {@code lombok.singular.nullCollections} = one of: [{@code NullPointerException}, {@code IllegalArgumentException}, {@code JDK}, {@code Guava}, or {@code ignore}].
- *
- * Lombok generates a 'plural form' method, which takes in a collection and will <em>add</em> each element in it to the {@code @Singular} marked target. What should happen if {@code null} is passed instead of a collection instance?<ul>
- * <li>If the chosen configuration is {@code NullPointerException} (the default), or {@code IllegalArgumentException}, that exception type is a thrown, with as message <code><em>field-name</em> must not be null</code>.</li>
- * <li>If the chosen configuration is {@code JDK}, a call to {@code java.util.Objects.requireNonNull} is generated with the fieldname passed along (which throws {@code NullPointerException}).</li>
- * <li>If the chosen configuration is {@code Guava}, a call to {@code com.google.common.base.Preconditions.checkNotNull} is generated with the fieldname passed along (which throws {@code NullPointerException}).</li>
- * <li>If the chosen configuration is {@code Ignore}, then no exception occurs, and the call does nothing; it acts as if an empty collection was passed.</li>
- * </ul>
- */
- public static final ConfigurationKey<NullCollectionBehavior> SINGULAR_NULL_COLLECTIONS = new ConfigurationKey<NullCollectionBehavior>("lombok.singular.nullCollections", "Lombok generates a method to add all elements in a collection when using @Singular. What should happen if a null ref is passed? default: throw NullPointerException.") {};
-
// ##### Standalones #####
// ----- Cleanup -----
@@ -360,6 +347,7 @@ public class ConfigurationKeys {
* <li>If the chosen configuration is {@code JDK}, a call to {@code java.util.Objects.requireNonNull} is generated with the fieldname passed along (which throws {@code NullPointerException}).</li>
* <li>If the chosen configuration is {@code Guava}, a call to {@code com.google.common.base.Preconditions.checkNotNull} is generated with the fieldname passed along (which throws {@code NullPointerException}).</li>
* </ul>
+ * NB: The chosen nullcheck style is also used by {@code @Builder}'s {@code @Singular} annotation to check any collections passed to a plural-form method.
*/
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).") {};
diff --git a/src/core/lombok/Singular.java b/src/core/lombok/Singular.java
index f8cf6853..2ceaad58 100644
--- a/src/core/lombok/Singular.java
+++ b/src/core/lombok/Singular.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015-2017 The Project Lombok Authors.
+ * Copyright (C) 2015-2020 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
@@ -27,10 +27,6 @@ import static java.lang.annotation.RetentionPolicy.*;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
-import lombok.core.LombokImmutableList;
-import lombok.core.configuration.ExampleValueString;
-import lombok.core.configuration.NullCheckExceptionType;
-
/**
* The singular annotation is used together with {@code @Builder} to create single element 'add' methods in the builder for collections.
*/
@@ -40,63 +36,6 @@ public @interface Singular {
/** @return The singular name of this field. If it's a normal english plural, lombok will figure it out automatically. Otherwise, this parameter is mandatory. */
String value() default "";
- NullCollectionBehavior nullBehavior() default NullCollectionBehavior.NULL_POINTER_EXCEPTION;
-
- @ExampleValueString("[NullPointerException | IllegalArgumentException | JDK | Guava | Ignore]")
- public enum NullCollectionBehavior {
- ILLEGAL_ARGUMENT_EXCEPTION {
- @Override public String getExceptionType() {
- return NullCheckExceptionType.ILLEGAL_ARGUMENT_EXCEPTION.getExceptionType();
- }
-
- @Override public LombokImmutableList<String> getMethod() {
- return NullCheckExceptionType.ILLEGAL_ARGUMENT_EXCEPTION.getMethod();
- }
- },
- NULL_POINTER_EXCEPTION {
- @Override public String getExceptionType() {
- return NullCheckExceptionType.NULL_POINTER_EXCEPTION.getExceptionType();
- }
-
- @Override public LombokImmutableList<String> getMethod() {
- return NullCheckExceptionType.NULL_POINTER_EXCEPTION.getMethod();
- }
- },
- JDK {
- @Override public String getExceptionType() {
- return NullCheckExceptionType.JDK.getExceptionType();
- }
-
- @Override public LombokImmutableList<String> getMethod() {
- return NullCheckExceptionType.JDK.getMethod();
- }
- },
- GUAVA {
- @Override public String getExceptionType() {
- return NullCheckExceptionType.GUAVA.getExceptionType();
- }
-
- @Override public LombokImmutableList<String> getMethod() {
- return NullCheckExceptionType.GUAVA.getMethod();
- }
- },
- IGNORE {
- @Override public String getExceptionType() {
- return null;
- }
-
- @Override public LombokImmutableList<String> getMethod() {
- return null;
- }
- };
-
-
- public String toExceptionMessage(String fieldName) {
- return fieldName + " cannot be null";
- }
-
- public abstract String getExceptionType();
-
- public abstract LombokImmutableList<String> getMethod();
- }
+ /** @return If true, the plural variant (which takes a collection and adds each element inside) will treat {@code null} as an empty collection, i.e. do nothing. If {@code false) (the default), it is null checked as if annotated with {@code @lombok.NonNull}. */
+ boolean ignoreNullCollections() default false;
}
diff --git a/src/core/lombok/core/configuration/NullCheckExceptionType.java b/src/core/lombok/core/configuration/NullCheckExceptionType.java
index 4632916c..2c1b7ce6 100644
--- a/src/core/lombok/core/configuration/NullCheckExceptionType.java
+++ b/src/core/lombok/core/configuration/NullCheckExceptionType.java
@@ -74,8 +74,9 @@ public enum NullCheckExceptionType {
private static final LombokImmutableList<String> METHOD_JDK = LombokImmutableList.of("java", "util", "Objects", "requireNonNull");
private static final LombokImmutableList<String> METHOD_GUAVA = LombokImmutableList.of("com", "google", "common", "base", "Preconditions", "checkNotNull");
- public String toExceptionMessage(String fieldName) {
- return fieldName + " is marked non-null but is null";
+ public String toExceptionMessage(String fieldName, String customMessage) {
+ if (customMessage == null) return fieldName + " is marked non-null but is null";
+ return customMessage.replace("%s", fieldName);
}
public abstract String getExceptionType();
diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
index bd0ad23b..bdb88299 100644
--- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
+++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
@@ -1992,7 +1992,7 @@ public class EclipseHandlerUtil {
* Generates a new statement that checks if the given local variable is null, and if so, throws a specified exception with the
* variable name as message.
*/
- public static Statement generateNullCheck(TypeReference type, char[] variable, EclipseNode sourceNode) {
+ public static Statement generateNullCheck(TypeReference type, char[] variable, EclipseNode sourceNode, String customMessage) {
NullCheckExceptionType exceptionType = sourceNode.getAst().readConfiguration(ConfigurationKeys.NON_NULL_EXCEPTION_TYPE);
if (exceptionType == null) exceptionType = NullCheckExceptionType.NULL_POINTER