21
21
import java .util .Map ;
22
22
import java .util .UUID ;
23
23
import java .util .function .Consumer ;
24
+ import java .util .function .Supplier ;
25
+ import software .amazon .awssdk .annotations .NotThreadSafe ;
24
26
import software .amazon .awssdk .annotations .SdkPublicApi ;
25
27
import software .amazon .awssdk .annotations .ThreadSafe ;
26
28
import software .amazon .awssdk .enhanced .dynamodb .AttributeValueType ;
33
35
import software .amazon .awssdk .services .dynamodb .model .AttributeValue ;
34
36
import software .amazon .awssdk .utils .Validate ;
35
37
36
-
37
38
/**
38
39
* This extension facilitates the automatic generation of a unique UUID (Universally Unique Identifier) for a specified attribute
39
40
* every time a new record is written to the database. The generated UUID is obtained using the
40
- * {@link java.util.UUID#randomUUID()} method.
41
+ * {@link java.util.UUID#randomUUID()} method by default or a custom UUID supplier instance provided by the user .
41
42
* <p>
42
43
* This extension is not loaded by default when you instantiate a
43
44
* {@link software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient}. Therefore, you need to specify it in a custom
44
45
* extension when creating the enhanced client.
45
46
* <p>
46
47
* Example to add AutoGeneratedUuidExtension along with default extensions is
47
- * {@snippet :
48
- * DynamoDbEnhancedClient.builder().extensions(Stream.concat(ExtensionResolver.defaultExtensions().stream(),
49
- * Stream.of(AutoGeneratedUuidExtension.create())).collect(Collectors.toList())).build();
50
- *}
48
+ * {@code DynamoDbEnhancedClient.builder().extensions(Stream.concat(ExtensionResolver.defaultExtensions().stream(),
49
+ * Stream.of(AutoGeneratedUuidExtension.create())).collect(Collectors.toList())).build();}
51
50
* </p>
52
51
* <p>
53
52
* Example to just add AutoGeneratedUuidExtension without default extensions is
54
- * {@snippet :
55
- * DynamoDbEnhancedClient.builder().extensions(AutoGeneratedUuidExtension.create()).build();
56
- *}
53
+ * {@code DynamoDbEnhancedClient.builder().extensions(AutoGeneratedUuidExtension.create())).build();}
57
54
* </p>
58
55
* <p>
59
56
* To utilize the auto-generated UUID feature, first, create a field in your model that will store the UUID for the attribute.
60
57
* This class field must be of type {@link java.lang.String}, and you need to tag it as the autoGeneratedUuidAttribute. If you are
61
58
* using the {@link software.amazon.awssdk.enhanced.dynamodb.mapper.BeanTableSchema}, then you should use the
62
59
* {@link software.amazon.awssdk.enhanced.dynamodb.extensions.annotations.DynamoDbAutoGeneratedUuid} annotation. If you are using
63
60
* the {@link software.amazon.awssdk.enhanced.dynamodb.mapper.StaticTableSchema}, then you should use the
64
- * {@link
65
- * software.amazon.awssdk.enhanced.dynamodb.extensions.AutoGeneratedUuidExtension.AttributeTags#autoGeneratedUuidAttribute()}
66
- * static attribute tag.
61
+ * {@link AttributeTags#autoGeneratedUuidAttribute()} static attribute tag.
67
62
* </p>
68
63
* <p>
69
64
* Every time a new record is successfully put into the database, the specified attribute will be automatically populated with a
70
- * unique UUID generated using {@link java.util.UUID#randomUUID()}. If the UUID needs to be created only for `putItem` and should
71
- * not be generated for an `updateItem`, then
65
+ * unique UUID generated using {@link java.util.UUID#randomUUID()}.
66
+ * <br>
67
+ * If the UUID needs to be created only for `putItem` and should not be generated for an `updateItem`, then
72
68
* {@link software.amazon.awssdk.enhanced.dynamodb.mapper.UpdateBehavior#WRITE_IF_NOT_EXISTS} must be along with
73
- * {@link DynamoDbUpdateBehavior}
74
- *
69
+ * {@link DynamoDbUpdateBehavior}.
75
70
* </p>
76
71
*/
77
72
@ SdkPublicApi
78
73
@ ThreadSafe
79
74
public final class AutoGeneratedUuidExtension implements DynamoDbEnhancedClientExtension {
80
- private static final String CUSTOM_METADATA_KEY =
81
- "software.amazon.awssdk.enhanced.dynamodb.extensions.AutoGeneratedUuidExtension:AutoGeneratedUuidAttribute" ;
82
- private static final AutoGeneratedUuidAttribute AUTO_GENERATED_UUID_ATTRIBUTE = new AutoGeneratedUuidAttribute ();
75
+
76
+ private static final String CUSTOM_METADATA_KEY = "AutoGeneratedUuidExtension:AutoGeneratedUuidAttribute" ;
77
+ private static final StaticAttributeTag AUTO_GENERATED_UUID_ATTRIBUTE = new AutoGeneratedUuidAttribute ();
78
+
79
+ private final Supplier <UUID > uuidSupplier ;
83
80
84
81
private AutoGeneratedUuidExtension () {
82
+ this .uuidSupplier = UUID ::randomUUID ;
83
+ }
84
+
85
+ private AutoGeneratedUuidExtension (Builder builder ) {
86
+ this .uuidSupplier = builder .uuidSupplier == null ? UUID ::randomUUID : builder .uuidSupplier ;
87
+ }
88
+
89
+ public static Builder builder () {
90
+ return new Builder ();
91
+ }
92
+
93
+ public Builder toBuilder () {
94
+ return builder ().uuidSupplier (this .uuidSupplier );
85
95
}
86
96
87
- /**
88
- * @return an Instance of {@link AutoGeneratedUuidExtension}
89
- */
90
97
public static AutoGeneratedUuidExtension create () {
91
98
return new AutoGeneratedUuidExtension ();
92
99
}
93
100
94
- /**
95
- * Modifies the WriteModification UUID string with the attribute updated with the extension.
96
- *
97
- * @param context The {@link DynamoDbExtensionContext.BeforeWrite} context containing the state of the execution.
98
- * @return WriteModification String updated with attribute updated with Extension.
99
- */
100
101
@ Override
101
102
public WriteModification beforeWrite (DynamoDbExtensionContext .BeforeWrite context ) {
102
-
103
-
104
103
Collection <String > customMetadataObject = context .tableMetadata ()
105
104
.customMetadataObject (CUSTOM_METADATA_KEY , Collection .class )
106
105
.orElse (null );
@@ -116,32 +115,25 @@ public WriteModification beforeWrite(DynamoDbExtensionContext.BeforeWrite contex
116
115
.build ();
117
116
}
118
117
119
- private void insertUuidInItemToTransform (Map <String , AttributeValue > itemToTransform ,
120
- String key ) {
121
- itemToTransform .put (key , AttributeValue .builder ().s (UUID .randomUUID ().toString ()).build ());
118
+ private void insertUuidInItemToTransform (Map <String , AttributeValue > itemToTransform , String key ) {
119
+ itemToTransform .put (key , AttributeValue .builder ().s (uuidSupplier .get ().toString ()).build ());
122
120
}
123
121
124
122
public static final class AttributeTags {
125
123
126
124
private AttributeTags () {
127
125
}
128
126
129
- /**
130
- * Tags which indicate that the given attribute is supported wih Auto Generated UUID Record Extension.
131
- *
132
- * @return Tag name for AutoGenerated UUID Records
133
- */
134
127
public static StaticAttributeTag autoGeneratedUuidAttribute () {
135
128
return AUTO_GENERATED_UUID_ATTRIBUTE ;
136
129
}
130
+
137
131
}
138
132
139
133
private static class AutoGeneratedUuidAttribute implements StaticAttributeTag {
140
134
141
135
@ Override
142
- public <R > void validateType (String attributeName , EnhancedType <R > type ,
143
- AttributeValueType attributeValueType ) {
144
-
136
+ public <R > void validateType (String attributeName , EnhancedType <R > type , AttributeValueType attributeValueType ) {
145
137
Validate .notNull (type , "type is null" );
146
138
Validate .notNull (type .rawClass (), "rawClass is null" );
147
139
Validate .notNull (attributeValueType , "attributeValueType is null" );
@@ -159,5 +151,34 @@ public Consumer<StaticTableMetadata.Builder> modifyMetadata(String attributeName
159
151
return metadata -> metadata .addCustomMetadataObject (CUSTOM_METADATA_KEY , Collections .singleton (attributeName ))
160
152
.markAttributeAsKey (attributeName , attributeValueType );
161
153
}
154
+
155
+ }
156
+
157
+ @ NotThreadSafe
158
+ public static final class Builder {
159
+
160
+ private Supplier <UUID > uuidSupplier ;
161
+
162
+ private Builder () {
163
+ }
164
+
165
+ /**
166
+ * Sets the UUID supplier instance , else {@link UUID#randomUUID()} is used by default. Every time a new UUID is generated
167
+ * this supplier will be used to get the current UUID. If a custom supplier is not specified, the default randomUUID
168
+ * supplier will be used.
169
+ *
170
+ * @param uuidSupplier Supplier instance to set the current UUID.
171
+ * @return This builder for method chaining.
172
+ */
173
+ public Builder uuidSupplier (Supplier <UUID > uuidSupplier ) {
174
+ this .uuidSupplier = uuidSupplier ;
175
+ return this ;
176
+ }
177
+
178
+ public AutoGeneratedUuidExtension build () {
179
+ return new AutoGeneratedUuidExtension (this );
180
+ }
181
+
162
182
}
163
- }
183
+
184
+ }
0 commit comments