javalin / javalin-routing-extensions

Set of alternative routing implementations for Javalin 5.x
https://github.com/javalin/javalin-routing-extensions/wiki
MIT License
14 stars 2 forks source link

ReflectiveEndpointLoader doesn't detect methods declared in the superclass #47

Open Memexurer opened 1 month ago

Memexurer commented 1 month ago

Actual behavior (the bug) Look at the example code - the only available endpoint is /ab/b; /ab/a doesn't work

Expected behavior Endpoints should be loaded from the superclasses too

To Reproduce

public class TestEndpoints {
    public static class Endpoint1 {
        @Get("/a")
        public void a(Context ctx) {
            ctx.result("a");
        }
    }

    @Endpoints("/ab")
    public static class Endpoint2 extends Endpoint1 {
        @Get("/b")
        public void b(Context ctx) {
            ctx.result("b");
        }
    }
}

Additional context This happens because getDeclaredMethods doesn't return methods declared in the superclasses. This could be fixed by changing getDeclaredMethods invocations inside ReflectiveEndpointLoader class with getMethods (but I think that would break compatibility with earlier versions of javalin-routing-extensions)

dzikoysk commented 1 month ago

Hey, it seems to be a bit specific way to use the annotated api, so we just simply never tried to support it. Is there any particular reason why you're trying to introduce such abstraction at the controller level?

Memexurer commented 1 month ago

Basically I have two classes with very similar endpoints, but only one endpoint is different in those two classes. So I just extracted these similar endpoints to another class which these two classes now extend. But the problem now is, that this project doesn't support such class layout.

dzikoysk commented 1 month ago

Maybe instead of going for straightforwrd inheritance, we could try to support it via the more explicit API. It' should be a bit more user-friendly - especially considering some bigger apps with a lot of endpoints. E.g.:

// as repatable annotation:
@Endpoints("/a")
@Endpoints("/b")
// or via new parameter:
@Endpoints(roots = {"/a", "/b"})
public class SharedEndpoints {
    @Get("/shared")
    public void a(Context ctx) {
        ctx.result("a or b");
    }
}

@Endpoints("/b")
public class BSpecificEndpoints {
    @Get("/extra")
    public void b(Context ctx) {
        ctx.result("b");
    }
}