mirror of
https://github.com/tiennm99/lombok.git
synced 2026-10-13 22:16:11 +00:00
Merge pull request #3420 from Rawi01/tostring-array
Ignore annotations during array detection
This commit is contained in:
10 files changed
+138
-65
No files matched your search
@@ -25,7 +25,6 @@ import static lombok.core.handlers.HandlerUtil.handleFlagUsage;
|
||||
import static lombok.javac.Javac.*;
|
||||
import static lombok.javac.handlers.JavacHandlerUtil.*;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -269,7 +268,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
|
||||
|
||||
for (Included<JavacNode, EqualsAndHashCode.Include> member : members) {
|
||||
JavacNode memberNode = member.getNode();
|
||||
JCExpression fType = unnotate(getFieldType(memberNode, fieldAccess));
|
||||
JCExpression fType = removeTypeUseAnnotations(getFieldType(memberNode, fieldAccess));
|
||||
boolean isMethod = memberNode.getKind() == Kind.METHOD;
|
||||
|
||||
JCExpression fieldAccessor = isMethod ? createMethodAccessor(maker, memberNode) : createFieldAccessor(maker, memberNode, fieldAccess);
|
||||
@@ -316,8 +315,8 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
|
||||
} else if (fType instanceof JCArrayTypeTree) {
|
||||
JCArrayTypeTree array = (JCArrayTypeTree) fType;
|
||||
/* java.util.Arrays.deepHashCode(this.fieldName) //use just hashCode() for primitive arrays. */
|
||||
boolean multiDim = unnotate(array.elemtype) instanceof JCArrayTypeTree;
|
||||
boolean primitiveArray = unnotate(array.elemtype) instanceof JCPrimitiveTypeTree;
|
||||
boolean multiDim = removeTypeUseAnnotations(array.elemtype) instanceof JCArrayTypeTree;
|
||||
boolean primitiveArray = removeTypeUseAnnotations(array.elemtype) instanceof JCPrimitiveTypeTree;
|
||||
boolean useDeepHC = multiDim || !primitiveArray;
|
||||
|
||||
JCExpression hcMethod = chainDots(typeNode, "java", "util", "Arrays", useDeepHC ? "deepHashCode" : "hashCode");
|
||||
@@ -503,7 +502,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
|
||||
JavacNode memberNode = member.getNode();
|
||||
boolean isMethod = memberNode.getKind() == Kind.METHOD;
|
||||
|
||||
JCExpression fType = unnotate(getFieldType(memberNode, fieldAccess));
|
||||
JCExpression fType = removeTypeUseAnnotations(getFieldType(memberNode, fieldAccess));
|
||||
JCExpression thisFieldAccessor = isMethod ? createMethodAccessor(maker, memberNode) : createFieldAccessor(maker, memberNode, fieldAccess);
|
||||
JCExpression otherFieldAccessor = isMethod ? createMethodAccessor(maker, memberNode, maker.Ident(otherName)) : createFieldAccessor(maker, memberNode, fieldAccess, maker.Ident(otherName));
|
||||
if (fType instanceof JCPrimitiveTypeTree) {
|
||||
@@ -525,8 +524,8 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
|
||||
} else if (fType instanceof JCArrayTypeTree) {
|
||||
JCArrayTypeTree array = (JCArrayTypeTree) fType;
|
||||
/* if (!java.util.Arrays.deepEquals(this.fieldName, other.fieldName)) return false; //use equals for primitive arrays. */
|
||||
boolean multiDim = unnotate(array.elemtype) instanceof JCArrayTypeTree;
|
||||
boolean primitiveArray = unnotate(array.elemtype) instanceof JCPrimitiveTypeTree;
|
||||
boolean multiDim = removeTypeUseAnnotations(array.elemtype) instanceof JCArrayTypeTree;
|
||||
boolean primitiveArray = removeTypeUseAnnotations(array.elemtype) instanceof JCPrimitiveTypeTree;
|
||||
boolean useDeepEquals = multiDim || !primitiveArray;
|
||||
|
||||
JCExpression eqMethod = chainDots(typeNode, "java", "util", "Arrays", useDeepEquals ? "deepEquals" : "equals");
|
||||
@@ -603,30 +602,4 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
|
||||
public JCStatement returnBool(JavacTreeMaker maker, boolean bool) {
|
||||
return maker.Return(maker.Literal(CTC_BOOLEAN, bool ? 1 : 0));
|
||||
}
|
||||
|
||||
private boolean jcAnnotatedTypeInit;
|
||||
private Class<?> jcAnnotatedTypeClass = null;
|
||||
private Field jcAnnotatedTypeUnderlyingTypeField = null;
|
||||
|
||||
private JCExpression unnotate(JCExpression type) {
|
||||
if (!isJcAnnotatedType(type)) return type;
|
||||
if (jcAnnotatedTypeUnderlyingTypeField == null) return type;
|
||||
try {
|
||||
return (JCExpression) jcAnnotatedTypeUnderlyingTypeField.get(type);
|
||||
} catch (Exception ignore) {}
|
||||
return type;
|
||||
}
|
||||
|
||||
private boolean isJcAnnotatedType(JCExpression o) {
|
||||
if (o == null) return false;
|
||||
if (!jcAnnotatedTypeInit) {
|
||||
try {
|
||||
jcAnnotatedTypeClass = Class.forName("com.sun.tools.javac.tree.JCTree$JCAnnotatedType", false, o.getClass().getClassLoader());
|
||||
jcAnnotatedTypeUnderlyingTypeField = jcAnnotatedTypeClass.getDeclaredField("underlyingType");
|
||||
}
|
||||
catch (Exception ignore) {}
|
||||
jcAnnotatedTypeInit = true;
|
||||
}
|
||||
return jcAnnotatedTypeClass == o.getClass();
|
||||
}
|
||||
}
|
||||
@@ -206,7 +206,7 @@ public class HandleToString extends JavacAnnotationHandler<ToString> {
|
||||
memberAccessor = createFieldAccessor(maker, memberNode, fieldAccess);
|
||||
}
|
||||
|
||||
JCExpression memberType = getFieldType(memberNode, fieldAccess);
|
||||
JCExpression memberType = removeTypeUseAnnotations(getFieldType(memberNode, fieldAccess));
|
||||
|
||||
// The distinction between primitive and object will be useful if we ever add a 'hideNulls' option.
|
||||
@SuppressWarnings("unused")
|
||||
|
||||
@@ -586,29 +586,40 @@ public class JavacHandlerUtil {
|
||||
static class RecordComponentReflect {
|
||||
|
||||
private static final Field astField;
|
||||
private static final Field originalAnnos;
|
||||
private static final Method findRecordComponentToRemove;
|
||||
|
||||
static {
|
||||
Field a = null;
|
||||
Field o = null;
|
||||
Method m = null;
|
||||
try {
|
||||
Class<?> forName = Class.forName("com.sun.tools.javac.code.Symbol$RecordComponent");
|
||||
a = Permit.permissiveGetField(forName, "ast");
|
||||
o = Permit.permissiveGetField(forName, "originalAnnos");
|
||||
m = Permit.permissiveGetMethod(ClassSymbol.class, "findRecordComponentToRemove", JCVariableDecl.class);
|
||||
} catch (Throwable e) {
|
||||
// Ignore
|
||||
}
|
||||
astField = a;
|
||||
originalAnnos = o;
|
||||
findRecordComponentToRemove = m;
|
||||
}
|
||||
|
||||
static void deleteAnnotation(JCClassDecl record, JCVariableDecl component, JCTree annotation) {
|
||||
if (astField == null || findRecordComponentToRemove == null) return;
|
||||
if ((astField == null && originalAnnos == null) || findRecordComponentToRemove == null) return;
|
||||
|
||||
try {
|
||||
Object toRemove = Permit.invokeSneaky(findRecordComponentToRemove, record.sym, component);
|
||||
JCVariableDecl variable = (JCVariableDecl) Permit.get(astField, toRemove);
|
||||
variable.mods.annotations = filterListByPos(variable.mods.annotations, annotation);
|
||||
if (astField != null) {
|
||||
// OpenJDK
|
||||
JCVariableDecl variable = Permit.get(astField, toRemove);
|
||||
variable.mods.annotations = filterListByPos(variable.mods.annotations, annotation);
|
||||
} else {
|
||||
// Zulu JDK 17
|
||||
List<JCAnnotation> annotations = Permit.get(originalAnnos, toRemove);
|
||||
Permit.set(originalAnnos, toRemove, filterListByPos(annotations, annotation));
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
// Ignore
|
||||
}
|
||||
@@ -1212,41 +1223,39 @@ public class JavacHandlerUtil {
|
||||
}
|
||||
|
||||
static class JCAnnotatedTypeReflect {
|
||||
private static Class<?> TYPE;
|
||||
private static Constructor<?> CONSTRUCTOR;
|
||||
private static Field ANNOTATIONS, UNDERLYING_TYPE;
|
||||
private static final Class<?> TYPE;
|
||||
private static final Constructor<?> CONSTRUCTOR;
|
||||
private static final Field ANNOTATIONS, UNDERLYING_TYPE;
|
||||
|
||||
private static void initByLoader(ClassLoader classLoader) {
|
||||
if (TYPE != null) return;
|
||||
Class<?> c;
|
||||
static {
|
||||
Class<?> t = null;
|
||||
Constructor<?> c = null;
|
||||
Field a = null;
|
||||
Field u = null;
|
||||
|
||||
try {
|
||||
c = classLoader.loadClass("com.sun.tools.javac.tree.JCTree$JCAnnotatedType");
|
||||
t = Class.forName("com.sun.tools.javac.tree.JCTree$JCAnnotatedType");
|
||||
c = Permit.getConstructor(t, List.class, JCExpression.class);
|
||||
a = Permit.permissiveGetField(t, "annotations");
|
||||
u = Permit.permissiveGetField(t, "underlyingType");
|
||||
} catch (Exception e) {
|
||||
return;
|
||||
// Ignore
|
||||
}
|
||||
init(c);
|
||||
}
|
||||
|
||||
private static void init(Class<?> in) {
|
||||
if (TYPE != null) return;
|
||||
if (!in.getName().equals("com.sun.tools.javac.tree.JCTree$JCAnnotatedType")) return;
|
||||
try {
|
||||
CONSTRUCTOR = Permit.getConstructor(in, List.class, JCExpression.class);
|
||||
ANNOTATIONS = Permit.getField(in, "annotations");
|
||||
UNDERLYING_TYPE = Permit.getField(in, "underlyingType");
|
||||
TYPE = in;
|
||||
} catch (Exception ignore) {}
|
||||
|
||||
TYPE = t;
|
||||
CONSTRUCTOR = c;
|
||||
ANNOTATIONS = a;
|
||||
UNDERLYING_TYPE = u;
|
||||
}
|
||||
|
||||
static boolean is(JCTree obj) {
|
||||
if (obj == null) return false;
|
||||
init(obj.getClass());
|
||||
return obj.getClass() == TYPE;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static List<JCAnnotation> getAnnotations(JCTree obj) {
|
||||
init(obj.getClass());
|
||||
if (ANNOTATIONS == null) return List.nil();
|
||||
try {
|
||||
return (List<JCAnnotation>) ANNOTATIONS.get(obj);
|
||||
} catch (Exception e) {
|
||||
@@ -1255,14 +1264,16 @@ public class JavacHandlerUtil {
|
||||
}
|
||||
|
||||
static void setAnnotations(JCTree obj, List<JCAnnotation> anns) {
|
||||
init(obj.getClass());
|
||||
if (ANNOTATIONS == null) return;
|
||||
try {
|
||||
ANNOTATIONS.set(obj, anns);
|
||||
} catch (Exception e) {}
|
||||
} catch (Exception e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
static JCExpression getUnderlyingType(JCTree obj) {
|
||||
init(obj.getClass());
|
||||
if (UNDERLYING_TYPE == null) return null;
|
||||
try {
|
||||
return (JCExpression) UNDERLYING_TYPE.get(obj);
|
||||
} catch (Exception e) {
|
||||
@@ -1271,7 +1282,7 @@ public class JavacHandlerUtil {
|
||||
}
|
||||
|
||||
static JCExpression create(List<JCAnnotation> annotations, JCExpression underlyingType) {
|
||||
initByLoader(underlyingType.getClass().getClassLoader());
|
||||
if (CONSTRUCTOR == null) return underlyingType;
|
||||
try {
|
||||
return (JCExpression) CONSTRUCTOR.newInstance(annotations, underlyingType);
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -297,9 +297,9 @@ public class Permit {
|
||||
}
|
||||
}
|
||||
|
||||
public static Object get(Field f, Object receiver) throws IllegalAccessException {
|
||||
public static <T> T get(Field f, Object receiver) throws IllegalAccessException {
|
||||
try {
|
||||
return f.get(receiver);
|
||||
return (T) f.get(receiver);
|
||||
} catch (IllegalAccessException e) {
|
||||
handleReflectionDebug(e, null);
|
||||
throw e;
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
public class ToStringArray {
|
||||
int[] primitiveArray;
|
||||
Object[] objectArray;
|
||||
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public java.lang.String toString() {
|
||||
return "ToStringArray(primitiveArray=" + java.util.Arrays.toString(this.primitiveArray) + ", objectArray=" + java.util.Arrays.deepToString(this.objectArray) + ")";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
//version 8:
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
public class ToStringArrayTypeAnnotations {
|
||||
@TA
|
||||
int[] primitiveArray1;
|
||||
int @TA [] primitiveArray2;
|
||||
@TA
|
||||
Object[] objectArray1;
|
||||
Object @TA [] objectArray2;
|
||||
|
||||
|
||||
@Target({ElementType.TYPE_USE})
|
||||
@interface TA {
|
||||
}
|
||||
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public java.lang.String toString() {
|
||||
return "ToStringArrayTypeAnnotations(primitiveArray1=" + java.util.Arrays.toString(this.primitiveArray1) + ", primitiveArray2=" + java.util.Arrays.toString(this.primitiveArray2) + ", objectArray1=" + java.util.Arrays.deepToString(this.objectArray1) + ", objectArray2=" + java.util.Arrays.deepToString(this.objectArray2) + ")";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Target;
|
||||
public @lombok.ToString class ToStringArray {
|
||||
int[] primitiveArray;
|
||||
Object[] objectArray;
|
||||
public ToStringArray() {
|
||||
super();
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
|
||||
return (((("ToStringArray(primitiveArray=" + java.util.Arrays.toString(this.primitiveArray)) + ", objectArray=") + java.util.Arrays.deepToString(this.objectArray)) + ")");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Target;
|
||||
public @lombok.ToString class ToStringArrayTypeAnnotations {
|
||||
@Target({ElementType.TYPE_USE}) @interface TA {
|
||||
}
|
||||
@TA int[] primitiveArray1;
|
||||
int @TA [] primitiveArray2;
|
||||
@TA Object[] objectArray1;
|
||||
Object @TA [] objectArray2;
|
||||
public ToStringArrayTypeAnnotations() {
|
||||
super();
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
|
||||
return (((((((("ToStringArrayTypeAnnotations(primitiveArray1=" + java.util.Arrays.toString(this.primitiveArray1)) + ", primitiveArray2=") + java.util.Arrays.toString(this.primitiveArray2)) + ", objectArray1=") + java.util.Arrays.deepToString(this.objectArray1)) + ", objectArray2=") + java.util.Arrays.deepToString(this.objectArray2)) + ")");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@lombok.ToString
|
||||
public class ToStringArray {
|
||||
int[] primitiveArray;
|
||||
|
||||
Object[] objectArray;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
//version 8:
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@lombok.ToString
|
||||
public class ToStringArrayTypeAnnotations {
|
||||
@TA int[] primitiveArray1;
|
||||
int @TA [] primitiveArray2;
|
||||
|
||||
@TA Object[] objectArray1;
|
||||
Object @TA [] objectArray2;
|
||||
|
||||
@Target({ElementType.TYPE_USE})
|
||||
@interface TA {
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user