Skip to content
Łukasz Witkowski edited this page Jan 22, 2023 · 18 revisions

Built in Exception Mappers

Here's a list of Exceptions for which this extension provides mappers, along with comparison between quarkus-resteasy-problem and raw quarkus-resteasy-jackson.

javax.validation.ConstraintViolationException

Thrown by Hibernate Validator (@Valid)

Given:

@GET
@Path("/hello/{which_continent}")
@Produces(MediaType.APPLICATION_JSON)
public String hello(
        @PathParam("which_continent") @Valid @Length(min = 5) @NotNull String whichContinent,
        @QueryParam("message") @Valid @Length(min = 15) @NotNull String messageParameter
) {
    return "Hello RESTEasy from " + whichContinent + " with message: " + messageParameter;
}

When

curl `http://localhost:8080/hello/asia?message=konnichiwa`

Then:

quarkus-resteasy-problem (all resteasy versions) quarkus-resteasy-jackson/jsonb quarkus-resteasy-reactive-jackson/jsonb
HTTP/1.1 400 Bad Request
Content-Type: application/problem+json

{
"status": 400,
"title": "Bad Request",
"instance": "/hello/asia",
"violations" : [
{
"field": "which_continent",
"in": "path",
"message": "length must be between 5 and 2147483647"
},
{
"field": "message",
"in": "query",
"message": "length must be between 15 and 2147483647"
}
]
}
HTTP/1.1 400 Bad Request
validation-exception: true
Content-Type: application/json

{
"exception": null,
"propertyViolations": [],
"classViolations": [],
"parameterViolations": [
{
"constraintType": "PARAMETER",
"path": "hello.whichContinent",
"message": "length must be between 5 and 2147483647",
"value": "asia"
},
{
"constraintType": "PARAMETER",
"path": "hello.messageParameter",
"message": "length must be between 15 and 2147483647",
"value": "konnichiwa"
}
],
"returnValueViolations": []
}
HTTP/1.1 400 Bad Request
Content-Type: application/json

{
"title": "Constraint Violation",
"status": 400,
"violations": [
{
"field": "hello.messageParameter",
"message": "length must be between 15 and 2147483647"
},
{
"field": "hello.whichContinent",
"message": "length must be between 5 and 2147483647"
}
]
}

javax.ws.rs.NotFoundException

Thrown by RESTeasy.

quarkus-resteasy-problem quarkus-resteasy-jackson
HTTP/1.1 404 Not Found
Content-Type: application/problem+json

{
"status": 404,
"title": "Not Found",
"detail": "RESTEASY003210: Could not find resource (...)",
"instance": "/resource"
}
HTTP/1.1 404 Not Found
Content-Length: 0

javax.ws.rs.RedirectionException

Thrown by Quarkus.

quarkus-resteasy-problem quarkus-resteasy-jackson
HTTP/1.1 301 Moved Permanently
Location: https://somewhere-else.com/
Pragma: no-cache
Cache-Control: no-store
Content-Type: application/problem+json

{
"status": 301,
"title": "Moved Permanently",
"instance": "/resource"
}
HTTP/1.1 301 Moved Permanently
Content-Length: 0
Location: http://localhost:8081/new-location

javax.ws.rs.WebApplicationException

Thrown by Quarkus/JaxRS.

quarkus-resteasy-problem quarkus-resteasy-jackson
HTTP/1.1 409 Conflict
Content-Type: application/problem+json

{
"status": 409,
"title": "Conflict",
"detail": "This is custom message",
"instance": "/resource"
}
HTTP/1.1 409 Conflict
Content-Length: 0

io.quarkus.security.AuthenticationFailedException / io.quarkus.security.AuthenticationCompletionExceptionMapper / io.quarkus.security.UnauthorizedException

Thrown by Quarkus if JWT token is missing or invalid.

quarkus-resteasy-problem quarkus-resteasy-jackson
HTTP/1.1 401 Unauthorized
www-authenticate: Bearer
Content-Type: application/problem+json

{
"status": 401,
"title": "Unauthorized",
"instance": "/resource"
}
HTTP/1.1 401 Unauthorized
www-authenticate: Bearer {token}
Content-Length: 0

io.quarkus.security.ForbiddenException

Thrown by Quarkus when @RolesAllowed not satisfied.

quarkus-resteasy-problem quarkus-resteasy-jackson
HTTP/1.1 403 Forbidden
Content-Type: application/problem+json

{
"status": 403,
"title": "Forbidden",
"instance": "/resource"
}
HTTP/1.1 403 Forbidden
Content-Length: 0

com.tietoevry.quarkus.resteasy.problem.HttpProblem

Example:

throw HttpProblem.builder()
    .withType(URI.create("/business-problem"))
    .withStatus(Status.CONFLICT)
    .withTitle("Business Conflict")
    .withDetail("Some business conflict has happened")
    .withInstance(URI.create("/problem/special-case"))
    .withHeader("X-Custom-Header", "rfc7807-by-example")    
    .with("custom_property", 123)    
    .build();                    
quarkus-resteasy-problem quarkus-resteasy-jackson
HTTP/1.1 409 Conflict
X-Custom-Header: rfc7807-by-example
Content-Type: application/problem+json

{
"type": "/business-problem",
"status": 409,
"title": "Business Problem",
"detail": "Some business conflict has happened",
"instance": "/problem/special-case",
"custom_property": 123
}
not supported, http 500

org.zalando.problem.Problem

Example:

throw Problem.builder()
    .withType(URI.create("/business-problem"))
    .withStatus(Status.CONFLICT)
    .withTitle("Business Conflict")
    .withDetail("Some business conflict has happened")
    .withInstance(URI.create("/problem/special-case"))
    .with("custom_property", 123)    
    .build();
quarkus-resteasy-problem quarkus-resteasy-jackson
HTTP/1.1 409 Conflict
Content-Type: application/problem+json

{
"type": "/business-problem",
"status": 409,
"title": "Business Problem",
"detail": "Some business conflict has happened",
"instance": "/problem/special-case",
"custom_property": 123
}
not supported, http 500

java.lang.Throwable

Finally top-level exception mapper for all other exceptions throw by user or Quarkus.

quarkus-resteasy-problem quarkus-resteasy-jackson
HTTP/1.1 500 Internal Server Error
Content-Type: application/problem+json

{
"status": 500,
"title": "Internal Server Error",
"instance": "/resource"
}
HTTP/1.1 500 Internal Server Error
content-type: text/html; charset=utf-8

<html lang="en">
<head>
<title>Internal Server Error - Error handling ebcf54c0-1c84-4eb6-aa28-d62809a0577c-3, org.jboss.resteasy.spi.UnhandledException: (...)</title>
</head>
<body>
(...) whole stack trace (...)
<body>