-
Notifications
You must be signed in to change notification settings - Fork 866
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
DDB Enhanced adding ChainConverterProvider #1746
DDB Enhanced adding ChainConverterProvider #1746
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1746 +/- ##
============================================
+ Coverage 75.81% 76.28% +0.46%
Complexity 182 182
============================================
Files 1069 1073 +4
Lines 32030 32235 +205
Branches 2489 2516 +27
============================================
+ Hits 24285 24589 +304
+ Misses 6511 6411 -100
- Partials 1234 1235 +1
Continue to review full report at Codecov.
|
return new ChainConverterProvider(providers); | ||
} | ||
|
||
public Queue<AttributeConverterProvider> chainedProviders() { |
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 an [immutable] List would be the most appropriate collection to return here.
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 might have gone overboard with utilizing the same patterns as for the extension chains :-)
return this.providerChain.stream() | ||
.filter(provider -> provider.converterFor(enhancedType) != null) | ||
.map(p -> p.converterFor(enhancedType)) | ||
.findFirst().orElse(null); |
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: linebreak before second dot [.]
*/ | ||
@SdkInternalApi | ||
public final class ChainConverterProvider implements AttributeConverterProvider { | ||
private final Deque<AttributeConverterProvider> providerChain; |
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'd have chosen ArrayList here as it's simpler and perfectly well suited to the only way we use it which is to iterate through its items in order.
return converterClasses.length > 0 ? | ||
Optional.of((AttributeConverterProvider) newObjectSupplierForClass(converterClasses[0]).get()) : | ||
Optional.empty(); | ||
private static List<AttributeConverterProvider> converterProviderAnnotation(DynamoDbBean dynamoDbBean) { |
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.
The name of this method confuses me a bit. When I read it, I think that it's going to return the annotation object itself. Maybe call it 'createConverterProvidersFromAnnotation' ? or something like that.
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 chose the name because of the prior art of naming similar methods in the same class, called from that particular method. I am somewhat on the same page as you, but then I'd rename all of the 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.
Yes feel free to rename anything that doesn't make sense, I was just looking at your changes.
private List<AttributeConverterProvider> attributeConverterProviders = | ||
Collections.singletonList(ConverterProviderResolver.defaultConverterProvider()); |
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.
As a general pattern I avoid having the Builder own the defaults to things, I prefer to see that in the constructor of the object. It can be tested and is more reliable there. Ideally the builder should do absolutely nothing just collect information and pass it to the constructor.
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.
There is prior art here:
Lines 153 to 154 in c72d2b5
private List<DynamoDbEnhancedClientExtension> dynamoDbEnhancedClientExtensions = | |
new ArrayList<>(ExtensionResolver.defaultExtensions()); |
What should take precedence?
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.
There's also prior art for the other way
Line 85 in c72d2b5
this.attributeConverterProvider = builder.attributeConverterProvider != null ? |
The reality is we started off inconsistent and I believe we gravitated (at least I did) towards the way I'm now recommending.
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 like that pattern better too, for the reasons you wrote.
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.
Then I must set the list to null by default in the builder. Which is the best choice, null or using the default?
* Calling this method will override the default attribute converter provider | ||
* {@link DefaultAttributeConverterProvider}, which provides standard converters | ||
* for most primitive and common Java types, so that provider must included in the supplied list if it is to be | ||
* used. Providing an empty list here will cause no providers to get loaded. |
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 this would be a good place to insert a code example of how to 'best' use the default one (since there are a number of different valid ways to instantiate it). I think we should encourage people to use the most friendly one.
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'd be not using the annotation at all. Right?!
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.
StaticTableSchema should not use the annotation. I was thinking the defaultProvider() method on the base interface if it's still there, otherwise DefaultAttributeConverterProvider.create() or whatever.
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.
Sorry, I was still in the bean space. Yes.
Class<? extends AttributeConverterProvider>[] converterProviders() | ||
default { NoAttributeConverterProviderOverride.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.
Maybe we should mention in the javadoc that passing an empty list as converterProviders results in no converters at all.
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'll add that
final class NoAttributeConverterProviderOverride implements AttributeConverterProvider { | ||
@Override | ||
public <T> AttributeConverter<T> converterFor(EnhancedType<T> enhancedType) { | ||
return null; |
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 'throw UnsupportedOperationException("This is not a real converter [or something to that effect]") ' would be more appropriate
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.
You're right, will update
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.
Actually let's just get rid of this and use the real DefaultAttributeConverterProvider
Class<? extends AttributeConverterProvider>[] converterProviders() | ||
default { NoAttributeConverterProviderOverride.class }; | ||
|
||
final class NoAttributeConverterProviderOverride implements AttributeConverterProvider { |
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.
By inheritance, this class is effectively public (which is why you're able to use it elsewhere in the code). That means we should either javadoc it or move it out of here and into internal namespace. I think I favor the latter but open to discussion.
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.
Offline agreed to just use DefaultAttriburteConverterProvider instead (which will be a public class in this PR)
@@ -80,7 +77,7 @@ | |||
* Given an input, this will identify a converter that can convert the specific Java type and invoke it. If a converter cannot | |||
* be found, it will invoke a "parent" converter, which would be expected to be able to convert the value (or throw an exception). | |||
*/ | |||
@SdkInternalApi | |||
@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.
I think we should spruce up the javadoc a bit to celebrate this class' new status as 'public'. At a minimum mention (preferably with examples) how to use it in a StaticTableSchema builder and a BeanTableSchema annotation.
* converter provided by the table schema. | ||
* <p> | ||
* Note: | ||
* <ul> |
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 it'd be nice to give an example here of using a single custom converter provider with default as fallback (as we did in the StaticTableSchema example).
e2e5624
to
077b0a3
Compare
Kudos, SonarCloud Quality Gate passed! 0 Bugs |
Remove createBucketAlreadyExists test
Description
AttributeConverterProvider
that can hold any number of user-supplied AttributeConverterProviders and will match converters using strict precedence, first-come-first-served.AttributeConverter
for each attribute in the schemaStaticTableSchema
and forDynamoDbBeans
(BeanTableSchema
).For reference: Issue 35
Note: README updated separately in PR 1731.
Motivation and Context
Testing
Unit tested
Screenshots (if appropriate)
Types of changes
Checklist
mvn install
succeeds