class RootRouteExceptionHandler {

    public static ExceptionHandler getInstance(
            final Function<DittoRuntimeException, HttpResponse> dittoRuntimeExceptionToHttpResponse) {

        final RootRouteExceptionHandler rootRouteExceptionHandler =
                new RootRouteExceptionHandler(dittoRuntimeExceptionToHttpResponse);

        final FI.TypedPredicate<CompletionException> isCausedByDittoRuntimeException = exception -> {
            @Nullable final Throwable cause = exception.getCause();
            return cause instanceof DittoRuntimeException;
        };

        final FI.TypedPredicate<CompletionException> isCausedByJsonRuntimeException = exception -> {
            @Nullable final Throwable cause = exception.getCause();
            return cause instanceof JsonRuntimeException;
        };

        return ExceptionHandler.newBuilder()
                .match(DittoRuntimeException.class, rootRouteExceptionHandler::handleDittoRuntimeException)
                .match(JsonRuntimeException.class, jsonRuntimeException -> {
                    final DittoRuntimeException dittoJsonException = new DittoJsonException(jsonRuntimeException);
                    return rootRouteExceptionHandler.handleDittoRuntimeException(dittoJsonException);
                })
                .match(CompletionException.class, isCausedByDittoRuntimeException, ce -> {
                    final DittoRuntimeException dittoRuntimeException = (DittoRuntimeException) ce.getCause();
                    return rootRouteExceptionHandler.handleDittoRuntimeException(dittoRuntimeException);
                })
                .match(CompletionException.class, isCausedByJsonRuntimeException, ce -> {
                    final JsonRuntimeException jsonRuntimeException = (JsonRuntimeException) ce.getCause();
                    final DittoRuntimeException dittoRuntimeException = new DittoJsonException(jsonRuntimeException);
                    return rootRouteExceptionHandler.handleDittoRuntimeException(dittoRuntimeException);
                })
                .matchAny(RootRouteExceptionHandler::handleInternalServerError)
                .build();
    }

    private  RootRouteExceptionHandler(final Function<DittoRuntimeException, HttpResponse> dreToHttpResponse);

}