Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Register OptionHandlers through META-INF/services/annotations and Annotation Indexer rather than META-INF/services and Commons Discovery #9980

Merged
merged 3 commits into from
Jan 4, 2025

Conversation

basil
Copy link
Member

@basil basil commented Nov 15, 2024

CLICommand has two mechanisms for registering OptionHandlers:

  1. /**
    * Auto-discovers {@link OptionHandler}s and add them to the given command line parser.
    */
    protected void registerOptionHandlers() {
    try {
    for (Class c : Index.list(OptionHandlerExtension.class, Jenkins.get().pluginManager.uberClassLoader, Class.class)) {
    Type t = Types.getBaseClass(c, OptionHandler.class);
    CmdLineParser.registerHandler(Types.erasure(Types.getTypeArgument(t, 0)), c);
    }
    } catch (IOException e) {
    throw new Error(e);
    }
    }
    which uses the Annotation Indexer to index (based on an @OptionHandlerExtension annotation) and load the handlers.
  2. static {
    // register option handlers that are defined
    ClassLoaders cls = new ClassLoaders();
    Jenkins j = Jenkins.getInstanceOrNull();
    if (j != null) { // only when running on the controller
    cls.put(j.getPluginManager().uberClassLoader);
    ResourceNameIterator servicesIter =
    new DiscoverServiceNames(cls).findResourceNames(OptionHandler.class.getName());
    final ResourceClassIterator itr =
    new DiscoverClasses(cls).findResourceClasses(servicesIter);
    while (itr.hasNext()) {
    Class h = itr.nextResourceClass().loadClass();
    Class c = Types.erasure(Types.getTypeArgument(Types.getBaseClass(h, OptionHandler.class), 0));
    CmdLineParser.registerHandler(c, h);
    }
    }
    }
    which uses a combination of Kohsuke's META-INF/services generator to index (based on a @MetaInfServices(OptionHandler.class) annotation) the handlers and Commons Discovery to load the handlers.

There is a desire to reduce and eventually remove usages of Commons Discovery, since it is an abandoned and unmaintained library. The second of these two code paths cannot be replaced with ServiceLoader, since ServiceLoader insists on having a zero-argument public constructor for each service, and OptionHandler violates this contract. So if getting rid of Commons Discovery is desired, then the second code path must be deprecated in favor of the first. Once all usages of the second code path in core and plugins have been converted to the first code path, and once those releases have been sufficiently deployed, then the second code path can be deleted.

This PR migrates from the second pattern to the first pattern in Jenkins core. I am aware of two cases where the second pattern is used in plugins:

I am not aware of any usages in proprietary plugins.

Implementation

The second code path was being invoked at class loading time (a single time) and loading the bulk of the handlers in practice there. The first code path was being invoked when each CLI command was invoked, which was simultaneously too frequent (a handler only needs to be registered once) and too late: HelpCommandTest started failing because we could not show the help until the handler had been loaded, and the handler was not loaded until the command was first invoked. We solved the latter problem by unifying the invocation of these two code paths from the same place: initialization of the class. In practice, this means that the existing handlers are loaded after this PR at the same time (and frequency) as they were before this PR, minimizing regressions and increasing consistency.

Testing done

mvn clean verify -Dtest=hudson.cli.AddJobToViewCommandTest,hudson.cli.BuildCommandTest,hudson.cli.CancelQuietDownCommandTest,hudson.cli.ClearQueueCommandTest,hudson.cli.ComputerStateTest,hudson.cli.ConnectNodeCommandTest,hudson.cli.ConsoleCommandTest,hudson.cli.CopyJobCommandTest,hudson.cli.CreateJobCommandTest,hudson.cli.CreateNodeCommandTest,hudson.cli.CreateViewCommandTest,hudson.cli.DeleteBuildsCommandTest,hudson.cli.DeleteJobCommandTest,hudson.cli.DeleteNodeCommandTest,hudson.cli.DeleteViewCommandTest,hudson.cli.DisablePluginCommandTest,hudson.cli.DisconnectNodeCommandTest,hudson.cli.EnableJobCommandTest,hudson.cli.EnablePluginCommandTest,hudson.cli.GetJobCommandTest,hudson.cli.GetNodeCommandTest,hudson.cli.GetViewCommandTest,hudson.cli.GroovyshCommandTest,hudson.cli.HelpCommandTest,hudson.cli.InstallPluginCommandTest,hudson.cli.ListJobsCommandTest,hudson.cli.ListPluginsCommandTest,hudson.cli.OfflineNodeCommandTest,hudson.cli.OnlineNodeCommandTest,hudson.cli.QuietDownCommandTest,hudson.cli.ReloadConfigurationCommandTest,hudson.cli.ReloadJobCommandTest,hudson.cli.RemoveJobFromViewCommandTest,hudson.cli.RunRangeCommand2Test,hudson.cli.RunRangeCommandTest,hudson.cli.SetBuildDescriptionCommandTest,hudson.cli.SetBuildDisplayNameCommandTest,hudson.cli.UpdateNodeCommandTest,hudson.cli.UpdateViewCommandTest,hudson.cli.ViewManipulationTestBase,hudson.cli.WaitNodeOfflineCommandTest,hudson.cli.WaitNodeOnlineCommandTest,hudson.model.ComputerSetTest,hudson.model.ItemsTest,hudson.model.listeners.ItemListenerTest,hudson.util.RobustReflectionConverterTest,jenkins.cli.StopBuildsCommandTest,jenkins.model.JenkinsManagePermissionTest,jenkins.model.NodeListenerTest,jenkins.model.RunIdMigratorTest,jenkins.model.ScriptListenerTest,jenkins.security.Security3314Test,jenkins.security.Security3448Test,lib.form.PasswordTest

