Skip to content

Commit a7cf274

Browse files
committed
Bytes in a toJson of EnhancedDocument should be represented in a hexadecimal encoded format for their binary representation.
1 parent a3e9909 commit a7cf274

File tree

7 files changed

+144
-10
lines changed

7 files changed

+144
-10
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"type": "bugfix",
3+
"category": "AWS SDK for Java v2",
4+
"contributor": "",
5+
"description": "Bytes in a toJSon of EnhancedDoucment should be represented in a hexadecimal encoded format for their binary representation."
6+
}

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

+4-3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.Arrays;
2020
import java.util.Collection;
2121
import java.util.Collections;
22+
import java.util.LinkedHashMap;
2223
import java.util.LinkedHashSet;
2324
import java.util.List;
2425
import java.util.Map;
@@ -127,17 +128,17 @@ public Map<String, AttributeValue> itemToMap(EnhancedDocument item, Collection<S
127128
if (item.toMap() == null) {
128129
return null;
129130
}
130-
131131
List<AttributeConverterProvider> providers = mergeAttributeConverterProviders(item);
132132
return item.toBuilder().attributeConverterProviders(providers).build().toMap().entrySet()
133133
.stream()
134134
.filter(entry -> attributes.contains(entry.getKey()))
135-
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
135+
.collect(Collectors.toMap(entry -> entry.getKey(), entry -> entry.getValue(),
136+
(left, right) -> left, LinkedHashMap::new));
136137
}
137138

