Skip to content

Commit 52bdcf1

Browse files
authored
Merge pull request #4021 from graphql-java/immutables-in-type-registry
Added a read only copy of a type registry for performance reasons
2 parents aecbb36 + 3409acf commit 52bdcf1

7 files changed

Lines changed: 401 additions & 21 deletions

File tree

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package graphql.schema.idl;
2+
3+
import com.google.common.collect.ImmutableList;
4+
import com.google.common.collect.ImmutableMap;
5+
import graphql.GraphQLError;
6+
import graphql.PublicApi;
7+
import graphql.language.DirectiveDefinition;
8+
import graphql.language.EnumTypeExtensionDefinition;
9+
import graphql.language.InputObjectTypeExtensionDefinition;
10+
import graphql.language.InterfaceTypeExtensionDefinition;
11+
import graphql.language.ObjectTypeExtensionDefinition;
12+
import graphql.language.SDLDefinition;
13+
import graphql.language.ScalarTypeDefinition;
14+
import graphql.language.ScalarTypeExtensionDefinition;
15+
import graphql.language.SchemaExtensionDefinition;
16+
import graphql.language.TypeDefinition;
17+
import graphql.language.UnionTypeExtensionDefinition;
18+
import graphql.schema.idl.errors.SchemaProblem;
19+
import org.jspecify.annotations.NullMarked;
20+
21+
import java.util.Collection;
22+
import java.util.List;
23+
import java.util.Map;
24+
import java.util.Optional;
25+
26+
import static com.google.common.collect.ImmutableMap.copyOf;
27+
28+
/**
29+
* A {@link ImmutableTypeDefinitionRegistry} contains an immutable set of type definitions that come from compiling
30+
* a graphql schema definition file via {@link SchemaParser#parse(String)} and is more performant because it
31+
* uses {@link ImmutableMap} structures.
32+
*/
33+
@SuppressWarnings("rawtypes")
34+
@PublicApi
35+
@NullMarked
36+
public class ImmutableTypeDefinitionRegistry extends TypeDefinitionRegistry {
37+
ImmutableTypeDefinitionRegistry(TypeDefinitionRegistry registry) {
38+
super(
39+
copyOf(registry.objectTypeExtensions),
40+
copyOf(registry.interfaceTypeExtensions),
41+
copyOf(registry.unionTypeExtensions),
42+
copyOf(registry.enumTypeExtensions),
43+
copyOf(registry.scalarTypeExtensions),
44+
copyOf(registry.inputObjectTypeExtensions),
45+
copyOf(registry.types),
46+
copyOf(registry.scalars()), // has an extra side effect
47+
copyOf(registry.directiveDefinitions),
48+
ImmutableList.copyOf(registry.schemaExtensionDefinitions),
49+
registry.schema,
50+
registry.schemaParseOrder
51+
);
52+
}
53+
54+
private UnsupportedOperationException unsupportedOperationException() {
55+
return new UnsupportedOperationException("The TypeDefinitionRegistry is in read only mode");
56+
}
57+
58+
@Override
59+
public TypeDefinitionRegistry merge(TypeDefinitionRegistry typeRegistry) throws SchemaProblem {
60+
throw unsupportedOperationException();
61+
}
62+
63+
@Override
64+
public Optional<GraphQLError> addAll(Collection<SDLDefinition> definitions) {
65+
throw unsupportedOperationException();
66+
}
67+
68+
@Override
69+
public Optional<GraphQLError> add(SDLDefinition definition) {
70+
throw unsupportedOperationException();
71+
}
72+
73+
@Override
74+
public void remove(SDLDefinition definition) {
75+
throw unsupportedOperationException();
76+
}
77+
78+
@Override
79+
public void remove(String key, SDLDefinition definition) {
80+
throw unsupportedOperationException();
81+
}
82+
83+
@Override
84+
public Map<String, TypeDefinition> types() {
85+
return types;
86+
}
87+
88+
@Override
89+
public Map<String, ScalarTypeDefinition> scalars() {
90+
return scalarTypes;
91+
}
92+
93+
@Override
94+
public Map<String, List<ObjectTypeExtensionDefinition>> objectTypeExtensions() {
95+
return objectTypeExtensions;
96+
}
97+
98+
@Override
99+
public Map<String, List<InterfaceTypeExtensionDefinition>> interfaceTypeExtensions() {
100+
return interfaceTypeExtensions;
101+
}
102+
103+
@Override
104+
public Map<String, List<UnionTypeExtensionDefinition>> unionTypeExtensions() {
105+
return unionTypeExtensions;
106+
}
107+
108+
@Override
109+
public Map<String, List<EnumTypeExtensionDefinition>> enumTypeExtensions() {
110+
return enumTypeExtensions;
111+
}
112+
113+
@Override
114+
public Map<String, List<ScalarTypeExtensionDefinition>> scalarTypeExtensions() {
115+
return scalarTypeExtensions;
116+
}
117+
118+
@Override
119+
public Map<String, List<InputObjectTypeExtensionDefinition>> inputObjectTypeExtensions() {
120+
return inputObjectTypeExtensions;
121+
}
122+
123+
@Override
124+
public List<SchemaExtensionDefinition> getSchemaExtensionDefinitions() {
125+
return schemaExtensionDefinitions;
126+
}
127+
128+
@Override
129+
public Map<String, DirectiveDefinition> getDirectiveDefinitions() {
130+
return directiveDefinitions;
131+
}
132+
}

