IntelliJ运行Gradle多模块项目main方法报错:未知属性commonslangversion
项目背景
我们有一个基于Gradle v6.8.2的多模块项目,目录结构如下:
. ├── searchapi │ ├── build.gradle │ └── settings.gradle ├── searchcommon │ ├── build.gradle │ └── settings.gradle ├── searchconfig │ ├── build.gradle │ └── settings.gradle ├── searchindexer │ ├── build.gradle │ └── settings.gradle ├── build.gradle └── settings.gradle
为了统一管理子模块中的重复依赖(比如commons-lang),我们在顶层build.gradle中通过ext变量统一指定版本:
ext.commonslangversion = "[2,3)"
子项目中则通过以下方式声明依赖:
implementation "commons-lang:commons-lang:${commonslangversion}"
项目顶层构建在CLI和IntelliJ(v2022.1.4)中都能正常执行,但遇到了以下异常问题:
问题现象
- 右键运行
searchindexer模块中带main()方法的类时,触发构建错误:
A problem occurred evaluating root project 'searchindexer'.
Could not get unknown property 'commonslangversion' for object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.
- 但将
main()方法的代码移入JUnit测试类并执行测试时,构建和运行完全正常。
原因分析
1. IntelliJ运行main方法的构建上下文错误
当你右键运行子模块的main类时,IntelliJ默认会把该子模块当作独立的Gradle根项目来执行构建流程。此时子模块自己的settings.gradle不会加载顶层的父build.gradle,自然无法获取到父级定义的ext.commonslangversion变量,导致依赖版本解析失败。
2. 测试运行正常的核心原因
执行JUnit测试时,IntelliJ是基于整个多模块项目的Gradle上下文来构建的:它会优先加载顶层的settings.gradle和build.gradle,再处理子模块的构建脚本,因此能正常读取父级定义的ext变量,依赖解析自然不会出问题。
3. 子模块独立settings.gradle的负面影响
你的每个子模块都自带settings.gradle,这会让IntelliJ误判每个子模块都是独立的Gradle项目。标准的Gradle多模块项目中,应该只有顶层项目拥有settings.gradle,用来声明所有子模块,子模块不需要单独的settings.gradle文件——这也是触发本次问题的关键因素。
解决方案
- 规范项目结构(推荐)
删除所有子模块中的settings.gradle文件,只保留顶层项目的settings.gradle,并在其中明确声明所有子模块:
include ':searchapi', ':searchcommon', ':searchconfig', ':searchindexer'
- 修改IntelliJ运行配置
如果需要保留子模块的独立配置,可在运行main类时手动指定Gradle根项目:
- 打开IntelliJ的运行配置窗口,找到
Gradle选项卡; - 将
Gradle project设置为顶层项目的路径,而非子模块路径。
- 子模块引用父级构建脚本(临时方案)
在子模块的build.gradle中添加对父级构建脚本的引用,确保能读取到变量:
apply from: rootProject.file('build.gradle')
不过这种方式会导致构建脚本冗余,不推荐作为长期解决方案。
内容的提问来源于stack exchange,提问作者fmpdmb

