2017-06-13 101 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