Repository: jooby-project/jooby
Pull request #3411 (2024-04-18 18:13:20)

Fix/dagger mvc openapi
@jknack    
My previous PR https://github.com/jooby-project/jooby/pull/3398 about Avaje BeanScope controllers parsing in openapi broke the dagger controllers parsing. My apologies, here is the fix


Patch:
diff --git a/modules/jooby-openapi/src/main/java/io/jooby/internal/openapi/AnnotationParser.java b/modules/jooby-openapi/src/main/java/io/jooby/internal/openapi/AnnotationParser.java
index 5962aca40..d9dc17f67 100644
--- a/modules/jooby-openapi/src/main/java/io/jooby/internal/openapi/AnnotationParser.java
+++ b/modules/jooby-openapi/src/main/java/io/jooby/internal/openapi/AnnotationParser.java
@@ -19,15 +19,7 @@ import java.util.stream.Stream;
 
 import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.Type;
-import org.objectweb.asm.tree.AbstractInsnNode;
-import org.objectweb.asm.tree.AnnotationNode;
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.tree.FieldInsnNode;
-import org.objectweb.asm.tree.LdcInsnNode;
-import org.objectweb.asm.tree.LocalVariableNode;
-import org.objectweb.asm.tree.MethodInsnNode;
-import org.objectweb.asm.tree.MethodNode;
-import org.objectweb.asm.tree.ParameterNode;
+import org.objectweb.asm.tree.*;
 
 import io.jooby.Context;
 import io.jooby.MediaType;
