-
Notifications
You must be signed in to change notification settings - Fork 25.5k
Adjust jdk-api-extractor output to be compatible with the public-callers-finder #135824
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
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,39 @@ | ||
This tool scans the JDK on which it is running to extract its public accessible API. | ||
That is: | ||
- public methods (including constructors) of public, exported classes as well as protected methods of these if not final. | ||
- internal implementations (overwrites) of above. | ||
- public methods (including constructors) of public, exported classes as well as protected methods of non-final classes. | ||
- any overwrites of public methods of public, exported super classes and interfaces. | ||
|
||
The output of this tool is meant to be diffed against the output for another JDK | ||
version to identify changes that need to be reviewed for entitlements. | ||
The output is compatible with the `public-callers-finder` tool to calculate the | ||
public transitive surface of new additions. See the example below. | ||
|
||
The following `TAB`-separated columns are written: | ||
1. module name | ||
2. fully qualified class name (ASM style, with `/` separators) | ||
3. method name | ||
4. method descriptor (ASM signature) | ||
5. visibility (`PUBLIC` / `PROTECTED`) | ||
6. `STATIC` modifier or empty | ||
7. `FINAL` modifier or empty | ||
2. unused / empty (for compatibility with `public-callers-finder`) | ||
3. unused / empty (for compatibility with `public-callers-finder`) | ||
4. fully qualified class name (ASM style, with `/` separators) | ||
5. method name | ||
6. method descriptor (ASM signature) | ||
7. visibility (`PUBLIC` / `PROTECTED`) | ||
8. `STATIC` modifier or empty | ||
9. `FINAL` modifier or empty | ||
|
||
Usage example: | ||
```bash | ||
./gradlew :libs:entitlement:tools:jdk-api-extractor:run -Druntime.java=24 --args="api-jdk24.tsv" | ||
./gradlew :libs:entitlement:tools:jdk-api-extractor:run -Druntime.java=25 --args="api-jdk25.tsv" | ||
|
||
# diff the public apis | ||
diff -u libs/entitlement/tools/jdk-api-extractor/api-jdk24.tsv libs/entitlement/tools/jdk-api-extractor/api-jdk25.tsv > libs/entitlement/tools/jdk-api-extractor/api.diff | ||
|
||
# extract additions in the new JDK, these require the most careful review | ||
cat libs/entitlement/tools/jdk-api-extractor/api.diff | grep '^+[^+]' | sed 's/^+//' > api-jdk25-additions.tsv | ||
|
||
# review new additions next for critical ones that should require entitlements | ||
# once done, remove all lines that are not considered critical and run the public-callers-finder to report | ||
# the transitive public surface for these additions | ||
./gradlew :libs:entitlement:tools:public-callers-finder:run -Druntime.java=25 --args="api-jdk25-additions.tsv true" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. for followup: can we make this use the latest jdk (or maybe the bundled?) so we don't have to specify it? And why There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
that's mostly for reference in the examples, I'll update the docs to mention it will default to the bundled JDK if not provided There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
That's how gradle run passes args to the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah I see, this is a task created by the gradle application plugin. You can have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll follow up with a separate PR to simplify how to invoke these tools. @mark-vieira any advice? |
||
``` | ||
|
||
### Optional arguments: | ||
|
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.
Why public class and not protected class? What does this class represent (a short javadoc would be nice)?
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.
PROTECTED
refers to methods, that's only used by the jdk-api-extractor. The class had to be public in this case.I can add a comment for that 👍
@ldematte maybe you could also chime in here, this part of the old
public-callers-finder
was a bit confusing.fromPermissions
is invoked as follows:elasticsearch/libs/entitlement/tools/public-callers-finder/src/main/java/org/elasticsearch/entitlement/tools/publiccallersfinder/FindUsagesClassVisitor.java
Lines 123 to 128 in 7cbc236
so being exported is a requirement for
PUBLIC_CLASS
in addition to either extending a public interface or being public:elasticsearch/libs/entitlement/tools/common/src/main/java/org/elasticsearch/entitlement/tools/ExternalAccess.java
Lines 27 to 48 in 7cbc236
isExternallyAccessible
seems to be to restrictive as it requiresPUBLIC_CLASS
. That practically excludes all classes that are not exported but which are externally accessible via exported public interfaces (or similarly super classes), doesn't it?elasticsearch/libs/entitlement/tools/common/src/main/java/org/elasticsearch/entitlement/tools/ExternalAccess.java
Lines 50 to 53 in 7cbc236
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.
I think you are right: looking at the code you posted, it seems to me that
PUBLIC_CLASS
isaccessibleViaInterfaces || (classAccess & ACC_PUBLIC) != 0
, but alsopackageExported
.The fix here is maybe not too complicated: the boolean
accessibleViaInterfaces
should be changed to be true only ifmoduleExports.contains(getPackageName(interfaceName)
(I think that is not the case currently?), and passed separately.Then we can change
PUBLIC_CLASS
to be true ifpackageExported && (classAccess & ACC_PUBLIC) != 0
ORaccessibleViaInterfaces
.Or something similar.
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 @ldematte , I'll follow up with a separate PR for this 👍
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.
I wanted to give this a go, unfortunately it is more involved. Having a closer look, i'm seeing a couple if issues:
moduleExports.contains(getPackageName(interfaceName)
is already checked, but not necessarily correct. the interface might belong to another module.superName
needs to be treated the same way as an interfaceaccessibleViaInterfaces
currently applies to all public methods. In case of interfaces likeAutoClosable
that could be very misleading, reporting far too much.I'll create a separate issue for this.
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.
Yep, that's why I think we need to do that when we compute and pass
accessibleViaInterfaces
(so at the call side, not here).You might be right with superName; I acted under the assumption that were the JDK wants to expose something with an internal implementation it does so via interfaces, but it might be that they use e.g. abstract classes.
And yes, this need to be per-method, which I think is going to be the most complex part.
I want this to be correct, but not sure how urgent it is; probably we'd like to have it correct before JDK 26?
I wonder if this could be a good "first issue", e.g. something for onboarding? It's entitlements related, but this being a separate project it could be quite self-contained
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.
yes, I agree... I'm also leaning towards postponing this ➕
regarding
accessibleViaInterfaces
:findAccessibility
currently uses the exports of the current class rather than the exports of the module the interface originates from.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.
Yeah, I was suspecting this was the case :/