From a301aba6139fce7a87a1aab1d1311e6ceb8adfb7 Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Tue, 24 Feb 2015 10:08:37 -0700 Subject: [PATCH] return Observable from Spring MVC --- .../main/java/myfeed/MyfeedAutoConfig.java | 31 +++++++++++++++++++ .../myfeed/ObservableReturnValueHandler.java | 17 +++++----- .../src/main/java/myfeed/ui/UiController.java | 14 +++------ 3 files changed, 42 insertions(+), 20 deletions(-) diff --git a/myfeed-core/src/main/java/myfeed/MyfeedAutoConfig.java b/myfeed-core/src/main/java/myfeed/MyfeedAutoConfig.java index 38c9d86..5bb1b12 100644 --- a/myfeed-core/src/main/java/myfeed/MyfeedAutoConfig.java +++ b/myfeed-core/src/main/java/myfeed/MyfeedAutoConfig.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; import org.springframework.cloud.netflix.ribbon.RibbonInterceptor; import org.springframework.context.annotation.Bean; @@ -14,7 +16,12 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.client.AsyncRestTemplate; import org.springframework.web.client.RestTemplate; +import org.springframework.web.method.support.HandlerMethodReturnValueHandler; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; +import rx.Observable; +import javax.annotation.PostConstruct; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; @@ -89,4 +96,28 @@ public AsyncRestTemplate asyncRestTemplate(RibbonInterceptor interceptor, LoadBa public TraversonFactory traversonFactory(LoadBalancerClient loadBalancerClient) { return new TraversonFactory(loadBalancerClient); } + + @Configuration + @ConditionalOnClass(Observable.class) + public static class WebConfig extends WebMvcConfigurerAdapter { + @Autowired + private RequestMappingHandlerAdapter requestMappingHandlerAdapter; + + @Bean + public ObservableReturnValueHandler observableReturnValueHandler() { + return new ObservableReturnValueHandler(); + } + + @PostConstruct + public void init() { + final List originalHandlers = new ArrayList<>(requestMappingHandlerAdapter.getReturnValueHandlers()); + originalHandlers.add(0, observableReturnValueHandler()); + requestMappingHandlerAdapter.setReturnValueHandlers(originalHandlers); + } + + /*@Override + public void addReturnValueHandlers(List returnValueHandlers) { + returnValueHandlers.add(0, observableReturnValueHandler()); + }*/ + } } diff --git a/myfeed-core/src/main/java/myfeed/ObservableReturnValueHandler.java b/myfeed-core/src/main/java/myfeed/ObservableReturnValueHandler.java index cf4874a..959f997 100644 --- a/myfeed-core/src/main/java/myfeed/ObservableReturnValueHandler.java +++ b/myfeed-core/src/main/java/myfeed/ObservableReturnValueHandler.java @@ -2,11 +2,11 @@ import org.springframework.core.MethodParameter; import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.context.request.async.WebAsyncUtils; import org.springframework.web.method.support.HandlerMethodReturnValueHandler; import org.springframework.web.method.support.ModelAndViewContainer; -import rx.Observable; -import java.util.Map; +import rx.Observable; /** * @author Spencer Gibb @@ -23,13 +23,10 @@ public void handleReturnValue(Object returnValue, MethodParameter returnType, Mo return; } - if (returnValue instanceof Observable) { - Observable observable = (Observable) returnValue; - mavContainer.addAttribute(observable.toBlocking().first()); - } else { - // should not happen - throw new UnsupportedOperationException("Unexpected return type: " + - returnType.getParameterType().getName() + " in method: " + returnType.getMethod()); - } + Observable observable = Observable.class.cast(returnValue); + + ObservableAdapter adapter = new ObservableAdapter<>(observable); + WebAsyncUtils.getAsyncManager(webRequest) + .startDeferredResultProcessing(adapter, mavContainer); } } diff --git a/myfeed-ui/src/main/java/myfeed/ui/UiController.java b/myfeed-ui/src/main/java/myfeed/ui/UiController.java index ec0d46e..b09982b 100644 --- a/myfeed-ui/src/main/java/myfeed/ui/UiController.java +++ b/myfeed-ui/src/main/java/myfeed/ui/UiController.java @@ -1,5 +1,7 @@ package myfeed.ui; +import static rx.Observable.*; + import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -7,8 +9,6 @@ import lombok.Data; import lombok.NoArgsConstructor; import myfeed.AsyncRest; -import myfeed.ObservableAdapter; -import myfeed.Rest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.ParameterizedTypeReference; @@ -18,11 +18,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.context.request.async.DeferredResult; import rx.Observable; -import static rx.Observable.*; - /** * @author Spencer Gibb */ @@ -34,11 +31,8 @@ public class UiController { @Autowired private AsyncRest rest; - @Autowired - private Rest syncRest; - @RequestMapping("/ui/feed/{username}") - public DeferredResult feed(@PathVariable("username") String username) { + public Observable feed(@PathVariable("username") String username) { Observable> feedItems = from(rest.get("http://myfeed-feed/{username}", FEED_ITEM_TYPE, username)) .map(HttpEntity::getBody); @@ -56,7 +50,7 @@ public DeferredResult feed(@PathVariable("username") String username) { return zip(u, following, feedItems, Feed::new); }); - return new ObservableAdapter<>(feed); + return feed; } private Observable> getUser(String url, String username) {