2017-06-13 127 views
1

我想创建一个使用GraphQL Java Annotations的递归模式,但会引发异常。GraphQL Java注释递归问题

import org.junit.Assert; 
import org.junit.Test; 

import java.util.concurrent.ThreadLocalRandom; 

import graphql.ExecutionResult; 
import graphql.GraphQL; 
import graphql.annotations.GraphQLAnnotations; 
import graphql.annotations.GraphQLDataFetcher; 
import graphql.annotations.GraphQLDescription; 
import graphql.annotations.GraphQLField; 
import graphql.annotations.GraphQLName; 
import graphql.schema.DataFetcher; 
import graphql.schema.DataFetchingEnvironment; 
import graphql.schema.GraphQLObjectType; 
import graphql.schema.GraphQLSchema; 

import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition; 

public class RecursiveSchemaTest { 

    @GraphQLDescription("TestObject object") 
    @GraphQLName("TestObject") 
    public static class TestObject { 

    @GraphQLField 
    private Integer id; 

    @GraphQLField 
    @GraphQLDataFetcher(TestObjectDataFetcher.class) 
    private TestObject child; 

    public TestObject(Integer id) { 
     this.id = id; 
    } 

    public Integer getId() { 
     return id; 
    } 

    public void setId(Integer id) { 
     this.id = id; 
    } 

    public TestObject getChild() { 
     return child; 
    } 

    public void setChild(TestObject child) { 
     this.child = child; 
    } 
    } 

    public static class TestObjectDataFetcher implements DataFetcher<TestObject> { 

    @Override 
    public TestObject get(DataFetchingEnvironment environment) { 
     return new TestObject(ThreadLocalRandom.current().nextInt()); 
    } 
    } 

    @Test 
    public void test() { 
    GraphQLObjectType graphQLObjectType = GraphQLAnnotations.object(TestObject.class); 
    GraphQLObjectType rootQuery = GraphQLObjectType.newObject().name("data").field(
     newFieldDefinition().name(graphQLObjectType.getName()).type(graphQLObjectType) 
      .dataFetcher(new TestObjectDataFetcher()).build()).build(); 

    GraphQLSchema schema = GraphQLSchema.newSchema().query(rootQuery).build(); 
    GraphQL graphQL = GraphQL.newGraphQL(schema).build(); 

    ExecutionResult result = graphQL.execute("{ TestObject { id, child { id , child { id }}"); 
    Assert.assertFalse(result.getErrors() != null && !result.getErrors().isEmpty()); 
    Assert.assertNotNull(result.getData()); 
    } 
} 

解析班经过很好,但创建模式引发以下异常(此行:GraphQLSchema schema = GraphQLSchema.newSchema().query(rootQuery).build();):

graphql.AssertException: All types within a GraphQL schema must have unique names. No two provided types may have the same name. 
No provided type may have a name which conflicts with any built in types (including Scalar and Introspection types). 
You have redefined the type 'TestObject' from being a 'GraphQLObjectTypeWrapper' to a 'GraphQLObjectTypeWrapper' 

    at graphql.schema.SchemaUtil.assertTypeUniqueness(SchemaUtil.java:86) 
    at graphql.schema.SchemaUtil.collectTypesForObjects(SchemaUtil.java:122) 
    at graphql.schema.SchemaUtil.collectTypes(SchemaUtil.java:56) 
    at graphql.schema.SchemaUtil.collectTypesForObjects(SchemaUtil.java:128) 
    at graphql.schema.SchemaUtil.collectTypes(SchemaUtil.java:56) 
    at graphql.schema.SchemaUtil.collectTypesForObjects(SchemaUtil.java:128) 
    at graphql.schema.SchemaUtil.collectTypes(SchemaUtil.java:56) 
    at graphql.schema.SchemaUtil.allTypes(SchemaUtil.java:153) 
    at graphql.schema.GraphQLSchema.<init>(GraphQLSchema.java:42) 
    at graphql.schema.GraphQLSchema$Builder.build(GraphQLSchema.java:130) 
    at graphql.schema.GraphQLSchema$Builder.build(GraphQLSchema.java:125) 
    at RecursiveSchemaTest.test(RecursiveSchemaTest.java:74) 

为什么架构建立不正确任何想法?我使用graphql-java(3.0.0)和graphql-java-annotations(0.14.0)的最新版本

+0

我相信这是一个正在使用的graphql-java-annotation中的错误(团队成员提到发布即将推出)。以前版本的graphql-java允许复制类型名称,但从3.0.0开始它是一个错误,并且注释库还没有赶上。顺便说一句,看看我的lib,[graphql-spqr](https://github.com/leangen/graphql-spqr),它允许更自动的模式生成。 – kaqqao

+0

啊,这是一个无赖。在Github上是否存在这个问题?我找不到它,如果需要,我可以创建一个。 Graphql-spqr看起来非常棒,我会把它作为测试骑:) :) – ifodor

+0

将我的评论转换为答案并链接到跟踪升级到3.0.0的问题,这也解决了您的问题。至于graphql-spqr,如果您需要帮助,请至[Gitter room](https://gitter.im/leangen/graphql-spqr)下载,至少在完成文档编写之前(我目前正在编写该文档)。 – kaqqao

回答

1

我相信这是一个使用graphql-java-annotation has already been closed的bug。以前版本的graphql-java允许复制类型名称,但从3.0.0开始它是一个错误,并且注释库还没有赶上。

的修复,应在即将发布...

顺便说一下,看看我的lib,graphql-spqr,它允许更多的自动化架构生成,并会轻松支付你的用例:

public static class TestObject { 
    private Integer id; 

    public TestObject(Integer id) { 
     this.id = id; 
    } 

    public Integer getId() { 
     return id; 
    } 

    public void setId(Integer id) { 
     this.id = id; 
    } 
} 

public static class TestObjectService { 

    @GraphQLQuery(name = "TestObject") 
    public TestObject getRoot() { //no GraphQL-specific classes mentioned 
     return getRandom(); 
    } 

    @GraphQLQuery(name = "child") 
    public TestObject getChild(@GraphQLContext TestObject parent) { 
     return getRandom(); 
    } 

    private TestObject getRandom() { 
     return new TestObject(ThreadLocalRandom.current().nextInt()); 
    } 
} 

@Test 
public void test() { 
    GraphQLSchema schema = new GraphQLSchemaGenerator() 
      .withOperationsFromSingleton(new TestObjectService()) 
      .generate(); //that's all :) 
    GraphQL graphQL = GraphQL.newGraphQL(schema).build(); 

    ExecutionResult result = graphQL.execute("{ TestObject { id, child { id , child { id }}}}"); //your query has a syntax error 
    assertFalse(result.getErrors() != null && !result.getErrors().isEmpty()); 
    assertNotNull(result.getData()); 
} 

请注意,我从TestObject中删除child属性,因为它没有被真正使用(因为它被替换为不同的提取器)。尽管如此,如果您将它放在一边,则不会有什么区别 - 自定义提取器(通过@GraphQLContext嵌套)仍会覆盖它。 @GraphQLContext背后的想法是允许嵌套查询,而不必将逻辑嵌入到模型中,甚至不需要触摸模型对象。

如果您想重新命名或添加说明(例如,

@GraphQLQuery(name = "child", description = "The child object") 
public TestObject getChild() { 
    return child; 
} 
+0

您链接的问题包含修复原始问题的PR。它不在maven中央,但在当地工作!谢谢 – ifodor