@Test public void handleReturnValueLastModified() throws Exception { Instant currentTime = Instant.now().truncatedTo(ChronoUnit.SECONDS); Instant oneMinAgo = currentTime.minusSeconds(60); long timestamp = currentTime.toEpochMilli(); MockServerWebExchange exchange = MockServerWebExchange.from(get("/path").ifModifiedSince(timestamp)); ResponseEntity<String> entity = ok().lastModified(oneMinAgo.toEpochMilli()).body("body"); MethodParameter returnType = on(TestController.class).resolveReturnType(entity(String.class)); HandlerResult result = handlerResult(entity, returnType); this.resultHandler.handleResult(exchange, result).block(Duration.ofSeconds(5)); assertConditionalResponse(exchange, HttpStatus.NOT_MODIFIED, null, null, oneMinAgo); }
@Test // SPR-12894 public void useDefaultContentType() throws Exception { Resource body = new ClassPathResource("logo.png", getClass()); MethodParameter type = on(TestController.class).resolveReturnType(Resource.class); this.resultHandler.writeBody(body, type, this.exchange).block(Duration.ofSeconds(5)); assertEquals("image/png", this.exchange.getResponse().getHeaders().getFirst("Content-Type")); }
@Test // SPR-14877 public void handleMonoWithWildcardBodyType() throws Exception { MockServerWebExchange exchange = MockServerWebExchange.from(get("/path")); exchange.getAttributes().put(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, Collections.singleton(APPLICATION_JSON)); MethodParameter type = on(TestController.class).resolveReturnType(Mono.class, ResponseEntity.class); HandlerResult result = new HandlerResult(new TestController(), Mono.just(ok().body("body")), type); this.resultHandler.handleResult(exchange, result).block(Duration.ofSeconds(5)); assertEquals(HttpStatus.OK, exchange.getResponse().getStatusCode()); assertResponseBody(exchange, "body"); }
@Test // SPR-14559 public void handleReturnValueEtagInvalidIfNoneMatch() throws Exception { MockServerWebExchange exchange = MockServerWebExchange.from(get("/path").ifNoneMatch("unquoted")); ResponseEntity<String> entity = ok().eTag("\"deadb33f8badf00d\"").body("body"); MethodParameter returnType = on(TestController.class).resolveReturnType(entity(String.class)); HandlerResult result = handlerResult(entity, returnType); this.resultHandler.handleResult(exchange, result).block(Duration.ofSeconds(5)); assertEquals(HttpStatus.OK, exchange.getResponse().getStatusCode()); assertResponseBody(exchange, "body"); }
@Test public void responseEntityStatusCode() throws Exception { ResponseEntity<Void> value = ResponseEntity.noContent().build(); MethodParameter returnType = on(TestController.class).resolveReturnType(entity(Void.class)); HandlerResult result = handlerResult(value, returnType); MockServerWebExchange exchange = MockServerWebExchange.from(get("/path")); this.resultHandler.handleResult(exchange, result).block(Duration.ofSeconds(5)); assertEquals(HttpStatus.NO_CONTENT, exchange.getResponse().getStatusCode()); assertEquals(0, exchange.getResponse().getHeaders().size()); assertResponseBodyIsEmpty(exchange); }
@Test public void unresolvedViewName() { String returnValue = "account"; MethodParameter returnType = on(Handler.class).annotPresent(ModelAttribute.class).resolveReturnType(String.class); HandlerResult result = new HandlerResult(new Object(), returnValue, returnType, this.bindingContext); MockServerWebExchange exchange = MockServerWebExchange.from(get("/path")); Mono<Void> mono = resultHandler().handleResult(exchange, result); StepVerifier.create(mono) .expectNextCount(0) .expectErrorMessage("Could not resolve view with name 'path'.") .verify(); }
@Test public void handleWithMultipleResolvers() { testHandle("/account", on(Handler.class).annotNotPresent(ModelAttribute.class).resolveReturnType(String.class), "profile", "profile: {id=123}", new TestViewResolver("account"), new TestViewResolver("profile")); }
@Test // SPR-13318 public void jacksonTypeWithSubTypeOfListElement() throws Exception { MethodParameter returnType = on(TestController.class).resolveReturnType(List.class, Identifiable.class); List<SimpleBean> body = Arrays.asList(new SimpleBean(123L, "foo"), new SimpleBean(456L, "bar")); this.resultHandler.writeBody(body, returnType, this.exchange).block(Duration.ofSeconds(5)); assertEquals(APPLICATION_JSON_UTF8, this.exchange.getResponse().getHeaders().getContentType()); assertResponseBody("[{\"id\":123,\"name\":\"foo\"},{\"id\":456,\"name\":\"bar\"}]"); }
@Test // SPR-13318 public void jacksonTypeWithSubType() throws Exception { SimpleBean body = new SimpleBean(123L, "foo"); MethodParameter type = on(TestController.class).resolveReturnType(Identifiable.class); this.resultHandler.writeBody(body, type, this.exchange).block(Duration.ofSeconds(5)); assertEquals(APPLICATION_JSON_UTF8, this.exchange.getResponse().getHeaders().getContentType()); assertResponseBody("{\"id\":123,\"name\":\"foo\"}"); }
@Test // SPR-12811 public void jacksonTypeOfListElement() throws Exception { MethodParameter returnType = on(TestController.class).resolveReturnType(List.class, ParentClass.class); List<ParentClass> body = Arrays.asList(new Foo("foo"), new Bar("bar")); this.resultHandler.writeBody(body, returnType, this.exchange).block(Duration.ofSeconds(5)); assertEquals(APPLICATION_JSON_UTF8, this.exchange.getResponse().getHeaders().getContentType()); assertResponseBody("[{\"type\":\"foo\",\"parentProperty\":\"foo\"}," + "{\"type\":\"bar\",\"parentProperty\":\"bar\"}]"); }
@Test public void supportsReturnType() throws Exception { assertTrue(this.handler.supportsReturnType( on(TestController.class).resolveReturnType(DeferredResult.class, String.class))); assertTrue(this.handler.supportsReturnType( on(TestController.class).resolveReturnType(ListenableFuture.class, String.class))); assertTrue(this.handler.supportsReturnType( on(TestController.class).resolveReturnType(CompletableFuture.class, String.class))); }
@Test // SPR-17076 public void responseEntityFluxWithCustomHeader() throws Exception { EmitterProcessor<SimpleBean> processor = EmitterProcessor.create(); ResponseEntity<Flux<SimpleBean>> entity = ResponseEntity.ok().header("x-foo", "bar").body(processor); ResolvableType bodyType = forClassWithGenerics(Flux.class, SimpleBean.class); MethodParameter type = on(TestController.class).resolveReturnType(ResponseEntity.class, bodyType); this.handler.handleReturnValue(entity, type, this.mavContainer, this.webRequest); assertTrue(this.request.isAsyncStarted()); assertEquals(200, this.response.getStatus()); assertEquals("bar", this.response.getHeader("x-foo")); assertFalse(this.response.isCommitted()); }
private ResponseBodyEmitter handleValue(Object returnValue, Class<?> asyncType, ResolvableType genericType) throws Exception { ModelAndViewContainer mavContainer = new ModelAndViewContainer(); MethodParameter returnType = on(TestController.class).resolveReturnType(asyncType, genericType); return this.handler.handleValue(returnValue, returnType, mavContainer, this.webRequest); }
@Test public void defaultViewName() { testDefaultViewName(null, on(Handler.class).annotPresent(ModelAttribute.class).resolveReturnType(String.class)); testDefaultViewName(Mono.empty(), on(Handler.class).resolveReturnType(Mono.class, String.class)); testDefaultViewName(Mono.empty(), on(Handler.class).resolveReturnType(Mono.class, Void.class)); testDefaultViewName(Completable.complete(), on(Handler.class).resolveReturnType(Completable.class)); }
@Test // SPR-13631 public void useDefaultCharset() throws Exception { this.exchange.getAttributes().put(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, Collections.singleton(APPLICATION_JSON)); String body = "foo"; MethodParameter type = on(TestController.class).resolveReturnType(String.class); this.resultHandler.writeBody(body, type, this.exchange).block(Duration.ofSeconds(5)); assertEquals(APPLICATION_JSON_UTF8, this.exchange.getResponse().getHeaders().getContentType()); }
@Test public void doesNotSupport() throws Exception { Object value = null; MethodParameter returnType = on(TestController.class).resolveReturnType(String.class); assertFalse(this.resultHandler.supports(handlerResult(value, returnType))); returnType = on(TestController.class).resolveReturnType(Completable.class); assertFalse(this.resultHandler.supports(handlerResult(value, returnType))); // SPR-15464 returnType = on(TestController.class).resolveReturnType(Flux.class); assertFalse(this.resultHandler.supports(handlerResult(value, returnType))); }
@Test // SPR-13135 public void unsupportedReturnType() throws Exception { ByteArrayOutputStream body = new ByteArrayOutputStream(); MethodParameter type = on(TestController.class).resolveReturnType(OutputStream.class); HttpMessageWriter<?> writer = new EncoderHttpMessageWriter<>(new ByteBufferEncoder()); Mono<Void> mono = initResultHandler(writer).writeBody(body, type, this.exchange); StepVerifier.create(mono).expectError(IllegalStateException.class).verify(); }
@Test public void handleReturnValueEtag() throws Exception { String etagValue = "\"deadb33f8badf00d\""; MockServerWebExchange exchange = MockServerWebExchange.from(get("/path").ifNoneMatch(etagValue)); ResponseEntity<String> entity = ok().eTag(etagValue).body("body"); MethodParameter returnType = on(TestController.class).resolveReturnType(entity(String.class)); HandlerResult result = handlerResult(entity, returnType); this.resultHandler.handleResult(exchange, result).block(Duration.ofSeconds(5)); assertConditionalResponse(exchange, HttpStatus.NOT_MODIFIED, null, etagValue, Instant.MIN); }
@Test public void handleResponseEntityWithNullBody() throws Exception { Object returnValue = Mono.just(notFound().build()); MethodParameter type = on(TestController.class).resolveReturnType(Mono.class, entity(String.class)); HandlerResult result = handlerResult(returnValue, type); MockServerWebExchange exchange = MockServerWebExchange.from(get("/path")); this.resultHandler.handleResult(exchange, result).block(Duration.ofSeconds(5)); assertEquals(HttpStatus.NOT_FOUND, exchange.getResponse().getStatusCode()); assertResponseBodyIsEmpty(exchange); }
@Test // SPR-14877 public void handleMonoWithWildcardBodyTypeAndNullBody() throws Exception { MockServerWebExchange exchange = MockServerWebExchange.from(get("/path")); exchange.getAttributes().put(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, Collections.singleton(APPLICATION_JSON)); MethodParameter returnType = on(TestController.class).resolveReturnType(Mono.class, ResponseEntity.class); HandlerResult result = new HandlerResult(new TestController(), Mono.just(notFound().build()), returnType); this.resultHandler.handleResult(exchange, result).block(Duration.ofSeconds(5)); assertEquals(HttpStatus.NOT_FOUND, exchange.getResponse().getStatusCode()); assertResponseBodyIsEmpty(exchange); }