Gradle 不收集以 -D 开头的字符串

Posted

技术标签:

【中文标题】Gradle 不收集以 -D 开头的字符串【英文标题】:Gradle doesn't collect strings starting with -D 【发布时间】:2018-03-08 21:14:24 【问题描述】:

这是 Gradle 还是 Groovy 错误?

我想将 JVM 参数从 Gradle 传递到分叉的 JVM,不幸的是这不是自动完成的。这应该可以工作,build.gradle:

...
bootRun 
   jvmArgs = System.properties.iterator().findAllit.key.startsWith('myapp').collect 
     "-D$it.key=$it.value"

...

执行如下:

 gradle bootRun -Dmyapp.port=34501 -Dmyapp.member.name=server1

如果字符串以-D 开头,方法collect 总是返回空集合。如果它以其他任何内容开头,则返回预期的两个元素字符串集合。如果我在-D 之前放置空间,它也可以工作,但是它会在:findMainClass 上进一步破坏下游的构建,并用主类名误解-Dmyapp.port=...。它只需以-D 开头。

我也尝试了不同的字符串连接,但结果是一个以 -D 开头的字符串,它不起作用。

这是一个错误还是我遗漏了什么。这是我的第一个 Gradle 项目,我不是 Groovy 开发人员。 我应该报告错误吗?在哪里,Groovy 还是 Gradle?

注意事项: 我正在从 IntelliJ IDE 2016.1.2 运行 Gradle 使用 Gradle 3.5 Forked JVM 运行 Spring Boot 应用程序

更新 非常抱歉,我的错!事实上,JVM 参数使用上面的公式传递下来的;问题在于我如何测量它不是。我只是把打印输出:

 println "jvmArgs: $jvmArgs"
 println "jvmArgs.size: $jvmArgs.size"
 println "jvmArgs.class: $jvmArgs.class"

..如果jvmArgs.size == 0,则中止bootRun,以避免应用程序启动缓慢;也就是说,我并没有真正检查应用程序本身是否传递了参数。事实证明他们是。

仅供参考,输出是:

 jvmArgs: []
 jvmArgs.size: 0
 jvmArgs.class: java.lang.ArrayList

jvmArgs 类被报告为标准 ArrayList,但其行为更像 输入流使用者,无论 jvmArgs 分配给什么数组,都会扫描该数组以查找所有以“-D”开头的字符串,那些是消耗(被什么?),传递给一些 ProcessBuilder (??) 并且 jvmArgs 只剩下剩余的元素。

举个例子:

 jvmArgs = ["-Daaa=bbb", "foo", "bar"]
 jvmArgs = ["stuff", "-Dccc=ddd", "morestuff"]
 jvmArgs = ["-Deee=fff"]
 println "jvmArgs: $jvmArgs"

..它打印 jvmArgs: [] 并且 Spring Boot 应用程序以 -Daaa=bbb -Dccc=ddd -Deee=fff 启动。

有人能解释一下是什么原因导致这个神奇的流类似于 jvmArgs 的属性,否则它声称是一个简单的 ListArray?

【问题讨论】:

这绝对不是一个错误——它早就被发现了。你如何运行gradle?从控制台,哪个外壳?或者可能来自 IDE。 你是对的,它一直有效,请阅读我的解释。奇怪的行为似乎是设计使然。 【参考方案1】:

这对我有用,但我对观察到的行为没有解释。无论如何,希望它有所帮助。

def array = System.properties.iterator().findAll
   it.key.startsWith('myapp')
.collect 
   "-D$it.key=$it.value"

jvmArgs.addAll(array)

编辑

jvmArgs = ["value"] 调用 setJvmArgs,如果我没有遗漏什么,它会从 JavaExec 转到 JavaExecHandleBuilder,然后是 JvmOptions。在这里,一些参数被删除。以 -D 开头的条目被添加到系统属性中。

setJvmArgs( ["-Dtest=1", "xx"])
println getJvmArgs() //[xx]
println systemProperties //[test:1]

您的应用程序是否无权访问这些属性?

https://github.com/gradle/gradle/blob/master/subprojects/core/src/main/java/org/gradle/process/internal/JvmOptions.java#L183

编辑:后台发生了什么

在 Groovy 中,属性赋值调用 setter,访问它会调用 getter。它们可以互换。如果您省略了 setter 和 getter 对,它将为您生成并在字节码中可见。但你甚至可以省略属性本身,只写 getter 和 setter 对并将其用作属性。

class Foo 
   def setBar(String foo) println "no thanks"
   String getBar() "test"

f = new Foo()
f.bar="write Var" // println "no thanks"
println f.bar instanceof String // --> f.getBar() inst... true
println f.bar // 

因此,您从未将 List 分配给变量,而是调用 setJvmArgs(List)。您可以使用 getAllJvmArgs() btw 列出所有参数。

结合委托策略和动态属性/方法,这可能是 DSL 编程的福音,但却是调试的祸根……

http://groovy-lang.org/style-guide.html#_getters_and_setters 如果您想了解有关此主题的更多信息,请搜索 groovy propertyMissing/groovy metaprogramming/groovy Resolve Strategies。

【讨论】:

我尝试使用像您这样的传递变量,然后将其分配给jvmArgs。令人困惑的是,传递变量的打印输出与预期的一样,它的行为就像正常的集合,但jvmArgs 又是空的。我没有尝试过addAll(),但我怀疑它会产生相同的效果。 感谢源代码,它看起来像是我正在寻找的解释。你是怎样找到它的?你是如何弄清楚事件链的?是否可以调试 Gradle? @Espinosa 我已经更新了答案。可以肯定地调试 gradle 脚本,但我从来没有让它工作。我想我已经在 gradle docs 中找到了 javaExec 任务的起点,后来切换到了 github。

以上是关于Gradle 不收集以 -D 开头的字符串的主要内容,如果未能解决你的问题,请参考以下文章

如何让 CSS 选择以字符串开头的 ID(不是在 Javascript 中)?

正则表达式:如何匹配不以前缀列表开头的子字符串

js判断字符串以啥开头

编写不区分大小写的Cypher查询以匹配Neo4j中字符串的开头

如果存在,则替换文件中以字符串开头的行,如果不存在则添加

set<string>:如何列出不以给定字符串开头并以`/`结尾的字符串?