Enigmatis / graphql-java-annotations

GraphQL Annotations for Java

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

IndexOutOfBoundException when using directive annotations

cocobey73 opened this issue · comments

When I added a directive annotation to one of my additional classes (not the query class) the process fail with an index out of bound exception.

commented

I would be happy if you give us a code example

Sure, here is an example. When I add the Upper annotation to a pojo field, I get this error

Exception in thread "main" java.lang.IllegalArgumentException: fromIndex(1) > toIndex(0) at java.util.ArrayList.subListRangeCheck(ArrayList.java:1014) at java.util.ArrayList.subList(ArrayList.java:1004) at java.util.Collections$UnmodifiableRandomAccessList.subList(Collections.java:1402) at graphql.schema.SchemaTransformer.moveUp(SchemaTransformer.java:363) at graphql.schema.SchemaTransformer.toRootNode(SchemaTransformer.java:217) at graphql.schema.SchemaTransformer.transform(SchemaTransformer.java:176) at graphql.annotations.AnnotationsSchemaCreator$Builder.build(AnnotationsSchemaCreator.java:271) at FailureExample.main(FailureExample.java:71)

Here is the sample code to get this error.

import graphql.ExecutionResult;
import graphql.GraphQL;
import graphql.GraphQLError;
import graphql.annotations.AnnotationsSchemaCreator;
import graphql.annotations.annotationTypes.GraphQLDeprecate;
import graphql.annotations.annotationTypes.GraphQLField;
import graphql.annotations.annotationTypes.GraphQLName;
import graphql.annotations.annotationTypes.directives.definition.DirectiveLocations;
import graphql.annotations.annotationTypes.directives.definition.GraphQLDirectiveDefinition;
import graphql.annotations.directives.AnnotationsDirectiveWiring;
import graphql.annotations.directives.AnnotationsWiringEnvironment;
import graphql.annotations.processor.util.CodeRegistryUtil;
import graphql.introspection.Introspection;
import graphql.schema.GraphQLFieldDefinition;
import graphql.schema.GraphQLSchema;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Map;
import java.util.stream.Collectors;

public class FailureExample {

    public static class UpperWiring implements AnnotationsDirectiveWiring {
        @Override
        public GraphQLFieldDefinition onField(AnnotationsWiringEnvironment environment) {
            GraphQLFieldDefinition field = (GraphQLFieldDefinition) environment.getElement();
            boolean isActive = (boolean) environment.getDirective().getArgument("isActive").getValue();
            CodeRegistryUtil.wrapDataFetcher(field, environment, (((dataFetchingEnvironment, value) -> {
                if (value instanceof String && isActive) {
                    return ((String) value).toUpperCase();
                }
                return value;
            })));
            return field;
        }
    }

    @GraphQLName("upper")
    @GraphQLDirectiveDefinition(wiring = UpperWiring.class)
    @DirectiveLocations({Introspection.DirectiveLocation.FIELD_DEFINITION})
    @Retention(RetentionPolicy.RUNTIME)
    @interface Upper {
        @GraphQLName("isActive")
        boolean isActive() default true;
    }

    public static class Query {
        @GraphQLField
        @GraphQLDeprecate
        public static Pojo pojoQuery() {
            return new Pojo();
        }
    }

    public static class Pojo {
        @GraphQLField
        @GraphQLDeprecate
        @Upper
        public String pojoField() {
            return "hello!";
        }
    }

    public static void main(String... args) {
        GraphQLSchema schema = AnnotationsSchemaCreator.newAnnotationsSchema()
                .query(Query.class) // to create you query object
                .additionalType(Pojo.class) // to create some additional type and add it to the schema
                .setAlwaysPrettify(true) // to set the global prettifier of field names (removes get/set/is prefixes from names)
                .directive(Upper.class) // to create a directive
                .build();

        GraphQL graphQL = GraphQL.newGraphQL(schema).build();

        ExecutionResult result = graphQL.execute("{ pojoQuery { pojoField } }");

        if (!result.getErrors().isEmpty()) {
            throw new RuntimeException(result.getErrors().stream().map(GraphQLError::getMessage).collect(Collectors.joining()));
        } else {
            String pojoField = ((Map) result.<Map>getData().get("pojoQuery")).get("pojoField").toString();
            if (!pojoField.equals("HELLO!")) {
                throw new RuntimeException("Result was not upper cased -> " + pojoField);
            }
        }
    }
}

My only dependency

dependencies {
    implementation group: 'io.github.graphql-java', name: 'graphql-java-annotations', version: '8.0'
}

Im running on unix using jdk 1.8.0_241.

Let me know if you need more details, and appreciate the help.

commented

If I delete the following line
.additionalType(Pojo.class) // to create some additional type and add it to the schema
The execution works without any exception.
I wonder why have you added this line of code?
The Pojo class is referenced from the Query class, therefore you do not need to add it as an AdditionalType. Only classes that are not referenced from the Query or his subtypes (such as graphql interface's implementations) should be inserted to the additional types of the schema.

Hope it helps.

Thanks for the explanation. That was not very clear, but it does work.