Skip to content

Commit a5ae056

Browse files
committed
DefaultEnhancedDocument implementation
1 parent 92ca159 commit a5ae056

File tree

8 files changed

+1387
-10
lines changed

8 files changed

+1387
-10
lines changed

core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/unmarshall/document/DocumentUnmarshaller.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,11 @@ public Document visitString(String string) {
4646
return Document.fromString(string);
4747
}
4848

49+
// TODO : A separate PR will be raised on Master and these changes will be merged separately for Master branch.
4950
@Override
5051
public Document visitArray(List<JsonNode> array) {
5152
return Document.fromList(array.stream()
52-
.map(node -> node.visit(this))
53+
.map(node -> node == null ? Document.fromNull() : node.visit(this))
5354
.collect(Collectors.toList()));
5455
}
5556

services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/document/EnhancedDocument.java

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import software.amazon.awssdk.enhanced.dynamodb.AttributeConverter;
2626
import software.amazon.awssdk.enhanced.dynamodb.AttributeConverterProvider;
2727
import software.amazon.awssdk.enhanced.dynamodb.EnhancedType;
28-
import software.amazon.awssdk.enhanced.dynamodb.KeyAttributeMetadata;
2928

3029
/**
3130
* Interface representing Document API for DynamoDB. Document API operations are used to carry open content i.e. data with no
@@ -145,8 +144,6 @@ static Builder builder() {
145144
* @param attributeName Name of the attribute.
146145
* @return the value of the specified attribute in the current document as SdkBytes; or null if the attribute either
147146
* doesn't exist or the attribute value is null.
148-
* @throws UnsupportedOperationException If the attribute value involves a byte buffer which is not backed by an accessible
149-
* array
150147
*/
151148
SdkBytes getSdkBytes(String attributeName);
152149

