Merge branch 'master' into delegate

This commit is contained in:
Reinier Zwitserloot committed 2010-11-11 18:04:00 +01:00
commit b30f8e351b
26 files changed
+1194 -104

No files matched your search

+2
View File
@@ -65,6 +65,8 @@ public @interface Getter {
*/
AnyAnnotation[] onMethod() default {};
boolean lazy() default false;
/**
* Placeholder annotation to enable the placement of annotations on the getter method.
* @deprecated Don't use this annotation, since we might remove it.
+38 -12
View File
@@ -352,16 +352,24 @@ public class Eclipse {
if (base != null) {
if (dims > 0) {
return new ArrayTypeReference(base, dims, pos(pos));
TypeReference result = new ArrayTypeReference(base, dims, pos(pos));
Eclipse.setGeneratedBy(result, pos);
return result;
}
return new SingleTypeReference(base, pos(pos));
TypeReference result = new SingleTypeReference(base, pos(pos));
Eclipse.setGeneratedBy(result, pos);
return result;
}
if (binding.isAnonymousType()) {
ReferenceBinding ref = (ReferenceBinding)binding;
ReferenceBinding[] supers = ref.superInterfaces();
if (supers == null || supers.length == 0) supers = new ReferenceBinding[] {ref.superclass()};
if (supers[0] == null) return new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, poss(pos, 3));
if (supers[0] == null) {
TypeReference result = new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, poss(pos, 3));
Eclipse.setGeneratedBy(result, pos);
return result;
}
return makeType(supers[0], pos, false);
}
@@ -371,9 +379,12 @@ public class Eclipse {
if (binding.isUnboundWildcard()) {
if (!allowCompound) {
return new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, poss(pos, 3));
TypeReference result = new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, poss(pos, 3));
Eclipse.setGeneratedBy(result, pos);
return result;
} else {
Wildcard out = new Wildcard(Wildcard.UNBOUND);
Eclipse.setGeneratedBy(out, pos);
out.sourceStart = pos.sourceStart;
out.sourceEnd = pos.sourceEnd;
return out;
@@ -387,6 +398,7 @@ public class Eclipse {
return makeType(wildcard.bound, pos, false);
} else {
Wildcard out = new Wildcard(Wildcard.EXTENDS);
Eclipse.setGeneratedBy(out, pos);
out.bound = makeType(wildcard.bound, pos, false);
out.sourceStart = pos.sourceStart;
out.sourceEnd = pos.sourceEnd;
@@ -394,12 +406,15 @@ public class Eclipse {
}
} else if (allowCompound && wildcard.boundKind == Wildcard.SUPER) {
Wildcard out = new Wildcard(Wildcard.SUPER);
Eclipse.setGeneratedBy(out, pos);
out.bound = makeType(wildcard.bound, pos, false);
out.sourceStart = pos.sourceStart;
out.sourceEnd = pos.sourceEnd;
return out;
} else {
return new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, poss(pos, 3));
TypeReference result = new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, poss(pos, 3));
Eclipse.setGeneratedBy(result, pos);
return result;
}
}
@@ -433,23 +448,34 @@ public class Eclipse {
if (parts.length > 1) {
TypeReference[][] typeArguments = new TypeReference[parts.length][];
typeArguments[typeArguments.length - 1] = params;
return new ParameterizedQualifiedTypeReference(parts, typeArguments, dims, poss(pos, parts.length));
TypeReference result = new ParameterizedQualifiedTypeReference(parts, typeArguments, dims, poss(pos, parts.length));
Eclipse.setGeneratedBy(result, pos);
return result;
}
return new ParameterizedSingleTypeReference(parts[0], params, dims, pos(pos));
TypeReference result = new ParameterizedSingleTypeReference(parts[0], params, dims, pos(pos));
Eclipse.setGeneratedBy(result, pos);
return result;
}
if (dims > 0) {
if (parts.length > 1) {
return new ArrayQualifiedTypeReference(parts, dims, poss(pos, parts.length));
TypeReference result = new ArrayQualifiedTypeReference(parts, dims, poss(pos, parts.length));
Eclipse.setGeneratedBy(result, pos);
return result;
}
return new ArrayTypeReference(parts[0], dims, pos(pos));
TypeReference result = new ArrayTypeReference(parts[0], dims, pos(pos));
Eclipse.setGeneratedBy(result, pos);
return result;
}
if (parts.length > 1) {
return new QualifiedTypeReference(parts, poss(pos, parts.length));
TypeReference result = new QualifiedTypeReference(parts, poss(pos, parts.length));
Eclipse.setGeneratedBy(result, pos);
return result;
}
return new SingleTypeReference(parts[0], pos(pos));
TypeReference result = new SingleTypeReference(parts[0], pos(pos));
Eclipse.setGeneratedBy(result, pos);
return result;
}
private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
@@ -175,8 +175,29 @@ public class EclipseHandlerUtil {
return null;
}
static TypeReference getFieldType(EclipseNode field, boolean useFieldsDirectly) {
GetterMethod getter = useFieldsDirectly ? null : findGetter(field);
enum FieldAccess {
GETTER, PREFER_FIELD, ALWAYS_FIELD;
}
static boolean lookForGetter(EclipseNode 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 (EclipseNode child : field.down()) {
if (child.getKind() != Kind.ANNOTATION) continue;
if (Eclipse.annotationTypeMatches(Getter.class, child)) {
AnnotationValues<Getter> ann = Eclipse.createAnnotation(Getter.class, child);
if (ann.getInstance().lazy()) return true;
}
}
return false;
}
static TypeReference getFieldType(EclipseNode field, FieldAccess fieldAccess) {
boolean lookForGetter = lookForGetter(field, fieldAccess);
GetterMethod getter = lookForGetter ? findGetter(field) : null;
if (getter == null) {
return ((FieldDeclaration)field.get()).type;
}
@@ -184,11 +205,13 @@ public class EclipseHandlerUtil {
return getter.type;
}
static Expression createFieldAccessor(EclipseNode field, boolean useFieldsDirectly, ASTNode source) {
static Expression createFieldAccessor(EclipseNode field, FieldAccess fieldAccess, ASTNode source) {
int pS = source.sourceStart, pE = source.sourceEnd;
long p = (long)pS << 32 | pE;
GetterMethod getter = useFieldsDirectly ? null : findGetter(field);
boolean lookForGetter = lookForGetter(field, fieldAccess);
GetterMethod getter = lookForGetter ? findGetter(field) : null;
if (getter == null) {
FieldDeclaration fieldDecl = (FieldDeclaration)field.get();
@@ -219,11 +242,13 @@ public class EclipseHandlerUtil {
return call;
}
static Expression createFieldAccessor(EclipseNode field, boolean useFieldsDirectly, ASTNode source, char[] receiver) {
static Expression createFieldAccessor(EclipseNode field, FieldAccess fieldAccess, ASTNode source, char[] receiver) {
int pS = source.sourceStart, pE = source.sourceEnd;
long p = (long)pS << 32 | pE;
GetterMethod getter = useFieldsDirectly ? null : findGetter(field);
boolean lookForGetter = lookForGetter(field, fieldAccess);
GetterMethod getter = lookForGetter ? findGetter(field) : null;
if (getter == null) {
NameReference ref;
@@ -113,7 +113,7 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA
}
}
generateMethods(typeNode, errorNode, null, null, null, false, false);
generateMethods(typeNode, errorNode, null, null, null, false, FieldAccess.GETTER);
}
@Override public boolean handle(AnnotationValues<EqualsAndHashCode> annotation,
@@ -135,11 +135,13 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA
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 boolean generateMethods(EclipseNode typeNode, EclipseNode errorNode, List<String> excludes, List<String> includes,
Boolean callSuper, boolean whineIfExists, boolean useFieldsDirectly) {
Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess) {
assert excludes == null || includes == null;
TypeDeclaration typeDecl = null;
@@ -209,7 +211,7 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA
boolean isFinal = (typeDecl.modifiers & ClassFileConstants.AccFinal) != 0;
needsCanEqual = !isDirectDescendantOfObject || !isFinal;
MethodDeclaration equals = createEquals(typeNode, nodesForEquality, callSuper, errorNode.get(), useFieldsDirectly, needsCanEqual);
MethodDeclaration equals = createEquals(typeNode, nodesForEquality, callSuper, errorNode.get(), fieldAccess, needsCanEqual);
injectMethod(typeNode, equals);
break;
case EXISTS_BY_LOMBOK:
@@ -237,7 +239,7 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA
switch (methodExists("hashCode", typeNode)) {
case NOT_EXISTS:
MethodDeclaration hashCode = createHashCode(typeNode, nodesForEquality, callSuper, errorNode.get(), useFieldsDirectly);
MethodDeclaration hashCode = createHashCode(typeNode, nodesForEquality, callSuper, errorNode.get(), fieldAccess);
injectMethod(typeNode, hashCode);
break;
case EXISTS_BY_LOMBOK:
@@ -253,7 +255,7 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA
return true;
}
private MethodDeclaration createHashCode(EclipseNode type, Collection<EclipseNode> fields, boolean callSuper, ASTNode source, boolean useFieldsDirectly) {
private MethodDeclaration createHashCode(EclipseNode type, Collection<EclipseNode> fields, boolean callSuper, ASTNode source, FieldAccess fieldAccess) {
int pS = source.sourceStart, pE = source.sourceEnd;
long p = (long)pS << 32 | pE;
@@ -318,9 +320,9 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA
int tempCounter = 0;
for (EclipseNode field : fields) {
TypeReference fType = getFieldType(field, useFieldsDirectly);
TypeReference fType = getFieldType(field, fieldAccess);
char[] token = fType.getLastToken();
Expression fieldAccessor = createFieldAccessor(field, useFieldsDirectly, source);
Expression fieldAccessor = createFieldAccessor(field, fieldAccess, source);
if (fType.dimensions() == 0 && token != null) {
if (Arrays.equals(TypeConstants.FLOAT, token)) {
/* Float.floatToIntBits(fieldName) */
@@ -363,7 +365,7 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA
Eclipse.setGeneratedBy(int1231or1237, source);
intoResult.add(int1231or1237);
} else if (Arrays.equals(TypeConstants.LONG, token)) {
intoResult.add(longToIntForHashCode(fieldAccessor, createFieldAccessor(field, useFieldsDirectly, source), source));
intoResult.add(longToIntForHashCode(fieldAccessor, createFieldAccessor(field, fieldAccess, source), source));
} else if (BUILT_IN_TYPES.contains(new String(token))) {
intoResult.add(fieldAccessor);
} else /* objects */ {
@@ -371,7 +373,7 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA
MessageSend hashCodeCall = new MessageSend();
hashCodeCall.sourceStart = pS; hashCodeCall.sourceEnd = pE;
Eclipse.setGeneratedBy(hashCodeCall, source);
hashCodeCall.receiver = createFieldAccessor(field, useFieldsDirectly, source);
hashCodeCall.receiver = createFieldAccessor(field, fieldAccess, source);
hashCodeCall.selector = "hashCode".toCharArray();
NullLiteral nullLiteral = new NullLiteral(pS, pE);
Eclipse.setGeneratedBy(nullLiteral, source);
@@ -433,7 +435,7 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA
return method;
}
private MethodDeclaration createEquals(EclipseNode type, Collection<EclipseNode> fields, boolean callSuper, ASTNode source, boolean useFieldsDirectly, boolean needsCanEqual) {
private MethodDeclaration createEquals(EclipseNode type, Collection<EclipseNode> fields, boolean callSuper, ASTNode source, FieldAccess fieldAccess, boolean needsCanEqual) {
int pS = source.sourceStart; int pE = source.sourceEnd;
long p = (long)pS << 32 | pE;
TypeDeclaration typeDecl = (TypeDeclaration)type.get();
@@ -589,10 +591,10 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA
}
for (EclipseNode field : fields) {
TypeReference fType = getFieldType(field, useFieldsDirectly);
TypeReference fType = getFieldType(field, fieldAccess);
char[] token = fType.getLastToken();
Expression thisFieldAccessor = createFieldAccessor(field, useFieldsDirectly, source);
Expression otherFieldAccessor = createFieldAccessor(field, useFieldsDirectly, source, otherName);
Expression thisFieldAccessor = createFieldAccessor(field, fieldAccess, source);
Expression otherFieldAccessor = createFieldAccessor(field, fieldAccess, source, otherName);
if (fType.dimensions() == 0 && token != null) {
if (Arrays.equals(TypeConstants.FLOAT, token)) {
@@ -619,9 +621,9 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandler<EqualsA
MessageSend equalsCall = new MessageSend();
equalsCall.sourceStart = pS; equalsCall.sourceEnd = pE;
Eclipse.setGeneratedBy(equalsCall, source);
equalsCall.receiver = createFieldAccessor(field, useFieldsDirectly, source);
equalsCall.receiver = createFieldAccessor(field, fieldAccess, source);
equalsCall.selector = "equals".toCharArray();
equalsCall.arguments = new Expression[] { createFieldAccessor(field, useFieldsDirectly, source, otherName) };
equalsCall.arguments = new Expression[] { createFieldAccessor(field, fieldAccess, source, otherName) };
UnaryExpression fieldsNotEqual = new UnaryExpression(equalsCall, OperatorIds.NOT);
fieldsNotEqual.sourceStart = pS; fieldsNotEqual.sourceEnd = pE;
Eclipse.setGeneratedBy(fieldsNotEqual, source);
@@ -25,6 +25,9 @@ import static lombok.eclipse.Eclipse.*;
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import lombok.AccessLevel;
import lombok.Getter;
@@ -34,14 +37,30 @@ import lombok.core.handlers.TransformationsUtil;
import lombok.eclipse.Eclipse;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;
import lombok.eclipse.handlers.EclipseHandlerUtil.FieldAccess;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference;
import org.eclipse.jdt.internal.compiler.ast.Assignment;
import org.eclipse.jdt.internal.compiler.ast.BinaryExpression;
import org.eclipse.jdt.internal.compiler.ast.Block;
import org.eclipse.jdt.internal.compiler.ast.EqualExpression;
import org.eclipse.jdt.internal.compiler.ast.Expression;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.ast.IfStatement;
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.NullLiteral;
import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
import org.eclipse.jdt.internal.compiler.ast.Statement;
import org.eclipse.jdt.internal.compiler.ast.SynchronizedStatement;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
@@ -76,7 +95,7 @@ public class HandleGetter implements EclipseAnnotationHandler<Getter> {
}
for (EclipseNode field : typeNode.down()) {
if (fieldQualifiesForGetterGeneration(field)) generateGetterForField(field, pos.get(), level, null);
if (fieldQualifiesForGetterGeneration(field)) generateGetterForField(field, pos.get(), level, null, false);
}
return true;
}
@@ -103,7 +122,7 @@ public class HandleGetter implements EclipseAnnotationHandler<Getter> {
* If not, the getter is still generated if it isn't already there, though there will not
* be a warning if its already there. The default access level is used.
*/
public void generateGetterForField(EclipseNode fieldNode, ASTNode pos, AccessLevel level, Annotation[] onMethod) {
public void generateGetterForField(EclipseNode fieldNode, ASTNode pos, AccessLevel level, Annotation[] onMethod, boolean lazy) {
for (EclipseNode child : fieldNode.down()) {
if (child.getKind() == Kind.ANNOTATION) {
if (annotationTypeMatches(Getter.class, child)) {
@@ -113,42 +132,61 @@ public class HandleGetter implements EclipseAnnotationHandler<Getter> {
}
}
createGetterForField(level, fieldNode, fieldNode, pos, false, onMethod);
createGetterForField(level, fieldNode, fieldNode, pos, false, onMethod, lazy);
}
public boolean handle(AnnotationValues<Getter> annotation, Annotation ast, EclipseNode annotationNode) {
EclipseNode 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;
Annotation[] onMethod = getAndRemoveAnnotationParameter(ast, "onMethod");
if (node.getKind() == Kind.FIELD) {
return createGetterForFields(level, annotationNode.upFromAnnotationToFields(), annotationNode, annotationNode.get(), true, onMethod);
return createGetterForFields(level, annotationNode.upFromAnnotationToFields(), annotationNode, annotationNode.get(), true, onMethod, lazy);
}
if (node.getKind() == Kind.TYPE) {
if (onMethod != null && onMethod.length != 0) 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<EclipseNode> fieldNodes, EclipseNode errorNode, ASTNode source, boolean whineIfExists, Annotation[] onMethod) {
private boolean createGetterForFields(AccessLevel level, Collection<EclipseNode> fieldNodes, EclipseNode errorNode, ASTNode source, boolean whineIfExists, Annotation[] onMethod, boolean lazy) {
for (EclipseNode fieldNode : fieldNodes) {
createGetterForField(level, fieldNode, errorNode, source, whineIfExists, onMethod);
createGetterForField(level, fieldNode, errorNode, source, whineIfExists, onMethod, lazy);
}
return true;
}
private boolean createGetterForField(AccessLevel level,
EclipseNode fieldNode, EclipseNode errorNode, ASTNode source, boolean whineIfExists, Annotation[] onMethod) {
EclipseNode fieldNode, EclipseNode errorNode, ASTNode source, boolean whineIfExists, Annotation[] onMethod, boolean lazy) {
if (fieldNode.getKind() != Kind.FIELD) {
errorNode.addError("@Getter is only supported on a class or a field.");
return true;
}
FieldDeclaration field = (FieldDeclaration) fieldNode.get();
if (lazy) {
if ((field.modifiers & ClassFileConstants.AccPrivate) == 0 || (field.modifiers & ClassFileConstants.AccFinal) == 0) {
errorNode.addError("'lazy' requires the field to be private and final.");
return true;
}
if (field.initialization == null) {
errorNode.addError("'lazy' requires field initialization.");
return true;
}
}
TypeReference fieldType = copyType(field.type, source);
String fieldName = new String(field.name);
boolean isBoolean = nameEquals(fieldType.getTypeName(), "boolean") && fieldType.dimensions() == 0;
@@ -174,7 +212,7 @@ public class HandleGetter implements EclipseAnnotationHandler<Getter> {
}
}
MethodDeclaration method = generateGetter((TypeDeclaration) fieldNode.up().get(), fieldNode, getterName, modifier, source);
MethodDeclaration method = generateGetter((TypeDeclaration) fieldNode.up().get(), fieldNode, getterName, modifier, source, lazy);
Annotation[] copiedAnnotations = copyAnnotations(source, findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN), findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN), onMethod);
if (copiedAnnotations.length != 0) {
method.annotations = copiedAnnotations;
@@ -185,12 +223,22 @@ public class HandleGetter implements EclipseAnnotationHandler<Getter> {
return true;
}
private MethodDeclaration generateGetter(TypeDeclaration parent, EclipseNode fieldNode, String name, int modifier, ASTNode source) {
FieldDeclaration field = (FieldDeclaration) fieldNode.get();
private MethodDeclaration generateGetter(TypeDeclaration parent, EclipseNode fieldNode, String name, int modifier, ASTNode source, boolean lazy) {
// Remember the type; lazy will change it;
TypeReference returnType = copyType(((FieldDeclaration) fieldNode.get()).type, source);
Statement[] statements;
if (lazy) {
statements = createLazyGetterBody(source, fieldNode);
} else {
statements = createSimpleGetterBody(source, fieldNode);
}
MethodDeclaration method = new MethodDeclaration(parent.compilationResult);
Eclipse.setGeneratedBy(method, source);
method.modifiers = modifier;
method.returnType = copyType(field.type, source);
method.returnType = returnType;
method.annotations = null;
method.arguments = null;
method.selector = name.toCharArray();
@@ -198,12 +246,209 @@ public class HandleGetter implements EclipseAnnotationHandler<Getter> {
method.thrownExceptions = null;
method.typeParameters = null;
method.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
Expression fieldRef = createFieldAccessor(fieldNode, true, source);
Statement returnStatement = new ReturnStatement(fieldRef, field.sourceStart, field.sourceEnd);
Eclipse.setGeneratedBy(returnStatement, source);
method.bodyStart = method.declarationSourceStart = method.sourceStart = source.sourceStart;
method.bodyEnd = method.declarationSourceEnd = method.sourceEnd = source.sourceEnd;
method.statements = new Statement[] { returnStatement };
method.statements = statements;
return method;
}
private Statement[] createSimpleGetterBody(ASTNode source, EclipseNode fieldNode) {
FieldDeclaration field = (FieldDeclaration) fieldNode.get();
Expression fieldRef = createFieldAccessor(fieldNode, FieldAccess.ALWAYS_FIELD, source);
Statement returnStatement = new ReturnStatement(fieldRef, field.sourceStart, field.sourceEnd);
Eclipse.setGeneratedBy(returnStatement, source);
return new Statement[] {returnStatement};
}
private static final char[][] AR = fromQualifiedName("java.util.concurrent.atomic.AtomicReference");
private static final TypeReference[][] AR_PARAMS = new TypeReference[5][];
private static final java.util.Map<String, char[][]> TYPE_MAP;
static {
Map<String, char[][]> m = new HashMap<String, char[][]>();
m.put("int", fromQualifiedName("java.lang.Integer"));
m.put("double", fromQualifiedName("java.lang.Double"));
m.put("float", fromQualifiedName("java.lang.Float"));
m.put("short", fromQualifiedName("java.lang.Short"));
m.put("byte", fromQualifiedName("java.lang.Byte"));
m.put("long", fromQualifiedName("java.lang.Long"));
m.put("boolean", fromQualifiedName("java.lang.Boolean"));
m.put("char", fromQualifiedName("java.lang.Character"));
TYPE_MAP = Collections.unmodifiableMap(m);
}
private static char[] valueName = "value".toCharArray();
private Statement[] createLazyGetterBody(ASTNode source, EclipseNode 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();
*/
FieldDeclaration field = (FieldDeclaration) fieldNode.get();
int pS = source.sourceStart, pE = source.sourceEnd;
long p = (long)pS << 32 | pE;
TypeReference componentType = copyType(field.type, source);
if (field.type instanceof SingleTypeReference && !(field.type instanceof ArrayTypeReference)) {
char[][] newType = TYPE_MAP.get(new String(((SingleTypeReference)field.type).token));
if (newType != null) {
componentType = new QualifiedTypeReference(newType, poss(source, 3));
Eclipse.setGeneratedBy(componentType, source);
}
}
Statement[] statements = new Statement[3];
/* java.util.concurrent.atomic.AtomicReference<ValueType> value = this.fieldName.get(); */ {
LocalDeclaration valueDecl = new LocalDeclaration(valueName, pS, pE);
Eclipse.setGeneratedBy(valueDecl, source);
TypeReference[][] typeParams = AR_PARAMS.clone();
typeParams[4] = new TypeReference[] {copyType(componentType, source)};
valueDecl.type = new ParameterizedQualifiedTypeReference(AR, typeParams, 0, poss(source, 5));
valueDecl.type.sourceStart = pS; valueDecl.type.sourceEnd = pE;
Eclipse.setGeneratedBy(valueDecl.type, source);
MessageSend getter = new MessageSend();
Eclipse.setGeneratedBy(getter, source);
getter.sourceStart = pS; getter.sourceEnd = pE;
getter.selector = new char[] {'g', 'e', 't'};
getter.receiver = EclipseHandlerUtil.createFieldAccessor(fieldNode, FieldAccess.ALWAYS_FIELD, source);
valueDecl.initialization = getter;
Eclipse.setGeneratedBy(valueDecl.initialization, source);
statements[0] = valueDecl;
}
/*
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);
}
}
}
*/ {
EqualExpression cond = new EqualExpression(
new SingleNameReference(valueName, p), new NullLiteral(pS, pE),
BinaryExpression.EQUAL_EQUAL);
Eclipse.setGeneratedBy(cond.left, source);
Eclipse.setGeneratedBy(cond.right, source);
Eclipse.setGeneratedBy(cond, source);
Block then = new Block(0);
Eclipse.setGeneratedBy(then, source);
Expression lock = EclipseHandlerUtil.createFieldAccessor(fieldNode, FieldAccess.ALWAYS_FIELD, source);
Block inner = new Block(0);
Eclipse.setGeneratedBy(inner, source);
inner.statements = new Statement[2];
/* value = this.fieldName.get(); */ {
MessageSend getter = new MessageSend();
Eclipse.setGeneratedBy(getter, source);
getter.sourceStart = pS; getter.sourceEnd = pE;
getter.selector = new char[] {'g', 'e', 't'};
getter.receiver = EclipseHandlerUtil.createFieldAccessor(fieldNode, FieldAccess.ALWAYS_FIELD, source);
Assignment assign = new Assignment(new SingleNameReference(valueName, p), getter, pE);
Eclipse.setGeneratedBy(assign, source);
Eclipse.setGeneratedBy(assign.lhs, source);
inner.statements[0] = assign;
}
/* if (value == null) */ {
EqualExpression innerCond = new EqualExpression(
new SingleNameReference(valueName, p), new NullLiteral(pS, pE),
BinaryExpression.EQUAL_EQUAL);
Eclipse.setGeneratedBy(innerCond.left, source);
Eclipse.setGeneratedBy(innerCond.right, source);
Eclipse.setGeneratedBy(innerCond, source);
Block innerThen = new Block(0);
Eclipse.setGeneratedBy(innerThen, source);
innerThen.statements = new Statement[2];
/*value = new java.util.concurrent.atomic.AtomicReference<ValueType>(new ValueType()); */ {
AllocationExpression create = new AllocationExpression();
Eclipse.setGeneratedBy(create, source);
create.sourceStart = pS; create.sourceEnd = pE;
TypeReference[][] typeParams = AR_PARAMS.clone();
typeParams[4] = new TypeReference[] {copyType(componentType, source)};
create.type = new ParameterizedQualifiedTypeReference(AR, typeParams, 0, poss(source, 5));
create.type.sourceStart = pS; create.type.sourceEnd = pE;
Eclipse.setGeneratedBy(create.type, source);
create.arguments = new Expression[] {field.initialization};
Assignment innerAssign = new Assignment(new SingleNameReference(valueName, p), create, pE);
Eclipse.setGeneratedBy(innerAssign, source);
Eclipse.setGeneratedBy(innerAssign.lhs, source);
innerThen.statements[0] = innerAssign;
}
/*this.fieldName.set(value);*/ {
MessageSend setter = new MessageSend();
Eclipse.setGeneratedBy(setter, source);
setter.sourceStart = pS; setter.sourceEnd = pE;
setter.receiver = EclipseHandlerUtil.createFieldAccessor(fieldNode, FieldAccess.ALWAYS_FIELD, source);
setter.selector = new char[] { 's', 'e', 't' };
setter.arguments = new Expression[] {
new SingleNameReference(valueName, p)};
Eclipse.setGeneratedBy(setter.arguments[0], source);
innerThen.statements[1] = setter;
}
IfStatement innerIf = new IfStatement(innerCond, innerThen, pS, pE);
Eclipse.setGeneratedBy(innerIf, source);
inner.statements[1] = innerIf;
}
SynchronizedStatement sync = new SynchronizedStatement(lock, inner, pS, pE);
Eclipse.setGeneratedBy(sync, source);
then.statements = new Statement[] {sync};
IfStatement ifStatement = new IfStatement(cond, then, pS, pE);
Eclipse.setGeneratedBy(ifStatement, source);
statements[1] = ifStatement;
}
/* return value.get(); */ {
MessageSend getter = new MessageSend();
Eclipse.setGeneratedBy(getter, source);
getter.sourceStart = pS; getter.sourceEnd = pE;
getter.selector = new char[] {'g', 'e', 't'};
getter.receiver = new SingleNameReference(valueName, p);
Eclipse.setGeneratedBy(getter.receiver, source);
statements[2] = new ReturnStatement(getter, pS, pE);
Eclipse.setGeneratedBy(statements[2], source);
}
// 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>>(); */ {
LocalDeclaration first = (LocalDeclaration) statements[0];
TypeReference innerType = copyType(first.type, source);
TypeReference[][] typeParams = AR_PARAMS.clone();
typeParams[4] = new TypeReference[] {copyType(innerType, source)};
TypeReference type = new ParameterizedQualifiedTypeReference(AR, typeParams, 0, poss(source, 5));
// Some magic here
type.sourceStart = -1; type.sourceEnd = -2;
Eclipse.setGeneratedBy(type, source);
field.type = type;
AllocationExpression init = new AllocationExpression();
// Some magic here
init.sourceStart = field.initialization.sourceStart; init.sourceEnd = field.initialization.sourceEnd;
init.type = copyType(type, source);
field.initialization = init;
}
return statements;
}
}
@@ -35,6 +35,7 @@ import lombok.core.handlers.TransformationsUtil;
import lombok.eclipse.Eclipse;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;
import lombok.eclipse.handlers.EclipseHandlerUtil.FieldAccess;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
@@ -206,7 +207,7 @@ public class HandleSetter implements EclipseAnnotationHandler<Setter> {
method.thrownExceptions = null;
method.typeParameters = null;
method.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
Expression fieldRef = createFieldAccessor(fieldNode, true, source);
Expression fieldRef = createFieldAccessor(fieldNode, FieldAccess.ALWAYS_FIELD, source);
NameReference fieldNameRef = new SingleNameReference(field.name, p);
Eclipse.setGeneratedBy(fieldNameRef, source);
Assignment assignment = new Assignment(fieldRef, fieldNameRef, (int)p);
@@ -38,6 +38,7 @@ import lombok.core.AST.Kind;
import lombok.eclipse.Eclipse;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;
import lombok.eclipse.handlers.EclipseHandlerUtil.FieldAccess;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
@@ -94,7 +95,7 @@ public class HandleToString implements EclipseAnnotationHandler<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);
}
public boolean handle(AnnotationValues<ToString> annotation, Annotation ast, EclipseNode annotationNode) {
@@ -115,11 +116,13 @@ public class HandleToString implements EclipseAnnotationHandler<ToString> {
checkForBogusFieldNames(typeNode, annotation);
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 boolean generateToString(EclipseNode typeNode, EclipseNode errorNode, List<String> excludes, List<String> includes,
boolean includeFieldNames, Boolean callSuper, boolean whineIfExists, boolean useFieldsDirectly) {
boolean includeFieldNames, Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess) {
TypeDeclaration typeDecl = null;
if (typeNode.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) typeNode.get();
@@ -161,7 +164,7 @@ public class HandleToString implements EclipseAnnotationHandler<ToString> {
switch (methodExists("toString", typeNode)) {
case NOT_EXISTS:
MethodDeclaration toString = createToString(typeNode, nodesForToString, includeFieldNames, callSuper, errorNode.get(), useFieldsDirectly);
MethodDeclaration toString = createToString(typeNode, nodesForToString, includeFieldNames, callSuper, errorNode.get(), fieldAccess);
injectMethod(typeNode, toString);
return true;
case EXISTS_BY_LOMBOK:
@@ -176,7 +179,7 @@ public class HandleToString implements EclipseAnnotationHandler<ToString> {
}
private MethodDeclaration createToString(EclipseNode type, Collection<EclipseNode> fields,
boolean includeFieldNames, boolean callSuper, ASTNode source, boolean useFieldsDirectly) {
boolean includeFieldNames, boolean callSuper, ASTNode source, FieldAccess fieldAccess) {
String typeName = getTypeName(type);
char[] suffix = ")".toCharArray();
String infixS = ", ";
@@ -214,8 +217,8 @@ public class HandleToString implements EclipseAnnotationHandler<ToString> {
}
for (EclipseNode field : fields) {
TypeReference fType = getFieldType(field, useFieldsDirectly);
Expression fieldAccessor = createFieldAccessor(field, useFieldsDirectly, source);
TypeReference fType = getFieldType(field, fieldAccess);
Expression fieldAccessor = createFieldAccessor(field, fieldAccess, source);
Expression ex;
if (fType.dimensions() > 0) {
@@ -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));
}
+173 -15
View File
@@ -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,26 @@ 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();
@@ -209,6 +251,122 @@ public class HandleGetter implements JavacAnnotationHandler<Getter> {
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;
}
@Override public boolean isResolutionBased() {
return false;
}
@@ -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;
@@ -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;
@@ -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) {
@@ -0,0 +1,19 @@
class GetterLazy {
static class ValueType {
}
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>>();
@java.lang.SuppressWarnings("all")
public ValueType getFieldName() {
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();
}
}
@@ -0,0 +1,58 @@
class GetterLazyEahcToString {
private final java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<String>> value = new java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<String>>();
private final String value2 = "";
@java.lang.Override
@java.lang.SuppressWarnings("all")
public boolean equals(final java.lang.Object o) {
if (o == this) return true;
if (!(o instanceof GetterLazyEahcToString)) return false;
final GetterLazyEahcToString other = (GetterLazyEahcToString)o;
if (!other.canEqual(this)) return false;
if (this.getValue() == null ? other.getValue() != null : !this.getValue().equals(other.getValue())) return false;
if (this.value2 == null ? other.value2 != null : !this.value2.equals(other.value2)) return false;
return true;
}
@java.lang.SuppressWarnings("all")
public boolean canEqual(final java.lang.Object other) {
return other instanceof GetterLazyEahcToString;
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
public int hashCode() {
final int PRIME = 31;
int result = 1;
result = result * PRIME + (this.getValue() == null ? 0 : this.getValue().hashCode());
result = result * PRIME + (this.value2 == null ? 0 : this.value2.hashCode());
return result;
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
public java.lang.String toString() {
return "GetterLazyEahcToString(value=" + this.getValue() + ", value2=" + this.value2 + ")";
}
@java.lang.SuppressWarnings("all")
public String getValue() {
java.util.concurrent.atomic.AtomicReference<String> value = this.value.get();
if (value == null) {
synchronized (this.value) {
value = this.value.get();
if (value == null) {
value = new java.util.concurrent.atomic.AtomicReference<String>("");
this.value.set(value);
}
}
}
return value.get();
}
@java.lang.SuppressWarnings("all")
public String getValue2() {
return this.value2;
}
}
@@ -0,0 +1,25 @@
class GetterLazyInvalidNotFinal {
private String fieldName = "";
}
class GetterLazyInvalidNotPrivate {
final String fieldName = "";
}
class GetterLazyInvalidNotPrivateFinal {
String fieldName = "";
}
class GetterLazyInvalidNone {
private final String fieldName = "";
}
class GetterLazyInvalidClass {
private final String fieldName = "";
@java.lang.SuppressWarnings("all")
public String getFieldName() {
return this.fieldName;
}
}
class GetterLazyInvalidNoInit {
private final String fieldName;
GetterLazyInvalidNoInit() {
this.fieldName = "foo";
}
}
@@ -0,0 +1,137 @@
class GetterLazyNative {
private final java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Boolean>> booleanField = new java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Boolean>>();
private final java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Byte>> byteField = new java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Byte>>();
private final java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Short>> shortField = new java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Short>>();
private final java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Integer>> intField = new java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Integer>>();
private final java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Long>> longField = new java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Long>>();
private final java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Float>> floatField = new java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Float>>();
private final java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Double>> doubleField = new java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Double>>();
private final java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Character>> charField = new java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Character>>();
private final java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<int[]>> intArrayField = new java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<int[]>>();
@java.lang.SuppressWarnings("all")
public boolean getBooleanField() {
java.util.concurrent.atomic.AtomicReference<java.lang.Boolean> value = this.booleanField.get();
if (value == null) {
synchronized (this.booleanField) {
value = this.booleanField.get();
if (value == null) {
value = new java.util.concurrent.atomic.AtomicReference<java.lang.Boolean>(true);
this.booleanField.set(value);
}
}
}
return value.get();
}
@java.lang.SuppressWarnings("all")
public byte getByteField() {
java.util.concurrent.atomic.AtomicReference<java.lang.Byte> value = this.byteField.get();
if (value == null) {
synchronized (this.byteField) {
value = this.byteField.get();
if (value == null) {
value = new java.util.concurrent.atomic.AtomicReference<java.lang.Byte>(1);
this.byteField.set(value);
}
}
}
return value.get();
}
@java.lang.SuppressWarnings("all")
public short getShortField() {
java.util.concurrent.atomic.AtomicReference<java.lang.Short> value = this.shortField.get();
if (value == null) {
synchronized (this.shortField) {
value = this.shortField.get();
if (value == null) {
value = new java.util.concurrent.atomic.AtomicReference<java.lang.Short>(1);
this.shortField.set(value);
}
}
}
return value.get();
}
@java.lang.SuppressWarnings("all")
public int getIntField() {
java.util.concurrent.atomic.AtomicReference<java.lang.Integer> value = this.intField.get();
if (value == null) {
synchronized (this.intField) {
value = this.intField.get();
if (value == null) {
value = new java.util.concurrent.atomic.AtomicReference<java.lang.Integer>(1);
this.intField.set(value);
}
}
}
return value.get();
}
@java.lang.SuppressWarnings("all")
public long getLongField() {
java.util.concurrent.atomic.AtomicReference<java.lang.Long> value = this.longField.get();
if (value == null) {
synchronized (this.longField) {
value = this.longField.get();
if (value == null) {
value = new java.util.concurrent.atomic.AtomicReference<java.lang.Long>(1);
this.longField.set(value);
}
}
}
return value.get();
}
@java.lang.SuppressWarnings("all")
public float getFloatField() {
java.util.concurrent.atomic.AtomicReference<java.lang.Float> value = this.floatField.get();
if (value == null) {
synchronized (this.floatField) {
value = this.floatField.get();
if (value == null) {
value = new java.util.concurrent.atomic.AtomicReference<java.lang.Float>(1.0F);
this.floatField.set(value);
}
}
}
return value.get();
}
@java.lang.SuppressWarnings("all")
public double getDoubleField() {
java.util.concurrent.atomic.AtomicReference<java.lang.Double> value = this.doubleField.get();
if (value == null) {
synchronized (this.doubleField) {
value = this.doubleField.get();
if (value == null) {
value = new java.util.concurrent.atomic.AtomicReference<java.lang.Double>(1.0);
this.doubleField.set(value);
}
}
}
return value.get();
}
@java.lang.SuppressWarnings("all")
public char getCharField() {
java.util.concurrent.atomic.AtomicReference<java.lang.Character> value = this.charField.get();
if (value == null) {
synchronized (this.charField) {
value = this.charField.get();
if (value == null) {
value = new java.util.concurrent.atomic.AtomicReference<java.lang.Character>('1');
this.charField.set(value);
}
}
}
return value.get();
}
@java.lang.SuppressWarnings("all")
public int[] getIntArrayField() {
java.util.concurrent.atomic.AtomicReference<int[]> value = this.intArrayField.get();
if (value == null) {
synchronized (this.intArrayField) {
value = this.intArrayField.get();
if (value == null) {
value = new java.util.concurrent.atomic.AtomicReference<int[]>(new int[]{1});
this.intArrayField.set(value);
}
}
}
return value.get();
}
}
@@ -0,0 +1,27 @@
class GetterLazy {
static class ValueType {
ValueType() {
super();
}
}
private final @lombok.Getter(lazy = true) java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<ValueType>> fieldName = new java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<ValueType>>();
public @java.lang.SuppressWarnings("all") ValueType getFieldName() {
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();
}
GetterLazy() {
super();
}
}
@@ -0,0 +1,53 @@
@lombok.EqualsAndHashCode(doNotUseGetters = true) @lombok.ToString(doNotUseGetters = true) class GetterLazyEahcToString {
private final @lombok.Getter(lazy = true) java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<String>> value = new java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<String>>();
private final @lombok.Getter String value2 = "";
public @java.lang.SuppressWarnings("all") String getValue() {
java.util.concurrent.atomic.AtomicReference<String> value = this.value.get();
if ((value == null))
{
synchronized (this.value)
{
value = this.value.get();
if ((value == null))
{
value = new java.util.concurrent.atomic.AtomicReference<String>("");
this.value.set(value);
}
}
}
return value.get();
}
public @java.lang.SuppressWarnings("all") String getValue2() {
return this.value2;
}
public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) {
if ((o == this))
return true;
if ((! (o instanceof GetterLazyEahcToString)))
return false;
final GetterLazyEahcToString other = (GetterLazyEahcToString) o;
if ((! other.canEqual(this)))
return false;
if (((this.getValue() == null) ? (other.getValue() != null) : (! this.getValue().equals(other.getValue()))))
return false;
if (((this.value2 == null) ? (other.value2 != null) : (! this.value2.equals(other.value2))))
return false;
return true;
}
public @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) {
return (other instanceof GetterLazyEahcToString);
}
public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() {
final int PRIME = 31;
int result = 1;
result = ((result * PRIME) + ((this.getValue() == null) ? 0 : this.getValue().hashCode()));
result = ((result * PRIME) + ((this.value2 == null) ? 0 : this.value2.hashCode()));
return result;
}
public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
return (((("GetterLazyEahcToString(value=" + this.getValue()) + ", value2=") + this.value2) + ")");
}
GetterLazyEahcToString() {
super();
}
}
@@ -0,0 +1,40 @@
class GetterLazyInvalidNotFinal {
private @lombok.Getter(lazy = true) String fieldName = "";
GetterLazyInvalidNotFinal() {
super();
}
}
class GetterLazyInvalidNotPrivate {
final @lombok.Getter(lazy = true) String fieldName = "";
GetterLazyInvalidNotPrivate() {
super();
}
}
class GetterLazyInvalidNotPrivateFinal {
@lombok.Getter(lazy = true) String fieldName = "";
GetterLazyInvalidNotPrivateFinal() {
super();
}
}
class GetterLazyInvalidNone {
private final @lombok.Getter(lazy = true,value = lombok.AccessLevel.NONE) String fieldName = "";
GetterLazyInvalidNone() {
super();
}
}
@lombok.Getter(lazy = true) class GetterLazyInvalidClass {
private final String fieldName = "";
public @java.lang.SuppressWarnings("all") String getFieldName() {
return this.fieldName;
}
GetterLazyInvalidClass() {
super();
}
}
class GetterLazyInvalidNoInit {
private final @lombok.Getter(lazy = true) String fieldName;
GetterLazyInvalidNoInit() {
super();
this.fieldName = "foo";
}
}
@@ -0,0 +1,158 @@
class GetterLazyNative {
private final @lombok.Getter(lazy = true) java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Boolean>> booleanField = new java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Boolean>>();
private final @lombok.Getter(lazy = true) java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Byte>> byteField = new java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Byte>>();
private final @lombok.Getter(lazy = true) java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Short>> shortField = new java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Short>>();
private final @lombok.Getter(lazy = true) java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Integer>> intField = new java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Integer>>();
private final @lombok.Getter(lazy = true) java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Long>> longField = new java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Long>>();
private final @lombok.Getter(lazy = true) java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Float>> floatField = new java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Float>>();
private final @lombok.Getter(lazy = true) java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Double>> doubleField = new java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Double>>();
private final @lombok.Getter(lazy = true) java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Character>> charField = new java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<java.lang.Character>>();
private final @lombok.Getter(lazy = true) java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<int[]>> intArrayField = new java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<int[]>>();
public @java.lang.SuppressWarnings("all") boolean isBooleanField() {
java.util.concurrent.atomic.AtomicReference<java.lang.Boolean> value = this.booleanField.get();
if ((value == null))
{
synchronized (this.booleanField)
{
value = this.booleanField.get();
if ((value == null))
{
value = new java.util.concurrent.atomic.AtomicReference<java.lang.Boolean>(true);
this.booleanField.set(value);
}
}
}
return value.get();
}
public @java.lang.SuppressWarnings("all") byte getByteField() {
java.util.concurrent.atomic.AtomicReference<java.lang.Byte> value = this.byteField.get();
if ((value == null))
{
synchronized (this.byteField)
{
value = this.byteField.get();
if ((value == null))
{
value = new java.util.concurrent.atomic.AtomicReference<java.lang.Byte>(1);
this.byteField.set(value);
}
}
}
return value.get();
}
public @java.lang.SuppressWarnings("all") short getShortField() {
java.util.concurrent.atomic.AtomicReference<java.lang.Short> value = this.shortField.get();
if ((value == null))
{
synchronized (this.shortField)
{
value = this.shortField.get();
if ((value == null))
{
value = new java.util.concurrent.atomic.AtomicReference<java.lang.Short>(1);
this.shortField.set(value);
}
}
}
return value.get();
}
public @java.lang.SuppressWarnings("all") int getIntField() {
java.util.concurrent.atomic.AtomicReference<java.lang.Integer> value = this.intField.get();
if ((value == null))
{
synchronized (this.intField)
{
value = this.intField.get();
if ((value == null))
{
value = new java.util.concurrent.atomic.AtomicReference<java.lang.Integer>(1);
this.intField.set(value);
}
}
}
return value.get();
}
public @java.lang.SuppressWarnings("all") long getLongField() {
java.util.concurrent.atomic.AtomicReference<java.lang.Long> value = this.longField.get();
if ((value == null))
{
synchronized (this.longField)
{
value = this.longField.get();
if ((value == null))
{
value = new java.util.concurrent.atomic.AtomicReference<java.lang.Long>(1);
this.longField.set(value);
}
}
}
return value.get();
}
public @java.lang.SuppressWarnings("all") float getFloatField() {
java.util.concurrent.atomic.AtomicReference<java.lang.Float> value = this.floatField.get();
if ((value == null))
{
synchronized (this.floatField)
{
value = this.floatField.get();
if ((value == null))
{
value = new java.util.concurrent.atomic.AtomicReference<java.lang.Float>(1.0f);
this.floatField.set(value);
}
}
}
return value.get();
}
public @java.lang.SuppressWarnings("all") double getDoubleField() {
java.util.concurrent.atomic.AtomicReference<java.lang.Double> value = this.doubleField.get();
if ((value == null))
{
synchronized (this.doubleField)
{
value = this.doubleField.get();
if ((value == null))
{
value = new java.util.concurrent.atomic.AtomicReference<java.lang.Double>(1.0);
this.doubleField.set(value);
}
}
}
return value.get();
}
public @java.lang.SuppressWarnings("all") char getCharField() {
java.util.concurrent.atomic.AtomicReference<java.lang.Character> value = this.charField.get();
if ((value == null))
{
synchronized (this.charField)
{
value = this.charField.get();
if ((value == null))
{
value = new java.util.concurrent.atomic.AtomicReference<java.lang.Character>('1');
this.charField.set(value);
}
}
}
return value.get();
}
public @java.lang.SuppressWarnings("all") int[] getIntArrayField() {
java.util.concurrent.atomic.AtomicReference<int[]> value = this.intArrayField.get();
if ((value == null))
{
synchronized (this.intArrayField)
{
value = this.intArrayField.get();
if ((value == null))
{
value = new java.util.concurrent.atomic.AtomicReference<int[]>(new int[]{1});
this.intArrayField.set(value);
}
}
}
return value.get();
}
GetterLazyNative() {
super();
}
}
@@ -0,0 +1,7 @@
class GetterLazy {
static class ValueType {
}
@lombok.Getter(lazy=true)
private final ValueType fieldName = new ValueType();
}
@@ -0,0 +1,8 @@
@lombok.EqualsAndHashCode(doNotUseGetters = true)
@lombok.ToString(doNotUseGetters = true)
class GetterLazyEahcToString {
@lombok.Getter(lazy=true)
private final String value = "";
@lombok.Getter
private final String value2 = "";
}
@@ -0,0 +1,27 @@
class GetterLazyInvalidNotFinal {
@lombok.Getter(lazy=true)
private String fieldName = "";
}
class GetterLazyInvalidNotPrivate {
@lombok.Getter(lazy=true)
final String fieldName = "";
}
class GetterLazyInvalidNotPrivateFinal {
@lombok.Getter(lazy=true)
String fieldName = "";
}
class GetterLazyInvalidNone {
@lombok.Getter(lazy=true, value=lombok.AccessLevel.NONE)
private final String fieldName = "";
}
@lombok.Getter(lazy = true)
class GetterLazyInvalidClass {
private final String fieldName = "";
}
class GetterLazyInvalidNoInit {
@lombok.Getter(lazy = true)
private final String fieldName;
GetterLazyInvalidNoInit() {
this.fieldName = "foo";
}
}
@@ -0,0 +1,28 @@
class GetterLazyNative {
@lombok.Getter(lazy=true)
private final boolean booleanField = true;
@lombok.Getter(lazy=true)
private final byte byteField = 1;
@lombok.Getter(lazy=true)
private final short shortField = 1;
@lombok.Getter(lazy=true)
private final int intField = 1;
@lombok.Getter(lazy=true)
private final long longField = 1;
@lombok.Getter(lazy=true)
private final float floatField = 1.0f;
@lombok.Getter(lazy=true)
private final double doubleField = 1.0;
@lombok.Getter(lazy=true)
private final char charField = '1';
@lombok.Getter(lazy=true)
private final int[] intArrayField = new int[] {1};
}
@@ -0,0 +1,6 @@
2:9 ERROR 'lazy' requires the field to be private and final.
6:9 ERROR 'lazy' requires the field to be private and final.
10:9 ERROR 'lazy' requires the field to be private and final.
14:9 WARNING 'lazy' does not work with AccessLevel.NONE.
17:1 ERROR 'lazy' is not supported for @Getter on a type.
22:9 ERROR 'lazy' requires field initialization.
@@ -0,0 +1,6 @@
2 error 'lazy' requires the field to be private and final.
6 error 'lazy' requires the field to be private and final.
10 error 'lazy' requires the field to be private and final.
14 warning 'lazy' does not work with AccessLevel.NONE.
17 error 'lazy' is not supported for @Getter on a type.
22 error 'lazy' requires field initialization.