138139
@Override
139140
public AttributeValue attributeValue(EnhancedDocument item, String attributeName) {
140-
if (item == null || item.toMap() == null) {
141+
if (item == null) {
141142
return null;
142143
}
143144
List<AttributeConverterProvider> providers = mergeAttributeConverterProviders(item);

services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/converter/attribute/JsonItemAttributeConverter.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import software.amazon.awssdk.protocols.jsoncore.internal.ObjectJsonNode;
3636
import software.amazon.awssdk.protocols.jsoncore.internal.StringJsonNode;
3737
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
38+
import software.amazon.awssdk.utils.BinaryUtils;
3839

3940
/**
4041
* An Internal converter between JsonNode and {@link AttributeValue}.
@@ -119,7 +120,7 @@ public JsonNode convertBytes(SdkBytes value) {
119120
if (value == null) {
120121
return null;
121122
}
122-
return new StringJsonNode(value.asUtf8String());
123+
return new StringJsonNode(BinaryUtils.toBase64(value.asByteArray()));
123124
}
124125

125126
@Override
@@ -151,8 +152,8 @@ public JsonNode convertSetOfBytes(List<SdkBytes> value) {
151152
if (value == null) {
152153
return null;
153154
}
154-
return new ArrayJsonNode(value.stream().map(sdkByte ->
155-
new StringJsonNode(sdkByte.asUtf8String())
155+
return new ArrayJsonNode(value.stream().map(
156+
sdkByte -> new StringJsonNode(BinaryUtils.toBase64(sdkByte.asByteArray()))
156157
).collect(Collectors.toList()));
157158
}
158159

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

-1
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,6 @@ public Map<String, AttributeValue> toMap() {
245245

246246
private Map<String, AttributeValue> initializeAttributeValueMap() {
247247
Map<String, AttributeValue> result = new LinkedHashMap<>(this.nonAttributeValueMap.size());
248-
Validate.notEmpty(this.attributeConverterProviders, "attributeConverterProviders");
249248
this.nonAttributeValueMap.forEach((k, v) -> {
250249
if (v == null) {
251250
result.put(k, NULL_ATTRIBUTE_VALUE);

services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/document/EnhancedDocumentTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,9 @@ void enhancedDocWithNestedListAndMaps() {
119119
.build();
120120

121121
assertThat(simpleDoc.toJson()).isEqualTo("{\"HashKey\":\"abcdefg123\",\"nullKey\":null,\"numberKey\":2.0,"
122-
+ "\"sdkByte\":\"a\",\"booleanKey\":true,\"jsonKey\":{\"1\":[\"a\",\"b\","
122+
+ "\"sdkByte\":\"YQ==\",\"booleanKey\":true,\"jsonKey\":{\"1\":[\"a\",\"b\","
123123
+ "\"c\"],\"2\":1},\"stingSet\":[\"a\",\"b\",\"c\"],\"numberSet\":[1,2,3,4],"
124-
+ "\"sdkByteSet\":[\"a\"]}");
124+
+ "\"sdkByteSet\":[\"YQ==\"]}");
125125

126126

127127
assertThat(simpleDoc.isPresent("HashKey")).isTrue();

services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/document/EnhancedDocumentTestData.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ private void initializeTestData() {
169169
.putStringSet("stringSet", Stream.of("a", "b", "c").collect(Collectors.toSet()))
170170
.build())
171171
.json("{\"stringKey\":\"stringValue\",\"numberKey\":10,\"boolKey\":true,\"nullKey\":null,"
172-
+ "\"numberSet\":[1,2,3],\"sdkBytesSet\":[\"a\",\"b\",\"c\"],\"stringSet\":[\"a\","
172+
+ "\"numberSet\":[1,2,3],\"sdkBytesSet\":[\"YQ==\",\"Yg==\",\"Yw==\"],\"stringSet\":[\"a\","
173173
+ "\"b\",\"c\"]}")
174174
.attributeConverterProvider(defaultProvider())
175175
.build());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
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.functionaltests.document;
17+
18+
import static org.hamcrest.MatcherAssert.assertThat;
19+
import static org.hamcrest.Matchers.is;
20+
import static software.amazon.awssdk.enhanced.dynamodb.AttributeConverterProvider.defaultProvider;
21+
22+
import java.nio.ByteBuffer;
23+
import java.nio.charset.StandardCharsets;
24+
import java.util.LinkedHashMap;
25+
import java.util.LinkedHashSet;
26+
import java.util.Map;
27+
import java.util.stream.Collectors;
28+
import java.util.stream.Stream;
29+
import org.junit.After;
30+
import org.junit.Before;
31+
import org.junit.Test;
32+
import software.amazon.awssdk.core.SdkBytes;
33+
import software.amazon.awssdk.enhanced.dynamodb.AttributeValueType;
34+
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
35+
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable;
36+
import software.amazon.awssdk.enhanced.dynamodb.EnhancedType;
37+
import software.amazon.awssdk.enhanced.dynamodb.TableMetadata;
38+
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
39+
import software.amazon.awssdk.enhanced.dynamodb.document.EnhancedDocument;
40+
import software.amazon.awssdk.enhanced.dynamodb.functionaltests.LocalDynamoDbSyncTestBase;
41+
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
42+
import software.amazon.awssdk.services.dynamodb.model.DeleteTableRequest;
43+
44+
public class ComplexInputItemsTests extends LocalDynamoDbSyncTestBase {
45+
private final String tableName = getConcreteTableName("table-name");
46+
private DynamoDbEnhancedClient enhancedClient;
47+
private DynamoDbClient lowLevelClient;
48+
private DynamoDbTable<EnhancedDocument> docMappedtable;
49+
50+
@Before
51+
public void setUp() {
52+
lowLevelClient = getDynamoDbClient();
53+
enhancedClient = DynamoDbEnhancedClient.builder()
54+
.dynamoDbClient(lowLevelClient)
55+
.build();
56+
docMappedtable = enhancedClient.table(tableName,
57+
TableSchema.documentSchemaBuilder()
58+
.addIndexPartitionKey(TableMetadata.primaryIndexName(),
59+
"id",
60+
AttributeValueType.S)
61+
.addIndexSortKey(TableMetadata.primaryIndexName(), "sort",
62+
AttributeValueType.N)
63+
.attributeConverterProviders(defaultProvider())
64+
.build());
65+
docMappedtable.createTable();
66+
}
67+
68+
@After
69+
public void deleteTable() {
70+
getDynamoDbClient().deleteTable(DeleteTableRequest.builder()
71+
.tableName(tableName)
72+
.build());
73+
}
74+
75+
@Test
76+
public void getAndPutDocumentWithNoAttributeConverters() {
77+
78+
docMappedtable.putItem(EnhancedDocument.builder()
79+
.putString("id", "one")
80+
.putNumber("sort", 1)
81+
.putString("element", "noAttributeConverter")
82+
.build());
83+
84+
EnhancedDocument noConverterInGetItem = docMappedtable.getItem(EnhancedDocument.builder()
85+
.putString("id", "one")
86+
.putNumber("sort", 1)
87+
.build());
88+
assertThat(noConverterInGetItem.toJson(), is("{\"id\":\"one\",\"sort\":1,\"element\":\"noAttributeConverter\"}"));
89+
90+
}
91+
92+
93+
@Test
94+
public void bytesInAlTypes() {
95+
96+
Map<String, SdkBytes> bytesMap = new LinkedHashMap<>();
97+
bytesMap.put("key1", SdkBytes.fromByteArray("1".getBytes(StandardCharsets.UTF_8)));
98+
bytesMap.put("key2", SdkBytes.fromByteArray("2".getBytes(StandardCharsets.UTF_8)));
99+
EnhancedDocument enhancedDocument = EnhancedDocument.builder()
100+
.putString("id", "allTypesBytes")
101+
.putNumber("sort", 2)
102+
.put("put", SdkBytes.fromUtf8String("1"), SdkBytes.class)
103+
.putBytes("putBytes",
104+
SdkBytes.fromByteBuffer(ByteBuffer.wrap("1".getBytes(StandardCharsets.UTF_8))))
105+
.putBytesSet("putBytesSet",
106+
Stream.of(SdkBytes.fromUtf8String("1"),
107+
SdkBytes.fromUtf8String("2")).collect(Collectors.toCollection(LinkedHashSet::new)))
108+
.putList("putBytesList",
109+
Stream.of(SdkBytes.fromUtf8String("1"),
110+
SdkBytes.fromUtf8String("2")).collect(Collectors.toList()),
111+
EnhancedType.of(SdkBytes.class))
112+
.putMap("bytesMap", bytesMap, EnhancedType.of(String.class),
113+
EnhancedType.of(SdkBytes.class))
114+
.build();
115+
116+
docMappedtable.putItem(enhancedDocument);
117+
118+
119+
EnhancedDocument retrievedItem = docMappedtable.getItem(EnhancedDocument.builder()
120+
.putString("id", "allTypesBytes")
121+
.putNumber("sort", 2)
122+
.build());
123+
124+
assertThat(retrievedItem.toJson(), is("{\"putBytesSet\":[\"MQ==\",\"Mg==\"],\"putBytes\":\"MQ==\",\"putBytesList\":[\"MQ==\",\"Mg==\"],\"id\":\"allTypesBytes\",\"sort\":2,\"bytesMap\":{\"key1\":\"MQ==\",\"key2\":\"Mg==\"},\"put\":\"MQ==\"}"
125+
));
126+
}
127+
}

0 commit comments

Comments
 (0)