• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

FIWARE / contract-management / #104

01 Oct 2026 07:34AM UTC coverage: 4.489% (+0.7%) from 3.796%
#104

Pull #28

vramperez
Remove unused exception constructors, explain the handler defer

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Pull Request #28: Add failure reasons, downstream error descriptions and configurable log output

218 of 379 new or added lines in 33 files covered. (57.52%)

9 existing lines in 6 files now uncovered.

1606 of 35773 relevant lines covered (4.49%)

0.04 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

68.57
/src/main/java/org/fiware/iam/exception/CatchAllExceptionHandler.java
1
package org.fiware.iam.exception;
2

3
import io.micronaut.context.annotation.Requires;
4
import io.micronaut.http.HttpRequest;
5
import io.micronaut.http.HttpResponse;
6
import io.micronaut.http.HttpStatus;
7
import io.micronaut.http.annotation.Produces;
8
import io.micronaut.http.client.exceptions.HttpClientResponseException;
9
import io.micronaut.http.server.exceptions.ExceptionHandler;
10
import jakarta.inject.Singleton;
11
import lombok.extern.slf4j.Slf4j;
12
import org.fiware.iam.logging.DownstreamError;
13
import org.fiware.iam.tmforum.productorder.model.ErrorVO;
14
import reactor.core.Exceptions;
15

16
import java.time.format.DateTimeParseException;
17

18
/**
19
 * Handler to catch and log all exceptions and translate them into a proper error response.
20
 * <p>
21
 * Faulty requests are logged as a single line, failed downstream calls with the downstream answer and their stack
22
 * trace, unexpected exceptions as errors.
23
 */
24
@Produces
25
@Singleton
26
@Requires(classes = {Exception.class, ExceptionHandler.class})
27
@Slf4j
1 ✔
28
public class CatchAllExceptionHandler implements ExceptionHandler<Exception, HttpResponse<ErrorVO>> {
1 ✔
29

30
        @Override
31
        public HttpResponse<ErrorVO> handle(HttpRequest request, Exception exception) {
32
                // several failures collected by a zipDelayError arrive as one composite - it is answered like its first failure,
33
                // while message and log contain all of them
34
                Throwable primary = Exceptions.unwrapMultipleExcludingTracebacks(exception).stream().findFirst().orElse(exception);
1 ✔
35
                if (primary instanceof DateTimeParseException dateTimeParseException) {
1 ✔
NEW
36
                        return respond(request, HttpStatus.BAD_REQUEST,
×
NEW
37
                                        "Request could not be answered due to an invalid date: %s.".formatted(dateTimeParseException.getParsedString()),
×
38
                                        exception);
39
                }
40
                if (primary instanceof TMForumException) {
1 ✔
41
                        return respond(request, HttpStatus.BAD_GATEWAY,
1 ✔
42
                                        "Request could not be answered due to error in downstream tmforum service: %s".formatted(DownstreamError.reason(exception)),
1 ✔
43
                                        exception);
44
                }
45
                if (primary instanceof TrustedIssuersException) {
1 ✔
NEW
46
                        return respond(request, HttpStatus.BAD_GATEWAY,
×
NEW
47
                                        "Request could not be answered due to error in downstream trusted issuers list service: %s".formatted(DownstreamError.reason(exception)),
×
48
                                        exception);
49
                }
50
                if (primary instanceof RainbowException) {
1 ✔
NEW
51
                        return respond(request, HttpStatus.BAD_GATEWAY,
×
NEW
52
                                        "Request could not be answered due to error in downstream rainbow service: %s".formatted(DownstreamError.reason(exception)),
×
53
                                        exception);
54
                }
55
                if (primary instanceof PapException) {
1 ✔
56
                        return respond(request, HttpStatus.BAD_GATEWAY,
1 ✔
57
                                        "Request could not be answered due to error in downstream odrl-pap service: %s".formatted(DownstreamError.reason(exception)),
1 ✔
58
                                        exception);
59
                }
60
                if (primary instanceof HttpClientResponseException) {
1 ✔
61
                        return respond(request, HttpStatus.BAD_GATEWAY,
1 ✔
62
                                        "Request could not be answered due to error in a downstream service: %s".formatted(DownstreamError.reason(exception)),
1 ✔
63
                                        exception);
64
                }
65
                if (primary instanceof IllegalArgumentException) {
1 ✔
66
                        return respond(request, HttpStatus.BAD_REQUEST, DownstreamError.reason(exception), exception);
1 ✔
67
                }
NEW
68
                log.error("Unexpected error while handling {} {}: {}", request.getMethod(), request.getUri(), DownstreamError.reason(exception), exception);
×
69
                return HttpResponse.status(HttpStatus.INTERNAL_SERVER_ERROR)
×
70
                                .body(new ErrorVO().status(HttpStatus.INTERNAL_SERVER_ERROR.toString())
×
71
                                                .reason(HttpStatus.INTERNAL_SERVER_ERROR.getReason())
×
72
                                                .message("Request could not be answered due to an unexpected internal error."));
×
73
        }
74

75
        private HttpResponse<ErrorVO> respond(HttpRequest<?> request, HttpStatus status, String message, Exception exception) {
76
                if (status.getCode() < 500) {
1 ✔
77
                        // a faulty request of the client, the message tells everything
78
                        log.warn("Answered {} {} with {}: {}", request.getMethod(), request.getUri(), status.getCode(), DownstreamError.reason(exception));
1 ✔
79
                } else {
80
                        log.warn("Answered {} {} with {}: {}", request.getMethod(), request.getUri(), status.getCode(), DownstreamError.reason(exception), exception);
1 ✔
81
                }
82
                return HttpResponse.status(status)
1 ✔
83
                                .body(new ErrorVO().status(status.toString())
1 ✔
84
                                                .reason(status.getReason())
1 ✔
85
                                                .message(message));
1 ✔
86
        }
87
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc