欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【GraphQL Java 源码解析】SchemaParser

程序员文章站 2022-03-03 17:03:39
...

 一、GraphQL最开始就是定义Schema,并有SchemaParser解析并处理

定义有3三方式:

1. SchemaParser.newParser构建一个SchemaParserBuilder,并直接编写schemaString

 

// My application class
SchemaParser.newParser()
    .schemaString("Query { }")

2. SchemaParser.newParser构建一个SchemaParserBuilder,并指定文件路径

 

// My application class
SchemaParser.newParser()
    .file("my-schema.graphqls")

3. 由Spring构建,先SchemaStringProvider提供所有的schema文件。然后交给SchemaParserBuilder解析。

 

 @Bean
  @ConditionalOnBean({GraphQLResolver.class})
  @ConditionalOnMissingBean
  public SchemaParser schemaParser(
      List<GraphQLResolver<?>> resolvers,
      SchemaStringProvider schemaStringProvider,
      SchemaParserOptions.Builder optionsBuilder,
      @Autowired(required = false) SchemaParserDictionary dictionary,
      @Autowired(required = false) GraphQLScalarType[] scalars,
      @Autowired(required = false) List<SchemaDirective> directives,
      @Autowired(required = false) List<SchemaDirectiveWiring> directiveWirings
  )

Spring构建 SchemaParser时,自动装载

1. GraphQLResolver    //Field 字段处理器

    工具将GraphQL对象上的字段映射到Java对象上的方法和属性。对于大多数标量字段,带有字段和/或getter方法的POJO足以描述GraphQL中的数据。更复杂的字段(如查找另一个对象)通常需要具有GraphQL上下文(存储库、连接等)未提供的状态的更复杂方法。graphqljava工具使用“数据类”和“解析器”的概念来解释这两种情况。当给定resolver实例时,graphqljava工具首先尝试将字段映射到解析器上的方法,然后再将它们映射到数据类上的字段或方法。如果解析器上有匹配的方法,则将数据类实例作为第一个参数传递给解析器函数。这不适用于根解析程序,因为它们没有要解析的数据类。可以定义一个可选参数来注入DataFetchingEnvironment,并且必须是最后一个参数。

2. SchemaStringProvider    // Schema文件提供者

    多个源将按给定的顺序连接在一起,允许您根据需要模块化模式。

3. SchemaParserOptions.Builder  // 解析器选项

4. SchemaParserDictionary       // 实体映射词典

   有时graphqljava工具在扫描对象时找不到类,这通常是由于接口和联合类型的限制。有时您的Java类也与GraphQL模式不完全一致。GraphQLJava工具允许您手动提供其他类,并根据需要“重命名”它们。

5. GraphQLScalarType 

   通过创建GraphQLScalarType类的新实例,可以在graphqljava中创建自定义标量类型。要在GraphQL Java工具中使用自定义标量,请将标量添加到GraphQL schema 中:          

6. SchemaDirective

   有关指令的详细说明,包括如何在SDL中定义指令和创建所需类的示例,请参见Schema指令,要将自定义SchemaDirectiveWiring添加到graphql,java工具在使用创建SchemaParser时传递它

7. SchemaDirectiveWiring 

 

不管任何一种模式,最终构建的所有schema都会加入到SchemaParserBuilder的 private val schemaString 中。

 

二、SchemaParserBuilder进行解析

1. scan解析入口(使用提供的schema和dictionary扫描类。)

调用parseDefinitions获取schema定义的所有Definitions,schema解析成Definitions是由Parser完成

Definitions主要包括,都是实现了Definition接口

  DirectiveDefinition

  EnumValueDefinition

  InputObjectTypeDefinition

  InterfaceTypeDefinition

  ObjectTypeDefinition

  ScalarTypeDefinition

  UnionTypeDefinition

2. SchemaClassScanner 尝试通过匹配已知字段上的返回类型/参数类型来发现GraphQL Type->Java类关系

通过 RootQuery 开始进行扫描构建FieldDefinition,并将每个root的field的自定义类型加入到队列中,然后通过队列获取新的Definition进行下一次的扫描

scanResolverInfoForPotentialMatches()->fieldResolver->handleFoundType()->type: TypeDefinition, javaType: JavaType, reference: Reference 三者的关系,将找找到的新类型放入dictionary中->handleNewType->将新类型放入queue中。->scanInterfacesOfType查找类对应的接口->scanQueueItemForPotentialMatches()->scanResolverInfoForPotentialMatches()

3. 将所有相关的架构文件/类传递给解析器后,调用.build()和.makeExecutableSchema()以获取graphql java GraphQLSchema。

4. 构建了GraphQLSchema,可以使用parseSchemaObjects()获取所有已解析的对象。

 

注意:

如果定义了Type类型,并implements接口,如果此类型没有在任何Query或则Field中使用,系统将会报错。

 Object type 'MediaImage' implements a known interface, but no class could be found for that type name.  Please pass a class for type 'MediaImage' in the parser's dictionary.

三种解决方案:

1.将此Type删除

2.将此Type应用到Query,或者Field中。

3.在SchemaParserDictionary加入

   @Bean
    public SchemaParserDictionary dictionary() {
        return new SchemaParserDictionary()
                .add(MediaImage.class)
                ;
    }