Skip to content

Commit

Permalink
Merge pull request #20216 from geoand/#20202
Browse files Browse the repository at this point in the history
Allow injection of Exception type in @ServerExceptionMapper when handling multiple exceptions
  • Loading branch information
geoand authored Sep 16, 2021
2 parents ac59cf9 + 713150a commit 08721da
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import static io.quarkus.gizmo.MethodDescriptor.ofConstructor;
import static io.quarkus.gizmo.MethodDescriptor.ofMethod;
import static io.quarkus.resteasy.reactive.common.deployment.QuarkusResteasyReactiveDotNames.*;
import static io.quarkus.resteasy.reactive.common.deployment.QuarkusResteasyReactiveDotNames.HTTP_SERVER_REQUEST;
import static io.quarkus.resteasy.reactive.server.deployment.GeneratorUtils.paramHandleFromReqContextMethod;
import static io.quarkus.resteasy.reactive.server.deployment.GeneratorUtils.routingContextHandler;
Expand All @@ -18,6 +17,7 @@
import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.URI_INFO;

import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -63,6 +63,7 @@
final class ServerExceptionMapperGenerator {

private static final DotName THROWABLE = DotName.createSimple(Throwable.class.getName());
private static final DotName EXCEPTION = DotName.createSimple(Exception.class.getName());

private ServerExceptionMapperGenerator() {
}
Expand Down Expand Up @@ -117,6 +118,10 @@ public static Map<String, String> generatePerClassMapper(MethodInfo targetMethod
ClassInfo targetClass = targetMethod.declaringClass();
Type[] handledExceptionTypes = getHandledExceptionTypes(targetMethod);
Map<String, String> result = new HashMap<>();

boolean handlesMultipleExceptions = handledExceptionTypes.length > 1;
boolean handledContainsThrowable = Arrays.stream(handledExceptionTypes).anyMatch(t -> t.name().equals(THROWABLE));

for (Type handledExceptionType : handledExceptionTypes) {
String generatedClassName = getGeneratedClassName(targetMethod, handledExceptionType);
try (ClassCreator cc = ClassCreator.builder().className(generatedClassName)
Expand Down Expand Up @@ -145,7 +150,7 @@ public static Map<String, String> generatePerClassMapper(MethodInfo targetMethod

// RESTEasy Reactive toResponse(...) method
generateRRResponse(targetMethod, targetClass, handledExceptionType, cc, rrToResponseDescriptor,
returnType,
returnType, handlesMultipleExceptions, handledContainsThrowable,
(method, contextHandle) -> {
ResultHandle endpointInstanceHandle = method.invokeVirtualMethod(
ofMethod(ResteasyReactiveRequestContext.class, "getEndpointInstance", Object.class),
Expand All @@ -163,7 +168,7 @@ public static Map<String, String> generatePerClassMapper(MethodInfo targetMethod

// RESTEasy Reactive asyncResponse(...) method
generateRRUniResponse(targetMethod, targetClass, handledExceptionType, cc, rrAsyncResponseDescriptor,
returnType,
returnType, handlesMultipleExceptions, handledContainsThrowable,
(method, contextHandle) -> {
ResultHandle endpointInstanceHandle = method.invokeVirtualMethod(
ofMethod(ResteasyReactiveRequestContext.class, "getEndpointInstance", Object.class),
Expand Down Expand Up @@ -238,6 +243,10 @@ public static Map<String, String> generateGlobalMapper(MethodInfo targetMethod,
ClassInfo targetClass = targetMethod.declaringClass();
Type[] handledExceptionTypes = getHandledExceptionTypes(targetMethod);
Map<String, String> result = new HashMap<>();

boolean handlesMultipleExceptions = handledExceptionTypes.length > 1;
boolean handledContainsThrowable = Arrays.stream(handledExceptionTypes).anyMatch(t -> t.name().equals(THROWABLE));

for (Type handledExceptionType : handledExceptionTypes) {
String generatedClassName = getGeneratedClassName(targetMethod, handledExceptionType);
try (ClassCreator cc = ClassCreator.builder().className(generatedClassName)
Expand Down Expand Up @@ -276,7 +285,7 @@ public static Map<String, String> generateGlobalMapper(MethodInfo targetMethod,

// RESTEasy Reactive toResponse(...) method
generateRRResponse(targetMethod, targetClass, handledExceptionType, cc, rrToResponseDescriptor,
returnType,
returnType, handlesMultipleExceptions, handledContainsThrowable,
(method, contextHandle) -> method.readInstanceField(delegateField, method.getThis()));
} else if (returnType == ReturnType.UNI_RESPONSE || returnType == ReturnType.UNI_REST_RESPONSE) {
MethodDescriptor rrAsyncResponseDescriptor = asyncResponseDescriptor(handledExceptionType,
Expand All @@ -289,7 +298,7 @@ public static Map<String, String> generateGlobalMapper(MethodInfo targetMethod,

// RESTEasy Reactive asyncResponse(...) method
generateRRUniResponse(targetMethod, targetClass, handledExceptionType, cc, rrAsyncResponseDescriptor,
returnType,
returnType, handlesMultipleExceptions, handledContainsThrowable,
(method, contextHandle) -> method.readInstanceField(delegateField, method.getThis()));
} else {
throw new IllegalStateException("ReturnType: '" + returnType + "' is not supported");
Expand Down Expand Up @@ -395,7 +404,7 @@ private static void generateRRResponseBridge(Type handledExceptionType, ClassCre

private static void generateRRResponse(MethodInfo targetMethod, ClassInfo targetClass, Type handledExceptionType,
ClassCreator cc, MethodDescriptor rrToResponseDescriptor,
ReturnType returnType,
ReturnType returnType, boolean handlesMultipleExceptions, boolean handledContainsThrowable,
BiFunction<MethodCreator, ResultHandle, ResultHandle> targetInstanceHandleCreator) {
MethodCreator mc = cc.getMethodCreator(rrToResponseDescriptor);
ResultHandle exceptionHandle = mc.getMethodParam(0);
Expand All @@ -414,7 +423,8 @@ private static void generateRRResponse(MethodInfo targetMethod, ClassInfo target
mc.returnValue(resultHandle);
} else {
TargetMethodParamsInfo targetMethodParamsInfo = getTargetMethodParamsInfo(targetMethod, targetClass,
handledExceptionType, mc, exceptionHandle, contextHandle);
handledExceptionType, mc, exceptionHandle, contextHandle, handlesMultipleExceptions,
handledContainsThrowable);
ResultHandle resultHandle = mc.invokeVirtualMethod(
ofMethod(targetClass.name().toString(), targetMethod.name(),
targetMethod.returnType().name().toString(), targetMethodParamsInfo.getTypes()),
Expand All @@ -441,7 +451,7 @@ private static void generateRRUniResponseBridge(Type handledExceptionType, Class

private static void generateRRUniResponse(MethodInfo targetMethod, ClassInfo targetClass, Type handledExceptionType,
ClassCreator cc, MethodDescriptor rrAsyncResponseDescriptor,
ReturnType returnType,
ReturnType returnType, boolean handlesMultipleExceptions, boolean handledContainsThrowable,
BiFunction<MethodCreator, ResultHandle, ResultHandle> targetInstanceHandleCreator) {
MethodCreator mc = cc.getMethodCreator(rrAsyncResponseDescriptor);
ResultHandle exceptionHandle = mc.getMethodParam(0);
Expand All @@ -459,7 +469,8 @@ private static void generateRRUniResponse(MethodInfo targetMethod, ClassInfo tar
targetInstanceHandle);
} else {
TargetMethodParamsInfo targetMethodParamsInfo = getTargetMethodParamsInfo(targetMethod, targetClass,
handledExceptionType, mc, exceptionHandle, contextHandle);
handledExceptionType, mc, exceptionHandle, contextHandle, handlesMultipleExceptions,
handledContainsThrowable);
uniHandle = mc.invokeVirtualMethod(
ofMethod(targetClass.name().toString(), targetMethod.name(),
Uni.class.getName(), targetMethodParamsInfo.getTypes()),
Expand All @@ -472,7 +483,8 @@ private static void generateRRUniResponse(MethodInfo targetMethod, ClassInfo tar
}

private static TargetMethodParamsInfo getTargetMethodParamsInfo(MethodInfo targetMethod, ClassInfo targetClass,
Type handledExceptionType, MethodCreator mc, ResultHandle exceptionHandle, ResultHandle contextHandle) {
Type handledExceptionType, MethodCreator mc, ResultHandle exceptionHandle, ResultHandle contextHandle,
boolean handlesMultipleExceptions, boolean handledContainsThrowable) {
List<Type> parameters = targetMethod.parameters();
ResultHandle[] targetMethodParamHandles = new ResultHandle[parameters.size()];
String[] parameterTypes = new String[parameters.size()];
Expand All @@ -481,7 +493,41 @@ private static TargetMethodParamsInfo getTargetMethodParamsInfo(MethodInfo targe
Type parameter = parameters.get(i);
DotName paramDotName = parameter.name();
parameterTypes[i] = paramDotName.toString();
String parameterName = targetMethod.parameterName(i);
if (paramDotName.equals(handledExceptionType.name())) {
if (handlesMultipleExceptions) {
throw new RuntimeException("Parameter '" + parameterName + "' of method '" + targetMethod.name()
+ " of class '" + targetClass.name() + "' cannot be of type '" + handledExceptionType.name()
+ "' because the method handles multiple exceptions. You can use '"
+ (handledContainsThrowable ? Throwable.class.getName() : Exception.class.getName())
+ "' instead.");
} else {
targetMethodParamHandles[i] = exceptionHandle;
}
} else if (paramDotName.equals(THROWABLE)) {
targetMethodParamHandles[i] = exceptionHandle;
} else if (paramDotName.equals(EXCEPTION)) {
if (handlesMultipleExceptions) {
if (handledContainsThrowable) {
throw new RuntimeException("Parameter '" + parameterName + "' of method '" + targetMethod.name()
+ " of class '" + targetClass.name()
+ "' cannot be of type '" + handledExceptionType.name()
+ "' because the method handles multiple exceptions. You can use '" + Exception.class.getName()
+ "' instead.");
} else {
targetMethodParamHandles[i] = exceptionHandle;
}
} else {
if (handledContainsThrowable) {
throw new RuntimeException("Parameter '" + parameterName + "' of method '" + targetMethod.name()
+ " of class '" + targetClass.name()
+ "' cannot be of type '" + handledExceptionType.name() + "'. You can use '"
+ Throwable.class.getName() + "' instead.");
} else {
targetMethodParamHandles[i] = exceptionHandle;
}
}
} else if (paramDotName.equals(handledExceptionType.name())) {
targetMethodParamHandles[i] = exceptionHandle;
} else if (CONTAINER_REQUEST_CONTEXT.equals(paramDotName)
|| QUARKUS_REST_CONTAINER_REQUEST_CONTEXT.equals(paramDotName)) {
Expand Down Expand Up @@ -528,7 +574,6 @@ private static TargetMethodParamsInfo getTargetMethodParamsInfo(MethodInfo targe
} else if (ROUTING_CONTEXT.equals(paramDotName)) {
targetMethodParamHandles[i] = routingContextHandler(mc, contextHandle);
} else {
String parameterName = targetMethod.parameterName(i);
throw new RuntimeException("Parameter '" + parameterName + "' of method '" + targetMethod.name()
+ " of class '" + targetClass.name()
+ "' is not allowed");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ public class CustomExceptionMappersTest {
public JavaArchive get() {
return ShrinkWrap.create(JavaArchive.class)
.addClasses(FirstResource.class, SecondResource.class,
MyException.class, MyOtherException.class, UniException.class, ExtendsUniException.class,
MyException.class, MyOtherException.class, UniException.class,
OtherUniException.class, ExtendsUniException.class,
MyOtherExceptionMapper.class, UniExceptionMapper.class,
SomeBean.class, ExceptionUtil.class);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ public Uni<String> uni(@RestQuery String name) {
}

@ServerExceptionMapper({ IllegalStateException.class, IllegalArgumentException.class })
public Response handleIllegal() {
return Response.status(409).build();
public Response handleIllegal(Exception e) {
return Response.status(409).entity(e.getMessage()).build();
}

@ServerExceptionMapper
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package io.quarkus.resteasy.reactive.server.test.customexceptions;

public class OtherUniException extends RuntimeException {
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@

public class UniExceptionMapper {

@ServerExceptionMapper(UniException.class)
Uni<Response> handleUni() {
@ServerExceptionMapper({ UniException.class, OtherUniException.class })
Uni<Response> handleUni(Throwable t) {
return Uni.createFrom().deferred(() -> Uni.createFrom().item(Response.status(413).build()));
}

Expand Down

0 comments on commit 08721da

Please sign in to comment.