Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,8 @@ private List<Annotation> getProcessedAnnotations(Annotation[] annotations) {
}
return Arrays.stream(annotations)
.filter(a -> {
String pkg = a.annotationType().getPackage().getName();
return !pkg.startsWith("java.") && !pkg.startsWith("jdk.") && !pkg.startsWith("sun.");
Package pkg = a.annotationType().getPackage();
return a.annotationType().equals(Deprecated.class) || processableAnnotationPackage(pkg);
})
.sorted(Comparator.comparing(a -> a.annotationType().getName()))
.collect(Collectors.toList());
Expand All @@ -275,13 +275,13 @@ public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof AnnotatedType)) return false;
AnnotatedType that = (AnnotatedType) o;
List<Annotation> thisAnnotatinons = getProcessedAnnotations(this.ctxAnnotations);
List<Annotation> thatAnnotatinons = getProcessedAnnotations(that.ctxAnnotations);
List<Annotation> thisAnnotations = getProcessedAnnotations(this.ctxAnnotations);
List<Annotation> thatAnnotations = getProcessedAnnotations(that.ctxAnnotations);
return includePropertiesWithoutJSONView == that.includePropertiesWithoutJSONView &&
schemaProperty == that.schemaProperty &&
isSubtype == that.isSubtype &&
Objects.equals(type, that.type) &&
Objects.equals(thisAnnotatinons, thatAnnotatinons) &&
Objects.equals(thisAnnotations, thatAnnotations) &&
Objects.equals(jsonViewAnnotation, that.jsonViewAnnotation) &&
(!schemaProperty || Objects.equals(propertyName, that.propertyName));
}
Expand All @@ -291,4 +291,9 @@ public int hashCode() {
List<Annotation> processedAnnotations = getProcessedAnnotations(this.ctxAnnotations);
return Objects.hash(type, jsonViewAnnotation, includePropertiesWithoutJSONView, processedAnnotations, schemaProperty, isSubtype, schemaProperty ? propertyName : null);
}

