Skip to content

Commit 0e66825

Browse files
committed
openapi: lambda routes can't be hidden fix #3575
1 parent 8a734f4 commit 0e66825

6 files changed

Lines changed: 118 additions & 50 deletions

File tree

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

Lines changed: 2 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@
3232
import io.jooby.annotation.Path;
3333
import io.jooby.annotation.PathParam;
3434
import io.jooby.annotation.QueryParam;
35-
import io.swagger.v3.oas.annotations.Hidden;
36-
import io.swagger.v3.oas.annotations.Operation;
3735
import io.swagger.v3.oas.models.media.Content;
3836
import io.swagger.v3.oas.models.media.ObjectSchema;
3937
import io.swagger.v3.oas.models.media.Schema;
@@ -265,26 +263,18 @@ private static Map<String, MethodNode> methods(ParserContext ctx, ClassNode node
265263

266264
private static List<OperationExt> routerMethod(
267265
ParserContext ctx, String prefix, ClassNode classNode, MethodNode method) {
268-
List<OperationExt> result = new ArrayList<>();
269266

270267
AtomicReference<RequestBodyExt> requestBody = new AtomicReference<>();
271268
List<ParameterExt> arguments = routerArguments(ctx, method, requestBody::set);
272269
ResponseExt response = returnTypes(method);
273270

274-
// If the method is hidden, don't generate an operation for it
275-
if (isHidden(method.visibleAnnotations)) {
276-
return result;
277-
}
278-
271+
List<OperationExt> result = new ArrayList<>();
279272
for (String httpMethod : httpMethod(method.visibleAnnotations)) {
280273
for (String pattern : httpPattern(ctx, classNode, method, httpMethod)) {
281274
OperationExt operation =
282275
new OperationExt(
283276
method, httpMethod, RoutePath.path(prefix, pattern), arguments, response);
284277
operation.setOperationId(method.name);
285-
if (isDeprecated(method.visibleAnnotations)) {
286-
operation.setDeprecated(true);
287-
}
288278
Optional.ofNullable(requestBody.get()).ifPresent(operation::setRequestBody);
289279

290280
result.add(operation);
@@ -294,31 +284,6 @@ private static List<OperationExt> routerMethod(
294284
return result;
295285
}
296286

297-
private static boolean isDeprecated(List<AnnotationNode> annotations) {
298-
if (annotations != null) {
299-
return annotations.stream()
300-
.anyMatch(a -> a.desc.equals(Type.getDescriptor(Deprecated.class)));
301-
}
302-
return false;
303-
}
304-
305-
private static boolean isHidden(List<AnnotationNode> annotations) {
306-
if (annotations != null) {
307-
// If the method is annotated with @Hidden, it's always hidden
308-
boolean hiddenAnnotationExists =
309-
annotations.stream().anyMatch(a -> a.desc.equals(Type.getDescriptor(Hidden.class)));
310-
311-
if (hiddenAnnotationExists) {
312-
return true;
313-
}
314-
315-
// If the method is annotated with @Operation, and the value of "hidden" is true, it's hidden
316-
return findAnnotationByType(annotations, Operation.class).stream()
317-
.anyMatch(it -> boolValue(toMap(it), "hidden"));
318-
}
319-
return false;
320-
}
321-
322287
private static ResponseExt returnTypes(MethodNode method) {
323288
Signature signature = Signature.create(method);
324289
String desc = Optional.ofNullable(method.signature).orElse(method.desc);
@@ -393,9 +358,7 @@ private static List<ParameterExt> routerArguments(
393358
ParamType paramType = ParamType.find(annotations);
394359

395360
/* Required: */
396-
boolean required =
397-
isPrimitive(javaType)
398-
|| !isNullable(method, i); // !javaType.startsWith("java.util.Optional");
361+
boolean required = isPrimitive(javaType) || !isNullable(method, i);
399362

400363
if (paramType == ParamType.BODY) {
401364
RequestBodyExt body = new RequestBodyExt();

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

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,7 @@
3939
import io.jooby.MediaType;
4040
import io.swagger.v3.core.util.Json;
4141
import io.swagger.v3.core.util.RefUtils;
42-
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
43-
import io.swagger.v3.oas.annotations.Operation;
44-
import io.swagger.v3.oas.annotations.Parameter;
45-
import io.swagger.v3.oas.annotations.Parameters;
42+
import io.swagger.v3.oas.annotations.*;
4643
import io.swagger.v3.oas.annotations.enums.Explode;
4744
import io.swagger.v3.oas.annotations.enums.ParameterIn;
4845
import io.swagger.v3.oas.annotations.extensions.Extension;
@@ -184,6 +181,25 @@ private static void flow(
184181
consumer.accept(flow);
185182
}
186183

184+
private static Boolean isHidden(List<AnnotationNode> annotations) {
185+
if (annotations != null) {
186+
// If the method is annotated with @Hidden, it's always hidden
187+
return annotations.stream().anyMatch(a -> a.desc.equals(Type.getDescriptor(Hidden.class)))
188+
? true
189+
: null;
190+
}
191+
return null;
192+
}
193+
194+
private static Boolean isDeprecated(List<AnnotationNode> annotations) {
195+
if (annotations != null) {
196+
return annotations.stream().anyMatch(a -> a.desc.equals(Type.getDescriptor(Deprecated.class)))
197+
? true
198+
: null;
199+
}
200+
return null;
201+
}
202+
187203
public static void parse(ParserContext ctx, OperationExt operation) {
188204
/** Tags: */
189205
MethodNode method = operation.getNode();
@@ -196,6 +212,8 @@ public static void parse(ParserContext ctx, OperationExt operation) {
196212
.findFirst()
197213
.ifPresent(it -> tags(singletonList(toMap(it)), operation::addTag));
198214

215+
operation.setHidden(isHidden(annotations));
216+
operation.setDeprecated(isDeprecated(annotations));
199217
/**
200218
* @Operation:
201219
*/
@@ -392,9 +410,15 @@ private static void operation(
392410

393411
stringValue(annotation, "method", operation::setMethod);
394412

395-
boolValue(annotation, "deprecated", operation::setDeprecated);
413+
if (operation.getDeprecated() != Boolean.TRUE) {
414+
// Don't override deprecated
415+
boolValue(annotation, "deprecated", operation::setDeprecated);
416+
}
396417

397-
boolValue(annotation, "hidden", operation::setHidden);
418+
if (operation.getHidden() != Boolean.TRUE) {
419+
// Don't override hidden
420+
boolValue(annotation, "hidden", operation::setHidden);
421+
}
398422

399423
stringValue(annotation, "summary", operation::setSummary);
400424

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -253,9 +253,15 @@ private String patternToOperationId(String pattern) {
253253
}
254254

255255
private void cleanup(List<OperationExt> operations) {
256-
for (OperationExt operation : operations) {
257-
if (operation.getParameters().isEmpty()) {
258-
operation.setParameters(null);
256+
var it = operations.iterator();
257+
while (it.hasNext()) {
258+
var operation = it.next();
259+
if (operation.getHidden() == Boolean.TRUE) {
260+
it.remove();
261+
} else {
262+
if (operation.getParameters().isEmpty()) {
263+
operation.setParameters(null);
264+
}
259265
}
260266
}
261267
}
@@ -326,8 +332,7 @@ private List<OperationExt> routeHandler(ParserContext ctx, String prefix, Method
326332
AbstractInsnNode instructionTo = null;
327333
int routeIndex = -1;
328334
for (AbstractInsnNode it : method.instructions) {
329-
if (it instanceof MethodInsnNode && ctx.process(it)) {
330-
MethodInsnNode node = (MethodInsnNode) it;
335+
if (it instanceof MethodInsnNode node && ctx.process(it)) {
331336
Signature signature = Signature.create(node);
332337
if (ctx.isRouter(signature.getOwner().orElse(null))) {
333338
if (signature.matches("mvc")) {
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Jooby https://jooby.io
3+
* Apache License Version 2.0 https://jooby.io/LICENSE.txt
4+
* Copyright 2014 Edgar Espina
5+
*/
6+
package issues.i3575;
7+
8+
import io.jooby.Context;
9+
import io.jooby.Jooby;
10+
import io.swagger.v3.oas.annotations.Hidden;
11+
import io.swagger.v3.oas.annotations.Operation;
12+
13+
public class App3575 extends Jooby {
14+
{
15+
get("/", this::home);
16+
get("/hide-op", this::hideOp);
17+
18+
mvc(Controller3575.class);
19+
}
20+
21+
@Operation(hidden = true)
22+
private Object hideOp(Context context) {
23+
return null;
24+
}
25+
26+
@Hidden
27+
private Object home(Context context) {
28+
return null;
29+
}
30+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Jooby https://jooby.io
3+
* Apache License Version 2.0 https://jooby.io/LICENSE.txt
4+
* Copyright 2014 Edgar Espina
5+
*/
6+
package issues.i3575;
7+
8+
import io.jooby.annotation.GET;
9+
import io.jooby.annotation.Path;
10+
import io.swagger.v3.oas.annotations.Hidden;
11+
12+
@Path("/3575")
13+
public class Controller3575 {
14+
15+
@GET("/mvc")
16+
@Hidden
17+
public String sayHi() {
18+
return "hi";
19+
}
20+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Jooby https://jooby.io
3+
* Apache License Version 2.0 https://jooby.io/LICENSE.txt
4+
* Copyright 2014 Edgar Espina
5+
*/
6+
package issues.i3575;
7+
8+
import static org.junit.jupiter.api.Assertions.assertEquals;
9+
10+
import io.jooby.openapi.OpenAPIResult;
11+
import io.jooby.openapi.OpenAPITest;
12+
13+
public class Issue3575 {
14+
15+
@OpenAPITest(value = App3575.class)
16+
public void shouldHideFromLambdaReference(OpenAPIResult result) {
17+
assertEquals(
18+
"openapi: 3.0.1\n"
19+
+ "info:\n"
20+
+ " title: 3575 API\n"
21+
+ " description: 3575 API description\n"
22+
+ " version: \"1.0\"\n"
23+
+ "paths: {}\n",
24+
result.toYaml());
25+
}
26+
}

0 commit comments

Comments
 (0)