@@ -189,6 +186,15 @@ static Builder builder() {
189186

190187
<T> List<T> getList(String attributeName, EnhancedType<T> type);
191188

189+
190+
/**
191+
* Gets the List of values for the given attribute in the current document.
192+
* @param attributeName Name of the attribute.
193+
* @return value of the specified attribute in the current document as a list; or null if the
194+
* attribute either doesn't exist or the attribute value is null.
195+
*/
196+
List<?> getList(String attributeName);
197+
192198
/**
193199
* Gets the Map with Key as String and values as type T for the given attribute in the current document.
194200
* <p>Note that any numeric type of map is always canonicalized into {@link SdkNumber}, and therefore if <code>T</code>
@@ -261,13 +267,16 @@ <T extends Number> Map<String, T> getMapOfNumbers(String attributeName,
261267
* @return value of the specified attribute in the current document as a JSON string with pretty indentation; or null if the
262268
* attribute either doesn't exist or the attribute value is null.
263269
*/
264-
String getJSONPretty(String attributeName);
270+
String getJsonPretty(String attributeName);
265271

266272
/**
267273
* Gets the {@link Boolean} value for the specified attribute.
268274
*
269275
* @param attributeName Name of the attribute.
270276
* @return value of the specified attribute in the current document as a non-null Boolean.
277+
* @throws RuntimeException
278+
* if either the attribute doesn't exist or if the attribute
279+
* value cannot be converted into a boolean value.
271280
*/
272281
Boolean getBoolean(String attributeName);
273282

@@ -440,13 +449,12 @@ interface Builder {
440449
Builder addJson(String attributeName, String json);
441450

442451
/**
443-
* Convenience builder methods that sets an attribute of this document for the specified key attribute name and value.
444-
*
445-
* @param keyAttrName Name of the attribute that needs to be added in the Document.
446-
* @param keyAttrValue The value that needs to be set.
452+
* Appends an attribute of name attributeName with specified value of the give EnhancedDocument.
453+
* @param attributeName Name of the attribute that needs to be added in the Document.
454+
* @param enhancedDocument that needs to be added as a value to a key attribute.
447455
* @return Builder instance to construct a {@link EnhancedDocument}
448456
*/
449-
Builder keyComponent(KeyAttributeMetadata keyAttrName, Object keyAttrValue);
457+
Builder addEnhancedDocument(String attributeName, EnhancedDocument enhancedDocument);
450458

451459
/**
452460
* Appends collection of attributeConverterProvider to the document builder. These
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.enhanced.dynamodb.internal.converter.attribute;
17+
18+
import java.util.LinkedHashMap;
19+
import java.util.List;
20+
import java.util.Map;
21+
import java.util.stream.Collectors;
22+
import software.amazon.awssdk.annotations.Immutable;
23+
import software.amazon.awssdk.annotations.SdkInternalApi;
24+
import software.amazon.awssdk.annotations.ThreadSafe;
25+
import software.amazon.awssdk.core.SdkBytes;
26+
import software.amazon.awssdk.enhanced.dynamodb.AttributeConverter;
27+
import software.amazon.awssdk.enhanced.dynamodb.AttributeValueType;
28+
import software.amazon.awssdk.enhanced.dynamodb.EnhancedType;
29+
import software.amazon.awssdk.enhanced.dynamodb.internal.converter.TypeConvertingVisitor;
30+
import software.amazon.awssdk.protocols.jsoncore.JsonNode;
31+
import software.amazon.awssdk.protocols.jsoncore.internal.ArrayJsonNode;
32+
import software.amazon.awssdk.protocols.jsoncore.internal.BooleanJsonNode;
33+
import software.amazon.awssdk.protocols.jsoncore.internal.NullJsonNode;
34+
import software.amazon.awssdk.protocols.jsoncore.internal.NumberJsonNode;
35+
import software.amazon.awssdk.protocols.jsoncore.internal.ObjectJsonNode;
36+
import software.amazon.awssdk.protocols.jsoncore.internal.StringJsonNode;
37+
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
38+
39+
/**
40+
* An Internal converter between JsonNode and {@link AttributeValue}.
41+
*
42+
* <p>
43+
* This converts the Attribute Value read from the DDB to JsonNode.
44+
*/
45+
@SdkInternalApi
46+
@ThreadSafe
47+
@Immutable
48+
public final class JsonItemAttributeConverter implements AttributeConverter<JsonNode> {
49+
private static final Visitor VISITOR = new Visitor();
50+
51+
private JsonItemAttributeConverter() {
52+
}
53+
54+
public static JsonItemAttributeConverter create() {
55+
return new JsonItemAttributeConverter();
56+
}
57+
58+
@Override
59+
public EnhancedType<JsonNode> type() {
60+
return EnhancedType.of(JsonNode.class);
61+
}
62+
63+
@Override
64+
public AttributeValueType attributeValueType() {
65+
return AttributeValueType.M;
66+
}
67+
68+
@Override
69+
public AttributeValue transformFrom(JsonNode input) {
70+
JsonNodeToAttributeValueMapConvertor jsonNodeToAttributeValueMapConvertor = new JsonNodeToAttributeValueMapConvertor();
71+
return input.visit(jsonNodeToAttributeValueMapConvertor);
72+
}
73+
74+
@Override
75+
public JsonNode transformTo(AttributeValue input) {
76+
return EnhancedAttributeValue.fromAttributeValue(input).convert(VISITOR);
77+
}
78+
79+
private static final class Visitor extends TypeConvertingVisitor<JsonNode> {
80+
private Visitor() {
81+
super(JsonNode.class, JsonItemAttributeConverter.class);
82+
}
83+
84+
@Override
85+
public JsonNode convertMap(Map<String, AttributeValue> value) {
86+
Map<String, JsonNode> jsonNodeMap = new LinkedHashMap<>();
87+
value.entrySet().forEach(
88+
k -> {
89+
JsonNode jsonNode = this.convert(EnhancedAttributeValue.fromAttributeValue(k.getValue()));
90+
jsonNodeMap.put(k.getKey(), jsonNode == null ? NullJsonNode.instance() : jsonNode);
91+
});
92+
return new ObjectJsonNode(jsonNodeMap);
93+
}
94+
95+
@Override
96+
public JsonNode convertString(String value) {
97+
return new StringJsonNode(value);
98+
}
99+
100+
@Override
101+
public JsonNode convertNumber(String value) {
102+
return new NumberJsonNode(value);
103+
}
104+
105+
@Override
106+
public JsonNode convertBytes(SdkBytes value) {
107+
return new StringJsonNode(value.asUtf8String());
108+
}
109+
110+
@Override
111+
public JsonNode convertBoolean(Boolean value) {
112+
return new BooleanJsonNode(value);
113+
}
114+
115+
@Override
116+
public JsonNode convertSetOfStrings(List<String> value) {
117+
return new ArrayJsonNode(value.stream().map(s -> new StringJsonNode(s)).collect(Collectors.toList()));
118+
}
119+
120+
@Override
121+
public JsonNode convertSetOfNumbers(List<String> value) {
122+
return new ArrayJsonNode(value.stream().map(s -> new NumberJsonNode(s)).collect(Collectors.toList()));
123+
}
124+
125+
@Override
126+
public JsonNode convertSetOfBytes(List<SdkBytes> value) {
127+
return new ArrayJsonNode(value.stream().map(sdkByte ->
128+
new StringJsonNode(sdkByte.asUtf8String())
129+
).collect(Collectors.toList()));
130+
}
131+
132+
@Override
133+
public JsonNode convertListOfAttributeValues(List<AttributeValue> value) {
134+
return new ArrayJsonNode(value.stream().map(
135+
attributeValue -> EnhancedAttributeValue.fromAttributeValue(
136+
attributeValue).convert(VISITOR)).collect(Collectors.toList()));
137+
138+
}
139+
}
140+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.enhanced.dynamodb.internal.converter.attribute;
17+
18+
import java.util.LinkedHashMap;
19+
import java.util.List;
20+
import java.util.Map;
21+
import java.util.stream.Collectors;
22+
import software.amazon.awssdk.annotations.SdkInternalApi;
23+
import software.amazon.awssdk.protocols.jsoncore.JsonNode;
24+
import software.amazon.awssdk.protocols.jsoncore.JsonNodeVisitor;
25+
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
26+
27+
@SdkInternalApi
28+
public class JsonNodeToAttributeValueMapConvertor implements JsonNodeVisitor<AttributeValue> {
29+
@Override
30+
public AttributeValue visitNull() {
31+
return AttributeValue.builder().build();
32+
}
33+
34+
@Override
35+
public AttributeValue visitBoolean(boolean bool) {
36+
return AttributeValue.builder().bool(bool).build();
37+
}
38+
39+
@Override
40+
public AttributeValue visitNumber(String number) {
41+
return AttributeValue.builder().n(number).build();
42+
}
43+
44+
@Override
45+
public AttributeValue visitString(String string) {
46+
return AttributeValue.builder().s(string).build();
47+
}
48+
49+
@Override
50+
public AttributeValue visitArray(List<JsonNode> array) {
51+
return AttributeValue.builder().l(array.stream()
52+
.map(node -> node.visit(this))
53+
.collect(Collectors.toList())).build();
54+
}
55+
56+
@Override
57+
public AttributeValue visitObject(Map<String, JsonNode> object) {
58+
return AttributeValue.builder().m(object.entrySet()
59+
.stream()
60+
.collect(
61+
Collectors.toMap(
62+
entry -> entry.getKey(),
63+
entry -> entry.getValue().visit(this),
64+
(left, right) -> left,
65+
LinkedHashMap::new)))
66+
.build();
67+
}
68+
69+
@Override
70+
public AttributeValue visitEmbeddedObject(Object embeddedObject) {
71+
throw new UnsupportedOperationException("Embedded objects are not supported within Document types.");
72+
}
73+
}

0 commit comments

Comments
 (0)