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

Add ExtensionList#lookupFirst convenience method #3021

Merged
merged 4 commits into from Oct 28, 2017

Conversation

daniel-beck
Copy link
Member

I find myself typing ExtensionList.lookup(Whatever.class).get(Whatever.class) a lot to get the singleton instance for a registered @Extension.

If I'm not the only one (and haven't missed something obvious), maybe this is useful? @jenkinsci/code-reviewers More to tell me there's an obvious alternative I've missed.

Copy link
Member

@oleg-nenashev oleg-nenashev left a comment

Choose a reason for hiding this comment

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

Yes, it is something we really need. Probably makes sense to refactor bits within the core.

A more strict method would be also useful:

public static @CheckForNull <U,T> T lookup(Class<U> extensionType, Class<T> implementationType) {
        return lookup(extensionType).get(implementationType);
 }

*
* @param type The type to look up.
* @param <U>
* @return
Copy link
Member

Choose a reason for hiding this comment

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

Empty param/return should be removed or documented

@daniel-beck
Copy link
Member Author

daniel-beck commented Sep 14, 2017

more strict method

But what would you even gain from that? This one simplifies things by getting rid of redundancy. Your proposal saves ~4 characters?

@oleg-nenashev
Copy link
Member

But what would you even gain from that? This one simplifies things by getting rid of redundancy. Your proposal saves ~4 characters?

It also avoids the "YOLO" mode of lookupFirst (). But probably you could just remove "first" from the method name, because the call guarantees to have only one result IIUC

@daniel-beck
Copy link
Member Author

because the call guarantees to have only one result IIUC

No, as I may pass e.g. Builder.class.

@oleg-nenashev
Copy link
Member

Builder... Uh oh, it should not be stored in the extension implementation list imho. But if it is true now, then the current method naming is correct of course

Copy link
Member

@oleg-nenashev oleg-nenashev left a comment

Choose a reason for hiding this comment

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

Javadoc still needs to be fixed

@daniel-beck
Copy link
Member Author

@oleg-nenashev

it should not be stored in the extension implementation list imho

Good point, then whatever the Descriptor type for that is, if any. The point is, the list can be any @Extension type, including super types, from a single implementation to e.g. Descriptor. To get a singleton instance, you may lookup(Super).get(Specific) or just lookup(Specific).get(Specific).

Notably, lookup(Super).get(Super) already works and just gets whatever entry first fits.

@oleg-nenashev oleg-nenashev added the needs-comments-resolved Comments in the PR need to be addressed before it can be considered for merging label Sep 18, 2017
@daniel-beck daniel-beck removed the needs-comments-resolved Comments in the PR need to be addressed before it can be considered for merging label Sep 28, 2017
@daniel-beck
Copy link
Member Author

@oleg-nenashev Done

@daniel-beck daniel-beck added the needs-more-reviews Complex change, which would benefit from more eyes label Sep 28, 2017
@daniel-beck
Copy link
Member Author

This is the kind of change where I expect @jglick to tell me it's stupid and redundant due to something I didn't know about, so asking him for review.

Copy link
Member

@amuniz amuniz left a comment

Choose a reason for hiding this comment

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

👍

Copy link
Member

@jglick jglick left a comment

Choose a reason for hiding this comment

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

Needs some sample calls, for example of Uptime from AbstractProject._poll.

*
* @since TODO
*/
public static @CheckForNull <U> U lookupFirst(Class<U> type) {
Copy link
Member

Choose a reason for hiding this comment

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

@CheckForNull here more or less defeats the real need for this, which is for cases where you expect that there must be one instance. I would rather say something like

ExtensionList<U> all = lookup(type);
if (all.size() != 1) throw new IllegalStateException(…);
return all.get(0);

And name it something like lookUpSingleton.

See for example GlobalConfigurationCategory.get, Jenkins.doConfigExecutorsSubmit call to MasterBuildConfiguration, JenkinsLocationConfiguration.get, UserDetailsCache.get, ad nauseam. Basically just Find Usages on ExtensionList.get(Class). If you know that the singleton has been registered, then you expect to be able to load it without null checks. Maybe existing calls in fact just assume that the result is not null, meaning FindBugs would complain if we actually let it.

@daniel-beck daniel-beck added the work-in-progress The PR is under active development, not ready to the final review label Sep 30, 2017
@daniel-beck daniel-beck self-assigned this Sep 30, 2017
@daniel-beck daniel-beck removed the work-in-progress The PR is under active development, not ready to the final review label Oct 2, 2017
public static @Nonnull <U> U lookupSingleton(Class<U> type) {
ExtensionList<U> all = lookup(type);
if (all.size() != 1) {
throw new IllegalStateException("Expected 1 instance of " + type.getName() + " but got " + all.size());
Copy link
Member

Choose a reason for hiding this comment

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

Needs to be Javadoced. throws would be also useful.
In the case of this method, I agree that RuntimeException is a right approach.

Copy link
Member

Choose a reason for hiding this comment

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

Javadoced 😄 Love English language.

Copy link
Member Author

Choose a reason for hiding this comment

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

@oleg-nenashev It's mentioned in https://github.com/jenkinsci/jenkins/pull/3021/files#diff-e3f986a0854b9b724f4e12690cdeeac3R423 and I see no point in adding it to the signature. It's a runtime exception after all.

Copy link
Member

Choose a reason for hiding this comment

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

Still a good practice; helpful for Javadoc viewers.

/**
 * …
 * @throws IllegalStateException if there are no instances, or more than one
 */

@oleg-nenashev
Copy link
Member

I see no point in adding it to the signature. It's a runtime exception after all.

@daniel-beck The only point of it is to have just another place where the API users are warned about that in IDE. Nothing else

Copy link
Member

@oleg-nenashev oleg-nenashev left a comment

Choose a reason for hiding this comment

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

OK though @throws tag in Javadoc exits for a reason. 🐝

public static @Nonnull <U> U lookupSingleton(Class<U> type) {
ExtensionList<U> all = lookup(type);
if (all.size() != 1) {
throw new IllegalStateException("Expected 1 instance of " + type.getName() + " but got " + all.size());
Copy link
Member

Choose a reason for hiding this comment

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

Still a good practice; helpful for Javadoc viewers.

/**
 * …
 * @throws IllegalStateException if there are no instances, or more than one
 */

if (mbc!=null)
mbc.configure(req,json);
MasterBuildConfiguration mbc = ExtensionList.lookupSingleton(MasterBuildConfiguration.class);
mbc.configure(req,json);
Copy link
Member

Choose a reason for hiding this comment

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

or even inline var

@daniel-beck
Copy link
Member Author

Addressed @jglick's review comments (including one identical to one by @oleg-nenashev ), so I think this is ready to go into the next weekly.

Copy link
Member

@oleg-nenashev oleg-nenashev left a comment

Choose a reason for hiding this comment

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

🐝 Ready to go.

@oleg-nenashev oleg-nenashev added ready-for-merge The PR is ready to go, and it will be merged soon if there is no negative feedback and removed needs-more-reviews Complex change, which would benefit from more eyes labels Oct 21, 2017
@oleg-nenashev
Copy link
Member

retriggering CI

@oleg-nenashev
Copy link
Member

@daniel-beck Sorry, I've forgotten to reopen it :( Was in my TODO list for the next weekly anyway

@oleg-nenashev
Copy link
Member

CI hates us :(

@oleg-nenashev
Copy link
Member

🚢 🇮🇹

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
Projects
None yet
4 participants