diff options
| author | Reinier Zwitserloot <r.zwitserloot@projectlombok.org> | 2020-01-31 06:33:33 +0100 |
|---|---|---|
| committer | Reinier Zwitserloot <r.zwitserloot@projectlombok.org> | 2020-01-31 06:33:33 +0100 |
| commit | c42bfbae39990b365a5f05eb23895da6203023bc (patch) | |
| tree | 6bbebbff773571debc5709072e735f2f42469d46 | |
| parent | d31182c4383a5ccc499862d2a8035d49e5202319 (diff) | |
| download | lombok-c42bfbae39990b365a5f05eb23895da6203023bc.tar.gz lombok-c42bfbae39990b365a5f05eb23895da6203023bc.tar.bz2 lombok-c42bfbae39990b365a5f05eb23895da6203023bc.zip | |
[issue #2221] simplified configuration for `@Singular`-generated plural form nullchecks.
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 |
