diff --git a/http-server-netty/src/main/java/io/micronaut/http/server/netty/jackson/JsonViewServerFilter.java b/http-server-netty/src/main/java/io/micronaut/http/server/netty/jackson/JsonViewServerFilter.java index 4c5894375f6..cce2e65b6d8 100644 --- a/http-server-netty/src/main/java/io/micronaut/http/server/netty/jackson/JsonViewServerFilter.java +++ b/http-server-netty/src/main/java/io/micronaut/http/server/netty/jackson/JsonViewServerFilter.java @@ -84,7 +84,10 @@ public final Publisher> doFilter(HttpRequest if (routeInfo != null) { final Optional> viewClass = routeInfo.findAnnotation(JsonView.class) .flatMap(AnnotationValue::classValue); - if (viewClass.isPresent()) { + if (viewClass.isPresent() && + // if this is an error response, the response body does not come from the controller + !response.getAttributes().contains(HttpAttributes.EXCEPTION.toString())) { + final Optional optionalBody = response.getBody(); if (optionalBody.isPresent()) { Object body = optionalBody.get(); diff --git a/http-server-netty/src/test/groovy/io/micronaut/http/server/netty/jackson/JsonViewController.groovy b/http-server-netty/src/test/groovy/io/micronaut/http/server/netty/jackson/JsonViewController.groovy index b296c50c4b0..8c7b13ef91b 100644 --- a/http-server-netty/src/test/groovy/io/micronaut/http/server/netty/jackson/JsonViewController.groovy +++ b/http-server-netty/src/test/groovy/io/micronaut/http/server/netty/jackson/JsonViewController.groovy @@ -17,10 +17,13 @@ package io.micronaut.http.server.netty.jackson import com.fasterxml.jackson.annotation.JsonView import io.micronaut.http.HttpResponse +import io.micronaut.http.HttpStatus import io.micronaut.http.annotation.Body import io.micronaut.http.annotation.Controller +import io.micronaut.http.annotation.Error import io.micronaut.http.annotation.Get import io.micronaut.http.annotation.Post +import io.micronaut.http.hateoas.JsonError import reactor.core.publisher.Flux import reactor.core.publisher.Mono @@ -77,4 +80,24 @@ class JsonViewController { assert model.password == null return HttpResponse.ok(model) } + + @JsonView(Views.Public) + @Get("/failing") + TestModel failing() { + throw new Failure1() + } + + @JsonView(Views.Public) + @Get("/failing-with-route") + TestModel failingWithRoute() { + throw new Failure2() + } + + @Error + HttpResponse errorRoute(Failure2 f) { + return HttpResponse.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new JsonError("failure2")); + } + + static class Failure1 extends Exception {} + static class Failure2 extends Exception {} } diff --git a/http-server-netty/src/test/groovy/io/micronaut/http/server/netty/jackson/JsonViewServerFilterSpec.groovy b/http-server-netty/src/test/groovy/io/micronaut/http/server/netty/jackson/JsonViewServerFilterSpec.groovy index 24cb442ec82..8cb1a8bb1e0 100644 --- a/http-server-netty/src/test/groovy/io/micronaut/http/server/netty/jackson/JsonViewServerFilterSpec.groovy +++ b/http-server-netty/src/test/groovy/io/micronaut/http/server/netty/jackson/JsonViewServerFilterSpec.groovy @@ -20,6 +20,8 @@ import io.micronaut.core.type.Argument import io.micronaut.http.HttpRequest import io.micronaut.http.HttpResponse import io.micronaut.http.client.HttpClient +import io.micronaut.http.client.exceptions.HttpClientResponseException +import io.micronaut.http.hateoas.JsonError import io.micronaut.runtime.server.EmbeddedServer import spock.lang.AutoCleanup import spock.lang.Shared @@ -126,4 +128,20 @@ class JsonViewServerFilterSpec extends Specification { rsp.body().birthdate == null rsp.body().password == null } + + def "errors are written properly"() { + when: + client.toBlocking().exchange(HttpRequest.GET('/jsonview/failing'), TestModel) + + then: + def f = thrown HttpClientResponseException + f.response.getBody(JsonError).get().message == "Internal Server Error" + + when: + client.toBlocking().exchange(HttpRequest.GET('/jsonview/failing-with-route')) + + then: + HttpClientResponseException e = thrown() + e.response.getBody(JsonError).get().message == "failure2" + } }