aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReinier Zwitserloot <reinier@zwitserloot.com>2015-10-06 00:25:32 +0200
committerReinier Zwitserloot <reinier@zwitserloot.com>2015-10-06 00:25:32 +0200
commit9d8c4e4099bef9b7854cc5d77bc996c3b3bf0e41 (patch)
tree6ca48925c989d3f314fbeef08931a1940b5c03cf
parentb4d69f5cb8b093718bb7ffb539e5875df52ca48e (diff)
downloadlombok-9d8c4e4099bef9b7854cc5d77bc996c3b3bf0e41.tar.gz
lombok-9d8c4e4099bef9b7854cc5d77bc996c3b3bf0e41.tar.bz2
lombok-9d8c4e4099bef9b7854cc5d77bc996c3b3bf0e41.zip
New feature: FieldDefaults can now be configured to apply to _every_ file, regardless of annotations.
-rw-r--r--doc/changelog.markdown1
-rw-r--r--src/core/lombok/ConfigurationKeys.java14
-rw-r--r--src/core/lombok/eclipse/handlers/HandleFieldDefaults.java81
-rw-r--r--src/core/lombok/javac/handlers/HandleFieldDefaults.java75
-rw-r--r--src/core/lombok/javac/handlers/HandleVal.java14
-rw-r--r--src/utils/lombok/eclipse/Eclipse.java19
-rw-r--r--test/transform/resource/after-delombok/FieldDefaultsViaConfig.java11
-rw-r--r--test/transform/resource/after-delombok/FieldDefaultsViaConfigAndRequiredArgsConstructor.java9
-rw-r--r--test/transform/resource/after-ecj/FieldDefaultsViaConfig.java15
-rw-r--r--test/transform/resource/after-ecj/FieldDefaultsViaConfigAndRequiredArgsConstructor.java7
-rw-r--r--test/transform/resource/before/FieldDefaultsViaConfig.java16
-rw-r--r--test/transform/resource/before/FieldDefaultsViaConfigAndRequiredArgsConstructor.java5
-rw-r--r--website/features/configuration.html9
-rw-r--r--website/features/experimental/FieldDefaults.html4
14 files changed, 219 insertions, 61 deletions
diff --git a/doc/changelog.markdown b/doc/changelog.markdown
index ba1ea4b5..caff7f10 100644
--- a/doc/changelog.markdown
+++ b/doc/changelog.markdown
@@ -2,6 +2,7 @@ Lombok Changelog
----------------
### v1.16.7 "Edgy Guinea Pig"
+* FEATURE: A `lombok.config` key can now be used to make your fields `final` and/or `private`... __everywhere__. We'll be monitoring the performance impact of this for a while. We'll touch every source file if you turn these on, and even if you don't, we have to call into the lombok config system for every file.
* BUGFIX: `@Value` and `@FieldDefaults` no longer make uninitialized static fields final. [Issue #928](https://github.com/rzwitserloot/lombok/issues/928).
* ENHANCEMENT: Putting `@NonNull` on a parameter of an abstract method no longer generates a warning, to allow you to use this annotation to document intended behaviour [Issue #807](https://github.com/rzwitserloot/lombok/issues/807).
diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java
index 67d51895..dd6732ed 100644
--- a/src/core/lombok/ConfigurationKeys.java
+++ b/src/core/lombok/ConfigurationKeys.java
@@ -396,6 +396,20 @@ public class ConfigurationKeys {
// ----- FieldDefaults -----
/**
+ * lombok configuration: {@code lombok.fieldDefaults.defaultPrivate} = {@code true} | {@code false}.
+ *
+ * If set to <code>true</code> <em>any</em> field without an access modifier or {@code @PackagePrivate} is marked as {@code private} by lombok, in all source files compiled.
+ */
+ public static final ConfigurationKey<Boolean> FIELD_DEFAULTS_PRIVATE_EVERYWHERE = new ConfigurationKey<Boolean>("lombok.fieldDefaults.defaultPrivate", "If true, fields without any access modifier, in any file (lombok annotated or not) are marked as private. Use @PackagePrivate or an explicit modifier to override this.") {};
+
+ /**
+ * lombok configuration: {@code lombok.fieldDefaults.defaultFinal} = {@code true} | {@code false}.
+ *
+ * If set to <code>true</code> <em>any</em> field without {@code @NonFinal} is marked as {@code final} by lombok, in all source files compiled.
+ */
+ public static final ConfigurationKey<Boolean> FIELD_DEFAULTS_FINAL_EVERYWHERE = new ConfigurationKey<Boolean>("lombok.fieldDefaults.defaultFinal", "If true, fields, in any file (lombok annotated or not) are marked as final. Use @NonFinal to override this.") {};
+
+ /**
* lombok configuration: {@code lombok.fieldDefaults.flagUsage} = {@code WARNING} | {@code ERROR}.
*
* If set, <em>any</em> usage of {@code @FieldDefaults} results in a warning / error.
diff --git a/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java b/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java
index 33e796b7..f97a721b 100644
--- a/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java
+++ b/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java
@@ -23,12 +23,17 @@ package lombok.eclipse.handlers;
import static lombok.core.handlers.HandlerUtil.*;
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
+
+import java.util.Arrays;
+
import lombok.AccessLevel;
import lombok.ConfigurationKeys;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
import lombok.core.HandlerPriority;
-import lombok.eclipse.EclipseAnnotationHandler;
+import lombok.eclipse.Eclipse;
+import lombok.eclipse.EclipseASTAdapter;
+import lombok.eclipse.EclipseASTVisitor;
import lombok.eclipse.EclipseNode;
import lombok.experimental.FieldDefaults;
import lombok.experimental.NonFinal;
@@ -37,16 +42,19 @@ import lombok.experimental.PackagePrivate;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.mangosdk.spi.ProviderFor;
/**
* Handles the {@code lombok.FieldDefaults} annotation for eclipse.
*/
-@ProviderFor(EclipseAnnotationHandler.class)
+@ProviderFor(EclipseASTVisitor.class)
@HandlerPriority(-2048) //-2^11; to ensure @Value picks up on messing with the fields' 'final' state, run earlier.
-public class HandleFieldDefaults extends EclipseAnnotationHandler<FieldDefaults> {
+public class HandleFieldDefaults extends EclipseASTAdapter {
public boolean generateFieldDefaultsForType(EclipseNode typeNode, EclipseNode pos, AccessLevel level, boolean makeFinal, boolean checkForTypeLevelFieldDefaults) {
if (checkForTypeLevelFieldDefaults) {
if (hasAnnotation(FieldDefaults.class, typeNode)) {
@@ -105,29 +113,60 @@ public class HandleFieldDefaults extends EclipseAnnotationHandler<FieldDefaults>
fieldNode.rebuild();
}
- public void handle(AnnotationValues<FieldDefaults> annotation, Annotation ast, EclipseNode annotationNode) {
- handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.FIELD_DEFAULTS_FLAG_USAGE, "@FieldDefaults");
-
- EclipseNode node = annotationNode.up();
- FieldDefaults instance = annotation.getInstance();
- AccessLevel level = instance.level();
- boolean makeFinal = instance.makeFinal();
+ private static final char[] FIELD_DEFAULTS = "FieldDefaults".toCharArray();
+
+ @Override public void visitType(EclipseNode typeNode, TypeDeclaration type) {
+ AnnotationValues<FieldDefaults> fieldDefaults = null;
+ EclipseNode source = typeNode;
- if (level == AccessLevel.NONE && !makeFinal) {
- annotationNode.addError("This does nothing; provide either level or makeFinal or both.");
- return;
+ boolean levelIsExplicit = false;
+ boolean makeFinalIsExplicit = false;
+ FieldDefaults fd = null;
+ for (EclipseNode jn : typeNode.down()) {
+ if (jn.getKind() != Kind.ANNOTATION) continue;
+ Annotation ann = (Annotation) jn.get();
+ TypeReference typeTree = ann.type;
+ if (typeTree == null) continue;
+ if (typeTree instanceof SingleTypeReference) {
+ char[] t = ((SingleTypeReference) typeTree).token;
+ if (!Arrays.equals(t, FIELD_DEFAULTS)) continue;
+ } else if (typeTree instanceof QualifiedTypeReference) {
+ char[][] t = ((QualifiedTypeReference) typeTree).tokens;
+ if (!Eclipse.nameEquals(t, "lombok.experimental.FieldDefaults")) continue;
+ } else {
+ continue;
+ }
+
+ if (!typeMatches(FieldDefaults.class, jn, typeTree)) continue;
+
+ source = jn;
+ fieldDefaults = createAnnotation(FieldDefaults.class, jn);
+ levelIsExplicit = fieldDefaults.isExplicit("level");
+ makeFinalIsExplicit = fieldDefaults.isExplicit("makeFinal");
+
+ handleExperimentalFlagUsage(jn, ConfigurationKeys.FIELD_DEFAULTS_FLAG_USAGE, "@FieldDefaults");
+
+ fd = fieldDefaults.getInstance();
+ if (!levelIsExplicit && !makeFinalIsExplicit) {
+ jn.addError("This does nothing; provide either level or makeFinal or both.");
+ }
+
+ if (levelIsExplicit && fd.level() == AccessLevel.NONE) {
+ jn.addError("AccessLevel.NONE doesn't mean anything here. Pick another value.");
+ levelIsExplicit = false;
+ }
+ break;
}
- if (level == AccessLevel.PACKAGE) {
- annotationNode.addError("Setting 'level' to PACKAGE does nothing. To force fields as package private, use the @PackagePrivate annotation on the field.");
- }
+ if (fd == null && (type.modifiers & (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation)) != 0) return;
- if (!makeFinal && annotation.isExplicit("makeFinal")) {
- annotationNode.addError("Setting 'makeFinal' to false does nothing. To force fields to be non-final, use the @NonFinal annotation on the field.");
- }
+ boolean defaultToPrivate = Boolean.TRUE.equals(typeNode.getAst().readConfiguration(ConfigurationKeys.FIELD_DEFAULTS_PRIVATE_EVERYWHERE));
+ boolean defaultToFinal = Boolean.TRUE.equals(typeNode.getAst().readConfiguration(ConfigurationKeys.FIELD_DEFAULTS_FINAL_EVERYWHERE));
- if (node == null) return;
+ if (!defaultToPrivate && !defaultToFinal && fieldDefaults == null) return;
+ AccessLevel fdAccessLevel = (fieldDefaults != null && levelIsExplicit) ? fd.level() : defaultToPrivate ? AccessLevel.PRIVATE : null;
+ boolean fdToFinal = (fieldDefaults != null && makeFinalIsExplicit) ? fd.makeFinal() : defaultToFinal;
- generateFieldDefaultsForType(node, annotationNode, level, makeFinal, false);
+ generateFieldDefaultsForType(typeNode, source, fdAccessLevel, fdToFinal, false);
}
}
diff --git a/src/core/lombok/javac/handlers/HandleFieldDefaults.java b/src/core/lombok/javac/handlers/HandleFieldDefaults.java
index 95effded..5fb46afe 100644
--- a/src/core/lombok/javac/handlers/HandleFieldDefaults.java
+++ b/src/core/lombok/javac/handlers/HandleFieldDefaults.java
@@ -31,23 +31,24 @@ import lombok.core.HandlerPriority;
import lombok.experimental.FieldDefaults;
import lombok.experimental.NonFinal;
import lombok.experimental.PackagePrivate;
-import lombok.javac.JavacAnnotationHandler;
+import lombok.javac.JavacASTAdapter;
+import lombok.javac.JavacASTVisitor;
import lombok.javac.JavacNode;
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.JCAnnotation;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
-import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
/**
* Handles the {@code lombok.FieldDefaults} annotation for eclipse.
*/
-@ProviderFor(JavacAnnotationHandler.class)
+@ProviderFor(JavacASTVisitor.class)
@HandlerPriority(-2048) //-2^11; to ensure @Value picks up on messing with the fields' 'final' state, run earlier.
-public class HandleFieldDefaults extends JavacAnnotationHandler<FieldDefaults> {
+public class HandleFieldDefaults extends JavacASTAdapter {
public boolean generateFieldDefaultsForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, boolean makeFinal, boolean checkForTypeLevelFieldDefaults) {
if (checkForTypeLevelFieldDefaults) {
if (hasAnnotation(FieldDefaults.class, typeNode)) {
@@ -72,13 +73,13 @@ public class HandleFieldDefaults extends JavacAnnotationHandler<FieldDefaults> {
//Skip fields that start with $
if (fieldDecl.name.toString().startsWith("$")) continue;
- setFieldDefaultsForField(field, errorNode.get(), level, makeFinal);
+ setFieldDefaultsForField(field, level, makeFinal);
}
return true;
}
- public void setFieldDefaultsForField(JavacNode fieldNode, DiagnosticPosition pos, AccessLevel level, boolean makeFinal) {
+ public void setFieldDefaultsForField(JavacNode fieldNode, AccessLevel level, boolean makeFinal) {
JCVariableDecl field = (JCVariableDecl) fieldNode.get();
if (level != null && level != AccessLevel.NONE) {
if ((field.mods.flags & (Flags.PUBLIC | Flags.PRIVATE | Flags.PROTECTED)) == 0) {
@@ -99,31 +100,53 @@ public class HandleFieldDefaults extends JavacAnnotationHandler<FieldDefaults> {
fieldNode.rebuild();
}
- @Override public void handle(AnnotationValues<FieldDefaults> annotation, JCAnnotation ast, JavacNode annotationNode) {
- handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.FIELD_DEFAULTS_FLAG_USAGE, "@FieldDefaults");
+ @Override public void visitType(JavacNode typeNode, JCClassDecl type) {
+ AnnotationValues<FieldDefaults> fieldDefaults = null;
+ JavacNode source = typeNode;
- deleteAnnotationIfNeccessary(annotationNode, FieldDefaults.class);
- deleteImportFromCompilationUnit(annotationNode, "lombok.AccessLevel");
- JavacNode node = annotationNode.up();
- FieldDefaults instance = annotation.getInstance();
- AccessLevel level = instance.level();
- boolean makeFinal = instance.makeFinal();
-
- if (level == AccessLevel.NONE && !makeFinal) {
- annotationNode.addError("This does nothing; provide either level or makeFinal or both.");
- return;
+ boolean levelIsExplicit = false;
+ boolean makeFinalIsExplicit = false;
+ FieldDefaults fd = null;
+ for (JavacNode jn : typeNode.down()) {
+ if (jn.getKind() != Kind.ANNOTATION) continue;
+ JCAnnotation ann = (JCAnnotation) jn.get();
+ JCTree typeTree = ann.annotationType;
+ if (typeTree == null) continue;
+ String typeTreeToString = typeTree.toString();
+ if (!typeTreeToString.equals("FieldDefaults") && !typeTreeToString.equals("lombok.experimental.FieldDefaults")) continue;
+ if (!typeMatches(FieldDefaults.class, jn, typeTree)) continue;
+
+ source = jn;
+ fieldDefaults = createAnnotation(FieldDefaults.class, jn);
+ levelIsExplicit = fieldDefaults.isExplicit("level");
+ makeFinalIsExplicit = fieldDefaults.isExplicit("makeFinal");
+
+ handleExperimentalFlagUsage(jn, ConfigurationKeys.FIELD_DEFAULTS_FLAG_USAGE, "@FieldDefaults");
+
+ fd = fieldDefaults.getInstance();
+ if (!levelIsExplicit && !makeFinalIsExplicit) {
+ jn.addError("This does nothing; provide either level or makeFinal or both.");
+ }
+
+ if (levelIsExplicit && fd.level() == AccessLevel.NONE) {
+ jn.addError("AccessLevel.NONE doesn't mean anything here. Pick another value.");
+ levelIsExplicit = false;
+ }
+
+ deleteAnnotationIfNeccessary(jn, FieldDefaults.class);
+ deleteImportFromCompilationUnit(jn, "lombok.AccessLevel");
+ break;
}
- if (level == AccessLevel.PACKAGE) {
- annotationNode.addError("Setting 'level' to PACKAGE does nothing. To force fields as package private, use the @PackagePrivate annotation on the field.");
- }
+ if (fd == null && (type.mods.flags & (Flags.INTERFACE | Flags.ANNOTATION)) != 0) return;
- if (!makeFinal && annotation.isExplicit("makeFinal")) {
- annotationNode.addError("Setting 'makeFinal' to false does nothing. To force fields to be non-final, use the @NonFinal annotation on the field.");
- }
+ boolean defaultToPrivate = Boolean.TRUE.equals(typeNode.getAst().readConfiguration(ConfigurationKeys.FIELD_DEFAULTS_PRIVATE_EVERYWHERE));
+ boolean defaultToFinal = Boolean.TRUE.equals(typeNode.getAst().readConfiguration(ConfigurationKeys.FIELD_DEFAULTS_FINAL_EVERYWHERE));
- if (node == null) return;
+ if (!defaultToPrivate && !defaultToFinal && fieldDefaults == null) return;
+ AccessLevel fdAccessLevel = (fieldDefaults != null && levelIsExplicit) ? fd.level() : defaultToPrivate ? AccessLevel.PRIVATE : null;
+ boolean fdToFinal = (fieldDefaults != null && makeFinalIsExplicit) ? fd.makeFinal() : defaultToFinal;
- generateFieldDefaultsForType(node, annotationNode, level, makeFinal, false);
+ generateFieldDefaultsForType(typeNode, source, fdAccessLevel, fdToFinal, false);
}
}
diff --git a/src/core/lombok/javac/handlers/HandleVal.java b/src/core/lombok/javac/handlers/HandleVal.java
index 9eadd750..337ab2d7 100644
--- a/src/core/lombok/javac/handlers/HandleVal.java
+++ b/src/core/lombok/javac/handlers/HandleVal.java
@@ -51,11 +51,11 @@ import com.sun.tools.javac.util.List;
@ResolutionResetNeeded
public class HandleVal extends JavacASTAdapter {
@Override public void visitLocal(JavacNode localNode, JCVariableDecl local) {
- if (local.vartype == null || (!local.vartype.toString().equals("val") && !local.vartype.toString().equals("lombok.val"))) return;
-
- JCTree source = local.vartype;
-
- if (!typeMatches(val.class, localNode, local.vartype)) return;
+ JCTree typeTree = local.vartype;
+ if (typeTree == null) return;
+ String typeTreeToString = typeTree.toString();
+ if (!typeTreeToString.equals("val") && !typeTreeToString.equals("lombok.val")) return;
+ if (!typeMatches(val.class, localNode, typeTree)) return;
handleFlagUsage(localNode, ConfigurationKeys.VAL_FLAG_USAGE, "val");
@@ -88,7 +88,7 @@ public class HandleVal extends JavacASTAdapter {
local.mods.flags |= Flags.FINAL;
if (!localNode.shouldDeleteLombokAnnotations()) {
- JCAnnotation valAnnotation = recursiveSetGeneratedBy(localNode.getTreeMaker().Annotation(local.vartype, List.<JCExpression>nil()), source, localNode.getContext());
+ JCAnnotation valAnnotation = recursiveSetGeneratedBy(localNode.getTreeMaker().Annotation(local.vartype, List.<JCExpression>nil()), typeTree, localNode.getContext());
local.mods.annotations = local.mods.annotations == null ? List.of(valAnnotation) : local.mods.annotations.append(valAnnotation);
}
@@ -156,7 +156,7 @@ public class HandleVal extends JavacASTAdapter {
local.vartype = JavacResolution.createJavaLangObject(localNode.getAst());
throw e;
} finally {
- recursiveSetGeneratedBy(local.vartype, source, localNode.getContext());
+ recursiveSetGeneratedBy(local.vartype, typeTree, localNode.getContext());
}
}
}
diff --git a/src/utils/lombok/eclipse/Eclipse.java b/src/utils/lombok/eclipse/Eclipse.java
index c2a863d5..18b22256 100644
--- a/src/utils/lombok/eclipse/Eclipse.java
+++ b/src/utils/lombok/eclipse/Eclipse.java
@@ -98,15 +98,20 @@ public class Eclipse {
* string containing the same fully qualified name with dots in the string.
*/
public static boolean nameEquals(char[][] typeName, String string) {
- StringBuilder sb = new StringBuilder();
- boolean first = true;
- for (char[] elem : typeName) {
- if (first) first = false;
- else sb.append('.');
- sb.append(elem);
+ int pos = 0, len = string.length();
+ for (int i = 0; i < typeName.length; i++) {
+ char[] t = typeName[i];
+ if (i > 0) {
+ if (pos == len) return false;
+ if (string.charAt(pos++) != '.') return false;
+ }
+ for (int j = 0; j < t.length; j++) {
+ if (pos == len) return false;
+ if (string.charAt(pos++) != t[j]) return false;
+ }
}
- return string.contentEquals(sb);
+ return true;
}
public static boolean hasClinit(TypeDeclaration parent) {
diff --git a/test/transform/resource/after-delombok/FieldDefaultsViaConfig.java b/test/transform/resource/after-delombok/FieldDefaultsViaConfig.java
new file mode 100644
index 00000000..096769b6
--- /dev/null
+++ b/test/transform/resource/after-delombok/FieldDefaultsViaConfig.java
@@ -0,0 +1,11 @@
+class FieldDefaultsViaConfig1 {
+ private final int x;
+ private int y;
+ FieldDefaultsViaConfig1(int x) {
+ this.x = x;
+ }
+}
+class FieldDefaultsViaConfig2 {
+ final int x = 2;
+ protected final int y = 0;
+} \ No newline at end of file
diff --git a/test/transform/resource/after-delombok/FieldDefaultsViaConfigAndRequiredArgsConstructor.java b/test/transform/resource/after-delombok/FieldDefaultsViaConfigAndRequiredArgsConstructor.java
new file mode 100644
index 00000000..ebe6e2ed
--- /dev/null
+++ b/test/transform/resource/after-delombok/FieldDefaultsViaConfigAndRequiredArgsConstructor.java
@@ -0,0 +1,9 @@
+class FieldDefaultsViaConfigAndRequiredArgsConstructor {
+ final int x;
+ @java.beans.ConstructorProperties({"x"})
+ @java.lang.SuppressWarnings("all")
+ @javax.annotation.Generated("lombok")
+ public FieldDefaultsViaConfigAndRequiredArgsConstructor(final int x) {
+ this.x = x;
+ }
+} \ No newline at end of file
diff --git a/test/transform/resource/after-ecj/FieldDefaultsViaConfig.java b/test/transform/resource/after-ecj/FieldDefaultsViaConfig.java
new file mode 100644
index 00000000..689d2601
--- /dev/null
+++ b/test/transform/resource/after-ecj/FieldDefaultsViaConfig.java
@@ -0,0 +1,15 @@
+class FieldDefaultsViaConfig1 {
+ private final int x;
+ private @lombok.experimental.NonFinal int y;
+ FieldDefaultsViaConfig1(int x) {
+ super();
+ this.x = x;
+ }
+}
+@lombok.experimental.FieldDefaults(level = lombok.AccessLevel.PROTECTED) class FieldDefaultsViaConfig2 {
+ final @lombok.experimental.PackagePrivate int x = 2;
+ protected final int y = 0;
+ FieldDefaultsViaConfig2() {
+ super();
+ }
+}
diff --git a/test/transform/resource/after-ecj/FieldDefaultsViaConfigAndRequiredArgsConstructor.java b/test/transform/resource/after-ecj/FieldDefaultsViaConfigAndRequiredArgsConstructor.java
new file mode 100644
index 00000000..6a727f1d
--- /dev/null
+++ b/test/transform/resource/after-ecj/FieldDefaultsViaConfigAndRequiredArgsConstructor.java
@@ -0,0 +1,7 @@
+@lombok.RequiredArgsConstructor class FieldDefaultsViaConfigAndRequiredArgsConstructor {
+ final int x;
+ public @java.beans.ConstructorProperties({"x"}) @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") FieldDefaultsViaConfigAndRequiredArgsConstructor(final int x) {
+ super();
+ this.x = x;
+ }
+}
diff --git a/test/transform/resource/before/FieldDefaultsViaConfig.java b/test/transform/resource/before/FieldDefaultsViaConfig.java
new file mode 100644
index 00000000..61f6daca
--- /dev/null
+++ b/test/transform/resource/before/FieldDefaultsViaConfig.java
@@ -0,0 +1,16 @@
+//CONF: lombok.fieldDefaults.defaultFinal = true
+//CONF: lombok.fieldDefaults.defaultPrivate = true
+class FieldDefaultsViaConfig1 {
+ int x;
+ @lombok.experimental.NonFinal int y;
+
+ FieldDefaultsViaConfig1(int x) {
+ this.x = x;
+ }
+}
+
+@lombok.experimental.FieldDefaults(level = lombok.AccessLevel.PROTECTED)
+class FieldDefaultsViaConfig2 {
+ @lombok.experimental.PackagePrivate int x = 2;
+ int y = 0;
+}
diff --git a/test/transform/resource/before/FieldDefaultsViaConfigAndRequiredArgsConstructor.java b/test/transform/resource/before/FieldDefaultsViaConfigAndRequiredArgsConstructor.java
new file mode 100644
index 00000000..8c0607d7
--- /dev/null
+++ b/test/transform/resource/before/FieldDefaultsViaConfigAndRequiredArgsConstructor.java
@@ -0,0 +1,5 @@
+//CONF: lombok.fieldDefaults.defaultFinal = true
+@lombok.RequiredArgsConstructor
+class FieldDefaultsViaConfigAndRequiredArgsConstructor {
+ int x;
+}
diff --git a/website/features/configuration.html b/website/features/configuration.html
index 7e79a9c0..21864409 100644
--- a/website/features/configuration.html
+++ b/website/features/configuration.html
@@ -85,6 +85,15 @@
<code>lombok.extern.findbugs.addSuppressFBWarnings = true</code>
</div>
</div>
+ <div class="overview" style="clear: left;">
+ <h3>Config keys that can even affect source files with 0 lombok annotations</h3>
+ <p>
+ <div class="snippet example">
+ <code>lombok.fieldDefaults.defaultPrivate = true</code><br />
+ <code>lombok.fieldDefaults.defaultFinal = true</code>
+ </div>
+ Turning either of these options on means lombok will make <em>every</em> field in <em>every</em> source file final and/or private unless it has an explicit access modifier or annotation to suppress this. <a href="experimental/FieldDefaults.html">See the <code>@FieldDefaults</code> documentation for more</a>.
+ </div>
<div style="clear: left;"></div>
<div class="footer">
<a href="index.html">Back to features</a> | <a href="Log.html">Previous feature (@Log)</a> | <span class="disabled">Next feature</span><br />
diff --git a/website/features/experimental/FieldDefaults.html b/website/features/experimental/FieldDefaults.html
index 5ad30952..026f23fc 100644
--- a/website/features/experimental/FieldDefaults.html
+++ b/website/features/experimental/FieldDefaults.html
@@ -61,6 +61,10 @@
<dl>
<dt><code>lombok.fieldDefaults.flagUsage</code> = [<code>warning</code> | <code>error</code>] (default: not set)</dt>
<dd>Lombok will flag any usage of <code>@FieldDefaults</code> as a warning or error if configured.</dd>
+ <dt><code>lombok.fieldDefaults.defaultPrivate</code> = [<code>true</code> | <code>false</code>] (default: false)</dt>
+ <dd>(Since 1.16.8) If set to <code>true</code>, <em>every</em> field in <em>every</em> class or enum anywhere in the sources being compiled will be marked as <code>private</code> unless it has an explicit access modifier or the <code>@PackagePrivate</code> annotation, or an explicit <code>@FieldDefaults</code> annotation is present to override this config key.</dd>
+ <dt><code>lombok.fieldDefaults.defaultFinal</code> = [<code>true</code> | <code>false</code>] (default: false)</dt>
+ <dd>(Since 1.16.8) If set to <code>true</code>, <em>every</em> field in <em>every</em> class or enum anywhere in the sources being compiled will be marked as <code>final</code> unless it has the <code>@NonFinal</code> annotation, or an explicit <code>@FieldDefaults</code> annotation is present to override this config key.</dd>
</dl>
</div>
<div class="overview">