1
1
** Design:** New Feature, ** Status:**
2
2
[ In Development] ( ../../../README.md )
3
3
4
- # SDK Tenets (unless you know better ones)
4
+ ## Tenets (unless you know better ones)
5
5
6
6
1 . Meeting customers in their problem space allows them to deliver value
7
7
quickly.
8
8
2 . Meeting customer expectations drives usability.
9
9
3 . Discoverability drives usage.
10
+ 4 . Providing a Java-focused experience for DynamoDB reduces the coding
11
+ effort required to integrate with DynamoDB.
12
+ 5 . Reusing the same nouns and verbs as the generated DynamoDB client
13
+ meets customer expectations.
14
+ 6 . Optimizing for cold-start performance allows customers the
15
+ convenience of using object mapping in a Lambda environment.
10
16
11
- # Project Tenets (unless you know better ones)
17
+ ## Problem
12
18
13
- 1 . Providing a Java-focused experience for DynamoDB reduces the coding
14
- effort required to integrate with DynamoDB.
15
- 2 . Reusing the same nouns and verbs as the generated DynamoDB client
16
- meets customer expectations.
17
- 3 . Optimizing for cold-start performance allows customers the
18
- convenience of using object mapping in a Lambda environment.
19
+ Customers on the AWS SDK for Java 2.x currently use the ` DynamoDbClient `
20
+ to communicate with DynamoDB. This client is generated from the model
21
+ provided by the DynamoDB team.
22
+
23
+ Because this client is generated, it does not provide an idiomatic Java
24
+ experience. For example: (1) the client represents numbers as ` String `
25
+ instead of the more idiomatic ` Number ` , (2) customers must manually
26
+ convert common Java data types like ` Instant ` into types supported by
27
+ DynamoDB, (3) customers that represent their DynamoDB objects using Java
28
+ objects must manually convert these objects into the item representation
29
+ supported by DynamoDB.
30
+
31
+ ## Existing Solutions
32
+
33
+ This problem is not currently addressed directly in the AWS SDK for Java
34
+ 2.x by any known third-party tool. In 1.11.x, several solutions exist,
35
+ including AWS's own Document and Mapper Clients.
36
+
37
+ ## Proposed Solution
38
+
39
+ The AWS SDK for Java will add a new "enhanced DynamoDB client" that
40
+ provides an alternative to the data-access portion of the generated
41
+ DynamoDB APIs. Control-plane operations like "create table" will not be
42
+ supported at launch, but may be added at a later time.
43
+
44
+ This enhanced client will make DynamoDB easier to use for Java customers
45
+ by:
46
+ 1 . Supporting conversions between Java objects and DynamoDB items
47
+ 2 . Supporting conversions between Java built-in types (eg. ` Instant ` )
48
+ and DynamoDB attribute value types
49
+ 3 . Directly supporting every data-plane operation of DynamoDB
50
+ 4 . Using the same verbs and nouns of DynamoDB
51
+
52
+ ## Implementation Overview
53
+
54
+ ** New Clients**
55
+
56
+ Two new client classes will be added:
57
+ ` DynamoDbEnhancedClient ` and ` DynamoDbEnhancedAsyncClient ` . These
58
+ classes act as a wrapper around the generated ` DynamoDbClient ` and
59
+ ` DynamoDbAsyncClient ` classes, to provide additional functionality on
60
+ top of that which can be provided by the generated clients.
61
+
62
+ ``` java
63
+ DynamoDbEnhancedClient enhancedClient =
64
+ DynamoDbEnhancedClient . builder()
65
+ .dynamoDbClient(DynamoDbClient . create())
66
+ .build();
67
+ ```
68
+
69
+ ** Table Abstraction**
70
+
71
+ ` DynamoDbEnhancedClient ` provides access to ` Table ` and ` MappedTable ` ,
72
+ and ` DynamoDbEnhancedAsyncClient ` provides access to ` AsyncTable ` , and
73
+ ` AsyncMappedTable ` abstractions.
74
+
75
+ The operations on these "tables" match the data-plane operations in the
76
+ low-level DynamoDB client. For example, because ` DynamoDbClient.putItem `
77
+ exists, ` Table.putItem ` will also exist.
78
+
79
+ ` Table ` and ` AsyncTable ` work with "items", described below.
80
+ ` MappedTable ` and ` AsyncMappedTable ` work with "objects", described
81
+ below. ` Table ` and ` MappedTable ` returning results synchronously, and
82
+ ` AsyncTable ` and ` AsyncMappedTable ` returning results asynchronously.
83
+
84
+ ``` java
85
+ Table booksTable = enhancedClient. table(" books" );
86
+ booksTable. putItem(... );
87
+
88
+ MappedTable mappedBooksTable = enhancedClient. mappedTable(" books" );
89
+ mappedBooksTable. putItem(... );
90
+ ```
91
+
92
+ ** Item Abstraction**
93
+
94
+ The operations on ` Table ` and ` AsyncTable ` work on ` Item ` s. An ` Item ` is
95
+ a user-friendly representation of the generated `Map<String,
96
+ AttributeValue>` . ` Item`s support automatic type conversion between Java
97
+ built-in types and DynamoDB-specific ` AttributeValue ` types.
98
+
99
+ ``` java
100
+ booksTable. putItem(Item . builder()
101
+ .putAttribute(" isbn" , " 0-330-25864-8" )
102
+ .putAttribute(" title" , " The Hitchhiker's Guide to the Galaxy" )
103
+ .putAttribute(" creationDate" , Instant . now())
104
+ .build());
105
+ ```
106
+
107
+ The ` Table ` and ` AsyncTable ` abstractions can be seen as a replacement
108
+ for the 1.11.x DynamoDB Document client.
109
+
110
+ ** Object Abstraction**
111
+
112
+ The operations on ` MappedTable ` and ` AsyncMappedTable ` work on Java
113
+ objects (at launch, Java beans). These objects are automatically
114
+ converted by the enhanced client to the generated `Map<String,
115
+ AttributeValue>` . It's likely that the ` MappedTable` and
116
+ ` AsyncMappedTable ` will use the ` Table ` and ` AsyncTable ` as an
117
+ implementation detail.
118
+
119
+ ``` java
120
+ Book book = new Book ();
121
+ book. setIsbn(" 0-330-25864-8" );
122
+ book. setTitle(" The Hitchhiker's Guide to the Galaxy" );
123
+ book. setCreationDate(Instant . now());
124
+ mappedBooksTable. putItem(book);
125
+ ```
126
+
127
+ The ` MappedTable ` and ` AsyncMappedTable ` abstractions can be seen as a
128
+ replacement for the 1.11.x DynamoDB Mapper client.
129
+
130
+ ** Type Conversion**
131
+
132
+ The core feature of the mapper is the ability to convert common Java
133
+ structures (e.g. Java beans) and types (e.g. ` Instant ` , ` Number ` ) into
134
+ DynamoDB attribute values.
135
+
136
+ These conversions are performed based on the types specified by the
137
+ customer. For example, the SDK will automatically convert any ` Number `
138
+ types specified by the customer (as an Item attribute) into a DynamoDB
139
+ number.
140
+
141
+ The customer has the ability to configure the type converters used at
142
+ the ` Item ` or ` DynamoDbEnhanced[Async]Client ` -level. This allows the
143
+ customer to add support for unsupported types, change the DynamoDB type
144
+ associated with a Java type (e.g. storing an ` Instant ` as a DynamoDB
145
+ string instead of a number), or to add support for custom POJO
146
+ conversion logic (i.e. other than Java beans). This also allows the
147
+ customer to provide a hard-coded converter for a specific object type
148
+ that performs more efficiently than the built-in reflection-based object
149
+ converter.
150
+
151
+ ## Features
152
+
153
+ ** Launch Features**
19
154
20
- # Project Introduction
155
+ These features are intended for inclusion at launch of the library.
21
156
22
- The enhanced DynamoDB client replaces the generated DynamoDB client with
23
- one that is easier for a Java customer to use. It does this by
24
- supporting conversions between Java objects and DynamoDB items, as well
25
- as converting between Java built-in types (eg. java.time.Instant) and
26
- DynamoDB attribute value types.
157
+ 1 . Support for all existing data plane operations: get, put, query,
158
+ update, scan, delete, batch get, batch put, transaction get, and
159
+ transaction put.
160
+ 2 . Support for ` [Async]Table ` and ` [Async]MappedTable ` , as described
161
+ above.
162
+ 3 . Support for bean-based representations in ` [Async]MappedTable ` .
163
+ 4 . Type converters for all Java built-in types that are currently
164
+ supported by [ Joda Convert] ( https://www.joda.org/joda-convert/ ) .
27
165
28
- The enhanced DynamoDB client intentionally does not attempt to simplify
29
- specific data access patterns, like relational or time-series data. It
30
- is within the scope of future projects to provide data access
31
- pattern-specific abstractions on top of the enhanced DynamoDB client
32
- and/or other AWS services.
166
+ | API | Feature | Development | Usability Study |
167
+ | --- | --- | --- | --- |
168
+ | Item | Get | Done | |
169
+ | | Put | Done | |
170
+ | | Query | | |
171
+ | | Update | | |
172
+ | | Scan | | |
173
+ | | Delete | | |
174
+ | | Batch Get | | |
175
+ | | Batch Put | | |
176
+ | | Transaction Get | | |
177
+ | | Transaction Put | | |
178
+ | Object | Get | | |
179
+ | | Put | | |
180
+ | | Query | | |
181
+ | | Update | | |
182
+ | | Scan | | |
183
+ | | Delete | | |
184
+ | | Batch Get | | |
185
+ | | Batch Put | | |
186
+ | | Transaction Get | | |
187
+ | | Transaction Put | | |
188
+ | All | Type Support | In Progress | |
33
189
34
- # Links
190
+ ** Post-Launch Features**
191
+
192
+ 1 . Support for inheritance in ` [Async]MappedTable ` .
193
+ 2 . Support for immutable objects in ` [Async]MappedTable ` .
194
+ 3 . Support for projection statements in ` [Async]Table ` and
195
+ ` [Async]MappedTable ` .
196
+ 4 . Support for DynamoDB-provided API metrics (e.g. consumed capacity).
197
+ 5 . A ` software.amazon.aws:dynamodb-all ` module that automatically
198
+ includes all AWS DynamoDB artifacts, to enhance client
199
+ discoverability.
200
+
201
+ ** Missing Features**
202
+
203
+ These features are not intended for inclusion at launch of the library
204
+ (but may be added at a future time).
205
+
206
+ 1 . Support for control-plane operations, like create or delete table.
207
+ * Justification for exclusion:* For testing purposes, this can be done
208
+ through the AWS console or low-level SDK. For production purposes,
209
+ this should be done through the AWS CDK or cloud formation.
210
+ 2 . Versioning and UUID annotations. * Justification for exclusion:* This
211
+ is a higher-level concern than the "type converter" goal that the
212
+ enhanced client is attempting to deliver on. This is a piece of
213
+ functionality that will be built on-top of the enhanced client, not
214
+ in it.
215
+
216
+ ** Requested Features**
217
+
218
+ * [ Immutable classes] ( https://github.com/aws/aws-sdk-java-v2/issues/35#issuecomment-315049138 )
219
+ * [ Getter/setter-less fields] ( https://github.com/aws/aws-sdk-java/issues/547 )
220
+ * [ Replace ` PaginatedList ` with ` Stream ` ] ( https://github.com/aws/aws-sdk-java-v2/issues/35#issuecomment-318051305 )
221
+ * [ Allow 'setters' and 'getters' to support different types] ( https://github.com/aws/aws-sdk-java-v2/issues/35#issuecomment-318792534 )
222
+ * [ Have 'scan' respect the table's read throughput] ( https://github.com/aws/aws-sdk-java-v2/issues/35#issuecomment-329007523 )
223
+ * [ Allow creating a table with an LSI that projects all attributes] ( https://github.com/aws/aws-sdk-java/issues/214#issue-31304615 )
224
+ * [ Projection expressions in 'load' and 'batchLoad'] ( https://github.com/aws/aws-sdk-java/issues/527 )
225
+ * [ New condition expressions] ( https://github.com/aws/aws-sdk-java/issues/534 )
226
+ * [ Accessing un-modeled/dynamic attributes in a POJO] ( https://github.com/aws/aws-sdk-java/issues/674 )
227
+ * [ Inheritance] ( https://github.com/aws/aws-sdk-java/issues/832 )
228
+ * [ Service-side metrics] ( https://github.com/aws/aws-sdk-java/issues/953 )
229
+ ([ 1] ( https://github.com/aws/aws-sdk-java/issues/1170 ) ,
230
+ [ 2] ( https://github.com/aws/aws-sdk-java-v2/issues/703 ) ,
231
+ [ 3] ( https://github.com/aws/aws-sdk-java-v2/issues/35#issuecomment-417656448 ) )
232
+ * [ Merging DynamoDB mapper configurations] ( https://github.com/aws/aws-sdk-java/issues/1201 )
233
+ * [ Cache merged DynamoDB mapper configurations] ( https://github.com/aws/aws-sdk-java/issues/1235 )
234
+ * [ Create one single type converter interface] ( https://github.com/aws/aws-sdk-java-v2/issues/35#issuecomment-330616648 )
235
+ * [ Support ` @DynamoDBGeneratedUuid ` in objects nested within lists] ( https://github.com/aws/aws-sdk-java-v2/issues/35#issuecomment-332958299 )
236
+ * [ Allow annotating fields in addition to methods] ( https://github.com/aws/aws-sdk-java-v2/issues/35#issuecomment-332968651 )
237
+ * [ Non-string keys in maps] ( https://github.com/aws/aws-sdk-java-v2/issues/35#issuecomment-332974427 )
238
+ * [ Multiple conditions on the same attribute, for save/delete] ( https://github.com/aws/aws-sdk-java-v2/issues/35#issuecomment-342586344 )
239
+ * [ Persisting public getters from package-private classes] ( https://github.com/aws/aws-sdk-java-v2/issues/35#issuecomment-343006566 )
240
+ * [ Return modified attributes when doing a save] ( https://github.com/aws/aws-sdk-java-v2/issues/35#issuecomment-417656448 )
241
+ * [ More direct exposure of scan or filter expressions] ( https://github.com/aws/aws-sdk-java-v2/issues/35#issuecomment-430993224 )
242
+ * [ Transactions support] ( https://github.com/aws/aws-sdk-java-v2/issues/35#issuecomment-443308198 )
243
+ * [ Creating an Item from JSON (and vice-versa)] ( https://github.com/aws/aws-sdk-java-v2/issues/1240 )
244
+ * Straight-forward support for multiple classes in a single table (as
245
+ per
246
+ [ here] ( https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-general-nosql-design.html ) )
247
+ (from email)
248
+ * Support for ` Optional ` (from email)
249
+ * Support for ` Publisher ` for async paginated responses (from email)
250
+ * Create a table with partial projections (from email)
251
+ * Better integration with DynamoDB streams (from email)
252
+ * Configuring table auto-scaling when a table is created (from email)
253
+ * Request-level credentials (from email)
254
+ * Wrappers for transactional isolation (from email)
255
+ * Dynamic attributes - ones with different types depending on the value
256
+ of other attributes, or attributes with names that are generated at
257
+ runtime (from email)
258
+ * Structure versioning (from email)
259
+
260
+ ## Appendix A: Alternative Solutions
261
+
262
+ ### Alternative Solution 1: Level 3 Storage Library
263
+
264
+ A "Level 2" high-level library is a service-specific library built on
265
+ top of the "Level 1" generated client. The solution proposed above is a
266
+ Level 2 high-level library for DynamoDB.
267
+
268
+ A "Level 3" high-level library focuses on a specific customer problem
269
+ instead of a specific AWS service. For example, customers frequently use
270
+ DynamoDB to store time series data. An alternate to the proposed
271
+ solution above, would be to build multiple Level 3 libraries, each
272
+ focusing on a specific customer problem: a document database library, a
273
+ time series database library, etc. These libraries would support
274
+ DynamoDB as one of many backing data stores.
275
+
276
+ Instead of using traditional DynamoDB nouns and verbs (e.g. Item), a
277
+ Level 3 library would use words more aligned to the problem domain (e.g.
278
+ Document for document databases or Entry for time-series data). They
279
+ would also expose operations more constrained to the problem domain they
280
+ were trying to solve, instead of trying to expose every piece of
281
+ DynamoDB functionality.
282
+
283
+ This solution would be better for customers that are more familiar with
284
+ the problem they are trying to solve and less familiar with DynamoDB.
285
+ This solution would be worse for customers that are familiar with
286
+ DynamoDB and want to be "closer" to the service.
287
+
288
+ ** Customer Feedback**
289
+
290
+ The Java SDK team collected customer feedback internally and
291
+ [ externally] ( https://github.com/aws/aws-sdk-java-v2/issues/35#issuecomment-468435660 ) ,
292
+ comparing this alternate solution against the proposed solution.
293
+ Customers were presented with the following option comparison:
294
+
295
+ > Option 1: A DynamoDB-specific client that combines the functionality
296
+ > of 1.11.x's Documents APIs and DynamoDB Mapper APIs in a
297
+ > straight-forward manner.
298
+
299
+ > Option 2: A generic document database client that creates an
300
+ > abstraction over all document databases, like DynamoDB and MongoDB.
301
+ > This would simplify using multiple document databases in the same
302
+ > application, and make it easier to migrate between the two.
303
+ > Unfortunately as a result, it also wouldn't be a direct DynamoDB
304
+ > experience.
305
+
306
+ We requested that customers review these two options as well as a
307
+ [ prototype of option 1] ( prototype/option-1/sync/Prototype.java ) and a
308
+ [ prototype of option 2] ( prototype/option-2/sync/Prototype.java ) , to let
309
+ us know which they prefer.
310
+
311
+ The following anecdotes are from this customer feedback:
312
+
313
+ > If \[ Amazon] can make something like https://serverless.com/ or
314
+ > https://onnx.ai/ which free customers from vendor lock-in, that would
315
+ > be a great Think Big & Customer Obsession idea. If \[ Amazon] cannot,
316
+ > I feel that somebody who is more vendor-neutral can make a better
317
+ > mapper than \[ Amazon] .
318
+
319
+ > Have you thought about contributing to projects which already exist,
320
+ > like Spring Data? https://github.com/derjust/spring-data-dynamodb
321
+
322
+ > Both options would work well for us.
323
+
324
+ > I think \[ doing option 1 and then creating a Spring Data plugin] might
325
+ > get adoption from a broader audience than option 2. It could be used
326
+ > as a stepping stone to move to DynamoDB.
327
+
328
+ > I believe Option 2 does not make much sense. It would make sense to me
329
+ > to go for Option 1 and start a bounty program to implement a module to
330
+ > popular data access abstraction libraries such as spring-data
331
+ > mentioned above or GORM.
332
+
333
+ > Maybe you could implement/support JNOSQL spec http://www.jnosql.org/
334
+
335
+ ** Decision**
336
+
337
+ Based on customer feedback, it was decided to temporarily reject
338
+ alternative solution 1, and build the proposed solution. At a later
339
+ time, the SDK may build a Level 3 abstraction for DynamoDB or integrate
340
+ with existing Java Level 3 abstractions like Spring Data, Hibernate OGM,
341
+ and/or JNoSQL. This Level 3 abstraction will possibly leverage the Level
342
+ 2 solution "under the hood".
343
+
344
+ ## Links
35
345
36
346
** [ Features] ( features.md ) ** - The features intended for inclusion during
37
347
and after the launch of the enhanced DynamoDB client.
@@ -55,26 +365,4 @@ to solicit feedback from customers on potential design directions.
55
365
for DynamoDB mapper-equivalent functionality in 2.x.
56
366
* [ DynamoDB Document API Feature Request] ( https://github.com/aws/aws-sdk-java-v2/issues/36 )
57
367
\- A github issue for tracking customer feature requests and feedback
58
- for DynamoDB document API-equivalent functionality in 2.x.
59
-
60
- # FAQ
61
-
62
- ** Why not optimize for specific data access patterns, like relational
63
- data?**
64
-
65
- Some customers prefer to think about the DynamoDB-specific concepts of
66
- tables, queries, conditions and global secondary indices. These
67
- customers currently have trouble interacting with DynamoDB, because they
68
- have to perform a large amount of conversion between their Java types
69
- and DynamoDB types.
70
-
71
- If we were to optimize this specific project for a particular access
72
- pattern, customers that have other access patterns would either be
73
- forced to modify their access pattern into the one we've optimized for,
74
- or they would need to use the generated client and handle their own Java
75
- type conversion.
76
-
77
- Instead, this project focuses on making integrating with DynamoDB easier
78
- to do in Java, and leaves the problems of "making storing time series
79
- data on AWS easy" or "making storing documents on AWS easy" to another
80
- project.
368
+ for DynamoDB document API-equivalent functionality in 2.x.
0 commit comments