Skip to content

Commit 576ea45

Browse files
fix: add so that the Java Deprecated annotation is considered a processable annotation type (#5099). Fixes: #5043
* Add so that the Java Deprecated annotation is considered a processable annotation type * Add test showing that we get two cache entries if a field has a deprecated annotation
1 parent c40c53e commit 576ea45

File tree

3 files changed

+74
-17
lines changed

3 files changed

+74
-17
lines changed

modules/swagger-core/src/main/java/io/swagger/v3/core/converter/AnnotatedType.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,8 @@ private List<Annotation> getProcessedAnnotations(Annotation[] annotations) {
263263
}
264264
return Arrays.stream(annotations)
265265
.filter(a -> {
266-
String pkg = a.annotationType().getPackage().getName();
267-
return !pkg.startsWith("java.") && !pkg.startsWith("jdk.") && !pkg.startsWith("sun.");
266+
Package pkg = a.annotationType().getPackage();
267+
return a.annotationType().equals(Deprecated.class) || processableAnnotationPackage(pkg);
268268
})
269269
.sorted(Comparator.comparing(a -> a.annotationType().getName()))
270270
.collect(Collectors.toList());
@@ -275,13 +275,13 @@ public boolean equals(Object o) {
275275
if (this == o) return true;
276276
if (!(o instanceof AnnotatedType)) return false;
277277
AnnotatedType that = (AnnotatedType) o;
278-
List<Annotation> thisAnnotatinons = getProcessedAnnotations(this.ctxAnnotations);
279-
List<Annotation> thatAnnotatinons = getProcessedAnnotations(that.ctxAnnotations);
278+
List<Annotation> thisAnnotations = getProcessedAnnotations(this.ctxAnnotations);
279+
List<Annotation> thatAnnotations = getProcessedAnnotations(that.ctxAnnotations);
280280
return includePropertiesWithoutJSONView == that.includePropertiesWithoutJSONView &&
281281
schemaProperty == that.schemaProperty &&
282282
isSubtype == that.isSubtype &&
283283
Objects.equals(type, that.type) &&
284-
Objects.equals(thisAnnotatinons, thatAnnotatinons) &&
284+
Objects.equals(thisAnnotations, thatAnnotations) &&
285285
Objects.equals(jsonViewAnnotation, that.jsonViewAnnotation) &&
286286
(!schemaProperty || Objects.equals(propertyName, that.propertyName));
287287
}
@@ -291,4 +291,9 @@ public int hashCode() {
291291
List<Annotation> processedAnnotations = getProcessedAnnotations(this.ctxAnnotations);
292292
return Objects.hash(type, jsonViewAnnotation, includePropertiesWithoutJSONView, processedAnnotations, schemaProperty, isSubtype, schemaProperty ? propertyName : null);
293293
}
294+
295+
private boolean processableAnnotationPackage(Package pkg) {
296+
String pkgName = pkg.getName();
297+
return !pkgName.startsWith("java.") && !pkgName.startsWith("jdk.") && !pkgName.startsWith("sun.");
298+
}
294299
}

modules/swagger-core/src/test/java/io/swagger/v3/core/converting/AnnotatedTypeCachingTest.java

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import io.swagger.v3.oas.models.media.Schema;
88
import org.testng.annotations.Test;
99

10+
import java.lang.annotation.Annotation;
1011
import java.lang.reflect.Field;
1112
import java.util.Iterator;
1213
import java.util.Set;
@@ -69,4 +70,57 @@ public void testCacheHitsForRepeatedStringTypeWithCorrectedEquals() throws Excep
6970
.count();
7071
assertEquals(stringTypeCount, 1, "With the correct equals/hashCode, String type should be added to the cache only once.");
7172
}
73+
74+
@Test
75+
@SuppressWarnings("unchecked")
76+
public void testNoCacheHitForAFieldThatIsMarkedAsDeprecated() throws Exception {
77+
ModelConverterContextImpl context = new ModelConverterContextImpl(new FooBarDummyModelConverter());
78+
Schema fooSchema = context.resolve(new AnnotatedType(Foo.class));
79+
assertNotNull(fooSchema);
80+
Field processedTypesField = ModelConverterContextImpl.class.getDeclaredField("processedTypes");
81+
processedTypesField.setAccessible(true);
82+
Set<AnnotatedType> processedTypes = (Set<AnnotatedType>) processedTypesField.get(context);
83+
long stringTypeCount = processedTypes.stream()
84+
.filter(annotatedType -> annotatedType.getType().equals(String.class))
85+
.count();
86+
assertEquals(stringTypeCount, 2, "With the correct equals/hashCode, String type should be added to the cache twice, since one of them is deprecated.");
87+
}
88+
89+
private static class FooBarDummyModelConverter implements ModelConverter {
90+
@Override
91+
public Schema resolve(AnnotatedType type, ModelConverterContext context, Iterator<ModelConverter> chain) {
92+
if (type.getType().equals(Foo.class)) {
93+
context.resolve(new AnnotatedType(String.class).propertyName("fizz").ctxAnnotations(new Annotation[]{getAnnotationInstance(Deprecated.class)}));
94+
context.resolve(new AnnotatedType(String.class).propertyName("buzz"));
95+
context.resolve(new AnnotatedType(Bar.class).propertyName("bar"));
96+
return new Schema();
97+
}
98+
if (type.getType().equals(Bar.class)) {
99+
context.resolve(new AnnotatedType(String.class).propertyName("fizz"));
100+
context.resolve(new AnnotatedType(String.class).propertyName("buzz"));
101+
return new Schema();
102+
}
103+
return new Schema();
104+
}
105+
}
106+
107+
private static Annotation getAnnotationInstance(Class<? extends Annotation> clazz) {
108+
try {
109+
return Foo.class.getDeclaredField("fizz").getAnnotation(clazz);
110+
} catch (NoSuchFieldException e) {
111+
throw new RuntimeException(e);
112+
}
113+
}
114+
115+
static class Foo {
116+
@Deprecated
117+
public String fizz;
118+
public String buzz;
119+
public Bar bar;
120+
}
121+
122+
static class Bar {
123+
public String fizz;
124+
public String buzz;
125+
}
72126
}

