From 56150952c451f0d8c2018424191d4480ac5e8460 Mon Sep 17 00:00:00 2001
From: Reinier Zwitserloot
Date: Mon, 11 Mar 2013 22:04:27 +0100
Subject: Added @Log4j2 support.
---
src/core/lombok/eclipse/handlers/HandleLog.java | 15 +++++-
.../lombok/extern/apachecommons/CommonsLog.java | 3 +-
src/core/lombok/extern/java/Log.java | 3 +-
src/core/lombok/extern/log4j/Log4j.java | 3 +-
src/core/lombok/extern/log4j/Log4j2.java | 62 ++++++++++++++++++++++
src/core/lombok/extern/slf4j/Slf4j.java | 3 +-
src/core/lombok/extern/slf4j/XSlf4j.java | 3 +-
src/core/lombok/javac/handlers/HandleLog.java | 17 +++++-
8 files changed, 101 insertions(+), 8 deletions(-)
create mode 100644 src/core/lombok/extern/log4j/Log4j2.java
(limited to 'src/core')
diff --git a/src/core/lombok/eclipse/handlers/HandleLog.java b/src/core/lombok/eclipse/handlers/HandleLog.java
index bffe2d62..2e7b4475 100644
--- a/src/core/lombok/eclipse/handlers/HandleLog.java
+++ b/src/core/lombok/eclipse/handlers/HandleLog.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 The Project Lombok Authors.
+ * Copyright (C) 2010-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
@@ -177,6 +177,16 @@ public class HandleLog {
}
}
+ /**
+ * Handles the {@link lombok.extern.log4j.Log4j2} annotation for Eclipse.
+ */
+ @ProviderFor(EclipseAnnotationHandler.class)
+ public static class HandleLog4j2Log extends EclipseAnnotationHandler {
+ @Override public void handle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) {
+ processAnnotation(LoggingFramework.LOG4J2, annotation, source, annotationNode);
+ }
+ }
+
/**
* Handles the {@link lombok.extern.slf4j.Slf4j} annotation for Eclipse.
*/
@@ -224,6 +234,9 @@ public class HandleLog {
// private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(TargetType.class);
LOG4J("org.apache.log4j.Logger", "org.apache.log4j.Logger", "getLogger", "@Log4j"),
+ // private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(TargetType.class);
+ LOG4J2("org.apache.logging.log4j.Logger", "org.apache.logging.log4j.LogManager", "getLogger", "@Log4j2"),
+
// private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TargetType.class);
SLF4J("org.slf4j.Logger", "org.slf4j.LoggerFactory", "getLogger", "@Slf4j"),
diff --git a/src/core/lombok/extern/apachecommons/CommonsLog.java b/src/core/lombok/extern/apachecommons/CommonsLog.java
index f178ae05..024e3744 100644
--- a/src/core/lombok/extern/apachecommons/CommonsLog.java
+++ b/src/core/lombok/extern/apachecommons/CommonsLog.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 The Project Lombok Authors.
+ * Copyright (C) 2010-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
@@ -52,6 +52,7 @@ import java.lang.annotation.Target;
* @see org.apache.commons.logging.LogFactory#getLog(java.lang.Class) org.apache.commons.logging.LogFactory.getLog(Class target)
* @see lombok.extern.java.Log @Log
* @see lombok.extern.log4j.Log4j @Log4j
+ * @see lombok.extern.log4j.Log4j2 @Log4j2
* @see lombok.extern.slf4j.Slf4j @Slf4j
* @see lombok.extern.slf4j.XSlf4j @XSlf4j
*/
diff --git a/src/core/lombok/extern/java/Log.java b/src/core/lombok/extern/java/Log.java
index 90c62956..7ae4e07b 100644
--- a/src/core/lombok/extern/java/Log.java
+++ b/src/core/lombok/extern/java/Log.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 The Project Lombok Authors.
+ * Copyright (C) 2010-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
@@ -51,6 +51,7 @@ import java.lang.annotation.Target;
* @see java.util.logging.Logger#getLogger(java.lang.String) java.util.logging.Logger.getLogger(String name)
* @see lombok.extern.apachecommons.CommonsLog @CommonsLog
* @see lombok.extern.log4j.Log4j @Log4j
+ * @see lombok.extern.log4j.Log4j2 @Log4j2
* @see lombok.extern.slf4j.Slf4j @Slf4j
* @see lombok.extern.slf4j.XSlf4j @XSlf4j
*/
diff --git a/src/core/lombok/extern/log4j/Log4j.java b/src/core/lombok/extern/log4j/Log4j.java
index 9cfc5839..29e1b27c 100644
--- a/src/core/lombok/extern/log4j/Log4j.java
+++ b/src/core/lombok/extern/log4j/Log4j.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 The Project Lombok Authors.
+ * Copyright (C) 2010-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
@@ -50,6 +50,7 @@ import java.lang.annotation.Target;
*
* @see org.apache.log4j.Logger org.apache.log4j.Logger
* @see org.apache.log4j.Logger#getLogger(java.lang.Class) org.apache.log4j.Logger.getLogger(Class target)
+ * @see lombok.extern.log4j.Log4j2 @Log4j2
* @see lombok.extern.apachecommons.CommonsLog @CommonsLog
* @see lombok.extern.java.Log @Log
* @see lombok.extern.slf4j.Slf4j @Slf4j
diff --git a/src/core/lombok/extern/log4j/Log4j2.java b/src/core/lombok/extern/log4j/Log4j2.java
new file mode 100644
index 00000000..2a0f09e1
--- /dev/null
+++ b/src/core/lombok/extern/log4j/Log4j2.java
@@ -0,0 +1,62 @@
+/*
+ * 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.extern.log4j;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Causes lombok to generate a logger field.
+ *
+ * @Log4j2
+ * public class LogExample {
+ * }
+ *
+ *
+ * will generate:
+ *
+ *
+ * public class LogExample {
+ * private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.Logger.getLogger(LogExample.class);
+ * }
+ *
+ *
+ * This annotation is valid for classes and enumerations.
+ *
+ * @see org.apache.logging.log4j.Logger org.apache.logging.log4j.Logger
+ * @see org.apache.logging.log4j.LogManager#getLogger(java.lang.Class) org.apache.logging.log4j.LogManager.getLogger(Class target)
+ * @see lombok.extern.log4j.Log4j @Log4j
+ * @see lombok.extern.apachecommons.CommonsLog @CommonsLog
+ * @see lombok.extern.java.Log @Log
+ * @see lombok.extern.slf4j.Slf4j @Slf4j
+ * @see lombok.extern.slf4j.XSlf4j @XSlf4j
+ */
+@Retention(RetentionPolicy.SOURCE)
+@Target(ElementType.TYPE)
+public @interface Log4j2 {
+}
\ No newline at end of file
diff --git a/src/core/lombok/extern/slf4j/Slf4j.java b/src/core/lombok/extern/slf4j/Slf4j.java
index 14dbcba6..45942971 100644
--- a/src/core/lombok/extern/slf4j/Slf4j.java
+++ b/src/core/lombok/extern/slf4j/Slf4j.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 The Project Lombok Authors.
+ * Copyright (C) 2010-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
@@ -51,6 +51,7 @@ import java.lang.annotation.Target;
* @see lombok.extern.apachecommons.CommonsLog @CommonsLog
* @see lombok.extern.java.Log @Log
* @see lombok.extern.log4j.Log4j @Log4j
+ * @see lombok.extern.log4j.Log4j2 @Log4j2
*/
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
diff --git a/src/core/lombok/extern/slf4j/XSlf4j.java b/src/core/lombok/extern/slf4j/XSlf4j.java
index bdf8a62c..599c68ab 100644
--- a/src/core/lombok/extern/slf4j/XSlf4j.java
+++ b/src/core/lombok/extern/slf4j/XSlf4j.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Project Lombok Authors.
+ * Copyright (C) 2012-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
@@ -51,6 +51,7 @@ import java.lang.annotation.Target;
* @see lombok.extern.apachecommons.CommonsLog @CommonsLog
* @see lombok.extern.java.Log @Log
* @see lombok.extern.log4j.Log4j @Log4j
+ * @see lombok.extern.log4j.Log4j2 @Log4j2
* @see lombok.extern.slf4j.Slf4j @Slf4j
*/
@Retention(RetentionPolicy.SOURCE)
diff --git a/src/core/lombok/javac/handlers/HandleLog.java b/src/core/lombok/javac/handlers/HandleLog.java
index 62a55c44..35a32be5 100644
--- a/src/core/lombok/javac/handlers/HandleLog.java
+++ b/src/core/lombok/javac/handlers/HandleLog.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 The Project Lombok Authors.
+ * Copyright (C) 2010-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
@@ -82,7 +82,7 @@ public class HandleLog {
private static boolean createField(LoggingFramework framework, JavacNode typeNode, JCFieldAccess loggingType, JCTree source) {
TreeMaker maker = typeNode.getTreeMaker();
- // private static final log = ();
+ // private static final log = ();
JCExpression loggerType = chainDotsString(typeNode, framework.getLoggerTypeName());
JCExpression factoryMethod = chainDotsString(typeNode, framework.getLoggerFactoryMethodName());
@@ -127,6 +127,16 @@ public class HandleLog {
}
}
+ /**
+ * Handles the {@link lombok.extern.log4j.Log4j2} annotation for javac.
+ */
+ @ProviderFor(JavacAnnotationHandler.class)
+ public static class HandleLog4j2Log extends JavacAnnotationHandler {
+ @Override public void handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) {
+ processAnnotation(LoggingFramework.LOG4J2, annotation, annotationNode);
+ }
+ }
+
/**
* Handles the {@link lombok.extern.slf4j.Slf4j} annotation for javac.
*/
@@ -163,6 +173,9 @@ public class HandleLog {
// private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(TargetType.class);
LOG4J(lombok.extern.log4j.Log4j.class, "org.apache.log4j.Logger", "org.apache.log4j.Logger.getLogger"),
+ // private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(TargetType.class);
+ LOG4J2(lombok.extern.log4j.Log4j2.class, "org.apache.logging.log4j.Logger", "org.apache.logging.log4j.LogManager.getLogger"),
+
// private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TargetType.class);
SLF4J(lombok.extern.slf4j.Slf4j.class, "org.slf4j.Logger", "org.slf4j.LoggerFactory.getLogger"),
--
cgit
From cb9b907839aa0c72ffa41f8a13bfab5cb1341258 Mon Sep 17 00:00:00 2001
From: Reinier Zwitserloot
Date: Tue, 12 Mar 2013 01:29:15 +0100
Subject: In delombok, we mark the AST as changed if we remove an annotation;
this fixes the issue where delombok would leave lombok annotations in the
file if that annotation had no actual effect (such as @Getter on a field if
there is an explicit getX method for that field).
issue #443: delombok would screw up @SneakyThrows on methods or constructors with empty bodies. Now we generate warnings for this.
---
.../eclipse/handlers/HandleSneakyThrows.java | 24 ++++++++++++++++++----
.../lombok/javac/handlers/HandleSneakyThrows.java | 19 +++++++++++++++--
.../lombok/javac/handlers/JavacHandlerUtil.java | 1 +
website/features/SneakyThrows.html | 6 +++++-
4 files changed, 43 insertions(+), 7 deletions(-)
(limited to 'src/core')
diff --git a/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java b/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java
index b7c8a5d8..aa78ca3b 100644
--- a/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java
+++ b/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java
@@ -40,6 +40,8 @@ import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.Argument;
import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer;
import org.eclipse.jdt.internal.compiler.ast.Block;
+import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall;
import org.eclipse.jdt.internal.compiler.ast.Expression;
import org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
@@ -147,7 +149,21 @@ public class HandleSneakyThrows extends EclipseAnnotationHandler {
return;
}
- if (method.statements == null) return;
+ if (method.statements == null || method.statements.length == 0) {
+ boolean hasConstructorCall = false;
+ if (method instanceof ConstructorDeclaration) {
+ ExplicitConstructorCall constructorCall = ((ConstructorDeclaration) method).constructorCall;
+ hasConstructorCall = constructorCall != null && !constructorCall.isImplicitSuper() && !constructorCall.isImplicitThis();
+ }
+
+ if (hasConstructorCall) {
+ annotation.addWarning("Calls to sibling / super constructors are always excluded from @SneakyThrows; @SneakyThrows has been ignored because there is no other code in this constructor.");
+ } else {
+ annotation.addWarning("This method or constructor is empty; @SneakyThrows has been ignored.");
+ }
+
+ return;
+ }
Statement[] contents = method.statements;
@@ -160,9 +176,9 @@ public class HandleSneakyThrows extends EclipseAnnotationHandler {
}
private Statement buildTryCatchBlock(Statement[] contents, DeclaredException exception, ASTNode source, AbstractMethodDeclaration method) {
- int methodStart = method.bodyStart;
- int methodEnd = method.bodyEnd;
- long methodPosEnd = methodEnd << 32 | (methodEnd & 0xFFFFFFFFL);
+ int methodStart = method.bodyStart;
+ int methodEnd = method.bodyEnd;
+ long methodPosEnd = ((long) methodEnd) << 32 | (methodEnd & 0xFFFFFFFFL);
TryStatement tryStatement = new TryStatement();
setGeneratedBy(tryStatement, source);
diff --git a/src/core/lombok/javac/handlers/HandleSneakyThrows.java b/src/core/lombok/javac/handlers/HandleSneakyThrows.java
index a5bd74e7..c2394fc8 100644
--- a/src/core/lombok/javac/handlers/HandleSneakyThrows.java
+++ b/src/core/lombok/javac/handlers/HandleSneakyThrows.java
@@ -84,13 +84,20 @@ public class HandleSneakyThrows extends JavacAnnotationHandler {
return;
}
- if (method.body == null) return;
- if (method.body.stats.isEmpty()) return;
+ if (method.body == null || method.body.stats.isEmpty()) {
+ generateEmptyBlockWarning(methodNode, annotation, false);
+ return;
+ }
final JCStatement constructorCall = method.body.stats.get(0);
final boolean isConstructorCall = isConstructorCall(constructorCall);
List contents = isConstructorCall ? method.body.stats.tail : method.body.stats;
+ if (contents == null || contents.isEmpty()) {
+ generateEmptyBlockWarning(methodNode, annotation, true);
+ return;
+ }
+
for (String exception : exceptions) {
contents = List.of(buildTryCatchBlock(methodNode, contents, exception, annotation.get()));
}
@@ -99,6 +106,14 @@ public class HandleSneakyThrows extends JavacAnnotationHandler {
methodNode.rebuild();
}
+ private void generateEmptyBlockWarning(JavacNode methodNode, JavacNode annotation, boolean hasConstructorCall) {
+ if (hasConstructorCall) {
+ annotation.addWarning("Calls to sibling / super constructors are always excluded from @SneakyThrows; @SneakyThrows has been ignored because there is no other code in this constructor.");
+ } else {
+ annotation.addWarning("This method or constructor is empty; @SneakyThrows has been ignored.");
+ }
+ }
+
private boolean isConstructorCall(final JCStatement supect) {
if (!(supect instanceof JCExpressionStatement)) return false;
final JCExpression supectExpression = ((JCExpressionStatement) supect).expr;
diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
index c2de5b05..e79dd5dc 100644
--- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java
+++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
@@ -305,6 +305,7 @@ public class JavacHandlerUtil {
return;
}
+ parentNode.getAst().setChanged();
deleteImportFromCompilationUnit(annotation, annotationType.getName());
}
diff --git a/website/features/SneakyThrows.html b/website/features/SneakyThrows.html
index 0f04b7d9..808a7879 100644
--- a/website/features/SneakyThrows.html
+++ b/website/features/SneakyThrows.html
@@ -64,7 +64,11 @@
statement in a try/catch block with just e.printStackTrace() in the catch block. This is so spectacularly non-productive
compared to just sneakily throwing the exception onwards, that Roel and Reinier feel more than justified in claiming that the
checked exception system is far from perfect, and thus an opt-out mechanism is warranted.
-
+
+ If you put @SneakyThrows on a constructor, any call to a sibling or super constructor is excluded from the @SneakyThrows treatment. This is a
+ java restriction we cannot work around: Calls to sibling/super constructors MUST be the first statement in the constructor; they cannot be placed inside try/catch blocks.
+
+ @SneakyThrows on an empty method, or a constructor that is empty or only has a call to a sibling / super constructor results in no try/catch block and a warning.
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 @@
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 types or excludes 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.
-
-
+
When passing classes to the annotation, these classes do not need to be supertypes of the field. See the example.
-
-
+
@Delegate cannot be used on static fields or methods.
-
or: How I learned to stop worrying and love the NullPointerException.
+
+
Overview
+
+ NEW in Lombok 0.11.10: You can use @NonNull on the parameter of a method or constructor to have lombok generate a null-check statement for you.
+
+ Lombok has always treated any annotation named @NonNull on a field as a signal to generate a null-check if lombok generates an entire method or constructor for you, via
+ for example @Data. Now, however, using lombok's own @lombok.NonNull on a parameter results in the insertion of just the null-check
+ statement inside your own method or constructor.
+
+ The null-check looks like if (param == null) throw new NullPointerException("param"); and will be inserted at the very top of your method. For constructors, the null-check
+ will be inserted immediately following any explicit this() or super() calls.
+
+ If a null-check is already present at the top, no additional null-check will be generated.
+
+
+
+
+
With Lombok
+
@HTML_PRE@
+
+
+
+
Vanilla Java
+
@HTML_POST@
+
+
+
+
+
Small print
+
+ 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 must look exactly like PARAMNAME == null.
+ The first statement in your method that is not such a null-check stops the process of inspecting for null-checks.
+
+ While @Data and other method-generating lombok annotations will trigger on any annotation named @NonNull regardless of casing or package name,
+ this feature only triggers on lombok's own @NonNull annotation from the lombok package.
+
+ A @NonNull on a primitive parameter results in a warning. No null-check will be generated.
+
Because @SneakyThrows 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 throws statements to accommodate subclasses). Similarly, @SneakyThrows does not inherit.
@@ -72,7 +70,7 @@
All together now: A shortcut for @ToString, @EqualsAndHashCode,
@Getter on all fields, and @Setter on all non-final fields, and @RequiredArgsConstructor!
--
cgit
From 5fd82596f6e80c71da1012e423419eed5c293ac2 Mon Sep 17 00:00:00 2001
From: Reinier Zwitserloot
Date: Thu, 13 Jun 2013 00:33:14 +0200
Subject: Added some very limited reporting when OutOfMemorErrors occur during
parse tree builder under javac. Let's hope our users reporting these issues
can use this to figure out which files are triggering the issue.
---
src/core/lombok/javac/JavacAST.java | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
(limited to 'src/core')
diff --git a/src/core/lombok/javac/JavacAST.java b/src/core/lombok/javac/JavacAST.java
index 5a91258c..36c51210 100644
--- a/src/core/lombok/javac/JavacAST.java
+++ b/src/core/lombok/javac/JavacAST.java
@@ -315,9 +315,18 @@ public class JavacAST extends AST {
}
private JavacNode drill(JCTree statement) {
- List childNodes = new ArrayList();
- for (FieldAccess fa : fieldsOf(statement.getClass())) childNodes.addAll(buildWithField(JavacNode.class, statement, fa));
- return putInMap(new JavacNode(this, statement, childNodes, Kind.STATEMENT));
+ try {
+ List childNodes = new ArrayList();
+ for (FieldAccess fa : fieldsOf(statement.getClass())) childNodes.addAll(buildWithField(JavacNode.class, statement, fa));
+ return putInMap(new JavacNode(this, statement, childNodes, Kind.STATEMENT));
+ } catch (OutOfMemoryError oome) {
+ String msg = oome.getMessage();
+ if (msg == null) msg = "(no original message)";
+ OutOfMemoryError newError = new OutOfMemoryError(getFileName() + "@pos" + statement.getPreferredPosition() + ": " + msg);
+ // We could try to set the stack trace of the new exception to the same one as the old exception, but this costs memory,
+ // and we're already in an extremely fragile situation in regards to remaining heap space, so let's not do that.
+ throw newError;
+ }
}
/** For javac, both JCExpression and JCStatement are considered as valid children types. */
--
cgit
From b3dac7722e699b3f18169265fd77f1731a82d960 Mon Sep 17 00:00:00 2001
From: Reinier Zwitserloot
Date: Sun, 16 Jun 2013 10:57:53 +0200
Subject: issue 536: annotationprocessor now always returns false.
---
src/core/lombok/core/AnnotationProcessor.java | 7 ++-----
src/core/lombok/javac/apt/Processor.java | 4 ----
2 files changed, 2 insertions(+), 9 deletions(-)
(limited to 'src/core')
diff --git a/src/core/lombok/core/AnnotationProcessor.java b/src/core/lombok/core/AnnotationProcessor.java
index 8c5f7fba..e9cf3891 100644
--- a/src/core/lombok/core/AnnotationProcessor.java
+++ b/src/core/lombok/core/AnnotationProcessor.java
@@ -164,12 +164,9 @@ public class AnnotationProcessor extends AbstractProcessor {
}
}
- boolean handled = false;
- for (ProcessorDescriptor proc : active) {
- handled |= proc.process(annotations, roundEnv);
- }
+ for (ProcessorDescriptor proc : active) proc.process(annotations, roundEnv);
- return handled;
+ return false;
}
/**
diff --git a/src/core/lombok/javac/apt/Processor.java b/src/core/lombok/javac/apt/Processor.java
index 96150b06..110acaad 100644
--- a/src/core/lombok/javac/apt/Processor.java
+++ b/src/core/lombok/javac/apt/Processor.java
@@ -62,10 +62,6 @@ import com.sun.tools.javac.util.Context;
/**
* This Annotation Processor is the standard injection mechanism for lombok-enabling the javac compiler.
*
- * Due to lots of changes in the core javac code, as well as lombok's heavy usage of non-public API, this
- * code only works for the javac v1.6 compiler; it definitely won't work for javac v1.5, and it probably
- * won't work for javac v1.7 without modifications.
- *
* To actually enable lombok in a javac compilation run, this class should be in the classpath when
* running javac; that's the only requirement.
*/
--
cgit
From 4e521c558ed7355244dd1cb9c8d94bd5a9cb462d Mon Sep 17 00:00:00 2001
From: Reinier Zwitserloot
Date: Thu, 23 May 2013 12:50:59 +0200
Subject: Added injectType methods to Eclipse/JavacHandlerUtil, which we'll
need to inject the created $Builder type.
Inspired by Philipp Eichhorn's work in lombok-pg.
---
.../lombok/eclipse/handlers/EclipseHandlerUtil.java | 21 +++++++++++++++++++++
.../lombok/javac/handlers/JavacHandlerUtil.java | 13 +++++++++++++
2 files changed, 34 insertions(+)
(limited to 'src/core')
diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
index dc99dabf..f9295150 100644
--- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
+++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
@@ -1289,6 +1289,27 @@ public class EclipseHandlerUtil {
type.add(method, Kind.METHOD);
}
+ /**
+ * Adds an inner type (class, interface, enum) to the given type. Cannot inject top-level types.
+ *
+ * @param typeNode parent type to inject new type into
+ * @param type New type (class, interface, etc) to inject.
+ */
+ public static void injectType(final EclipseNode typeNode, final TypeDeclaration type) {
+ type.annotations = createSuppressWarningsAll(type, type.annotations);
+ TypeDeclaration parent = (TypeDeclaration) typeNode.get();
+
+ if (parent.memberTypes == null) {
+ parent.memberTypes = new TypeDeclaration[] { type };
+ } else {
+ TypeDeclaration[] newArray = new TypeDeclaration[parent.memberTypes.length + 1];
+ System.arraycopy(parent.memberTypes, 0, newArray, 0, parent.memberTypes.length);
+ newArray[parent.memberTypes.length] = type;
+ parent.memberTypes = newArray;
+ }
+ typeNode.add(type, Kind.TYPE);
+ }
+
private static final char[] ALL = "all".toCharArray();
public static Annotation[] createSuppressWarningsAll(ASTNode source, Annotation[] originalAnnotationArray) {
diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
index 7cbaa5ac..2577befb 100644
--- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java
+++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
@@ -801,6 +801,19 @@ public class JavacHandlerUtil {
typeNode.add(method, Kind.METHOD);
}
+ /**
+ * Adds an inner type (class, interface, enum) to the given type. Cannot inject top-level types.
+ *
+ * @param typeNode parent type to inject new type into
+ * @param type New type (class, interface, etc) to inject.
+ */
+ public static void injectType(final JavacNode typeNode, final JCClassDecl type) {
+ JCClassDecl typeDecl = (JCClassDecl) typeNode.get();
+ addSuppressWarningsAll(type.mods, typeNode, type.pos, getGeneratedBy(type));
+ typeDecl.defs = typeDecl.defs.append(type);
+ typeNode.add(type, Kind.TYPE);
+ }
+
private static void addSuppressWarningsAll(JCModifiers mods, JavacNode node, int pos, JCTree source) {
TreeMaker maker = node.getTreeMaker();
JCExpression suppressWarningsType = chainDots(node, "java", "lang", "SuppressWarnings");
--
cgit
From 2d76b1d22dea1e78326ebafdb48967512183cede Mon Sep 17 00:00:00 2001
From: Reinier Zwitserloot
Date: Thu, 23 May 2013 21:12:01 +0200
Subject: First steps Builder support
---
.../lombok/eclipse/handlers/HandleBuilder.java | 71 +++++++++++++
src/core/lombok/experimental/Builder.java | 112 +++++++++++++++++++++
src/utils/lombok/core/JavaIdentifiers.java | 57 +++++++++++
3 files changed, 240 insertions(+)
create mode 100644 src/core/lombok/eclipse/handlers/HandleBuilder.java
create mode 100644 src/core/lombok/experimental/Builder.java
create mode 100644 src/utils/lombok/core/JavaIdentifiers.java
(limited to 'src/core')
diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java
new file mode 100644
index 00000000..13271165
--- /dev/null
+++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java
@@ -0,0 +1,71 @@
+/*
+ * 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 static lombok.eclipse.handlers.EclipseHandlerUtil.*;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.jdt.internal.compiler.ast.Annotation;
+import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+
+import lombok.AccessLevel;
+import lombok.core.AnnotationValues;
+import lombok.core.ImmutableList;
+import lombok.core.JavaIdentifiers;
+import lombok.eclipse.EclipseAnnotationHandler;
+import lombok.eclipse.EclipseNode;
+import lombok.experimental.Builder;
+
+public class HandleBuilder extends EclipseAnnotationHandler {
+ @Override public void handle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) {
+ String builderMethodName = annotation.getInstance().builderMethodName();
+ if (builderMethodName == null) builderMethodName = "builder";
+ if (builderMethodName.length() == 0) {
+ annotationNode.addError("builderMethodName cannot be the empty string.");
+ return;
+ }
+
+ if (!JavaIdentifiers.isValidJavaIdentifier(builderMethodName)) {
+ annotationNode.addError("builderMethodName must be a valid java method name.");
+ return;
+ }
+
+ EclipseNode parent = annotationNode.up();
+
+ if (parent.get() instanceof ConstructorDeclaration) {
+
+ }
+
+ if (parent.get() instanceof MethodDeclaration) {
+
+ }
+
+ if (parent.get() instanceof TypeDeclaration) {
+ // TODO: How do we ensure this one will 'win' over the implicit constructors generated by @Data and @Value.
+ new HandleConstructor().generateAllArgsConstructor(parent, AccessLevel.PRIVATE, null, true, Collections.emptyList(), ast);
+ }
+ }
+}
diff --git a/src/core/lombok/experimental/Builder.java b/src/core/lombok/experimental/Builder.java
new file mode 100644
index 00000000..b6667462
--- /dev/null
+++ b/src/core/lombok/experimental/Builder.java
@@ -0,0 +1,112 @@
+/*
+ * 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.experimental;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * The builder annotation creates a so-called 'builder' aspect to the class that is annotated or the class
+ * that contains a member which is annotated with {@code @Builder}.
+ *
+ * If a member is annotated, it must be either a constructor or a static method. If a class is annotated,
+ * then a private constructor is generated with all fields as arguments
+ * (as if {@code @AllArgsConstructor(AccessLevel.PRIVATE)} is present
+ * on the class), and it is as if this constructor has been annotated with {@code @Builder} instead.
+ *
+ * The effect of {@code @Builder} is that an inner class is generated named TBuilder,
+ * with a private constructor. Instances of TBuilder are made with the static
+ * method named {@code builder()} which is also generated for you in the class itself (not in the builder class).
+ *
+ * The TBuilder class contains 1 method for each parameter of the annotated
+ * constructor / static method (each field, when annotating a class), which returns the builder itself.
+ * The builder also has a build() method which returns a completed instance of the original type,
+ * created by passing all parameters as set via the various other methods in the builder to the constructor
+ * or static method that was annotated with {@code @Builder}. The return type of this method will be the same
+ * as the relevant class, unless a static method has been annotated, in which case it'll be equal to the
+ * return type of that method.
+ *
It's like drinking tea with an extended pinky while wearing a monocle: No-hassle fancy-pants APIs for object creation!
+
+
Since
+
+ @Builder was introduced as experimental feature in lombok v0.11.10.
+
+
+
+
Experimental
+
+ Experimental because:
+
+
New feature - community feedback requested.
+
This feature will move to the core package soon.
+
+ Current status: sure thing - This feature will move to the core package soon.
+
+
+
Overview
+
+ The @Builder annotation produces complex builder APIs for your classes.
+
+ @Builder lets you automatically produce the code required to have your class be instantiable with code such as:
+ Person.builder().name("Adam Savage").city("San Francisco").worksAt("Mythbusters").build();
+
+ @Builder can be placed on a class, or on a constructor, or on a static method. While the "on a class" and "on a constructor"
+ mode are the most common use-case, @Builder is most easily explained with the "static method" use-case.
+
+ A static method annotated with @Builder (from now on called the target) causes the following 7 things to be generated:
+
An inner static class named FooBuilder, with the same type arguments as the static method (called the builder).
+
In the builder: One private non-static non-final field for each parameter of the target.
+
In the builder: A package private no-args empty constructor.
+
In the builder: A 'setter'-like method for each parmeter of the target: It has the same type as that parameter and the same name.
+ It returns the builder itself, so that the setter calls can be chained, as in the above example.
+
In the builder: A build() method which calls the static method, passing in each field. It returns the same type that the
+ target returns.
+
In the builder: A sensible toString() implementation.
+
In the class containing the target: A builder() method, which creates a new instance of the builder.
+
+ Each listed generated element will be silently skipped if that element already exists (disregarding parameter counts and looking only at names). This
+ includes the builder itself: If that class already exists, lombok will simply start injecting fields and methods inside this already existing
+ class, unless of course the fields / methods to be injected already exist.
+
+ Now that the "static method" mode is clear, putting a @Builder annotation on a constructor functions similarly; effectively,
+ constructors are just static methods that have a special syntax to invoke them: Their 'return type' is the class they construct, and their
+ type parameters are the same as the type parameters of the class itself.
+
+ Finally, applying @Builder to a class is as if you added @AllArgsConstructor(acces = AccessLevel.PACKAGE) to the class and applied the
+ @Builder annotation to this all-args-constructor. Note that this constructor is only generated if there is no explicit
+ constructor present in the so annotated class, but this @AllArgsConstructor has priority over any other implicitly
+ generated lombok constructor (such as @Data and @Value). If an explicit constructor is present, no constructor is generated,
+ but the builder will be created with the assumption that this constructor exists. If you've written another constructor, you'll get a compilation error.
+ The solution is to either let lombok write this constructor (delete your own), or, annotate your constructor instead.
+
+ The name of the builder class is FoobarBuilder, where Foobar is the simplified, title-cased form of the return type of the
+ target - that is, the name of your type for @Builder on constructors and types, and the name of the return type for @Builder
+ on static methods. For example, if @Builder is applied to a class named com.yoyodyne.FancyList<T>, then the builder name will be
+ FancyListBuilder<T>. If @Builder is applied to a static method that returns void, the builder will be named
+ VoidBuilder.
+
+ The only configurable aspect of builder are the builder's class name (default: return type + 'Builder'), the build() method's name, and the
+ builder() method's name:
+ @Builder(builderClassName = "HelloWorldBuilder", buildMethodName = "execute", builderMethodName = "helloWorld")
+
+
+
+
+
With Lombok
+
@HTML_PRE@
+
+
+
+
Vanilla Java
+
@HTML_POST@
+
+
+
+
+
Small print
+
+ Another strategy for fluent APIs is that the programmer using your library statically imports your 'builder' method. In this case, you might want to name your builder
+ method equal to your type's name. So, the builder method for a class called Person would become person(). This is nicer if the builder method
+ is statically imported.
+
+ If the return type of your target static method is a type parameter (such as T), lombok will enforce an explicit builder class name.
+
+ You don't HAVE to use @Builder to build anything; you can for example put it on a static method that has lots of parameter to improve the API of it.
+ In this case, we suggest you use buildMethodName = to rename the build method to execute() instead.
+
+ The builder class will NOT get an auto-generated implementation of hashCode or equals methods! These would suggest that it is sensible to use
+ instances of a builder as keys in a set or map. However, that's not a sensible thing to do. Hence, no hashCode or equals.
+
+ Generics are sorted out for you.
+
+
+
+
+
+
+
+
+
+
diff --git a/website/features/experimental/index.html b/website/features/experimental/index.html
index 24fbb541..d0a086a0 100644
--- a/website/features/experimental/index.html
+++ b/website/features/experimental/index.html
@@ -22,6 +22,8 @@
Features that receive positive community feedback and which seem to produce clean, flexible code will eventually become accepted
as a core feature and move out of the experimental package.
--
cgit
From b5747963c022f680168ff66ebdc7860adb954882 Mon Sep 17 00:00:00 2001
From: Reinier Zwitserloot
Date: Tue, 25 Jun 2013 00:23:02 +0200
Subject: Value has been promoted to the main package.
---
doc/changelog.markdown | 2 +-
src/core/lombok/Data.java | 4 +-
src/core/lombok/Value.java | 58 ++++++++++++++++
src/core/lombok/core/LombokInternalAliasing.java | 52 ++++++++++++++
src/core/lombok/core/TypeLibrary.java | 6 ++
src/core/lombok/core/TypeResolver.java | 9 +--
src/core/lombok/eclipse/EclipseImportList.java | 13 ++--
src/core/lombok/eclipse/handlers/HandleValue.java | 2 +-
src/core/lombok/javac/JavacImportList.java | 9 ++-
src/core/lombok/javac/handlers/HandleValue.java | 4 +-
.../lombok/javac/handlers/JavacHandlerUtil.java | 19 ++++-
src/delombok/lombok/delombok/DelombokApp.java | 1 +
.../resource/after-delombok/ValueExperimental.java | 46 ++++++++++++
.../ValueExperimentalStarImport.java | 25 +++++++
.../resource/after-ecj/ValueExperimental.java | 39 +++++++++++
.../after-ecj/ValueExperimentalStarImport.java | 20 ++++++
test/transform/resource/after-ecj/ValuePlain.java | 4 +-
.../resource/before/ValueExperimental.java | 9 +++
.../before/ValueExperimentalStarImport.java | 5 ++
test/transform/resource/before/ValuePlain.java | 4 +-
website/features/Data.html | 2 +-
website/features/SneakyThrows.html | 2 +-
website/features/Value.html | 76 ++++++++++++++++++++
website/features/experimental/Value.html | 81 ----------------------
website/features/experimental/Wither.html | 2 +-
website/features/experimental/index.html | 9 ++-
website/features/experimental/onX.html | 2 +-
website/features/index.html | 2 +
28 files changed, 396 insertions(+), 111 deletions(-)
create mode 100644 src/core/lombok/Value.java
create mode 100644 src/core/lombok/core/LombokInternalAliasing.java
create mode 100644 test/transform/resource/after-delombok/ValueExperimental.java
create mode 100644 test/transform/resource/after-delombok/ValueExperimentalStarImport.java
create mode 100644 test/transform/resource/after-ecj/ValueExperimental.java
create mode 100644 test/transform/resource/after-ecj/ValueExperimentalStarImport.java
create mode 100644 test/transform/resource/before/ValueExperimental.java
create mode 100644 test/transform/resource/before/ValueExperimentalStarImport.java
create mode 100644 website/features/Value.html
delete mode 100644 website/features/experimental/Value.html
(limited to 'src/core')
diff --git a/doc/changelog.markdown b/doc/changelog.markdown
index 85fcd86a..95ee5764 100644
--- a/doc/changelog.markdown
+++ b/doc/changelog.markdown
@@ -2,7 +2,7 @@ Lombok Changelog
----------------
### v0.11.9 (Edgy Guinea Pig)
-* FEATURE: {Experimental} `@Builder` support. One of our earliest feature request issues has finally been addressed. [@Builder documentation](http://projectlombok.org/features/experimental/Builder.html).
+* FEATURE: {Experimental} `@Builder` support. One of our earliest feature request issues, [Issue #16](https://code.google.com/p/projectlombok/issues/detail?id=16), has finally been addressed. [@Builder documentation](http://projectlombok.org/features/experimental/Builder.html).
* 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)
diff --git a/src/core/lombok/Data.java b/src/core/lombok/Data.java
index ee6f2fcb..bbc8d920 100644
--- a/src/core/lombok/Data.java
+++ b/src/core/lombok/Data.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2012 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
@@ -39,7 +39,7 @@ import java.lang.annotation.Target;
* @see RequiredArgsConstructor
* @see ToString
* @see EqualsAndHashCode
- * @see lombok.experimental.Value
+ * @see lombok.Value
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
diff --git a/src/core/lombok/Value.java b/src/core/lombok/Value.java
new file mode 100644
index 00000000..2cffe15b
--- /dev/null
+++ b/src/core/lombok/Value.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2012-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;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Generates a lot of code which fits with a class that is a representation of an immutable entity.
+ *
+ * Complete documentation is found at the project lombok features page for @Value.
+ *
+ * @see lombok.Getter
+ * @see lombok.experimental.FieldDefaults
+ * @see lombok.RequiredArgsConstructor
+ * @see lombok.ToString
+ * @see lombok.EqualsAndHashCode
+ * @see lombok.Data
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.SOURCE)
+public @interface Value {
+ /**
+ * If you specify a static constructor name, then the generated constructor will be private, and
+ * instead a static factory method is created that other classes can use to create instances.
+ * We suggest the name: "of", like so:
+ *
+ *
+ * public @Data(staticConstructor = "of") class Point { final int x, y; }
+ *
+ *
+ * Default: No static constructor, instead the normal constructor is public.
+ */
+ String staticConstructor() default "";
+}
diff --git a/src/core/lombok/core/LombokInternalAliasing.java b/src/core/lombok/core/LombokInternalAliasing.java
new file mode 100644
index 00000000..4fd7b29d
--- /dev/null
+++ b/src/core/lombok/core/LombokInternalAliasing.java
@@ -0,0 +1,52 @@
+/*
+ * 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.core;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+public class LombokInternalAliasing {
+ public static final Map IMPLIED_EXTRA_STAR_IMPORTS;
+ public static final Map ALIASES;
+
+ /**
+ * Provide a fully qualified name (FQN), and the canonical version of this is returned.
+ */
+ public static String processAliases(String in) {
+ if (in == null) return null;
+ for (Map.Entry e : ALIASES.entrySet()) {
+ if (in.equals(e.getKey())) return e.getValue();
+ }
+ return in;
+ }
+
+ static {
+ Map m = new HashMap();
+ m.put("lombok.experimental", "lombok");
+ IMPLIED_EXTRA_STAR_IMPORTS = Collections.unmodifiableMap(m);
+
+ m = new HashMap();
+ m.put("lombok.experimental.Value", "lombok.Value");
+ ALIASES = Collections.unmodifiableMap(m);
+ }
+}
diff --git a/src/core/lombok/core/TypeLibrary.java b/src/core/lombok/core/TypeLibrary.java
index a89091c4..c0e9dc43 100644
--- a/src/core/lombok/core/TypeLibrary.java
+++ b/src/core/lombok/core/TypeLibrary.java
@@ -74,6 +74,9 @@ public class TypeLibrary {
unqualifiedToQualifiedMap.put(unqualified, fullyQualifiedTypeName);
unqualifiedToQualifiedMap.put(fullyQualifiedTypeName, fullyQualifiedTypeName);
+ for (Map.Entry e : LombokInternalAliasing.ALIASES.entrySet()) {
+ if (fullyQualifiedTypeName.equals(e.getValue())) unqualifiedToQualifiedMap.put(e.getKey(), fullyQualifiedTypeName);
+ }
}
/**
@@ -85,6 +88,9 @@ public class TypeLibrary {
public String toQualified(String typeReference) {
if (unqualifiedToQualifiedMap == null) {
if (typeReference.equals(unqualified) || typeReference.equals(qualified)) return qualified;
+ for (Map.Entry e : LombokInternalAliasing.ALIASES.entrySet()) {
+ if (e.getKey().equals(typeReference)) return e.getValue();
+ }
return null;
}
return unqualifiedToQualifiedMap.get(typeReference);
diff --git a/src/core/lombok/core/TypeResolver.java b/src/core/lombok/core/TypeResolver.java
index e2ba03b5..287a085f 100644
--- a/src/core/lombok/core/TypeResolver.java
+++ b/src/core/lombok/core/TypeResolver.java
@@ -39,19 +39,12 @@ public class TypeResolver {
this.imports = importList;
}
-// private static ImportList makeImportList(String packageString, Collection importStrings) {
-// Set imports = new HashSet();
-// if (packageString != null) imports.add(packageString + ".*");
-// imports.addAll(importStrings == null ? Collections.emptySet() : importStrings);
-// imports.add("java.lang.*");
-// return imports;
-// }
-//
public boolean typeMatches(LombokNode, ?, ?> context, String fqn, String typeRef) {
return typeRefToFullyQualifiedName(context, TypeLibrary.createLibraryForSingleType(fqn), typeRef) != null;
}
public String typeRefToFullyQualifiedName(LombokNode, ?, ?> context, TypeLibrary library, String typeRef) {
+ typeRef = LombokInternalAliasing.processAliases(typeRef);
// When asking if 'Foo' could possibly be referring to 'bar.Baz', the answer is obviously no.
String qualified = library.toQualified(typeRef);
if (qualified == null) return null;
diff --git a/src/core/lombok/eclipse/EclipseImportList.java b/src/core/lombok/eclipse/EclipseImportList.java
index 264ed91f..69246b3c 100644
--- a/src/core/lombok/eclipse/EclipseImportList.java
+++ b/src/core/lombok/eclipse/EclipseImportList.java
@@ -21,19 +21,21 @@
*/
package lombok.eclipse;
-import static lombok.eclipse.Eclipse.*;
+import static lombok.eclipse.Eclipse.toQualifiedName;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
+
+import lombok.core.ImportList;
+import lombok.core.LombokInternalAliasing;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ImportReference;
-import lombok.core.ImportList;
-
public class EclipseImportList implements ImportList {
private ImportReference[] imports;
private ImportReference pkg;
@@ -53,13 +55,16 @@ public class EclipseImportList implements ImportList {
int len = token.length;
if (len != unqualified.length()) continue;
for (int i = 0; i < len; i++) if (token[i] != unqualified.charAt(i)) continue outer;
- return toQualifiedName(tokens);
+ return LombokInternalAliasing.processAliases(toQualifiedName(tokens));
}
}
return null;
}
@Override public boolean hasStarImport(String packageName) {
+ for (Map.Entry e : LombokInternalAliasing.IMPLIED_EXTRA_STAR_IMPORTS.entrySet()) {
+ if (e.getValue().equals(packageName) && hasStarImport(e.getKey())) return true;
+ }
if (isEqual(packageName, pkg)) return true;
if ("java.lang".equals(packageName)) return true;
if (imports != null) for (ImportReference imp : imports) {
diff --git a/src/core/lombok/eclipse/handlers/HandleValue.java b/src/core/lombok/eclipse/handlers/HandleValue.java
index 60938649..0607137b 100644
--- a/src/core/lombok/eclipse/handlers/HandleValue.java
+++ b/src/core/lombok/eclipse/handlers/HandleValue.java
@@ -32,7 +32,7 @@ import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;
import lombok.eclipse.handlers.HandleConstructor.SkipIfConstructorExists;
import lombok.experimental.NonFinal;
-import lombok.experimental.Value;
+import lombok.Value;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
diff --git a/src/core/lombok/javac/JavacImportList.java b/src/core/lombok/javac/JavacImportList.java
index fbd4a518..d5d7460a 100644
--- a/src/core/lombok/javac/JavacImportList.java
+++ b/src/core/lombok/javac/JavacImportList.java
@@ -23,6 +23,7 @@ package lombok.javac;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Map;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
@@ -32,6 +33,7 @@ import com.sun.tools.javac.tree.JCTree.JCImport;
import com.sun.tools.javac.util.List;
import lombok.core.ImportList;
+import lombok.core.LombokInternalAliasing;
public class JavacImportList implements ImportList {
private final JCExpression pkg;
@@ -48,13 +50,18 @@ public class JavacImportList implements ImportList {
JCTree qual = ((JCImport) def).qualid;
if (!(qual instanceof JCFieldAccess)) continue;
String simpleName = ((JCFieldAccess) qual).name.toString();
- if (simpleName.equals(unqualified)) return qual.toString();
+ if (simpleName.equals(unqualified)) {
+ return LombokInternalAliasing.processAliases(qual.toString());
+ }
}
return null;
}
@Override public boolean hasStarImport(String packageName) {
+ for (Map.Entry e : LombokInternalAliasing.IMPLIED_EXTRA_STAR_IMPORTS.entrySet()) {
+ if (e.getValue().equals(packageName) && hasStarImport(e.getKey())) return true;
+ }
if (pkg != null && pkg.toString().equals(packageName)) return true;
if ("java.lang".equals(packageName)) return true;
diff --git a/src/core/lombok/javac/handlers/HandleValue.java b/src/core/lombok/javac/handlers/HandleValue.java
index a59865f7..c0127f3c 100644
--- a/src/core/lombok/javac/handlers/HandleValue.java
+++ b/src/core/lombok/javac/handlers/HandleValue.java
@@ -26,7 +26,7 @@ import lombok.AccessLevel;
import lombok.core.AnnotationValues;
import lombok.core.HandlerPriority;
import lombok.experimental.NonFinal;
-import lombok.experimental.Value;
+import lombok.Value;
import lombok.javac.JavacAnnotationHandler;
import lombok.javac.JavacNode;
import lombok.javac.handlers.HandleConstructor.SkipIfConstructorExists;
@@ -45,7 +45,7 @@ import com.sun.tools.javac.tree.JCTree.JCModifiers;
@HandlerPriority(-512) //-2^9; to ensure @EqualsAndHashCode and such pick up on this handler making the class final and messing with the fields' access levels, run earlier.
public class HandleValue extends JavacAnnotationHandler {
@Override public void handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) {
- deleteAnnotationIfNeccessary(annotationNode, Value.class);
+ deleteAnnotationIfNeccessary(annotationNode, Value.class, lombok.experimental.Value.class);
JavacNode typeNode = annotationNode.up();
boolean notAClass = !isClass(typeNode);
diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
index 92cebf4c..1784be90 100644
--- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java
+++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
@@ -280,7 +280,22 @@ public class JavacHandlerUtil {
* then removes any import statement that imports this exact annotation (not star imports).
* Only does this if the DeleteLombokAnnotations class is in the context.
*/
+ @SuppressWarnings("unchecked")
public static void deleteAnnotationIfNeccessary(JavacNode annotation, Class extends Annotation> annotationType) {
+ deleteAnnotationIfNeccessary0(annotation, annotationType);
+ }
+
+ /**
+ * Removes the annotation from javac's AST (it remains in lombok's AST),
+ * then removes any import statement that imports this exact annotation (not star imports).
+ * Only does this if the DeleteLombokAnnotations class is in the context.
+ */
+ @SuppressWarnings("unchecked")
+ public static void deleteAnnotationIfNeccessary(JavacNode annotation, Class extends Annotation> annotationType1, Class extends Annotation> annotationType2) {
+ deleteAnnotationIfNeccessary0(annotation, annotationType1, annotationType2);
+ }
+
+ private static void deleteAnnotationIfNeccessary0(JavacNode annotation, Class extends Annotation>... annotationTypes) {
if (inNetbeansEditor(annotation)) return;
if (!annotation.shouldDeleteLombokAnnotations()) return;
JavacNode parentNode = annotation.directUp();
@@ -309,7 +324,9 @@ public class JavacHandlerUtil {
}
parentNode.getAst().setChanged();
- deleteImportFromCompilationUnit(annotation, annotationType.getName());
+ for (Class> annotationType : annotationTypes) {
+ deleteImportFromCompilationUnit(annotation, annotationType.getName());
+ }
}
public static void deleteImportFromCompilationUnit(JavacNode node, String name) {
diff --git a/src/delombok/lombok/delombok/DelombokApp.java b/src/delombok/lombok/delombok/DelombokApp.java
index 90a7b55e..5b97be08 100644
--- a/src/delombok/lombok/delombok/DelombokApp.java
+++ b/src/delombok/lombok/delombok/DelombokApp.java
@@ -84,6 +84,7 @@ public class DelombokApp extends LombokApp {
return null;
}
+ @SuppressWarnings("resource")
final JarFile toolsJarFile = new JarFile(toolsJar);
ClassLoader loader = new ClassLoader() {
diff --git a/test/transform/resource/after-delombok/ValueExperimental.java b/test/transform/resource/after-delombok/ValueExperimental.java
new file mode 100644
index 00000000..77a48ec9
--- /dev/null
+++ b/test/transform/resource/after-delombok/ValueExperimental.java
@@ -0,0 +1,46 @@
+final class ValueExperimental1 {
+ @java.lang.SuppressWarnings("all")
+ public ValueExperimental1() {
+ }
+ @java.lang.Override
+ @java.lang.SuppressWarnings("all")
+ public boolean equals(final java.lang.Object o) {
+ if (o == this) return true;
+ if (!(o instanceof ValueExperimental1)) return false;
+ return true;
+ }
+ @java.lang.Override
+ @java.lang.SuppressWarnings("all")
+ public int hashCode() {
+ int result = 1;
+ return result;
+ }
+ @java.lang.Override
+ @java.lang.SuppressWarnings("all")
+ public java.lang.String toString() {
+ return "ValueExperimental1()";
+ }
+}
+final class ValueExperimental2 {
+ @java.lang.SuppressWarnings("all")
+ public ValueExperimental2() {
+ }
+ @java.lang.Override
+ @java.lang.SuppressWarnings("all")
+ public boolean equals(final java.lang.Object o) {
+ if (o == this) return true;
+ if (!(o instanceof ValueExperimental2)) return false;
+ return true;
+ }
+ @java.lang.Override
+ @java.lang.SuppressWarnings("all")
+ public int hashCode() {
+ int result = 1;
+ return result;
+ }
+ @java.lang.Override
+ @java.lang.SuppressWarnings("all")
+ public java.lang.String toString() {
+ return "ValueExperimental2()";
+ }
+}
\ No newline at end of file
diff --git a/test/transform/resource/after-delombok/ValueExperimentalStarImport.java b/test/transform/resource/after-delombok/ValueExperimentalStarImport.java
new file mode 100644
index 00000000..6911f260
--- /dev/null
+++ b/test/transform/resource/after-delombok/ValueExperimentalStarImport.java
@@ -0,0 +1,25 @@
+import lombok.experimental.*;
+final class ValueExperimentalStarImport {
+ @java.lang.SuppressWarnings("all")
+ public ValueExperimentalStarImport() {
+
+ }
+ @java.lang.Override
+ @java.lang.SuppressWarnings("all")
+ public boolean equals(final java.lang.Object o) {
+ if (o == this) return true;
+ if (!(o instanceof ValueExperimentalStarImport)) return false;
+ return true;
+ }
+ @java.lang.Override
+ @java.lang.SuppressWarnings("all")
+ public int hashCode() {
+ int result = 1;
+ return result;
+ }
+ @java.lang.Override
+ @java.lang.SuppressWarnings("all")
+ public java.lang.String toString() {
+ return "ValueExperimentalStarImport()";
+ }
+}
\ No newline at end of file
diff --git a/test/transform/resource/after-ecj/ValueExperimental.java b/test/transform/resource/after-ecj/ValueExperimental.java
new file mode 100644
index 00000000..dd13574a
--- /dev/null
+++ b/test/transform/resource/after-ecj/ValueExperimental.java
@@ -0,0 +1,39 @@
+import lombok.experimental.Value;
+final @Value class ValueExperimental1 {
+ public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) {
+ if ((o == this))
+ return true;
+ if ((! (o instanceof ValueExperimental1)))
+ return false;
+ return true;
+ }
+ public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() {
+ int result = 1;
+ return result;
+ }
+ public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
+ return "ValueExperimental1()";
+ }
+ public @java.lang.SuppressWarnings("all") ValueExperimental1() {
+ super();
+ }
+}
+final @lombok.experimental.Value class ValueExperimental2 {
+ public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) {
+ if ((o == this))
+ return true;
+ if ((! (o instanceof ValueExperimental2)))
+ return false;
+ return true;
+ }
+ public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() {
+ int result = 1;
+ return result;
+ }
+ public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
+ return "ValueExperimental2()";
+ }
+ public @java.lang.SuppressWarnings("all") ValueExperimental2() {
+ super();
+ }
+}
\ No newline at end of file
diff --git a/test/transform/resource/after-ecj/ValueExperimentalStarImport.java b/test/transform/resource/after-ecj/ValueExperimentalStarImport.java
new file mode 100644
index 00000000..b69e85d9
--- /dev/null
+++ b/test/transform/resource/after-ecj/ValueExperimentalStarImport.java
@@ -0,0 +1,20 @@
+import lombok.experimental.*;
+final @Value class ValueExperimentalStarImport {
+ public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) {
+ if ((o == this))
+ return true;
+ if ((! (o instanceof ValueExperimentalStarImport)))
+ return false;
+ return true;
+ }
+ public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() {
+ int result = 1;
+ return result;
+ }
+ public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
+ return "ValueExperimentalStarImport()";
+ }
+ public @java.lang.SuppressWarnings("all") ValueExperimentalStarImport() {
+ super();
+ }
+}
diff --git a/test/transform/resource/after-ecj/ValuePlain.java b/test/transform/resource/after-ecj/ValuePlain.java
index b798b308..d095913f 100644
--- a/test/transform/resource/after-ecj/ValuePlain.java
+++ b/test/transform/resource/after-ecj/ValuePlain.java
@@ -1,5 +1,5 @@
-import lombok.experimental.Value;
-final @lombok.experimental.Value class Value1 {
+import lombok.Value;
+final @lombok.Value class Value1 {
private final int x;
private final String name;
public @java.lang.SuppressWarnings("all") int getX() {
diff --git a/test/transform/resource/before/ValueExperimental.java b/test/transform/resource/before/ValueExperimental.java
new file mode 100644
index 00000000..6bae26a0
--- /dev/null
+++ b/test/transform/resource/before/ValueExperimental.java
@@ -0,0 +1,9 @@
+import lombok.experimental.Value;
+
+@Value
+class ValueExperimental1 {
+}
+
+@lombok.experimental.Value
+class ValueExperimental2 {
+}
\ No newline at end of file
diff --git a/test/transform/resource/before/ValueExperimentalStarImport.java b/test/transform/resource/before/ValueExperimentalStarImport.java
new file mode 100644
index 00000000..5f18cffe
--- /dev/null
+++ b/test/transform/resource/before/ValueExperimentalStarImport.java
@@ -0,0 +1,5 @@
+import lombok.experimental.*;
+
+@Value
+class ValueExperimentalStarImport {
+}
\ No newline at end of file
diff --git a/test/transform/resource/before/ValuePlain.java b/test/transform/resource/before/ValuePlain.java
index 39c583cc..3fe33705 100644
--- a/test/transform/resource/before/ValuePlain.java
+++ b/test/transform/resource/before/ValuePlain.java
@@ -1,5 +1,5 @@
-import lombok.experimental.Value;
-@lombok.experimental.Value class Value1 {
+import lombok.Value;
+@lombok.Value class Value1 {
final int x;
String name;
}
diff --git a/website/features/Data.html b/website/features/Data.html
index 1c8510b7..ad3aa892 100644
--- a/website/features/Data.html
+++ b/website/features/Data.html
@@ -75,7 +75,7 @@
diff --git a/website/features/SneakyThrows.html b/website/features/SneakyThrows.html
index 573bd95c..3b3987e4 100644
--- a/website/features/SneakyThrows.html
+++ b/website/features/SneakyThrows.html
@@ -70,7 +70,7 @@
diff --git a/website/features/Value.html b/website/features/Value.html
new file mode 100644
index 00000000..92fcc825
--- /dev/null
+++ b/website/features/Value.html
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+ @ExtensionMethod
+
+ @Value was introduced as experimental feature in lombok v0.11.4.
+
+ @Value no longer implies @Wither since lombok v0.11.8.
+
+ @Value promoted to the main lombok package since lombok v0.11.10.
+
+
+
Overview
+
+ @Value is the immutable variant of @Data; all fields are made private and final by default, and setters are not generated. The class itself is also made final by default, because immutability is not something that can be forced onto a subclass. Like @Data, useful toString(), equals() and hashCode() methods are also generated, each field gets a getter method, and a constructor that covers every
+ argument (except final fields that are initialized in the field declaration) is also generated.
+
+ In practice, @Value is shorthand for: final @ToString @EqualsAndHashCode @AllArgsConstructor @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @Getter.
+
+ It is possible to override the final-by-default and private-by-default behaviour using either an explicit access level on a field, or by using the @NonFinal or @PackagePrivate annotations.
+ It is possible to override any default behaviour for any of the 'parts' that make up @Value by explicitly using that annotation.
+
+ For classes with generics, it's useful to have a static method which serves as a constructor, because inference of generic parameters via static methods works in java6 and avoids having to use the diamond operator. While you can force this by applying an explicit @AllArgsConstructor(staticConstructor="of") annotation, there's also the @Value(staticConstructor="of") feature, which will make the generated all-arguments constructor private, and generates a public static method named of which is a wrapper around this private constructor.
+
+ @Value was an experimental feature from v0.11.4 to v0.11.9 (as @lombok.experimental.Value). It has since been moved into the core package. The old annotation is still
+ around (and is an alias). It will eventually be removed in a future version, though.
+
- @Value was introduced as experimental feature in lombok v0.11.4.
-
- @Value no longer implies @Wither since lombok v0.11.8.
-
-
-
Experimental
-
- Experimental because:
-
-
Various choices still have to be vetted as being the correct 'least surprise' choice: Should the class be made final by default, etc.
-
- Current status: positive - Currently we feel this feature may move out of experimental status with no or minor changes soon.
-
-
-
Overview
-
- @Value is the immutable variant of @Data; all fields are made private and final by default, and setters are not generated. The class itself is also made final by default, because immutability is not something that can be forced onto a subclass. Like @Data, useful toString(), equals() and hashCode() methods are also generated, each field gets a getter method, and a constructor that covers every
- argument (except final fields that are initialized in the field declaration) is also generated.
-
- In practice, @Value is shorthand for: final @ToString @EqualsAndHashCode @AllArgsConstructor @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @Getter.
-
- It is possible to override the final-by-default and private-by-default behaviour using either an explicit access level on a field, or by using the @NonFinal or @PackagePrivate annotations.
- It is possible to override any default behaviour for any of the 'parts' that make up @Value by explicitly using that annotation.
-
- For classes with generics, it's useful to have a static method which serves as a constructor, because inference of generic parameters via static methods works in java6 and avoids having to use the diamond operator. While you can force this by applying an explicit @AllArgsConstructor(staticConstructor="of") annotation, there's also the @Value(staticConstructor="of") feature, which will make the generated all-arguments constructor private, and generates a public static method named of which is a wrapper around this private constructor.
-
All together now: A shortcut for @ToString, @EqualsAndHashCode,
@Getter on all fields, and @Setter on all non-final fields, and @RequiredArgsConstructor!