jooby icon indicating copy to clipboard operation
jooby copied to clipboard

Allow extension to provide handlers for routes' return type

Open Gui-Yom opened this issue 3 years ago • 3 comments

It would be cool to allow extensions to provide handlers for return types. Example : I want to add first party support for reactive Mutiny types (Uni<T> and Multi<T>). Some links : https://github.com/smallrye/smallrye-mutiny & https://smallrye.io/smallrye-mutiny.

By taking a look at io.jooby.Pipeline, this looks hardcoded for core types and most common reactive libraries types but this looks pretty straightforward :

// Single:
    Optional<Class> single = loadClass(loader, "io.reactivex.Single");
    if (single.isPresent()) {
      if (single.get().isAssignableFrom(type)) {
        return single(mode, route, executor);
      }
    }
// and

private static Handler single(ExecutionMode mode, Route next, Executor executor) {
    return next(mode, executor,
        new DetachHandler(decorate(next, new RxSingleHandler(next.getPipeline()))),
        false);
  }

Offloading this logic into extensions would permit a cleaner way to add support for other types by requiring the user to install a module and removing those loadClass calls (less reflection is good). This would also allow to remove the core module dependencies related to those.

Providing an api similar to MessageEncoder/MessageDecoder would be nice. From jooby-jackson :

application.decoder(MediaType.json, this);

Proposition :

application.monadResolver(Single.class, this);

Is it something you can consider ? Maybe you already thought of it ?

Gui-Yom avatar Aug 14 '20 15:08 Gui-Yom

Like it. I want to remove those loadClass checks from core and make this more modular (like it was in 1.x). The reason why I added like this was to simplify integration.

But in general:

  • remove the return type concept (bc it is based on reflection)
  • move the reactive types to his own module

In 1.x we do have something like:

use(new Rx());

get("/", () -> Observable.from("reactive programming in jooby!"));

Where Rx was an extension that install a filter/decorator

jknack avatar Aug 14 '20 18:08 jknack

Just realize that there is an API for custom types: https://www.javadoc.io/doc/io.jooby/jooby/latest/io/jooby/ResponseHandler.html


MyExtension {
    install(Jooby app) {
       app.responseHandler(...);
   }
}

Rocker template engine uses a custom response handler: https://github.com/jooby-project/jooby/blob/2.x/modules/jooby-rocker/src/main/java/io/jooby/rocker/RockerModule.java#L45

Still we should improve and make it better:

  • reflection free
  • extract reactive types to his own module

jknack avatar Aug 18 '20 00:08 jknack

I think the only reactive support that should be provided is JDK 9 Flow. All the reactive libraries have bridges to JDK 9 Flow and it seems reasonable to support a data structure that is builtin. CompletableFuture for singles and Flow.Publisher for streams is good enough for OOB.

However you still need to move it out to its own module since Flow requires 9.

agentgt avatar Dec 31 '20 19:12 agentgt