@@ -207,13 +199,26 @@ public class AnnotationParser {
           Type type = Type.getObjectType(methodInsnNode.owner);
           return parse(ctx, prefix, type);
         } else if (methodInsnNode.getOpcode() == Opcodes.INVOKEINTERFACE) {
-          // mvc(beanScope.get(...));
-          Type type = (Type) ((LdcInsnNode) methodInsnNode.getPrevious()).cst;
-          return parse(ctx, prefix, type);
+          AbstractInsnNode methodPrev = methodInsnNode.getPrevious();
+          if (methodPrev instanceof VarInsnNode) {
+            // mvc(daggerApp.myController());
+            Type type = Type.getReturnType(methodInsnNode.desc);
+            return parse(ctx, prefix, type);
+          } else if (methodPrev instanceof LdcInsnNode ldcInsnNode) {
+            // mvc(beanScope.get(...));
+            Type type = (Type) (ldcInsnNode).cst;
+            return parse(ctx, prefix, type);
+          }
         } else {
-          // mvc(some.myController());
-          Type type = Type.getReturnType(methodInsnNode.desc);
-          return parse(ctx, prefix, type);
+          if (methodInsnNode.getPrevious() instanceof LdcInsnNode ldcInsnNode) {
+            // mvc(require(Controller.class))
+            Type type = (Type) (ldcInsnNode).cst;
+            return parse(ctx, prefix, type);
+          } else {
+            // mvc(some.myController());
+            Type type = Type.getReturnType(methodInsnNode.desc);
+            return parse(ctx, prefix, type);
+          }
         }
       } else if (previous instanceof FieldInsnNode) {
         FieldInsnNode fieldInsnNode = (FieldInsnNode) previous;


Test patch:
diff --git a/modules/jooby-openapi/src/test/java/examples/MvcDaggerApp.java b/modules/jooby-openapi/src/test/java/examples/MvcDaggerApp.java
new file mode 100644
index 000000000..f0fa98f7d
--- /dev/null
+++ b/modules/jooby-openapi/src/test/java/examples/MvcDaggerApp.java
@@ -0,0 +1,38 @@
+package examples;
+
+import io.jooby.Jooby;
+import io.jooby.OpenAPIModule;
+import io.jooby.annotation.GET;
+import io.jooby.annotation.Path;
+
+public class MvcDaggerApp extends Jooby {
+
+    // simulate dagger app
+    interface DaggerApp {
+        Controller controller();
+    }
+    static class DaggerAppImpl implements DaggerApp {
+
+        public Controller controller() {
+            return new Controller();
+        }
+
+    }
+
+
+    @Path("/")
+    static class Controller {
+
+        @GET("/welcome")
+        public String sayHi() {
+            return "hi";
+        }
+    }
+
+    {
+        install(new OpenAPIModule());
+        DaggerApp daggerApp = new DaggerAppImpl();
+
+        mvc(daggerApp.controller());
+    }
+}
diff --git a/modules/jooby-openapi/src/test/java/examples/MvcRequireApp.java b/modules/jooby-openapi/src/test/java/examples/MvcRequireApp.java
new file mode 100644
index 000000000..976a1badf
--- /dev/null
+++ b/modules/jooby-openapi/src/test/java/examples/MvcRequireApp.java
@@ -0,0 +1,24 @@
+package examples;
+
+import io.jooby.Jooby;
+import io.jooby.OpenAPIModule;
+import io.jooby.annotation.GET;
+import io.jooby.annotation.Path;
+
+public class MvcRequireApp extends Jooby {
+
+    @Path("/")
+    static class Controller {
+
+        @GET("/welcome")
+        public String sayHi() {
+            return "hi";
+        }
+    }
+
+    {
+        install(new OpenAPIModule());
+
+        mvc(require(Controller.class));
+    }
+}
diff --git a/modules/jooby-openapi/src/test/java/io/jooby/openapi/OpenAPIYamlTest.java b/modules/jooby-openapi/src/test/java/io/jooby/openapi/OpenAPIYamlTest.java
index af44a48d5..fb1e7ed41 100644
--- a/modules/jooby-openapi/src/test/java/io/jooby/openapi/OpenAPIYamlTest.java
+++ b/modules/jooby-openapi/src/test/java/io/jooby/openapi/OpenAPIYamlTest.java
@@ -5,14 +5,11 @@
  */
 package io.jooby.openapi;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-import examples.FilterApp;
-import examples.FormApp;
-import examples.FormMvcApp;
-import examples.MinApp;
+import examples.*;
 import kt.KtMinApp;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
 public class OpenAPIYamlTest {
 
   @OpenAPITest(value = MinApp.class)
@@ -576,4 +573,48 @@ public class OpenAPIYamlTest {
             + "                type: string\n",
         result.toYaml());
   }
+
+  @OpenAPITest(value = MvcDaggerApp.class)
+  public void shouldParseDaggerController(OpenAPIResult result) {
+    assertEquals(
+            "openapi: 3.0.1\n"
+                    + "info:\n"
+                    + "  title: MvcDagger API\n"
+                    + "  description: MvcDagger API description\n"
+                    + "  version: \"1.0\"\n"
+                    + "paths:\n"
+                    + "  /welcome:\n"
+                    + "    get:\n"
+                    + "      operationId: sayHi\n"
+                    + "      responses:\n"
+                    + "        \"200\":\n"
+                    + "          description: Success\n"
+                    + "          content:\n"
+                    + "            application/json:\n"
+                    + "              schema:\n"
+                    + "                type: string\n",
+            result.toYaml());
+  }
+
+  @OpenAPITest(value = MvcRequireApp.class)
+  public void shouldParseMvcRequireController(OpenAPIResult result) {
+    assertEquals(
+            "openapi: 3.0.1\n"
+                    + "info:\n"
+                    + "  title: MvcRequire API\n"
+                    + "  description: MvcRequire API description\n"
+                    + "  version: \"1.0\"\n"
+                    + "paths:\n"
+                    + "  /welcome:\n"
+                    + "    get:\n"
+                    + "      operationId: sayHi\n"
+                    + "      responses:\n"
+                    + "        \"200\":\n"
+                    + "          description: Success\n"
+                    + "          content:\n"
+                    + "            application/json:\n"
+                    + "              schema:\n"
+                    + "                type: string\n",
+            result.toYaml());
+  }
 }
diff --git a/modules/jooby-openapi/src/test/java/issues/i3397/Issue3397.java b/modules/jooby-openapi/src/test/java/issues/i3397/Issue3397.java
index deeec8fc7..a346c679c 100644
--- a/modules/jooby-openapi/src/test/java/issues/i3397/Issue3397.java
+++ b/modules/jooby-openapi/src/test/java/issues/i3397/Issue3397.java
@@ -9,7 +9,6 @@ public class Issue3397 {
 
   @OpenAPITest(value = App3397.class)
   public void shouldParseAvajeBeanScopeControllers(OpenAPIResult result) {
-   var s = result.toYaml();
     assertEquals(
         "openapi: 3.0.1\n"
             + "info:\n"