From fbe87359accb1319162015f1434b912c03ff67c2 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Fri, 24 Sep 2021 11:58:00 +0100 Subject: [PATCH] Extract InvocableHandlerMethodSupport This prepares the way to invoke handler methods other than those adapted to a DataFetcher with DataFetcherEnvironment as input. See gh-130 --- ...hod.java => DataFetcherHandlerMethod.java} | 50 ++----------- .../graphql/data/method/HandlerMethod.java | 3 + .../method/InvocableHandlerMethodSupport.java | 75 +++++++++++++++++++ 3 files changed, 83 insertions(+), 45 deletions(-) rename spring-graphql/src/main/java/org/springframework/graphql/data/method/{InvocableHandlerMethod.java => DataFetcherHandlerMethod.java} (69%) create mode 100644 spring-graphql/src/main/java/org/springframework/graphql/data/method/InvocableHandlerMethodSupport.java diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/InvocableHandlerMethod.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/DataFetcherHandlerMethod.java similarity index 69% rename from spring-graphql/src/main/java/org/springframework/graphql/data/method/InvocableHandlerMethod.java rename to spring-graphql/src/main/java/org/springframework/graphql/data/method/DataFetcherHandlerMethod.java index a17b08f3..edae42b5 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/InvocableHandlerMethod.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/DataFetcherHandlerMethod.java @@ -15,30 +15,26 @@ */ package org.springframework.graphql.data.method; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.Arrays; import graphql.schema.DataFetchingEnvironment; -import org.springframework.core.CoroutinesUtils; import org.springframework.core.DefaultParameterNameDiscoverer; -import org.springframework.core.KotlinDetector; import org.springframework.core.MethodParameter; import org.springframework.core.ParameterNameDiscoverer; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; -import org.springframework.util.ReflectionUtils; /** - * Extension of {@link HandlerMethod} that can resolve method arguments from a - * {@link DataFetchingEnvironment} and invoke the method. + * An extension of {@link HandlerMethod} for annotated handler methods adapted + * to {@link graphql.schema.DataFetcher} with {@link DataFetchingEnvironment} + * as their input. * * @author Rossen Stoyanchev * @since 1.0.0 */ -public class InvocableHandlerMethod extends HandlerMethod { +public class DataFetcherHandlerMethod extends InvocableHandlerMethodSupport { private static final Object[] EMPTY_ARGS = new Object[0]; @@ -48,7 +44,7 @@ public class InvocableHandlerMethod extends HandlerMethod { private final ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer(); - public InvocableHandlerMethod(HandlerMethod handlerMethod, HandlerMethodArgumentResolverComposite resolvers) { + public DataFetcherHandlerMethod(HandlerMethod handlerMethod, HandlerMethodArgumentResolverComposite resolvers) { super(handlerMethod); Assert.isTrue(!resolvers.getResolvers().isEmpty(), "No argument resolvers"); this.resolvers = resolvers; @@ -127,40 +123,4 @@ public class InvocableHandlerMethod extends HandlerMethod { return args; } - /** - * Invoke the handler method with the given argument values. - */ - @Nullable - protected Object doInvoke(Object... args) throws Exception { - Method method = getBridgedMethod(); - ReflectionUtils.makeAccessible(method); - try { - if (KotlinDetector.isSuspendingFunction(method)) { - return CoroutinesUtils.invokeSuspendingFunction(method, getBean(), args); - } - return method.invoke(getBean(), args); - } - catch (IllegalArgumentException ex) { - assertTargetBean(method, getBean(), args); - String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument"); - throw new IllegalStateException(formatInvokeError(text, args), ex); - } - catch (InvocationTargetException ex) { - // Unwrap for DataFetcherExceptionResolvers ... - Throwable targetException = ex.getTargetException(); - if (targetException instanceof RuntimeException) { - throw (RuntimeException) targetException; - } - else if (targetException instanceof Error) { - throw (Error) targetException; - } - else if (targetException instanceof Exception) { - throw (Exception) targetException; - } - else { - throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException); - } - } - } - } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/HandlerMethod.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/HandlerMethod.java index 9f0f69e9..e56eb4f3 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/HandlerMethod.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/HandlerMethod.java @@ -32,6 +32,7 @@ import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; +import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; /** @@ -78,6 +79,7 @@ public class HandlerMethod { this.beanType = ClassUtils.getUserClass(bean); this.method = method; this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method); + ReflectionUtils.makeAccessible(this.bridgedMethod); this.parameters = initMethodParameters(); } @@ -100,6 +102,7 @@ public class HandlerMethod { this.beanType = ClassUtils.getUserClass(beanType); this.method = method; this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method); + ReflectionUtils.makeAccessible(this.bridgedMethod); this.parameters = initMethodParameters(); } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/InvocableHandlerMethodSupport.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/InvocableHandlerMethodSupport.java new file mode 100644 index 00000000..ec765fe8 --- /dev/null +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/InvocableHandlerMethodSupport.java @@ -0,0 +1,75 @@ +/* + * Copyright 2002-2021 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 + * + * https://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 org.springframework.graphql.data.method; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.springframework.core.CoroutinesUtils; +import org.springframework.core.KotlinDetector; +import org.springframework.lang.Nullable; + +/** + * Extension of {@link HandlerMethod} that adds support for invoking the + * annotated handler methods. + * + * @author Rossen Stoyanchev + * @since 1.0.0 + */ +public abstract class InvocableHandlerMethodSupport extends HandlerMethod { + + + protected InvocableHandlerMethodSupport(HandlerMethod handlerMethod) { + super(handlerMethod.createWithResolvedBean()); + } + + + /** + * Invoke the handler method with the given argument values. + */ + @Nullable + protected Object doInvoke(Object... args) throws Exception { + Method method = getBridgedMethod(); + try { + if (KotlinDetector.isSuspendingFunction(method)) { + return CoroutinesUtils.invokeSuspendingFunction(method, getBean(), args); + } + return method.invoke(getBean(), args); + } + catch (IllegalArgumentException ex) { + assertTargetBean(method, getBean(), args); + String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument"); + throw new IllegalStateException(formatInvokeError(text, args), ex); + } + catch (InvocationTargetException ex) { + // Unwrap for DataFetcherExceptionResolvers ... + Throwable targetException = ex.getTargetException(); + if (targetException instanceof RuntimeException) { + throw (RuntimeException) targetException; + } + else if (targetException instanceof Error) { + throw (Error) targetException; + } + else if (targetException instanceof Exception) { + throw (Exception) targetException; + } + else { + throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException); + } + } + } + +}