mirror of
https://github.com/tiennm99/lombok.git
synced 2026-10-18 18:15:34 +00:00
[issue #2221] simplified configuration for @Singular-generated plural form nullchecks.
This commit is contained in:
85 files changed
+517
-643
No files matched your search
@@ -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).") {};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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_EXCEPTION;
|
||||
|
||||
@@ -2001,11 +2001,11 @@ public class EclipseHandlerUtil {
|
||||
int pS = source.sourceStart, pE = source.sourceEnd;
|
||||
long p = (long) pS << 32 | pE;
|
||||
|
||||
if (isPrimitive(type)) return null;
|
||||
if (type != null && isPrimitive(type)) return null;
|
||||
SingleNameReference varName = new SingleNameReference(variable, p);
|
||||
setGeneratedBy(varName, source);
|
||||
|
||||
StringLiteral message = new StringLiteral(exceptionType.toExceptionMessage(new String(variable)).toCharArray(), pS, pE, 0);
|
||||
StringLiteral message = new StringLiteral(exceptionType.toExceptionMessage(new String(variable), customMessage).toCharArray(), pS, pE, 0);
|
||||
setGeneratedBy(message, source);
|
||||
|
||||
LombokImmutableList<String> method = exceptionType.getMethod();
|
||||
@@ -2071,8 +2071,8 @@ public class EclipseHandlerUtil {
|
||||
*
|
||||
* @param exName The name of the exception to throw; normally {@code java.lang.NullPointerException}.
|
||||
*/
|
||||
public static Statement generateNullCheck(AbstractVariableDeclaration variable, EclipseNode sourceNode) {
|
||||
return generateNullCheck(variable.type, variable.name, sourceNode);
|
||||
public static Statement generateNullCheck(AbstractVariableDeclaration variable, EclipseNode sourceNode, String customMessage) {
|
||||
return generateNullCheck(variable.type, variable.name, sourceNode, customMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -33,7 +33,6 @@ import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
|
||||
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Annotation;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Argument;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Block;
|
||||
@@ -49,16 +48,13 @@ import org.eclipse.jdt.internal.compiler.ast.NullLiteral;
|
||||
import org.eclipse.jdt.internal.compiler.ast.OperatorIds;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Reference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Statement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.StringLiteral;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ThisReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ThrowStatement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Wildcard;
|
||||
import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
|
||||
@@ -67,12 +63,10 @@ import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
|
||||
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Singular.NullCollectionBehavior;
|
||||
import lombok.core.LombokImmutableList;
|
||||
import lombok.core.SpiLoadUtil;
|
||||
import lombok.core.TypeLibrary;
|
||||
import lombok.core.configuration.CheckerFrameworkVersion;
|
||||
import lombok.eclipse.Eclipse;
|
||||
import lombok.eclipse.EclipseNode;
|
||||
|
||||
public class EclipseSingularsRecipes {
|
||||
@@ -135,14 +129,14 @@ public class EclipseSingularsRecipes {
|
||||
private final List<TypeReference> typeArgs;
|
||||
private final String targetFqn;
|
||||
private final EclipseSingularizer singularizer;
|
||||
private final NullCollectionBehavior nullCollectionBehavior;
|
||||
private final boolean ignoreNullCollections;
|
||||
private final ASTNode source;
|
||||
|
||||
public SingularData(EclipseNode annotation, char[] singularName, char[] pluralName, List<TypeReference> typeArgs, String targetFqn, EclipseSingularizer singularizer, ASTNode source, NullCollectionBehavior nullCollectionBehavior) {
|
||||
this(annotation, singularName, pluralName, typeArgs, targetFqn, singularizer, source, nullCollectionBehavior, new char[0]);
|
||||
public SingularData(EclipseNode annotation, char[] singularName, char[] pluralName, List<TypeReference> typeArgs, String targetFqn, EclipseSingularizer singularizer, ASTNode source, boolean ignoreNullCollections) {
|
||||
this(annotation, singularName, pluralName, typeArgs, targetFqn, singularizer, source, ignoreNullCollections, new char[0]);
|
||||
}
|
||||
|
||||
public SingularData(EclipseNode annotation, char[] singularName, char[] pluralName, List<TypeReference> typeArgs, String targetFqn, EclipseSingularizer singularizer, ASTNode source, NullCollectionBehavior nullCollectionBehavior, char[] setterPrefix) {
|
||||
public SingularData(EclipseNode annotation, char[] singularName, char[] pluralName, List<TypeReference> typeArgs, String targetFqn, EclipseSingularizer singularizer, ASTNode source, boolean ignoreNullCollections, char[] setterPrefix) {
|
||||
this.annotation = annotation;
|
||||
this.singularName = singularName;
|
||||
this.pluralName = pluralName;
|
||||
@@ -150,7 +144,7 @@ public class EclipseSingularsRecipes {
|
||||
this.targetFqn = targetFqn;
|
||||
this.singularizer = singularizer;
|
||||
this.source = source;
|
||||
this.nullCollectionBehavior = nullCollectionBehavior;
|
||||
this.ignoreNullCollections = ignoreNullCollections;
|
||||
this.setterPrefix = setterPrefix;
|
||||
}
|
||||
|
||||
@@ -198,8 +192,8 @@ public class EclipseSingularsRecipes {
|
||||
return singularizer;
|
||||
}
|
||||
|
||||
public NullCollectionBehavior getNullCollectionBehavior() {
|
||||
return nullCollectionBehavior;
|
||||
public boolean isIgnoreNullCollections() {
|
||||
return ignoreNullCollections;
|
||||
}
|
||||
|
||||
public String getTargetSimpleType() {
|
||||
@@ -439,9 +433,9 @@ public class EclipseSingularsRecipes {
|
||||
}
|
||||
|
||||
protected void nullBehaviorize(EclipseNode typeNode, SingularData data, List<Statement> statements, Argument arg) {
|
||||
NullCollectionBehavior behavior = data.getNullCollectionBehavior();
|
||||
boolean ignoreNullCollections = data.isIgnoreNullCollections();
|
||||
|
||||
if (behavior == NullCollectionBehavior.IGNORE) {
|
||||
if (ignoreNullCollections) {
|
||||
Expression isNotNull = new EqualExpression(new SingleNameReference(data.getPluralName(), 0L), new NullLiteral(0, 0), OperatorIds.NOT_EQUAL);
|
||||
Block b = new Block(0);
|
||||
b.statements = statements.toArray(new Statement[statements.size()]);
|
||||
@@ -452,32 +446,8 @@ public class EclipseSingularsRecipes {
|
||||
}
|
||||
|
||||
EclipseHandlerUtil.createRelevantNonNullAnnotation(typeNode, arg);
|
||||
|
||||
String exceptionTypeStr = behavior.getExceptionType();
|
||||
StringLiteral message = new StringLiteral(behavior.toExceptionMessage(new String(data.getPluralName())).toCharArray(), 0, 0, 0);
|
||||
if (exceptionTypeStr != null) {
|
||||
Expression isNull = new EqualExpression(new SingleNameReference(data.getPluralName(), 0L), new NullLiteral(0, 0), OperatorIds.EQUAL_EQUAL);
|
||||
int partCount = 1;
|
||||
for (int i = 0; i < exceptionTypeStr.length(); i++) if (exceptionTypeStr.charAt(i) == '.') partCount++;
|
||||
long[] ps = new long[partCount];
|
||||
Arrays.fill(ps, 0L);
|
||||
AllocationExpression alloc = new AllocationExpression();
|
||||
alloc.type = new QualifiedTypeReference(Eclipse.fromQualifiedName(exceptionTypeStr), ps);
|
||||
alloc.arguments = new Expression[] {message};
|
||||
Statement t = new ThrowStatement(alloc, 0, 0);
|
||||
statements.add(0, new IfStatement(isNull, t, 0, 0));
|
||||
return;
|
||||
}
|
||||
|
||||
MessageSend invoke = new MessageSend();
|
||||
LombokImmutableList<String> method = behavior.getMethod();
|
||||
char[][] utilityTypeName = new char[method.size() - 1][];
|
||||
for (int i = 0; i < method.size() - 1; i++) utilityTypeName[i] = method.get(i).toCharArray();
|
||||
|
||||
invoke.receiver = new QualifiedNameReference(utilityTypeName, new long[method.size() - 1], 0, 0);
|
||||
invoke.selector = method.get(method.size() - 1).toCharArray();
|
||||
invoke.arguments = new Expression[] {new SingleNameReference(data.getPluralName(), 0L), message};
|
||||
statements.add(0, invoke);
|
||||
Statement nullCheck = EclipseHandlerUtil.generateNullCheck(null, data.getPluralName(), typeNode, "%s cannot be null");
|
||||
statements.add(0, nullCheck);
|
||||
}
|
||||
|
||||
protected abstract char[][] getEmptyMakerReceiver(String targetFqn);
|
||||
|
||||
@@ -79,7 +79,6 @@ import org.mangosdk.spi.ProviderFor;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Builder;
|
||||
import lombok.Builder.ObtainVia;
|
||||
import lombok.Singular.NullCollectionBehavior;
|
||||
import lombok.ConfigurationKeys;
|
||||
import lombok.Singular;
|
||||
import lombok.ToString;
|
||||
@@ -1036,21 +1035,9 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
return null;
|
||||
}
|
||||
|
||||
NullCollectionBehavior behavior = getNullBehaviorFor(ann, singularInstance, node);
|
||||
return new SingularData(child, singularName, pluralName, typeArgs == null ? Collections.<TypeReference>emptyList() : Arrays.asList(typeArgs), targetFqn, singularizer, source, behavior, setterPrefix.toCharArray());
|
||||
return new SingularData(child, singularName, pluralName, typeArgs == null ? Collections.<TypeReference>emptyList() : Arrays.asList(typeArgs), targetFqn, singularizer, source, singularInstance.ignoreNullCollections(), setterPrefix.toCharArray());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static NullCollectionBehavior getNullBehaviorFor(AnnotationValues<Singular> ann, Singular singularInstance, EclipseNode node) {
|
||||
NullCollectionBehavior behavior;
|
||||
if (ann.isExplicit("nullBehavior")) {
|
||||
behavior = singularInstance.nullBehavior();
|
||||
} else {
|
||||
behavior = node.getAst().readConfiguration(ConfigurationKeys.SINGULAR_NULL_COLLECTIONS);
|
||||
}
|
||||
if (behavior == null) return NullCollectionBehavior.NULL_POINTER_EXCEPTION;
|
||||
return behavior;
|
||||
}
|
||||
}
|
||||
@@ -411,7 +411,7 @@ public class HandleConstructor {
|
||||
Argument parameter = new Argument(fieldName, fieldPos, copyType(field.type, source), Modifier.FINAL);
|
||||
Annotation[] copyableAnnotations = findCopyableAnnotations(fieldNode);
|
||||
if (hasNonNullAnnotations(fieldNode)) {
|
||||
Statement nullCheck = generateNullCheck(parameter, sourceNode);
|
||||
Statement nullCheck = generateNullCheck(parameter, sourceNode, null);
|
||||
if (nullCheck != null) nullChecks.add(nullCheck);
|
||||
}
|
||||
parameter.annotations = copyAnnotations(source, copyableAnnotations);
|
||||
|
||||
@@ -145,7 +145,7 @@ public class HandleNonNull extends EclipseAnnotationHandler<NonNull> {
|
||||
// and if they exist, create a new method in the class: 'private static <T> T lombok$nullCheck(T expr, String msg) {if (expr == null) throw NPE; return expr;}' and
|
||||
// wrap all references to it in the super/this to a call to this method.
|
||||
|
||||
Statement nullCheck = generateNullCheck(param, annotationNode);
|
||||
Statement nullCheck = generateNullCheck(param, annotationNode, null);
|
||||
|
||||
if (nullCheck == null) {
|
||||
// @NonNull applied to a primitive. Kinda pointless. Let's generate a warning.
|
||||
|
||||
@@ -245,7 +245,7 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> {
|
||||
if (!hasNonNullAnnotations(fieldNode) && !hasNonNullAnnotations(fieldNode, onParam)) {
|
||||
statements.add(assignment);
|
||||
} else {
|
||||
Statement nullCheck = generateNullCheck(field.type, paramName, sourceNode);
|
||||
Statement nullCheck = generateNullCheck(field.type, paramName, sourceNode, null);
|
||||
if (nullCheck != null) statements.add(nullCheck);
|
||||
statements.add(assignment);
|
||||
}
|
||||
|
||||
@@ -79,7 +79,6 @@ import org.mangosdk.spi.ProviderFor;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Builder;
|
||||
import lombok.Builder.ObtainVia;
|
||||
import lombok.Singular.NullCollectionBehavior;
|
||||
import lombok.ConfigurationKeys;
|
||||
import lombok.Singular;
|
||||
import lombok.ToString;
|
||||
@@ -567,7 +566,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
|
||||
}
|
||||
|
||||
if (hasNonNullAnnotations(fieldNode.originalFieldNode)) {
|
||||
Statement nullCheck = generateNullCheck((FieldDeclaration) fieldNode.originalFieldNode.get(), sourceNode);
|
||||
Statement nullCheck = generateNullCheck((FieldDeclaration) fieldNode.originalFieldNode.get(), sourceNode, null);
|
||||
if (nullCheck != null) statements.add(nullCheck);
|
||||
}
|
||||
}
|
||||
@@ -1044,8 +1043,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
|
||||
return null;
|
||||
}
|
||||
|
||||
NullCollectionBehavior behavior = HandleBuilder.getNullBehaviorFor(ann, singularInstance, node);
|
||||
return new SingularData(child, singularName, pluralName, typeArgs == null ? Collections.<TypeReference>emptyList() : Arrays.asList(typeArgs), targetFqn, singularizer, source, behavior);
|
||||
return new SingularData(child, singularName, pluralName, typeArgs == null ? Collections.<TypeReference>emptyList() : Arrays.asList(typeArgs), targetFqn, singularizer, source, singularInstance.ignoreNullCollections());
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -278,7 +278,7 @@ public class HandleWith extends EclipseAnnotationHandler<With> {
|
||||
|
||||
List<Statement> statements = new ArrayList<Statement>(5);
|
||||
if (hasNonNullAnnotations(fieldNode)) {
|
||||
Statement nullCheck = generateNullCheck(field, sourceNode);
|
||||
Statement nullCheck = generateNullCheck(field, sourceNode, null);
|
||||
if (nullCheck != null) statements.add(nullCheck);
|
||||
}
|
||||
statements.add(returnStatement);
|
||||
|
||||
@@ -61,7 +61,6 @@ import lombok.Builder;
|
||||
import lombok.Builder.ObtainVia;
|
||||
import lombok.ConfigurationKeys;
|
||||
import lombok.Singular;
|
||||
import lombok.Singular.NullCollectionBehavior;
|
||||
import lombok.ToString;
|
||||
import lombok.core.AST.Kind;
|
||||
import lombok.core.AnnotationValues;
|
||||
@@ -908,22 +907,9 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
|
||||
return null;
|
||||
}
|
||||
|
||||
NullCollectionBehavior behavior = getNullBehaviorFor(ann, singularInstance, node);
|
||||
|
||||
return new SingularData(child, singularName, pluralName, typeArgs, targetFqn, singularizer, behavior, setterPrefix);
|
||||
return new SingularData(child, singularName, pluralName, typeArgs, targetFqn, singularizer, singularInstance.ignoreNullCollections(), setterPrefix);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static NullCollectionBehavior getNullBehaviorFor(AnnotationValues<Singular> ann, Singular singularInstance, JavacNode node) {
|
||||
NullCollectionBehavior behavior;
|
||||
if (ann.isExplicit("nullBehavior")) {
|
||||
behavior = singularInstance.nullBehavior();
|
||||
} else {
|
||||
behavior = node.getAst().readConfiguration(ConfigurationKeys.SINGULAR_NULL_COLLECTIONS);
|
||||
}
|
||||
if (behavior == null) return NullCollectionBehavior.NULL_POINTER_EXCEPTION;
|
||||
return behavior;
|
||||
}
|
||||
}
|
||||
@@ -248,7 +248,7 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> {
|
||||
if (!hasNonNullAnnotations(field) && !hasNonNullAnnotations(field, onParam)) {
|
||||
statements.append(treeMaker.Exec(assign));
|
||||
} else {
|
||||
JCStatement nullCheck = generateNullCheck(treeMaker, fieldDecl.vartype, paramName, source);
|
||||
JCStatement nullCheck = generateNullCheck(treeMaker, fieldDecl.vartype, paramName, source, null);
|
||||
if (nullCheck != null) statements.append(nullCheck);
|
||||
statements.append(treeMaker.Exec(assign));
|
||||
}
|
||||
|
||||
@@ -59,7 +59,6 @@ import com.sun.tools.javac.util.Name;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Builder;
|
||||
import lombok.Builder.ObtainVia;
|
||||
import lombok.Singular.NullCollectionBehavior;
|
||||
import lombok.ConfigurationKeys;
|
||||
import lombok.Singular;
|
||||
import lombok.ToString;
|
||||
@@ -976,8 +975,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
|
||||
return null;
|
||||
}
|
||||
|
||||
NullCollectionBehavior behavior = HandleBuilder.getNullBehaviorFor(ann, singularInstance, node);
|
||||
return new SingularData(child, singularName, pluralName, typeArgs, targetFqn, singularizer, behavior);
|
||||
return new SingularData(child, singularName, pluralName, typeArgs, targetFqn, singularizer, singularInstance.ignoreNullCollections());
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -1537,12 +1537,12 @@ public class JavacHandlerUtil {
|
||||
* Generates a new statement that checks if the given local is null, and if so, throws a configured exception with the
|
||||
* local variable name as message.
|
||||
*/
|
||||
public static JCStatement generateNullCheck(JavacTreeMaker maker, JCExpression typeNode, Name varName, JavacNode source) {
|
||||
public static JCStatement generateNullCheck(JavacTreeMaker maker, JCExpression typeNode, Name varName, JavacNode source, String customMessage) {
|
||||
NullCheckExceptionType exceptionType = source.getAst().readConfiguration(ConfigurationKeys.NON_NULL_EXCEPTION_TYPE);
|
||||
if (exceptionType == null) exceptionType = NullCheckExceptionType.NULL_POINTER_EXCEPTION;
|
||||
|
||||
if (isPrimitive(typeNode)) return null;
|
||||
JCLiteral message = maker.Literal(exceptionType.toExceptionMessage(varName.toString()));
|
||||
if (typeNode != null && isPrimitive(typeNode)) return null;
|
||||
JCLiteral message = maker.Literal(exceptionType.toExceptionMessage(varName.toString(), customMessage));
|
||||
|
||||
LombokImmutableList<String> method = exceptionType.getMethod();
|
||||
if (method != null) {
|
||||
@@ -1569,7 +1569,7 @@ public class JavacHandlerUtil {
|
||||
* stripped as a result of @Accessors.prefix.
|
||||
*/
|
||||
public static JCStatement generateNullCheck(JavacTreeMaker maker, JCVariableDecl varDecl, JavacNode source) {
|
||||
return generateNullCheck(maker, varDecl.vartype, varDecl.name, source);
|
||||
return generateNullCheck(maker, varDecl.vartype, varDecl.name, source, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,7 +37,6 @@ import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
|
||||
import com.sun.tools.javac.tree.JCTree.JCBlock;
|
||||
import com.sun.tools.javac.tree.JCTree.JCExpression;
|
||||
import com.sun.tools.javac.tree.JCTree.JCLiteral;
|
||||
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
|
||||
import com.sun.tools.javac.tree.JCTree.JCModifiers;
|
||||
import com.sun.tools.javac.tree.JCTree.JCStatement;
|
||||
@@ -51,7 +50,6 @@ import com.sun.tools.javac.util.Name;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.ConfigurationKeys;
|
||||
import lombok.Singular.NullCollectionBehavior;
|
||||
import lombok.core.LombokImmutableList;
|
||||
import lombok.core.SpiLoadUtil;
|
||||
import lombok.core.TypeLibrary;
|
||||
@@ -122,13 +120,13 @@ public class JavacSingularsRecipes {
|
||||
private final String targetFqn;
|
||||
private final JavacSingularizer singularizer;
|
||||
private final String setterPrefix;
|
||||
private final NullCollectionBehavior nullCollectionBehavior;
|
||||
private final boolean ignoreNullCollections;
|
||||
|
||||
public SingularData(JavacNode annotation, Name singularName, Name pluralName, List<JCExpression> typeArgs, String targetFqn, JavacSingularizer singularizer, NullCollectionBehavior nullCollectionBehavior) {
|
||||
this(annotation, singularName, pluralName, typeArgs, targetFqn, singularizer, nullCollectionBehavior, "");
|
||||
public SingularData(JavacNode annotation, Name singularName, Name pluralName, List<JCExpression> typeArgs, String targetFqn, JavacSingularizer singularizer, boolean ignoreNullCollections) {
|
||||
this(annotation, singularName, pluralName, typeArgs, targetFqn, singularizer, ignoreNullCollections, "");
|
||||
}
|
||||
|
||||
public SingularData(JavacNode annotation, Name singularName, Name pluralName, List<JCExpression> typeArgs, String targetFqn, JavacSingularizer singularizer, NullCollectionBehavior nullCollectionBehavior, String setterPrefix) {
|
||||
public SingularData(JavacNode annotation, Name singularName, Name pluralName, List<JCExpression> typeArgs, String targetFqn, JavacSingularizer singularizer, boolean ignoreNullCollections, String setterPrefix) {
|
||||
this.annotation = annotation;
|
||||
this.singularName = singularName;
|
||||
this.pluralName = pluralName;
|
||||
@@ -136,7 +134,7 @@ public class JavacSingularsRecipes {
|
||||
this.targetFqn = targetFqn;
|
||||
this.singularizer = singularizer;
|
||||
this.setterPrefix = setterPrefix;
|
||||
this.nullCollectionBehavior = nullCollectionBehavior;
|
||||
this.ignoreNullCollections = ignoreNullCollections;
|
||||
}
|
||||
|
||||
public JavacNode getAnnotation() {
|
||||
@@ -167,8 +165,8 @@ public class JavacSingularsRecipes {
|
||||
return singularizer;
|
||||
}
|
||||
|
||||
public NullCollectionBehavior getNullCollectionBehavior() {
|
||||
return nullCollectionBehavior;
|
||||
public boolean isIgnoreNullCollections() {
|
||||
return ignoreNullCollections;
|
||||
}
|
||||
|
||||
public String getTargetSimpleType() {
|
||||
@@ -273,17 +271,19 @@ public class JavacSingularsRecipes {
|
||||
generateClearMethod(cfv, deprecate, maker, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType, source, access);
|
||||
}
|
||||
|
||||
private void finishAndInjectMethod(CheckerFrameworkVersion cfv, JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, boolean deprecate, ListBuffer<JCStatement> statements, Name methodName, List<JCVariableDecl> jcVariableDecls, AccessLevel access, NullCollectionBehavior nullBehavior) {
|
||||
private void finishAndInjectMethod(CheckerFrameworkVersion cfv, JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, boolean deprecate, ListBuffer<JCStatement> statements, Name methodName, List<JCVariableDecl> jcVariableDecls, AccessLevel access, Boolean ignoreNullCollections) {
|
||||
if (returnStatement != null) statements.append(returnStatement);
|
||||
JCBlock body = maker.Block(0, statements.toList());
|
||||
JCModifiers mods = makeMods(maker, cfv, builderType, deprecate, access);
|
||||
List<JCTypeParameter> typeParams = List.nil();
|
||||
List<JCExpression> thrown = List.nil();
|
||||
|
||||
if (nullBehavior == NullCollectionBehavior.IGNORE) {
|
||||
for (JCVariableDecl d : jcVariableDecls) createRelevantNullableAnnotation(builderType, d);
|
||||
} else if (nullBehavior != null) {
|
||||
for (JCVariableDecl d : jcVariableDecls) createRelevantNonNullAnnotation(builderType, d);
|
||||
if (ignoreNullCollections != null) {
|
||||
if (ignoreNullCollections.booleanValue()) {
|
||||
for (JCVariableDecl d : jcVariableDecls) createRelevantNullableAnnotation(builderType, d);
|
||||
} else {
|
||||
for (JCVariableDecl d : jcVariableDecls) createRelevantNonNullAnnotation(builderType, d);
|
||||
}
|
||||
}
|
||||
|
||||
JCMethodDecl method = maker.MethodDef(mods, methodName, returnType, typeParams, jcVariableDecls, thrown, body, null);
|
||||
@@ -343,33 +343,21 @@ public class JavacSingularsRecipes {
|
||||
JCExpression paramType = getPluralMethodParamType(builderType);
|
||||
paramType = addTypeArgs(getTypeArgumentsCount(), true, builderType, paramType, data.getTypeArgs(), source);
|
||||
long paramFlags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, builderType.getContext());
|
||||
NullCollectionBehavior behavior = data.getNullCollectionBehavior();
|
||||
if (behavior == null) behavior = NullCollectionBehavior.IGNORE;
|
||||
boolean ignoreNullCollections = data.isIgnoreNullCollections();
|
||||
JCModifiers paramMods = maker.Modifiers(paramFlags);
|
||||
JCVariableDecl param = maker.VarDef(paramMods, data.getPluralName(), paramType, null);
|
||||
statements.prepend(createConstructBuilderVarIfNeeded(maker, data, builderType, source));
|
||||
|
||||
if (behavior == NullCollectionBehavior.IGNORE) {
|
||||
if (ignoreNullCollections) {
|
||||
JCExpression incomingIsNotNull = maker.Binary(CTC_NOT_EQUAL, maker.Ident(data.getPluralName()), maker.Literal(CTC_BOT, null));
|
||||
JCStatement onNotNull = maker.Block(0, statements.toList());
|
||||
statements = new ListBuffer<JCStatement>();
|
||||
statements.add(maker.If(incomingIsNotNull, onNotNull, null));
|
||||
} else {
|
||||
JCLiteral message = maker.Literal(behavior.toExceptionMessage(data.getPluralName().toString()));
|
||||
if (behavior.getExceptionType() != null) {
|
||||
JCExpression incomingIsNull = maker.Binary(CTC_EQUAL, maker.Ident(data.getPluralName()), maker.Literal(CTC_BOT, null));
|
||||
JCExpression exType = genTypeRef(builderType, behavior.getExceptionType());
|
||||
JCExpression exception = maker.NewClass(null, List.<JCExpression>nil(), exType, List.<JCExpression>of(message), null);
|
||||
JCStatement onNull = maker.Throw(exception);
|
||||
statements.prepend(maker.If(incomingIsNull, onNull, null));
|
||||
} else {
|
||||
LombokImmutableList<String> method = behavior.getMethod();
|
||||
JCExpression invoke = maker.Apply(List.<JCExpression>nil(), chainDots(builderType, method), List.of(maker.Ident(data.getPluralName()), message));
|
||||
statements.prepend(maker.Exec(invoke));
|
||||
}
|
||||
statements.prepend(JavacHandlerUtil.generateNullCheck(maker, null, data.getPluralName(), builderType, "%s cannot be null"));
|
||||
}
|
||||
|
||||
finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, name, List.of(param), access, behavior);
|
||||
finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, name, List.of(param), access, ignoreNullCollections);
|
||||
}
|
||||
|
||||
protected ListBuffer<JCStatement> generatePluralMethodStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, JCTree source) {
|
||||
|
||||
Reference in new issue
Block a user