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

Supporting wildcard and keys fn in JmesPathRuntime #5198

Conversation

cenedhryn
Copy link
Contributor

@cenedhryn cenedhryn commented May 7, 2024

Motivation and Context

Modifications

  • Modifies the wildcard function, which has existed in the runtime but never been used in waiters, to accept lists which is according to specs: https://jmespath.org/specification.html#wildcard-expressions
  • Adds a keys function which can return the names of SdkField members in an SdkPojo
  • [INCORRECT] Catches errors when evaluating OperationContextParams at runtime and returns null instead, logging errors. It's complex functionality especially when sourcing parameters from a customization config. We can re-evaluate this behavior when model traits are available.
  • Fixes a minor bug in project to filter null values from the result. Another alternative would be to just filter nulls when returning stringValues but I can't think of a Java use-case where we want to preserve the null when evaluating an expression.
  • Also changed to filter nulls for stringValues, because it is correct.

Testing

Tested in codegen-generated-classes-test

Testing with incomplete objects where the projected field does not exist in a list projection member didn't work with the approximation of and SdkPojo in the test class. Instead, switched to a modeled pojo that correctly returns null for a field instead of not recognizing field.

@cenedhryn cenedhryn requested a review from a team as a code owner May 7, 2024 22:23
@@ -125,6 +128,8 @@ public TypeSpec poetSpec() {
.addAnnotation(SdkInternalApi.class)
.addSuperinterface(ExecutionInterceptor.class);

b.addField(logger());
Copy link
Contributor Author

Choose a reason for hiding this comment

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

In general, wondering if we should add logic to only generate operation context params if they exist, potentially including the logger dependency. Do not have time to check exactly what is generated under which circumstances for this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added removing empty methods to follow up task

String jmesPathString = ((JrsString) value.getValue()).getValue();
CodeBlock addParam = CodeBlock.builder()
.add("params.$N(", setterName)
.add(jmesPathGenerator.interpret(jmesPathString, "input"))
.add(matchToParameterType(key))
.add(")")
.build();

Copy link
Contributor

Choose a reason for hiding this comment

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

I believe that doing a try catch exception here will absorb any issue in this case we should be doing a fail-fast rather than fail safe for following reasons

  1. We should immediately fail if there are issues while extracting the value using JmesPathRuntime

Example : Currently the customization was specified as "value": "Delete.Objects[*].key" , note that it should have have been "value": "Delete.Objects[*].Key"
Because of this the Binding is not happening and it gets ignored silently with a warning.
However , if we have an exception we get IllegalArgumentException: No such field: key upfront

java.lang.IllegalArgumentException: No such field: key
	at software.amazon.awssdk.services.s3.jmespath.internal.JmesPathRuntime$Value.lambda$field$4(JmesPathRuntime.java:297)
	at java.util.Optional.orElseThrow(Optional.java:290)
  1. This might cause issue while AuthSchemes tries to use it , Auth scheme will not have a way to know if its params were Null because of Exception or if user had not set it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed

assertThat(jmesRuntimeEvents).extracting("message.formattedMessage")
.usingElementComparator(stringContains())
.contains("emptyKeyListOfString", "missingFieldListOfString")
.contains("No such field: NonExistingMember");
Copy link
Contributor

Choose a reason for hiding this comment

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

If there is a NonExistingMember defined should we get an exception?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed


Arguments.of("List of String parameter from wildcard works as expected", new TestAssertion(
p -> assertThat(p.wildcardKeyListOfString()).isNotEmpty().hasSize(2)
.containsExactly("StringMemberS1", "StringMemberS2"))),
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we write a test case when only one of the List has entry

Source Json

{
 "bucket": "someBucket",
 "delete": {
   "objects": [
     {
       "id": "a",
       "key": "One"
     },
     {
       "id": "b"
     }
   ]
 }
}

JMESPath Expression : delete.objects[*].key

Output

[
  "One"
]

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, had to update the test harness to handle this case.

@joviegas
Copy link
Contributor

joviegas commented May 9, 2024

Can we please add test cases in Acceptor too.

@Test(expected = UnsupportedOperationException.class)
public void testSliceExpressionWithNoNumbers2() {
testConversion("[:]", "");
}
@Test(expected = UnsupportedOperationException.class)
public void testSliceExpressionWithNoNumbers3() {
testConversion("[::]", "");
}
@Test(expected = UnsupportedOperationException.class)
public void testSliceExpressionWithStartNumber2() {
testConversion("[10:]", "");
}
@Test(expected = UnsupportedOperationException.class)
public void testSliceExpressionWithStopNumber2() {
testConversion("[:10]", "");
}
@Test(expected = UnsupportedOperationException.class)
public void testSliceExpressionWithStartStopNumber2() {
testConversion("[10:20]", "");
}
@Test(expected = UnsupportedOperationException.class)
public void testSliceExpressionWithStartNumber3() {
testConversion("[10::]", "");
}
@Test(expected = UnsupportedOperationException.class)
public void testSliceExpressionWithStopNumber3() {
testConversion("[:10:]", "");
}
@Test(expected = UnsupportedOperationException.class)
public void testSliceExpressionWithStartStopNumber3() {
testConversion("[10:20:]", "");
}
@Test(expected = UnsupportedOperationException.class)
public void testSliceExpressionWithStartStopStepNumber3() {
testConversion("[10:20:30]", "");
}
@Test(expected = UnsupportedOperationException.class)
public void testSliceExpressionWithStepNumber3() {
testConversion("[::30]", "");
}
@Test(expected = UnsupportedOperationException.class)
public void testCurrentNode() {
testConversion("@", "");
}

Since we are supporting it now can we add corresponding test for above cases .

Or if we only support [*] then add test for [*] and keep the remaining assertion as it was before

@cenedhryn
Copy link
Contributor Author

Can we please add test cases in Acceptor too.

@Test(expected = UnsupportedOperationException.class)
public void testSliceExpressionWithNoNumbers2() {
testConversion("[:]", "");
}
@Test(expected = UnsupportedOperationException.class)
public void testSliceExpressionWithNoNumbers3() {
testConversion("[::]", "");
}
@Test(expected = UnsupportedOperationException.class)
public void testSliceExpressionWithStartNumber2() {
testConversion("[10:]", "");
}
@Test(expected = UnsupportedOperationException.class)
public void testSliceExpressionWithStopNumber2() {
testConversion("[:10]", "");
}
@Test(expected = UnsupportedOperationException.class)
public void testSliceExpressionWithStartStopNumber2() {
testConversion("[10:20]", "");
}
@Test(expected = UnsupportedOperationException.class)
public void testSliceExpressionWithStartNumber3() {
testConversion("[10::]", "");
}
@Test(expected = UnsupportedOperationException.class)
public void testSliceExpressionWithStopNumber3() {
testConversion("[:10:]", "");
}
@Test(expected = UnsupportedOperationException.class)
public void testSliceExpressionWithStartStopNumber3() {
testConversion("[10:20:]", "");
}
@Test(expected = UnsupportedOperationException.class)
public void testSliceExpressionWithStartStopStepNumber3() {
testConversion("[10:20:30]", "");
}
@Test(expected = UnsupportedOperationException.class)
public void testSliceExpressionWithStepNumber3() {
testConversion("[::30]", "");
}
@Test(expected = UnsupportedOperationException.class)
public void testCurrentNode() {
testConversion("@", "");
}

Since we are supporting it now can we add corresponding test for above cases .

Or if we only support [*] then add test for [*] and keep the remaining assertion as it was before

There a few things I want to clean up in a follow-up PR - some renaming, excluding codegen of empty methods etc. I will add this to that list.

Copy link

sonarcloud bot commented May 10, 2024

Quality Gate Failed Quality Gate failed

Failed conditions
77.0% Coverage on New Code (required ≥ 80%)

See analysis details on SonarCloud

@cenedhryn cenedhryn merged commit 14dd8d1 into feature/StringArrayEndpointParams May 10, 2024
14 of 17 checks passed
@cenedhryn cenedhryn deleted the salande/add-runtime-support-wildcard branch May 10, 2024 20:51
cenedhryn added a commit that referenced this pull request May 13, 2024
* feat(StringArrayEndpointParams) Codegen String Array Enpoint params and Auth schemes params based on end-point-rule-set.json. (#5122)

* Support Customization string array endpoint params for S3 access grants, until all SDKs add support for string array. (#5137)

* new(StringArrayEndpointParams) Codegeneration of OperationContextParams defined for a Operation. (#5146)

* Extracting existing JMESPath runtime to a separate class (#5155)

* new(StringArrayEndpointParams) Customization of Operation Context params and adding customizations for S3 (#5159)

* Converts endpoint param list of string to list of value (#5169)

* Generates JmesPath expressions for operation context parameters (#5172)

* Supporting wildcard and keys fn in JmesPathRuntime (#5198)

* Adds functional tests for list of string auth params (#5216)

* Changelog

---------

Co-authored-by: John Viegas <70235430+joviegas@users.noreply.github.com>
Co-authored-by: John Viegas <joviegas@amazon.com>
akidambisrinivasan pushed a commit to akidambisrinivasan/aws-sdk-java-v2 that referenced this pull request Jun 28, 2024
* feat(StringArrayEndpointParams) Codegen String Array Enpoint params and Auth schemes params based on end-point-rule-set.json. (aws#5122)

* Support Customization string array endpoint params for S3 access grants, until all SDKs add support for string array. (aws#5137)

* new(StringArrayEndpointParams) Codegeneration of OperationContextParams defined for a Operation. (aws#5146)

* Extracting existing JMESPath runtime to a separate class (aws#5155)

* new(StringArrayEndpointParams) Customization of Operation Context params and adding customizations for S3 (aws#5159)

* Converts endpoint param list of string to list of value (aws#5169)

* Generates JmesPath expressions for operation context parameters (aws#5172)

* Supporting wildcard and keys fn in JmesPathRuntime (aws#5198)

* Adds functional tests for list of string auth params (aws#5216)

* Changelog

---------

Co-authored-by: John Viegas <70235430+joviegas@users.noreply.github.com>
Co-authored-by: John Viegas <joviegas@amazon.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants