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.document; 17 18 import static org.assertj.core.api.Assertions.assertThatExceptionOfType; 19 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; 20 import static org.assertj.core.api.Assertions.assertThatIllegalStateException; 21 import static org.assertj.core.api.Assertions.assertThatNullPointerException; 22 import static software.amazon.awssdk.enhanced.dynamodb.AttributeConverterProvider.defaultProvider; 23 import static org.assertj.core.api.Assertions.assertThat; 24 import static software.amazon.awssdk.enhanced.dynamodb.document.EnhancedDocumentTestData.testDataInstance; 25 26 import com.fasterxml.jackson.core.JsonProcessingException; 27 import com.fasterxml.jackson.databind.ObjectMapper; 28 import java.math.BigDecimal; 29 import java.time.LocalDate; 30 import java.util.ArrayList; 31 import java.util.Arrays; 32 import java.util.HashMap; 33 import java.util.LinkedHashMap; 34 import java.util.List; 35 import java.util.Map; 36 import java.util.Set; 37 import java.util.UUID; 38 import java.util.stream.Collectors; 39 import java.util.stream.Stream; 40 import org.junit.jupiter.api.Assertions; 41 import org.junit.jupiter.api.Test; 42 import org.junit.jupiter.params.ParameterizedTest; 43 import org.junit.jupiter.params.provider.Arguments; 44 import org.junit.jupiter.params.provider.MethodSource; 45 import org.junit.jupiter.params.provider.ValueSource; 46 import software.amazon.awssdk.core.SdkBytes; 47 import software.amazon.awssdk.core.SdkNumber; 48 import software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider; 49 import software.amazon.awssdk.enhanced.dynamodb.EnhancedType; 50 import software.amazon.awssdk.enhanced.dynamodb.converters.document.CustomAttributeForDocumentConverterProvider; 51 import software.amazon.awssdk.enhanced.dynamodb.converters.document.CustomClassForDocumentAPI; 52 53 class EnhancedDocumentTest { 54 escapeDocumentStrings()55 private static Stream<Arguments> escapeDocumentStrings() { 56 char c = 0x0a; 57 return Stream.of( 58 Arguments.of(String.valueOf(c), "{\"key\":\"\\n\"}") 59 , Arguments.of("", "{\"key\":\"\"}") 60 , Arguments.of("\"", "{\"key\":\"\\\"\"}") 61 , Arguments.of("\\", "{\"key\":\"\\\\\"}") 62 , Arguments.of(" ", "{\"key\":\" \"}") 63 , Arguments.of("\t", "{\"key\":\"\\t\"}") 64 , Arguments.of("\n", "{\"key\":\"\\n\"}") 65 , Arguments.of("\r", "{\"key\":\"\\r\"}") 66 , Arguments.of("\f", "{\"key\":\"\\f\"}") 67 ); 68 } 69 unEscapeDocumentStrings()70 private static Stream<Arguments> unEscapeDocumentStrings() { 71 return Stream.of( 72 Arguments.of("'", "{\"key\":\"'\"}"), 73 Arguments.of("'single quote'", "{\"key\":\"'single quote'\"}") 74 ); 75 } 76 77 @Test enhancedDocumentGetters()78 void enhancedDocumentGetters() { 79 80 EnhancedDocument document = testDataInstance() 81 .dataForScenario("complexDocWithSdkBytesAndMapArrays_And_PutOverWritten") 82 .getEnhancedDocument(); 83 // Assert 84 assertThat(document.getString("stringKey")).isEqualTo("stringValue"); 85 assertThat(document.getNumber("numberKey")).isEqualTo(SdkNumber.fromInteger(1)); 86 assertThat(document.getList("numberList", EnhancedType.of(BigDecimal.class))) 87 .containsExactly(BigDecimal.valueOf(4), BigDecimal.valueOf(5), BigDecimal.valueOf(6)); 88 assertThat(document.getList("numberList", EnhancedType.of(SdkNumber.class))) 89 .containsExactly(SdkNumber.fromInteger(4), SdkNumber.fromInteger(5), SdkNumber.fromInteger(6)); 90 assertThat(document.get("simpleDate", EnhancedType.of(LocalDate.class))).isEqualTo(LocalDate.MIN); 91 assertThat(document.getStringSet("stringSet")).containsExactly("one", "two"); 92 assertThat(document.getBytes("sdkByteKey")).isEqualTo(SdkBytes.fromUtf8String("a")); 93 assertThat(document.getBytesSet("sdkByteSet")) 94 .containsExactlyInAnyOrder(SdkBytes.fromUtf8String("a"), SdkBytes.fromUtf8String("b")); 95 assertThat(document.getNumberSet("numberSetSet")).containsExactlyInAnyOrder(SdkNumber.fromInteger(1), 96 SdkNumber.fromInteger(2)); 97 98 Map<String, BigDecimal> expectedBigDecimalMap = new LinkedHashMap<>(); 99 expectedBigDecimalMap.put("78b3522c-2ab3-4162-8c5d-f093fa76e68c", BigDecimal.valueOf(3)); 100 expectedBigDecimalMap.put("4ae1f694-52ce-4cf6-8211-232ccf780da8", BigDecimal.valueOf(9)); 101 assertThat(document.getMap("simpleMap", EnhancedType.of(String.class), EnhancedType.of(BigDecimal.class))) 102 .containsExactlyEntriesOf(expectedBigDecimalMap); 103 104 Map<UUID, BigDecimal> expectedUuidBigDecimalMap = new LinkedHashMap<>(); 105 expectedUuidBigDecimalMap.put(UUID.fromString("78b3522c-2ab3-4162-8c5d-f093fa76e68c"), BigDecimal.valueOf(3)); 106 expectedUuidBigDecimalMap.put(UUID.fromString("4ae1f694-52ce-4cf6-8211-232ccf780da8"), BigDecimal.valueOf(9)); 107 assertThat(document.getMap("simpleMap", EnhancedType.of(UUID.class), EnhancedType.of(BigDecimal.class))) 108 .containsExactlyEntriesOf(expectedUuidBigDecimalMap); 109 } 110 111 @Test enhancedDocWithNestedListAndMaps()112 void enhancedDocWithNestedListAndMaps() { 113 /** 114 * No attributeConverters supplied, in this case it uses the {@link DefaultAttributeConverterProvider} and does not error 115 */ 116 EnhancedDocument simpleDoc = EnhancedDocument.builder() 117 .attributeConverterProviders(defaultProvider()) 118 .putString("HashKey", "abcdefg123") 119 .putNull("nullKey") 120 .putNumber("numberKey", 2.0) 121 .putBytes("sdkByte", SdkBytes.fromUtf8String("a")) 122 .putBoolean("booleanKey", true) 123 .putJson("jsonKey", "{\"1\": [\"a\", \"b\", \"c\"],\"2\": 1}") 124 .putStringSet("stingSet", 125 Stream.of("a", "b", "c").collect(Collectors.toSet())) 126 127 .putNumberSet("numberSet", Stream.of(1, 2, 3, 4).collect(Collectors.toSet())) 128 .putBytesSet("sdkByteSet", 129 Stream.of(SdkBytes.fromUtf8String("a")).collect(Collectors.toSet())) 130 .build(); 131 132 assertThat(simpleDoc.toJson()).isEqualTo("{\"HashKey\":\"abcdefg123\",\"nullKey\":null,\"numberKey\":2.0," 133 + "\"sdkByte\":\"YQ==\",\"booleanKey\":true,\"jsonKey\":{\"1\":[\"a\",\"b\"," 134 + "\"c\"],\"2\":1},\"stingSet\":[\"a\",\"b\",\"c\"],\"numberSet\":[1,2,3,4]," 135 + "\"sdkByteSet\":[\"YQ==\"]}"); 136 137 138 assertThat(simpleDoc.isPresent("HashKey")).isTrue(); 139 // No Null pointer or doesnot exist is thrown 140 assertThat(simpleDoc.isPresent("HashKey2")).isFalse(); 141 assertThat(simpleDoc.getString("HashKey")).isEqualTo("abcdefg123"); 142 assertThat(simpleDoc.isNull("nullKey")).isTrue(); 143 144 assertThat(simpleDoc.getNumber("numberKey")).isEqualTo(SdkNumber.fromDouble(2.0)); 145 assertThat(simpleDoc.getNumber("numberKey").bigDecimalValue().compareTo(BigDecimal.valueOf(2.0))).isEqualTo(0); 146 147 assertThat(simpleDoc.getBytes("sdkByte")).isEqualTo(SdkBytes.fromUtf8String("a")); 148 assertThat(simpleDoc.getBoolean("booleanKey")).isTrue(); 149 assertThat(simpleDoc.getJson("jsonKey")).isEqualTo("{\"1\":[\"a\",\"b\",\"c\"],\"2\":1}"); 150 assertThat(simpleDoc.getStringSet("stingSet")).isEqualTo(Stream.of("a", "b", "c").collect(Collectors.toSet())); 151 assertThat(simpleDoc.getList("stingSet", EnhancedType.of(String.class))).isEqualTo(Stream.of("a", "b", "c").collect(Collectors.toList())); 152 153 assertThat(simpleDoc.getNumberSet("numberSet") 154 .stream().map(n -> n.intValue()).collect(Collectors.toSet())) 155 .isEqualTo(Stream.of(1, 2, 3, 4).collect(Collectors.toSet())); 156 157 158 assertThat(simpleDoc.getBytesSet("sdkByteSet")).isEqualTo(Stream.of(SdkBytes.fromUtf8String("a")).collect(Collectors.toSet())); 159 160 161 // Trying to access some other Types 162 assertThatExceptionOfType(IllegalStateException.class).isThrownBy(() -> simpleDoc.getBoolean("sdkByteSet")) 163 .withMessageContaining("BooleanAttributeConverter cannot convert " 164 + "an attribute of type BS into the requested type class java.lang.Boolean"); 165 166 167 } 168 169 @Test testNullArgsInStaticConstructor()170 void testNullArgsInStaticConstructor() { 171 assertThatNullPointerException() 172 .isThrownBy(() -> EnhancedDocument.fromAttributeValueMap(null)) 173 .withMessage("attributeValueMap must not be null."); 174 175 assertThatNullPointerException() 176 .isThrownBy(() -> EnhancedDocument.fromJson(null)) 177 .withMessage("json must not be null."); 178 } 179 180 @Test accessingSetFromBuilderMethodsAsListsInDocuments()181 void accessingSetFromBuilderMethodsAsListsInDocuments() { 182 Set<String> stringSet = Stream.of("a", "b", "c").collect(Collectors.toSet()); 183 184 EnhancedDocument enhancedDocument = EnhancedDocument.builder() 185 .addAttributeConverterProvider(defaultProvider()) 186 .putStringSet("stringSet", stringSet) 187 .build(); 188 189 Set<String> retrievedStringSet = enhancedDocument.getStringSet("stringSet"); 190 assertThat(retrievedStringSet).isEqualTo(stringSet); 191 // Note that this behaviour is different in V1 , in order to remain consistent with EnhancedDDB converters 192 List<String> retrievedStringList = enhancedDocument.getList("stringSet", EnhancedType.of(String.class)); 193 assertThat(retrievedStringList).containsExactlyInAnyOrderElementsOf(stringSet); 194 } 195 196 @Test builder_ResetsTheOldValues_beforeJsonSetterIsCalled()197 void builder_ResetsTheOldValues_beforeJsonSetterIsCalled() { 198 199 EnhancedDocument enhancedDocument = EnhancedDocument.builder() 200 .attributeConverterProviders(defaultProvider()) 201 .putString("simpleKeyOriginal", "simpleValueOld") 202 .json("{\"stringKey\": \"stringValue\"}") 203 .putString("simpleKeyNew", "simpleValueNew") 204 .build(); 205 206 assertThat(enhancedDocument.toJson()).isEqualTo("{\"stringKey\":\"stringValue\",\"simpleKeyNew\":\"simpleValueNew\"}"); 207 assertThat(enhancedDocument.getString("simpleKeyOriginal")).isNull(); 208 209 } 210 211 @Test builder_with_NullKeys()212 void builder_with_NullKeys() { 213 String EMPTY_OR_NULL_ERROR = "Attribute name must not be null or empty."; 214 assertThatIllegalArgumentException() 215 .isThrownBy(() -> EnhancedDocument.builder().putString(null, "Sample")) 216 .withMessage(EMPTY_OR_NULL_ERROR); 217 218 assertThatIllegalArgumentException() 219 .isThrownBy(() -> EnhancedDocument.builder().putNull(null)) 220 .withMessage(EMPTY_OR_NULL_ERROR); 221 222 assertThatIllegalArgumentException() 223 .isThrownBy(() -> EnhancedDocument.builder().putNumber(null, 3)) 224 .withMessage(EMPTY_OR_NULL_ERROR); 225 226 assertThatIllegalArgumentException() 227 .isThrownBy(() -> EnhancedDocument.builder().putList(null, Arrays.asList(), EnhancedType.of(String.class))) 228 .withMessage(EMPTY_OR_NULL_ERROR); 229 230 assertThatIllegalArgumentException() 231 .isThrownBy(() -> EnhancedDocument.builder().putBytes(null, SdkBytes.fromUtf8String("a"))) 232 .withMessage(EMPTY_OR_NULL_ERROR); 233 234 assertThatIllegalArgumentException() 235 .isThrownBy(() -> EnhancedDocument.builder().putMap(null, new HashMap<>(), null, null)) 236 .withMessage(EMPTY_OR_NULL_ERROR); 237 238 assertThatIllegalArgumentException() 239 .isThrownBy(() -> EnhancedDocument.builder().putStringSet(null, Stream.of("a").collect(Collectors.toSet()))) 240 .withMessage(EMPTY_OR_NULL_ERROR); 241 242 assertThatIllegalArgumentException() 243 .isThrownBy(() -> EnhancedDocument.builder().putNumberSet(null, Stream.of(1).collect(Collectors.toSet()))) 244 .withMessage(EMPTY_OR_NULL_ERROR); 245 assertThatIllegalArgumentException() 246 .isThrownBy(() -> EnhancedDocument.builder().putStringSet(null, Stream.of("a").collect(Collectors.toSet()))) 247 .withMessage(EMPTY_OR_NULL_ERROR); 248 assertThatIllegalArgumentException() 249 .isThrownBy(() -> EnhancedDocument.builder().putBytesSet(null, Stream.of(SdkBytes.fromUtf8String("a")) 250 .collect(Collectors.toSet()))) 251 .withMessage(EMPTY_OR_NULL_ERROR); 252 } 253 254 @Test errorWhen_NoAttributeConverter_IsProviderIsDefined()255 void errorWhen_NoAttributeConverter_IsProviderIsDefined() { 256 EnhancedDocument enhancedDocument = testDataInstance().dataForScenario("simpleString") 257 .getEnhancedDocument() 258 .toBuilder() 259 .attributeConverterProviders(CustomAttributeForDocumentConverterProvider.create()) 260 .build(); 261 262 EnhancedType getType = EnhancedType.of(EnhancedDocumentTestData.class); 263 assertThatExceptionOfType(IllegalStateException.class).isThrownBy(() -> enhancedDocument.get( 264 "stringKey", getType 265 )).withMessage( 266 "AttributeConverter not found for class EnhancedType(java.lang.String). Please add an AttributeConverterProvider " 267 + "for this type. " 268 + "If it is a default type, add the DefaultAttributeConverterProvider to the builder."); 269 } 270 271 @Test access_NumberAttributeFromMap()272 void access_NumberAttributeFromMap() { 273 EnhancedDocument enhancedDocument = EnhancedDocument.fromJson(testDataInstance() 274 .dataForScenario("ElementsOfCustomType") 275 .getJson()); 276 277 assertThatExceptionOfType(IllegalStateException.class).isThrownBy(() -> 278 enhancedDocument.getNumber("customMapValue")) 279 .withMessage( 280 "software.amazon.awssdk.enhanced.dynamodb.internal.converter" 281 + ".attribute.SdkNumberAttributeConverter cannot convert" 282 + " an attribute of type M into the requested type class " 283 + "software.amazon.awssdk.core.SdkNumber"); 284 } 285 286 @Test access_CustomType_without_AttributeConverterProvider()287 void access_CustomType_without_AttributeConverterProvider() { 288 EnhancedDocument enhancedDocument = EnhancedDocument.fromJson(testDataInstance() 289 .dataForScenario("ElementsOfCustomType") 290 .getJson()); 291 292 EnhancedType enhancedType = EnhancedType.of( 293 CustomClassForDocumentAPI.class); 294 295 assertThatExceptionOfType(IllegalStateException.class).isThrownBy( 296 () -> enhancedDocument.get( 297 "customMapValue", enhancedType)).withMessage("Converter not found for " 298 + "EnhancedType(software.amazon.awssdk.enhanced.dynamodb.converters" 299 + ".document.CustomClassForDocumentAPI)"); 300 EnhancedDocument docWithCustomProvider = 301 enhancedDocument.toBuilder().attributeConverterProviders(CustomAttributeForDocumentConverterProvider.create(), 302 defaultProvider()).build(); 303 assertThat(docWithCustomProvider.get("customMapValue", EnhancedType.of(CustomClassForDocumentAPI.class))).isNotNull(); 304 } 305 306 @Test error_When_DefaultProviderIsPlacedCustomProvider()307 void error_When_DefaultProviderIsPlacedCustomProvider() { 308 CustomClassForDocumentAPI customObject = CustomClassForDocumentAPI.builder().string("str_one") 309 .longNumber(26L) 310 .aBoolean(false).build(); 311 EnhancedDocument afterCustomClass = EnhancedDocument.builder() 312 .attributeConverterProviders( 313 314 CustomAttributeForDocumentConverterProvider.create(), 315 defaultProvider()) 316 .putString("direct_attr", "sample_value") 317 .put("customObject", customObject, 318 EnhancedType.of(CustomClassForDocumentAPI.class)) 319 .build(); 320 321 assertThat(afterCustomClass.toJson()).isEqualTo("{\"direct_attr\":\"sample_value\",\"customObject\":{\"longNumber\":26," 322 + "\"string\":\"str_one\"}}"); 323 324 EnhancedDocument enhancedDocument = EnhancedDocument.builder() 325 .putString("direct_attr", "sample_value") 326 .put("customObject", customObject, 327 EnhancedType.of(CustomClassForDocumentAPI.class)).attributeConverterProviders 328 (defaultProvider(), 329 CustomAttributeForDocumentConverterProvider.create()) 330 .build(); 331 332 assertThatIllegalStateException().isThrownBy( 333 () -> enhancedDocument.toJson() 334 ).withMessage("Converter not found for " 335 + "EnhancedType(software.amazon.awssdk.enhanced.dynamodb.converters.document.CustomClassForDocumentAPI)"); 336 } 337 338 @ParameterizedTest 339 @ValueSource(strings = {"", " ", "\t", " ", "\n", "\r", "\f"}) invalidKeyNames(String escapingString)340 void invalidKeyNames(String escapingString) { 341 assertThatIllegalArgumentException().isThrownBy(() -> 342 EnhancedDocument.builder() 343 .attributeConverterProviders(defaultProvider()) 344 .putString(escapingString, "sample") 345 .build()) 346 .withMessageContaining("Attribute name must not be null or empty."); 347 } 348 349 @ParameterizedTest 350 @MethodSource("escapeDocumentStrings") escapingTheValues(String escapingString, String expectedJson)351 void escapingTheValues(String escapingString, String expectedJson) throws JsonProcessingException { 352 353 EnhancedDocument document = EnhancedDocument.builder() 354 .attributeConverterProviders(defaultProvider()) 355 .putString("key", escapingString) 356 .build(); 357 assertThat(document.toJson()).isEqualTo(expectedJson); 358 assertThat(new ObjectMapper().readTree(document.toJson())).isNotNull(); 359 } 360 361 @ParameterizedTest 362 @MethodSource("unEscapeDocumentStrings") unEscapingTheValues(String escapingString, String expectedJson)363 void unEscapingTheValues(String escapingString, String expectedJson) throws JsonProcessingException { 364 365 EnhancedDocument document = EnhancedDocument.builder() 366 .attributeConverterProviders(defaultProvider()) 367 .putString("key", escapingString) 368 .build(); 369 assertThat(document.toJson()).isEqualTo(expectedJson); 370 assertThat(new ObjectMapper().readTree(document.toJson())).isNotNull(); 371 372 } 373 374 @Test removeParameterFromDocument()375 void removeParameterFromDocument() { 376 EnhancedDocument allSimpleTypes = testDataInstance().dataForScenario("allSimpleTypes").getEnhancedDocument(); 377 assertThat(allSimpleTypes.isPresent("nullKey")).isTrue(); 378 assertThat(allSimpleTypes.isNull("nullKey")).isTrue(); 379 assertThat(allSimpleTypes.getNumber("numberKey").intValue()).isEqualTo(10); 380 assertThat(allSimpleTypes.getString("stringKey")).isEqualTo("stringValue"); 381 382 EnhancedDocument removedAttributesDoc = allSimpleTypes.toBuilder() 383 .remove("nullKey") 384 .remove("numberKey") 385 .build(); 386 387 assertThat(removedAttributesDoc.isPresent("nullKey")).isFalse(); 388 assertThat(removedAttributesDoc.isNull("nullKey")).isFalse(); 389 assertThat(removedAttributesDoc.isPresent("numberKey")).isFalse(); 390 assertThat(removedAttributesDoc.getString("stringKey")).isEqualTo("stringValue"); 391 392 assertThatIllegalArgumentException().isThrownBy( 393 () -> removedAttributesDoc.toBuilder().remove("")) 394 .withMessage("Attribute name must not be null or empty"); 395 396 397 assertThatIllegalArgumentException().isThrownBy( 398 () -> removedAttributesDoc.toBuilder().remove(null)) 399 .withMessage("Attribute name must not be null or empty"); 400 } 401 402 @Test nullValueInsertion()403 void nullValueInsertion() { 404 405 final String SAMPLE_KEY = "sampleKey"; 406 407 String expectedNullMessage = "Value for sampleKey must not be null. Use putNull API to insert a Null value"; 408 409 EnhancedDocument.Builder builder = EnhancedDocument.builder(); 410 assertThatNullPointerException().isThrownBy(() -> builder.putString(SAMPLE_KEY, null)).withMessage(expectedNullMessage); 411 assertThatNullPointerException().isThrownBy(() -> builder.put(SAMPLE_KEY, null, 412 EnhancedType.of(String.class))).withMessageContaining(expectedNullMessage); 413 assertThatNullPointerException().isThrownBy(() -> builder.putNumber(SAMPLE_KEY, null)).withMessage(expectedNullMessage); 414 assertThatNullPointerException().isThrownBy(() -> builder.putBytes(SAMPLE_KEY, null)).withMessage(expectedNullMessage); 415 assertThatNullPointerException().isThrownBy(() -> builder.putStringSet(SAMPLE_KEY, null)).withMessage(expectedNullMessage); 416 assertThatNullPointerException().isThrownBy(() -> builder.putBytesSet(SAMPLE_KEY, null)).withMessage(expectedNullMessage); 417 assertThatNullPointerException().isThrownBy(() -> builder.putJson(SAMPLE_KEY, null)).withMessage(expectedNullMessage); 418 assertThatNullPointerException().isThrownBy(() -> builder.putNumberSet(SAMPLE_KEY, null)).withMessage(expectedNullMessage); 419 assertThatNullPointerException().isThrownBy(() -> builder.putMap(SAMPLE_KEY, null, EnhancedType.of(String.class), 420 EnhancedType.of(String.class))).withMessage(expectedNullMessage); 421 assertThatNullPointerException().isThrownBy(() -> builder.putList(SAMPLE_KEY, null, EnhancedType.of(String.class))).withMessage(expectedNullMessage); 422 } 423 424 @Test accessingNulAttributeValue()425 void accessingNulAttributeValue() { 426 String NULL_KEY = "nullKey"; 427 EnhancedDocument enhancedDocument = 428 EnhancedDocument.builder().attributeConverterProviders(defaultProvider()).putNull(NULL_KEY).build(); 429 430 Assertions.assertNull(enhancedDocument.getString(NULL_KEY)); 431 Assertions.assertNull(enhancedDocument.getList(NULL_KEY, EnhancedType.of(String.class))); 432 assertThat(enhancedDocument.getBoolean(NULL_KEY)).isNull(); 433 } 434 435 @Test booleanValueRepresentation()436 void booleanValueRepresentation() { 437 EnhancedDocument.Builder builder = EnhancedDocument.builder() 438 .attributeConverterProviders(defaultProvider()); 439 assertThat(builder.putString("boolean", "true").build().getBoolean("boolean")).isTrue(); 440 assertThat(builder.putNumber("boolean", 1).build().getBoolean("boolean")).isTrue(); 441 } 442 443 @Test putAndGetOfCustomTypes_with_EnhancedTypeApi()444 void putAndGetOfCustomTypes_with_EnhancedTypeApi() { 445 CustomClassForDocumentAPI customObject = CustomClassForDocumentAPI.builder().string("str_one") 446 .longNumber(26L) 447 .aBoolean(false).build(); 448 EnhancedDocument enhancedDocument = EnhancedDocument.builder() 449 .attributeConverterProviders( 450 CustomAttributeForDocumentConverterProvider.create(), 451 defaultProvider()) 452 .putString("direct_attr", "sample_value") 453 .put("customObject", customObject, 454 EnhancedType.of(CustomClassForDocumentAPI.class)) 455 .build(); 456 457 assertThat(enhancedDocument.get("customObject", EnhancedType.of(CustomClassForDocumentAPI.class))) 458 .isEqualTo(customObject); 459 } 460 461 @Test putAndGetOfCustomTypes_with_ClassTypes()462 void putAndGetOfCustomTypes_with_ClassTypes() { 463 CustomClassForDocumentAPI customObject = CustomClassForDocumentAPI.builder().string("str_one") 464 .longNumber(26L) 465 .aBoolean(false).build(); 466 EnhancedDocument enhancedDocument = EnhancedDocument.builder() 467 .attributeConverterProviders( 468 CustomAttributeForDocumentConverterProvider.create(), 469 defaultProvider()) 470 .putString("direct_attr", "sample_value") 471 .put("customObject", customObject, 472 CustomClassForDocumentAPI.class) 473 .build(); 474 475 assertThat(enhancedDocument.get("customObject", CustomClassForDocumentAPI.class)).isEqualTo(customObject); 476 } 477 478 @Test error_when_usingClassGetPut_for_CollectionValues()479 void error_when_usingClassGetPut_for_CollectionValues(){ 480 481 assertThatIllegalArgumentException().isThrownBy( 482 () -> EnhancedDocument.builder().put("mapKey", new HashMap(), Map.class)) 483 .withMessage("Values of type Map are not supported by this API, please use the putMap API instead"); 484 485 assertThatIllegalArgumentException().isThrownBy( 486 () -> EnhancedDocument.builder().put("listKey", new ArrayList<>() , List.class)) 487 .withMessage("Values of type List are not supported by this API, please use the putList API instead"); 488 489 490 assertThatIllegalArgumentException().isThrownBy( 491 () -> EnhancedDocument.builder().build().get("mapKey", Map.class)) 492 .withMessage("Values of type Map are not supported by this API, please use the getMap API instead"); 493 494 assertThatIllegalArgumentException().isThrownBy( 495 () -> EnhancedDocument.builder().build().get("listKey" , List.class)) 496 .withMessage("Values of type List are not supported by this API, please use the getList API instead"); 497 } 498 } 499