如何声明构造函数或扩展 groovy 脚本的 class?
How to declare a constructor or extends a class of a groovy script?
我正在为 Jenkins 开发 shared library,我想访问某些 class 之间的一些实用程序方法,但不是全部,因此我建立了一些声明:
- 我想避免使用静态方法,因为它不直接访问管道步骤,并且每次调用都传递管道实例会很痛苦;
- 我也想避免单例,或者在每个方法调用前加上 util class' 实例;
- 因为它不应该在所有 class 之间共享,所以我想避免将每个方法作为文件放在
vars/
特殊目录中,但我想要类似的行为;
- 尽管扩展 class 将是 anti-pattern,但它是可以接受的,尽管我想避免使用冗长的 Java 语法来声明 class与文件同名,一旦它隐含在 groovy;
这个 确实部分解决了我的问题,尽管存在序列化问题,但我注意到当我使用检查点并且从某个阶段恢复某些构建时,该实例会丢失所有额外的方法。
这个 本来可以帮助我解决序列化问题,但是作者似乎已经使用一种不是标题为的原始问题的方式解决了他的问题的根本原因。
有没有办法在不使用 class NameOfFile extends SomeOtherClass { put every thing inside this block }
语法的情况下扩展 groovy 中的隐式脚本 class?并且不使用 inner-class?
否则,有没有办法使用脚本 groovy 类似于上一个问题的语法来声明构造函数?
或者甚至,有没有办法更改序列化行为以在反序列化后再次安装额外的方法?
附录
脚本语法 more-or-less 如下所示:
考虑文件内容 src/cicd/pipeline/SomePipeline.groovy
:
package cicd.pipeline
// there is no need to wrap everything inside class SomePipeline,
// since it is implicit
def method() {
// instance method, here I can access pipeline steps freely
}
def static otherMethod() {
// static method, here it is unable to access pipeline steps
// without a instance
}
@groovy.transform.Field
def field
def call() {
// if the class is used as method it will run
this.method()
SomePipeline.otherMethod() // or simply otherMethod() should work
this.field = 'foo'
println "this instance ${this.getClass().canonicalName} should be cicd.pipeline.SomePipeline"
}
// any code other than methods or variables with @Field
// annotation will be inside a implicit run method that is
// triggered likewise main method but isn't a static one
def localVar = 'foo'
println "It will not execute on constructor since it is on run: $localVar"
println "Method: ${org.codehaus.groovy.runtime.StackTraceUtils.sanitize(new Throwable()).stackTrace[0].methodName}"
println "this instance ${this.getClass().canonicalName} should be cicd.pipeline.SomePipeline"
如果我要使用 Java 冗长的语法,我必须将几乎所有内容都包装在 class SomePipeline
中,这在 groovy 中是隐含的,这就是我想要的脚本语法保留。
我意识到 this.getClass().superclass.canonicalName
当外部 Jenkins 管道是 groovy.lang.Script
并且当内部管道是 org.jenkinsci.plugins.workflow.cps.CpsScript
并且基于 this resource 我能够详细说明以下解决方案:
abstract class CustomScript extends org.jenkinsci.plugins.workflow.cps.CpsScript {
public CustomScript() {
// do something here, it will always execute regardless
// serialization, and before everything
}
}
@groovy.transform.BaseScript CustomScript baseScript
就是这样,按预期工作!当然你可以更好地阐述这个解决方案,以减少重复和避免inner-classes,但我会留给你想象。
我正在为 Jenkins 开发 shared library,我想访问某些 class 之间的一些实用程序方法,但不是全部,因此我建立了一些声明:
- 我想避免使用静态方法,因为它不直接访问管道步骤,并且每次调用都传递管道实例会很痛苦;
- 我也想避免单例,或者在每个方法调用前加上 util class' 实例;
- 因为它不应该在所有 class 之间共享,所以我想避免将每个方法作为文件放在
vars/
特殊目录中,但我想要类似的行为; - 尽管扩展 class 将是 anti-pattern,但它是可以接受的,尽管我想避免使用冗长的 Java 语法来声明 class与文件同名,一旦它隐含在 groovy;
这个
这个
有没有办法在不使用 class NameOfFile extends SomeOtherClass { put every thing inside this block }
语法的情况下扩展 groovy 中的隐式脚本 class?并且不使用 inner-class?
否则,有没有办法使用脚本 groovy 类似于上一个问题的语法来声明构造函数?
或者甚至,有没有办法更改序列化行为以在反序列化后再次安装额外的方法?
附录
脚本语法 more-or-less 如下所示:
考虑文件内容 src/cicd/pipeline/SomePipeline.groovy
:
package cicd.pipeline
// there is no need to wrap everything inside class SomePipeline,
// since it is implicit
def method() {
// instance method, here I can access pipeline steps freely
}
def static otherMethod() {
// static method, here it is unable to access pipeline steps
// without a instance
}
@groovy.transform.Field
def field
def call() {
// if the class is used as method it will run
this.method()
SomePipeline.otherMethod() // or simply otherMethod() should work
this.field = 'foo'
println "this instance ${this.getClass().canonicalName} should be cicd.pipeline.SomePipeline"
}
// any code other than methods or variables with @Field
// annotation will be inside a implicit run method that is
// triggered likewise main method but isn't a static one
def localVar = 'foo'
println "It will not execute on constructor since it is on run: $localVar"
println "Method: ${org.codehaus.groovy.runtime.StackTraceUtils.sanitize(new Throwable()).stackTrace[0].methodName}"
println "this instance ${this.getClass().canonicalName} should be cicd.pipeline.SomePipeline"
如果我要使用 Java 冗长的语法,我必须将几乎所有内容都包装在 class SomePipeline
中,这在 groovy 中是隐含的,这就是我想要的脚本语法保留。
我意识到 this.getClass().superclass.canonicalName
当外部 Jenkins 管道是 groovy.lang.Script
并且当内部管道是 org.jenkinsci.plugins.workflow.cps.CpsScript
并且基于 this resource 我能够详细说明以下解决方案:
abstract class CustomScript extends org.jenkinsci.plugins.workflow.cps.CpsScript {
public CustomScript() {
// do something here, it will always execute regardless
// serialization, and before everything
}
}
@groovy.transform.BaseScript CustomScript baseScript
就是这样,按预期工作!当然你可以更好地阐述这个解决方案,以减少重复和避免inner-classes,但我会留给你想象。