Skip to content

Commit e07c928

Browse files
committed
open-api: parse javadoc #3729
- better support for tags
1 parent e53dd2f commit e07c928

File tree

5 files changed

+60
-33
lines changed

5 files changed

+60
-33
lines changed

modules/jooby-openapi/src/main/java/io/jooby/internal/openapi/AnnotationParser.java

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import io.swagger.v3.oas.models.media.ObjectSchema;
3434
import io.swagger.v3.oas.models.media.Schema;
3535
import io.swagger.v3.oas.models.parameters.Parameter;
36-
import io.swagger.v3.oas.models.tags.Tag;
3736
import jakarta.inject.Named;
3837
import jakarta.inject.Provider;
3938

@@ -280,7 +279,7 @@ public static List<OperationExt> parse(ParserContext ctx, String prefix, Type ty
280279
doc -> {
281280
operationExt.setPathDescription(doc.getDescription());
282281
operationExt.setPathSummary(doc.getSummary());
283-
tags(doc.getTags()).forEach(operationExt::addTag);
282+
doc.getTags().forEach(operationExt::addTag);
284283
if (!doc.getExtensions().isEmpty()) {
285284
operationExt.setPathExtensions(doc.getExtensions());
286285
}
@@ -298,7 +297,7 @@ public static List<OperationExt> parse(ParserContext ctx, String prefix, Type ty
298297
if (!methodDoc.getExtensions().isEmpty()) {
299298
operationExt.setExtensions(methodDoc.getExtensions());
300299
}
301-
tags(methodDoc.getTags()).forEach(operationExt::addTag);
300+
methodDoc.getTags().forEach(operationExt::addTag);
302301
// Parameters
303302
for (var parameterName : parameterNames) {
304303
var paramExt =
@@ -346,17 +345,6 @@ public static List<OperationExt> parse(ParserContext ctx, String prefix, Type ty
346345
return result;
347346
}
348347

349-
private static List<Tag> tags(Map<String, String> tags) {
350-
List<Tag> result = new ArrayList<>();
351-
for (var tagNode : tags.entrySet()) {
352-
var tag = new Tag();
353-
tag.setName(tagNode.getKey());
354-
tag.setDescription(tagNode.getValue());
355-
result.add(tag);
356-
}
357-
return result;
358-
}
359-
360348
private static Map<String, MethodNode> methods(ParserContext ctx, ClassNode node) {
361349
Map<String, MethodNode> methods = new LinkedHashMap<>();
362350
if (node.superName != null && !node.superName.equals(TypeFactory.OBJECT.getInternalName())) {

modules/jooby-openapi/src/main/java/io/jooby/internal/openapi/javadoc/ExtensionJavaDocParser.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,11 @@ public static Map<String, Object> parse(List<String> properties) {
3434
(List<String>) currentNode.computeIfAbsent(finalKey, k -> new ArrayList<String>());
3535
values.add(value);
3636
}
37-
return (Map<String, Object>) restructureNode(root);
37+
var result = restructureNode(root);
38+
if (result instanceof Map) {
39+
return (Map<String, Object>) result;
40+
}
41+
throw new IllegalStateException("DD");
3842
}
3943

4044
/**

modules/jooby-openapi/src/main/java/io/jooby/internal/openapi/javadoc/JavaDocNode.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import com.puppycrawl.tools.checkstyle.api.DetailNode;
1818
import com.puppycrawl.tools.checkstyle.api.JavadocTokenTypes;
1919
import com.puppycrawl.tools.checkstyle.utils.JavadocUtil;
20+
import io.swagger.v3.oas.models.tags.Tag;
2021

2122
public class JavaDocNode {
2223
private static final Predicate<DetailNode> JAVADOC_TAG =
@@ -26,7 +27,7 @@ public class JavaDocNode {
2627
protected final DetailAST node;
2728
protected final DetailNode javadoc;
2829
private final Map<String, Object> extensions;
29-
private final Map<String, String> tags;
30+
private final List<Tag> tags;
3031

3132
public JavaDocNode(JavaDocParser ctx, DetailAST node, DetailAST comment) {
3233
this(ctx, node, toJavaDocNode(comment));
@@ -76,7 +77,7 @@ public String getSummary() {
7677
return string.isEmpty() ? null : string;
7778
}
7879

79-
public Map<String, String> getTags() {
80+
public List<Tag> getTags() {
8081
return tags;
8182
}
8283

modules/jooby-openapi/src/main/java/io/jooby/internal/openapi/javadoc/JavaDocTag.java

Lines changed: 48 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@
1818
import io.jooby.SneakyThrows.Consumer3;
1919
import io.jooby.StatusCode;
2020
import io.swagger.v3.oas.models.servers.Server;
21+
import io.swagger.v3.oas.models.tags.Tag;
2122

2223
public class JavaDocTag {
2324
private static final Predicate<DetailNode> CUSTOM_TAG =
2425
javadocToken(JavadocTokenTypes.CUSTOM_NAME);
2526
private static final Predicate<DetailNode> TAG =
26-
CUSTOM_TAG.and(it -> it.getText().equals("@tag"));
27+
CUSTOM_TAG.and(it -> it.getText().startsWith("@tag.") || it.getText().equals("@tag"));
2728
private static final Predicate<DetailNode> SERVER =
2829
CUSTOM_TAG.and(it -> it.getText().startsWith("@server."));
2930
private static final Predicate<DetailNode> EXTENSION =
@@ -124,31 +125,63 @@ public static Map<String, Object> extensions(DetailNode node) {
124125
return ExtensionJavaDocParser.parse(values);
125126
}
126127

127-
public static Map<String, String> tags(DetailNode node) {
128-
var result = new LinkedHashMap<String, String>();
128+
public static List<Tag> tags(DetailNode node) {
129+
var result = new ArrayList<Tag>();
130+
var values = new ArrayList<String>();
129131
javaDocTag(
130132
node,
131133
TAG,
132134
(tag, value) -> {
133-
var dot = value.indexOf(".");
134-
var tagName = value;
135-
String tagDescription = null;
136-
if (dot > 0) {
137-
tagName = value.substring(0, dot);
138-
if (dot + 1 < value.length()) {
139-
tagDescription = value.substring(dot + 1).trim();
140-
if (tagDescription.isBlank()) {
141-
tagDescription = null;
135+
if (tag.getText().equals("@tag")) {
136+
// Process single line tag:
137+
// - @tag Book. Book Operations
138+
// - @tag Book
139+
var dot = value.indexOf(".");
140+
var tagName = value;
141+
String tagDescription = null;
142+
if (dot > 0) {
143+
tagName = value.substring(0, dot);
144+
if (dot + 1 < value.length()) {
145+
tagDescription = value.substring(dot + 1).trim();
146+
if (tagDescription.isBlank()) {
147+
tagDescription = null;
148+
}
142149
}
143150
}
144-
}
145-
if (!tagName.trim().isEmpty()) {
146-
result.put(tagName, tagDescription);
151+
if (!tagName.trim().isEmpty()) {
152+
153+
result.add(createTag(tagName, tagDescription));
154+
}
155+
} else {
156+
values.add(tag.getText().substring(1));
157+
values.add(value);
147158
}
148159
});
160+
if (!values.isEmpty()) {
161+
var tagMap = ExtensionJavaDocParser.parse(values);
162+
var tags = tagMap.get("tag");
163+
if (!(tags instanceof List<?>)) {
164+
tags = List.of(tags);
165+
}
166+
((List) tags)
167+
.forEach(
168+
e -> {
169+
if (e instanceof Map<?, ?> hash) {
170+
result.add(
171+
createTag((String) hash.get("name"), (String) hash.get("description")));
172+
}
173+
});
174+
}
149175
return result;
150176
}
151177

178+
private static Tag createTag(String tagName, String tagDescription) {
179+
Tag tag = new Tag();
180+
tag.setName(tagName);
181+
tag.setDescription(tagDescription);
182+
return tag;
183+
}
184+
152185
public static void javaDocTag(
153186
DetailNode tree, Predicate<DetailNode> filter, Consumer2<DetailNode, String> consumer) {
154187
javaDocTag(tree, filter, (tag, value, text) -> consumer.accept(tag, text));

modules/jooby-openapi/src/test/java/issues/i3729/api/LibraryApi.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
*
1717
* <p>Contains all operations for creating, updating and fetching books.
1818
*
19-
* @tag Library. Access to all books.
19+
* @tag.name Library
20+
* @tag.description Access to all books.
2021
*/
2122
@Path("/api/library")
2223
public class LibraryApi {

0 commit comments

Comments
 (0)