From e06a7b03ea1ffb12c7ef6865a024407f7466d50d Mon Sep 17 00:00:00 2001 From: Jan Ouwens Date: Wed, 8 Jan 2025 11:14:31 +0100 Subject: [PATCH] Adds logic to detect Kotlin classes --- .../internal/checkers/FieldInspector.java | 7 +++-- .../internal/checkers/FieldsChecker.java | 2 +- .../internal/checkers/NullChecker.java | 2 +- .../internal/reflection/FieldIterable.java | 30 +++++++++++++++---- .../annotations/SupportedAnnotations.java | 4 ++- .../internal/util/Configuration.java | 9 ++++++ 6 files changed, 43 insertions(+), 11 deletions(-) diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/FieldInspector.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/FieldInspector.java index 19cedf166..a7451ff83 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/FieldInspector.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/FieldInspector.java @@ -7,13 +7,16 @@ public class FieldInspector { private final Class type; + private final boolean isKotlin; - public FieldInspector(Class type) { + public FieldInspector(Class type, boolean isKotlin) { this.type = type; + this.isKotlin = isKotlin; } public void check(FieldCheck check) { - for (FieldProbe fieldProbe : FieldIterable.of(type)) { + FieldIterable it = isKotlin ? FieldIterable.ofKotlin(type) : FieldIterable.of(type); + for (FieldProbe fieldProbe : it) { check.execute(fieldProbe); } } diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/FieldsChecker.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/FieldsChecker.java index 4199ecfd2..4a1aa1c6c 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/FieldsChecker.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/FieldsChecker.java @@ -55,7 +55,7 @@ public FieldsChecker(Context context) { @Override public void check() { - FieldInspector inspector = new FieldInspector<>(context.getType()); + FieldInspector inspector = new FieldInspector<>(context.getType(), config.isKotlin()); if (!context.getClassProbe().isEqualsInheritedFromObject()) { inspector.check(arrayFieldCheck); diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/NullChecker.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/NullChecker.java index 736a06c6a..3635e3f6f 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/NullChecker.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/checkers/NullChecker.java @@ -18,7 +18,7 @@ public void check() { return; } - FieldInspector inspector = new FieldInspector<>(context.getType()); + FieldInspector inspector = new FieldInspector<>(context.getType(), context.getConfiguration().isKotlin()); inspector.check(new NullPointerExceptionFieldCheck<>(context)); } } diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/FieldIterable.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/FieldIterable.java index 2309de8e2..7f554aaab 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/FieldIterable.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/FieldIterable.java @@ -12,12 +12,14 @@ public final class FieldIterable implements Iterable { private final Class type; private final boolean includeSuperclasses; private final boolean includeStatic; + private final boolean isKotlin; /** Private constructor. Call {@link #of(Class)} or {@link #ofIgnoringSuper(Class)} instead. */ - private FieldIterable(Class type, boolean includeSuperclasses, boolean includeStatic) { + private FieldIterable(Class type, boolean includeSuperclasses, boolean includeStatic, boolean isKotlin) { this.type = type; this.includeSuperclasses = includeSuperclasses; this.includeStatic = includeStatic; + this.isKotlin = isKotlin; } /** @@ -28,7 +30,18 @@ private FieldIterable(Class type, boolean includeSuperclasses, boolean includ * @return A FieldIterable. */ public static FieldIterable of(Class type) { - return new FieldIterable(type, true, true); + return new FieldIterable(type, true, true, false); + } + + /** + * Factory method for a FieldIterable that iterates over all declared fields of {@code type} and over the declared + * fields of all of its superclasses, but that ignores overridden Kotlin backing fields in superclasses. + * + * @param type The class that contains the fields over which to iterate. + * @return A FieldIterable. + */ + public static FieldIterable ofKotlin(Class type) { + return new FieldIterable(type, true, true, true); } /** @@ -39,7 +52,7 @@ public static FieldIterable of(Class type) { * @return A FieldIterable. */ public static FieldIterable ofIgnoringSuper(Class type) { - return new FieldIterable(type, false, true); + return new FieldIterable(type, false, true, false); } /** @@ -50,7 +63,7 @@ public static FieldIterable ofIgnoringSuper(Class type) { * @return A FieldIterable. */ public static FieldIterable ofIgnoringStatic(Class type) { - return new FieldIterable(type, true, false); + return new FieldIterable(type, true, false, false); } /** @@ -61,7 +74,7 @@ public static FieldIterable ofIgnoringStatic(Class type) { * @return A FieldIterable. */ public static FieldIterable ofIgnoringSuperAndStatic(Class type) { - return new FieldIterable(type, false, false); + return new FieldIterable(type, false, false, false); } /** @@ -75,7 +88,12 @@ public Iterator iterator() { } private List createFieldList() { - return createJavaFieldList(); + if (isKotlin) { + return createKotlinFieldList(); + } + else { + return createJavaFieldList(); + } } private List createJavaFieldList() { diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/annotations/SupportedAnnotations.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/annotations/SupportedAnnotations.java index 4148769cc..bb3343b9a 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/annotations/SupportedAnnotations.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/reflection/annotations/SupportedAnnotations.java @@ -194,7 +194,9 @@ public boolean validate( Set ignoredAnnotations) { return "LAZY".equals(properties.getEnumValue("fetch")); } - }; + }, + + KOTLIN(false, "kotlin.Metadata"); private final boolean inherits; private final Set partialClassNames; diff --git a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/util/Configuration.java b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/util/Configuration.java index 11a29bead..a825c5b8d 100644 --- a/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/util/Configuration.java +++ b/equalsverifier-core/src/main/java/nl/jqno/equalsverifier/internal/util/Configuration.java @@ -24,6 +24,7 @@ public final class Configuration { private final boolean usingGetClass; private final EnumSet warningsToSuppress; private final Function fieldnameToGetter; + private final boolean isKotlin; private final TypeTag typeTag; private final AnnotationCache annotationCache; @@ -46,6 +47,7 @@ private Configuration( boolean usingGetClass, EnumSet warningsToSuppress, Function fieldnameToGetter, + boolean isKotlin, List equalExamples, List unequalExamples) { this.type = type; @@ -60,6 +62,7 @@ private Configuration( this.usingGetClass = usingGetClass; this.warningsToSuppress = warningsToSuppress; this.fieldnameToGetter = fieldnameToGetter; + this.isKotlin = isKotlin; this.equalExamples = equalExamples; this.unequalExamples = unequalExamples; } @@ -91,6 +94,7 @@ public static Configuration build( actualFields); Function converter = fieldnameToGetter != null ? fieldnameToGetter : DEFAULT_FIELDNAME_TO_GETTER_CONVERTER; + boolean isKotlin = annotationCache.hasClassAnnotation(type, SupportedAnnotations.KOTLIN); return new Configuration<>(type, typeTag, @@ -104,6 +108,7 @@ public static Configuration build( usingGetClass, warningsToSuppress, converter, + isKotlin, equalExamples, unequalExamples); } @@ -200,6 +205,10 @@ public Function getFieldnameToGetter() { return fieldnameToGetter; } + public boolean isKotlin() { + return isKotlin; + } + public List getEqualExamples() { return Collections.unmodifiableList(equalExamples); }