‎src/main/java/graphql/schema/idl/SchemaGenerator.java‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,17 +103,19 @@ public GraphQLSchema makeExecutableSchema(Options options, TypeDefinitionRegistr
103103

104104
schemaGeneratorHelper.addDirectivesIncludedByDefault(typeRegistryCopy);
105105

106-
List<GraphQLError> errors = typeChecker.checkTypeRegistry(typeRegistryCopy, wiring);
106+
// by making it read only all the traversal and checks run faster
107+
ImmutableTypeDefinitionRegistry fasterImmutableRegistry = typeRegistryCopy.readOnly();
108+
List<GraphQLError> errors = typeChecker.checkTypeRegistry(fasterImmutableRegistry, wiring);
107109
if (!errors.isEmpty()) {
108110
throw new SchemaProblem(errors);
109111
}
110112

111-
Map<String, OperationTypeDefinition> operationTypeDefinitions = SchemaExtensionsChecker.gatherOperationDefs(typeRegistry);
113+
Map<String, OperationTypeDefinition> operationTypeDefinitions = SchemaExtensionsChecker.gatherOperationDefs(fasterImmutableRegistry);
112114

113-
return makeExecutableSchemaImpl(typeRegistryCopy, wiring, operationTypeDefinitions, options);
115+
return makeExecutableSchemaImpl(fasterImmutableRegistry, wiring, operationTypeDefinitions, options);
114116
}
115117

