-
Notifications
You must be signed in to change notification settings - Fork 916
Generate DelegatingS3Client #3745
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
Conversation
@@ -53,7 +53,7 @@ public TypeSpec poetSpec() { | |||
TypeSpec.Builder result = PoetUtils.createClassBuilder(className); | |||
|
|||
result.addSuperinterface(interfaceClass) | |||
.addAnnotation(SdkInternalApi.class) | |||
.addAnnotation(SdkProtectedApi.class) |
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 would need to be an SdkPublicApi if it's going to be used by someone other than our team (e.g. the crypto tools teams).
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.
Updated to PublicApi
TypeSpec.Builder result = PoetUtils.createClassBuilder(className); | ||
|
||
result.addSuperinterface(interfaceClass) | ||
.addAnnotation(SdkProtectedApi.class) |
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.
Same here: SdkPublicApi?
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.
updated
|
||
result.addSuperinterface(interfaceClass) | ||
.addAnnotation(SdkProtectedApi.class) | ||
.addModifiers(Modifier.ABSTRACT, Modifier.PUBLIC) |
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.
Does it need to be abstract? Are there unimplemented methods?
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 all methods are implemented except serviceName. One benefit of using abstract is that people can't initialize it directly, which is not the intended use-case.
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.
serviceName() in SdkClient is unimplemented
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.
Any reason not to implement serviceName()
? I feel like it shouldn't differ in subclasses?
Also, should we create a subclass of the delegating class in our codegen generated classes test module, so that if we fail to override a method, it'll fail compilation in our project instead of in our customer's?
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.
implemented serviceName in DelegatingSyncClientClass
.addField(FieldSpec.builder(interfaceClass, "delegate") | ||
.addModifiers(Modifier.PROTECTED, Modifier.FINAL) | ||
.build()) |
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.
Nit: Should we encapsulate this field and let them use a method for accessing it (e.g. delegate()
)? It's probably not a big deal for this class, since I don't expect internals of this one to change, but I'm being picky here so that we don't start thinking this is great practice in other contexts.
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.
makes sense, encapsulated field and added delegate() method
if (model.getCustomizationConfig().getUtilitiesMethod() != null) { | ||
result.addMethod(utilitiesMethod()); | ||
} |
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 pattern sets off some warning signs in my mind: If we add something like utilities or waiters in the future, how will we remember to add them here as well? I'm worried we'd have to wait for someone to report that we forgot to implement them. That seems likely.
Can we refactor things so that isn't possible? I can think of some patterns, but you know the code better, so you might have better ideas.
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.
Refactored and made poetSpec final in SyncClientInterface as discussed. Created various methods that are called in poetSpec
return MethodSpec.constructorBuilder() | ||
.addModifiers(Modifier.PUBLIC) | ||
.addParameter(interfaceClass, "delegate") | ||
.addStatement("this.delegate = delegate") |
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.
Should we Validate.paramNotNull(delegate, "delegate")
?
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 Validate in constructor
|
||
public class DelegatingAsyncClientClass extends AsyncClientInterface { | ||
|
||
private static final String DELEGATE = "delegate"; |
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 feels kind of silly. Should we just inline it? I think the principal of not having magic constants applies to where the constants aren't self-describing. E.g. 24 instead of HOURS_PER_DAY. This particular case feels redundant.
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.
reverted back to inline
if (opModel.hasStreamingInput() || opModel.hasStreamingOutput()) { | ||
String variableName = opModel.hasStreamingInput() ? SYNC_STREAMING_INPUT_PARAM : SYNC_STREAMING_OUTPUT_PARAM; | ||
return builder.addStatement("return delegate.$N($N, $N)", | ||
opModel.getMethodName(), | ||
opModel.getInput().getVariableName(), | ||
variableName); | ||
} | ||
|
||
if (opModel.hasEventStreamInput() && opModel.hasEventStreamOutput()) { | ||
return builder.addStatement("return delegate.$N($N, $N, $N)", | ||
opModel.getMethodName(), | ||
opModel.getInput().getVariableName(), | ||
EVENT_PUBLISHER_PARAM_NAME, | ||
SYNC_STREAMING_OUTPUT_PARAM); | ||
} | ||
|
||
if (opModel.hasEventStreamInput() || opModel.hasEventStreamOutput()) { | ||
String variableName = opModel.hasEventStreamInput() ? EVENT_PUBLISHER_PARAM_NAME : EVENT_RESPONSE_HANDLER_PARAM_NAME; | ||
return builder.addStatement("return delegate.$N($N, $N)", | ||
opModel.getMethodName(), | ||
opModel.getInput().getVariableName(), | ||
variableName); | ||
} |
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.
nit: any way to just copy the delegate method name and parameters from the incoming MethodSpec.Builder, since the caller already has it figured out?
Something like:
builder.addStatement("return delegate.$N($L)",
opModel.getMethodName(),
builder.parameters.stream().map(p -> p.name).collect(joining(", "));
(I haven't tested this, I could be way off).
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.
that worked seamlessly! :)
MethodSpec delegate = MethodSpec.methodBuilder("delegate") | ||
.addModifiers(PUBLIC) | ||
.addStatement("return this.delegate") | ||
.returns(SdkClient.class) | ||
.build(); |
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.
nit: should this and the constructor be in addAdditionalMethods
?
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.
moved to addAdditionalMethods, same for DelegatingSyncClientClass
.addField(FieldSpec.builder(interfaceClass, "delegate") | ||
.addModifiers(PRIVATE, FINAL) | ||
.build()) |
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.
nit: should this be in addFields?
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.
moved to addFields, same for DelegatingSyncClientClass
return delegate.streamingInputOutputOperation(streamingInputOutputOperationRequest, requestBody); | ||
return delegate | ||
.streamingInputOutputOperation(streamingInputOutputOperationRequest, requestBody, asyncResponseTransformer); |
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.
Oops, looks like some of these were broken before?
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.
yup i noticed they were off in the diff
public void close() { | ||
delegate.close(); | ||
public final String serviceName() { | ||
return SERVICE_NAME; |
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.
should we delegate the serviceName method?
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.
updated to return delegate.serviceName()
/** | ||
* <p> | ||
* Performs a post operation to the query service and has no output | ||
* </p> | ||
* | ||
* @param aPostOperationRequest | ||
* @return Result of the APostOperation operation returned by the service. | ||
* @throws InvalidInputException | ||
* The request was rejected because an invalid or out-of-range value was supplied for an input parameter. | ||
* @throws SdkException | ||
* Base class for all exceptions that can be thrown by the SDK (both service and client). Can be used for | ||
* catch all scenarios. | ||
* @throws SdkClientException | ||
* If any client side error occurs such as an IO related failure, failure to get credentials, etc. | ||
* @throws JsonException | ||
* Base class for all service exceptions. Unknown exceptions will be thrown as an instance of this type. | ||
* @sample JsonClient.APostOperation | ||
* @see <a href="https://docs.aws.amazon.com/goto/WebAPI/json-service-2010-05-08/APostOperation" target="_top">AWS | ||
* API Documentation</a> | ||
* | ||
* @deprecated This API is deprecated, use something else | ||
*/ |
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.
Is this changing the javadoc at all? If not, we can probably just rely on it being inherited?
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.
looks like its inherited already
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.
Great work!
SonarCloud Quality Gate failed. |
Part of S3 Encryption Client Integration
Motivation and Context
We have an existing DelegatingS3AsyncClient, but not one for Sync client
Modifications
Testing
Screenshots (if appropriate)
Types of changes
Checklist
mvn install
succeedsscripts/new-change
script and following the instructions. Commit the new file created by the script in.changes/next-release
with your changes.License