Skip to content
This repository was archived by the owner on Dec 19, 2023. It is now read-only.

Commit f1cb743

Browse files
committed
Merge remote-tracking branch 'origin/master' into deprecated_support
2 parents 2a88467 + ad3b757 commit f1cb743

File tree

5 files changed

+220
-8
lines changed

5 files changed

+220
-8
lines changed

spring-auto-restdocs-core/src/main/java/capital/scalable/restdocs/javadoc/JavadocReaderImpl.java

Lines changed: 65 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -82,20 +82,35 @@ public String resolveFieldTag(Class<?> javaBaseClass, String javaFieldName, Stri
8282
}
8383

8484
@Override
85-
public String resolveMethodComment(Class<?> javaBaseClass, String javaMethodName) {
86-
return classJavadoc(javaBaseClass).getMethodComment(javaMethodName);
85+
public String resolveMethodComment(Class<?> javaBaseClass, final String javaMethodName) {
86+
return resolveCommentFromClassHierarchy(javaBaseClass, new CommentExtractor() {
87+
@Override
88+
public String comment(ClassJavadoc classJavadoc) {
89+
return classJavadoc.getMethodComment(javaMethodName);
90+
}
91+
});
8792
}
8893

8994
@Override
90-
public String resolveMethodParameterComment(Class<?> javaBaseClass, String javaMethodName,
91-
String javaParameterName) {
92-
return classJavadoc(javaBaseClass)
93-
.getMethodParameterComment(javaMethodName, javaParameterName);
95+
public String resolveMethodTag(Class<?> javaBaseClass, final String javaMethodName,
96+
final String tagName) {
97+
return resolveCommentFromClassHierarchy(javaBaseClass, new CommentExtractor() {
98+
@Override
99+
public String comment(ClassJavadoc classJavadoc) {
100+
return classJavadoc.getMethodTag(javaMethodName, tagName);
101+
}
102+
});
94103
}
95104

96105
@Override
97-
public String resolveMethodTag(Class<?> javaBaseClass, String javaMethodName, String tagName) {
98-
return classJavadoc(javaBaseClass).getMethodTag(javaMethodName, tagName);
106+
public String resolveMethodParameterComment(Class<?> javaBaseClass, final String javaMethodName,
107+
final String javaParameterName) {
108+
return resolveCommentFromClassHierarchy(javaBaseClass, new CommentExtractor() {
109+
@Override
110+
public String comment(ClassJavadoc classJavadoc) {
111+
return classJavadoc.getMethodParameterComment(javaMethodName, javaParameterName);
112+
}
113+
});
99114
}
100115

101116
private ClassJavadoc classJavadoc(Class<?> clazz) {
@@ -191,4 +206,46 @@ private static List<File> toAbsoluteDirs(String javadocJsonDirs) {
191206
}
192207
return absoluteDirs;
193208
}
209+
210+
/**
211+
* Walks up the class hierarchy and interfaces until a comment is found or top most class is reached.
212+
* <p>
213+
* Javadoc on super classes and Javadoc on interfaces of super classes has precedence
214+
* over the Javadoc on direct interfaces of the class. This is only important in the rare
215+
* case of competing Javadoc comments.
216+
* <p>
217+
* As we do not know the full method signature here, we can not check
218+
* whether a method in the super class actually overwrites the given method.
219+
* However, the Javadoc model ignores method signatures anyway and it
220+
* should not cause issues for the usual use case.
221+
*/
222+
private String resolveCommentFromClassHierarchy(Class<?> javaBaseClass,
223+
CommentExtractor commentExtractor) {
224+
String comment = commentExtractor.comment(classJavadoc(javaBaseClass));
225+
if (isNotBlank(comment)) {
226+
// Direct Javadoc on a method always wins.
227+
return comment;
228+
}
229+
// Super class has precedence over interfaces, but this also means that interfaces
230+
// of super classes have precedence over interfaces of the class itself.
231+
if (javaBaseClass.getSuperclass() != null) {
232+
String superClassComment =
233+
resolveCommentFromClassHierarchy(javaBaseClass.getSuperclass(),
234+
commentExtractor);
235+
if (isNotBlank(superClassComment)) {
236+
return superClassComment;
237+
}
238+
}
239+
for (Class<?> i : javaBaseClass.getInterfaces()) {
240+
String interfaceComment = resolveCommentFromClassHierarchy(i, commentExtractor);
241+
if (isNotBlank(interfaceComment)) {
242+
return interfaceComment;
243+
}
244+
}
245+
return "";
246+
}
247+
248+
private interface CommentExtractor {
249+
String comment(ClassJavadoc classJavadoc);
250+
}
194251
}

spring-auto-restdocs-core/src/test/java/capital/scalable/restdocs/javadoc/JavadocReaderImplTest.java

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,27 @@ public void resolveMethodCommentFromClasspath() {
8282
assertThat(comment, equalTo("Simple method comment from classpath"));
8383
}
8484

85+
@Test
86+
public void resolveMethodCommentFromInterfaceA() {
87+
JavadocReader javadocReader = JavadocReaderImpl.createWith(SOURCE_DIR);
88+
String comment = javadocReader.resolveMethodComment(ClassC.class, "javadocOnInterfaceA");
89+
assertThat(comment, equalTo("Method comment on interface A"));
90+
}
91+
92+
@Test
93+
public void resolveMethodCommentFromSuperClassB() {
94+
JavadocReader javadocReader = JavadocReaderImpl.createWith(SOURCE_DIR);
95+
String comment = javadocReader.resolveMethodComment(ClassC.class, "javadocOnClassB");
96+
assertThat(comment, equalTo("Method comment on class B"));
97+
}
98+
99+
@Test
100+
public void resolveMethodCommentFromClassC() {
101+
JavadocReader javadocReader = JavadocReaderImpl.createWith(SOURCE_DIR);
102+
String comment = javadocReader.resolveMethodComment(ClassC.class, "javadocOnClassC");
103+
assertThat(comment, equalTo("Method comment on class C"));
104+
}
105+
85106
@Test
86107
public void resolveMethodTag() {
87108
JavadocReader javadocReader = JavadocReaderImpl.createWith(SOURCE_DIR);
@@ -96,6 +117,28 @@ public void resolveMethodTagFromClasspath() {
96117
assertThat(comment, equalTo("Simple method title from classpath"));
97118
}
98119

120+
@Test
121+
public void resolveMethodTagFromInterfaceA() {
122+
JavadocReader javadocReader = JavadocReaderImpl.createWith(SOURCE_DIR);
123+
String comment =
124+
javadocReader.resolveMethodTag(ClassC.class, "javadocOnInterfaceA", "title");
125+
assertThat(comment, equalTo("Method title on interface A"));
126+
}
127+
128+
@Test
129+
public void resolveMethodTagFromSuperClassB() {
130+
JavadocReader javadocReader = JavadocReaderImpl.createWith(SOURCE_DIR);
131+
String comment = javadocReader.resolveMethodTag(ClassC.class, "javadocOnClassB", "title");
132+
assertThat(comment, equalTo("Method title on class B"));
133+
}
134+
135+
@Test
136+
public void resolveMethodTagFromClassC() {
137+
JavadocReader javadocReader = JavadocReaderImpl.createWith(SOURCE_DIR);
138+
String comment = javadocReader.resolveMethodTag(ClassC.class, "javadocOnClassC", "title");
139+
assertThat(comment, equalTo("Method title on class C"));
140+
}
141+
99142
@Test
100143
public void resolveMethodParameterComment() {
101144
JavadocReader javadocReader = JavadocReaderImpl.createWith(SOURCE_DIR);
@@ -112,6 +155,30 @@ public void resolveMethodParameterCommentFromClasspath() {
112155
assertThat(comment, equalTo("Simple parameter comment from classpath"));
113156
}
114157

158+
@Test
159+
public void resolveMethodParameterCommentFromInterfaceA() {
160+
JavadocReader javadocReader = JavadocReaderImpl.createWith(SOURCE_DIR);
161+
String comment = javadocReader.resolveMethodParameterComment(ClassC.class,
162+
"javadocOnInterfaceA", "parameter");
163+
assertThat(comment, equalTo("Parameter comment on interface A"));
164+
}
165+
166+
@Test
167+
public void resolveMethodParameterCommentFromSuperClassB() {
168+
JavadocReader javadocReader = JavadocReaderImpl.createWith(SOURCE_DIR);
169+
String comment = javadocReader.resolveMethodParameterComment(ClassC.class,
170+
"javadocOnClassB", "parameter");
171+
assertThat(comment, equalTo("Parameter comment on class B"));
172+
}
173+
174+
@Test
175+
public void resolveMethodParameterCommentFromClassC() {
176+
JavadocReader javadocReader = JavadocReaderImpl.createWith(SOURCE_DIR);
177+
String comment = javadocReader.resolveMethodParameterComment(ClassC.class,
178+
"javadocOnClassC", "parameter");
179+
assertThat(comment, equalTo("Parameter comment on class C"));
180+
}
181+
115182
@Test
116183
public void jsonFileDoesNotExist() {
117184
JavadocReader javadocReader = JavadocReaderImpl.createWith(SOURCE_DIR);
@@ -167,6 +234,34 @@ private void simpleMethod(String simpleParameter) {
167234
}
168235
}
169236

237+
private interface InterfaceA {
238+
239+
void javadocOnInterfaceA(String parameter);
240+
241+
void javadocOnClassB(String parameter);
242+
243+
void javadocOnClassC(String parameter);
244+
}
245+
246+
private static class ClassB implements InterfaceA {
247+
248+
@Override
249+
public void javadocOnInterfaceA(String parameter) {
250+
}
251+
252+
@Override
253+
public void javadocOnClassB(String parameter) {
254+
}
255+
256+
@Override
257+
public void javadocOnClassC(String parameter) {
258+
}
259+
}
260+
261+
private static class ClassC extends ClassB {
262+
263+
}
264+
170265
private static class NotExisting {
171266
}
172267
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"fields": {},
3+
"methods": {
4+
"javadocOnClassB": {
5+
"comment": "Method comment on class B",
6+
"parameters": {
7+
"parameter": "Parameter comment on class B"
8+
},
9+
"tags": {
10+
"title": "Method title on class B"
11+
}
12+
}
13+
}
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"fields": {},
3+
"methods": {
4+
"javadocOnClassC": {
5+
"comment": "Method comment on class C",
6+
"parameters": {
7+
"parameter": "Parameter comment on class C"
8+
},
9+
"tags": {
10+
"title": "Method title on class C"
11+
}
12+
}
13+
}
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"fields": {},
3+
"methods": {
4+
"javadocOnInterfaceA": {
5+
"comment": "Method comment on interface A",
6+
"parameters": {
7+
"parameter": "Parameter comment on interface A"
8+
},
9+
"tags": {
10+
"title": "Method title on interface A"
11+
}
12+
},
13+
"javadocOnClassB": {
14+
"comment": "Ignored method comment on interface A",
15+
"parameters": {
16+
"parameter": "Ignored parameter comment on interface A"
17+
},
18+
"tags": {
19+
"title": "Ignored method title on interface A"
20+
}
21+
},
22+
"javadocOnClassC": {
23+
"comment": "Ignored method comment on interface A",
24+
"parameters": {
25+
"parameter": "Ignored parameter comment on interface A"
26+
},
27+
"tags": {
28+
"title": "Ignored method title on interface A"
29+
}
30+
}
31+
}
32+
}

0 commit comments

Comments
 (0)