如何在build步骤的config.jelly中使用optionalBlock

时间:2012-10-23 06:48:26

标签: java jenkins hudson jelly

我在创建构造函数时遇到问题,Jenkins可以调用一些源自Jelly表单的JSON数据。为了进行测试,我使用mvn hpi:create创建了一个最小的Jenkins插件,并跟随两个自定义文件:

的src /主/资源/富/海德/詹金斯/插件/ OptionalBlockSampleBuilder / config.jelly

<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<f:block>
    <table>
        <f:optionalBlock name="enableText" title="Enable optional text" checked="${instance.enableText}">
            <f:entry title="Optional text" field="text">
                <f:textbox />
            </f:entry>
        </f:optionalBlock>
    </table>
</f:block>

的src /主/爪哇/富/海德/詹金斯/插件/ OptionalBlockSampleBuilder.java

package foo.hyde.jenkins.plugins;

public class OptionalBlockSampleBuilder extends hudson.tasks.Builder {

    public final String text;
    public final boolean enableText;

    @org.kohsuke.stapler.DataBoundConstructor
    public OptionalBlockSampleBuilder(String text, Boolean enableText) {
        this.text = text;
        this.enableText = (enableText != null) && enableText;
    }

    @Override
    public boolean perform(hudson.model.AbstractBuild build, hudson.Launcher launcher, hudson.model.BuildListener listener) {
        listener.getLogger().println("OptionalBlockSampleBuilder " + enableText + "/" + text);
        return true;
    }

    @hudson.Extension
    public static final class DescriptorImpl extends hudson.tasks.BuildStepDescriptor<hudson.tasks.Builder> {
        public boolean isApplicable(Class<? extends hudson.model.AbstractProject> aClass) {
            return true;
        }
        public String getDisplayName() {
            return "Optional Block Sample";
        }
    }
}

我正在构建针对pom.xml父<groupId>org.jenkins-ci.plugins</groupId><artifactId>plugin</artifactId><version>1.454</version>的构建,并且所有内容都构建完毕,Netbeans 6.9.1启动了Debug Jenkins,我可以使用此构建步骤创建一个作业。如果我不检查该复选框,一切都有效,我得到OptionalBlockSampleBuilder false/null到作业的控制台输出。

但是,如果我选中复选框并添加文本,那么当它尝试调用我的构造函数时,保存/应用作业配置会从Jenkins代码的深度中提供此异常:

java.lang.RuntimeException:
  Failed to instantiate class
    foo.hyde.jenkins.plugins.OptionalBlockSampleBuilder 
  from {
    "enableText":{"text":"xx"},
    "kind":"foo.hyde.jenkins.plugins.OptionalBlockSampleBuilder",
    "stapler-class":"foo.hyde.jenkins.plugins.OptionalBlockSampleBuilder"
    }

必须有一个简单的解决方法。我尝试了很多不同的更改,并试图了解其他插件如何使用它,最后创建了这个最小的测试插件。如何修复它以使optionalBlock工作?

2 个答案:

答案 0 :(得分:15)

提示来自JSON数据:

{
"enableText":{"text":"xx"},
"kind":"foo.hyde.jenkins.plugins.OptionalBlockSampleBuilder",
"stapler-class":"foo.hyde.jenkins.plugins.OptionalBlockSampleBuilder"
}

您可以在此处看到enableText包含子属性text。这意味着f:optionalBlock实际上期望块中包含的所有字段的封装 - 当检查块时,您将收到封装字段类的实例;取消选中时,该字段将为null。要正确使用optionalBlock,您需要@DataBoundConstructor接受封装整个optionalBlock的单个可空类实例。例如:

private String text;

@DataBoundConstructor
public MyClass(EnableTextBlock enableText)
{
    if (enableText != null)
    {
        this.text = enableText.text;
    }
}

public static class EnableTextBlock
{
    private String text;

    @DataBoundConstructor
    public EnableTextBlock(String text)
    {
        this.text = text;
    }
}

请注意,在这种情况下,enableText字段实际上是EnableTextBlock类的实例,其中包含子属性text。这将满足在表单中发送的JSON对象。


相反,如果您只需要一个具有复选框以启用该字段输入的字段,您可能需要考虑使用f:optionalProperty标记,该标记将处理该单字段封装您。但是,在许多情况下,实际上需要optionalBlock来配置多个字段,在这种情况下,封装类 - 如上所示 - 通常是正确的方法。

封装类不必是静态内部类;它可能是你的包中的一个单独的类,但重要的是DataBoundConstructor应该接受一个与从表单传递的JSON结构相匹配的参数。

答案 1 :(得分:10)

或者您可以将inline标记添加到optionalBlock,如下所示:

<f:optionalBlock inline="true">

如果存在inline,则在提交时,可折叠部分不会被分组为单独的JSON对象。