modules/swagger-core/src/test/java/io/swagger/v3/core/converting/AnnotatedTypeTest.java

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,7 @@
33
import io.swagger.v3.core.converter.AnnotatedType;
44
import org.testng.annotations.Test;
55

6-
import java.lang.annotation.Annotation;
7-
import java.lang.annotation.ElementType;
8-
import java.lang.annotation.Retention;
9-
import java.lang.annotation.RetentionPolicy;
10-
import java.lang.annotation.Target;
6+
import java.lang.annotation.*;
117
import java.lang.reflect.Type;
128
import java.util.HashSet;
139
import java.util.Set;
@@ -49,20 +45,22 @@ public void testEqualsAndHashCode_shouldBeOrderInsensitiveForAnnotations() {
4945
}
5046

5147
/**
52-
* Tests that JDK/internal annotations are filtered out for equals() and hashCode() comparison.
48+
* Tests that the JDK Deprecated annotation is considered for equals() and hashCode() comparison.
5349
*/
5450
@Test
55-
public void testEqualsAndHashCode_shouldIgnoreJdkInternalAnnotations() {
51+
public void testEqualsAndHashCode_shouldIncludeJdkDeprecatedAnnotations() {
5652
Annotation annA = getAnnotationInstance(TestAnnA.class);
5753
Annotation deprecated = getAnnotationInstance(Deprecated.class);
5854
AnnotatedType typeWithUserAnn = new AnnotatedType(String.class).ctxAnnotations(new Annotation[]{annA});
59-
AnnotatedType typeWithJdkAnn = new AnnotatedType(String.class).ctxAnnotations(new Annotation[]{annA, deprecated});
55+
AnnotatedType typeWithJdkAnnAndUserAnn = new AnnotatedType(String.class).ctxAnnotations(new Annotation[]{deprecated, annA});
56+
AnnotatedType typeWithUserAnnAndJdkAnn = new AnnotatedType(String.class).ctxAnnotations(new Annotation[]{annA, deprecated});
6057
AnnotatedType typeWithOnlyJdkAnn = new AnnotatedType(String.class).ctxAnnotations(new Annotation[]{deprecated});
6158
AnnotatedType typeWithNoAnn = new AnnotatedType(String.class);
62-
assertEquals(typeWithUserAnn, typeWithJdkAnn, "JDK annotations should be ignored in equality comparison.");
63-
assertEquals(typeWithUserAnn.hashCode(), typeWithJdkAnn.hashCode(), "JDK annotations should be ignored in hashCode calculation.");
64-
assertEquals(typeWithOnlyJdkAnn, typeWithNoAnn, "An object with only JDK annotations should be equal to one with no annotations.");
65-
assertEquals(typeWithOnlyJdkAnn.hashCode(), typeWithNoAnn.hashCode(), "The hash code of an object with only JDK annotations should be the same as one with no annotations.");
59+
assertNotEquals(typeWithUserAnn, typeWithJdkAnnAndUserAnn, "JDK Deprecated annotation should be included in equality comparison.");
60+
assertNotEquals(typeWithUserAnn.hashCode(), typeWithJdkAnnAndUserAnn.hashCode(), "JDK Deprecated annotation should be included in hashCode calculation.");
61+
assertNotEquals(typeWithOnlyJdkAnn, typeWithNoAnn, "An object with only JDK Deprecated annotation should not be equal to one with no annotations.");
62+
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.");
63+
assertEquals(typeWithJdkAnnAndUserAnn, typeWithUserAnnAndJdkAnn, "Hash codes should be equal even if annotation order is different.");
6664
}
6765

6866
/**

0 commit comments

Comments
 (0)