Skip to content

Commit 6316259

Browse files
committed
openapi: javadoc
- working in progress of adding javadoc to openapi - still a lot to do
1 parent 6ff90e2 commit 6316259

24 files changed

Lines changed: 876 additions & 182 deletions

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

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
import static java.util.Arrays.asList;
1111
import static java.util.Collections.singletonList;
1212

13+
import java.io.File;
14+
import java.nio.file.Paths;
1315
import java.util.*;
1416
import java.util.concurrent.atomic.AtomicReference;
1517
import java.util.function.Consumer;
@@ -32,6 +34,7 @@
3234
import io.jooby.annotation.Path;
3335
import io.jooby.annotation.PathParam;
3436
import io.jooby.annotation.QueryParam;
37+
import io.jooby.internal.openapi.javadoc.JavaDocParser;
3538
import io.swagger.v3.oas.models.media.Content;
3639
import io.swagger.v3.oas.models.media.ObjectSchema;
3740
import io.swagger.v3.oas.models.media.Schema;
@@ -251,9 +254,18 @@ public static List<OperationExt> parse(
251254
return parse(ctx, prefix, type);
252255
}
253256
}
254-
return Collections.emptyList();
257+
return List.of();
255258
}
256259

260+
/**
261+
* This is the main entrypoint beside there is a public {@link #parse(ParserContext, String,
262+
* Signature, MethodInsnNode)}.
263+
*
264+
* @param ctx
265+
* @param prefix
266+
* @param type
267+
* @return
268+
*/
257269
public static List<OperationExt> parse(ParserContext ctx, String prefix, Type type) {
258270
List<OperationExt> result = new ArrayList<>();
259271
ClassNode classNode = ctx.classNode(type);
@@ -262,10 +274,63 @@ public static List<OperationExt> parse(ParserContext ctx, String prefix, Type ty
262274
ctx.debugHandler(method);
263275
result.addAll(routerMethod(ctx, prefix, classNode, method));
264276
}
265-
result.forEach(it -> it.setController(classNode));
277+
var javadocContext = ctx.javadoc();
278+
var javadocParser = new JavaDocParser(javadocContext);
279+
for (OperationExt operationExt : result) {
280+
operationExt.setController(classNode);
281+
try {
282+
var className = operationExt.getControllerName();
283+
javadocParser
284+
.parseMvc(toJavaPath(className))
285+
.ifPresent(
286+
doc -> {
287+
operationExt.setPathDescription(doc.getDescription());
288+
operationExt.setPathSummary(doc.getSummary());
289+
var args =
290+
operationExt.getParameters().stream()
291+
.map(ParameterExt.class::cast)
292+
.map(
293+
p ->
294+
Optional.ofNullable(p.getContainerType()).orElse(p.getJavaType()))
295+
.map(
296+
qualifiedName -> {
297+
var index = qualifiedName.lastIndexOf('.');
298+
return index == -1
299+
? qualifiedName
300+
: qualifiedName.substring(index + 1);
301+
})
302+
.toList();
303+
doc.getMethod(operationExt.getOperationId(), args)
304+
.ifPresent(
305+
methodDoc -> {
306+
operationExt.setSummary(methodDoc.getSummary());
307+
operationExt.setDescription(methodDoc.getDescription());
308+
309+
for (var parameter : operationExt.getParameters()) {
310+
var paramExt = (ParameterExt) parameter;
311+
var paramDoc =
312+
methodDoc.getParameterDoc(
313+
paramExt.getName(), paramExt.getContainerType());
314+
if (paramDoc != null) {
315+
paramExt.setDescription(paramDoc);
316+
}
317+
}
318+
});
319+
});
320+
} catch (Exception x) {
321+
// TODO: how to log from here
322+
x.printStackTrace();
323+
}
324+
}
266325
return result;
267326
}
268327

