-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
[core] Isolate classloaders for runtime and auxclasspath #680
Conversation
- We will now always load classes from auxclasspath during typeresolution, even if we have a class with the same name in PMD's classpath - This prevents conflicts when using different versions of the same dependencies
@@ -543,7 +543,7 @@ private void parseSingleRuleNode(RuleSetReferenceId ruleSetReferenceId, RuleSetB | |||
if (attribute == null || "".equals(attribute)) { | |||
throw new IllegalArgumentException("The 'class' field of rule can't be null, nor empty."); | |||
} | |||
Rule rule = (Rule) classLoader.loadClass(attribute).newInstance(); | |||
Rule rule = (Rule) RuleSetFactory.class.getClassLoader().loadClass(attribute).newInstance(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change in particular means users can no longer write custom Java rules within their project's codebase / auxclasspath and apply them. This feature was undocumented and unsupported.
Custom rules can be written, but must be part of PMD's execution classpath.
@jsotuyod Is this a fix for the build problem described in #679?
This sounds totally correct - I wouldn't have expected to be implemented otherwise. But it was... With this PR, the classes need to be on the execution classpath, but the rulesets still can be on the auxclasspath, which is wrong, I think. I don't know, why we use the auxclasspath in the RuleSetFactory at all. It looks like, it was a wrong fix some time ago, for the problem, that PMD didn't find a rule/ruleset (because it's easier to change the auxclasspath -> command line option, than to change the execution class path -> shell script). One point to the classloading: The maven plugin configures the Thread's context classloader - which might make a difference - not sure. I'm not sure, whether we really need the change for the parent-last strategy. It would only make a difference, if the same class is multiple times on the auxclasspath... |
@adangel yes, this addresses the issue on #679, I was finally able to reproduce it even from outside Maven. You are right, the ruleset can be in the auxclasspath. I believe the reason why we give a classloader to the rule set factory is here: It can probably be worked out more elegantly.
If a project uses any dependency we use, but a different version, they will have a conflict. Suppose someone is using |
@jsotuyod Ok, understood the issue why parent-last. But: Should the execution classpath ever end up in the auxclasspath, like it currently always does? https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/PMDConfiguration.java#L191-L196 (either classpath is null or set via the method you mentioned for ant) We probably should only have on the auxclasspath, whatever is given as the auxclasspath configuration option + the standard java base classpath (java.lang.*, etc.) / bootclasspath. |
@adangel I thought about it, but I don't know if we can get a hold of the same "boot classloader" as the one being used to run PMD. Otherwise I see 2 issues:
Code such as this will fail the exact same way: I'm uncertain if setting the parent classloader to |
// First, check if the class has already been loaded | ||
Class<?> c = findLoadedClass(name); | ||
if (c == null) { | ||
if (c == null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nothing harmful, but the null check is done twice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Bad copy-paste on my part
@adangel I confirm, We could, request that classloader's parent, and that one DOES only resolve JRE classes, but I am not sure how reliable that is... I can't find documentation saying this behavior is standard. That parent classloader is a |
- ResourceLoader is now instantiable, and we can tell which classloader to use to get resources - We will always use the execution classloader, or just add the paths added by ant, but *never* the auxclasspath - The classpath added by Ant won't get into the auxclasspath either
@adangel I reworked how we load rulesets. In doing so we now enforce both rules and rulesets are only in the execution classpath. As for typeresolution, we keep the newly introduced parent-last approach to avoid issues. I'm no longer adding Please review it, and provide feedback on the open issue on which parent classloader to use for typeresolution. |
Completely agree - this would be a no-go.
Probably not reliable :) At least, the documentation about the So, let's stay with the parent-last approach for resolving classing during typeresolution. I like, how you reworked ruleset loading with using the resource loader! Nice! |
typeresolution, even if we have a class with the same name in PMD's
classpath
dependencies