[Plugin dev] Handling JSONObject from config.jelly

131 views
Skip to first unread message

Tiago Lopes

unread,
Jun 20, 2016, 7:46:35 AM6/20/16
to Jenkins Developers

Hey,

 

 

 

I was using a the inline=”true” property on config.jelly to get the parsed parameters from config.jelly to my @DataBoundConstuctor but I now must remove this property.

 

So the problem is, How can I adapt my constructor to receive parsed parameters as well as JSONObject? Or what method should I call to handle the JSONObject?

 

 

I was trying with “@Override public boolean configure(…)” but it seems that method is only for global configuration, correct?

 

 

What is the simplest approach to solve this problem?

 

Config.jelly:

__________________________________________________________________________________________

<f:entry title="${%installation}" field="installation">

                                <f:select/>

                 </f:entry>

                 

                   

                <f:entry title="${%startingURL}" field="startingURL">

                               <f:textbox clazz="required"/>

                </f:entry> 

                   

                <f:section title="" name="genReport"> 

                               <f:optionalBlock title="${%generateReport}"  field="generateReport" <!--inline=”true” -->>

                                               <f:entry>

                                              

                                                               <f:entry field="reportName" title="Report title">

                                                                              <f:textbox/>

                                                              </f:entry>

                                                             

                                                               <f:entry field="htmlReport" title="HTML Report">

                                                                              <f:checkbox/>

                                                              </f:entry>

                                                             

                                                               <f:entry field="pdfReport" title="PDF Report">

                                                                              <f:checkbox/>

                                                              </f:entry>

                                

                                               </f:entry>

                               </f:optionalBlock>

                 </f:section>

               

__________________________________________________________________________________________

 

With the inline=”true”, this is working:

 

                @DataBoundConstructor

                public XBuilder(String installation, String startingURL,boolean generateReport, String reportName, boolean htmlReport, boolean pdfReport)

 

Without, “generateReport” is a JSONObject and thus the constructor is not working.

 

 

 

 

I figured I’d want something like this:

 

                                               JSONObject json = formData.getJSONObject("genReport");

                                               generateReport = json.getBoolean("generateReport");

                                               reportName = json.getString("reportName");

                                               htmlReport = json.getBoolean("htmlReport");

                                               pdfReport = json.getBoolean("pdfReport");

 

But which method do I use to implement this?

 

 

 

Thanks in advance.

 

Jesse Glick

unread,
Jun 20, 2016, 12:09:32 PM6/20/16
to Jenkins Dev
Avoid this low-level manipulation. Use proper databinding: create a
nested `Describable` object and use `f:property`.

Tiago Lopes

unread,
Jun 22, 2016, 6:52:36 AM6/22/16
to Jenkins Developers
I'm drowning, I kept digging as I didn't find the necessary information to implement your suggestion...

config.jelly:
_____________________________________________________________________
    <f:section title="">
        <f:optionalBlock title="${%generateReport}"  field="generateReport">
            <f:entry>
                       
                      <f:entry field="reportName" title="Report title">
                      <f:textbox/>
                  </f:entry>
                 
                      <f:entry field="htmlReport" title="HTML Report">
                      <f:checkbox/>
                  </f:entry>
                 
                  <f:entry field="pdfReport" title="PDF Report">
                      <f:checkbox/>
                  </f:entry>
     
            </f:entry>
        </f:optionalBlock>
     </f:section>
_____________________________________________________________________


Builder:
_____________________________________________________________________
    @DataBoundSetter
    public void setGenerateReport(JSONObject formData){   
        if(!formData.isNullObject() && !formData.isEmpty()){
            this.generateReport = true;   
            this.reportName = formData.getString("reportName");
            this.htmlReport = formData.getBoolean("htmlReport");
            this.pdfReport = formData.getBoolean("pdfReport");   
        }
        else
            this.generateReport = false;      
    }
_____________________________________________________________________



the problem now is that if the optionalBlock is unchecked (with data in the fields) and then checked, the values are lost (not being properly persisted)

any suggestion on how to fix this?

Jesse Glick

unread,
Jun 22, 2016, 1:45:08 PM6/22/16
to Jenkins Dev
You are doing too much work. Create a separate class extending
`AbstractDescribableImpl` with its own `config.jelly` and just use
`f:property` to include its configuration form. You do not need to use
low-level controls like `f:optionalBlock` or deal with raw JSON form
data.