Proposed changelog entries

N/A

Proposed upgrade guidelines

N/A

Submitter checklist

Preview Give feedback

Desired reviewers

@mention

Before the changes are marked as ready-for-merge:

Maintainer checklist

Preview Give feedback

… Annotation Indexer rather than `META-INF/services` and Commons Discovery
@basil basil added the skip-changelog Should not be shown in the changelog label Nov 15, 2024
Comment on lines +569 to +572
for (Class c : Index.list(OptionHandlerExtension.class, Jenkins.get().pluginManager.uberClassLoader, Class.class)) {
Type t = Types.getBaseClass(c, OptionHandler.class);
CmdLineParser.registerHandler(Types.erasure(Types.getTypeArgument(t, 0)), c);
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved from lines 535-537, so please do not review this as original code authored by me.

@@ -35,7 +35,6 @@

/**
* {@link OptionHandler}s that should be auto-discovered.
* TODO is this actually necessary? {@code @MetaInfServices(OptionHandler.class)} seems to work as well.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Answer: it is actually necessary if we want to remove Commons Discovery someday, as ServiceLoader cannot work with the OptionHandler classes that have no public zero-argument constructor.

@timja
Copy link
Member

timja commented Jan 2, 2025

@basil is this waiting on anything?

@basil
Copy link
Member Author

basil commented Jan 2, 2025

Not that I know of.

@timja
Copy link
Member

timja commented Jan 2, 2025

/label ready-for-merge


This PR is now ready for merge, after ~24 hours, we will merge it if there's no negative feedback.

Thanks!

@comment-ops-bot comment-ops-bot bot added the ready-for-merge The PR is ready to go, and it will be merged soon if there is no negative feedback label Jan 2, 2025
@krisstern krisstern merged commit 519eb19 into jenkinsci:master Jan 4, 2025
16 checks passed
janfaracik added a commit to janfaracik/jenkins that referenced this pull request Jan 5, 2025
commit 76d4bb8
Author: Jan Faracik <[email protected]>
Date:   Sun Jan 5 11:01:47 2025 +0000

    Fix in case of null provider

commit ebb6831
Author: Jan Faracik <[email protected]>
Date:   Sat Jan 4 15:23:03 2025 +0000

    Lint

commit 11e4b8d
Author: Jan Faracik <[email protected]>
Date:   Sat Jan 4 14:48:20 2025 +0000

    Init

commit 519eb19
Merge: 908030e b3b5a69
Author: Kris Stern <[email protected]>
Date:   Sat Jan 4 16:01:19 2025 +0800

    Merge pull request jenkinsci#9980 from basil/OptionHandlerExtension

    Register `OptionHandler`s through `META-INF/services/annotations` and Annotation Indexer rather than `META-INF/services` and Commons Discovery

commit 908030e
Merge: d3e8908 fc4a567
Author: Kris Stern <[email protected]>
Date:   Sat Jan 4 16:00:31 2025 +0800

    Merge pull request jenkinsci#10026 from mtughan/allow-immutable-collections

    Allow all immutable List subclasses from Java 11

commit d3e8908
Author: Jesse Glick <[email protected]>
Date:   Fri Jan 3 05:43:27 2025 -0500

    Correcting API documentation of `builds` vs. `allBuilds` (jenkinsci#10112)

commit 89f48c5
Merge: 238c498 e1dff1a
Author: Kris Stern <[email protected]>
Date:   Fri Jan 3 18:00:18 2025 +0800

    Merge pull request jenkinsci#10106 from timja/ballColorTd-table

    [JENKINS-74868] Use new build status symbols in multi branch projects

commit 238c498
Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Date:   Thu Jan 2 20:32:04 2025 -0800

    Update dependency io.jenkins.plugins:design-library to v342 (jenkinsci#10111)

    Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

commit 75410bc
Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Date:   Thu Jan 2 10:45:55 2025 -0800

    Update dependency io.jenkins.plugins:json-api to v20241224 (jenkinsci#10110)

    Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

commit 1aa9c57
Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Date:   Thu Jan 2 10:44:50 2025 -0800

    Update Yarn to v4.6.0 (jenkinsci#10109)

    Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

commit e1dff1a
Author: Tim Jacomb <[email protected]>
Date:   Tue Dec 31 19:46:12 2024 +0000

    Adjust test

commit 5fd9f51
Author: Tim Jacomb <[email protected]>
Date:   Mon Dec 30 22:20:15 2024 +0000

    [JENKINS-74868] Use new build status symbols in multi branch projects

commit b3b5a69
Merge: 33d8280 d73c0ea
Author: Basil Crow <[email protected]>
Date:   Tue Dec 17 10:19:22 2024 -1000

    Merge branch 'master' into OptionHandlerExtension

commit fc4a567
Author: Michael Tughan <[email protected]>
Date:   Wed Dec 4 15:15:13 2024 -0500

    Allow all immutable List subclasses from Java 11

    A previous commit specifically allowed one of the two subclasses used by
    `List.of` and `List.copyOf`, but not the other, which can result in
    unexpected errors and bugs. Add the other to the default allow list of
    classes to avoid these.

commit 33d8280
Merge: a1c8c83 9965f04
Author: Tim Jacomb <[email protected]>
Date:   Sun Dec 8 08:32:24 2024 +0000

    Merge branch 'master' into OptionHandlerExtension

commit a1c8c83
Author: Basil Crow <[email protected]>
Date:   Fri Nov 15 10:58:26 2024 -0800

    Register `OptionHandler`s through `META-INF/services/annotations` and Annotation Indexer rather than `META-INF/services` and Commons Discovery
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ready-for-merge The PR is ready to go, and it will be merged soon if there is no negative feedback skip-changelog Should not be shown in the changelog
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants