Skip to content

Commit ea06fe5

Browse files
committed
make nodes immutable (compiles)
1 parent d4bf856 commit ea06fe5

66 files changed

Lines changed: 805 additions & 844 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/main/antlr/GraphqlSDL.g4

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,7 @@ objectTypeDefinition : description? TYPE name implementsInterfaces? directives?
4545
objectTypeExtensionDefinition : EXTEND TYPE name implementsInterfaces? directives? fieldsDefinition?;
4646

4747
implementsInterfaces :
48-
IMPLEMENTS '&'? ty
49-
peName+ |
48+
IMPLEMENTS '&'? typeName+ |
5049
implementsInterfaces '&' typeName ;
5150

5251
fieldsDefinition : '{' fieldDefinition* '}';

src/main/java/graphql/introspection/IntrospectionResultToSchema.java

Lines changed: 54 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import graphql.language.InputValueDefinition;
1515
import graphql.language.InterfaceTypeDefinition;
1616
import graphql.language.ListType;
17+
import graphql.language.NodeDirectivesBuilder;
1718
import graphql.language.NonNullType;
1819
import graphql.language.ObjectTypeDefinition;
1920
import graphql.language.OperationTypeDefinition;
@@ -70,41 +71,41 @@ public Document createSchemaDefinition(Map<String, Object> introspectionResult)
7071

7172
Map<String, Object> queryType = (Map<String, Object>) schema.get("queryType");
7273
assertNotNull(queryType, "queryType expected");
73-
TypeName query = new TypeName((String) queryType.get("name"));
74+
TypeName query = TypeName.newTypeName().name((String) queryType.get("name")).build();
7475
boolean nonDefaultQueryName = !"Query".equals(query.getName());
7576

76-
SchemaDefinition schemaDefinition = new SchemaDefinition();
77-
schemaDefinition.getOperationTypeDefinitions().add(new OperationTypeDefinition("query", query));
77+
SchemaDefinition.Builder schemaDefinition = SchemaDefinition.newSchemaDefintion();
78+
schemaDefinition.operationTypeDefinition(OperationTypeDefinition.newOperationTypeDefinition().name("query").type(query).build());
7879

7980
Map<String, Object> mutationType = (Map<String, Object>) schema.get("mutationType");
8081
boolean nonDefaultMutationName = false;
8182
if (mutationType != null) {
82-
TypeName mutation = new TypeName((String) mutationType.get("name"));
83+
TypeName mutation = TypeName.newTypeName().name((String) mutationType.get("name")).build();
8384
nonDefaultMutationName = !"Mutation".equals(mutation.getName());
84-
schemaDefinition.getOperationTypeDefinitions().add(new OperationTypeDefinition("mutation", mutation));
85+
schemaDefinition.operationTypeDefinition(OperationTypeDefinition.newOperationTypeDefinition().name("mutation").type(mutation).build());
8586
}
8687

8788
Map<String, Object> subscriptionType = (Map<String, Object>) schema.get("subscriptionType");
8889
boolean nonDefaultSubscriptionName = false;
8990
if (subscriptionType != null) {
90-
TypeName subscription = new TypeName((String) subscriptionType.get("name"));
91+
TypeName subscription = TypeName.newTypeName().name(((String) subscriptionType.get("name"))).build();
9192
nonDefaultSubscriptionName = !"Subscription".equals(subscription.getName());
92-
schemaDefinition.getOperationTypeDefinitions().add(new OperationTypeDefinition("subscription", subscription));
93+
schemaDefinition.operationTypeDefinition(OperationTypeDefinition.newOperationTypeDefinition().name("subscription").type(subscription).build());
9394
}
9495

95-
Document document = new Document();
96+
Document.Builder document = Document.newDocument();
9697
if (nonDefaultQueryName || nonDefaultMutationName || nonDefaultSubscriptionName) {
97-
document.getDefinitions().add(schemaDefinition);
98+
document.definition(schemaDefinition.build());
9899
}
99100

100101
List<Map<String, Object>> types = (List<Map<String, Object>>) schema.get("types");
101102
for (Map<String, Object> type : types) {
102103
TypeDefinition typeDefinition = createTypeDefinition(type);
103104
if (typeDefinition == null) continue;
104-
document.getDefinitions().add(typeDefinition);
105+
document.definition(typeDefinition);
105106
}
106107

107-
return document;
108+
return document.build();
108109
}
109110

110111
private TypeDefinition createTypeDefinition(Map<String, Object> type) {
@@ -134,59 +135,60 @@ private TypeDefinition createScalar(Map<String, Object> input) {
134135
if (ScalarInfo.isStandardScalar(name)) {
135136
return null;
136137
}
137-
return new ScalarTypeDefinition(name);
138+
return ScalarTypeDefinition.newScalarTypeDefinition().name(name).build();
138139
}
139140

140141

141142
@SuppressWarnings("unchecked")
142143
UnionTypeDefinition createUnion(Map<String, Object> input) {
143144
assertTrue(input.get("kind").equals("UNION"), "wrong input");
144145

145-
UnionTypeDefinition unionTypeDefinition = new UnionTypeDefinition((String) input.get("name"));
146-
unionTypeDefinition.setComments(toComment((String) input.get("description")));
146+
UnionTypeDefinition.Builder unionTypeDefinition = UnionTypeDefinition.newUnionTypeDefinition();
147+
unionTypeDefinition.name((String) input.get("name"));
148+
unionTypeDefinition.comments(toComment((String) input.get("description")));
147149

148150
List<Map<String, Object>> possibleTypes = (List<Map<String, Object>>) input.get("possibleTypes");
149151

150152
for (Map<String, Object> possibleType : possibleTypes) {
151-
TypeName typeName = new TypeName((String) possibleType.get("name"));
152-
unionTypeDefinition.getMemberTypes().add(typeName);
153+
TypeName typeName = TypeName.newTypeName().name((String) possibleType.get("name")).build();
154+
unionTypeDefinition.memberType(typeName);
153155
}
154156

155-
return unionTypeDefinition;
157+
return unionTypeDefinition.build();
156158
}
157159

158160
@SuppressWarnings("unchecked")
159161
EnumTypeDefinition createEnum(Map<String, Object> input) {
160162
assertTrue(input.get("kind").equals("ENUM"), "wrong input");
161163

162-
EnumTypeDefinition enumTypeDefinition = new EnumTypeDefinition((String) input.get("name"));
163-
enumTypeDefinition.setComments(toComment((String) input.get("description")));
164+
EnumTypeDefinition.Builder enumTypeDefinition = EnumTypeDefinition.newEnumTypeDefinition().name((String) input.get("name"));
165+
enumTypeDefinition.comments(toComment((String) input.get("description")));
164166

165167
List<Map<String, Object>> enumValues = (List<Map<String, Object>>) input.get("enumValues");
166168

167169
for (Map<String, Object> enumValue : enumValues) {
168170

169-
EnumValueDefinition enumValueDefinition = new EnumValueDefinition((String) enumValue.get("name"));
170-
enumValueDefinition.setComments(toComment((String) enumValue.get("description")));
171+
EnumValueDefinition.Builder enumValueDefinition = EnumValueDefinition.newEnumValueDefinition().name((String) enumValue.get("name"));
172+
enumValueDefinition.comments(toComment((String) enumValue.get("description")));
171173

172-
createDeprecatedDirective(enumValue, enumValueDefinition.getDirectives());
174+
createDeprecatedDirective(enumValue, enumValueDefinition);
173175

174-
enumTypeDefinition.getEnumValueDefinitions().add(enumValueDefinition);
176+
enumTypeDefinition.enumValueDefinition(enumValueDefinition.build());
175177
}
176178

177-
return enumTypeDefinition;
179+
return enumTypeDefinition.build();
178180
}
179181

180182
@SuppressWarnings("unchecked")
181183
InterfaceTypeDefinition createInterface(Map<String, Object> input) {
182184
assertTrue(input.get("kind").equals("INTERFACE"), "wrong input");
183185

184-
InterfaceTypeDefinition interfaceTypeDefinition = new InterfaceTypeDefinition((String) input.get("name"));
185-
interfaceTypeDefinition.setComments(toComment((String) input.get("description")));
186+
InterfaceTypeDefinition.Builder interfaceTypeDefinition = InterfaceTypeDefinition.newInterfaceTypeDefinition().name((String) input.get("name"));
187+
interfaceTypeDefinition.comments(toComment((String) input.get("description")));
186188
List<Map<String, Object>> fields = (List<Map<String, Object>>) input.get("fields");
187-
interfaceTypeDefinition.getFieldDefinitions().addAll(createFields(fields));
189+
interfaceTypeDefinition.definitions(createFields(fields));
188190

189-
return interfaceTypeDefinition;
191+
return interfaceTypeDefinition.build();
190192

191193
}
192194

@@ -209,65 +211,67 @@ InputObjectTypeDefinition createInputObject(Map<String, Object> input) {
209211
ObjectTypeDefinition createObject(Map<String, Object> input) {
210212
assertTrue(input.get("kind").equals("OBJECT"), "wrong input");
211213

212-
ObjectTypeDefinition objectTypeDefinition = new ObjectTypeDefinition((String) input.get("name"));
213-
objectTypeDefinition.setComments(toComment((String) input.get("description")));
214+
ObjectTypeDefinition.Builder objectTypeDefinition = ObjectTypeDefinition.newObjectTypeDefinition().name((String) input.get("name"));
215+
objectTypeDefinition.comments(toComment((String) input.get("description")));
214216
if (input.containsKey("interfaces")) {
215-
objectTypeDefinition.getImplements().addAll(
216-
((List<Map<String, Object>>)input.get("interfaces")).stream()
217+
objectTypeDefinition.implementz(
218+
((List<Map<String, Object>>) input.get("interfaces")).stream()
217219
.map(this::createTypeIndirection)
218220
.collect(Collectors.toList())
219221
);
220222
}
221223
List<Map<String, Object>> fields = (List<Map<String, Object>>) input.get("fields");
222224

223-
objectTypeDefinition.getFieldDefinitions().addAll(createFields(fields));
225+
objectTypeDefinition.fieldDefinitions(createFields(fields));
224226

225-
return objectTypeDefinition;
227+
return objectTypeDefinition.build();
226228
}
227229

228230
private List<FieldDefinition> createFields(List<Map<String, Object>> fields) {
229231
List<FieldDefinition> result = new ArrayList<>();
230232
for (Map<String, Object> field : fields) {
231-
FieldDefinition fieldDefinition = new FieldDefinition((String) field.get("name"));
232-
fieldDefinition.setComments(toComment((String) field.get("description")));
233-
fieldDefinition.setType(createTypeIndirection((Map<String, Object>) field.get("type")));
233+
FieldDefinition.Builder fieldDefinition = FieldDefinition.newFieldDefintion().name((String) field.get("name"));
234+
fieldDefinition.comments(toComment((String) field.get("description")));
235+
fieldDefinition.type(createTypeIndirection((Map<String, Object>) field.get("type")));
234236

235-
createDeprecatedDirective(field, fieldDefinition.getDirectives());
237+
createDeprecatedDirective(field, fieldDefinition);
236238

237239
List<Map<String, Object>> args = (List<Map<String, Object>>) field.get("args");
238240
List<InputValueDefinition> inputValueDefinitions = createInputValueDefinitions(args);
239-
fieldDefinition.getInputValueDefinitions().addAll(inputValueDefinitions);
240-
result.add(fieldDefinition);
241+
fieldDefinition.inputValueDefinitions(inputValueDefinitions);
242+
result.add(fieldDefinition.build());
241243
}
242244
return result;
243245
}
244246

245-
private void createDeprecatedDirective(Map<String, Object> field, List<Directive> directives) {
247+
private void createDeprecatedDirective(Map<String, Object> field, NodeDirectivesBuilder nodeDirectivesBuilder) {
248+
List<Directive> directives = new ArrayList<>();
246249
if ((Boolean) field.get("isDeprecated")) {
247250
String reason = (String) field.get("deprecationReason");
248251
if (reason == null) {
249252
reason = "No longer supported"; // default according to spec
250253
}
251-
Argument reasonArg = new Argument("reason", new StringValue(reason));
252-
Directive deprecated = new Directive("deprecated", Collections.singletonList(reasonArg));
254+
Argument reasonArg = Argument.newArgument().name("reason").value(StringValue.newStringValue().value(reason).build()).build();
255+
Directive deprecated = Directive.newDirective().name("deprecated").arguments(Collections.singletonList(reasonArg)).build();
253256
directives.add(deprecated);
254257
}
258+
nodeDirectivesBuilder.directives(directives);
255259
}
256260

257261
@SuppressWarnings("unchecked")
258262
private List<InputValueDefinition> createInputValueDefinitions(List<Map<String, Object>> args) {
259263
List<InputValueDefinition> result = new ArrayList<>();
260264
for (Map<String, Object> arg : args) {
261265
Type argType = createTypeIndirection((Map<String, Object>) arg.get("type"));
262-
InputValueDefinition inputValueDefinition = new InputValueDefinition((String) arg.get("name"), argType);
263-
inputValueDefinition.setComments(toComment((String) arg.get("description")));
266+
InputValueDefinition.Builder inputValueDefinition = InputValueDefinition.newInputValueDefinition().name((String) arg.get("name")).type(argType);
267+
inputValueDefinition.comments(toComment((String) arg.get("description")));
264268

265269
String valueLiteral = (String) arg.get("defaultValue");
266270
if (valueLiteral != null) {
267271
Value defaultValue = AstValueHelper.valueFromAst(valueLiteral);
268-
inputValueDefinition.setDefaultValue(defaultValue);
272+
inputValueDefinition.defaultValue(defaultValue);
269273
}
270-
result.add(inputValueDefinition);
274+
result.add(inputValueDefinition.build());
271275
}
272276
return result;
273277
}
@@ -282,11 +286,11 @@ private Type createTypeIndirection(Map<String, Object> type) {
282286
case "ENUM":
283287
case "INPUT_OBJECT":
284288
case "SCALAR":
285-
return new TypeName((String) type.get("name"));
289+
return TypeName.newTypeName().name((String) type.get("name")).build();
286290
case "NON_NULL":
287-
return new NonNullType(createTypeIndirection((Map<String, Object>) type.get("ofType")));
291+
return NonNullType.newNonNullType().type(createTypeIndirection((Map<String, Object>) type.get("ofType"))).build();
288292
case "LIST":
289-
return new ListType(createTypeIndirection((Map<String, Object>) type.get("ofType")));
293+
return ListType.newListType().type(createTypeIndirection((Map<String, Object>) type.get("ofType"))).build();
290294
default:
291295
return assertShouldNeverHappen("Unknown kind %s", kind);
292296
}

src/main/java/graphql/language/AbstractNode.java

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
11
package graphql.language;
22

33

4-
import java.util.Collections;
4+
import graphql.Assert;
5+
import graphql.PublicApi;
6+
7+
import java.util.ArrayList;
58
import java.util.List;
69
import java.util.stream.Collectors;
710

8-
import static graphql.Assert.assertNotNull;
9-
11+
@PublicApi
1012
public abstract class AbstractNode<T extends Node> implements Node<T> {
1113

12-
private SourceLocation sourceLocation;
13-
private List<Comment> comments = Collections.emptyList();
14+
private final SourceLocation sourceLocation;
15+
private final List<Comment> comments;
1416

15-
16-
public void setSourceLocation(SourceLocation sourceLocation) {
17+
public AbstractNode(SourceLocation sourceLocation, List<Comment> comments) {
1718
this.sourceLocation = sourceLocation;
19+
Assert.assertNotNull(comments, "comments can't be null");
20+
this.comments = new ArrayList<>(comments);
1821
}
1922

2023
@Override
@@ -24,13 +27,9 @@ public SourceLocation getSourceLocation() {
2427

2528
@Override
2629
public List<Comment> getComments() {
27-
return comments;
30+
return new ArrayList<>(comments);
2831
}
2932

30-
public void setComments(List<Comment> comments) {
31-
assertNotNull(comments, "You must provide non null comments");
32-
this.comments = comments;
33-
}
3433

3534
@SuppressWarnings("unchecked")
3635
protected <V extends Node> V deepCopy(V nullableObj) {

src/main/java/graphql/language/Argument.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
11
package graphql.language;
22

33

4+
import graphql.PublicApi;
45
import graphql.util.TraversalControl;
56
import graphql.util.TraverserContext;
67

78
import java.util.ArrayList;
89
import java.util.Collections;
910
import java.util.List;
1011

12+
@PublicApi
1113
public class Argument extends AbstractNode<Argument> implements NamedNode<Argument> {
1214

1315
private final String name;
1416
private final Value value;
1517

16-
public Argument(String name, Value value) {
18+
private Argument(String name, Value value, SourceLocation sourceLocation, List<Comment> comments) {
19+
super(sourceLocation, comments);
1720
this.name = name;
1821
this.value = value;
1922
}
@@ -48,7 +51,7 @@ public boolean isEqualTo(Node o) {
4851

4952
@Override
5053
public Argument deepCopy() {
51-
return new Argument(name, deepCopy(value));
54+
return new Argument(name, deepCopy(value), getSourceLocation(), getComments());
5255
}
5356

5457
@Override
@@ -99,9 +102,7 @@ public Builder comments(List<Comment> comments) {
99102
}
100103

101104
public Argument build() {
102-
Argument argument = new Argument(name, value);
103-
argument.setSourceLocation(sourceLocation);
104-
argument.setComments(comments);
105+
Argument argument = new Argument(name, value, sourceLocation, comments);
105106
return argument;
106107
}
107108
}

0 commit comments

Comments
 (0)