From dcc6a93a27f71d28c4d82b9cd67efa0537394f8c Mon Sep 17 00:00:00 2001 From: bbaker Date: Sat, 28 Jun 2025 16:47:55 +1000 Subject: [PATCH] A more memory efficient directives container --- .../graphql/language/DirectivesContainer.java | 14 ++----- .../graphql/language/EnumTypeDefinition.java | 27 ++++++++++--- .../graphql/language/EnumValueDefinition.java | 28 +++++++++---- src/main/java/graphql/language/Field.java | 27 ++++++++++--- .../graphql/language/FieldDefinition.java | 27 ++++++++++--- .../graphql/language/FragmentDefinition.java | 26 ++++++++++--- .../java/graphql/language/FragmentSpread.java | 27 ++++++++++--- .../java/graphql/language/InlineFragment.java | 28 ++++++++++--- .../language/InputObjectTypeDefinition.java | 27 ++++++++++--- .../language/InputValueDefinition.java | 28 ++++++++++--- .../language/InterfaceTypeDefinition.java | 27 ++++++++++--- src/main/java/graphql/language/NodeUtil.java | 39 +++++++++++++++++++ .../language/ObjectTypeDefinition.java | 28 +++++++++---- .../graphql/language/OperationDefinition.java | 29 +++++++++++--- .../language/ScalarTypeDefinition.java | 27 ++++++++++--- .../graphql/language/SchemaDefinition.java | 28 ++++++++++--- .../graphql/language/UnionTypeDefinition.java | 27 ++++++++++--- .../graphql/language/VariableDefinition.java | 27 ++++++++++--- 18 files changed, 383 insertions(+), 108 deletions(-) diff --git a/src/main/java/graphql/language/DirectivesContainer.java b/src/main/java/graphql/language/DirectivesContainer.java index 3acd7f55b7..b4058f6ff8 100644 --- a/src/main/java/graphql/language/DirectivesContainer.java +++ b/src/main/java/graphql/language/DirectivesContainer.java @@ -34,20 +34,16 @@ public interface DirectivesContainer extends Node * * @return a map of all directives by directive name */ - default Map> getDirectivesByName() { - return ImmutableMap.copyOf(allDirectivesByName(getDirectives())); - } + Map> getDirectivesByName(); /** - * Returns all of the directives with the provided name, including repeatable and non repeatable directives. + * Returns all the directives with the provided name, including repeatable and non repeatable directives. * * @param directiveName the name of the directives to retrieve * * @return the directives or empty list if there is not one with that name */ - default List getDirectives(String directiveName) { - return getDirectivesByName().getOrDefault(directiveName, emptyList()); - } + List getDirectives(String directiveName); /** * This returns true if the AST node contains one or more directives by the specified name @@ -56,7 +52,5 @@ default List getDirectives(String directiveName) { * * @return true if the AST node contains one or more directives by the specified name */ - default boolean hasDirective(String directiveName) { - return !getDirectives(directiveName).isEmpty(); - } + boolean hasDirective(String directiveName); } diff --git a/src/main/java/graphql/language/EnumTypeDefinition.java b/src/main/java/graphql/language/EnumTypeDefinition.java index 243e20acaf..51bad7b12a 100644 --- a/src/main/java/graphql/language/EnumTypeDefinition.java +++ b/src/main/java/graphql/language/EnumTypeDefinition.java @@ -23,7 +23,7 @@ public class EnumTypeDefinition extends AbstractDescribedNode implements TypeDefinition, DirectivesContainer, NamedNode { private final String name; private final ImmutableList enumValueDefinitions; - private final ImmutableList directives; + private final NodeUtil.DirectivesHolder directives; public static final String CHILD_ENUM_VALUE_DEFINITIONS = "enumValueDefinitions"; public static final String CHILD_DIRECTIVES = "directives"; @@ -38,7 +38,7 @@ protected EnumTypeDefinition(String name, IgnoredChars ignoredChars, Map additionalData) { super(sourceLocation, comments, ignoredChars, additionalData, description); this.name = name; - this.directives = ImmutableKit.nonNullCopyOf(directives); + this.directives = NodeUtil.DirectivesHolder.of(directives); this.enumValueDefinitions = ImmutableKit.nonNullCopyOf(enumValueDefinitions); } @@ -57,7 +57,22 @@ public List getEnumValueDefinitions() { @Override public List getDirectives() { - return directives; + return directives.getDirectives(); + } + + @Override + public Map> getDirectivesByName() { + return directives.getDirectivesByName(); + } + + @Override + public List getDirectives(String directiveName) { + return directives.getDirectives(directiveName); + } + + @Override + public boolean hasDirective(String directiveName) { + return directives.hasDirective(directiveName); } @Override @@ -69,7 +84,7 @@ public String getName() { public List getChildren() { List result = new ArrayList<>(); result.addAll(enumValueDefinitions); - result.addAll(directives); + result.addAll(directives.getDirectives()); return result; } @@ -77,7 +92,7 @@ public List getChildren() { public NodeChildrenContainer getNamedChildren() { return newNodeChildrenContainer() .children(CHILD_ENUM_VALUE_DEFINITIONS, enumValueDefinitions) - .children(CHILD_DIRECTIVES, directives) + .children(CHILD_DIRECTIVES, directives.getDirectives()) .build(); } @@ -107,7 +122,7 @@ public boolean isEqualTo(Node o) { public EnumTypeDefinition deepCopy() { return new EnumTypeDefinition(name, deepCopy(enumValueDefinitions), - deepCopy(directives), + deepCopy(directives.getDirectives()), description, getSourceLocation(), getComments(), diff --git a/src/main/java/graphql/language/EnumValueDefinition.java b/src/main/java/graphql/language/EnumValueDefinition.java index 2a7ef13f10..5e28ae87f9 100644 --- a/src/main/java/graphql/language/EnumValueDefinition.java +++ b/src/main/java/graphql/language/EnumValueDefinition.java @@ -17,13 +17,12 @@ import static graphql.Assert.assertNotNull; import static graphql.collect.ImmutableKit.emptyList; import static graphql.collect.ImmutableKit.emptyMap; -import static graphql.collect.ImmutableKit.nonNullCopyOf; import static graphql.language.NodeChildrenContainer.newNodeChildrenContainer; @PublicApi public class EnumValueDefinition extends AbstractDescribedNode implements DirectivesContainer, NamedNode { private final String name; - private final ImmutableList directives; + private final NodeUtil.DirectivesHolder directives; public static final String CHILD_DIRECTIVES = "directives"; @@ -36,7 +35,7 @@ protected EnumValueDefinition(String name, IgnoredChars ignoredChars, Map additionalData) { super(sourceLocation, comments, ignoredChars, additionalData, description); this.name = name; - this.directives = nonNullCopyOf(directives); + this.directives = NodeUtil.DirectivesHolder.of(directives); } /** @@ -65,18 +64,33 @@ public String getName() { @Override public List getDirectives() { - return directives; + return directives.getDirectives(); + } + + @Override + public Map> getDirectivesByName() { + return directives.getDirectivesByName(); + } + + @Override + public List getDirectives(String directiveName) { + return directives.getDirectives(directiveName); + } + + @Override + public boolean hasDirective(String directiveName) { + return directives.hasDirective(directiveName); } @Override public List getChildren() { - return ImmutableList.copyOf(directives); + return ImmutableList.copyOf(directives.getDirectives()); } @Override public NodeChildrenContainer getNamedChildren() { return newNodeChildrenContainer() - .children(CHILD_DIRECTIVES, directives) + .children(CHILD_DIRECTIVES, directives.getDirectives()) .build(); } @@ -104,7 +118,7 @@ public boolean isEqualTo(Node o) { @Override public EnumValueDefinition deepCopy() { - return new EnumValueDefinition(name, deepCopy(directives), description, getSourceLocation(), getComments(), getIgnoredChars(), getAdditionalData()); + return new EnumValueDefinition(name, deepCopy(directives.getDirectives()), description, getSourceLocation(), getComments(), getIgnoredChars(), getAdditionalData()); } @Override diff --git a/src/main/java/graphql/language/Field.java b/src/main/java/graphql/language/Field.java index b4b0bcd97a..45f9103f3d 100644 --- a/src/main/java/graphql/language/Field.java +++ b/src/main/java/graphql/language/Field.java @@ -32,7 +32,7 @@ public class Field extends AbstractNode implements Selection, Sele private final String name; private final String alias; private final ImmutableList arguments; - private final ImmutableList directives; + private final NodeUtil.DirectivesHolder directives; private final SelectionSet selectionSet; public static final String CHILD_ARGUMENTS = "arguments"; @@ -54,7 +54,7 @@ protected Field(String name, this.name = name == null ? null : Interning.intern(name); this.alias = alias; this.arguments = ImmutableList.copyOf(arguments); - this.directives = ImmutableList.copyOf(directives); + this.directives = NodeUtil.DirectivesHolder.of(directives); this.selectionSet = selectionSet; } @@ -103,7 +103,7 @@ public Field(String name, SelectionSet selectionSet) { public List getChildren() { List result = new ArrayList<>(); result.addAll(arguments); - result.addAll(directives); + result.addAll(directives.getDirectives()); if (selectionSet != null) { result.add(selectionSet); } @@ -114,7 +114,7 @@ public List getChildren() { public NodeChildrenContainer getNamedChildren() { return NodeChildrenContainer.newNodeChildrenContainer() .children(CHILD_ARGUMENTS, arguments) - .children(CHILD_DIRECTIVES, directives) + .children(CHILD_DIRECTIVES, directives.getDirectives()) .child(CHILD_SELECTION_SET, selectionSet) .build(); } @@ -147,7 +147,22 @@ public List getArguments() { @Override public List getDirectives() { - return directives; + return directives.getDirectives(); + } + + @Override + public Map> getDirectivesByName() { + return directives.getDirectivesByName(); + } + + @Override + public List getDirectives(String directiveName) { + return directives.getDirectives(directiveName); + } + + @Override + public boolean hasDirective(String directiveName) { + return directives.hasDirective(directiveName); } @Override @@ -175,7 +190,7 @@ public Field deepCopy() { return new Field(name, alias, deepCopy(arguments), - deepCopy(directives), + deepCopy(directives.getDirectives()), deepCopy(selectionSet), getSourceLocation(), getComments(), diff --git a/src/main/java/graphql/language/FieldDefinition.java b/src/main/java/graphql/language/FieldDefinition.java index 52d5b97da9..5fc03257aa 100644 --- a/src/main/java/graphql/language/FieldDefinition.java +++ b/src/main/java/graphql/language/FieldDefinition.java @@ -25,7 +25,7 @@ public class FieldDefinition extends AbstractDescribedNode impl private final String name; private final Type type; private final ImmutableList inputValueDefinitions; - private final ImmutableList directives; + private final NodeUtil.DirectivesHolder directives; public static final String CHILD_TYPE = "type"; public static final String CHILD_INPUT_VALUE_DEFINITION = "inputValueDefinition"; @@ -45,7 +45,7 @@ protected FieldDefinition(String name, this.name = name; this.type = type; this.inputValueDefinitions = ImmutableList.copyOf(inputValueDefinitions); - this.directives = ImmutableList.copyOf(directives); + this.directives = NodeUtil.DirectivesHolder.of(directives); } public FieldDefinition(String name, @@ -68,7 +68,22 @@ public List getInputValueDefinitions() { @Override public List getDirectives() { - return directives; + return directives.getDirectives(); + } + + @Override + public Map> getDirectivesByName() { + return directives.getDirectivesByName(); + } + + @Override + public List getDirectives(String directiveName) { + return directives.getDirectives(directiveName); + } + + @Override + public boolean hasDirective(String directiveName) { + return directives.hasDirective(directiveName); } @Override @@ -76,7 +91,7 @@ public List getChildren() { List result = new ArrayList<>(); result.add(type); result.addAll(inputValueDefinitions); - result.addAll(directives); + result.addAll(directives.getDirectives()); return result; } @@ -85,7 +100,7 @@ public NodeChildrenContainer getNamedChildren() { return newNodeChildrenContainer() .child(CHILD_TYPE, type) .children(CHILD_INPUT_VALUE_DEFINITION, inputValueDefinitions) - .children(CHILD_DIRECTIVES, directives) + .children(CHILD_DIRECTIVES, directives.getDirectives()) .build(); } @@ -117,7 +132,7 @@ public FieldDefinition deepCopy() { return new FieldDefinition(name, deepCopy(type), deepCopy(inputValueDefinitions), - deepCopy(directives), + deepCopy(directives.getDirectives()), description, getSourceLocation(), getComments(), diff --git a/src/main/java/graphql/language/FragmentDefinition.java b/src/main/java/graphql/language/FragmentDefinition.java index 10ec71d237..3913959607 100644 --- a/src/main/java/graphql/language/FragmentDefinition.java +++ b/src/main/java/graphql/language/FragmentDefinition.java @@ -27,7 +27,7 @@ public class FragmentDefinition extends AbstractNode impleme private final String name; private final TypeName typeCondition; - private final ImmutableList directives; + private final NodeUtil.DirectivesHolder directives; private final SelectionSet selectionSet; public static final String CHILD_TYPE_CONDITION = "typeCondition"; @@ -46,7 +46,7 @@ protected FragmentDefinition(String name, super(sourceLocation, comments, ignoredChars, additionalData); this.name = name; this.typeCondition = typeCondition; - this.directives = ImmutableList.copyOf(directives); + this.directives = NodeUtil.DirectivesHolder.of(directives); this.selectionSet = selectionSet; } @@ -62,9 +62,23 @@ public TypeName getTypeCondition() { @Override public List getDirectives() { - return directives; + return directives.getDirectives(); } + @Override + public Map> getDirectivesByName() { + return directives.getDirectivesByName(); + } + + @Override + public List getDirectives(String directiveName) { + return directives.getDirectives(directiveName); + } + + @Override + public boolean hasDirective(String directiveName) { + return directives.hasDirective(directiveName); + } @Override public SelectionSet getSelectionSet() { @@ -75,7 +89,7 @@ public SelectionSet getSelectionSet() { public List getChildren() { List result = new ArrayList<>(); result.add(typeCondition); - result.addAll(directives); + result.addAll(directives.getDirectives()); result.add(selectionSet); return result; } @@ -84,7 +98,7 @@ public List getChildren() { public NodeChildrenContainer getNamedChildren() { return newNodeChildrenContainer() .child(CHILD_TYPE_CONDITION, typeCondition) - .children(CHILD_DIRECTIVES, directives) + .children(CHILD_DIRECTIVES, directives.getDirectives()) .child(CHILD_SELECTION_SET, selectionSet) .build(); } @@ -116,7 +130,7 @@ public boolean isEqualTo(Node o) { public FragmentDefinition deepCopy() { return new FragmentDefinition(name, deepCopy(typeCondition), - deepCopy(directives), + deepCopy(directives.getDirectives()), deepCopy(selectionSet), getSourceLocation(), getComments(), diff --git a/src/main/java/graphql/language/FragmentSpread.java b/src/main/java/graphql/language/FragmentSpread.java index 421ba135cb..36575b36ed 100644 --- a/src/main/java/graphql/language/FragmentSpread.java +++ b/src/main/java/graphql/language/FragmentSpread.java @@ -23,7 +23,7 @@ public class FragmentSpread extends AbstractNode implements Selection, DirectivesContainer, NamedNode { private final String name; - private final ImmutableList directives; + private final NodeUtil.DirectivesHolder directives; public static final String CHILD_DIRECTIVES = "directives"; @@ -31,7 +31,7 @@ public class FragmentSpread extends AbstractNode implements Sele protected FragmentSpread(String name, List directives, SourceLocation sourceLocation, List comments, IgnoredChars ignoredChars, Map additionalData) { super(sourceLocation, comments, ignoredChars, additionalData); this.name = name; - this.directives = ImmutableList.copyOf(directives); + this.directives = NodeUtil.DirectivesHolder.of(directives); } /** @@ -50,7 +50,22 @@ public String getName() { @Override public List getDirectives() { - return directives; + return directives.getDirectives(); + } + + @Override + public Map> getDirectivesByName() { + return directives.getDirectivesByName(); + } + + @Override + public List getDirectives(String directiveName) { + return directives.getDirectives(directiveName); + } + + @Override + public boolean hasDirective(String directiveName) { + return directives.hasDirective(directiveName); } @Override @@ -70,13 +85,13 @@ public boolean isEqualTo(Node o) { @Override public List getChildren() { - return ImmutableList.copyOf(directives); + return ImmutableList.copyOf(directives.getDirectives()); } @Override public NodeChildrenContainer getNamedChildren() { return newNodeChildrenContainer() - .children(CHILD_DIRECTIVES, directives) + .children(CHILD_DIRECTIVES, directives.getDirectives()) .build(); } @@ -89,7 +104,7 @@ public FragmentSpread withNewChildren(NodeChildrenContainer newChildren) { @Override public FragmentSpread deepCopy() { - return new FragmentSpread(name, deepCopy(directives), getSourceLocation(), getComments(), getIgnoredChars(), getAdditionalData()); + return new FragmentSpread(name, deepCopy(directives.getDirectives()), getSourceLocation(), getComments(), getIgnoredChars(), getAdditionalData()); } @Override diff --git a/src/main/java/graphql/language/InlineFragment.java b/src/main/java/graphql/language/InlineFragment.java index df17229a6e..b065a5b8df 100644 --- a/src/main/java/graphql/language/InlineFragment.java +++ b/src/main/java/graphql/language/InlineFragment.java @@ -22,7 +22,7 @@ @PublicApi public class InlineFragment extends AbstractNode implements Selection, SelectionSetContainer, DirectivesContainer { private final TypeName typeCondition; - private final ImmutableList directives; + private final NodeUtil.DirectivesHolder directives; private final SelectionSet selectionSet; public static final String CHILD_TYPE_CONDITION = "typeCondition"; @@ -39,7 +39,7 @@ protected InlineFragment(TypeName typeCondition, Map additionalData) { super(sourceLocation, comments, ignoredChars, additionalData); this.typeCondition = typeCondition; - this.directives = ImmutableList.copyOf(directives); + this.directives = NodeUtil.DirectivesHolder.of(directives); this.selectionSet = selectionSet; } @@ -66,8 +66,24 @@ public TypeName getTypeCondition() { return typeCondition; } + @Override public List getDirectives() { - return directives; + return directives.getDirectives(); + } + + @Override + public Map> getDirectivesByName() { + return directives.getDirectivesByName(); + } + + @Override + public List getDirectives(String directiveName) { + return directives.getDirectives(directiveName); + } + + @Override + public boolean hasDirective(String directiveName) { + return directives.hasDirective(directiveName); } @Override @@ -81,7 +97,7 @@ public List getChildren() { if (typeCondition != null) { result.add(typeCondition); } - result.addAll(directives); + result.addAll(directives.getDirectives()); result.add(selectionSet); return result; } @@ -90,7 +106,7 @@ public List getChildren() { public NodeChildrenContainer getNamedChildren() { return newNodeChildrenContainer() .child(CHILD_TYPE_CONDITION, typeCondition) - .children(CHILD_DIRECTIVES, directives) + .children(CHILD_DIRECTIVES, directives.getDirectives()) .child(CHILD_SELECTION_SET, selectionSet) .build(); } @@ -116,7 +132,7 @@ public boolean isEqualTo(Node o) { public InlineFragment deepCopy() { return new InlineFragment( deepCopy(typeCondition), - deepCopy(directives), + deepCopy(directives.getDirectives()), deepCopy(selectionSet), getSourceLocation(), getComments(), diff --git a/src/main/java/graphql/language/InputObjectTypeDefinition.java b/src/main/java/graphql/language/InputObjectTypeDefinition.java index 127d7da308..c2f414404d 100644 --- a/src/main/java/graphql/language/InputObjectTypeDefinition.java +++ b/src/main/java/graphql/language/InputObjectTypeDefinition.java @@ -23,7 +23,7 @@ public class InputObjectTypeDefinition extends AbstractDescribedNode implements TypeDefinition, DirectivesContainer, NamedNode { private final String name; - private final ImmutableList directives; + private final NodeUtil.DirectivesHolder directives; private final ImmutableList inputValueDefinitions; public static final String CHILD_DIRECTIVES = "directives"; @@ -40,13 +40,28 @@ protected InputObjectTypeDefinition(String name, Map additionalData) { super(sourceLocation, comments, ignoredChars, additionalData, description); this.name = name; - this.directives = ImmutableList.copyOf(directives); + this.directives = NodeUtil.DirectivesHolder.of(directives); this.inputValueDefinitions = ImmutableList.copyOf(inputValueDefinitions); } @Override public List getDirectives() { - return directives; + return directives.getDirectives(); + } + + @Override + public Map> getDirectivesByName() { + return directives.getDirectivesByName(); + } + + @Override + public List getDirectives(String directiveName) { + return directives.getDirectives(directiveName); + } + + @Override + public boolean hasDirective(String directiveName) { + return directives.hasDirective(directiveName); } public List getInputValueDefinitions() { @@ -61,7 +76,7 @@ public String getName() { @Override public List getChildren() { List result = new ArrayList<>(); - result.addAll(directives); + result.addAll(directives.getDirectives()); result.addAll(inputValueDefinitions); return result; } @@ -69,7 +84,7 @@ public List getChildren() { @Override public NodeChildrenContainer getNamedChildren() { return newNodeChildrenContainer() - .children(CHILD_DIRECTIVES, directives) + .children(CHILD_DIRECTIVES, directives.getDirectives()) .children(CHILD_INPUT_VALUES_DEFINITIONS, inputValueDefinitions) .build(); } @@ -99,7 +114,7 @@ public boolean isEqualTo(Node o) { @Override public InputObjectTypeDefinition deepCopy() { return new InputObjectTypeDefinition(name, - deepCopy(directives), + deepCopy(directives.getDirectives()), deepCopy(inputValueDefinitions), description, getSourceLocation(), diff --git a/src/main/java/graphql/language/InputValueDefinition.java b/src/main/java/graphql/language/InputValueDefinition.java index 6250a1c41b..c0db3318fa 100644 --- a/src/main/java/graphql/language/InputValueDefinition.java +++ b/src/main/java/graphql/language/InputValueDefinition.java @@ -25,7 +25,7 @@ public class InputValueDefinition extends AbstractDescribedNode directives; + private final NodeUtil.DirectivesHolder directives; public static final String CHILD_TYPE = "type"; public static final String CHILD_DEFAULT_VALUE = "defaultValue"; @@ -45,7 +45,7 @@ protected InputValueDefinition(String name, this.name = name; this.type = type; this.defaultValue = defaultValue; - this.directives = ImmutableList.copyOf(directives); + this.directives = NodeUtil.DirectivesHolder.of(directives); } /** @@ -88,8 +88,24 @@ public Value getDefaultValue() { return defaultValue; } + @Override public List getDirectives() { - return directives; + return directives.getDirectives(); + } + + @Override + public Map> getDirectivesByName() { + return directives.getDirectivesByName(); + } + + @Override + public List getDirectives(String directiveName) { + return directives.getDirectives(directiveName); + } + + @Override + public boolean hasDirective(String directiveName) { + return directives.hasDirective(directiveName); } @Override @@ -99,7 +115,7 @@ public List getChildren() { if (defaultValue != null) { result.add(defaultValue); } - result.addAll(directives); + result.addAll(directives.getDirectives()); return result; } @@ -108,7 +124,7 @@ public NodeChildrenContainer getNamedChildren() { return newNodeChildrenContainer() .child(CHILD_TYPE, type) .child(CHILD_DEFAULT_VALUE, defaultValue) - .children(CHILD_DIRECTIVES, directives) + .children(CHILD_DIRECTIVES, directives.getDirectives()) .build(); } @@ -141,7 +157,7 @@ public InputValueDefinition deepCopy() { return new InputValueDefinition(name, deepCopy(type), deepCopy(defaultValue), - deepCopy(directives), + deepCopy(directives.getDirectives()), description, getSourceLocation(), getComments(), diff --git a/src/main/java/graphql/language/InterfaceTypeDefinition.java b/src/main/java/graphql/language/InterfaceTypeDefinition.java index c86c0fa486..3fd1343f89 100644 --- a/src/main/java/graphql/language/InterfaceTypeDefinition.java +++ b/src/main/java/graphql/language/InterfaceTypeDefinition.java @@ -26,7 +26,7 @@ public class InterfaceTypeDefinition extends AbstractDescribedNode implementz; private final ImmutableList definitions; - private final ImmutableList directives; + private final NodeUtil.DirectivesHolder directives; public static final String CHILD_IMPLEMENTZ = "implementz"; public static final String CHILD_DEFINITIONS = "definitions"; @@ -46,7 +46,7 @@ protected InterfaceTypeDefinition(String name, this.name = name; this.implementz = ImmutableList.copyOf(implementz); this.definitions = ImmutableList.copyOf(definitions); - this.directives = ImmutableList.copyOf(directives); + this.directives = NodeUtil.DirectivesHolder.of(directives); } /** @@ -70,7 +70,22 @@ public List getFieldDefinitions() { @Override public List getDirectives() { - return directives; + return directives.getDirectives(); + } + + @Override + public Map> getDirectivesByName() { + return directives.getDirectivesByName(); + } + + @Override + public List getDirectives(String directiveName) { + return directives.getDirectives(directiveName); + } + + @Override + public boolean hasDirective(String directiveName) { + return directives.hasDirective(directiveName); } @Override @@ -83,7 +98,7 @@ public List getChildren() { List result = new ArrayList<>(); result.addAll(implementz); result.addAll(definitions); - result.addAll(directives); + result.addAll(directives.getDirectives()); return result; } @@ -92,7 +107,7 @@ public NodeChildrenContainer getNamedChildren() { return newNodeChildrenContainer() .children(CHILD_IMPLEMENTZ, implementz) .children(CHILD_DEFINITIONS, definitions) - .children(CHILD_DIRECTIVES, directives) + .children(CHILD_DIRECTIVES, directives.getDirectives()) .build(); } @@ -124,7 +139,7 @@ public InterfaceTypeDefinition deepCopy() { return new InterfaceTypeDefinition(name, deepCopy(implementz), deepCopy(definitions), - deepCopy(directives), + deepCopy(directives.getDirectives()), description, getSourceLocation(), getComments(), diff --git a/src/main/java/graphql/language/NodeUtil.java b/src/main/java/graphql/language/NodeUtil.java index ebb8b2253c..71ccc46ca9 100644 --- a/src/main/java/graphql/language/NodeUtil.java +++ b/src/main/java/graphql/language/NodeUtil.java @@ -1,17 +1,20 @@ package graphql.language; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import graphql.Internal; import graphql.execution.UnknownOperationException; import graphql.util.FpKit; import graphql.util.NodeLocation; +import java.io.Serializable; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; import static graphql.util.FpKit.mergeFirst; +import static java.util.Objects.requireNonNull; /** * Helper class for working with {@link Node}s @@ -100,4 +103,40 @@ public static Node removeChild(Node node, NodeLocation childLocationToRemove) { NodeChildrenContainer newChildren = namedChildren.transform(builder -> builder.removeChild(childLocationToRemove.getName(), childLocationToRemove.getIndex())); return node.withNewChildren(newChildren); } + + + /** + * A simple directives holder that makes it easier for {@link DirectivesContainer} classes + * to have their methods AND be efficient via immutable structures + */ + @Internal + static class DirectivesHolder implements Serializable { + private final ImmutableList directives; + private final ImmutableMap> directivesByName; + + static DirectivesHolder of(List directives) { + return new DirectivesHolder(directives); + } + + DirectivesHolder(List directives) { + this.directives = ImmutableList.copyOf(directives); + directivesByName = ImmutableMap.copyOf(allDirectivesByName(directives)); + } + + ImmutableList getDirectives() { + return directives; + } + + ImmutableMap> getDirectivesByName() { + return directivesByName; + } + + ImmutableList getDirectives(String directiveName) { + return ImmutableList.copyOf(requireNonNull(directivesByName.getOrDefault(directiveName, ImmutableList.of()))); + } + + boolean hasDirective(String directiveName) { + return directivesByName.containsKey(directiveName); + } + } } diff --git a/src/main/java/graphql/language/ObjectTypeDefinition.java b/src/main/java/graphql/language/ObjectTypeDefinition.java index d24a970c08..fca017594e 100644 --- a/src/main/java/graphql/language/ObjectTypeDefinition.java +++ b/src/main/java/graphql/language/ObjectTypeDefinition.java @@ -24,7 +24,7 @@ public class ObjectTypeDefinition extends AbstractDescribedNode implements ImplementingTypeDefinition, DirectivesContainer, NamedNode { private final String name; private final ImmutableList implementz; - private final ImmutableList directives; + private final NodeUtil.DirectivesHolder directives; private final ImmutableList fieldDefinitions; public static final String CHILD_IMPLEMENTZ = "implementz"; @@ -44,7 +44,7 @@ protected ObjectTypeDefinition(String name, super(sourceLocation, comments, ignoredChars, additionalData, description); this.name = name; this.implementz = ImmutableList.copyOf(implementz); - this.directives = ImmutableList.copyOf(directives); + this.directives = NodeUtil.DirectivesHolder.of(directives); this.fieldDefinitions = ImmutableList.copyOf(fieldDefinitions); } @@ -62,9 +62,23 @@ public List getImplements() { return implementz; } - @Override public List getDirectives() { - return directives; + return directives.getDirectives(); + } + + @Override + public Map> getDirectivesByName() { + return directives.getDirectivesByName(); + } + + @Override + public List getDirectives(String directiveName) { + return directives.getDirectives(directiveName); + } + + @Override + public boolean hasDirective(String directiveName) { + return directives.hasDirective(directiveName); } @Override @@ -81,7 +95,7 @@ public String getName() { public List getChildren() { List result = new ArrayList<>(); result.addAll(implementz); - result.addAll(directives); + result.addAll(directives.getDirectives()); result.addAll(fieldDefinitions); return result; } @@ -90,7 +104,7 @@ public List getChildren() { public NodeChildrenContainer getNamedChildren() { return newNodeChildrenContainer() .children(CHILD_IMPLEMENTZ, implementz) - .children(CHILD_DIRECTIVES, directives) + .children(CHILD_DIRECTIVES, directives.getDirectives()) .children(CHILD_FIELD_DEFINITIONS, fieldDefinitions) .build(); } @@ -120,7 +134,7 @@ public boolean isEqualTo(Node o) { public ObjectTypeDefinition deepCopy() { return new ObjectTypeDefinition(name, deepCopy(implementz), - deepCopy(directives), + deepCopy(directives.getDirectives()), deepCopy(fieldDefinitions), description, getSourceLocation(), diff --git a/src/main/java/graphql/language/OperationDefinition.java b/src/main/java/graphql/language/OperationDefinition.java index b60aac3a11..824180bb49 100644 --- a/src/main/java/graphql/language/OperationDefinition.java +++ b/src/main/java/graphql/language/OperationDefinition.java @@ -5,6 +5,7 @@ import graphql.Internal; import graphql.PublicApi; import graphql.collect.ImmutableKit; +import graphql.language.NodeUtil.DirectivesHolder; import graphql.util.TraversalControl; import graphql.util.TraverserContext; @@ -31,7 +32,7 @@ public enum Operation { private final Operation operation; private final ImmutableList variableDefinitions; - private final ImmutableList directives; + private final DirectivesHolder directives; private final SelectionSet selectionSet; public static final String CHILD_VARIABLE_DEFINITIONS = "variableDefinitions"; @@ -52,7 +53,7 @@ protected OperationDefinition(String name, this.name = name; this.operation = operation; this.variableDefinitions = ImmutableList.copyOf(variableDefinitions); - this.directives = ImmutableList.copyOf(directives); + this.directives = DirectivesHolder.of(directives); this.selectionSet = selectionSet; } @@ -69,7 +70,7 @@ public OperationDefinition(String name) { public List getChildren() { List result = new ArrayList<>(); result.addAll(variableDefinitions); - result.addAll(directives); + result.addAll(directives.getDirectives()); result.add(selectionSet); return result; } @@ -78,7 +79,7 @@ public List getChildren() { public NodeChildrenContainer getNamedChildren() { return newNodeChildrenContainer() .children(CHILD_VARIABLE_DEFINITIONS, variableDefinitions) - .children(CHILD_DIRECTIVES, directives) + .children(CHILD_DIRECTIVES, directives.getDirectives()) .child(CHILD_SELECTION_SET, selectionSet) .build(); } @@ -105,7 +106,22 @@ public List getVariableDefinitions() { } public List getDirectives() { - return directives; + return directives.getDirectives(); + } + + @Override + public Map> getDirectivesByName() { + return directives.getDirectivesByName(); + } + + @Override + public List getDirectives(String directiveName) { + return directives.getDirectives(directiveName); + } + + @Override + public boolean hasDirective(String directiveName) { + return directives.hasDirective(directiveName); } @Override @@ -133,7 +149,7 @@ public OperationDefinition deepCopy() { return new OperationDefinition(name, operation, deepCopy(variableDefinitions), - deepCopy(directives), + deepCopy(directives.getDirectives()), deepCopy(selectionSet), getSourceLocation(), getComments(), @@ -234,6 +250,7 @@ public Builder directive(Directive directive) { this.directives = ImmutableKit.addToList(directives, directive); return this; } + public Builder selectionSet(SelectionSet selectionSet) { this.selectionSet = selectionSet; return this; diff --git a/src/main/java/graphql/language/ScalarTypeDefinition.java b/src/main/java/graphql/language/ScalarTypeDefinition.java index ac2d0f427f..3374b69dab 100644 --- a/src/main/java/graphql/language/ScalarTypeDefinition.java +++ b/src/main/java/graphql/language/ScalarTypeDefinition.java @@ -23,7 +23,7 @@ public class ScalarTypeDefinition extends AbstractDescribedNode implements TypeDefinition, DirectivesContainer, NamedNode { private final String name; - private final ImmutableList directives; + private final NodeUtil.DirectivesHolder directives; public static final String CHILD_DIRECTIVES = "directives"; @@ -37,7 +37,7 @@ protected ScalarTypeDefinition(String name, Map additionalData) { super(sourceLocation, comments, ignoredChars, additionalData, description); this.name = name; - this.directives = ImmutableList.copyOf(directives); + this.directives = NodeUtil.DirectivesHolder.of(directives); } /** @@ -51,7 +51,22 @@ public ScalarTypeDefinition(String name) { @Override public List getDirectives() { - return directives; + return directives.getDirectives(); + } + + @Override + public Map> getDirectivesByName() { + return directives.getDirectivesByName(); + } + + @Override + public List getDirectives(String directiveName) { + return directives.getDirectives(directiveName); + } + + @Override + public boolean hasDirective(String directiveName) { + return directives.hasDirective(directiveName); } @Override @@ -61,13 +76,13 @@ public String getName() { @Override public List getChildren() { - return ImmutableList.copyOf(directives); + return ImmutableList.copyOf(directives.getDirectives()); } @Override public NodeChildrenContainer getNamedChildren() { return newNodeChildrenContainer() - .children(CHILD_DIRECTIVES, directives) + .children(CHILD_DIRECTIVES, directives.getDirectives()) .build(); } @@ -94,7 +109,7 @@ public boolean isEqualTo(Node o) { @Override public ScalarTypeDefinition deepCopy() { - return new ScalarTypeDefinition(name, deepCopy(directives), description, getSourceLocation(), getComments(), getIgnoredChars(), getAdditionalData()); + return new ScalarTypeDefinition(name, deepCopy(directives.getDirectives()), description, getSourceLocation(), getComments(), getIgnoredChars(), getAdditionalData()); } @Override diff --git a/src/main/java/graphql/language/SchemaDefinition.java b/src/main/java/graphql/language/SchemaDefinition.java index 613a46bcca..666decc462 100644 --- a/src/main/java/graphql/language/SchemaDefinition.java +++ b/src/main/java/graphql/language/SchemaDefinition.java @@ -21,7 +21,7 @@ @PublicApi public class SchemaDefinition extends AbstractDescribedNode implements SDLDefinition, DirectivesContainer { - private final ImmutableList directives; + private final NodeUtil.DirectivesHolder directives; private final ImmutableList operationTypeDefinitions; public static final String CHILD_DIRECTIVES = "directives"; @@ -37,12 +37,28 @@ protected SchemaDefinition(List directives, Map additionalData, Description description) { super(sourceLocation, comments, ignoredChars, additionalData, description); - this.directives = ImmutableList.copyOf(directives); + this.directives = NodeUtil.DirectivesHolder.of(directives); this.operationTypeDefinitions = ImmutableList.copyOf(operationTypeDefinitions); } + @Override public List getDirectives() { - return directives; + return directives.getDirectives(); + } + + @Override + public Map> getDirectivesByName() { + return directives.getDirectivesByName(); + } + + @Override + public List getDirectives(String directiveName) { + return directives.getDirectives(directiveName); + } + + @Override + public boolean hasDirective(String directiveName) { + return directives.hasDirective(directiveName); } public List getOperationTypeDefinitions() { @@ -56,7 +72,7 @@ public Description getDescription() { @Override public List getChildren() { List result = new ArrayList<>(); - result.addAll(directives); + result.addAll(directives.getDirectives()); result.addAll(operationTypeDefinitions); return result; } @@ -64,7 +80,7 @@ public List getChildren() { @Override public NodeChildrenContainer getNamedChildren() { return newNodeChildrenContainer() - .children(CHILD_DIRECTIVES, directives) + .children(CHILD_DIRECTIVES, directives.getDirectives()) .children(CHILD_OPERATION_TYPE_DEFINITIONS, operationTypeDefinitions) .build(); } @@ -90,7 +106,7 @@ public boolean isEqualTo(Node o) { @Override public SchemaDefinition deepCopy() { - return new SchemaDefinition(deepCopy(directives), deepCopy(operationTypeDefinitions), getSourceLocation(), getComments(), + return new SchemaDefinition(deepCopy(directives.getDirectives()), deepCopy(operationTypeDefinitions), getSourceLocation(), getComments(), getIgnoredChars(), getAdditionalData(), description); } diff --git a/src/main/java/graphql/language/UnionTypeDefinition.java b/src/main/java/graphql/language/UnionTypeDefinition.java index 00f9e6fc90..c932c63908 100644 --- a/src/main/java/graphql/language/UnionTypeDefinition.java +++ b/src/main/java/graphql/language/UnionTypeDefinition.java @@ -24,7 +24,7 @@ public class UnionTypeDefinition extends AbstractDescribedNode implements TypeDefinition, DirectivesContainer, NamedNode { private final String name; - private final ImmutableList directives; + private final NodeUtil.DirectivesHolder directives; private final ImmutableList memberTypes; public static final String CHILD_DIRECTIVES = "directives"; @@ -40,7 +40,7 @@ protected UnionTypeDefinition(String name, IgnoredChars ignoredChars, Map additionalData) { super(sourceLocation, comments, ignoredChars, additionalData, description); this.name = name; - this.directives = ImmutableList.copyOf(directives); + this.directives = NodeUtil.DirectivesHolder.of(directives); this.memberTypes = ImmutableList.copyOf(memberTypes); } @@ -66,7 +66,22 @@ public UnionTypeDefinition(String name) { @Override public List getDirectives() { - return directives; + return directives.getDirectives(); + } + + @Override + public Map> getDirectivesByName() { + return directives.getDirectivesByName(); + } + + @Override + public List getDirectives(String directiveName) { + return directives.getDirectives(directiveName); + } + + @Override + public boolean hasDirective(String directiveName) { + return directives.hasDirective(directiveName); } public List getMemberTypes() { @@ -81,7 +96,7 @@ public String getName() { @Override public List getChildren() { List result = new ArrayList<>(); - result.addAll(directives); + result.addAll(directives.getDirectives()); result.addAll(memberTypes); return result; } @@ -89,7 +104,7 @@ public List getChildren() { @Override public NodeChildrenContainer getNamedChildren() { return newNodeChildrenContainer() - .children(CHILD_DIRECTIVES, directives) + .children(CHILD_DIRECTIVES, directives.getDirectives()) .children(CHILD_MEMBER_TYPES, memberTypes) .build(); } @@ -119,7 +134,7 @@ public boolean isEqualTo(Node o) { @Override public UnionTypeDefinition deepCopy() { return new UnionTypeDefinition(name, - deepCopy(directives), + deepCopy(directives.getDirectives()), deepCopy(memberTypes), description, getSourceLocation(), diff --git a/src/main/java/graphql/language/VariableDefinition.java b/src/main/java/graphql/language/VariableDefinition.java index 16fc258a62..c119222d47 100644 --- a/src/main/java/graphql/language/VariableDefinition.java +++ b/src/main/java/graphql/language/VariableDefinition.java @@ -26,7 +26,7 @@ public class VariableDefinition extends AbstractNode impleme private final String name; private final Type type; private final Value defaultValue; - private final ImmutableList directives; + private final NodeUtil.DirectivesHolder directives; public static final String CHILD_TYPE = "type"; public static final String CHILD_DEFAULT_VALUE = "defaultValue"; @@ -45,7 +45,7 @@ protected VariableDefinition(String name, this.name = name; this.type = type; this.defaultValue = defaultValue; - this.directives = ImmutableList.copyOf(directives); + this.directives = NodeUtil.DirectivesHolder.of(directives); } /** @@ -86,7 +86,22 @@ public Type getType() { @Override public List getDirectives() { - return directives; + return directives.getDirectives(); + } + + @Override + public Map> getDirectivesByName() { + return directives.getDirectivesByName(); + } + + @Override + public List getDirectives(String directiveName) { + return directives.getDirectives(directiveName); + } + + @Override + public boolean hasDirective(String directiveName) { + return directives.hasDirective(directiveName); } @Override @@ -96,7 +111,7 @@ public List getChildren() { if (defaultValue != null) { result.add(defaultValue); } - result.addAll(directives); + result.addAll(directives.getDirectives()); return result; } @@ -105,7 +120,7 @@ public NodeChildrenContainer getNamedChildren() { return newNodeChildrenContainer() .child(CHILD_TYPE, type) .child(CHILD_DEFAULT_VALUE, defaultValue) - .children(CHILD_DIRECTIVES, directives) + .children(CHILD_DIRECTIVES, directives.getDirectives()) .build(); } @@ -138,7 +153,7 @@ public VariableDefinition deepCopy() { return new VariableDefinition(name, deepCopy(type), deepCopy(defaultValue), - deepCopy(directives), + deepCopy(directives.getDirectives()), getSourceLocation(), getComments(), getIgnoredChars(),