diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/WebHandlerHandlerAdapter.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/SimpleHandlerAdapter.java similarity index 75% rename from spring-web-reactive/src/main/java/org/springframework/web/reactive/result/WebHandlerHandlerAdapter.java rename to spring-web-reactive/src/main/java/org/springframework/web/reactive/result/SimpleHandlerAdapter.java index c9f8932eb4..a4836426e8 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/WebHandlerHandlerAdapter.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/SimpleHandlerAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,6 @@ package org.springframework.web.reactive.result; -import org.reactivestreams.Publisher; import reactor.core.publisher.Mono; import org.springframework.core.ResolvableType; @@ -27,15 +26,16 @@ import org.springframework.web.server.WebHandler; import org.springframework.web.server.ServerWebExchange; /** - * Adapter to use a {@link WebHandler} through the {@link DispatcherHandler}. + * HandlerAdapter that allows using the plain {@link WebHandler} contract with + * the generic {@link DispatcherHandler}. * * @author Rossen Stoyanchev * @author Sebastien Deleuze */ -public class WebHandlerHandlerAdapter implements HandlerAdapter { +public class SimpleHandlerAdapter implements HandlerAdapter { - private static final ResolvableType PUBLISHER_VOID = ResolvableType.forClassWithGenerics( - Publisher.class, Void.class); + private static final ResolvableType MONO_VOID = ResolvableType.forClassWithGenerics( + Mono.class, Void.class); @Override @@ -47,7 +47,7 @@ public class WebHandlerHandlerAdapter implements HandlerAdapter { public Mono handle(ServerWebExchange exchange, Object handler) { WebHandler webHandler = (WebHandler) handler; Mono mono = webHandler.handle(exchange); - return Mono.just(new HandlerResult(webHandler, mono, PUBLISHER_VOID)); + return Mono.just(new HandlerResult(webHandler, mono, MONO_VOID)); } } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/server/WebHandler.java b/spring-web-reactive/src/main/java/org/springframework/web/server/WebHandler.java index b2c8045b19..45e2da9595 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/server/WebHandler.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/server/WebHandler.java @@ -18,19 +18,18 @@ package org.springframework.web.server; import reactor.core.publisher.Mono; -import org.springframework.web.server.adapter.WebHttpHandlerAdapter; +import org.springframework.web.server.adapter.HttpWebHandlerAdapter; import org.springframework.web.server.adapter.WebHttpHandlerBuilder; /** - * Contract to handle a web server exchange. + * Contract to handle a web request. * - *

Use {@link WebHttpHandlerAdapter} to adapt a {@code WebHandler} to an + *

Use {@link HttpWebHandlerAdapter} to adapt a {@code WebHandler} to an * {@link org.springframework.http.server.reactive.HttpHandler HttpHandler}. * The {@link WebHttpHandlerBuilder} provides a convenient way to do that while * also optionally configuring one or more filters and/or exception handlers. * * @author Rossen Stoyanchev - * @see WebHttpHandlerBuilder */ public interface WebHandler { diff --git a/spring-web-reactive/src/main/java/org/springframework/web/server/adapter/WebHttpHandlerAdapter.java b/spring-web-reactive/src/main/java/org/springframework/web/server/adapter/HttpWebHandlerAdapter.java similarity index 94% rename from spring-web-reactive/src/main/java/org/springframework/web/server/adapter/WebHttpHandlerAdapter.java rename to spring-web-reactive/src/main/java/org/springframework/web/server/adapter/HttpWebHandlerAdapter.java index fab3ffcdcb..da9deadaab 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/server/adapter/WebHttpHandlerAdapter.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/server/adapter/HttpWebHandlerAdapter.java @@ -38,15 +38,15 @@ import org.springframework.web.server.session.WebSessionManager; * * @author Rossen Stoyanchev */ -public class WebHttpHandlerAdapter extends WebHandlerDecorator implements HttpHandler { +public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHandler { - private static Log logger = LogFactory.getLog(WebHttpHandlerAdapter.class); + private static Log logger = LogFactory.getLog(HttpWebHandlerAdapter.class); private WebSessionManager sessionManager = new DefaultWebSessionManager(); - public WebHttpHandlerAdapter(WebHandler delegate) { + public HttpWebHandlerAdapter(WebHandler delegate) { super(delegate); } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/server/adapter/WebHttpHandlerBuilder.java b/spring-web-reactive/src/main/java/org/springframework/web/server/adapter/WebHttpHandlerBuilder.java index 38dfda1b54..8893bf0460 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/server/adapter/WebHttpHandlerBuilder.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/server/adapter/WebHttpHandlerBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,28 +31,20 @@ import org.springframework.web.server.handler.FilteringWebHandler; import org.springframework.web.server.session.WebSessionManager; /** - * Build an {@link org.springframework.http.server.reactive.HttpHandler HttpHandler} - * to handle requests with a chain of {@link #filters(WebFilter...) web filters}, - * a target {@link #webHandler(WebHandler) web handler}, and apply one or more - * {@link #exceptionHandlers(WebExceptionHandler...) exception handlers}. - * - *

Effective this sets up the following {@code WebHandler} delegation:
- * {@link WebHttpHandlerAdapter} {@code -->} - * {@link ExceptionHandlingWebHandler} {@code -->} - * {@link FilteringWebHandler} {@code -->} - * {@link WebHandler} + * Builder for an {@link HttpHandler} that adapts to a target {@link WebHandler} + * along with a chain of {@link WebFilter}s and a set of + * {@link WebExceptionHandler}s. * *

Example usage: *

- * WebFilter myFilter = ... ;
- * WebHandler myHandler = ... ;
+ * WebFilter filter = ... ;
+ * WebHandler webHandler = ... ;
+ * WebExceptionHandler exceptionHandler = ...;
  *
- * HttpHandler httpHandler = WebToHttpHandlerBuilder.webHandler(myHandler)
- *         .filters(myFilter)
- *         .exceptionHandlers(new ResponseStatusExceptionHandler())
+ * HttpHandler httpHandler = WebHttpHandlerBuilder.webHandler(webHandler)
+ *         .filters(filter)
+ *         .exceptionHandlers(exceptionHandler)
  *         .build();
- *
- * // Configure the HttpServer with the created httpHandler
  * 
* * @author Rossen Stoyanchev @@ -70,7 +62,7 @@ public class WebHttpHandlerBuilder { /** * Private constructor. - * See static factory method {@link #webHandler(WebHandler)}. + * See factory method {@link #webHandler(WebHandler)}. */ private WebHttpHandlerBuilder(WebHandler targetHandler) { Assert.notNull(targetHandler, "'targetHandler' must not be null"); @@ -80,10 +72,10 @@ public class WebHttpHandlerBuilder { /** * Factory method to create a new builder instance. - * @param targetHandler the target handler to process requests with + * @param webHandler the target handler for the request */ - public static WebHttpHandlerBuilder webHandler(WebHandler targetHandler) { - return new WebHttpHandlerBuilder(targetHandler); + public static WebHttpHandlerBuilder webHandler(WebHandler webHandler) { + return new WebHttpHandlerBuilder(webHandler); } @@ -114,6 +106,7 @@ public class WebHttpHandlerBuilder { * {@link ServerWebExchange WebServerExchange} * created for each HTTP request. * @param sessionManager the session manager + * @see HttpWebHandlerAdapter#setSessionManager(WebSessionManager) */ public WebHttpHandlerBuilder sessionManager(WebSessionManager sessionManager) { this.sessionManager = sessionManager; @@ -124,35 +117,20 @@ public class WebHttpHandlerBuilder { * Build the {@link HttpHandler}. */ public HttpHandler build() { - WebHandler handler = createWebHandler(); - return adaptWebHandler(handler); - } - - /** - * Create the final (decorated) {@link WebHandler} to use. - */ - protected WebHandler createWebHandler() { WebHandler webHandler = this.targetHandler; - if (!this.exceptionHandlers.isEmpty()) { - WebExceptionHandler[] array = new WebExceptionHandler[this.exceptionHandlers.size()]; - webHandler = new ExceptionHandlingWebHandler(webHandler, this.exceptionHandlers.toArray(array)); - } if (!this.filters.isEmpty()) { WebFilter[] array = new WebFilter[this.filters.size()]; webHandler = new FilteringWebHandler(webHandler, this.filters.toArray(array)); } - return webHandler; - } - - /** - * Adapt the {@link WebHandler} to {@link HttpHandler}. - */ - protected WebHttpHandlerAdapter adaptWebHandler(WebHandler handler) { - WebHttpHandlerAdapter adapter = new WebHttpHandlerAdapter(handler); - if (this.sessionManager != null) { - adapter.setSessionManager(this.sessionManager); + if (!this.exceptionHandlers.isEmpty()) { + WebExceptionHandler[] array = new WebExceptionHandler[this.exceptionHandlers.size()]; + webHandler = new ExceptionHandlingWebHandler(webHandler, this.exceptionHandlers.toArray(array)); } - return adapter; + HttpWebHandlerAdapter httpHandler = new HttpWebHandlerAdapter(webHandler); + if (this.sessionManager != null) { + httpHandler.setSessionManager(this.sessionManager); + } + return httpHandler; } } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/server/handler/FilteringWebHandler.java b/spring-web-reactive/src/main/java/org/springframework/web/server/handler/FilteringWebHandler.java index 8dc1d7396a..de12581575 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/server/handler/FilteringWebHandler.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/server/handler/FilteringWebHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,8 +27,8 @@ import org.springframework.web.server.WebHandler; import org.springframework.web.server.ServerWebExchange; /** - * WebHandler that delegates to a chain of {@link WebFilter} instances followed - * by a target {@link WebHandler}. + * WebHandler that delegates to a chain of {@link WebFilter} instances and then + * to the target {@link WebHandler}. * * @author Rossen Stoyanchev */ diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/WebHandlerIntegrationTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/WebHandlerIntegrationTests.java index dc9a56baf3..7eee8878ed 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/WebHandlerIntegrationTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/WebHandlerIntegrationTests.java @@ -48,7 +48,7 @@ import static org.junit.Assert.assertEquals; /** - * Integration tests with simple WebHandler's processing requests. + * Integration tests with requests mapped to plain {@link WebHandler}s. * * @author Rossen Stoyanchev */ @@ -61,9 +61,9 @@ public class WebHandlerIntegrationTests extends AbstractHttpHandlerIntegrationTe protected HttpHandler createHttpHandler() { StaticApplicationContext wac = new StaticApplicationContext(); - wac.registerSingleton("hm", TestHandlerMapping.class); - wac.registerSingleton("ha", WebHandlerHandlerAdapter.class); - wac.registerSingleton("rh", SimpleResultHandler.class); + wac.registerSingleton("handlerMapping", TestSimpleUrlHandlerMapping.class); + wac.registerSingleton("handlerAdapter", SimpleHandlerAdapter.class); + wac.registerSingleton("resultHandler", SimpleResultHandler.class); wac.refresh(); DispatcherHandler dispatcherHandler = new DispatcherHandler(); @@ -129,9 +129,9 @@ public class WebHandlerIntegrationTests extends AbstractHttpHandlerIntegrationTe } - private static class TestHandlerMapping extends SimpleUrlHandlerMapping { + private static class TestSimpleUrlHandlerMapping extends SimpleUrlHandlerMapping { - public TestHandlerMapping() { + public TestSimpleUrlHandlerMapping() { Map map = new HashMap<>(); map.put("/foo", new FooHandler()); map.put("/bar", new BarHandler()); @@ -140,7 +140,6 @@ public class WebHandlerIntegrationTests extends AbstractHttpHandlerIntegrationTe } } - private static DataBuffer asDataBuffer(String text) { return new DefaultDataBufferAllocator().allocateBuffer().write(text.getBytes(StandardCharsets.UTF_8)); } diff --git a/spring-web-reactive/src/test/java/org/springframework/web/server/handler/FilteringWebHandlerTests.java b/spring-web-reactive/src/test/java/org/springframework/web/server/handler/FilteringWebHandlerTests.java index 3ba4e6966d..57078bbe02 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/server/handler/FilteringWebHandlerTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/server/handler/FilteringWebHandlerTests.java @@ -23,20 +23,25 @@ import org.apache.commons.logging.LogFactory; import org.junit.Before; import org.junit.Test; import reactor.core.publisher.Mono; +import reactor.core.test.TestSubscriber; import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; import org.springframework.http.server.reactive.HttpHandler; import org.springframework.http.server.reactive.MockServerHttpRequest; import org.springframework.http.server.reactive.MockServerHttpResponse; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.web.server.WebExceptionHandler; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; import org.springframework.web.server.WebHandler; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.adapter.WebHttpHandlerBuilder; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; /** @@ -47,9 +52,9 @@ public class FilteringWebHandlerTests { private static Log logger = LogFactory.getLog(FilteringWebHandlerTests.class); - private ServerHttpRequest request; + private MockServerHttpRequest request; - private ServerHttpResponse response; + private MockServerHttpResponse response; @Before @@ -108,6 +113,20 @@ public class FilteringWebHandlerTests { assertTrue(webHandler.invoked()); } + @Test + public void handleErrorFromFilter() throws Exception { + TestExceptionHandler exceptionHandler = new TestExceptionHandler(); + HttpHandler handler = WebHttpHandlerBuilder.webHandler(new StubWebHandler()) + .filters(new ExceptionFilter()).exceptionHandlers(exceptionHandler).build(); + handler.handle(this.request, this.response).get(); + + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, this.response.getStatus()); + + Throwable savedException = exceptionHandler.ex; + assertNotNull(savedException); + assertEquals("boo", savedException.getMessage()); + } + private HttpHandler createHttpHandler(StubWebHandler webHandler, WebFilter... filters) { return WebHttpHandlerBuilder.webHandler(webHandler).filters(filters).build(); } @@ -117,7 +136,6 @@ public class FilteringWebHandlerTests { private volatile boolean invoked; - public boolean invoked() { return this.invoked; } @@ -156,6 +174,24 @@ public class FilteringWebHandlerTests { } } + private static class ExceptionFilter implements WebFilter { + + @Override + public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { + return Mono.error(new IllegalStateException("boo")); + } + } + + private static class TestExceptionHandler implements WebExceptionHandler { + + private Throwable ex; + + @Override + public Mono handle(ServerWebExchange exchange, Throwable ex) { + this.ex = ex; + return Mono.error(ex); + } + } private static class StubWebHandler implements WebHandler {