Tiago Lopes

unread,
Jun 24, 2016, 11:50:00 AM6/24/16
to Jenkins Developers
I have implemented the separate class, I'm using <st:include ../> to include its config.jelly (it's not finding with the f:property [searching in the wrong package]) and it's working as before, meaning...

this did in no way solve my problem, actually made it more complex, as now I'm storing the values in a different class and not in the one where I need them, also, how come I don't need optionalBlock? what's the other option?

All I managed to do was include the configuration form, as it was, still no values being persisted.

Tiago Lopes

unread,
Jun 24, 2016, 12:36:32 PM6/24/16
to Jenkins Developers
I need a work around for the optionalBlock, because if it's checked everything works well, the instance of my separate class (GenerateReport) is created and passed to the builder's @DataBoundConstructor, however I have set "@Nullable GenerateReport generateReport" because if the optionalBlock is not checked the <st:include > is never called and no object is created, thus losing the values from the generate report config.jelly... how can I handle this (persist them regardless of optionalBlock option)?

or replace the optionalBlock with a similar option to hide/show certain fields?

Jesse Glick

unread,
Jun 24, 2016, 2:18:47 PM6/24/16
to Jenkins Dev
On Fri, Jun 24, 2016 at 11:50 AM, Tiago Lopes <tlope...@gmail.com> wrote:
> it's not finding with the f:property [searching in the
> wrong package])

Not sure what this means. You do not need low-level `st:include` here.

> now
> I'm storing the values in a different class and not in the one where I need
> them

A simple `.` notation in Java to access the field from a nested object.

Look at `ui-samples-plugin`.

Tiago Lopes

unread,
Jun 25, 2016, 9:16:57 AM6/25/16
to Jenkins Developers
I have pushed the plugin to github at https://github.com/tlopesPT/appscanstandard-plugin

With that setup, f:property is not finding the right config.jelly because it's searching in the current package (AppScanStandardBuilder) and not in the one associated with the separate class (AppScanStandardGenerateReport).

I'm receiving and handling the nested object in the builder's constructor but still have issues with no object being created if the optionalBlock is disabled.

Jesse Glick

unread,
Jun 28, 2016, 12:20:27 PM6/28/16
to Jenkins Dev
On Sat, Jun 25, 2016 at 9:16 AM, Tiago Lopes <tlope...@gmail.com> wrote:
> I'm receiving and handling the nested object in the builder's constructor
> but still have issues with no object being created if the optionalBlock is
> disabled.

What is the issue? That is the intended behavior. If the block is
disabled, the nested object is null.

Tiago Lopes

unread,
Jun 28, 2016, 2:30:21 PM6/28/16
to Jenkins Developers
The issue is that the values in the data field are not persisting, if I uncheck, exit config, go back to config and check the block, the data fields are empty.

I want the data to remain bound to the field regardless of the block being enabled or disabled.

Tiago Lopes

unread,
Jun 29, 2016, 9:51:41 AM6/29/16
to Jenkins Developers
Do I need to setup an overridden newInstance(req,resp) or doConfigSubmit(req,resp) ?

Jesse Glick

unread,
Jun 29, 2016, 7:05:50 PM6/29/16
to Jenkins Dev
On Tue, Jun 28, 2016 at 2:30 PM, Tiago Lopes <tlope...@gmail.com> wrote:
> The issue is that the values in the data field are not persisting, if I
> uncheck, exit config, go back to config and check the block, the data fields
> are empty.

Well, that is the general behavior of optional blocks in Jenkins. If
you want to go back to some earlier version of the configuration, try
restoring a backup.

Tiago Lopes

unread,
Jun 29, 2016, 7:14:43 PM6/29/16
to Jenkins Developers
I understand that, but if I'm not using [inline="true"] then the data is persisted regardless of the optionalBlock checked value because the data is passed as independent Strings,

I'm trying to achieve a similar behavior without the inline property, because of an issue tracked here https://github.com/jenkinsci/jenkins/pull/2193#issuecomment-229435236


thanks for the help so far.
Reply all
Reply to author
Forward
0 new messages