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

Commit 05943be

Browse files
authored
Merge branch 'master' into master
2 parents 9b5bc32 + d54d805 commit 05943be

File tree

11 files changed

+243
-16
lines changed

11 files changed

+243
-16
lines changed

README.md

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ and join the team!
1616
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
1717
**Table of Contents**
1818

19-
- [WARNING: NoClassDefFoundError when using GraphQL Java Tools > 5.4.x](#warning-noclassdeffounderror-when-using-graphql-java-tools--54x)
19+
- [WARNING: NoClassDefFoundError when using GraphQL Java Tools > 5.4.x](#warning-noclassdeffounderror-when-using-graphql-java-tools--54x)
2020
- [Using Gradle](#using-gradle)
2121
- [Using Maven](#using-maven)
2222
- [Documentation](#documentation)
@@ -26,21 +26,22 @@ and join the team!
2626
- [Enable Graph*i*QL](#enable-graphiql)
2727
- [Enable Altair](#enable-altair)
2828
- [Enable GraphQL Playground](#enable-graphql-playground)
29-
- [Basic settings](#basic-settings)
30-
- [CDN](#cdn)
31-
- [Custom static resources](#custom-static-resources)
32-
- [Customizing GraphQL Playground](#customizing-graphql-playground)
33-
- [Tabs](#tabs)
29+
- [Basic settings](#basic-settings)
30+
- [CDN](#cdn)
31+
- [Custom static resources](#custom-static-resources)
32+
- [Customizing GraphQL Playground](#customizing-graphql-playground)
33+
- [Tabs](#tabs)
3434
- [Supported GraphQL-Java Libraries](#supported-graphql-java-libraries)
35-
- [GraphQL Java Tools](#graphql-java-tools)
36-
- [GraphQL Annotations](#graphql-annotations)
37-
- [Configuration](#configuration)
38-
- [Root resolvers, directives, type extensions](#root-resolvers-directives-type-extensions)
39-
- [Interfaces](#interfaces)
40-
- [Custom scalars and type functions](#custom-scalars-and-type-functions)
41-
- [Custom Relay and GraphQL Annotation Processor](#custom-relay-and-graphql-annotation-processor)
35+
- [GraphQL Java Tools](#graphql-java-tools)
36+
- [GraphQL Annotations](#graphql-annotations)
37+
- [Configuration](#configuration)
38+
- [Root resolvers, directives, type extensions](#root-resolvers-directives-type-extensions)
39+
- [Interfaces](#interfaces)
40+
- [Custom scalars and type functions](#custom-scalars-and-type-functions)
41+
- [Custom Relay and GraphQL Annotation Processor](#custom-relay-and-graphql-annotation-processor)
42+
- [Extended scalars](#extended-scalars)
4243
- [Tracing and Metrics](#tracing-and-metrics)
43-
- [Usage](#usage)
44+
- [Usage](#usage)
4445
- [Contributions](#contributions)
4546
- [Licenses](#licenses)
4647

@@ -233,6 +234,7 @@ graphql:
233234
corsEnabled: true
234235
cors:
235236
allowed-origins: http://some.domain.com
237+
allowed-methods: GET, HEAD, POST
236238
# if you want to @ExceptionHandler annotation for custom GraphQLErrors
237239
exception-handlers-enabled: true
238240
contextSetting: PER_REQUEST_WITH_INSTRUMENTATION
@@ -537,6 +539,31 @@ It is possible to define a bean implementing `Relay` and/or `GraphQLAnnotations`
537539
will be passed to the schema builder. Spring dependency injection works as usual. Note that GraphQL
538540
Annotations provides default implementation for these which should be sufficient is most cases.
539541
542+
## Extended scalars
543+
544+
[Extended scalars](https://github.com/graphql-java/graphql-java-extended-scalars) can be enabled by using the
545+
`graphql.extended-scalars` configuration property, e. g.:
546+
547+
```yaml
548+
graphql:
549+
extended-scalars: BigDecimal, Date
550+
```
551+
552+
The available scalars are the following: `BigDecimal`, `BigInteger`, `Byte`, `Char`, `Date`, `DateTime`, `JSON`,
553+
`Locale`, `Long`, `NegativeFloat`, `NegativeInt`, `NonNegativeFloat`, `NonNegativeInt`, `NonPositiveFloat`,
554+
`NonPositiveInt`, `Object`, `PositiveFloat`, `PositiveInt`, `Short`, `Time`, `Url`.
555+
556+
This setting works with both the [GraphQL Java Tools](#graphql-java-tools) and the
557+
[GraphQL Annotations](#graphql-annotations) integration.
558+
559+
When using the [GraphQL Java Tools](#graphql-java-tools) integration, the scalars must also be declared in the GraphQL
560+
Schema:
561+
562+
```graphql
563+
scalar BigDecimal
564+
scalar Date
565+
```
566+
540567
# Tracing and Metrics
541568

542569
[Apollo style tracing](https://github.com/apollographql/apollo-tracing) along with two levels of

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,6 @@ spring:
33
name: graphql-subscription-example
44
server:
55
port: 9001
6+
7+
graphql:
8+
extended-scalars: BigDecimal

example-graphql-subscription/src/main/resources/subscription.graphqls

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ schema {
66
subscription : Subscription
77
}
88

9+
scalar BigDecimal
10+
911
type Query {
1012
hello : String
1113
}
@@ -17,6 +19,6 @@ type Subscription {
1719
type StockPriceUpdate {
1820
dateTime : String
1921
stockCode : String
20-
stockPrice : Float
21-
stockPriceChange : Float!
22+
stockPrice : BigDecimal
23+
stockPriceChange : BigDecimal!
2224
}

gradle.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ SOURCE_COMPATIBILITY=1.8
3232
TARGET_COMPATIBILITY=1.8
3333
### Dependencies
3434
LIB_GRAPHQL_JAVA_VER=16.2
35+
LIB_EXTENDED_SCALARS_VERSION=16.0.0
3536
LIB_SPRING_BOOT_VER=2.4.2
3637
LIB_GRAPHQL_SERVLET_VER=11.0.0
3738
LIB_GRAPHQL_JAVA_TOOLS_VER=11.0.0

graphql-spring-boot-autoconfigure/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ dependencies {
2121
api(project(":graphql-kickstart-spring-boot-starter-tools"))
2222
api(project(":graphql-kickstart-spring-support"))
2323
implementation "org.springframework.boot:spring-boot-autoconfigure"
24+
api "com.graphql-java:graphql-java-extended-scalars:$LIB_EXTENDED_SCALARS_VERSION"
2425
api "com.graphql-java-kickstart:graphql-java-kickstart:$LIB_GRAPHQL_SERVLET_VER"
2526
api "com.graphql-java-kickstart:graphql-java-servlet:$LIB_GRAPHQL_SERVLET_VER"
2627
api "com.graphql-java:graphql-java:$LIB_GRAPHQL_JAVA_VER"
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package graphql.kickstart.spring.web.boot;
2+
3+
import graphql.scalars.ExtendedScalars;
4+
import graphql.schema.GraphQLScalarType;
5+
import lombok.NoArgsConstructor;
6+
import org.springframework.context.ApplicationContextException;
7+
import org.springframework.context.ApplicationContextInitializer;
8+
import org.springframework.context.support.GenericApplicationContext;
9+
import org.springframework.util.ReflectionUtils;
10+
11+
import java.lang.reflect.Modifier;
12+
import java.util.Collection;
13+
import java.util.Collections;
14+
import java.util.HashSet;
15+
import java.util.Set;
16+
import java.util.stream.Collectors;
17+
18+
@NoArgsConstructor
19+
public class GraphQLExtendedScalarsInitializer implements ApplicationContextInitializer<GenericApplicationContext> {
20+
21+
@Override
22+
public void initialize(final GenericApplicationContext applicationContext) {
23+
final Collection<String> enabledExtendedScalars = getEnabledExtendedScalars(applicationContext);
24+
final Collection<String> validScalarNames = new HashSet<>();
25+
ReflectionUtils.doWithFields(ExtendedScalars.class, scalarField -> {
26+
if (Modifier.isPublic(scalarField.getModifiers()) && Modifier.isStatic(scalarField.getModifiers())
27+
&& scalarField.getType().equals(GraphQLScalarType.class)) {
28+
final GraphQLScalarType graphQLScalarType = (GraphQLScalarType) scalarField.get(null);
29+
if (enabledExtendedScalars.contains(graphQLScalarType.getName())) {
30+
applicationContext.registerBean(
31+
graphQLScalarType.getName(),
32+
GraphQLScalarType.class,
33+
() -> graphQLScalarType
34+
);
35+
}
36+
validScalarNames.add(graphQLScalarType.getName());
37+
}
38+
});
39+
verifyEnabledScalars(enabledExtendedScalars, validScalarNames);
40+
}
41+
42+
private void verifyEnabledScalars(
43+
final Collection<String> enabledExtendedScalars,
44+
final Collection<String> validScalarNames
45+
) {
46+
final Collection<String> invalidScalarNames = new HashSet<>(enabledExtendedScalars);
47+
invalidScalarNames.removeAll(validScalarNames);
48+
if (!invalidScalarNames.isEmpty()) {
49+
throw new ApplicationContextException(String.format(
50+
"Invalid extended scalar name(s) found: %s. Valid names are: %s.",
51+
joinNames(invalidScalarNames),
52+
joinNames(validScalarNames)
53+
)
54+
);
55+
}
56+
}
57+
58+
private String joinNames(final Collection<String> names) {
59+
return names.stream().sorted().collect(Collectors.joining(", "));
60+
}
61+
62+
@SuppressWarnings("unchecked")
63+
private Set<String> getEnabledExtendedScalars(final GenericApplicationContext applicationContext) {
64+
return (Set<String>) applicationContext.getEnvironment()
65+
.getProperty("graphql.extended-scalars", Collection.class, Collections.emptySet())
66+
.stream().map(String::valueOf).collect(Collectors.toSet());
67+
}
68+
}

graphql-spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,10 @@
55
}
66
],
77
"properties": [
8+
{
9+
"name": "graphql.extended-scalars",
10+
"type": "java.util.Set",
11+
"description": "List of extended scalars to be used."
12+
}
813
]
914
}

graphql-spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
org.springframework.context.ApplicationContextInitializer=\
2+
graphql.kickstart.spring.web.boot.GraphQLExtendedScalarsInitializer
13
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
24
graphql.kickstart.spring.web.boot.GraphQLWebAutoConfiguration,\
35
graphql.kickstart.spring.web.boot.GraphQLWebsocketAutoConfiguration,\
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package graphql.kickstart.spring.web.boot.test.extendedscalars;
2+
3+
import graphql.scalars.ExtendedScalars;
4+
import graphql.schema.GraphQLScalarType;
5+
import org.junit.jupiter.api.DisplayName;
6+
import org.junit.jupiter.api.Test;
7+
import org.springframework.beans.factory.annotation.Autowired;
8+
import org.springframework.boot.autoconfigure.SpringBootApplication;
9+
import org.springframework.boot.test.context.SpringBootTest;
10+
import org.springframework.context.ApplicationContext;
11+
import org.springframework.test.context.TestPropertySource;
12+
13+
import java.util.AbstractMap;
14+
15+
import static org.assertj.core.api.Assertions.assertThat;
16+
17+
@SpringBootTest(
18+
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
19+
classes = ExtendedScalarAutoConfigurationTest.ExtendedScalarsTestApplication.class
20+
)
21+
@TestPropertySource(properties = "graphql.extended-scalars=BigDecimal")
22+
@DisplayName("Testing extended scalars auto configuration")
23+
public class ExtendedScalarAutoConfigurationTest {
24+
25+
@Autowired
26+
private ApplicationContext applicationContext;
27+
28+
@Test
29+
@DisplayName("The extended scalars initializer should be properly picked up by Spring auto configuration.")
30+
void testAutoConfiguration() {
31+
assertThat(applicationContext.getBeansOfType(GraphQLScalarType.class))
32+
.containsOnly(new AbstractMap.SimpleEntry<>("BigDecimal", ExtendedScalars.GraphQLBigDecimal));
33+
}
34+
35+
@SpringBootApplication
36+
public static class ExtendedScalarsTestApplication {
37+
}
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package graphql.kickstart.spring.web.boot.test.extendedscalars;
2+
3+
import graphql.kickstart.spring.web.boot.GraphQLExtendedScalarsInitializer;
4+
import graphql.scalars.ExtendedScalars;
5+
import graphql.schema.GraphQLScalarType;
6+
import org.junit.jupiter.api.DisplayName;
7+
import org.junit.jupiter.api.Test;
8+
import org.springframework.boot.SpringApplication;
9+
import org.springframework.boot.WebApplicationType;
10+
import org.springframework.context.ApplicationContextException;
11+
import org.springframework.context.ConfigurableApplicationContext;
12+
import org.springframework.core.env.MapPropertySource;
13+
import org.springframework.core.env.StandardEnvironment;
14+
15+
import java.util.AbstractMap;
16+
import java.util.Collections;
17+
18+
import static org.assertj.core.api.Assertions.assertThat;
19+
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
20+
21+
@DisplayName("Testing extended scalars configuration")
22+
public class ExtendedScalarsTest {
23+
24+
@Test
25+
@DisplayName("Should throw exception at context initialization when invalid extended scalar name is provided.")
26+
void shouldThrowErrorOnStartupIfExtendedScalarDoesNotExists() {
27+
// GIVEN
28+
final SpringApplication application = setupTestApplication("Long,Short,Datee,BadDecimal");
29+
// THEN
30+
assertThatExceptionOfType(ApplicationContextException.class)
31+
.isThrownBy(application::run)
32+
.withMessage("Invalid extended scalar name(s) found: BadDecimal, Datee. Valid names are: BigDecimal, " +
33+
"BigInteger, Byte, Char, Date, DateTime, JSON, Locale, Long, NegativeFloat, NegativeInt, " +
34+
"NonNegativeFloat, NonNegativeInt, NonPositiveFloat, NonPositiveInt, Object, PositiveFloat, " +
35+
"PositiveInt, Short, Time, Url.");
36+
}
37+
38+
@Test
39+
@DisplayName("Should not create any extended scalars by default.")
40+
void shouldNotDeclareAnyExtendedScalarsByDefault() {
41+
// GIVEN
42+
final SpringApplication application = setupTestApplication(null);
43+
// WHEN
44+
final ConfigurableApplicationContext context = application.run();
45+
// THEN
46+
assertThat(context.getBeansOfType(GraphQLScalarType.class)).isEmpty();
47+
}
48+
49+
@Test
50+
@DisplayName("Should declare the configured extended scalars.")
51+
void shouldDeclareTheConfiguredScalars() {
52+
// GIVEN
53+
final SpringApplication application = setupTestApplication("Long,Short,BigDecimal,Date");
54+
// WHEN
55+
final ConfigurableApplicationContext context = application.run();
56+
// THEN
57+
assertThat(context.getBeansOfType(GraphQLScalarType.class))
58+
.containsOnly(
59+
new AbstractMap.SimpleEntry<>("Long", ExtendedScalars.GraphQLLong),
60+
new AbstractMap.SimpleEntry<>("Short", ExtendedScalars.GraphQLShort),
61+
new AbstractMap.SimpleEntry<>("BigDecimal", ExtendedScalars.GraphQLBigDecimal),
62+
new AbstractMap.SimpleEntry<>("Date", ExtendedScalars.Date)
63+
);
64+
}
65+
66+
private SpringApplication setupTestApplication(final String extendedScalarValue) {
67+
final StandardEnvironment standardEnvironment = new StandardEnvironment();
68+
standardEnvironment.getPropertySources().addFirst(new MapPropertySource("testProperties",
69+
Collections.singletonMap("graphql.extended-scalars", extendedScalarValue)));
70+
final SpringApplication application = new SpringApplication(GraphQLExtendedScalarsInitializer.class);
71+
application.setWebApplicationType(WebApplicationType.NONE);
72+
application.setEnvironment(standardEnvironment);
73+
return application;
74+
}
75+
}

0 commit comments

Comments
 (0)