private boolean processableAnnotationPackage(Package pkg) {
String pkgName = pkg.getName();
return !pkgName.startsWith("java.") && !pkgName.startsWith("jdk.") && !pkgName.startsWith("sun.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import io.swagger.v3.oas.models.media.Schema;
import org.testng.annotations.Test;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.Set;
Expand Down Expand Up @@ -69,4 +70,57 @@ public void testCacheHitsForRepeatedStringTypeWithCorrectedEquals() throws Excep
.count();
assertEquals(stringTypeCount, 1, "With the correct equals/hashCode, String type should be added to the cache only once.");
}

@Test
@SuppressWarnings("unchecked")
public void testNoCacheHitForAFieldThatIsMarkedAsDeprecated() throws Exception {
ModelConverterContextImpl context = new ModelConverterContextImpl(new FooBarDummyModelConverter());
Schema fooSchema = context.resolve(new AnnotatedType(Foo.class));
assertNotNull(fooSchema);
Field processedTypesField = ModelConverterContextImpl.class.getDeclaredField("processedTypes");
processedTypesField.setAccessible(true);
Set<AnnotatedType> processedTypes = (Set<AnnotatedType>) processedTypesField.get(context);
long stringTypeCount = processedTypes.stream()
.filter(annotatedType -> annotatedType.getType().equals(String.class))
.count();
assertEquals(stringTypeCount, 2, "With the correct equals/hashCode, String type should be added to the cache twice, since one of them is deprecated.");
}

private static class FooBarDummyModelConverter implements ModelConverter {
@Override
public Schema resolve(AnnotatedType type, ModelConverterContext context, Iterator<ModelConverter> chain) {
if (type.getType().equals(Foo.class)) {
context.resolve(new AnnotatedType(String.class).propertyName("fizz").ctxAnnotations(new Annotation[]{getAnnotationInstance(Deprecated.class)}));
context.resolve(new AnnotatedType(String.class).propertyName("buzz"));
context.resolve(new AnnotatedType(Bar.class).propertyName("bar"));
return new Schema();
}
if (type.getType().equals(Bar.class)) {
context.resolve(new AnnotatedType(String.class).propertyName("fizz"));
context.resolve(new AnnotatedType(String.class).propertyName("buzz"));
return new Schema();
}
return new Schema();
}
}

private static Annotation getAnnotationInstance(Class<? extends Annotation> clazz) {
try {
return Foo.class.getDeclaredField("fizz").getAnnotation(clazz);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
}

static class Foo {
@Deprecated
public String fizz;
public String buzz;
public Bar bar;
}

static class Bar {
public String fizz;
public String buzz;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,7 @@
import io.swagger.v3.core.converter.AnnotatedType;
import org.testng.annotations.Test;

import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.*;
import java.lang.reflect.Type;
import java.util.HashSet;
import java.util.Set;
Expand Down Expand Up @@ -49,20 +45,22 @@ public void testEqualsAndHashCode_shouldBeOrderInsensitiveForAnnotations() {
}

/**
* Tests that JDK/internal annotations are filtered out for equals() and hashCode() comparison.
* Tests that the JDK Deprecated annotation is considered for equals() and hashCode() comparison.
*/
@Test
public void testEqualsAndHashCode_shouldIgnoreJdkInternalAnnotations() {
public void testEqualsAndHashCode_shouldIncludeJdkDeprecatedAnnotations() {
Annotation annA = getAnnotationInstance(TestAnnA.class);
Annotation deprecated = getAnnotationInstance(Deprecated.class);
AnnotatedType typeWithUserAnn = new AnnotatedType(String.class).ctxAnnotations(new Annotation[]{annA});
AnnotatedType typeWithJdkAnn = new AnnotatedType(String.class).ctxAnnotations(new Annotation[]{annA, deprecated});
AnnotatedType typeWithJdkAnnAndUserAnn = new AnnotatedType(String.class).ctxAnnotations(new Annotation[]{deprecated, annA});
AnnotatedType typeWithUserAnnAndJdkAnn = new AnnotatedType(String.class).ctxAnnotations(new Annotation[]{annA, deprecated});
AnnotatedType typeWithOnlyJdkAnn = new AnnotatedType(String.class).ctxAnnotations(new Annotation[]{deprecated});
AnnotatedType typeWithNoAnn = new AnnotatedType(String.class);
assertEquals(typeWithUserAnn, typeWithJdkAnn, "JDK annotations should be ignored in equality comparison.");
assertEquals(typeWithUserAnn.hashCode(), typeWithJdkAnn.hashCode(), "JDK annotations should be ignored in hashCode calculation.");
assertEquals(typeWithOnlyJdkAnn, typeWithNoAnn, "An object with only JDK annotations should be equal to one with no annotations.");
assertEquals(typeWithOnlyJdkAnn.hashCode(), typeWithNoAnn.hashCode(), "The hash code of an object with only JDK annotations should be the same as one with no annotations.");
assertNotEquals(typeWithUserAnn, typeWithJdkAnnAndUserAnn, "JDK Deprecated annotation should be included in equality comparison.");
assertNotEquals(typeWithUserAnn.hashCode(), typeWithJdkAnnAndUserAnn.hashCode(), "JDK Deprecated annotation should be included in hashCode calculation.");
assertNotEquals(typeWithOnlyJdkAnn, typeWithNoAnn, "An object with only JDK Deprecated annotation should not be equal to one with no annotations.");
assertNotEquals(typeWithOnlyJdkAnn.hashCode(), typeWithNoAnn.hashCode(), "The hash code of an object with only a JDK Deprecated annotation should not be the same as one with no annotations.");
assertEquals(typeWithJdkAnnAndUserAnn, typeWithUserAnnAndJdkAnn, "Hash codes should be equal even if annotation order is different.");
}

/**
Expand Down