mirror of
https://github.com/tiennm99/lombok.git
synced 2026-10-14 06:17:44 +00:00
@Getter(lazy=true) support for javac
This commit is contained in:
1 parent
c8774389e7
commit
1c32333249
20 files changed
+602
-85
No files matched your search
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -76,7 +76,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 +103,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 +113,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' requires AccessLevel.PRIVATE or higher.");
|
||||
}
|
||||
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 | 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;
|
||||
@@ -198,7 +217,7 @@ 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);
|
||||
Expression fieldRef = createFieldAccessor(fieldNode, FieldAccess.ALWAYS_FIELD, source);
|
||||
Statement returnStatement = new ReturnStatement(fieldRef, field.sourceStart, field.sourceEnd);
|
||||
Eclipse.setGeneratedBy(returnStatement, source);
|
||||
method.bodyStart = method.declarationSourceStart = method.sourceStart = source.sourceStart;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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,44 @@
|
||||
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>>();
|
||||
@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;
|
||||
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());
|
||||
return result;
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public java.lang.String toString() {
|
||||
return "GetterLazyEahcToString(value=" + this.getValue() + ")";
|
||||
}
|
||||
@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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
class GetterLazyInvalidNotFinal {
|
||||
private String fieldName = "";
|
||||
}
|
||||
class GetterLazyInvalidNotPrivate {
|
||||
final String fieldName = "";
|
||||
}
|
||||
class GetterLazyInvalidNotPrivateFinal {
|
||||
String fieldName = "";
|
||||
}
|
||||
class GetterLazyInvalidNone {
|
||||
String fieldName = "";
|
||||
}
|
||||
class GetterLazyInvalidClass {
|
||||
String fieldName = "";
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public String getFieldName() {
|
||||
return this.fieldName;
|
||||
}
|
||||
}
|
||||
class GetterLazyInvalidNoInit {
|
||||
String fieldName;
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
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>>();
|
||||
|
||||
@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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
class GetterLazy {
|
||||
static class ValueType {
|
||||
}
|
||||
|
||||
@lombok.Getter(lazy=true)
|
||||
private final ValueType fieldName = new ValueType();
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
@lombok.EqualsAndHashCode(doNotUseGetters = true)
|
||||
@lombok.ToString(doNotUseGetters = true)
|
||||
class GetterLazyEahcToString {
|
||||
@lombok.Getter(lazy=true)
|
||||
private final String value = "";
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
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)
|
||||
String fieldName = "";
|
||||
}
|
||||
@lombok.Getter(lazy = true)
|
||||
class GetterLazyInvalidClass {
|
||||
String fieldName = "";
|
||||
}
|
||||
class GetterLazyInvalidNoInit {
|
||||
@lombok.Getter(lazy = true)
|
||||
String fieldName;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
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';
|
||||
}
|
||||
@@ -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 the field to be private and final.
|
||||
Reference in new issue
Block a user