-
Notifications
You must be signed in to change notification settings - Fork 1.1k
feat(gapic-generator-java): Extract resource name heuristicly #12207
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
Open
blakeli0
wants to merge
18
commits into
main
Choose a base branch
from
feature/heuristic-filter
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
3b82880
fix: Handle null server address
blakeli0 da23a42
Filter heuristic resource name extraction by proto package
blakeli0 366075b
Revert "fix: Handle null server address"
blakeli0 2e56cee
Remove empty line at the end of EndpointContextTest.java
blakeli0 4efed5a
tests: fix tests
blakeli0 409522d
tests: update integration tests goldens.
blakeli0 877fec6
fix: Update the heuristic logic per latest discussion.
blakeli0 fbd911f
Merge branch 'main' into feature/heuristic-filter
blakeli0 1b4b5e9
fix: update docs.
blakeli0 c18077a
fix: update version logic
blakeli0 523573e
fix: update javadocs
blakeli0 3edd75f
fix: Revert necessary changes.
blakeli0 a819980
fix: fix integration tests
blakeli0 ad9bc73
fix: fix integration tests
blakeli0 3bf58f0
docs: add comments.
blakeli0 e5142f1
fix: simplify logics to get the start of the binding.
blakeli0 67168ad
fix: simplify logics to get the start of the binding.
blakeli0 f63e3eb
fix: format
blakeli0 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -296,6 +296,124 @@ public Set<String> vars() { | |
| return bindings.keySet(); | ||
| } | ||
|
|
||
| /** Returns the set of resource literals. A resource literal is a literal followed by a binding */ | ||
| // For example, projects/{project} is a literal/binding pair and projects is a resource literal. | ||
| public Set<String> getResourceLiterals() { | ||
| Set<String> canonicalSegments = new java.util.LinkedHashSet<>(); | ||
| boolean inBinding = false; | ||
| for (int i = 0; i < segments.size(); i++) { | ||
| Segment seg = segments.get(i); | ||
| if (seg.kind() == SegmentKind.BINDING) { | ||
| inBinding = true; | ||
| } else if (seg.kind() == SegmentKind.END_BINDING) { | ||
| inBinding = false; | ||
| } else if (seg.kind() == SegmentKind.LITERAL) { | ||
| String value = seg.value(); | ||
| if (value.matches("^v\\d+[a-zA-Z0-9]*$")) { // just in case | ||
| continue; | ||
| } | ||
| if (inBinding) { | ||
| // This is for extracting "projects" and "locations" from named binding | ||
| // {name=projects/*/locations/*} | ||
| canonicalSegments.add(value); | ||
| } else if (i + 1 < segments.size() && segments.get(i + 1).kind() == SegmentKind.BINDING) { | ||
| // This is for regular cases projects/{project}/locations/{location} | ||
| canonicalSegments.add(value); | ||
| } | ||
| } | ||
| } | ||
| return canonicalSegments; | ||
| } | ||
|
|
||
| /** | ||
| * Returns the canonical resource name string. A canonical resource name is extracted from the | ||
| * template by finding the version literal, then finding the last binding that is a | ||
| * literal/binding pair or named binding, and then extracting the segments between the version | ||
| * literal and the last binding. | ||
| */ | ||
| // For example, projects/{project} is a literal/binding pair. {bar=projects/*/locations/*/bars/*} | ||
| // is a named binding. | ||
| // If a template is /compute/v1/projects/{project}/locations/{location}, known resources are | ||
| // "projects" and "locations", the canonical resource name is | ||
| // projects/{project}/locations/{location}. See unit tests for all cases. | ||
| public String getCanonicalResourceName(Set<String> knownResources) { | ||
| if (knownResources == null) { | ||
| return ""; | ||
| } | ||
|
|
||
| int startIndex = 0; | ||
| for (int i = 0; i < segments.size(); i++) { | ||
| Segment seg = segments.get(i); | ||
| if (seg.kind() == SegmentKind.LITERAL) { | ||
| String value = seg.value(); | ||
| if (value.matches("^v\\d+[a-zA-Z0-9]*$")) { | ||
| startIndex = i + 1; | ||
|
Contributor
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. Is this if statement guaranteed to end up setting the start index?
Contributor
Author
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. Yes, if there are not versions found, the start index would be 0. |
||
| break; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| int lastValidEndBindingIndex = -1; | ||
| // Iterate from the end of the segments to find the last valid resource binding. | ||
| // Searching backwards allows us to stop immediately once the last valid pair is found. | ||
| for (int i = segments.size() - 1; i >= 0; i--) { | ||
| Segment seg = segments.get(i); | ||
|
|
||
| // We are looking for the end of a binding (e.g., "}" in "{project}" or "{name=projects/*}") | ||
| if (seg.kind() == SegmentKind.END_BINDING) { | ||
| int bindingStartIndex = -1; | ||
| int literalCountInBinding = 0; | ||
| boolean isValidPair = false; | ||
|
|
||
| // Traverse backwards to find the start of this specific binding | ||
| // and count the literals captured inside it. | ||
| for (int j = i - 1; j >= 0; j--) { | ||
| Segment innerSeg = segments.get(j); | ||
| if (innerSeg.kind() == SegmentKind.BINDING) { | ||
| bindingStartIndex = j; | ||
| break; | ||
| } else if (innerSeg.kind() == SegmentKind.LITERAL) { | ||
| literalCountInBinding++; | ||
| } | ||
| } | ||
|
|
||
| if (bindingStartIndex != -1) { | ||
| // 1. If the binding contains any literals, it is considered a valid named resource | ||
| // binding. | ||
| if (literalCountInBinding > 0) { | ||
| isValidPair = true; | ||
| } else if (bindingStartIndex > 0) { | ||
| // 2. For simple bindings like "{project}", the binding itself has no inner literal | ||
| // resources. | ||
| // Instead, we check if the literal segment immediately preceding it (e.g., "projects/") | ||
| // is a known resource. | ||
| Segment prevSeg = segments.get(bindingStartIndex - 1); | ||
| if (prevSeg.kind() == SegmentKind.LITERAL && knownResources.contains(prevSeg.value())) { | ||
| isValidPair = true; | ||
| } | ||
| } | ||
|
|
||
| if (isValidPair) { | ||
| // We successfully found the last valid binding! Record its end index and terminate the | ||
| // search. | ||
| lastValidEndBindingIndex = i; | ||
| break; | ||
| } | ||
| // The current binding wasn't a valid resource pair. | ||
| // Skip over all inner segments of this invalid binding so we don't evaluate them again. | ||
| i = bindingStartIndex; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if (lastValidEndBindingIndex == -1 || lastValidEndBindingIndex < startIndex) { | ||
| return ""; | ||
| } | ||
|
|
||
| List<Segment> canonicalSegments = segments.subList(startIndex, lastValidEndBindingIndex + 1); | ||
| return toSyntax(canonicalSegments, true).replace("=*}", "}"); | ||
| } | ||
|
|
||
| /** | ||
| * Returns a template for the parent of this template. | ||
| * | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Can we also add a comment line saying what would be the output given an exemplary template?
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.
Added