aboutsummaryrefslogtreecommitdiff
path: root/src/core/lombok/javac/handlers
diff options
context:
space:
mode:
authorRoel Spilker <r.spilker@gmail.com>2010-11-11 01:58:48 +0100
committerRoel Spilker <r.spilker@gmail.com>2010-11-11 01:58:48 +0100
commit1c323332493148f0aaa936e668e1b0da5d09c8be (patch)
tree7b9107aa641fb913702360cc95133a640218552d /src/core/lombok/javac/handlers
parentc8774389e7cb73e494267af3a87f70c7497b220a (diff)
downloadlombok-1c323332493148f0aaa936e668e1b0da5d09c8be.tar.gz
lombok-1c323332493148f0aaa936e668e1b0da5d09c8be.tar.bz2
lombok-1c323332493148f0aaa936e668e1b0da5d09c8be.zip
@Getter(lazy=true) support for javac
Diffstat (limited to 'src/core/lombok/javac/handlers')
-rw-r--r--src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java34
-rw-r--r--src/core/lombok/javac/handlers/HandleGetter.java189
-rw-r--r--src/core/lombok/javac/handlers/HandleSetter.java3
-rw-r--r--src/core/lombok/javac/handlers/HandleToString.java17
-rw-r--r--src/core/lombok/javac/handlers/JavacHandlerUtil.java35
5 files changed, 233 insertions, 45 deletions
diff --git a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java
index 60b0f89f..e076b295 100644
--- a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java
+++ b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java
@@ -90,7 +90,9 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd
annotation.setWarning("exclude", "exclude and of are mutually exclusive; the 'exclude' parameter will be ignored.");
}
- return generateMethods(typeNode, annotationNode, excludes, includes, callSuper, true, ann.doNotUseGetters());
+ FieldAccess fieldAccess = ann.doNotUseGetters() ? FieldAccess.PREFER_FIELD : FieldAccess.GETTER;
+
+ return generateMethods(typeNode, annotationNode, excludes, includes, callSuper, true, fieldAccess);
}
public void generateEqualsAndHashCodeForType(JavacNode typeNode, JavacNode errorNode) {
@@ -103,11 +105,11 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd
}
}
- generateMethods(typeNode, errorNode, null, null, null, false, false);
+ generateMethods(typeNode, errorNode, null, null, null, false, FieldAccess.GETTER);
}
private boolean generateMethods(JavacNode typeNode, JavacNode errorNode, List<String> excludes, List<String> includes,
- Boolean callSuper, boolean whineIfExists, boolean useFieldsDirectly) {
+ Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess) {
boolean notAClass = true;
if (typeNode.get() instanceof JCClassDecl) {
long flags = ((JCClassDecl)typeNode.get()).mods.flags;
@@ -173,7 +175,7 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd
boolean isFinal = (((JCClassDecl)typeNode.get()).mods.flags & Flags.FINAL) != 0;
needsCanEqual = !isFinal || !isDirectDescendantOfObject;
- JCMethodDecl method = createEquals(typeNode, nodesForEquality, callSuper, useFieldsDirectly, needsCanEqual);
+ JCMethodDecl method = createEquals(typeNode, nodesForEquality, callSuper, fieldAccess, needsCanEqual);
injectMethod(typeNode, method);
break;
case EXISTS_BY_LOMBOK:
@@ -200,7 +202,7 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd
}
switch (methodExists("hashCode", typeNode)) {
case NOT_EXISTS:
- JCMethodDecl method = createHashCode(typeNode, nodesForEquality, callSuper, useFieldsDirectly);
+ JCMethodDecl method = createHashCode(typeNode, nodesForEquality, callSuper, fieldAccess);
injectMethod(typeNode, method);
break;
case EXISTS_BY_LOMBOK:
@@ -215,7 +217,7 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd
return true;
}
- private JCMethodDecl createHashCode(JavacNode typeNode, List<JavacNode> fields, boolean callSuper, boolean useFieldsDirectly) {
+ private JCMethodDecl createHashCode(JavacNode typeNode, List<JavacNode> fields, boolean callSuper, FieldAccess fieldAccess) {
TreeMaker maker = typeNode.getTreeMaker();
JCAnnotation overrideAnnotation = maker.Annotation(chainDots(maker, typeNode, "java", "lang", "Override"), List.<JCExpression>nil());
@@ -247,8 +249,8 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd
int tempCounter = 0;
for (JavacNode fieldNode : fields) {
- JCExpression fType = getFieldType(fieldNode, useFieldsDirectly);
- JCExpression fieldAccessor = createFieldAccessor(maker, fieldNode, useFieldsDirectly);
+ JCExpression fType = getFieldType(fieldNode, fieldAccess);
+ JCExpression fieldAccessor = createFieldAccessor(maker, fieldNode, fieldAccess);
if (fType instanceof JCPrimitiveTypeTree) {
switch (((JCPrimitiveTypeTree)fType).getPrimitiveTypeKind()) {
case BOOLEAN:
@@ -256,7 +258,7 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd
intoResult = intoResult.append(maker.Conditional(fieldAccessor, maker.Literal(1231), maker.Literal(1237)));
break;
case LONG:
- intoResult = intoResult.append(longToIntForHashCode(maker, fieldAccessor, createFieldAccessor(maker, fieldNode, useFieldsDirectly)));
+ intoResult = intoResult.append(longToIntForHashCode(maker, fieldAccessor, createFieldAccessor(maker, fieldNode, fieldAccess)));
break;
case FLOAT:
/* Float.floatToIntBits(this.fieldName) */
@@ -296,7 +298,7 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd
maker.Apply(List.<JCExpression>nil(), hcMethod, List.of(fieldAccessor)));
} else /* objects */ {
/* this.fieldName == null ? 0 : this.fieldName.hashCode() */
- JCExpression hcCall = maker.Apply(List.<JCExpression>nil(), maker.Select(createFieldAccessor(maker, fieldNode, useFieldsDirectly), typeNode.toName("hashCode")),
+ JCExpression hcCall = maker.Apply(List.<JCExpression>nil(), maker.Select(createFieldAccessor(maker, fieldNode, fieldAccess), typeNode.toName("hashCode")),
List.<JCExpression>nil());
JCExpression thisEqualsNull = maker.Binary(JCTree.EQ, fieldAccessor, maker.Literal(TypeTags.BOT, null));
intoResult = intoResult.append(
@@ -329,7 +331,7 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd
return maker.TypeCast(maker.TypeIdent(TypeTags.INT), xorBits);
}
- private JCMethodDecl createEquals(JavacNode typeNode, List<JavacNode> fields, boolean callSuper, boolean useFieldsDirectly, boolean needsCanEqual) {
+ private JCMethodDecl createEquals(JavacNode typeNode, List<JavacNode> fields, boolean callSuper, FieldAccess fieldAccess, boolean needsCanEqual) {
TreeMaker maker = typeNode.getTreeMaker();
JCClassDecl type = (JCClassDecl) typeNode.get();
@@ -398,9 +400,9 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd
}
for (JavacNode fieldNode : fields) {
- JCExpression fType = getFieldType(fieldNode, useFieldsDirectly);
- JCExpression thisFieldAccessor = createFieldAccessor(maker, fieldNode, useFieldsDirectly);
- JCExpression otherFieldAccessor = createFieldAccessor(maker, fieldNode, useFieldsDirectly, maker.Ident(otherName));
+ JCExpression fType = getFieldType(fieldNode, fieldAccess);
+ JCExpression thisFieldAccessor = createFieldAccessor(maker, fieldNode, fieldAccess);
+ JCExpression otherFieldAccessor = createFieldAccessor(maker, fieldNode, fieldAccess, maker.Ident(otherName));
if (fType instanceof JCPrimitiveTypeTree) {
switch (((JCPrimitiveTypeTree)fType).getPrimitiveTypeKind()) {
case FLOAT:
@@ -432,8 +434,8 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd
JCExpression thisEqualsNull = maker.Binary(JCTree.EQ, thisFieldAccessor, maker.Literal(TypeTags.BOT, null));
JCExpression otherNotEqualsNull = maker.Binary(JCTree.NE, otherFieldAccessor, maker.Literal(TypeTags.BOT, null));
JCExpression thisEqualsThat = maker.Apply(List.<JCExpression>nil(),
- maker.Select(createFieldAccessor(maker, fieldNode, useFieldsDirectly), typeNode.toName("equals")),
- List.of(createFieldAccessor(maker, fieldNode, useFieldsDirectly, maker.Ident(otherName))));
+ maker.Select(createFieldAccessor(maker, fieldNode, fieldAccess), typeNode.toName("equals")),
+ List.of(createFieldAccessor(maker, fieldNode, fieldAccess, maker.Ident(otherName))));
JCExpression fieldsAreNotEqual = maker.Conditional(thisEqualsNull, otherNotEqualsNull, maker.Unary(JCTree.NOT, thisEqualsThat));
statements = statements.append(maker.If(fieldsAreNotEqual, returnBool(maker, false), null));
}
diff --git a/src/core/lombok/javac/handlers/HandleGetter.java b/src/core/lombok/javac/handlers/HandleGetter.java
index 79e842dc..ab4bcb60 100644
--- a/src/core/lombok/javac/handlers/HandleGetter.java
+++ b/src/core/lombok/javac/handlers/HandleGetter.java
@@ -24,6 +24,9 @@ package lombok.javac.handlers;
import static lombok.javac.handlers.JavacHandlerUtil.*;
import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
import lombok.AccessLevel;
import lombok.Getter;
@@ -33,17 +36,28 @@ import lombok.core.handlers.TransformationsUtil;
import lombok.javac.Javac;
import lombok.javac.JavacAnnotationHandler;
import lombok.javac.JavacNode;
+import lombok.javac.handlers.JavacHandlerUtil.FieldAccess;
import org.mangosdk.spi.ProviderFor;
import com.sun.tools.javac.code.Flags;
+import com.sun.tools.javac.code.TypeTags;
+import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
+import com.sun.tools.javac.tree.JCTree.JCBinary;
import com.sun.tools.javac.tree.JCTree.JCBlock;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
+import com.sun.tools.javac.tree.JCTree.JCIf;
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
+import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
+import com.sun.tools.javac.tree.JCTree.JCNewClass;
+import com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree;
import com.sun.tools.javac.tree.JCTree.JCStatement;
+import com.sun.tools.javac.tree.JCTree.JCSynchronized;
+import com.sun.tools.javac.tree.JCTree.JCTypeApply;
import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.util.List;
@@ -78,7 +92,7 @@ public class HandleGetter implements JavacAnnotationHandler<Getter> {
}
for (JavacNode field : typeNode.down()) {
- if (fieldQualifiesForGetterGeneration(field)) generateGetterForField(field, errorNode.get(), level, List.<JCExpression>nil());
+ if (fieldQualifiesForGetterGeneration(field)) generateGetterForField(field, errorNode.get(), level, List.<JCExpression>nil(), false);
}
return true;
@@ -108,8 +122,9 @@ public class HandleGetter implements JavacAnnotationHandler<Getter> {
*
* @param fieldNode The node representing the field you want a getter for.
* @param pos The node responsible for generating the getter (the {@code @Data} or {@code @Getter} annotation).
+ * @param lazy
*/
- public void generateGetterForField(JavacNode fieldNode, DiagnosticPosition pos, AccessLevel level, List<JCExpression> onMethod) {
+ public void generateGetterForField(JavacNode fieldNode, DiagnosticPosition pos, AccessLevel level, List<JCExpression> onMethod, boolean lazy) {
for (JavacNode child : fieldNode.down()) {
if (child.getKind() == Kind.ANNOTATION) {
if (Javac.annotationTypeMatches(Getter.class, child)) {
@@ -119,7 +134,7 @@ public class HandleGetter implements JavacAnnotationHandler<Getter> {
}
}
- createGetterForField(level, fieldNode, fieldNode, false, onMethod);
+ createGetterForField(level, fieldNode, fieldNode, false, onMethod, lazy);
}
@Override public boolean handle(AnnotationValues<Getter> annotation, JCAnnotation ast, JavacNode annotationNode) {
@@ -127,38 +142,58 @@ public class HandleGetter implements JavacAnnotationHandler<Getter> {
markAnnotationAsProcessed(annotationNode, Getter.class);
deleteImportFromCompilationUnit(annotationNode, "lombok.AccessLevel");
JavacNode node = annotationNode.up();
- AccessLevel level = annotation.getInstance().value();
- if (level == AccessLevel.NONE) return true;
+ Getter annotationInstance = annotation.getInstance();
+ AccessLevel level = annotationInstance.value();
+ boolean lazy = annotationInstance.lazy();
+ if (level == AccessLevel.NONE) {
+ if (lazy) {
+ annotationNode.addWarning("'lazy' does not work with AccessLevel.NONE.");
+ }
+ return true;
+ }
if (node == null) return false;
List<JCExpression> onMethod = getAndRemoveAnnotationParameter(ast, "onMethod");
if (node.getKind() == Kind.FIELD) {
- return createGetterForFields(level, fields, annotationNode, true, onMethod);
+ return createGetterForFields(level, fields, annotationNode, true, onMethod, lazy);
}
if (node.getKind() == Kind.TYPE) {
if (!onMethod.isEmpty()) annotationNode.addError("'onMethod' is not supported for @Getter on a type.");
+ if (lazy) annotationNode.addError("'lazy' is not supported for @Getter on a type.");
return generateGetterForType(node, annotationNode, level, false);
}
return false;
}
- private boolean createGetterForFields(AccessLevel level, Collection<JavacNode> fieldNodes, JavacNode errorNode, boolean whineIfExists, List<JCExpression> onMethod) {
+ private boolean createGetterForFields(AccessLevel level, Collection<JavacNode> fieldNodes, JavacNode errorNode, boolean whineIfExists, List<JCExpression> onMethod, boolean lazy) {
for (JavacNode fieldNode : fieldNodes) {
- createGetterForField(level, fieldNode, errorNode, whineIfExists, onMethod);
+ createGetterForField(level, fieldNode, errorNode, whineIfExists, onMethod, lazy);
}
return true;
}
private boolean createGetterForField(AccessLevel level,
- JavacNode fieldNode, JavacNode errorNode, boolean whineIfExists, List<JCExpression> onMethod) {
+ JavacNode fieldNode, JavacNode errorNode, boolean whineIfExists, List<JCExpression> onMethod, boolean lazy) {
if (fieldNode.getKind() != Kind.FIELD) {
errorNode.addError("@Getter is only supported on a class or a field.");
return true;
}
JCVariableDecl fieldDecl = (JCVariableDecl)fieldNode.get();
+
+ if (lazy) {
+ if ((fieldDecl.mods.flags & Flags.PRIVATE) == 0 || (fieldDecl.mods.flags & Flags.FINAL) == 0) {
+ errorNode.addError("'lazy' requires the field to be private and final.");
+ return true;
+ }
+ if (fieldDecl.init == null) {
+ errorNode.addError("'lazy' requires field initialization.");
+ return true;
+ }
+ }
+
String methodName = toGetterName(fieldDecl);
for (String altName : toAllGetterNames(fieldDecl)) {
@@ -181,19 +216,27 @@ public class HandleGetter implements JavacAnnotationHandler<Getter> {
long access = toJavacModifier(level) | (fieldDecl.mods.flags & Flags.STATIC);
- injectMethod(fieldNode.up(), createGetter(access, fieldNode, fieldNode.getTreeMaker(), onMethod));
+ injectMethod(fieldNode.up(), createGetter(access, fieldNode, fieldNode.getTreeMaker(), onMethod, lazy));
return true;
}
- private JCMethodDecl createGetter(long access, JavacNode field, TreeMaker treeMaker, List<JCExpression> onMethod) {
+
+ private JCMethodDecl createGetter(long access, JavacNode field, TreeMaker treeMaker, List<JCExpression> onMethod, boolean lazy) {
JCVariableDecl fieldNode = (JCVariableDecl) field.get();
- JCExpression fieldRef = createFieldAccessor(treeMaker, field, true);
- JCStatement returnStatement = treeMaker.Return(fieldRef);
- JCBlock methodBody = treeMaker.Block(0, List.of(returnStatement));
+ // Remember the type; lazy will change it;
+ JCExpression methodType = copyType(treeMaker, fieldNode);
+
+ List<JCStatement> statements;
+ if (lazy) {
+ statements = createLazyGetterBody(treeMaker, field);
+ } else {
+ statements = createSimpleGetterBody(treeMaker, field);
+ }
+
+ JCBlock methodBody = treeMaker.Block(0, statements);
Name methodName = field.toName(toGetterName(fieldNode));
- JCExpression methodType = fieldNode.type != null ? treeMaker.Type(fieldNode.type) : fieldNode.vartype;
List<JCTypeParameter> methodGenericParams = List.nil();
List<JCVariableDecl> parameters = List.nil();
@@ -208,4 +251,120 @@ public class HandleGetter implements JavacAnnotationHandler<Getter> {
return treeMaker.MethodDef(treeMaker.Modifiers(access, annsOnMethod), methodName, methodType,
methodGenericParams, parameters, throwsClauses, methodBody, annotationMethodDefaultValue);
}
+
+ private List<JCStatement> createSimpleGetterBody(TreeMaker treeMaker, JavacNode field) {
+ return List.<JCStatement>of(treeMaker.Return(createFieldAccessor(treeMaker, field, FieldAccess.ALWAYS_FIELD)));
+ }
+
+ private static final String AR = "java.util.concurrent.atomic.AtomicReference";
+ private static final List<JCExpression> NIL_EXPRESSION = List.nil();
+
+ private static final java.util.Map<Integer, String> TYPE_MAP;
+ static {
+ Map<Integer, String> m = new HashMap<Integer, String>();
+ m.put(TypeTags.INT, "java.lang.Integer");
+ m.put(TypeTags.DOUBLE, "java.lang.Double");
+ m.put(TypeTags.FLOAT, "java.lang.Float");
+ m.put(TypeTags.SHORT, "java.lang.Short");
+ m.put(TypeTags.BYTE, "java.lang.Byte");
+ m.put(TypeTags.LONG, "java.lang.Long");
+ m.put(TypeTags.BOOLEAN, "java.lang.Boolean");
+ m.put(TypeTags.CHAR, "java.lang.Character");
+ TYPE_MAP = Collections.unmodifiableMap(m);
+ }
+
+ private List<JCStatement> createLazyGetterBody(TreeMaker maker, JavacNode fieldNode) {
+ /*
+ java.util.concurrent.atomic.AtomicReference<ValueType> value = this.fieldName.get();
+ if (value == null) {
+ synchronized (this.fieldName) {
+ value = this.fieldName.get();
+ if (value == null) {
+ value = new java.util.concurrent.atomic.AtomicReference<ValueType>(new ValueType());
+ this.fieldName.set(value);
+ }
+ }
+ }
+ return value.get();
+ */
+
+ List<JCStatement> statements = List.nil();
+
+ JCVariableDecl field = (JCVariableDecl) fieldNode.get();
+ field.type = null;
+ if (field.vartype instanceof JCPrimitiveTypeTree) {
+ String boxed = TYPE_MAP.get(((JCPrimitiveTypeTree)field.vartype).typetag);
+ if (boxed != null) {
+ field.vartype = chainDotsString(maker, fieldNode, boxed);
+ }
+ }
+
+ Name valueName = fieldNode.toName("value");
+
+ /* java.util.concurrent.atomic.AtomicReference<ValueType> value = this.fieldName.get();*/ {
+ JCTypeApply valueVarType = maker.TypeApply(chainDotsString(maker, fieldNode, AR), List.of(copyType(maker, field)));
+ statements = statements.append(maker.VarDef(maker.Modifiers(0), valueName, valueVarType, callGet(fieldNode, createFieldAccessor(maker, fieldNode, FieldAccess.ALWAYS_FIELD))));
+ }
+
+ /* if (value == null) { */ {
+ JCSynchronized synchronizedStatement;
+ /* synchronized (this.fieldName) { */ {
+ List<JCStatement> synchronizedStatements = List.nil();
+ /* value = this.fieldName.get(); */ {
+ JCExpressionStatement newAssign = maker.Exec(maker.Assign(maker.Ident(valueName), callGet(fieldNode, createFieldAccessor(maker, fieldNode, FieldAccess.ALWAYS_FIELD))));
+ synchronizedStatements = synchronizedStatements.append(newAssign);
+ }
+
+ /* if (value == null) { */ {
+ List<JCStatement> innerIfStatements = List.nil();
+ /* value = new java.util.concurrent.atomic.AtomicReference<ValueType>(new ValueType());*/ {
+ JCTypeApply valueVarType = maker.TypeApply(chainDotsString(maker, fieldNode, AR), List.of(copyType(maker, field)));
+ JCNewClass newInstance = maker.NewClass(null, NIL_EXPRESSION, valueVarType, List.<JCExpression>of(field.init), null);
+
+ JCStatement statement = maker.Exec(maker.Assign(maker.Ident(valueName), newInstance));
+ innerIfStatements = innerIfStatements.append(statement);
+ }
+ /* this.fieldName.set(value); */ {
+ JCStatement statement = callSet(fieldNode, createFieldAccessor(maker, fieldNode, FieldAccess.ALWAYS_FIELD), maker.Ident(valueName));
+ innerIfStatements = innerIfStatements.append(statement);
+ }
+
+ JCBinary isNull = maker.Binary(JCTree.EQ, maker.Ident(valueName), maker.Literal(TypeTags.BOT, null));
+ JCIf ifStatement = maker.If(isNull, maker.Block(0, innerIfStatements), null);
+ synchronizedStatements = synchronizedStatements.append(ifStatement);
+ }
+
+ synchronizedStatement = maker.Synchronized(createFieldAccessor(maker, fieldNode, FieldAccess.ALWAYS_FIELD), maker.Block(0, synchronizedStatements));
+ }
+
+ JCBinary isNull = maker.Binary(JCTree.EQ, maker.Ident(valueName), maker.Literal(TypeTags.BOT, null));
+ JCIf ifStatement = maker.If(isNull, maker.Block(0, List.<JCStatement>of(synchronizedStatement)), null);
+ statements = statements.append(ifStatement);
+ }
+ /* return value.get(); */
+ statements = statements.append(maker.Return(callGet(fieldNode, maker.Ident(valueName))));
+
+ // update the field type and init last
+
+ /* private final java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<ValueType> fieldName = new java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<ValueType>>(); */ {
+ field.vartype = maker.TypeApply(chainDotsString(maker, fieldNode, AR), List.<JCExpression>of(maker.TypeApply(chainDotsString(maker, fieldNode, AR), List.of(copyType(maker, field)))));
+ field.init = maker.NewClass(null, NIL_EXPRESSION, copyType(maker, field), NIL_EXPRESSION, null);
+ }
+
+ return statements;
+ }
+
+ private JCMethodInvocation callGet(JavacNode source, JCExpression receiver) {
+ TreeMaker maker = source.getTreeMaker();
+ return maker.Apply(NIL_EXPRESSION, maker.Select(receiver, source.toName("get")), NIL_EXPRESSION);
+ }
+
+ private JCStatement callSet(JavacNode source, JCExpression receiver, JCExpression value) {
+ TreeMaker maker = source.getTreeMaker();
+ return maker.Exec(maker.Apply(NIL_EXPRESSION, maker.Select(receiver, source.toName("set")), List.<JCExpression>of(value)));
+ }
+
+ private JCExpression copyType(TreeMaker treeMaker, JCVariableDecl fieldNode) {
+ return fieldNode.type != null ? treeMaker.Type(fieldNode.type) : fieldNode.vartype;
+ }
}
diff --git a/src/core/lombok/javac/handlers/HandleSetter.java b/src/core/lombok/javac/handlers/HandleSetter.java
index af6f546d..e6a39577 100644
--- a/src/core/lombok/javac/handlers/HandleSetter.java
+++ b/src/core/lombok/javac/handlers/HandleSetter.java
@@ -38,6 +38,7 @@ import lombok.core.handlers.TransformationsUtil;
import lombok.javac.Javac;
import lombok.javac.JavacAnnotationHandler;
import lombok.javac.JavacNode;
+import lombok.javac.handlers.JavacHandlerUtil.FieldAccess;
import org.mangosdk.spi.ProviderFor;
@@ -197,7 +198,7 @@ public class HandleSetter implements JavacAnnotationHandler<Setter> {
private JCMethodDecl createSetter(long access, JavacNode field, TreeMaker treeMaker, List<JCExpression> onMethod, List<JCExpression> onParam) {
JCVariableDecl fieldDecl = (JCVariableDecl) field.get();
- JCExpression fieldRef = createFieldAccessor(treeMaker, field, true);
+ JCExpression fieldRef = createFieldAccessor(treeMaker, field, FieldAccess.ALWAYS_FIELD);
JCAssign assign = treeMaker.Assign(fieldRef, treeMaker.Ident(fieldDecl.name));
List<JCStatement> statements;
diff --git a/src/core/lombok/javac/handlers/HandleToString.java b/src/core/lombok/javac/handlers/HandleToString.java
index e3cb0294..64200904 100644
--- a/src/core/lombok/javac/handlers/HandleToString.java
+++ b/src/core/lombok/javac/handlers/HandleToString.java
@@ -29,6 +29,7 @@ import lombok.core.AST.Kind;
import lombok.javac.Javac;
import lombok.javac.JavacAnnotationHandler;
import lombok.javac.JavacNode;
+import lombok.javac.handlers.JavacHandlerUtil.FieldAccess;
import org.mangosdk.spi.ProviderFor;
@@ -88,7 +89,9 @@ public class HandleToString implements JavacAnnotationHandler<ToString> {
annotation.setWarning("exclude", "exclude and of are mutually exclusive; the 'exclude' parameter will be ignored.");
}
- return generateToString(typeNode, annotationNode, excludes, includes, ann.includeFieldNames(), callSuper, true, ann.doNotUseGetters());
+ FieldAccess fieldAccess = ann.doNotUseGetters() ? FieldAccess.PREFER_FIELD : FieldAccess.GETTER;
+
+ return generateToString(typeNode, annotationNode, excludes, includes, ann.includeFieldNames(), callSuper, true, fieldAccess);
}
public void generateToStringForType(JavacNode typeNode, JavacNode errorNode) {
@@ -105,11 +108,11 @@ public class HandleToString implements JavacAnnotationHandler<ToString> {
try {
includeFieldNames = ((Boolean)ToString.class.getMethod("includeFieldNames").getDefaultValue()).booleanValue();
} catch (Exception ignore) {}
- generateToString(typeNode, errorNode, null, null, includeFieldNames, null, false, false);
+ generateToString(typeNode, errorNode, null, null, includeFieldNames, null, false, FieldAccess.GETTER);
}
private boolean generateToString(JavacNode typeNode, JavacNode errorNode, List<String> excludes, List<String> includes,
- boolean includeFieldNames, Boolean callSuper, boolean whineIfExists, boolean useFieldsDirectly) {
+ boolean includeFieldNames, Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess) {
boolean notAClass = true;
if (typeNode.get() instanceof JCClassDecl) {
long flags = ((JCClassDecl)typeNode.get()).mods.flags;
@@ -150,7 +153,7 @@ public class HandleToString implements JavacAnnotationHandler<ToString> {
switch (methodExists("toString", typeNode)) {
case NOT_EXISTS:
- JCMethodDecl method = createToString(typeNode, nodesForToString, includeFieldNames, callSuper, useFieldsDirectly);
+ JCMethodDecl method = createToString(typeNode, nodesForToString, includeFieldNames, callSuper, fieldAccess);
injectMethod(typeNode, method);
return true;
case EXISTS_BY_LOMBOK:
@@ -165,7 +168,7 @@ public class HandleToString implements JavacAnnotationHandler<ToString> {
}
- private JCMethodDecl createToString(JavacNode typeNode, List<JavacNode> fields, boolean includeFieldNames, boolean callSuper, boolean useFieldsDirectly) {
+ private JCMethodDecl createToString(JavacNode typeNode, List<JavacNode> fields, boolean includeFieldNames, boolean callSuper, FieldAccess fieldAccess) {
TreeMaker maker = typeNode.getTreeMaker();
JCAnnotation overrideAnnotation = maker.Annotation(chainDots(maker, typeNode, "java", "lang", "Override"), List.<JCExpression>nil());
@@ -202,9 +205,9 @@ public class HandleToString implements JavacAnnotationHandler<ToString> {
JCVariableDecl field = (JCVariableDecl) fieldNode.get();
JCExpression expr;
- JCExpression fieldAccessor = createFieldAccessor(maker, fieldNode, useFieldsDirectly);
+ JCExpression fieldAccessor = createFieldAccessor(maker, fieldNode, fieldAccess);
- if (getFieldType(fieldNode, useFieldsDirectly) instanceof JCArrayTypeTree) {
+ if (getFieldType(fieldNode, fieldAccess) instanceof JCArrayTypeTree) {
boolean multiDim = ((JCArrayTypeTree)field.vartype).elemtype instanceof JCArrayTypeTree;
boolean primitiveArray = ((JCArrayTypeTree)field.vartype).elemtype instanceof JCPrimitiveTypeTree;
boolean useDeepTS = multiDim || !primitiveArray;
diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
index bf356853..d1884e5c 100644
--- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java
+++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
@@ -345,13 +345,34 @@ public class JavacHandlerUtil {
return null;
}
+ enum FieldAccess {
+ GETTER, PREFER_FIELD, ALWAYS_FIELD;
+ }
+
+ static boolean lookForGetter(JavacNode field, FieldAccess fieldAccess) {
+ if (fieldAccess == FieldAccess.GETTER) return true;
+ if (fieldAccess == FieldAccess.ALWAYS_FIELD) return false;
+
+ // If @Getter(lazy = true) is used, then using it is mandatory.
+ for (JavacNode child : field.down()) {
+ if (child.getKind() != Kind.ANNOTATION) continue;
+ if (Javac.annotationTypeMatches(Getter.class, child)) {
+ AnnotationValues<Getter> ann = Javac.createAnnotation(Getter.class, child);
+ if (ann.getInstance().lazy()) return true;
+ }
+ }
+ return false;
+ }
+
/**
* Returns the type of the field, unless a getter exists for this field, in which case the return type of the getter is returned.
*
* @see #createFieldAccessor(TreeMaker, JavacNode)
*/
- static JCExpression getFieldType(JavacNode field, boolean useFieldsDirectly) {
- GetterMethod getter = useFieldsDirectly ? null : findGetter(field);
+ static JCExpression getFieldType(JavacNode field, FieldAccess fieldAccess) {
+ boolean lookForGetter = lookForGetter(field, fieldAccess);
+
+ GetterMethod getter = lookForGetter ? findGetter(field) : null;
if (getter == null) {
return ((JCVariableDecl)field.get()).vartype;
@@ -363,12 +384,14 @@ public class JavacHandlerUtil {
/**
* Creates an expression that reads the field. Will either be {@code this.field} or {@code this.getField()} depending on whether or not there's a getter.
*/
- static JCExpression createFieldAccessor(TreeMaker maker, JavacNode field, boolean useFieldsDirectly) {
- return createFieldAccessor(maker, field, useFieldsDirectly, null);
+ static JCExpression createFieldAccessor(TreeMaker maker, JavacNode field, FieldAccess fieldAccess) {
+ return createFieldAccessor(maker, field, fieldAccess, null);
}
- static JCExpression createFieldAccessor(TreeMaker maker, JavacNode field, boolean useFieldsDirectly, JCExpression receiver) {
- GetterMethod getter = useFieldsDirectly ? null : findGetter(field);
+ static JCExpression createFieldAccessor(TreeMaker maker, JavacNode field, FieldAccess fieldAccess, JCExpression receiver) {
+ boolean lookForGetter = lookForGetter(field, fieldAccess);
+
+ GetterMethod getter = lookForGetter ? findGetter(field) : null;
JCVariableDecl fieldDecl = (JCVariableDecl) field.get();
if (getter == null) {