Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring MVC + DeferredResult add Hateoas stuff

For the rest interface the Spring MVC + RxJava + DeferredResult returned from controllers is used.

I am thinking about adding Hateoas support to the endpoints. The natural choice would be the Spring Hateoas. The problem is that Spring Hateoas would not work in the asynchronous/multi-threading environment since it uses ThreadLocal.

Is there any way to workaround that constraint? I do not think so but maybe someone has any suggestions.

Has anyone used other APIs to add Hateoas support to the rest endpoints?

Thank you.

like image 566
Damian Avatar asked Feb 16 '15 11:02

Damian


People also ask

Should I use spring Hateoas?

Building REST APIs that follow HATEOAS principle is not easy. So Spring HATEOAS provides some APIs that ease the creation of hypermedia links in API responses (links in JSON documents). It works well with Spring MVC and Spring Data JPA and supports for hypermedia formats like HAL (Hypertext Application Language).

How DeferredResult works?

DeferredResult, available from Spring 3.2 onwards, assists in offloading a long-running computation from an http-worker thread to a separate thread. Although the other thread will take some resources for computation, the worker threads are not blocked in the meantime and can handle incoming client requests.

What is DeferredResult?

DeferredResult provides an alternative to using a Callable for asynchronous request processing. While a Callable is executed concurrently on behalf of the application, with a DeferredResult the application can produce the result from a thread of its choice.


1 Answers

So the solution I've used is to closure in the request attributes and then apply them as part of a lift operator

public class RequestContextStashOperator<T> implements Observable.Operator<T, T> {

    private final RequestAttributes attributes;

    /**
     * Spring hateoas requires the request context to be set but observables may happen on other threads
     * This operator will reapply the context of the constructing thread on the execution thread of the subscriber
     */
    public RequestContextStashOperator() {
        attributes = RequestContextHolder.currentRequestAttributes();
    }
    @Override
    public Subscriber<? super T> call(Subscriber<? super T> subscriber) {
        return new Subscriber<T>() {
            @Override
            public void onCompleted() {
                subscriber.onCompleted();
            }

            @Override
            public void onError(Throwable e) {
                subscriber.onError(e);
            }

            @Override
            public void onNext(T t) {
                RequestContextHolder.setRequestAttributes(attributes);
                subscriber.onNext(t);
            }
        };
    }
}

which you can then use on an observable like

lift(new RequestContextStashOperator<>())

as long as the object is created in the same thread as the request. You can then use a map after in the observable chain to map your object up to being a resource and add your hateoas links in.

like image 118
Mark James Talbot Avatar answered Oct 29 '22 14:10

Mark James Talbot