
com.visionarts.powerjambda.exceptions.DefaultActionExceptionResolver Maven / Gradle / Ivy
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.visionarts.powerjambda.exceptions;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Optional;
import com.amazonaws.services.lambda.runtime.Context;
import com.visionarts.powerjambda.ResponseWriter;
import com.visionarts.powerjambda.annotations.ExceptionHandler;
import com.visionarts.powerjambda.models.ResponseEntity;
import com.visionarts.powerjambda.utils.OptionalUtils;
import com.visionarts.powerjambda.utils.ReflectionUtils;
import com.visionarts.powerjambda.utils.Utils;
/**
* A ExceptionResolver that resolves the exception
* through {@code @ExceptionHandler} methods in the action.
*
*/
public class DefaultActionExceptionResolver implements ExceptionResolver {
private ResponseWriter, ResponseT> responseWriter;
private Class extends Throwable> exceptionClazz;
private Class> actionClazz;
/**
* Create new instance that resolves an exception.
*
*
*/
public DefaultActionExceptionResolver(ResponseWriter, ResponseT> responseWriter) {
this.responseWriter = responseWriter;
}
/**
* Handles an exception and returns the response using the ExceptionHandler method in the action.
*
*
* @param action The action with exception handler
* @param exception The raised exception
* @return The exception as error response to API Gateway
* @throws InternalErrorException The exception that occurred
*/
@Override
public ResponseT handleException(Throwable exception, T action, Context context) throws InternalErrorException {
this.exceptionClazz = exception.getClass();
this.actionClazz = action.getClass();
try {
return responseWriter.writeResponse(handle(exception, action, context));
} catch (IOException e) {
throw new InternalErrorException("Failed to write the error response", e);
}
}
/**
* Find an {@code @ExceptionHandler} method and invoke it to handle the raised exception.
*
*/
private ResponseEntity> handle(Throwable targetException, T action, Context context)
throws InternalErrorException {
Method method = findExceptionHandler(targetException);
Object retVal = invokeMethod(method, action, targetException, context);
Utils.requireNonNull(retVal,
() -> new InternalErrorException("Exception handler returns null"));
return (ResponseEntity>) retVal;
}
private Method findExceptionHandler(Throwable exception) throws InternalErrorException {
Optional handler = findExceptionHandler(actionClazz, exceptionClazz);
// fallback exception handlers if exists
handler = OptionalUtils.or(handler, () -> findExceptionHandler(actionClazz, Exception.class));
handler = OptionalUtils.or(handler, () -> findExceptionHandler(actionClazz, Throwable.class));
return handler.orElseThrow(
() -> new InternalErrorException(
"Not found any ExceptionHandler for " + exceptionClazz.getName(), exception));
}
private Optional findExceptionHandler(Class> actionClazz,
Class extends Throwable> exceptionClazz) {
return ReflectionUtils.findAllMethodsWithAnnotation(actionClazz, ExceptionHandler.class)
.stream()
.filter(m -> Arrays.asList(m.getAnnotation(ExceptionHandler.class).value()).contains(exceptionClazz))
.filter(m -> m.getReturnType().equals(ResponseEntity.class))
.findFirst();
}
private Object invokeMethod(Method handler, T action, Throwable targetException, Context context)
throws InternalErrorException {
Object[] args = new Object[] { targetException, context };
try {
return handler.invoke(action, args);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new InternalErrorException("Method invocation error : " + handler.getName(), e);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy