zandero / rest.vertx

A JAX-RS like annotation processor for vert.x verticals and more
Apache License 2.0
160 stars 28 forks source link

RestBuilder violates Vert.x 4.3's handler ordering #134

Closed swcm-mnestler closed 2 years ago

swcm-mnestler commented 2 years ago

Description

Since vert.x 4.3 the order in which routes are registered is checked by io.vertx.ext.web.impl.RouteState. Using rest.vertx with vert.x 4.3 can lead to an error in specific circumstances:

Exception in thread "main" java.lang.IllegalStateException: Cannot add [BODY] handler to route with [USER] handler at index 0
    at io.vertx.ext.web.impl.RouteState.addContextHandler(RouteState.java:554)
    at io.vertx.ext.web.impl.RouteImpl.handler(RouteImpl.java:143)
    at com.zandero.rest.RestRouter.register(RestRouter.java:152)
    at com.zandero.rest.RestRouter.register(RestRouter.java:70)
    at com.zandero.rest.RestBuilder.getRouter(RestBuilder.java:497)
    at com.zandero.rest.RestBuilder.build(RestBuilder.java:570)

This can be circumvented by setting the io.vertx.web.router.setup.lenient property to true, but even then a WARNING is logged.

As far as I could tell, this issue occurs

Resolution suggestions

From a cursory glance, the "weight" of a handler is determined by its type. As such, a PlatformHandler should have the highest "priority". So a possible solution would be to mark the custom handlers that are registered before the body handler as implements io.vertx.ext.web.handler.PlatformHandler.

If no marker interface is implemented, priority "USER" is assumed (lowest priority -> register last).

Steps to reproduce

Setup minimal vert.x app with a sample resource

fun main() {
    val vertx = Vertx.vertx()
    val router = RestBuilder(vertx)
        .register(TestResource::class.java)
        .build()
    vertx.createHttpServer().requestHandler(router).listen(8080)
}

@Path("/test")
class TestResource {
    @POST
    fun postFoo(requestBody: String) = requestBody

    @GET
    fun getFoo(@Context user: User?) = "${user?.subject()}"
}

Use vert.x 4.3+ and rest.vertx 1.1

dependencies {
    implementation(platform("io.vertx:vertx-stack-depchain:4.3.3"))
    implementation("io.vertx:vertx-web")
    implementation("com.zandero:rest.vertx:1.1")
}

Run app:

Exception in thread "main" java.lang.IllegalStateException: Cannot add [BODY] handler to route with [USER] handler at index 0
    at io.vertx.ext.web.impl.RouteState.addContextHandler(RouteState.java:554)
    at io.vertx.ext.web.impl.RouteImpl.handler(RouteImpl.java:143)
    at com.zandero.rest.RestRouter.register(RestRouter.java:152)
    at com.zandero.rest.RestRouter.register(RestRouter.java:70)
    at com.zandero.rest.RestBuilder.getRouter(RestBuilder.java:497)
    at com.zandero.rest.RestBuilder.build(RestBuilder.java:570)
    at rest.vertx.repro.AppKt.main(App.kt:10)
    at rest.vertx.repro.AppKt.main(App.kt)
drejc commented 2 years ago

Thanks for reporting this issue ... I will look into it and adjust the route registration order accordingly. Meanwhile you might circumvent the issue by setting the route order by hand with the @RouteOrder(number) annotation. It was not intended for this purpose but might do the trick.

drejc commented 2 years ago

I have hopefully fixed this / have not tested extensively but unit tests work just fine. Please report if you find additional problems.

swcm-mnestler commented 2 years ago

Thank you very much, it seems to work flawlessly!