Skip to content
This repository was archived by the owner on Dec 19, 2023. It is now read-only.

Commit 3737451

Browse files
committed
Scan for exception handlers using beans instead of classloader; fix #171
1 parent 9ed3b5b commit 3737451

File tree

6 files changed

+59
-16
lines changed

6 files changed

+59
-16
lines changed

example-graphql-tools/src/main/resources/application.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,17 @@ spring:
33
name: graphql-java-tools-app
44
server:
55
port: 9001
6+
graphql:
7+
servlet:
8+
exception-handlers-enabled: true
69
graphiql:
710
headers:
811
Authorization: "Bearer 05bd9a5f3fe0408f89520946b0fe1b06"
12+
logging:
13+
level:
14+
com:
15+
oembedler:
16+
moon:
17+
graphql:
18+
boot:
19+
error: debug

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1818
#
1919

20-
version = 5.4
20+
version = 5.4.1-SNAPSHOT
2121
PROJECT_GROUP = com.graphql-java-kickstart
2222
PROJECT_NAME = graphql-spring-boot
2323
PROJECT_DESC = GraphQL Spring Framework Boot

graphql-spring-boot-autoconfigure/src/main/java/com/oembedler/moon/graphql/boot/GraphQLWebAutoConfiguration.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import com.fasterxml.jackson.databind.InjectableValues;
2323
import com.fasterxml.jackson.databind.ObjectMapper;
24+
import com.oembedler.moon.graphql.boot.error.ErrorHandlerSupplier;
2425
import com.oembedler.moon.graphql.boot.error.GraphQLErrorHandlerFactory;
2526
import com.oembedler.moon.graphql.boot.metrics.MetricsInstrumentation;
2627
import graphql.execution.AsyncExecutionStrategy;
@@ -30,9 +31,12 @@
3031
import graphql.execution.preparsed.PreparsedDocumentProvider;
3132
import graphql.schema.GraphQLSchema;
3233
import graphql.servlet.*;
34+
import lombok.extern.slf4j.Slf4j;
3335
import org.springframework.beans.BeansException;
36+
import org.springframework.beans.factory.InitializingBean;
3437
import org.springframework.beans.factory.ObjectProvider;
3538
import org.springframework.beans.factory.annotation.Autowired;
39+
import org.springframework.beans.factory.annotation.Value;
3640
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
3741
import org.springframework.boot.autoconfigure.condition.*;
3842
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
@@ -48,6 +52,7 @@
4852
import org.springframework.web.servlet.DispatcherServlet;
4953
import org.springframework.web.servlet.config.annotation.CorsRegistryWorkaround;
5054

55+
import javax.annotation.PostConstruct;
5156
import javax.servlet.MultipartConfigElement;
5257
import java.util.Collections;
5358
import java.util.List;
@@ -60,6 +65,7 @@
6065
/**
6166
* @author <a href="mailto:java.lang.RuntimeException@gmail.com">oEmbedler Inc.</a>
6267
*/
68+
@Slf4j
6369
@Configuration
6470
@ConditionalOnWebApplication
6571
@ConditionalOnClass(DispatcherServlet.class)
@@ -85,6 +91,8 @@ public class GraphQLWebAutoConfiguration implements ApplicationContextAware {
8591
@Autowired(required = false)
8692
private GraphQLErrorHandler errorHandler;
8793

94+
private ErrorHandlerSupplier errorHandlerSupplier = new ErrorHandlerSupplier(null);
95+
8896
@Autowired(required = false)
8997
private Map<String, ExecutionStrategy> executionStrategies;
9098

@@ -110,6 +118,7 @@ public void setApplicationContext(ApplicationContext applicationContext) throws
110118
errorHandler = new GraphQLErrorHandlerFactory().create(context, graphQLServletProperties.isExceptionHandlersEnabled());
111119
context.getBeanFactory().registerSingleton(errorHandler.getClass().getCanonicalName(), errorHandler);
112120
}
121+
errorHandlerSupplier.setErrorHandler(errorHandler);
113122
}
114123

