文章目录
关于build.gradle.kts ext{}如何写的问题解决记录
最近新学习了一下Kotlin,然后做一个Springboot的项目基础脚手架,在创建新项目的时候发现gradle脚本也支持Kotlin了,索性做一个纯粹的,全用Kotlin,我觉得现在入Kotlin已经挺晚的了,没想到还有坑😂
下面先说结论,正忙的老铁一把Ctrl+C就走,记得再回来好评啊
👉Ctrl+C结论部分
父模块allprojects中的ext{}或项目的中的ext{}
ext {
set("logbackVersion", "1.1.1")
}
实际上在allprojects中的ext和groovy语言版本的使用方法相同,只是语言不同,需要转换一下
子模块的build.gradle.kts中的ext{}
dependencies {
//注意ext在dependencies里面
ext {
set("logbackVersion", "1.1.1")
}
testImplementation("junit:junit:4.12")
implementation("org.slf4j:slf4j-api:1.7.7")
// 读取方法${ext.get("logbackVersion"),不熟悉的请复习Kotlin
implementation("ch.qos.logback:logback-core:${ext.get("logbackVersion")}")
implementation("ch.qos.logback:logback-classic:${ext.get("logbackVersion")}")
}
★20210824更新,子模块可以使用allprojects中定义的ext,方法如下:
dependencies
testImplementation("junit:junit:4.12")
implementation("org.slf4j:slf4j-api:1.7.7")
// 不同的是加了一个project
implementation("ch.qos.logback:logback-core:${project.ext.get("logbackVersion")}")
implementation("ch.qos.logback:logback-classic:${project.ext.get("logbackVersion")}")
}
原因在于子模块中也有自己的ext对象,ext对象覆盖了allprojects中的变量的作用域,使用子模块的内置对象project就可以获取到project的全局定义
👉父模块allprojects中的ext{}或项目的中的ext{}
关于父模块或项目的的ext{}实际上没有太多可讲的,只是从groovy语言格式换成kotlin即可
- ext中调用set方法添加需要配置的参数,
有心的同学如果是idea开发,可以Ctrl点set跟过去看看,会发现这个是
ExtraPropertiesExtension
接口的一个方法void set(String name, @Nullable Object value);
- 在使用中注意是ext.get(“XXX”),注意括号里使用双引号
groovy版本:
buildscript {
ext {
dependencyManagementPluginVersion = '1.0.4.RELEASE'
springBootVersion = '2.0.3.RELEASE'
}
dependencies {
classpath("io.spring.gradle:dependency-management-plugin:${dependencyManagementPluginVersion}")
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
Kotlin版本:
buildscript {
ext {
set("dependencyManagementPluginVersion", "1.0.4.RELEASE")
set("springBootVersion", "2.0.3.RELEASE")
}
dependencies {
classpath("io.spring.gradle:dependency-management-plugin:${ext.get("dependencyManagementPluginVersion")}")
classpath("org.springframework.boot:spring-boot-gradle-plugin:${ext.get("springBootVersion")}")
}
}
具体所有Groovy转Kotlin的规则,请见gradle官方指南:
Migrating build logic from Groovy to Kotlin
👉子模块的build.gradle.kts中的ext{}
子模块的ext才真是这篇要讲的重点问题
原springboot脚手架的子模块build.gradle的groovy脚本如下(示例):
group = "com.muchenxinxi"
version = "1.0.0"
ext {
springfoxVersion = "2.9.2"
mapstructVersion = "1.3.0.Final"
lombokVersion = "1.18.12"
}
dependencies {
// Swagger 自动生成接口文档
compile "io.springfox:springfox-swagger2:${springfoxVersion}"
compile "io.springfox:springfox-swagger-ui:${springfoxVersion}"
}
转换成build.gradle.kts如下(示例):
ext {
set("springfoxVersion", "2.9.2")
set("mapstructVersion", "1.3.0.Final")
}
dependencies {
// Swagger 自动生成接口文档
implementation("io.springfox:springfox-swagger2:${ext.get("springfoxVersion")}")
implementation("io.springfox:springfox-swagger-ui:${ext.get("springfoxVersion")}")
}
眼看IDEA没有飘红,心想是成了,于是果断点了刷新按钮,应用gradle的变更,结果buid窗口蹦了出来(构建错误):
org.gradle.internal.exceptions.LocationAwareException: Build file 'D:\MyPlayground\KotlinSpringboot\app-service\build.gradle.kts' line: 20
Cannot get property 'springfoxVersion' on extra properties extension as it does not exist
at Program.execute(Unknown Source)
at Program.execute(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Caused by: org.gradle.api.plugins.ExtraPropertiesExtension$UnknownPropertyException: Cannot get property 'springfoxVersion' on extra properties extension as it does not exist
at Build_gradle$2.invoke(build.gradle.kts:20)
at Build_gradle$2.invoke(build.gradle.kts:1)
at Build_gradle.<init>(Unknown Source)
看意思是说没有找到springfoxVersion
这个值在extension(ext)中不存在,What?(问号脸)
明明在dependencies上面写了呀,我TM在Groovy都没毛病。。。这。。。
经过从网上一番搜索,有给出以下方案:
1.使用val定义常量,然后在dependencies直接${valName}使用
2.在allprojects中定义
实测,以上两种方式确实可以解决问题,但是想想:val定义常量?总觉得有点别扭;在allprojects中定义?那怎么能行,子模块的内容写到父项目的配置,显然不合理
正苦思冥想,突然发现父项目的build.gradle.kts的allproejct后面有个小标签this: Project
像这样:
allprojects { this: Project
}
这不就是这个对象就是一个变量传给了某个方法的那种提示吗?
Ctrl跟过去是这样的:
ProjectDelegate.kt文件中:
override fun allprojects(action: Action<in Project>) =
delegate.allprojects(action)
对应的是这个函数
接着再ctrl从dependencies
跟了过去:
dependencies{this: DenpendencyHandlerScop
}
发现跳转到了ProjectExtension.kt文件
/**
* Configures the dependencies for this project.
*
* Executes the given configuration block against the [DependencyHandlerScope] for this
* project.
*
* @param configuration the configuration block.
*/
fun Project.dependencies(configuration: DependencyHandlerScope.() -> Unit) =
DependencyHandlerScope.of(dependencies).configuration()
指向了这个函数,从子模块的dependencies
跟过去也是这里
显然DependencyHandlerScope.of()处理父项目和子项目的配置
继续Ctrl跟到DependencyHandlerScope类
/*
* Copyright 2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.gradle.kotlin.dsl
import org.gradle.api.Action
import org.gradle.api.Incubating
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.ExternalModuleDependency
import org.gradle.api.artifacts.ModuleDependency
import org.gradle.api.artifacts.dsl.DependencyConstraintHandler
import org.gradle.api.artifacts.dsl.DependencyHandler
import org.gradle.kotlin.dsl.support.delegates.DependencyHandlerDelegate
/**
* Receiver for `dependencies` block providing convenient utilities for configuring dependencies.
*
* @see [DependencyHandler]
*/
open class DependencyHandlerScope
private constructor(
val dependencies: DependencyHandler
) : DependencyHandlerDelegate() {
companion object {
fun of(dependencies: DependencyHandler): DependencyHandlerScope =
DependencyHandlerScope(dependencies)
}
override val delegate: DependencyHandler
get() = dependencies
@Deprecated(replaceWith = ReplaceWith("constraints"), message = "This method shouldn't be called because the most specific variant should be preferred by the Kotlin compiler", level = DeprecationLevel.HIDDEN)
override fun constraints(configureAction: Action<in DependencyConstraintHandler>) {
super.constraints(configureAction)
}
/**
* Configures dependency constraint for this project.
*
* @param configureAction the action to use to configure module metadata
*
* @since 6.3
*/
@Incubating
fun constraints(configureAction: DependencyConstraintHandlerScope.() -> Unit) {
super.constraints { t -> configureAction(DependencyConstraintHandlerScope.of(t)) }
}
/**
* Adds a dependency to the given configuration.
*
* @param dependencyNotation notation for the dependency to be added.
* @return The dependency.
* @see [DependencyHandler.add]
*/
operator fun String.invoke(dependencyNotation: Any): Dependency? =
dependencies.add(this, dependencyNotation)
/**
* Adds a dependency to the given configuration.
*
* @param dependencyNotation notation for the dependency to be added.
* @param dependencyConfiguration expression to use to configure the dependency.
* @return The dependency.
* @see [DependencyHandler.add]
*/
inline operator fun String.invoke(dependencyNotation: String, dependencyConfiguration: ExternalModuleDependency.() -> Unit): ExternalModuleDependency =
dependencies.add(this, dependencyNotation, dependencyConfiguration)
/**
* Adds a dependency to the given configuration.
*
* @param group the group of the module to be added as a dependency.
* @param name the name of the module to be added as a dependency.
* @param version the optional version of the module to be added as a dependency.
* @param configuration the optional configuration of the module to be added as a dependency.
* @param classifier the optional classifier of the module artifact to be added as a dependency.
* @param ext the optional extension of the module artifact to be added as a dependency.
* @return The dependency.
*
* @see [DependencyHandler.add]
*/
operator fun String.invoke(
group: String,
name: String,
version: String? = null,
configuration: String? = null,
classifier: String? = null,
ext: String? = null
): ExternalModuleDependency =
dependencies.create(group, name, version, configuration, classifier, ext).apply { add(this@invoke, this) }
/**
* Adds a dependency to the given configuration.
*
* @param group the group of the module to be added as a dependency.
* @param name the name of the module to be added as a dependency.
* @param version the optional version of the module to be added as a dependency.
* @param configuration the optional configuration of the module to be added as a dependency.
* @param classifier the optional classifier of the module artifact to be added as a dependency.
* @param ext the optional extension of the module artifact to be added as a dependency.
* @param dependencyConfiguration expression to use to configure the dependency.
* @return The dependency.
*
* @see [DependencyHandler.create]
* @see [DependencyHandler.add]
*/
inline operator fun String.invoke(
group: String,
name: String,
version: String? = null,
configuration: String? = null,
classifier: String? = null,
ext: String? = null,
dependencyConfiguration: ExternalModuleDependency.() -> Unit
): ExternalModuleDependency =
dependencies.add(this, create(group, name, version, configuration, classifier, ext), dependencyConfiguration)
/**
* Adds a dependency to the given configuration.
*
* @param dependency dependency to be added.
* @param dependencyConfiguration expression to use to configure the dependency.
* @return The dependency.
*
* @see [DependencyHandler.add]
*/
inline operator fun <T : ModuleDependency> String.invoke(dependency: T, dependencyConfiguration: T.() -> Unit): T =
dependencies.add(this, dependency, dependencyConfiguration)
/**
* Adds a dependency to the given configuration.
*
* @param dependencyNotation notation for the dependency to be added.
* @return The dependency.
* @see [DependencyHandler.add]
*/
operator fun Configuration.invoke(dependencyNotation: Any): Dependency? =
add(name, dependencyNotation)
/**
* Adds a dependency to the given configuration.
*
* @param dependencyNotation notation for the dependency to be added.
* @param dependencyConfiguration expression to use to configure the dependency.
* @return The dependency.
* @see [DependencyHandler.add]
*/
inline operator fun Configuration.invoke(dependencyNotation: String, dependencyConfiguration: ExternalModuleDependency.() -> Unit): ExternalModuleDependency =
add(name, dependencyNotation, dependencyConfiguration)
/**
* Adds a dependency to the given configuration.
*
* @param group the group of the module to be added as a dependency.
* @param name the name of the module to be added as a dependency.
* @param version the optional version of the module to be added as a dependency.
* @param configuration the optional configuration of the module to be added as a dependency.
* @param classifier the optional classifier of the module artifact to be added as a dependency.
* @param ext the optional extension of the module artifact to be added as a dependency.
* @return The dependency.
*
* @see [DependencyHandler.add]
*/
operator fun Configuration.invoke(
group: String,
name: String,
version: String? = null,
configuration: String? = null,
classifier: String? = null,
ext: String? = null
): ExternalModuleDependency =
create(group, name, version, configuration, classifier, ext).apply { add(this@invoke.name, this) }
/**
* Adds a dependency to the given configuration.
*
* @param group the group of the module to be added as a dependency.
* @param name the name of the module to be added as a dependency.
* @param version the optional version of the module to be added as a dependency.
* @param configuration the optional configuration of the module to be added as a dependency.
* @param classifier the optional classifier of the module artifact to be added as a dependency.
* @param ext the optional extension of the module artifact to be added as a dependency.
* @param dependencyConfiguration expression to use to configure the dependency.
* @return The dependency.
*
* @see [DependencyHandler.create]
* @see [DependencyHandler.add]
*/
inline operator fun Configuration.invoke(
group: String,
name: String,
version: String? = null,
configuration: String? = null,
classifier: String? = null,
ext: String? = null,
dependencyConfiguration: ExternalModuleDependency.() -> Unit
): ExternalModuleDependency =
add(this.name, create(group, name, version, configuration, classifier, ext), dependencyConfiguration)
/**
* Adds a dependency to the given configuration.
*
* @param dependency dependency to be added.
* @param dependencyConfiguration expression to use to configure the dependency.
* @return The dependency.
*
* @see [DependencyHandler.add]
*/
inline operator fun <T : ModuleDependency> Configuration.invoke(dependency: T, dependencyConfiguration: T.() -> Unit): T =
add(name, dependency, dependencyConfiguration)
/**
* Configures the dependencies.
*/
inline operator fun invoke(configuration: DependencyHandlerScope.() -> Unit) =
this.configuration()
}
What?!我看到了ext?再结合DependencyHandlerScope.of(dependencies).configuration()
这句代码,得出结论似乎是dependencies中有ext{}
于是乎赶紧把ext{}搬到了dependencies{}里面,经过测试能够正确加载依赖了!Wow~