modifying a @DataboundConstructor

43 views
Skip to first unread message

Goyot, Martin

unread,
Jul 8, 2020, 4:17:03 AM7/8/20
to jenkin...@googlegroups.com
Hi there,

On the OAuth plugin I'm working on, I'd like to modify the @DataboundConstructor for the Realm. Issue is, if I modify it, whether be the signature or the inners of the function, the deserialization for previous instances won't work anymore hence breaking any previous installation of the plugin.

How am I supposed to proceed in such particular cases, when I need to update this constructor without breaking any config already set on Jenkins instances?

Here is some code for reference:

public class MySecurityRealm extends SecurityRealm {
    private String clientId;
    private Secret clientSecret;

    @DataBoundConstructor
    public MySecurityRealm(String clientId, String clientSecret) {
        this.clientId = Util.fixEmptyAndTrim(clientId);
        this.setClientSecret(Util.fixEmptyAndTrim(clientSecret));
    }
}

Thanks in advance !
Martin

Ullrich Hafner

unread,
Jul 8, 2020, 4:34:25 AM7/8/20
to Jenkins Developers

Am 08.07.2020 um 10:16 schrieb Goyot, Martin <martin...@enalean.com>:

Hi there,

On the OAuth plugin I'm working on, I'd like to modify the @DataboundConstructor for the Realm. Issue is, if I modify it, whether be the signature or the inners of the function, the deserialization for previous instances won't work anymore hence breaking any previous installation of the plugin.

How am I supposed to proceed in such particular cases, when I need to update this constructor without breaking any config already set on Jenkins instances?


The serialization does not use the constructor. You need to provide a readResolve method that will map the old fields to the new fields.

Here is some code for reference:

public class MySecurityRealm extends SecurityRealm {
    private String clientId;
    private Secret clientSecret;

    @DataBoundConstructor
    public MySecurityRealm(String clientId, String clientSecret) {
        this.clientId = Util.fixEmptyAndTrim(clientId);
        this.setClientSecret(Util.fixEmptyAndTrim(clientSecret));
    }
}

Thanks in advance !
Martin

--
You received this message because you are subscribed to the Google Groups "Jenkins Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jenkinsci-de...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/jenkinsci-dev/CA%2Bb6JB-wx%3D%2BPRcXb057-9idgZkL7kYw%3DSvmSsaR-mxRJ9_g96A%40mail.gmail.com.

Goyot, Martin

unread,
Jul 8, 2020, 4:51:38 AM7/8/20
to jenkin...@googlegroups.com
Thanks Ullrich!

Do you have any pointer for me as to how to proceed?

Ullrich Hafner

unread,
Jul 8, 2020, 9:50:27 AM7/8/20
to Jenkins Developers
https://wiki.jenkins.io/display/JENKINS/Hint+on+retaining+backward+compatibility

It would help if you could describe the exact changes in your class (old vs. new version).

Matt Sicker

unread,
Jul 8, 2020, 9:51:09 AM7/8/20
to jenkin...@googlegroups.com
There's an automatic converter between String and Secret when loading
XML files via XStream in Jenkins. The only compatibility concerns you
should have here are for any code that directly calls that constructor
or uses the string value of the secret.
> To view this discussion on the web visit https://groups.google.com/d/msgid/jenkinsci-dev/CA%2Bb6JB8J4-AHbMyb%3DWDATiXGvtnuw6YcEcB-pV0SPc4Ju6xNkA%40mail.gmail.com.



--
Matt Sicker
Senior Software Engineer, CloudBees

Goyot, Martin

unread,
Jul 8, 2020, 9:58:04 AM7/8/20
to jenkin...@googlegroups.com
Sure,

so the old version was:


public class MySecurityRealm extends SecurityRealm {
    private String clientId;
    private Secret clientSecret;

    @DataBoundConstructor
    public MySecurityRealm(String clientId, String clientSecret) {
        this.clientId = Util.fixEmptyAndTrim(clientId);
        this.setClientSecret(Util.fixEmptyAndTrim(clientSecret));
    }
}

And the new is:


public class MySecurityRealm extends SecurityRealm {
    private MyConfiguration configuration;

    @DataBoundConstructor
    public MySecurityRealm(String clientId, String clientSecret) {
        this.configuration = new MyConfiguration(
          Util.fixEmptyAndTrim(clientId),
          Secret.fromString(Util.fixEmptyAndTrim(clientSecret))
        );
    }
}

Something along those lines.

Daniel Beck

unread,
Jul 8, 2020, 4:32:34 PM7/8/20
to Jenkins Developers
You want something like this:

-----

public class MySecurityRealm extends SecurityRealm {
private MyConfiguration configuration;
private transient String clientId;
private transient Secret clientSecret;

private Object readResolve() {
if (clientId != null || clientSecret != null) {
this.configuration = new MyConfiguration(…)
clientId = null;
clientSecret = null;
}
return this;
}

@DataBoundConstructor
public MySecurityRealm(String clientId, String clientSecret) {
this.configuration = new MyConfiguration(
Util.fixEmptyAndTrim(clientId),
Secret.fromString(Util.fixEmptyAndTrim(clientSecret))
);
}
}

-----

For examples, search for readResolve in Jenkins and plugin source code.
> To view this discussion on the web visit https://groups.google.com/d/msgid/jenkinsci-dev/CA%2Bb6JB9Bz-YyMi9oC1mrRWZdDtteCszf7FmpCOxHEQLRmrKRQw%40mail.gmail.com.

Goyot, Martin

unread,
Jul 9, 2020, 4:03:12 AM7/9/20
to jenkin...@googlegroups.com
Thank you very much! I'll try this!

Reply all
Reply to author
Forward
0 new messages