aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--buildScripts/website.ant.xml3
-rw-r--r--doc/changelog.markdown1
-rw-r--r--src/core/lombok/NonNull.java16
-rw-r--r--src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java7
-rw-r--r--src/core/lombok/eclipse/handlers/NonNullHandler.java147
-rw-r--r--src/core/lombok/javac/handlers/HandleSneakyThrows.java12
-rw-r--r--src/core/lombok/javac/handlers/JavacHandlerUtil.java23
-rw-r--r--src/core/lombok/javac/handlers/NonNullHandler.java148
-rw-r--r--src/utils/lombok/javac/Javac.java32
-rw-r--r--test/transform/resource/after-delombok/DataOnLocalClass.java8
-rw-r--r--test/transform/resource/after-delombok/NonNullOnParameter.java48
-rw-r--r--test/transform/resource/after-delombok/NonNullPlain.java8
-rw-r--r--test/transform/resource/after-delombok/SetterOnClass.java4
-rw-r--r--test/transform/resource/after-delombok/WitherOnClass.java4
-rw-r--r--test/transform/resource/after-ecj/DataOnLocalClass.java8
-rw-r--r--test/transform/resource/after-ecj/NonNullOnParameter.java61
-rw-r--r--test/transform/resource/after-ecj/NonNullPlain.java8
-rw-r--r--test/transform/resource/after-ecj/SetterOnClass.java4
-rw-r--r--test/transform/resource/after-ecj/WitherOnClass.java4
-rw-r--r--test/transform/resource/before/NonNullOnParameter.java30
-rw-r--r--test/transform/resource/messages-delombok/NonNullOnParameter.java.messages1
-rw-r--r--test/transform/resource/messages-delombok/NonNullPlain.java.messages1
-rw-r--r--test/transform/resource/messages-ecj/NonNullOnParameter.java.messages3
-rw-r--r--test/transform/resource/messages-ecj/NonNullPlain.java.messages1
-rw-r--r--test/transform/resource/messages-idempotent/NonNullOnParameter.java.messages1
-rw-r--r--test/transform/resource/messages-idempotent/NonNullPlain.java.messages3
-rw-r--r--usage_examples/NonNullExample_post.jpage13
-rw-r--r--usage_examples/NonNullExample_pre.jpage10
-rw-r--r--website/features/Cleanup.html2
-rw-r--r--website/features/Data.html2
-rw-r--r--website/features/Delegate.html11
-rw-r--r--website/features/GetterLazy.html2
-rw-r--r--website/features/GetterSetter.html2
-rw-r--r--website/features/Log.html2
-rw-r--r--website/features/NonNull.html73
-rw-r--r--website/features/SneakyThrows.html4
-rw-r--r--website/features/Synchronized.html2
-rw-r--r--website/features/ToString.html2
-rw-r--r--website/features/index.html18
-rw-r--r--website/features/val.html2
40 files changed, 674 insertions, 57 deletions
diff --git a/buildScripts/website.ant.xml b/buildScripts/website.ant.xml
index 405b388f..41130bd2 100644
--- a/buildScripts/website.ant.xml
+++ b/buildScripts/website.ant.xml
@@ -146,6 +146,9 @@ such as converting the changelog into HTML, and creating javadoc.
<param name="transformationName" value="Delegate" />
</antcall>
<antcall target="-integrateSnippet">
+ <param name="transformationName" value="NonNull" />
+ </antcall>
+ <antcall target="-integrateSnippet">
<param name="transformationName" value="experimental/Accessors" />
</antcall>
<antcall target="-integrateSnippet">
diff --git a/doc/changelog.markdown b/doc/changelog.markdown
index e2e3d6b5..aaf66030 100644
--- a/doc/changelog.markdown
+++ b/doc/changelog.markdown
@@ -2,6 +2,7 @@ Lombok Changelog
----------------
### v0.11.9 (Edgy Guinea Pig)
+* FEATURE: `@NonNull` on a method or constructor parameter now generates a null-check statement at the start of your method. This nullcheck will throw a `NullPointerException` with the name of the parameter as the message. [Issue #514](https://code.google.com/p/projectlombok/issues/detail?id=514)
* BUGFIX: Usage of `Lombok.sneakyThrow()` or `@SneakyThrows` would sometimes result in invalid classes (classes which fail with `VerifyError`). [Issue #470](https://code.google.com/p/projectlombok/issues/detail?id=470)
* BUGFIX: Using `val` in try-with-resources did not work for javac. [Issue #520](https://code.google.com/p/projectlombok/issues/detail?id=520)
* BUGFIX: When using `@Data`, warnings are not generated if certain aspects are not generated because you wrote explicit versions of them. However, this gets confusing with `equals` / `hashCode` / `canEqual`, as nothing is generated if any one of those methods is present. Now, if one of `equals` or `hashCode` is present but not the other one (or `canEqual` is present but `equals` and/or `hashCode` is missing), a warning is emitted to explain that lombok will not generate any of the equals / hashCode methods, and that you should either write them all yourself or remove them all. [Issue #513](https://code.google.com/p/projectlombok/issues/detail?id=513)
diff --git a/src/core/lombok/NonNull.java b/src/core/lombok/NonNull.java
index 5f5d8ed2..96813170 100644
--- a/src/core/lombok/NonNull.java
+++ b/src/core/lombok/NonNull.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Project Lombok Authors.
+ * Copyright (C) 2009-2013 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
@@ -28,12 +28,14 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
- * Lombok is smart enough to translate any annotation named {@code @NonNull} in any casing and
- * with any package name to the return type of generated getters and the parameter of generated setters and constructors,
- * as well as generate the appropriate null checks in the setter and constructor.
- *
- * You can use this annotation for the purpose, though you can also use JSR305's annotation, findbugs's, pmd's, or IDEA's, or just
- * about anyone elses. As long as it is named {@code @NonNull}.
+ * If put on a parameter, lombok will insert a null-check at the start of the method / constructor's body, throwing a
+ * {@code NullPointerException} with the parameter's name as message. If put on a field, any generated method assigning
+ * a value to this field will also produce these nullchecks.
+ * <p>
+ * Note that any annotation named {@code NonNull} with any casing and any package will result in nullchecks produced for
+ * generated methods (and the annotation will be copied to the getter return type and any parameters of generated methods),
+ * but <em>only</em> this annotation, if present on a parameter, will result in a null check inserted into your otherwise
+ * handwritten method.
*
* WARNING: If the java community ever does decide on supporting a single {@code @NonNull} annotation (for example via JSR305), then
* this annotation will <strong>be deleted</strong> from the lombok package. If the need to update an import statement scares
diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
index 7703336f..dc99dabf 100644
--- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
+++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
@@ -61,6 +61,7 @@ import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer;
import org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.Block;
import org.eclipse.jdt.internal.compiler.ast.CastExpression;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
@@ -1334,7 +1335,11 @@ public class EclipseHandlerUtil {
EqualExpression equalExpression = new EqualExpression(varName, nullLiteral, OperatorIds.EQUAL_EQUAL);
equalExpression.sourceStart = pS; equalExpression.statementEnd = equalExpression.sourceEnd = pE;
setGeneratedBy(equalExpression, source);
- IfStatement ifStatement = new IfStatement(equalExpression, throwStatement, 0, 0);
+ Block throwBlock = new Block(0);
+ throwBlock.statements = new Statement[] {throwStatement};
+ throwBlock.sourceStart = pS; throwBlock.sourceEnd = pE;
+ setGeneratedBy(throwBlock, source);
+ IfStatement ifStatement = new IfStatement(equalExpression, throwBlock, 0, 0);
setGeneratedBy(ifStatement, source);
return ifStatement;
}
diff --git a/src/core/lombok/eclipse/handlers/NonNullHandler.java b/src/core/lombok/eclipse/handlers/NonNullHandler.java
new file mode 100644
index 00000000..5c58069c
--- /dev/null
+++ b/src/core/lombok/eclipse/handlers/NonNullHandler.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2013 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.eclipse.handlers;
+
+import java.util.Arrays;
+
+import org.eclipse.jdt.internal.compiler.ast.ASTNode;
+import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.Annotation;
+import org.eclipse.jdt.internal.compiler.ast.Argument;
+import org.eclipse.jdt.internal.compiler.ast.Block;
+import org.eclipse.jdt.internal.compiler.ast.EqualExpression;
+import org.eclipse.jdt.internal.compiler.ast.Expression;
+import org.eclipse.jdt.internal.compiler.ast.IfStatement;
+import org.eclipse.jdt.internal.compiler.ast.NullLiteral;
+import org.eclipse.jdt.internal.compiler.ast.OperatorIds;
+import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
+import org.eclipse.jdt.internal.compiler.ast.Statement;
+import org.eclipse.jdt.internal.compiler.ast.ThrowStatement;
+import org.mangosdk.spi.ProviderFor;
+
+import lombok.NonNull;
+import lombok.core.AST.Kind;
+import lombok.core.AnnotationValues;
+import lombok.eclipse.DeferUntilPostDiet;
+import lombok.eclipse.EclipseAnnotationHandler;
+import lombok.eclipse.EclipseNode;
+
+import static lombok.eclipse.Eclipse.*;
+import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
+
+@DeferUntilPostDiet
+@ProviderFor(EclipseAnnotationHandler.class)
+public class NonNullHandler extends EclipseAnnotationHandler<NonNull> {
+ @Override public void handle(AnnotationValues<NonNull> annotation, Annotation ast, EclipseNode annotationNode) {
+ if (annotationNode.up().getKind() == Kind.FIELD) {
+ // This is meaningless unless the field is used to generate a method (@Setter, @RequiredArgsConstructor, etc),
+ // but in that case those handlers will take care of it. However, we DO check if the annotation is applied to
+ // a primitive, because those handlers trigger on any annotation named @NonNull and we only want the warning
+ // behaviour on _OUR_ 'lombok.NonNull'.
+
+ try {
+ if (isPrimitive(((AbstractVariableDeclaration) annotationNode.up().get()).type)) {
+ annotationNode.addWarning("@NonNull is meaningless on a primitive.");
+ }
+ } catch (Exception ignore) {}
+
+ return;
+ }
+
+ if (annotationNode.up().getKind() != Kind.ARGUMENT) return;
+
+ Argument arg;
+ AbstractMethodDeclaration declaration;
+
+ try {
+ arg = (Argument) annotationNode.up().get();
+ declaration = (AbstractMethodDeclaration) annotationNode.up().up().get();
+ } catch (Exception e) {
+ return;
+ }
+
+ if (isGenerated(declaration)) return;
+
+ // Possibly, if 'declaration instanceof ConstructorDeclaration', fetch declaration.constructorCall, search it for any references to our parameter,
+ // 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(arg, ast);
+
+ if (nullCheck == null) {
+ // @NonNull applied to a primitive. Kinda pointless. Let's generate a warning.
+ annotationNode.addWarning("@NonNull is meaningless on a primitive.");
+ return;
+ }
+
+ if (declaration.statements == null) {
+ declaration.statements = new Statement[] {nullCheck};
+ } else {
+ char[] expectedName = arg.name;
+ for (Statement stat : declaration.statements) {
+ char[] varNameOfNullCheck = returnVarNameIfNullCheck(stat);
+ if (varNameOfNullCheck == null) break;
+ if (Arrays.equals(expectedName, varNameOfNullCheck)) return;
+ }
+
+ Statement[] newStatements = new Statement[declaration.statements.length + 1];
+ int skipOver = 0;
+ for (Statement stat : declaration.statements) {
+ if (isGenerated(stat)) skipOver++;
+ else break;
+ }
+ System.arraycopy(declaration.statements, 0, newStatements, 0, skipOver);
+ System.arraycopy(declaration.statements, skipOver, newStatements, skipOver + 1, declaration.statements.length - skipOver);
+ newStatements[skipOver] = nullCheck;
+ declaration.statements = newStatements;
+ }
+ annotationNode.up().up().rebuild();
+ }
+
+ private char[] returnVarNameIfNullCheck(Statement stat) {
+ if (!(stat instanceof IfStatement)) return null;
+
+ /* Check that the if's statement is a throw statement, possibly in a block. */ {
+ Statement then = ((IfStatement) stat).thenStatement;
+ if (then instanceof Block) {
+ Statement[] blockStatements = ((Block) then).statements;
+ if (blockStatements == null || blockStatements.length == 0) return null;
+ then = blockStatements[0];
+ }
+
+ if (!(then instanceof ThrowStatement)) return null;
+ }
+
+ /* Check that the if's conditional is like 'x == null'. Return from this method (don't generate
+ a nullcheck) if 'x' is equal to our own variable's name: There's already a nullcheck here. */ {
+ Expression cond = ((IfStatement) stat).condition;
+ if (!(cond instanceof EqualExpression)) return null;
+ EqualExpression bin = (EqualExpression) cond;
+ int operatorId = ((bin.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT);
+ if (operatorId != OperatorIds.EQUAL_EQUAL) return null;
+ if (!(bin.left instanceof SingleNameReference)) return null;
+ if (!(bin.right instanceof NullLiteral)) return null;
+ return ((SingleNameReference) bin.left).token;
+ }
+ }
+}
diff --git a/src/core/lombok/javac/handlers/HandleSneakyThrows.java b/src/core/lombok/javac/handlers/HandleSneakyThrows.java
index c2394fc8..c818f630 100644
--- a/src/core/lombok/javac/handlers/HandleSneakyThrows.java
+++ b/src/core/lombok/javac/handlers/HandleSneakyThrows.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2011 The Project Lombok Authors.
+ * Copyright (C) 2009-2013 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
@@ -36,8 +36,6 @@ import org.mangosdk.spi.ProviderFor;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.tree.JCTree;
-import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
-import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
import com.sun.tools.javac.tree.JCTree.JCBlock;
@@ -114,14 +112,6 @@ public class HandleSneakyThrows extends JavacAnnotationHandler<SneakyThrows> {
}
}
- private boolean isConstructorCall(final JCStatement supect) {
- if (!(supect instanceof JCExpressionStatement)) return false;
- final JCExpression supectExpression = ((JCExpressionStatement) supect).expr;
- if (!(supectExpression instanceof JCMethodInvocation)) return false;
- final String methodName = ((JCMethodInvocation) supectExpression).meth.toString();
- return "super".equals(methodName) || "this".equals(methodName);
- }
-
private JCStatement buildTryCatchBlock(JavacNode node, List<JCStatement> contents, String exception, JCTree source) {
TreeMaker maker = node.getTreeMaker();
diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
index ef1a9f50..7cbaa5ac 100644
--- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java
+++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
@@ -50,9 +50,11 @@ import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree;
import com.sun.tools.javac.tree.JCTree.JCAssign;
+import com.sun.tools.javac.tree.JCTree.JCBlock;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
import com.sun.tools.javac.tree.JCTree.JCIdent;
import com.sun.tools.javac.tree.JCTree.JCImport;
@@ -121,6 +123,7 @@ public class JavacHandlerUtil {
}
public static <T extends JCTree> T recursiveSetGeneratedBy(T node, JCTree source) {
+ if (node == null) return null;
setGeneratedBy(node, source);
node.accept(new MarkingScanner(source));
@@ -543,6 +546,23 @@ public class JavacHandlerUtil {
return MemberExistsResult.NOT_EXISTS;
}
+ public static boolean isConstructorCall(final JCStatement statement) {
+ if (!(statement instanceof JCExpressionStatement)) return false;
+ JCExpression expr = ((JCExpressionStatement) statement).expr;
+ if (!(expr instanceof JCMethodInvocation)) return false;
+ JCExpression invocation = ((JCMethodInvocation) expr).meth;
+ String name;
+ if (invocation instanceof JCFieldAccess) {
+ name = ((JCFieldAccess) invocation).name.toString();
+ } else if (invocation instanceof JCIdent) {
+ name = ((JCIdent) invocation).name.toString();
+ } else {
+ name = "";
+ }
+
+ return "super".equals(name) || "this".equals(name);
+ }
+
/**
* Turns an {@code AccessLevel} instance into the flag bit used by javac.
*/
@@ -890,7 +910,8 @@ public class JavacHandlerUtil {
JCExpression npe = chainDots(variable, "java", "lang", "NullPointerException");
JCTree exception = treeMaker.NewClass(null, List.<JCExpression>nil(), npe, List.<JCExpression>of(treeMaker.Literal(fieldName.toString())), null);
JCStatement throwStatement = treeMaker.Throw(exception);
- return treeMaker.If(treeMaker.Binary(CTC_EQUAL, treeMaker.Ident(fieldName), treeMaker.Literal(CTC_BOT, null)), throwStatement, null);
+ JCBlock throwBlock = treeMaker.Block(0, List.of(throwStatement));
+ return treeMaker.If(treeMaker.Binary(CTC_EQUAL, treeMaker.Ident(fieldName), treeMaker.Literal(CTC_BOT, null)), throwBlock, null);
}
/**
diff --git a/src/core/lombok/javac/handlers/NonNullHandler.java b/src/core/lombok/javac/handlers/NonNullHandler.java
new file mode 100644
index 00000000..415d6032
--- /dev/null
+++ b/src/core/lombok/javac/handlers/NonNullHandler.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2013 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.javac.handlers;
+
+import static lombok.javac.Javac.*;
+import static lombok.javac.handlers.JavacHandlerUtil.*;
+
+import org.mangosdk.spi.ProviderFor;
+
+import com.sun.tools.javac.tree.JCTree.JCAnnotation;
+import com.sun.tools.javac.tree.JCTree.JCBinary;
+import com.sun.tools.javac.tree.JCTree.JCBlock;
+import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCIdent;
+import com.sun.tools.javac.tree.JCTree.JCIf;
+import com.sun.tools.javac.tree.JCTree.JCLiteral;
+import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
+import com.sun.tools.javac.tree.JCTree.JCParens;
+import com.sun.tools.javac.tree.JCTree.JCStatement;
+import com.sun.tools.javac.tree.JCTree.JCThrow;
+import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
+import com.sun.tools.javac.util.List;
+
+import lombok.NonNull;
+import lombok.core.AnnotationValues;
+import lombok.core.AST.Kind;
+import lombok.javac.JavacAnnotationHandler;
+import lombok.javac.JavacNode;
+
+@ProviderFor(JavacAnnotationHandler.class)
+public class NonNullHandler extends JavacAnnotationHandler<NonNull> {
+ @Override public void handle(AnnotationValues<NonNull> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ if (annotationNode.up().getKind() == Kind.FIELD) {
+ // This is meaningless unless the field is used to generate a method (@Setter, @RequiredArgsConstructor, etc),
+ // but in that case those handlers will take care of it. However, we DO check if the annotation is applied to
+ // a primitive, because those handlers trigger on any annotation named @NonNull and we only want the warning
+ // behaviour on _OUR_ 'lombok.NonNull'.
+
+ try {
+ if (isPrimitive(((JCVariableDecl) annotationNode.up().get()).vartype)) {
+ annotationNode.addWarning("@NonNull is meaningless on a primitive.");
+ }
+ } catch (Exception ignore) {}
+
+ return;
+ }
+
+ if (annotationNode.up().getKind() != Kind.ARGUMENT) return;
+
+ JCMethodDecl declaration;
+
+ try {
+ declaration = (JCMethodDecl) annotationNode.up().up().get();
+ } catch (Exception e) {
+ return;
+ }
+
+ if (JavacHandlerUtil.isGenerated(declaration)) return;
+
+ // Possibly, if 'declaration instanceof ConstructorDeclaration', fetch declaration.constructorCall, search it for any references to our parameter,
+ // 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.
+
+ JCStatement nullCheck = recursiveSetGeneratedBy(generateNullCheck(annotationNode.getTreeMaker(), annotationNode.up()), ast);
+
+ if (nullCheck == null) {
+ // @NonNull applied to a primitive. Kinda pointless. Let's generate a warning.
+ annotationNode.addWarning("@NonNull is meaningless on a primitive.");
+ return;
+ }
+
+ List<JCStatement> statements = declaration.body.stats;
+
+ String expectedName = annotationNode.up().getName();
+ for (JCStatement stat : statements) {
+ if (JavacHandlerUtil.isConstructorCall(stat)) continue;
+ String varNameOfNullCheck = returnVarNameIfNullCheck(stat);
+ if (varNameOfNullCheck == null) break;
+ if (varNameOfNullCheck.equals(expectedName)) return;
+ }
+
+ List<JCStatement> tail = statements;
+ List<JCStatement> head = List.nil();
+ for (JCStatement stat : statements) {
+ if (JavacHandlerUtil.isConstructorCall(stat) || JavacHandlerUtil.isGenerated(stat)) {
+ tail = tail.tail;
+ head = head.prepend(stat);
+ continue;
+ }
+ break;
+ }
+
+ List<JCStatement> newList = tail.prepend(nullCheck);
+ for (JCStatement stat : head) newList = newList.prepend(stat);
+ declaration.body.stats = newList;
+ }
+
+ /**
+ * Checks if the statement is of the form 'if (x == null) {throw WHATEVER;},
+ * where the block braces are optional. If it is of this form, returns "x".
+ * If it is not of this form, returns null.
+ */
+ private String returnVarNameIfNullCheck(JCStatement stat) {
+ if (!(stat instanceof JCIf)) return null;
+
+ /* Check that the if's statement is a throw statement, possibly in a block. */ {
+ JCStatement then = ((JCIf) stat).thenpart;
+ if (then instanceof JCBlock) {
+ List<JCStatement> stats = ((JCBlock) then).stats;
+ if (stats.length() == 0) return null;
+ then = stats.get(0);
+ }
+ if (!(then instanceof JCThrow)) return null;
+ }
+
+ /* Check that the if's conditional is like 'x == null'. Return from this method (don't generate
+ a nullcheck) if 'x' is equal to our own variable's name: There's already a nullcheck here. */ {
+ JCExpression cond = ((JCIf) stat).cond;
+ while (cond instanceof JCParens) cond = ((JCParens) cond).expr;
+ if (!(cond instanceof JCBinary)) return null;
+ JCBinary bin = (JCBinary) cond;
+ if (getTag(bin) != CTC_EQUAL) return null;
+ if (!(bin.lhs instanceof JCIdent)) return null;
+ if (!(bin.rhs instanceof JCLiteral)) return null;
+ if (((JCLiteral) bin.rhs).typetag != CTC_BOT) return null;
+ return ((JCIdent) bin.lhs).name.toString();
+ }
+ }
+}
diff --git a/src/utils/lombok/javac/Javac.java b/src/utils/lombok/javac/Javac.java
index b4e58b8f..08c7c957 100644
--- a/src/utils/lombok/javac/Javac.java
+++ b/src/utils/lombok/javac/Javac.java
@@ -21,6 +21,8 @@
*/
package lombok.javac;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -129,4 +131,34 @@ public class Javac {
throw new RuntimeException(e);
}
}
+
+ private static final Field JCTREE_TAG;
+ private static final Method JCTREE_GETTAG;
+ static {
+ Field f = null;
+ try {
+ f = JCTree.class.getDeclaredField("tag");
+ } catch (NoSuchFieldException e) {}
+ JCTREE_TAG = f;
+
+ Method m = null;
+ try {
+ m = JCTree.class.getDeclaredMethod("getTag");
+ } catch (NoSuchMethodException e) {}
+ JCTREE_GETTAG = m;
+ }
+
+ public static int getTag(JCTree node) {
+ if (JCTREE_GETTAG != null) {
+ try {
+ return (Integer) JCTREE_GETTAG.invoke(node);
+ } catch (Exception e) {}
+ }
+ try {
+ return (Integer) JCTREE_TAG.get(node);
+ } catch (Exception e) {
+ throw new IllegalStateException("Can't get node tag");
+ }
+ }
+
}
diff --git a/test/transform/resource/after-delombok/DataOnLocalClass.java b/test/transform/resource/after-delombok/DataOnLocalClass.java
index ed4d30ca..abe2757b 100644
--- a/test/transform/resource/after-delombok/DataOnLocalClass.java
+++ b/test/transform/resource/after-delombok/DataOnLocalClass.java
@@ -63,7 +63,9 @@ class DataOnLocalClass2 {
String name;
@java.lang.SuppressWarnings("all")
public InnerLocal(@lombok.NonNull final String name) {
- if (name == null) throw new java.lang.NullPointerException("name");
+ if (name == null) {
+ throw new java.lang.NullPointerException("name");
+ }
this.name = name;
}
@lombok.NonNull
@@ -73,7 +75,9 @@ class DataOnLocalClass2 {
}
@java.lang.SuppressWarnings("all")
public void setName(@lombok.NonNull final String name) {
- if (name == null) throw new java.lang.NullPointerException("name");
+ if (name == null) {
+ throw new java.lang.NullPointerException("name");
+ }
this.name = name;
}
@java.lang.Override
diff --git a/test/transform/resource/after-delombok/NonNullOnParameter.java b/test/transform/resource/after-delombok/NonNullOnParameter.java
new file mode 100644
index 00000000..a27d19c9
--- /dev/null
+++ b/test/transform/resource/after-delombok/NonNullOnParameter.java
@@ -0,0 +1,48 @@
+class NonNullOnParameter extends Thread {
+ NonNullOnParameter(@lombok.NonNull String arg) {
+ this(arg, "");
+ if (arg == null) {
+ throw new java.lang.NullPointerException("arg");
+ }
+ }
+ NonNullOnParameter(@lombok.NonNull String arg, @lombok.NonNull String arg2) {
+ super(arg);
+ if (arg2 == null) {
+ throw new java.lang.NullPointerException("arg2");
+ }
+ if (arg == null) throw new NullPointerException();
+ }
+ public void test2(@lombok.NonNull String arg, @lombok.NonNull String arg2, @lombok.NonNull String arg3) {
+ if (arg == null) {
+ throw new java.lang.NullPointerException("arg");
+ }
+ if (arg3 == null) {
+ throw new java.lang.NullPointerException("arg3");
+ }
+ if (arg2 == null) {
+ throw new NullPointerException("arg2");
+ }
+ if (arg == null) System.out.println("Hello");
+ }
+ public void test3(@lombok.NonNull String arg) {
+ if (arg == null) {
+ throw new java.lang.NullPointerException("arg");
+ }
+ if (arg != null) throw new IllegalStateException();
+ }
+ public void test(@lombok.NonNull String stringArg, @lombok.NonNull String arg2, @lombok.NonNull int primitiveArg) {
+ if (stringArg == null) {
+ throw new java.lang.NullPointerException("stringArg");
+ }
+ if (arg2 == null) {
+ throw new java.lang.NullPointerException("arg2");
+ }
+ }
+ public void test(@lombok.NonNull String arg) {
+ if (arg == null) {
+ throw new java.lang.NullPointerException("arg");
+ }
+ System.out.println("Hey");
+ if (arg == null) throw new NullPointerException();
+ }
+}
diff --git a/test/transform/resource/after-delombok/NonNullPlain.java b/test/transform/resource/after-delombok/NonNullPlain.java
index 064e00b9..6b85cbf7 100644
--- a/test/transform/resource/after-delombok/NonNullPlain.java
+++ b/test/transform/resource/after-delombok/NonNullPlain.java
@@ -16,7 +16,9 @@ class NonNullPlain {
@java.beans.ConstructorProperties({"i", "s"})
@java.lang.SuppressWarnings("all")
public NonNullPlain(@lombok.NonNull final int i, @lombok.NonNull final String s) {
- if (s == null) throw new java.lang.NullPointerException("s");
+ if (s == null) {
+ throw new java.lang.NullPointerException("s");
+ }
this.i = i;
this.s = s;
}
@@ -45,7 +47,9 @@ class NonNullPlain {
@java.lang.SuppressWarnings("all")
public void setS(@lombok.NonNull final String s) {
- if (s == null) throw new java.lang.NullPointerException("s");
+ if (s == null) {
+ throw new java.lang.NullPointerException("s");
+ }
this.s = s;
}
diff --git a/test/transform/resource/after-delombok/SetterOnClass.java b/test/transform/resource/after-delombok/SetterOnClass.java
index 151bc179..7077c492 100644
--- a/test/transform/resource/after-delombok/SetterOnClass.java
+++ b/test/transform/resource/after-delombok/SetterOnClass.java
@@ -53,7 +53,9 @@ class SetterOnClass6 {
}
@java.lang.SuppressWarnings("all")
public void setNonNull(@lombok.NonNull final String nonNull) {
- if (nonNull == null) throw new java.lang.NullPointerException("nonNull");
+ if (nonNull == null) {
+ throw new java.lang.NullPointerException("nonNull");
+ }
this.nonNull = nonNull;
}
} \ No newline at end of file
diff --git a/test/transform/resource/after-delombok/WitherOnClass.java b/test/transform/resource/after-delombok/WitherOnClass.java
index 783fede1..45d0c4b5 100644
--- a/test/transform/resource/after-delombok/WitherOnClass.java
+++ b/test/transform/resource/after-delombok/WitherOnClass.java
@@ -35,7 +35,9 @@ class WitherOnClass3 {
}
@java.lang.SuppressWarnings("all")
public WitherOnClass3 withNonNull(@lombok.NonNull final String nonNull) {
- if (nonNull == null) throw new java.lang.NullPointerException("nonNull");
+ if (nonNull == null) {
+ throw new java.lang.NullPointerException("nonNull");
+ }
return this.nonNull == nonNull ? this : new WitherOnClass3(this.couldBeNull, nonNull);
}
}
diff --git a/test/transform/resource/after-ecj/DataOnLocalClass.java b/test/transform/resource/after-ecj/DataOnLocalClass.java
index 137edf50..2f8dcca1 100644
--- a/test/transform/resource/after-ecj/DataOnLocalClass.java
+++ b/test/transform/resource/after-ecj/DataOnLocalClass.java
@@ -63,7 +63,9 @@ class DataOnLocalClass2 {
}
public @java.lang.SuppressWarnings("all") void setName(final @lombok.NonNull String name) {
if ((name == null))
- throw new java.lang.NullPointerException("name");
+ {
+ throw new java.lang.NullPointerException("name");
+ }
this.name = name;
}
public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) {
@@ -96,7 +98,9 @@ class DataOnLocalClass2 {
public @java.lang.SuppressWarnings("all") InnerLocal(final @lombok.NonNull String name) {
super();
if ((name == null))
- throw new java.lang.NullPointerException("name");
+ {
+ throw new java.lang.NullPointerException("name");
+ }
this.name = name;
}
}
diff --git a/test/transform/resource/after-ecj/NonNullOnParameter.java b/test/transform/resource/after-ecj/NonNullOnParameter.java
new file mode 100644
index 00000000..bbceb153
--- /dev/null
+++ b/test/transform/resource/after-ecj/NonNullOnParameter.java
@@ -0,0 +1,61 @@
+class NonNullOnParameter extends Thread {
+ NonNullOnParameter(@lombok.NonNull String arg) {
+ this(arg, "");
+ if ((arg == null))
+ {
+ throw new java.lang.NullPointerException("arg");
+ }
+ }
+ NonNullOnParameter(@lombok.NonNull String arg, @lombok.NonNull String arg2) {
+ super(arg);
+ if ((arg2 == null))
+ {
+ throw new java.lang.NullPointerException("arg2");
+ }
+ if ((arg == null))
+ throw new NullPointerException();
+ }
+ public void test2(@lombok.NonNull String arg, @lombok.NonNull String arg2, @lombok.NonNull String arg3) {
+ if ((arg == null))
+ {
+ throw new java.lang.NullPointerException("arg");
+ }
+ if ((arg3 == null))
+ {
+ throw new java.lang.NullPointerException("arg3");
+ }
+ if ((arg2 == null))
+ {
+ throw new NullPointerException("arg2");
+ }
+ if ((arg == null))
+ System.out.println("Hello");
+ }
+ public void test3(@lombok.NonNull String arg) {
+ if ((arg == null))
+ {
+ throw new java.lang.NullPointerException("arg");
+ }
+ if ((arg != null))
+ throw new IllegalStateException();
+ }
+ public void test(@lombok.NonNull String stringArg, @lombok.NonNull String arg2, @lombok.NonNull int primitiveArg) {
+ if ((stringArg == null))
+ {
+ throw new java.lang.NullPointerException("stringArg");
+ }
+ if ((arg2 == null))
+ {
+ throw new java.lang.NullPointerException("arg2");
+ }
+ }
+ public void test(@lombok.NonNull String arg) {
+ if ((arg == null))
+ {
+ throw new java.lang.NullPointerException("arg");
+ }
+ System.out.println("Hey");
+ if ((arg == null))
+ throw new NullPointerException();
+ }
+} \ No newline at end of file
diff --git a/test/transform/resource/after-ecj/NonNullPlain.java b/test/transform/resource/after-ecj/NonNullPlain.java
index c9c96d0a..6e937f6a 100644
--- a/test/transform/resource/after-ecj/NonNullPlain.java
+++ b/test/transform/resource/after-ecj/NonNullPlain.java
@@ -8,7 +8,9 @@ import java.lang.annotation.*;
public @java.beans.ConstructorProperties({"i", "s"}) @java.lang.SuppressWarnings("all") NonNullPlain(final @lombok.NonNull int i, final @lombok.NonNull String s) {
super();
if ((s == null))
- throw new java.lang.NullPointerException("s");
+ {
+ throw new java.lang.NullPointerException("s");
+ }
this.i = i;
this.s = s;
}
@@ -26,7 +28,9 @@ import java.lang.annotation.*;
}
public @java.lang.SuppressWarnings("all") void setS(final @lombok.NonNull String s) {
if ((s == null))
- throw new java.lang.NullPointerException("s");
+ {
+ throw new java.lang.NullPointerException("s");
+ }
this.s = s;
}
public @java.lang.SuppressWarnings("all") void setO(final Object o) {
diff --git a/test/transform/resource/after-ecj/SetterOnClass.java b/test/transform/resource/after-ecj/SetterOnClass.java
index da928f24..aa3459bb 100644
--- a/test/transform/resource/after-ecj/SetterOnClass.java
+++ b/test/transform/resource/after-ecj/SetterOnClass.java
@@ -63,7 +63,9 @@
}
public @java.lang.SuppressWarnings("all") void setNonNull(final @lombok.NonNull String nonNull) {
if ((nonNull == null))
- throw new java.lang.NullPointerException("nonNull");
+ {
+ throw new java.lang.NullPointerException("nonNull");
+ }
this.nonNull = nonNull;
}
}
diff --git a/test/transform/resource/after-ecj/WitherOnClass.java b/test/transform/resource/after-ecj/WitherOnClass.java
index ff4566e5..82132e87 100644
--- a/test/transform/resource/after-ecj/WitherOnClass.java
+++ b/test/transform/resource/after-ecj/WitherOnClass.java
@@ -33,7 +33,9 @@
}
public @java.lang.SuppressWarnings("all") WitherOnClass3 withNonNull(final @lombok.NonNull String nonNull) {
if ((nonNull == null))
- throw new java.lang.NullPointerException("nonNull");
+ {
+ throw new java.lang.NullPointerException("nonNull");
+ }
return ((this.nonNull == nonNull) ? this : new WitherOnClass3(this.couldBeNull, nonNull));
}
}
diff --git a/test/transform/resource/before/NonNullOnParameter.java b/test/transform/resource/before/NonNullOnParameter.java
new file mode 100644
index 00000000..7eb4c565
--- /dev/null
+++ b/test/transform/resource/before/NonNullOnParameter.java
@@ -0,0 +1,30 @@
+class NonNullOnParameter extends Thread {
+ NonNullOnParameter(@lombok.NonNull String arg) {
+ this(arg, "");
+ }
+
+ NonNullOnParameter(@lombok.NonNull String arg, @lombok.NonNull String arg2) {
+ super(arg);
+ if (arg == null) throw new NullPointerException();
+ }
+
+ public void test2(@lombok.NonNull String arg, @lombok.NonNull String arg2, @lombok.NonNull String arg3) {
+ if (arg2 == null) {
+ throw new NullPointerException("arg2");
+ }
+ if (arg == null) System.out.println("Hello");
+ }
+
+ public void test3(@lombok.NonNull String arg) {
+ if (arg != null) throw new IllegalStateException();
+ }
+
+ public void test(@lombok.NonNull String stringArg, @lombok.NonNull String arg2, @lombok.NonNull int primitiveArg) {
+
+ }
+
+ public void test(@lombok.NonNull String arg) {
+ System.out.println("Hey");
+ if (arg == null) throw new NullPointerException();
+ }
+} \ No newline at end of file
diff --git a/test/transform/resource/messages-delombok/NonNullOnParameter.java.messages b/test/transform/resource/messages-delombok/NonNullOnParameter.java.messages
new file mode 100644
index 00000000..ac87adcd
--- /dev/null
+++ b/test/transform/resource/messages-delombok/NonNullOnParameter.java.messages
@@ -0,0 +1 @@
+22:89 @NonNull is meaningless on a primitive.
diff --git a/test/transform/resource/messages-delombok/NonNullPlain.java.messages b/test/transform/resource/messages-delombok/NonNullPlain.java.messages
new file mode 100644
index 00000000..67eb8abe
--- /dev/null
+++ b/test/transform/resource/messages-delombok/NonNullPlain.java.messages
@@ -0,0 +1 @@
+7:9 @NonNull is meaningless on a primitive. \ No newline at end of file
diff --git a/test/transform/resource/messages-ecj/NonNullOnParameter.java.messages b/test/transform/resource/messages-ecj/NonNullOnParameter.java.messages
new file mode 100644
index 00000000..1539929b
--- /dev/null
+++ b/test/transform/resource/messages-ecj/NonNullOnParameter.java.messages
@@ -0,0 +1,3 @@
+15:460 Dead code
+22:683 @NonNull is meaningless on a primitive.
+28:823 Dead code \ No newline at end of file
diff --git a/test/transform/resource/messages-ecj/NonNullPlain.java.messages b/test/transform/resource/messages-ecj/NonNullPlain.java.messages
new file mode 100644
index 00000000..96eed252
--- /dev/null
+++ b/test/transform/resource/messages-ecj/NonNullPlain.java.messages
@@ -0,0 +1 @@
+7:116 @NonNull is meaningless on a primitive. \ No newline at end of file
diff --git a/test/transform/resource/messages-idempotent/NonNullOnParameter.java.messages b/test/transform/resource/messages-idempotent/NonNullOnParameter.java.messages
new file mode 100644
index 00000000..fd23a32a
--- /dev/null
+++ b/test/transform/resource/messages-idempotent/NonNullOnParameter.java.messages
@@ -0,0 +1 @@
+33:89 @NonNull is meaningless on a primitive. \ No newline at end of file
diff --git a/test/transform/resource/messages-idempotent/NonNullPlain.java.messages b/test/transform/resource/messages-idempotent/NonNullPlain.java.messages
new file mode 100644
index 00000000..c48da311
--- /dev/null
+++ b/test/transform/resource/messages-idempotent/NonNullPlain.java.messages
@@ -0,0 +1,3 @@
+4:9 @NonNull is meaningless on a primitive.
+18:29 @NonNull is meaningless on a primitive.
+44:26 @NonNull is meaningless on a primitive. \ No newline at end of file
diff --git a/usage_examples/NonNullExample_post.jpage b/usage_examples/NonNullExample_post.jpage
new file mode 100644
index 00000000..24175e06
--- /dev/null
+++ b/usage_examples/NonNullExample_post.jpage
@@ -0,0 +1,13 @@
+import lombok.NonNull;
+
+public class NonNullExample extends Something {
+ private String name;
+
+ public NonNullExample(@NonNull Person person) {
+ super("Hello");
+ if (person == null) {
+ throw new NullPointerException("person");
+ }
+ this.name = person.getName();
+ }
+}
diff --git a/usage_examples/NonNullExample_pre.jpage b/usage_examples/NonNullExample_pre.jpage
new file mode 100644
index 00000000..47556ce7
--- /dev/null
+++ b/usage_examples/NonNullExample_pre.jpage
@@ -0,0 +1,10 @@
+import lombok.NonNull;
+
+public class NonNullExample extends Something {
+ private String name;
+
+ public NonNullExample(@NonNull Person person) {
+ super("Hello");
+ this.name = person.getName();
+ }
+}
diff --git a/website/features/Cleanup.html b/website/features/Cleanup.html
index d1637dd4..a6e41f39 100644
--- a/website/features/Cleanup.html
+++ b/website/features/Cleanup.html
@@ -60,7 +60,7 @@
</div>
</div>
<div class="footer">
- <a href="index.html">Back to features</a> | <a href="Data.html">Previous feature (@Data)</a> | <a href="Synchronized.html">Next feature (@Synchronized)</a><br />
+ <a href="index.html">Back to features</a> | <a href="NonNull.html">Previous feature (@NonNull)</a> | <a href="GetterSetter.html">Next feature (@Getter / @Setter)</a><br />
<a href="../credits.html" class="creditsLink">credits</a> | <span class="copyright">Copyright &copy; 2009-2013 The Project Lombok Authors, licensed under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>.</span>
</div>
<div style="clear: both;"></div>
diff --git a/website/features/Data.html b/website/features/Data.html
index 8ace96cb..1c8510b7 100644
--- a/website/features/Data.html
+++ b/website/features/Data.html
@@ -75,7 +75,7 @@
</div>
</div>
<div class="footer">
- <a href="index.html">Back to features</a> | <a href="Constructor.html">Previous feature (@<em>X</em>Constructor)</a> | <a href="Cleanup.html">Next feature (@Cleanup)</a><br />
+ <a href="index.html">Back to features</a> | <a href="Constructor.html">Previous feature (@<em>X</em>Constructor)</a> | <a href="SneakyThrows.html">Next feature (@SneakyThrows)</a><br />
<a href="../credits.html" class="creditsLink">credits</a> | <span class="copyright">Copyright &copy; 2009-2013 The Project Lombok Authors, licensed under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>.</span>
</div>
<div style="clear: both;"></div>
diff --git a/website/features/Delegate.html b/website/features/Delegate.html
index 532f3f54..02cdf290 100644
--- a/website/features/Delegate.html
+++ b/website/features/Delegate.html
@@ -55,16 +55,15 @@
When passing classes to the annotation's <code>types</code> or <code>excludes</code> parameter, you cannot include generics.
This is a limitation of java. Use private inner interfaces or classes that extend the intended type including the
generics parameter to work around this problem.
- </p>
- <p>
+ </p><p>
When passing classes to the annotation, these classes do not need to be supertypes of the field. See the example.
- </p>
- <p>
+ </p><p>
<code>@Delegate</code> cannot be used on static fields or methods.
- <div>
+ </p>
+ </div>
</div>
<div class="footer">
- <a href="index.html">Back to features</a> | <a href="val.html">Previous feature (val)</a> | <span class="disabled">Next feature</span><br />
+ <a href="index.html">Back to features</a> | <a href="Log.html">Previous feature (@Log)</a> | <span class="disabled">Next feature</span><br />
<a href="../credits.html" class="creditsLink">credits</a> | <span class="copyright">Copyright &copy; 2010-2013 The Project Lombok Authors, licensed under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>.</span>
</div>
<div style="clear: both;"></div>
diff --git a/website/features/GetterLazy.html b/website/features/GetterLazy.html
index bc5ecb0c..f70c8e78 100644
--- a/website/features/GetterLazy.html
+++ b/website/features/GetterLazy.html
@@ -46,7 +46,7 @@
</div>
</div>
<div class="footer">
- <a href="index.html">Back to features</a> | <a href="GetterSetter.html">Previous feature (@Getter / @Setter)</a> | <a href="ToString.html">Next feature (@ToString)</a><br />
+ <a href="index.html">Back to features</a> | <a href="Synchronized.html">Previous feature (@Synchronized)</a> | <a href="Log.html">Next feature (@Log)</a><br />
<a href="../credits.html" class="creditsLink">credits</a> | <span class="copyright">Copyright &copy; 2009-2013 The Project Lombok Authors, licensed under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>.</span>
</div>
<div style="clear: both;"></div>
diff --git a/website/features/GetterSetter.html b/website/features/GetterSetter.html
index 03704119..c78b03bd 100644
--- a/website/features/GetterSetter.html
+++ b/website/features/GetterSetter.html
@@ -75,7 +75,7 @@
</div>
</div>
<div class="footer">
- <a href="index.html">Back to features</a> | <span class="disabled">Previous feature</span> | <a href="GetterLazy.html">Next feature (@Getter(lazy=true))</a><br />
+ <a href="index.html">Back to features</a> | <a href="Cleanup.html">Previous feature (@Cleanup)</a> | <a href="ToString.html">Next feature (@ToString)</a><br />
<a href="../credits.html" class="creditsLink">credits</a> | <span class="copyright">Copyright &copy; 2009-2013 The Project Lombok Authors, licensed under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>.</span>
</div>
<div style="clear: both;"></div>
diff --git a/website/features/Log.html b/website/features/Log.html
index 2fb91956..2d4fa375 100644
--- a/website/features/Log.html
+++ b/website/features/Log.html
@@ -60,7 +60,7 @@
</div>
</div>
<div class="footer">
- <a href="index.html">Back to features</a> | <a href="SneakyThrows.html">Previous feature (@SneakyThrows)</a> | <a href="val.html">Next feature (val)</a><br />
+ <a href="index.html">Back to features</a> | <a href="GetterLazy.html">Previous feature (@Getter(lazy=true))</a> | <a href="Delegate.html">Next feature (@Delegate)</a><br />
<a href="../credits.html" class="creditsLink">credits</a> | <span class="copyright">Copyright &copy; 2009-2013 The Project Lombok Authors, licensed under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>.</span>
</div>
<div style="clear: both;"></div>
diff --git a/website/features/NonNull.html b/website/features/NonNull.html
new file mode 100644
index 00000000..9faad502
--- /dev/null
+++ b/website/features/NonNull.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <link rel="stylesheet" type="text/css" href="../logi/reset.css" />
+ <link rel="stylesheet" type="text/css" href="features.css" />
+ <link rel="shortcut icon" href="../favicon.ico" type="image/x-icon" />
+ <meta name="description" content="Spice up your java" />
+ <title>val</title>
+</head><body><div id="pepper">
+ <div class="minimumHeight"></div>
+ <div class="meat">
+ <div class="header"><a href="../index.html">Project Lombok</a></div>
+ <h1>@NonNull</h1>
+ <div class="byline">or: How I learned to stop worrying and love the NullPointerException.</div>
+ <div class="overview">
+ <h3>Overview</h3>
+ <p>
+ <em>NEW in Lombok 0.11.10: </em>You can use <code>@NonNull</code> on the parameter of a method or constructor to have lombok generate a null-check statement for you.
+ </p><p>
+ Lombok has always treated any annotation named <code>@NonNull</code> on a field as a signal to generate a null-check if lombok generates an entire method or constructor for you, via
+ for example <a href="Data.html"><code>@Data</code></a>. Now, however, using lombok's own <code>@lombok.NonNull</code> on a parameter results in the insertion of just the null-check
+ statement inside your own method or constructor.
+ </p><p>
+ The null-check looks like <code>if (param == null) throw new NullPointerException("param");</code> and will be inserted at the very top of your method. For constructors, the null-check
+ will be inserted immediately following any explicit <code>this()</code> or <code>super()</code> calls.
+ </p><p>
+ If a null-check is already present at the top, no additional null-check will be generated.
+ </p>
+ </div>
+ <div class="snippets">
+ <div class="pre">
+ <h3>With Lombok</h3>
+ <div class="snippet">@HTML_PRE@</div>
+ </div>
+ <div class="sep"></div>
+ <div class="post">
+ <h3>Vanilla Java</h3>
+ <div class="snippet">@HTML_POST@</div>
+ </div>
+ </div>
+ <div style="clear: left;"></div>
+ <div class="overview">
+ <h3>Small print</h3><div class="smallprint">
+ <p>
+ Lombok's detection scheme for already existing null-checks consists of scanning for if statements that look just like lombok's own. Any 'throws' statement as
+ the 'then' part of the if statement, whether in braces or not, counts. The conditional of the if statement <em>must</em> look exactly like <code>PARAMNAME == null</code>.
+ The first statement in your method that is not such a null-check stops the process of inspecting for null-checks.
+ </p><p>
+ While <code>@Data</code> and other method-generating lombok annotations will trigger on any annotation named <code>@NonNull</code> regardless of casing or package name,
+ this feature only triggers on lombok's own <code>@NonNull</code> annotation from the <code>lombok</code> package.
+ </p><p>
+ A <code>@NonNull</code> on a primitive parameter results in a warning. No null-check will be generated.
+ </p>
+ </div>
+ </div>
+ <div class="footer">
+ <a href="index.html">Back to features</a> | <a href="val.html">Previous feature (val)</a> | <a href="Cleanup.html">Next feature (@Cleanup)</a><br />
+ <a href="../credits.html" class="creditsLink">credits</a> | <span class="copyright">Copyright &copy; 2013 The Project Lombok Authors, licensed under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>.</span>
+ </div>
+ <div style="clear: both;"></div>
+ </div>
+</div>
+<script type="text/javascript">
+ var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+ document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+</script>
+<script type="text/javascript">
+ try {
+ var pageTracker = _gat._getTracker("UA-9884254-1");
+ pageTracker._trackPageview();
+ } catch(err) {}
+</script>
+</body></html>
diff --git a/website/features/SneakyThrows.html b/website/features/SneakyThrows.html
index 808a7879..573bd95c 100644
--- a/website/features/SneakyThrows.html
+++ b/website/features/SneakyThrows.html
@@ -54,8 +54,6 @@
<div class="overview">
<h3>Small print</h3><div class="smallprint">
<p>
- <code>@SneakyThrows</code> is an implementation of this feature request: <a href="http://bugs.sun.com/view_bug.do?bug_id=6534270">http://bugs.sun.com/view_bug.do?bug_id=6534270</a>.
- </p><p>
Because <code>@SneakyThrows</code> is an implementation detail and not part of your method signature, it is an error if you try to
declare a checked exception as sneakily thrown when you don't call any methods that throw this exception. (Doing so is perfectly legal
for <code>throws</code> statements to accommodate subclasses). Similarly, <code>@SneakyThrows</code> does not inherit.
@@ -72,7 +70,7 @@
</div>
</div>
<div class="footer">
- <a href="index.html">Back to features</a> | <a href="Synchronized.html">Previous feature (@Synchronized)</a> | <a href="Log.html">Next feature (@Log)</a><br />
+ <a href="index.html">Back to features</a> | <a href="Data.html">Previous feature (@Data)</a> | <a href="Synchronized.html">Next feature (@Synchronized)</a><br />
<a href="../credits.html" class="creditsLink">credits</a> | <span class="copyright">Copyright &copy; 2009-2013 The Project Lombok Authors, licensed under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>.</span>
</div>
<div style="clear: both;"></div>
diff --git a/website/features/Synchronized.html b/website/features/Synchronized.html
index 4b6ef251..9ab6c87f 100644
--- a/website/features/Synchronized.html
+++ b/website/features/Synchronized.html
@@ -59,7 +59,7 @@
</div>
</div>
<div class="footer">
- <a href="index.html">Back to features</a> | <a href="Cleanup.html">Previous feature (@Cleanup)</a> | <a href="SneakyThrows.html">Next feature (@SneakyThrows)</a><br />
+ <a href="index.html">Back to features</a> | <a href="SneakyThrows.html">Previous feature (@SneakyThrows)</a> | <a href="GetterLazy.html">Next feature (@Getter(lazy=true))</a><br />
<a href="../credits.html" class="creditsLink">credits</a> | <span class="copyright">Copyright &copy; 2009-2013 The Project Lombok Authors, licensed under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>.</span>
</div>
<div style="clear: both;"></div>
diff --git a/website/features/ToString.html b/website/features/ToString.html
index c3b389ba..585dc72b 100644
--- a/website/features/ToString.html
+++ b/website/features/ToString.html
@@ -68,7 +68,7 @@
</div>
</div>
<div class="footer">
- <a href="index.html">Back to features</a> | <a href="GetterLazy.html">Previous feature (@Getter(lazy=true))</a> | <a href="EqualsAndHashCode.html">Next feature (@EqualsAndHashCode)</a><br />
+ <a href="index.html">Back to features</a> | <a href="GetterSetter.html">Previous feature (@Getter / @Setter)</a> | <a href="EqualsAndHashCode.html">Next feature (@EqualsAndHashCode)</a><br />
<a href="../credits.html" class="creditsLink">credits</a> | <span class="copyright">Copyright &copy; 2009-2013 The Project Lombok Authors, licensed under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>.</span>
</div>
<div style="clear: both;"></div>
diff --git a/website/features/index.html b/website/features/index.html
index 9751a37d..8b3765c1 100644
--- a/website/features/index.html
+++ b/website/features/index.html
@@ -13,10 +13,14 @@
<h1>Lombok features</h1>
<div class="index overview">
<dl>
+ <dt><a href="val.html"><code>val</code></a></dt>
+ <dd>Finally! Hassle-free final local variables.</dd>
+ <dt><a href="NonNull.html"><code>@NonNull</code></a></dt>
+ <dd>or: How I learned to stop worrying and love the NullPointerException.</dd>
+ <dt><a href="Cleanup.html"><code>@Cleanup</code></a></dt>
+ <dd>Automatic resource management: Call your <code>close()</code> methods safely with no hassle.</dd>
<dt><a href="GetterSetter.html"><code>@Getter</code> / <code>@Setter</code></a></dt>
<dd>Never write <code>public int getFoo() {return foo;}</code> again.</dd>
- <dt><a href="GetterLazy.html"><code>@Getter(lazy=true)</code></a></dt>
- <dd>Laziness is a virtue!</dd>
<dt><a href="ToString.html"><code>@ToString</code></a></dt>
<dd>No need to start a debugger to see your fields: Just let lombok generate a <code>toString</code> for you!</dd>
<dt><a href="EqualsAndHashCode.html"><code>@EqualsAndHashCode</code></a></dt>
@@ -26,16 +30,14 @@
<dt><a href="Data.html"><code>@Data</code></a></dt>
<dd>All together now: A shortcut for <code>@ToString</code>, <code>@EqualsAndHashCode</code>,
<code>@Getter</code> on all fields, and <code>@Setter</code> on all non-final fields, and <code>@RequiredArgsConstructor</code>!</dd>
- <dt><a href="Cleanup.html"><code>@Cleanup</code></a></dt>
- <dd>Automatic resource management: Call your <code>close()</code> methods safely with no hassle.</dd>
- <dt><a href="Synchronized.html"><code>@Synchronized</code></a></dt>
- <dd><code>synchronized</code> done right: Don't expose your locks.</dd>
<dt><a href="SneakyThrows.html"><code>@SneakyThrows</code></a></dt>
<dd>To boldly throw checked exceptions where no one has thrown them before!</dd>
+ <dt><a href="Synchronized.html"><code>@Synchronized</code></a></dt>
+ <dd><code>synchronized</code> done right: Don't expose your locks.</dd>
+ <dt><a href="GetterLazy.html"><code>@Getter(lazy=true)</code></a></dt>
+ <dd>Laziness is a virtue!</dd>
<dt><a href="Log.html"><code>@Log</code></a></dt>
<dd>Captain's Log, stardate 24435.7: &quot;What was that line again?&quot;</dd>
- <dt><a href="val.html"><code>val</code></a></dt>
- <dd>Finally! Hassle-free final local variables.</dd>
<dt><a href="Delegate.html"><code>@Delegate</code></a></dt>
<dd>Don't lose your composition.</dd>
<dt><a href="experimental/index.html">experimental features</a></dt>
diff --git a/website/features/val.html b/website/features/val.html
index cec799e9..c4c8ad27 100644
--- a/website/features/val.html
+++ b/website/features/val.html
@@ -50,7 +50,7 @@
</div>
</div>
<div class="footer">
- <a href="index.html">Back to features</a> | <a href="Log.html">Previous feature (@Log)</a> | <a href="Delegate.html">Next feature (@Delegate)</a><br />
+ <a href="index.html">Back to features</a> | <span class="disabled">Previous feature</span> | <a href="NonNull.html">Next feature (@NonNull)</a><br />
<a href="../credits.html" class="creditsLink">credits</a> | <span class="copyright">Copyright &copy; 2010-2013 The Project Lombok Authors, licensed under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>.</span>
</div>
<div style="clear: both;"></div>