Skip to content

Commit

Permalink
return Observable from Spring MVC
Browse files Browse the repository at this point in the history
  • Loading branch information
spencergibb committed Feb 24, 2015
1 parent e0db270 commit a301aba
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 20 deletions.
31 changes: 31 additions & 0 deletions myfeed-core/src/main/java/myfeed/MyfeedAutoConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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<HandlerMethodReturnValueHandler> originalHandlers = new ArrayList<>(requestMappingHandlerAdapter.getReturnValueHandlers());
originalHandlers.add(0, observableReturnValueHandler());

This comment has been minimized.

Copy link
@rstoyanchev

rstoyanchev May 29, 2015

I only noticed this now as I tried to recommend it somewhere else. This is less than ideal, not to mention hard to figure out. I've created https://jira.spring.io/browse/SPR-13083.

requestMappingHandlerAdapter.setReturnValueHandlers(originalHandlers);
}

/*@Override
public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
returnValueHandlers.add(0, observableReturnValueHandler());
}*/
}
}
17 changes: 7 additions & 10 deletions myfeed-core/src/main/java/myfeed/ObservableReturnValueHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
}
}
14 changes: 4 additions & 10 deletions myfeed-ui/src/main/java/myfeed/ui/UiController.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package myfeed.ui;

import static rx.Observable.*;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

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;
Expand All @@ -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
*/
Expand All @@ -34,11 +31,8 @@ public class UiController {
@Autowired
private AsyncRest rest;

@Autowired
private Rest syncRest;

@RequestMapping("/ui/feed/{username}")
public DeferredResult<Feed> feed(@PathVariable("username") String username) {
public Observable<Feed> feed(@PathVariable("username") String username) {
Observable<List<FeedItem>> feedItems = from(rest.get("http://myfeed-feed/{username}", FEED_ITEM_TYPE, username))
.map(HttpEntity::getBody);

Expand All @@ -56,7 +50,7 @@ public DeferredResult<Feed> feed(@PathVariable("username") String username) {
return zip(u, following, feedItems, Feed::new);
});

return new ObservableAdapter<>(feed);
return feed;
}

private Observable<ResponseEntity<User>> getUser(String url, String username) {
Expand Down

0 comments on commit a301aba

Please sign in to comment.