【GraphQL Java 源码解析】SchemaParser
一、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) ; }