116-
private GraphQLSchema makeExecutableSchemaImpl(TypeDefinitionRegistry typeRegistry,
118+
private GraphQLSchema makeExecutableSchemaImpl(ImmutableTypeDefinitionRegistry typeRegistry,
117119
RuntimeWiring wiring,
118120
Map<String, OperationTypeDefinition> operationTypeDefinitions,
119121
Options options) {

‎src/main/java/graphql/schema/idl/SchemaGeneratorHelper.java‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ public class SchemaGeneratorHelper {
111111
* it gives us helper functions
112112
*/
113113
static class BuildContext {
114-
private final TypeDefinitionRegistry typeRegistry;
114+
private final ImmutableTypeDefinitionRegistry typeRegistry;
115115
private final RuntimeWiring wiring;
116116
private final Deque<String> typeStack = new ArrayDeque<>();
117117

@@ -123,7 +123,7 @@ static class BuildContext {
123123
public final SchemaGenerator.Options options;
124124
public boolean directiveWiringRequired;
125125

126-
BuildContext(TypeDefinitionRegistry typeRegistry, RuntimeWiring wiring, Map<String, OperationTypeDefinition> operationTypeDefinitions, SchemaGenerator.Options options) {
126+
BuildContext(ImmutableTypeDefinitionRegistry typeRegistry, RuntimeWiring wiring, Map<String, OperationTypeDefinition> operationTypeDefinitions, SchemaGenerator.Options options) {
127127
this.typeRegistry = typeRegistry;
128128
this.wiring = wiring;
129129
this.codeRegistry = GraphQLCodeRegistry.newCodeRegistry(wiring.getCodeRegistry());

‎src/main/java/graphql/schema/idl/SchemaTypeChecker.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
@Internal
5353
public class SchemaTypeChecker {
5454

55-
public List<GraphQLError> checkTypeRegistry(TypeDefinitionRegistry typeRegistry, RuntimeWiring wiring) throws SchemaProblem {
55+
public List<GraphQLError> checkTypeRegistry(ImmutableTypeDefinitionRegistry typeRegistry, RuntimeWiring wiring) throws SchemaProblem {
5656
List<GraphQLError> errors = new ArrayList<>();
5757
checkForMissingTypes(errors, typeRegistry);
5858

‎src/main/java/graphql/schema/idl/TypeDefinitionRegistry.java‎

Lines changed: 63 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -54,20 +54,70 @@
5454
@NullMarked
5555
public class TypeDefinitionRegistry implements Serializable {
5656

57-
private final Map<String, List<ObjectTypeExtensionDefinition>> objectTypeExtensions = new LinkedHashMap<>();
58-
private final Map<String, List<InterfaceTypeExtensionDefinition>> interfaceTypeExtensions = new LinkedHashMap<>();
59-
private final Map<String, List<UnionTypeExtensionDefinition>> unionTypeExtensions = new LinkedHashMap<>();
60-
private final Map<String, List<EnumTypeExtensionDefinition>> enumTypeExtensions = new LinkedHashMap<>();
61-
private final Map<String, List<ScalarTypeExtensionDefinition>> scalarTypeExtensions = new LinkedHashMap<>();
62-
private final Map<String, List<InputObjectTypeExtensionDefinition>> inputObjectTypeExtensions = new LinkedHashMap<>();
63-
64-
private final Map<String, TypeDefinition> types = new LinkedHashMap<>();
65-
private final Map<String, ScalarTypeDefinition> scalarTypes = new LinkedHashMap<>();
66-
private final Map<String, DirectiveDefinition> directiveDefinitions = new LinkedHashMap<>();
67-
private @Nullable SchemaDefinition schema;
68-
private final List<SchemaExtensionDefinition> schemaExtensionDefinitions = new ArrayList<>();
69-
private final SchemaParseOrder schemaParseOrder = new SchemaParseOrder();
57+
protected final Map<String, List<ObjectTypeExtensionDefinition>> objectTypeExtensions;
58+
protected final Map<String, List<InterfaceTypeExtensionDefinition>> interfaceTypeExtensions;
59+
protected final Map<String, List<UnionTypeExtensionDefinition>> unionTypeExtensions;
60+
protected final Map<String, List<EnumTypeExtensionDefinition>> enumTypeExtensions;
61+
protected final Map<String, List<ScalarTypeExtensionDefinition>> scalarTypeExtensions;
62+
protected final Map<String, List<InputObjectTypeExtensionDefinition>> inputObjectTypeExtensions;
63+
64+
protected final Map<String, TypeDefinition> types;
65+
protected final Map<String, ScalarTypeDefinition> scalarTypes;
66+
protected final Map<String, DirectiveDefinition> directiveDefinitions;
67+
protected @Nullable SchemaDefinition schema;
68+
protected final List<SchemaExtensionDefinition> schemaExtensionDefinitions;
69+
protected final SchemaParseOrder schemaParseOrder;
70+
71+
public TypeDefinitionRegistry() {
72+
objectTypeExtensions = new LinkedHashMap<>();
73+
interfaceTypeExtensions = new LinkedHashMap<>();
74+
unionTypeExtensions = new LinkedHashMap<>();
75+
enumTypeExtensions = new LinkedHashMap<>();
76+
scalarTypeExtensions = new LinkedHashMap<>();
77+
inputObjectTypeExtensions = new LinkedHashMap<>();
78+
types = new LinkedHashMap<>();
79+
scalarTypes = new LinkedHashMap<>();
80+
directiveDefinitions = new LinkedHashMap<>();
81+
schemaExtensionDefinitions = new ArrayList<>();
82+
schemaParseOrder = new SchemaParseOrder();
83+
}
84+
85+
protected TypeDefinitionRegistry(Map<String, List<ObjectTypeExtensionDefinition>> objectTypeExtensions,
86+
Map<String, List<InterfaceTypeExtensionDefinition>> interfaceTypeExtensions,
87+
Map<String, List<UnionTypeExtensionDefinition>> unionTypeExtensions,
88+
Map<String, List<EnumTypeExtensionDefinition>> enumTypeExtensions,
89+
Map<String, List<ScalarTypeExtensionDefinition>> scalarTypeExtensions,
90+
Map<String, List<InputObjectTypeExtensionDefinition>> inputObjectTypeExtensions,
91+
Map<String, TypeDefinition> types,
92+
Map<String, ScalarTypeDefinition> scalarTypes,
93+
Map<String, DirectiveDefinition> directiveDefinitions,
94+
List<SchemaExtensionDefinition> schemaExtensionDefinitions,
95+
@Nullable SchemaDefinition schema,
96+
SchemaParseOrder schemaParseOrder) {
97+
this.objectTypeExtensions = objectTypeExtensions;
98+
this.interfaceTypeExtensions = interfaceTypeExtensions;
99+
this.unionTypeExtensions = unionTypeExtensions;
100+
this.enumTypeExtensions = enumTypeExtensions;
101+
this.scalarTypeExtensions = scalarTypeExtensions;
102+
this.inputObjectTypeExtensions = inputObjectTypeExtensions;
103+
this.types = types;
104+
this.scalarTypes = scalarTypes;
105+
this.directiveDefinitions = directiveDefinitions;
106+
this.schemaExtensionDefinitions = schemaExtensionDefinitions;
107+
this.schema = schema;
108+
this.schemaParseOrder = schemaParseOrder;
109+
}
70110

111+
/**
112+
* @return an immutable view of this {@link TypeDefinitionRegistry} that is more performant
113+
* when in read only mode.
114+
*/
115+
public ImmutableTypeDefinitionRegistry readOnly() {
116+
if (this instanceof ImmutableTypeDefinitionRegistry) {
117+
return (ImmutableTypeDefinitionRegistry) this;
118+
}
119+
return new ImmutableTypeDefinitionRegistry(this);
120+
}
71121

72122
/**
73123
* @return the order in which {@link SDLDefinition}s were parsed

0 commit comments

Comments
 (0)