@@ -159,7 +159,6 @@ index. Here's an example of how to do this:
159
159
PageIterable<Customer> customersWithName =
160
160
customersByName.query(r -> r.queryConditional(equalTo(k -> k.partitionValue("Smith"))));
161
161
```
162
-
163
162
### Non-blocking asynchronous operations
164
163
If your application requires non-blocking asynchronous calls to
165
164
DynamoDb, then you can use the asynchronous implementation of the
@@ -195,8 +194,7 @@ key differences:
195
194
// Perform other work and let the processor handle the results asynchronously
196
195
```
197
196
198
-
199
- ### Using extensions
197
+ ## Using extensions
200
198
The mapper supports plugin extensions to provide enhanced functionality
201
199
beyond the simple primitive mapped operations. Extensions have two hooks, beforeWrite() and
202
200
afterRead(); the former can modify a write operation before it happens,
@@ -221,7 +219,7 @@ DynamoDbEnhancedClient enhancedClient =
221
219
.build();
222
220
```
223
221
224
- #### VersionedRecordExtension
222
+ ### VersionedRecordExtension
225
223
226
224
This extension is loaded by default and will increment and track a record version number as
227
225
records are written to the database. A condition will be added to every
@@ -248,14 +246,143 @@ Or using a StaticTableSchema:
248
246
.tags(versionAttribute())
249
247
```
250
248
251
- ## Advanced StaticTableSchema scenarios
249
+ ## Advanced table schema features
250
+ ### Explicitly include/ exclude attributes in DDB mapping
251
+ #### Excluding attributes
252
+ Ignore attributes that should not participate in mapping to DDB
253
+ Mark the attribute with the @DynamoDbIgnore annotation:
254
+ ```java
255
+ private String internalKey;
256
+
257
+ @DynamoDbIgnore
258
+ public String getInternalKey() { return this . internalKey; }
259
+ public void setInternalKey(String internalKey) { return this . internalKey = internalKey;}
260
+ ```
261
+ #### Including attributes
262
+ Change the name used to store an attribute in DBB by explicitly marking it with the
263
+ @DynamoDbAttribute annotation and supplying a different name:
264
+ ```java
265
+ private String internalKey;
266
+
267
+ @DynamoDbAttribute (" renamedInternalKey" )
268
+ public String getInternalKey() { return this . internalKey; }
269
+ public void setInternalKey(String internalKey) { return this . internalKey = internalKey;}
270
+ ```
271
+
272
+ ### Control attribute conversion
273
+ By default , the table schema provides converters for all primitive and many common Java types
274
+ through a default implementation of the AttributeConverterProvider interface. This behavior
275
+ can be changed both at the attribute converter provider level as well as for a single attribute.
276
+
277
+ #### Provide custom attribute converter providers
278
+ You can provide a single AttributeConverterProvider or a chain of ordered AttributeConverterProviders
279
+ through the @DynamoDbBean ' converterProviders' annotation. Any custom AttributeConverterProvider must extend the AttributeConverterProvider
280
+ interface.
281
+
282
+ Note that if you supply your own chain of attribute converter providers, you will override
283
+ the default converter provider (DefaultAttributeConverterProvider ) and must therefore include it in the chain if you wish to
284
+ use its attribute converters. It ' s also possible to annotate the bean with an empty array `{}`, thus
285
+ disabling the usage of any attribute converter providers including the default, in which case
286
+ all attributes must have their own attribute converters (see below).
287
+
288
+ Single converter provider:
289
+ ```java
290
+ @DynamoDbBean(converterProviders = ConverterProvider1.class)
291
+ public class Customer {
292
+
293
+ }
294
+ ```
295
+
296
+ Chain of converter providers ending with the default (least priority):
297
+ ```java
298
+ @DynamoDbBean(converterProviders = {
299
+ ConverterProvider1.class,
300
+ ConverterProvider2.class,
301
+ DefaultAttributeConverterProvider.class})
302
+ public class Customer {
303
+
304
+ }
305
+ ```
306
+
307
+ In the same way, adding a chain of attribute converter providers directly to a StaticTableSchema:
308
+ ```java
309
+ private static final StaticTableSchema<Customer> CUSTOMER_TABLE_SCHEMA =
310
+ StaticTableSchema.builder(Customer.class)
311
+ .newItemSupplier(Customer::new)
312
+ .addAttribute(String.class, a -> a.name("name")
313
+ a.getter(Customer::getName)
314
+ a.setter(Customer::setName))
315
+ .attributeConverterProviders(converterProvider1, converterProvider2)
316
+ .build();
317
+ ```
318
+
319
+ #### Override the mapping of a single attribute
320
+ Supply an AttributeConverter when creating the attribute to directly override any
321
+ converters provided by the table schema AttributeConverterProviders. Note that you will
322
+ only add a custom converter for that attribute; other attributes, even of the same
323
+ type, will not use that converter unless explicitly specified for those other attributes.
324
+
325
+ Example:
326
+ ```java
327
+ @DynamoDbBean
328
+ public class Customer {
329
+ private String name;
330
+
331
+ @DynamoDbConvertedBy(CustomAttributeConverter.class)
332
+ public String getName() { return this.name; }
333
+ public void setName(String name) { this.name = name;}
334
+ }
335
+ ```
336
+ For StaticTableSchema:
337
+ ```java
338
+ private static final StaticTableSchema<Customer> CUSTOMER_TABLE_SCHEMA =
339
+ StaticTableSchema.builder(Customer.class)
340
+ .newItemSupplier(Customer::new)
341
+ .addAttribute(String.class, a -> a.name("name")
342
+ a.getter(Customer::getName)
343
+ a.setter(Customer::setName)
344
+ a.attributeConverter(customAttributeConverter))
345
+ .build();
346
+ ```
347
+
252
348
### Flat map attributes from another class
253
349
If the attributes for your table record are spread across several
254
350
different Java objects, either through inheritance or composition, the
255
351
static TableSchema implementation gives you a method of flat mapping
256
352
those attributes and rolling them up into a single schema.
257
353
258
- To accomplish this using inheritance: -
354
+ #### Using inheritance
355
+ To accomplish flat map using inheritance, the only requirement is that
356
+ both classes are annotated as a DynamoDb bean:
357
+
358
+ ```java
359
+ @DynamoDbBean
360
+ public class Customer extends GenericRecord {
361
+ private String name;
362
+ private GenericRecord record;
363
+
364
+ public String getName() { return this.name; }
365
+ public void setName(String name) { this.name = name;}
366
+
367
+ public String getRecord() { return this.record; }
368
+ public void setRecord(String record) { this.record = record;}
369
+ }
370
+
371
+ @DynamoDbBean
372
+ public abstract class GenericRecord {
373
+ private String id;
374
+ private String createdDate;
375
+
376
+ public String getId() { return this.id; }
377
+ public void setId(String id) { this.id = id;}
378
+
379
+ public String getCreatedDate() { return this.createdDate; }
380
+ public void setCreatedDate(String createdDate) { this.createdDate = createdDate;}
381
+ }
382
+
383
+ ```
384
+
385
+ For StaticTableSchema, use the ' extend' feature to achieve the same effect:
259
386
```java
260
387
@Data
261
388
public class Customer extends GenericRecord {
@@ -270,53 +397,96 @@ public abstract class GenericRecord {
270
397
271
398
private static final StaticTableSchema<GenericRecord> GENERIC_RECORD_SCHEMA =
272
399
StaticTableSchema.builder(GenericRecord.class)
273
- .attributes(
274
- // The partition key will be inherited by the top level mapper
275
- stringAttribute(" id" , GenericRecord :: getId, GenericRecord :: setId). as(primaryPartitionKey()),
276
- stringAttribute(" created_date" , GenericRecord :: getCreatedDate, GenericRecord :: setCreatedDate))
277
- .build();
400
+ // The partition key will be inherited by the top level mapper
401
+ .addAttribute(String.class, a -> a.name("id")
402
+ .getter(GenericRecord::getId)
403
+ .setter(GenericRecord::setId)
404
+ .tags(primaryPartitionKey()))
405
+ .addAttribute(String.class, a -> a.name("created_date")
406
+ .getter(GenericRecord::getCreatedDate)
407
+ .setter(GenericRecord::setCreatedDate))
408
+ .build();
278
409
279
410
private static final StaticTableSchema<Customer> CUSTOMER_TABLE_SCHEMA =
280
411
StaticTableSchema.builder(Customer.class)
281
412
.newItemSupplier(Customer::new)
282
- .attributes(
283
- stringAttribute(" name" , Customer :: getName, Customer :: setName))
413
+ .addAttribute(String.class, a -> a.name("name")
414
+ .getter(Customer::getName)
415
+ .setter(Customer::setName))
284
416
.extend(GENERIC_RECORD_SCHEMA) // All the attributes of the GenericRecord schema are added to Customer
285
417
.build();
286
418
```
419
+ #### Using composition
420
+
421
+ Using composition, the @DynamoDbFlatten annotation flat maps the composite class:
422
+ ```java
423
+ @DynamoDbBean
424
+ public class Customer {
425
+ private String name;
426
+ private GenericRecord record;
427
+
428
+ public String getName() { return this.name; }
429
+ public void setName(String name) { this.name = name;}
430
+
431
+ @DynamoDbFlatten(dynamoDbBeanClass = GenericRecord.class)
432
+ public String getRecord() { return this.record; }
433
+ public void setRecord(String record) { this.record = record;}
434
+ }
435
+
436
+ @DynamoDbBean
437
+ public class GenericRecord {
438
+ private String id;
439
+ private String createdDate;
440
+
441
+ public String getId() { return this.id; }
442
+ public void setId(String id) { this.id = id;}
443
+
444
+ public String getCreatedDate() { return this.createdDate; }
445
+ public void setCreatedDate(String createdDate) { this.createdDate = createdDate;}
446
+ }
447
+ ```
448
+ You can flatten as many different eligible classes as you like using the flatten annotation.
449
+ The only constraints are that attributes must not have the same name when they are being rolled
450
+ together, and there must never be more than one partition key, sort key or table name.
451
+
452
+ Flat map composite classes using StaticTableSchema:
287
453
288
- Using composition:
289
454
```java
290
455
@Data
291
456
public class Customer{
292
457
private String name;
293
458
private GenericRecord recordMetadata;
459
+ //getters and setters for all attributes
294
460
}
295
461
296
462
@Data
297
463
public class GenericRecord {
298
464
private String id;
299
465
private String createdDate;
466
+ //getters and setters for all attributes
300
467
}
301
468
302
469
private static final StaticTableSchema<GenericRecord> GENERIC_RECORD_SCHEMA =
303
470
StaticTableSchema.builder(GenericRecord.class)
304
- .newItemSupplier(GenericRecord :: new )
305
- .attributes(
306
- stringAttribute(" id" , GenericRecord :: getId, GenericRecord :: setId). as(primaryPartitionKey()),
307
- stringAttribute(" created_date" , GenericRecord :: getCreatedDate, GenericRecord :: setCreatedDate))
308
- .build();
471
+ .addAttribute(String.class, a -> a.name("id")
472
+ .getter(GenericRecord::getId)
473
+ .setter(GenericRecord::setId)
474
+ .tags(primaryPartitionKey()))
475
+ .addAttribute(String.class, a -> a.name("created_date")
476
+ .getter(GenericRecord::getCreatedDate)
477
+ .setter(GenericRecord::setCreatedDate))
478
+ .build();
309
479
310
480
private static final StaticTableSchema<Customer> CUSTOMER_TABLE_SCHEMA =
311
481
StaticTableSchema.builder(Customer.class)
312
482
.newItemSupplier(Customer::new)
313
- .attributes(stringAttribute(" name" , Customer :: getName, Customer :: setName))
483
+ .addAttribute(String.class, a -> a.name("name")
484
+ .getter(Customer::getName)
485
+ .setter(Customer::setName))
314
486
// Because we are flattening a component object, we supply a getter and setter so the
315
487
// mapper knows how to access it
316
- .flatten(CUSTOMER_TABLE_SCHEMA , Customer :: getRecordMetadata, Customer :: setRecordMetadata)
488
+ .flatten(GENERIC_RECORD_SCHEMA , Customer::getRecordMetadata, Customer::setRecordMetadata)
317
489
.build();
318
490
```
319
- You can flatten as many different eligible classes as you like using the
320
- builder pattern. The only constraints are that attributes must not have
321
- the same name when they are being rolled together, and there must never
322
- be more than one partition key, sort key or table name.
491
+ Just as for annotations, you can flatten as many different eligible classes as you like using the
492
+ builder pattern.
0 commit comments