代码生成插件初识

官方学习文档

DGS代码生成插件在你的项目构建过程中,根据你的Domain Graph Service的GraphQL模式文件生成代码。该插件生成以下内容。

类型、输入类型、枚举和接口的数据类型。一个包含类型和字段名称的DgsConstants类数据提取器的例子一个表示你的查询的类型安全查询API

// Using plugins DSL

plugins {

id "com.netflix.dgs.codegen" version "5.2.4"

}

该插件添加了一个generateJava的Gradle任务,作为项目构建的一部分运行。 generateJava在项目的构建/生成目录下生成代码。请注意,在Kotlin项目中,generateJava任务默认生成Kotlin代码(是的,这个名字很让人困惑)。这个文件夹会自动添加到项目的classpath中。类型是作为packageName.types指定的包的一部分,其中你指定packageName的值作为build.gradle文件中的配置。请确保你的项目的源代码使用指定的包名来引用生成的代码。

generateJava生成数据提取器,并将其放在build/generated-examples中。

generateJava{

schemaPaths = ["${projectDir}/src/main/resources/schema"] // List of directories containing schema files

packageName = 'com.openbayes.testDgs' // The package name to use to generate sources

generateClient = true // Enable generating the type safe query API

}

generateJava不会把它生成的数据提取器添加到你的项目源中。这些取数器主要是作为基本的模板代码,需要你进一步实现。

你可以将模式的某些部分排除在代码生成之外,方法是将它们放在一个不同的模式目录中,该目录不作为插件的schemaPaths的一部分被指定。

修复 "Could not initialize class graphql.parser.antlr.GraphqlLexer "问题

Gradle的插件系统为所有的插件使用了一个扁平的classpath,这使得它很容易遇到classpath冲突。Codegen插件的一个依赖项是ANTLR,不幸的是,其他一些插件也在使用它。如果你看到一个错误,比如无法初始化graphql.parser.antlr.GraphqlLexer类,这通常表明有一个classpath冲突。如果发生这种情况,请改变你的构建脚本中的插件的顺序。ANTLR通常是向后兼容的,但不是向前兼容的。

对于多模块项目意味着你需要在根构建文件中声明Codegen插件,而不应用它。

plugins {

id("com.netflix.dgs.codegen") version "[REPLACE_WITH_CODEGEN_PLUGIN_VERSION]" apply false

//other plugins

}

在应该应用该插件的模块中,你在插件块中再次指定该插件,但没有版本。

plugins {

id("com.netflix.dgs.codegen")

}

映射现有类型

Codegen试图为它在模式中发现的每个类型生成一个类型,但有几个例外。

基本标量类型–被映射到相应的Java/Kotlin类型(String, Integer等)。日期和时间类型–被映射到相应的java.time类。PageInfo和RelayPageInfo–被映射到graphql.relay类。用typeMapping配置映射的类型

当你有想使用的现有类,而不是为某个类型生成一个类时,你可以使用typeMapping来配置该插件。typeMapping配置是一个Map,其中每个键是GraphQL类型,每个值是一个完全合格的Java/Kotlin类型。

generateJava{

typeMapping = ["MyGraphQLType": "com.mypackage.MyJavaType"]

}

生成客户端API

代码生成器还可以创建客户端API类。你可以使用这些类来从使用Java的GraphQL端点查询数据,或者在单元测试中使用QueryExecutor。Java GraphQL 客户端对于服务器到服务器的通信非常有用。GraphQL Java客户端作为框架的一部分是可用的。

代码生成为每个查询和突变字段创建一个字段名GraphQLQuery。GraphQLQuery查询类包含字段的每个参数。对于每个由查询或突变返回的类型,代码生成创建一个ProjectionRoot。一个投影是一个构建器类,它指定哪些字段会被返回。

下面是一个生成的API的使用示例。

GraphQLQueryRequest graphQLQueryRequest =

new GraphQLQueryRequest(

new TicksGraphQLQuery.Builder()

.first(first)

.after(after)

.build(),

new TicksConnectionProjection()

.edges()

.node()

.date()

.route()

.name()

.votes()

.starRating()

.parent()

.grade());

这个API是基于以下模式生成的。边缘和节点类型是因为该模式使用了分页。该API允许以流畅的风格来编写查询,几乎与把查询写成String的感觉一样,但有代码完成和类型安全的额外好处。

type Query @extends {

ticks(first: Int, after: Int, allowCached: Boolean): TicksConnection

}

type Tick {

id: ID

route: Route

date: LocalDate

userStars: Int

userRating: String

leadStyle: LeadStyle

comments: String

}

type Votes {

starRating: Float

nrOfVotes: Int

}

type Route {

routeId: ID

name: String

grade: String

style: Style

pitches: Int

votes: Votes

location: [String]

}

type TicksConnection {

edges: [TickEdge]

}

type TickEdge {

cursor: String!

node: Tick

}

为外部服务产生查询API

生成上述的查询API对于测试你自己的DGS非常有用。在与另一个GraphQL服务交互时,同样类型的API也很有用,你的代码是该服务的客户端。这通常是使用DGS客户端完成的。

当你为你自己的模式和内部模式使用代码生成时,你可能希望为这两者使用不同的代码生成配置。建议在你的项目中创建一个单独的模块,包含外部服务的模式和codegen配置,只生成一个查询API。下面是只生成查询API的配置实例。

generateJava {

schemaPaths = ["${projectDir}/composed-schema.graphqls"]

packageName = "some.other.service"

generateClient = true

generateDataTypes = false

skipEntityQueries = true

includeQueries = ["hello"]

includeMutations = [""]

shortProjectionNames = true

maxProjectionDepth = 2

}

限制客户端API的生成代码

如果你的模式很大或者有很多周期,为整个模式生成客户端API并不理想,因为你最终会有大量的投影。这可能会导致代码生成速度明显减慢,或者根据你的模式耗尽内存。我们有一些配置参数可以帮助调整,所以你可以将客户端API的生成限制在只需要的部分。

generateJava {

...

generateClient = true

skipEntityQueries = true

includeQueries = ["hello"]

includeMutations = [""]

includeSubscriptions = [""]

maxProjectionDepth = 2

}

首先,你可以通过includeQueries、includeMutations和includeSubscriptions来指定到底要生成哪些查询/变异/订阅。 skipEntityQueries只在你为测试目的构建联合_entities查询时使用,所以你也可以设置它来限制生成的代码量。最后,maxProjectionDepth将指示codegen停止生成从查询根部开始超过2层的图形。默认值是10。这也将有助于进一步限制投影的数量。

配置代码生成

代码生成有许多配置开关。下表显示了Gradle的配置选项,但同样的选项在命令行和Maven中也是可用的。

查看原文