115124
@Bean
@@ -203,9 +212,7 @@ public GraphQLQueryInvoker queryInvoker(ExecutionStrategyProvider executionStrat
203212
public GraphQLObjectMapper graphQLObjectMapper(ObjectProvider<ObjectMapperProvider> objectMapperProviderObjectProvider) {
204213
GraphQLObjectMapper.Builder builder = newBuilder();
205214

206-
if (errorHandler != null) {
207-
builder.withGraphQLErrorHandler(errorHandler);
208-
}
215+
builder.withGraphQLErrorHandler(errorHandlerSupplier);
209216

210217
ObjectMapperProvider objectMapperProvider = objectMapperProviderObjectProvider.getIfAvailable();
211218

@@ -214,7 +221,7 @@ public GraphQLObjectMapper graphQLObjectMapper(ObjectProvider<ObjectMapperProvid
214221
} else if (objectMapperConfigurer != null) {
215222
builder.withObjectMapperConfigurer(objectMapperConfigurer);
216223
}
217-
224+
log.info("Building GraphQLObjectMapper including errorHandler: {}", errorHandler);
218225
return builder.build();
219226
}
220227

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.oembedler.moon.graphql.boot.error;
2+
3+
import graphql.servlet.GraphQLErrorHandler;
4+
5+
import java.util.Objects;
6+
import java.util.function.Supplier;
7+
8+
public class ErrorHandlerSupplier implements Supplier<GraphQLErrorHandler> {
9+
10+
private GraphQLErrorHandler errorHandler;
11+
12+
public ErrorHandlerSupplier(GraphQLErrorHandler errorHandler) {
13+
this.errorHandler = errorHandler;
14+
}
15+
16+
@Override
17+
public GraphQLErrorHandler get() {
18+
return errorHandler;
19+
}
20+
21+
public void setErrorHandler(GraphQLErrorHandler errorHandler) {
22+
this.errorHandler = Objects.requireNonNull(errorHandler);
23+
}
24+
25+
}

graphql-spring-boot-autoconfigure/src/main/java/com/oembedler/moon/graphql/boot/error/GraphQLErrorFromExceptionHandler.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
66
import graphql.SerializationError;
77
import graphql.servlet.DefaultGraphQLErrorHandler;
88
import graphql.servlet.GenericGraphQLError;
9+
import lombok.extern.slf4j.Slf4j;
910

1011
import java.util.HashMap;
1112
import java.util.List;
1213
import java.util.Map;
1314
import java.util.Optional;
1415
import java.util.stream.Collectors;
1516

17+
@Slf4j
1618
class GraphQLErrorFromExceptionHandler extends DefaultGraphQLErrorHandler {
1719

1820
private List<GraphQLErrorFactory> factories;

graphql-spring-boot-autoconfigure/src/main/java/com/oembedler/moon/graphql/boot/error/GraphQLErrorHandlerFactory.java

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import graphql.servlet.DefaultGraphQLErrorHandler;
55
import graphql.servlet.GraphQLErrorHandler;
66
import lombok.extern.slf4j.Slf4j;
7-
import org.springframework.beans.factory.config.BeanDefinition;
7+
import org.springframework.beans.factory.BeanCreationException;
88
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
99
import org.springframework.context.ApplicationContext;
1010
import org.springframework.context.ConfigurableApplicationContext;
@@ -14,7 +14,6 @@
1414
import java.util.Arrays;
1515
import java.util.Collections;
1616
import java.util.List;
17-
import java.util.Objects;
1817
import java.util.stream.Collectors;
1918

2019
@Slf4j
@@ -24,29 +23,28 @@ public GraphQLErrorHandler create(ConfigurableApplicationContext applicationCont
2423
ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
2524
List<GraphQLErrorFactory> factories = Arrays.stream(beanFactory.getBeanDefinitionNames())
2625
.filter(applicationContext::containsBean)
27-
.map(beanFactory::getBeanDefinition)
28-
.map(BeanDefinition::getBeanClassName)
29-
.filter(Objects::nonNull)
30-
.map(name -> scanForExceptionHandlers(applicationContext, beanFactory, name))
26+
.map(name -> scanForExceptionHandlers(applicationContext, name))
3127
.flatMap(List::stream)
3228
.collect(Collectors.toList());
3329

3430
if (!factories.isEmpty() || exceptionHandlersEnabled) {
31+
log.debug("Handle GraphQL errors using exception handlers defined in {} custom factories", factories.size());
3532
return new GraphQLErrorFromExceptionHandler(factories);
3633
}
3734

35+
log.debug("Using default GraphQL error handler");
3836
return new DefaultGraphQLErrorHandler();
3937
}
4038

41-
private List<GraphQLErrorFactory> scanForExceptionHandlers(ApplicationContext context, ConfigurableListableBeanFactory beanFactory, String className) {
39+
private List<GraphQLErrorFactory> scanForExceptionHandlers(ApplicationContext context, String name) {
4240
try {
43-
Class<?> objClz = beanFactory.getBeanClassLoader().loadClass(className);
41+
Class<?> objClz = context.getBean(name).getClass();
4442
return Arrays.stream(objClz.getDeclaredMethods())
4543
.filter(this::isGraphQLExceptionHandlerMethod)
46-
.map(method -> GraphQLErrorFactory.withReflection(context.getBean(className), method))
44+
.map(method -> GraphQLErrorFactory.withReflection(context.getBean(name), method))
4745
.collect(Collectors.toList());
48-
} catch (ClassNotFoundException e) {
49-
log.error("Cannot load class " + className + ". " + e.getMessage());
46+
} catch (BeanCreationException e) {
47+
log.error("Cannot load class " + name + ". " + e.getMessage());
5048
return Collections.emptyList();
5149
}
5250
}

0 commit comments

Comments
 (0)