Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -277,61 +277,16 @@ public static List<OperationExt> parse(ParserContext ctx, String prefix, Type ty
.parse(className)
.ifPresent(
doc -> {
operationExt.setPathDescription(doc.getDescription());
operationExt.setPathSummary(doc.getSummary());
doc.getTags().forEach(operationExt::addTag);
if (!doc.getExtensions().isEmpty()) {
operationExt.setPathExtensions(doc.getExtensions());
}
JavaDocSetter.setPath(operationExt, doc);
var parameterNames =
Optional.ofNullable(operationExt.getNode().parameters)
.orElse(List.of())
.stream()
.map(p -> p.name)
operationExt.getNode().parameters.stream().map(p -> p.name).toList();
var parameterTypes =
Stream.of(Type.getArgumentTypes(operationExt.getNode().desc))
.map(Type::getClassName)
.toList();
doc.getMethod(operationExt.getOperationId(), parameterNames)
doc.getMethod(operationExt.getOperationId(), parameterTypes)
.ifPresent(
methodDoc -> {
operationExt.setSummary(methodDoc.getSummary());
operationExt.setDescription(methodDoc.getDescription());
if (!methodDoc.getExtensions().isEmpty()) {
operationExt.setExtensions(methodDoc.getExtensions());
}
methodDoc.getTags().forEach(operationExt::addTag);
// Parameters
for (var parameterName : parameterNames) {
var paramExt =
operationExt.getParameters().stream()
.filter(p -> p.getName().equals(parameterName))
.findFirst()
.map(ParameterExt.class::cast)
.orElse(null);
var paramDoc = methodDoc.getParameterDoc(parameterName);
if (paramDoc != null) {
if (paramExt == null) {
operationExt.getRequestBody().setDescription(paramDoc);
} else {
paramExt.setDescription(paramDoc);
}
}
}
// return types
var defaultResponse = operationExt.getDefaultResponse();
if (defaultResponse != null) {
defaultResponse.setDescription(methodDoc.getReturnDoc());
}
for (var throwsDoc : methodDoc.getThrows().values()) {
var response =
operationExt.getResponse(
Integer.toString(throwsDoc.getStatusCode().value()));
if (response == null) {
response =
operationExt.addResponse(
Integer.toString(throwsDoc.getStatusCode().value()));
}
response.setDescription(throwsDoc.getText());
}
});
methodDoc -> JavaDocSetter.set(operationExt, methodDoc, parameterNames));
});
} catch (Exception x) {
throw SneakyThrows.propagate(x);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Jooby https://jooby.io
* Apache License Version 2.0 https://jooby.io/LICENSE.txt
* Copyright 2014 Edgar Espina
*/
package io.jooby.internal.openapi;

import java.util.LinkedHashSet;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import io.jooby.internal.openapi.javadoc.JavaDocNode;
import io.jooby.internal.openapi.javadoc.MethodDoc;
import io.jooby.internal.openapi.javadoc.ScriptDoc;
import io.swagger.v3.oas.models.parameters.Parameter;

public class JavaDocSetter {

public static void setPath(OperationExt operation, JavaDocNode doc) {
operation.setPathDescription(doc.getDescription());
operation.setPathSummary(doc.getSummary());
doc.getTags().forEach(operation::addTag);
if (!doc.getExtensions().isEmpty()) {
operation.setPathExtensions(doc.getExtensions());
}
}

public static void set(OperationExt operation, ScriptDoc doc) {
var parameters = Optional.ofNullable(operation.getParameters()).orElse(List.of());
var parameterNames = parameters.stream().map(Parameter::getName).collect(Collectors.toList());
if (operation.getRequestBody() != null) {
var javaDocNames = new LinkedHashSet<>(doc.getJavadocParameterNames());
parameterNames.forEach(javaDocNames::remove);
if (javaDocNames.size() == 1) {
// just add body name on lambda/script routes.
parameterNames.addAll(javaDocNames);
}
}
set(operation, doc, parameterNames);
}

public static void set(OperationExt operation, MethodDoc doc, List<String> parameterNames) {
operation.setOperationId(
Optional.ofNullable(operation.getOperationId()).orElse(doc.getOperationId()));
operation.setSummary(doc.getSummary());
operation.setDescription(doc.getDescription());
if (!doc.getExtensions().isEmpty()) {
operation.setExtensions(doc.getExtensions());
}
doc.getTags().forEach(operation::addTag);
// Parameters
for (var parameterName : parameterNames) {
var paramExt =
operation.getParameters().stream()
.filter(p -> p.getName().equals(parameterName))
.findFirst()
.map(ParameterExt.class::cast)
.orElse(null);
var paramDoc = doc.getParameterDoc(parameterName);
if (paramDoc != null) {
if (paramExt == null) {
var body = operation.getRequestBody();
if (body != null) {
body.setDescription(paramDoc);
}
} else {
paramExt.setDescription(paramDoc);
}
}
}
// return types
var defaultResponse = operation.getDefaultResponse();
if (defaultResponse != null) {
defaultResponse.setDescription(doc.getReturnDoc());
}
for (var throwsDoc : doc.getThrows().values()) {
var response = operation.getResponse(throwsDoc.getCode());
if (response == null) {
response = operation.addResponse(throwsDoc.getCode());
}
response.setDescription(throwsDoc.getDescription());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,11 @@ public void setController(ClassNode controller) {
this.controller = controller;
}

@Override
public void setOperationId(String operationId) {
super.setOperationId(operationId);
}

@JsonIgnore
public List<AnnotationNode> getAllAnnotations() {
return Stream.of(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ public class RequestBodyExt extends RequestBody {

@JsonIgnore private String contentType = MediaType.JSON;

{
setRequired(true);
}

public String getJavaType() {
return javaType;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ public List<OperationExt> parse(ParserContext ctx, OpenAPIExt openapi) {
Optional.ofNullable(ctx.getMainClass()).orElse(ctx.getRouter().getClassName());
ClassNode application = ctx.classNode(Type.getObjectType(applicationName.replace(".", "/")));

// JavaDoc
addJavaDoc(ctx, ctx.getRouter().getClassName(), "", operations);

// swagger/openapi:
for (OperationExt operation : operations) {
operation.setApplication(application);
Expand Down Expand Up @@ -100,6 +103,29 @@ public List<OperationExt> parse(ParserContext ctx, OpenAPIExt openapi) {
return result;
}

private static void addJavaDoc(
ParserContext ctx, String className, String prefix, List<OperationExt> operations) {
// javadoc
var offset = prefix == null || prefix.isEmpty() ? 0 : prefix.length();
var javaDoc = ctx.javadoc().parse(className);
for (OperationExt operation : operations) {
// Script/lambda
if (operation.getController() == null) {
javaDoc
.flatMap(
doc ->
doc.getScript(operation.getMethod(), operation.getPattern().substring(offset)))
.ifPresent(
scriptDoc -> {
if (scriptDoc.getPath() != null) {
JavaDocSetter.setPath(operation, scriptDoc.getPath());
}
JavaDocSetter.set(operation, scriptDoc);
});
}
}
}

private void checkResponses(ParserContext ctx, OperationExt operation) {
// checkResponse(ctx, operation, 200, operation.getDefaultResponse());
for (Map.Entry<String, ApiResponse> entry : operation.getResponses().entrySet()) {
Expand Down Expand Up @@ -591,7 +617,9 @@ private List<OperationExt> mountRouter(
throw new UnsupportedOperationException(InsnSupport.toString(node));
}
ClassNode classNode = ctx.classNode(router);
return parse(ctx.newContext(router), prefix, classNode);
var operations = parse(ctx.newContext(router), prefix, classNode);
addJavaDoc(ctx, router.getClassName(), prefix, operations);
return operations;
}

private List<OperationExt> installApp(
Expand All @@ -616,7 +644,9 @@ private List<OperationExt> installApp(
throw new UnsupportedOperationException(InsnSupport.toString(node));
}
ClassNode classNode = ctx.classNode(router);
return parse(ctx.newContext(router), prefix, classNode);
var operations = parse(ctx.newContext(router), prefix, classNode);
addJavaDoc(ctx, router.getClassName(), prefix, operations);
return operations;
}

private Type kotlinSupplier(ParserContext ctx, MethodInsnNode node, AbstractInsnNode ins) {
Expand Down Expand Up @@ -880,7 +910,8 @@ private OperationExt newRouteDescriptor(
node.name.equals("apply")
|| node.name.equals("invoke")
|| node.name.startsWith("invoke$")
|| node.name.contains("$lambda");
|| node.name.contains("$lambda")
|| node.name.startsWith("fake$");
if (notSynthetic && !lambda) {
operation.setOperationId(node.name);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
*/
package io.jooby.internal.openapi.javadoc;

import static io.jooby.internal.openapi.javadoc.JavaDocSupport.*;
import static io.jooby.internal.openapi.javadoc.JavaDocStream.*;
import static io.jooby.internal.openapi.javadoc.JavaDocSupport.getClassName;

import java.util.*;
import java.util.stream.Collectors;
Expand All @@ -24,6 +25,7 @@
public class ClassDoc extends JavaDocNode {
private final Map<String, FieldDoc> fields = new LinkedHashMap<>();
private final Map<String, MethodDoc> methods = new LinkedHashMap<>();
private final Map<String, ScriptDoc> scripts = new LinkedHashMap<>();
private final List<Server> servers;
private final List<Contact> contact;
private final List<License> license;
Expand Down Expand Up @@ -115,7 +117,11 @@ private void defaultRecordMembers() {
/* Virtual method */
var method =
new MethodDoc(
context, createVirtualMember(name.getText(), TokenTypes.METHOD_DEF), memberDoc);
context,
createVirtualMember(name.getText(), TokenTypes.METHOD_DEF),
memberDoc)
.markAsVirtual();

addMethod(method);
});
}
Expand All @@ -140,7 +146,7 @@ private void defaultEnumMembers() {
}
}

private static DetailAstImpl createVirtualMember(String name, int tokenType) {
private DetailAstImpl createVirtualMember(String name, int tokenType) {
var publicMod = new DetailAstImpl();
publicMod.initialize(
TokenTypes.LITERAL_PUBLIC, TokenUtil.getTokenName(TokenTypes.LITERAL_PUBLIC));
Expand All @@ -160,6 +166,10 @@ public void addMethod(MethodDoc method) {
this.methods.put(toMethodSignature(method), method);
}

public void addScript(ScriptDoc method) {
this.scripts.put(toScriptSignature(method), method);
}

public void addField(FieldDoc field) {
this.fields.put(field.getName(), field);
}
Expand All @@ -168,48 +178,40 @@ public Optional<FieldDoc> getField(String name) {
return Optional.ofNullable(fields.get(name));
}

public Optional<MethodDoc> getMethod(String name, List<String> parameterNames) {
return Optional.ofNullable(methods.get(toMethodSignature(name, parameterNames)));
public Optional<MethodDoc> getMethod(String name, List<String> types) {
return Optional.ofNullable(methods.get(toMethodSignature(name, types)));
}

public Optional<ScriptDoc> getScript(String method, String pattern) {
return Optional.ofNullable(scripts.get(toScriptSignature(method, pattern)));
}

private String toScriptSignature(ScriptDoc method) {
return toScriptSignature(method.getMethod(), method.getPattern());
}

private String toScriptSignature(String method, String pattern) {
return method + "/" + pattern;
}

private String toMethodSignature(MethodDoc method) {
return toMethodSignature(method.getName(), method.getParameterNames());
return toMethodSignature(method.getName(), method.getParameterTypes());
}

private String toMethodSignature(String methodName, List<String> parameterNames) {
return methodName + parameterNames.stream().collect(Collectors.joining(", ", "(", ")"));
private String toMethodSignature(String methodName, List<String> types) {
return methodName + types.stream().collect(Collectors.joining(", ", "(", ")"));
}

public String getSimpleName() {
return getSimpleName(node);
return JavaDocSupport.getSimpleName(node);
}

protected String getSimpleName(DetailAST node) {
return node.findFirstToken(TokenTypes.IDENT).getText();
public String getName() {
return getClassName(node);
}

public String getName() {
var classScope =
Stream.concat(
Stream.of(node),
backward(node)
.filter(
tokens(
TokenTypes.CLASS_DEF,
TokenTypes.INTERFACE_DEF,
TokenTypes.ENUM_DEF,
TokenTypes.RECORD_DEF)))
.map(this::getSimpleName)
.toList();
var packageScope =
backward(node)
.filter(tokens(TokenTypes.COMPILATION_UNIT))
.findFirst()
.flatMap(it -> tree(it).filter(tokens(TokenTypes.PACKAGE_DEF)).findFirst())
.map(it -> tree(it).filter(tokens(TokenTypes.IDENT)).map(DetailAST::getText).toList())
.orElse(List.of());
return Stream.concat(packageScope.stream(), classScope.stream())
.collect(Collectors.joining("."));
public String getPackage() {
return JavaDocSupport.getPackageName(node);
}

public boolean isRecord() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.DetailNode;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;

public class FieldDoc extends JavaDocNode {
public FieldDoc(JavaDocParser ctx, DetailAST node, DetailAST javadoc) {
Expand All @@ -19,6 +18,6 @@ public FieldDoc(JavaDocParser ctx, DetailAST node, DetailAST javadoc) {
}

public String getName() {
return node.findFirstToken(TokenTypes.IDENT).getText();
return JavaDocSupport.getSimpleName(node);
}
}
Loading
Loading