328+
private static java.nio.file.Path toJavaPath(String className) {
329+
var segments = className.split("/");
330+
segments[segments.length - 1] = segments[segments.length - 1] + ".java";
331+
return Paths.get(String.join(File.separator, segments));
332+
}
333+
269334
private static Map<String, MethodNode> methods(ParserContext ctx, ClassNode node) {
270335
Map<String, MethodNode> methods = new LinkedHashMap<>();
271336
if (node.superName != null && !node.superName.equals(TypeFactory.OBJECT.getInternalName())) {

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

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@
7070
import io.jooby.FileUpload;
7171
import io.jooby.SneakyThrows;
7272
import io.jooby.StatusCode;
73+
import io.jooby.internal.openapi.javadoc.JavaDocContext;
74+
import io.jooby.internal.openapi.javadoc.JavaDocParser;
7375
import io.jooby.openapi.DebugOption;
7476
import io.swagger.v3.core.converter.ModelConverters;
7577
import io.swagger.v3.core.converter.ResolvedSchema;
@@ -107,17 +109,24 @@ public TypeLiteral() {}
107109
private final Set<Object> instructions = new HashSet<>();
108110
private final Set<DebugOption> debug;
109111
private final ConcurrentMap<String, SchemaRef> schemas = new ConcurrentHashMap<>();
112+
private final JavaDocContext javadocContext;
110113

111-
public ParserContext(ClassSource source, Type router, Set<DebugOption> debug) {
112-
this(source, new HashMap<>(), router, debug);
114+
public ParserContext(
115+
ClassSource source, Type router, JavaDocContext javadocContext, Set<DebugOption> debug) {
116+
this(source, new HashMap<>(), router, javadocContext, debug);
113117
}
114118

115119
private ParserContext(
116-
ClassSource source, Map<Type, ClassNode> nodes, Type router, Set<DebugOption> debug) {
120+
ClassSource source,
121+
Map<Type, ClassNode> nodes,
122+
Type router,
123+
JavaDocContext javadocContext,
124+
Set<DebugOption> debug) {
117125
this.router = router;
118126
this.source = source;
119127
this.debug = Optional.ofNullable(debug).orElse(Collections.emptySet());
120128
this.nodes = nodes;
129+
this.javadocContext = javadocContext;
121130

122131
List<ObjectMapper> mappers = asList(Json.mapper(), Yaml.mapper());
123132
jacksonModules(source.getClassLoader(), mappers);
@@ -163,6 +172,10 @@ public Collection<Schema> schemas() {
163172
return schemas.values().stream().map(ref -> ref.schema).collect(Collectors.toList());
164173
}
165174

175+
public JavaDocContext javadoc() {
176+
return javadocContext;
177+
}
178+
166179
public Schema schema(Class type) {
167180
if (isVoid(type.getName())) {
168181
return null;
@@ -269,20 +282,25 @@ public Schema schema(Class type) {
269282
new SchemaRef(
270283
resolvedSchema.schema, RefUtils.constructRef(resolvedSchema.schema.getName()));
271284
schemas.put(type.getName(), schemaRef);
272-
285+
document(type.getName(), resolvedSchema.schema);
273286
if (resolvedSchema.referencedSchemas != null) {
274287
for (Map.Entry<String, Schema> e : resolvedSchema.referencedSchemas.entrySet()) {
275288
if (!e.getKey().equals(schemaRef.schema.getName())) {
276289
SchemaRef dependency =
277290
new SchemaRef(e.getValue(), RefUtils.constructRef(e.getValue().getName()));
278291
schemas.putIfAbsent(e.getKey(), dependency);
292+
document(e.getKey(), dependency.schema);
279293
}
280294
}
281295
}
282296
}
283297
return schemaRef.toSchema();
284298
}
285299

300+
private void document(String typeName, Schema schema) {
301+
var parser = new JavaDocParser(javadocContext);
302+
}
303+
286304
public Optional<SchemaRef> schemaRef(String type) {
287305
return Optional.ofNullable(schemas.get(type));
288306
}
@@ -429,7 +447,7 @@ public boolean process(AbstractInsnNode instruction) {
429447
}
430448

431449
public ParserContext newContext(Type router) {
432-
return new ParserContext(source, nodes, router, debug);
450+
return new ParserContext(source, nodes, router, javadocContext, debug);
433451
}
434452

435453
public String getMainClass() {

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,19 @@
55
*/
66
package io.jooby.internal.openapi;
77

8-
import java.util.Optional;
9-
108
import io.swagger.v3.oas.models.media.Schema;
119

1210
public class SchemaRef {
1311
public final Schema schema;
1412

15-
public final Optional<String> ref;
13+
public final String ref;
1614

1715
public SchemaRef(Schema schema, String ref) {
1816
this.schema = schema;
19-
this.ref = Optional.ofNullable(ref);
17+
this.ref = ref;
2018
}
2119

2220
public Schema toSchema() {
23-
return this.ref.map(ref -> new Schema().$ref(ref)).orElse(this.schema);
21+
return ref == null ? schema : new Schema().$ref(ref);
2422
}
2523
}

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

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,12 @@
1414
import java.util.stream.Collectors;
1515

1616
import com.puppycrawl.tools.checkstyle.api.DetailAST;
17-
import com.puppycrawl.tools.checkstyle.api.JavadocTokenTypes;
1817
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
1918

2019
public class ClassDoc extends JavaDocNode {
2120

2221
private final DetailAST node;
23-
private List<MethodDoc> methods = new ArrayList<>();
22+
private final List<MethodDoc> methods = new ArrayList<>();
2423

2524
public ClassDoc(JavaDocContext ctx, DetailAST node, DetailAST javaDoc) {
2625
super(ctx, javaDoc);
@@ -31,31 +30,13 @@ public void addMethod(MethodDoc method) {
3130
this.methods.add(method);
3231
}
3332

34-
public String getSummary() {
35-
var text = new StringBuilder();
36-
for (var node : forward(javadoc, STOP_TOKENS).toList()) {
37-
if (node.getType() == JavadocTokenTypes.NEWLINE && !text.isEmpty()) {
38-
break;
39-
} else if (node.getType() == JavadocTokenTypes.TEXT) {
40-
text.append(node.getText());
41-
}
42-
}
43-
return text.isEmpty() ? getText().trim() : text.toString().trim();
44-
}
45-
46-
public String getDescription() {
47-
var text = getText();
48-
var summary = getSummary();
49-
return summary.equals(text) ? "" : text.replaceAll(summary, "").trim();
50-
}
51-
5233
public Optional<MethodDoc> getMethod(String name, List<String> parameterNames) {
5334
var filtered = methods.stream().filter(it -> it.getName().equals(name)).toList();
5435
if (filtered.isEmpty()) {
5536
return Optional.empty();
5637
}
5738
if (filtered.size() == 1) {
58-
return Optional.of(filtered.get(0));
39+
return Optional.of(filtered.getFirst());
5940
}
6041
return filtered.stream()
6142
.filter(it -> it.getParameterNames().equals(parameterNames))

0 commit comments

Comments
 (0)