-
Notifications
You must be signed in to change notification settings - Fork 297
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
How to check top level classes which are unnecessary public? #583
Comments
As public classes are by definition accessible outside of their packages, I assume that you meant accessed... 😉 In this case, the following rule (using @ArchTest
ArchRule not_unnecessarily_public = classes()
.that().areTopLevelClasses().and(are(onlyUsedFromSamePackage()))
.should().notBePublic();
static DescribedPredicate<JavaClass> onlyUsedFromSamePackage() {
return DescribedPredicate.describe("only used from same package", javaClass ->
javaClass.getDirectDependenciesToSelf().stream().allMatch(dependency ->
dependency.getOriginClass().getPackage().equals(javaClass.getPackage())
)
);
} |
Yes, accessed is the proper word :) Thanks @hankem. I was testing something similar before, but the case is not so straightforward. I still have several "false positive" findings like:
//this class have to be public because StaticNestedClass is public and accessed outside but not_unnecessarily_public test is caching it
public class TopLevelClass {
...
public static class StaticNestedClass {
....
}
}
//this class have to be public because CONSTANT is public and accessed outside but not_unnecessarily_public test is caching it
public class TopLevelClass {
public static final String CONSTANT = "Thanks!";
}
//this class have to be public because FIRST, SECOND ara public and accessed outside but not_unnecessarily_public test is caching them
public enum SomeEnum {
FIRST, SECOND
}
//this class have to be public because doSomethingCommon() is public and accessed outside but not_unnecessarily_public test is caching it
public final class Utilities {
public static String doSomethingCommon() {
...
}
} How should I improve the |
Sounds like you're running up against some of the same limitations that I encountered when trying to detect unused classes and methods. I suspect you can adapt the rules I used there for your purpose as well. Some of the limitation I ran up against are:
In short you won't be able to completely detect all cases correctly (yet), so it might be best to combine your rule with |
Thanks @timtebeek for the tips. I will be following changes in ArchUnit regarding this. |
@prondzyn, I agree that my suggested starting point has false positives – some of them, as @timtebeek pointed out (🙏), require new features in ArchUnit, others like §2 in #583 (comment) ("[primitive] constant") unfortunately can't be resolved due to bytecode limitations. For §1 in #583 (comment) ("static nested class"), I believe that one could work out a more sophisticated solution. Regarding §3 ("enum") and §4 ("static method"): I'd expect that the rule suggested in #583 (comment) would handle those correctly. Can you provide a (counter) example? |
In my case the "enum" §3 is because one particular enum type is used as generic type like: For "static method" §4 I have for example a util class: public final class XssStripper {
public static String stripXss(String param) {
return param;
}
} and call to the method: public <T> Optional<String> test(Selector<T> selector) {
return selector.getFilters()
.map(XssStripper::stripXss);
} |
Ah, I see. 👍 Thanks! Then I was just mislead by the categorization, and these issues are those noted in #583 (comment):
|
With the recent additions in 0.23 I think it should now be possible to create a rule as described in this issue, without false positives. Would that be enough to close this issue? |
I would also guess that the recent additions should have solved this, so I'm gonna close the issue for now. But feel free to reopen if there is still a problem! |
I have a question. I'm trying to compose rule which find classes that are public but are not accessible anywhere outside of its package. Unfortunately I'm stuck. Do you have any clues for that?
The text was updated successfully, but these errors were encountered: