diff --git a/sdk/cosmos/azure-cosmos-benchmark/src/main/java/com/azure/cosmos/benchmark/ReadMyWriteWorkflow.java b/sdk/cosmos/azure-cosmos-benchmark/src/main/java/com/azure/cosmos/benchmark/ReadMyWriteWorkflow.java index 6b208d35fcf5..9e6416bbe398 100644 --- a/sdk/cosmos/azure-cosmos-benchmark/src/main/java/com/azure/cosmos/benchmark/ReadMyWriteWorkflow.java +++ b/sdk/cosmos/azure-cosmos-benchmark/src/main/java/com/azure/cosmos/benchmark/ReadMyWriteWorkflow.java @@ -3,9 +3,9 @@ package com.azure.cosmos.benchmark; -import com.azure.cosmos.BridgeInternal; import com.azure.cosmos.CosmosBridgeInternal; import com.azure.cosmos.CosmosException; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.AsyncDocumentClient; import com.azure.cosmos.implementation.CosmosPagedFluxOptions; import com.azure.cosmos.implementation.Database; @@ -194,12 +194,12 @@ private Flux writeDocument(Integer i) { String randomVal = UUID.randomUUID().toString(); Document document = new Document(); document.setId(idString); - BridgeInternal.setProperty(document, partitionKey, idString); - BridgeInternal.setProperty(document, QUERY_FIELD_NAME, randomVal); - BridgeInternal.setProperty(document, "dataField1", randomVal); - BridgeInternal.setProperty(document, "dataField2", randomVal); - BridgeInternal.setProperty(document, "dataField3", randomVal); - BridgeInternal.setProperty(document, "dataField4", randomVal); + document.set(partitionKey, idString, CosmosItemSerializer.DEFAULT_SERIALIZER); + document.set(QUERY_FIELD_NAME, randomVal, CosmosItemSerializer.DEFAULT_SERIALIZER); + document.set("dataField1", randomVal, CosmosItemSerializer.DEFAULT_SERIALIZER); + document.set("dataField2", randomVal, CosmosItemSerializer.DEFAULT_SERIALIZER); + document.set("dataField3", randomVal, CosmosItemSerializer.DEFAULT_SERIALIZER); + document.set("dataField4", randomVal, CosmosItemSerializer.DEFAULT_SERIALIZER); Integer key = i == null ? cacheKey() : i; return client.createDocument(getCollectionLink(), document, null, false) diff --git a/sdk/cosmos/azure-cosmos-encryption/CHANGELOG.md b/sdk/cosmos/azure-cosmos-encryption/CHANGELOG.md index 5999316fb858..7173d79c5fad 100644 --- a/sdk/cosmos/azure-cosmos-encryption/CHANGELOG.md +++ b/sdk/cosmos/azure-cosmos-encryption/CHANGELOG.md @@ -3,6 +3,7 @@ ### 2.11.0-beta.1 (Unreleased) #### Features Added +* Added public APIs `getCustomeSerializer` and `setCustomSerializer` to allow customers to specify custom payload transformations or serialization settings. - See [PR 38997](https://github.com/Azure/azure-sdk-for-java/pull/38997) #### Breaking Changes diff --git a/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/CosmosEncryptionAsyncClient.java b/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/CosmosEncryptionAsyncClient.java index aa42d6639164..9b1f7cafa114 100644 --- a/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/CosmosEncryptionAsyncClient.java +++ b/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/CosmosEncryptionAsyncClient.java @@ -11,6 +11,7 @@ import com.azure.cosmos.CosmosAsyncContainer; import com.azure.cosmos.CosmosAsyncDatabase; import com.azure.cosmos.CosmosException; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.encryption.implementation.Constants; import com.azure.cosmos.encryption.implementation.EncryptionImplementationBridgeHelpers; import com.azure.cosmos.encryption.implementation.keyprovider.EncryptionKeyStoreProviderImpl; @@ -46,6 +47,8 @@ public final class CosmosEncryptionAsyncClient implements Closeable { private final EncryptionKeyStoreProviderImpl encryptionKeyStoreProviderImpl; private final static ImplementationBridgeHelpers.CosmosAsyncClientEncryptionKeyHelper.CosmosAsyncClientEncryptionKeyAccessor cosmosAsyncClientEncryptionKeyAccessor = ImplementationBridgeHelpers.CosmosAsyncClientEncryptionKeyHelper.getCosmosAsyncClientEncryptionKeyAccessor(); + private final static ImplementationBridgeHelpers.CosmosAsyncClientHelper.CosmosAsyncClientAccessor cosmosAsyncClientAccessor = ImplementationBridgeHelpers.CosmosAsyncClientHelper.getCosmosAsyncClientAccessor(); + CosmosEncryptionAsyncClient(CosmosAsyncClient cosmosAsyncClient, KeyEncryptionKeyResolver keyEncryptionKeyResolver, String keyEncryptionKeyResolverName) { @@ -230,6 +233,15 @@ private CosmosContainerProperties getContainerPropertiesWithVersionValidation(Co return cosmosContainerResponse.getProperties(); } + CosmosItemSerializer getEffectiveItemSerializer( + CosmosItemSerializer requestOptionsItemSerializer) { + + return cosmosAsyncClientAccessor + .getEffectiveItemSerializer( + this.getCosmosAsyncClient(), + requestOptionsItemSerializer); + } + static { EncryptionImplementationBridgeHelpers.CosmosEncryptionAsyncClientHelper.seCosmosEncryptionAsyncClientAccessor(new EncryptionImplementationBridgeHelpers.CosmosEncryptionAsyncClientHelper.CosmosEncryptionAsyncClientAccessor() { @Override diff --git a/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/CosmosEncryptionAsyncContainer.java b/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/CosmosEncryptionAsyncContainer.java index 0de8fc4a4a54..2b814c12ae7b 100644 --- a/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/CosmosEncryptionAsyncContainer.java +++ b/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/CosmosEncryptionAsyncContainer.java @@ -6,6 +6,7 @@ import com.azure.cosmos.CosmosAsyncContainer; import com.azure.cosmos.CosmosBridgeInternal; import com.azure.cosmos.CosmosException; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.encryption.implementation.Constants; import com.azure.cosmos.encryption.implementation.CosmosEncryptionQueryTransformer; import com.azure.cosmos.encryption.implementation.CosmosResponseFactory; @@ -18,7 +19,9 @@ import com.azure.cosmos.implementation.CosmosPagedFluxOptions; import com.azure.cosmos.implementation.HttpConstants; import com.azure.cosmos.implementation.ImplementationBridgeHelpers; -import com.azure.cosmos.implementation.ItemDeserializer; +import com.azure.cosmos.implementation.JsonSerializable; +import com.azure.cosmos.implementation.ObjectNodeMap; +import com.azure.cosmos.implementation.Strings; import com.azure.cosmos.implementation.apachecommons.lang.tuple.Pair; import com.azure.cosmos.implementation.batch.ItemBatchOperation; import com.azure.cosmos.implementation.batch.ItemBulkOperation; @@ -138,7 +141,7 @@ public Mono> createItem(T item, if (requestOptions == null) { requestOptions = new CosmosItemRequestOptions(); } - byte[] streamPayload = cosmosSerializerToStream(item); + byte[] streamPayload = cosmosSerializerToStream(item, getEffectiveItemSerializer(requestOptions)); return createItemHelper(streamPayload, requestOptions,(Class) item.getClass(), false ); } @@ -168,7 +171,8 @@ public Mono> createItem(T item, Preconditions.checkArgument(partitionKey != null, "partitionKey cannot be null for operations using " + "EncryptionContainer."); - byte[] streamPayload = cosmosSerializerToStream(item); + byte[] streamPayload = cosmosSerializerToStream(item, getEffectiveItemSerializer(requestOptions)); + return createItemHelper(streamPayload, partitionKey, requestOptions, (Class) item.getClass(), false); } @@ -309,7 +313,6 @@ public Mono> deleteItem(T item, CosmosItemRequest * Deletes all items in the Container with the specified partitionKey value. * Starts an asynchronous Cosmos DB background operation which deletes all items in the Container with the specified value. * The asynchronous Cosmos DB background operation runs using a percentage of user RUs. - * * After subscription the operation will be performed. * The {@link Mono} upon successful completion will contain a single Cosmos item response for all the deleted items. * @@ -367,7 +370,7 @@ public Mono> upsertItem(T item, CosmosItemRequestOptio requestOptions = new CosmosItemRequestOptions(); } - byte[] streamPayload = cosmosSerializerToStream(item); + byte[] streamPayload = cosmosSerializerToStream(item, getEffectiveItemSerializer(requestOptions)); return upsertItemHelper(streamPayload, requestOptions, (Class) item.getClass(), false); } @@ -397,7 +400,7 @@ public Mono> upsertItem(T item, + "EncryptionContainer."); - byte[] streamPayload = cosmosSerializerToStream(item); + byte[] streamPayload = cosmosSerializerToStream(item, getEffectiveItemSerializer(requestOptions)); return upsertItemHelper(streamPayload, partitionKey, requestOptions, (Class) item.getClass(), false); } @@ -443,8 +446,7 @@ public Mono> replaceItem(T item, Preconditions.checkArgument(partitionKey != null, "partitionKey cannot be null for operations using " + "EncryptionContainer."); - - byte[] streamPayload = cosmosSerializerToStream(item); + byte[] streamPayload = cosmosSerializerToStream(item, getEffectiveItemSerializer(requestOptions)); return replaceItemHelper(streamPayload, itemId, partitionKey, requestOptions, (Class) item.getClass(), false); } @@ -485,10 +487,14 @@ public Mono> readItem(String id, .orElse(new CosmosItemRequestOptions()); Mono> responseMessageMono = this.readItemHelper(id, partitionKey, options, false); + CosmosItemSerializer effectiveItemSerializer = + cosmosEncryptionAsyncClient.getEffectiveItemSerializer(options.getCustomSerializer()); return responseMessageMono.publishOn(encryptionScheduler).flatMap(cosmosItemResponse -> setByteArrayContent(cosmosItemResponse, - this.encryptionProcessor.decrypt(cosmosItemResponseBuilderAccessor.getByteArrayContent(cosmosItemResponse))) - .map(bytes -> this.responseFactory.createItemResponse(cosmosItemResponse, classType))); + this.encryptionProcessor.decrypt( + cosmosItemResponseBuilderAccessor.getByteArrayContent(cosmosItemResponse), + CosmosItemSerializer.DEFAULT_SERIALIZER)) + .map(bytes -> this.responseFactory.createItemResponse(cosmosItemResponse, classType, effectiveItemSerializer))); } /** @@ -722,17 +728,26 @@ private Mono> patchItemInternalHelper(String itemId, boolean isRetry) { setRequestHeaders(requestOptions); + CosmosItemSerializer effectiveItemSerializer = + cosmosEncryptionAsyncClient.getEffectiveItemSerializer(requestOptions.getCustomSerializer()); + CosmosPatchItemRequestOptions requestOptionsWithDefaultSerializer = requestOptions != null + ? (CosmosPatchItemRequestOptions)cosmosItemRequestOptionsAccessor + .clonePatchItemRequestOptions(requestOptions) + .setCustomSerializer(CosmosItemSerializer.DEFAULT_SERIALIZER) + : new CosmosPatchItemRequestOptions(); return this.encryptionProcessor.initEncryptionSettingsIfNotInitializedAsync() .thenReturn(this.encryptionProcessor.getEncryptionSettings()) .flatMap(encryptionSettings -> Mono.zip( checkAndGetEncryptedId(itemId, encryptionSettings), checkAndGetEncryptedPartitionKey(partitionKey, encryptionSettings)) .flatMap(encryptedIdPartitionKeyTuple -> - this.container.patchItem(encryptedIdPartitionKeyTuple.getT1(), encryptedIdPartitionKeyTuple.getT2(), encryptedCosmosPatchOperations, requestOptions, itemType).publishOn(encryptionScheduler). + this.container.patchItem(encryptedIdPartitionKeyTuple.getT1(), encryptedIdPartitionKeyTuple.getT2(), encryptedCosmosPatchOperations, requestOptionsWithDefaultSerializer, itemType).publishOn(encryptionScheduler). flatMap(cosmosItemResponse -> setByteArrayContent((CosmosItemResponse) cosmosItemResponse, - this.encryptionProcessor.decrypt(cosmosItemResponseBuilderAccessor.getByteArrayContent((CosmosItemResponse) cosmosItemResponse))) + this.encryptionProcessor.decrypt( + cosmosItemResponseBuilderAccessor.getByteArrayContent((CosmosItemResponse) cosmosItemResponse), + CosmosItemSerializer.DEFAULT_SERIALIZER)) .map(bytes -> this.responseFactory.createItemResponse((CosmosItemResponse) cosmosItemResponse, - itemType))).onErrorResume(exception -> { + itemType, effectiveItemSerializer))).onErrorResume(exception -> { if (!isRetry && exception instanceof CosmosException) { final CosmosException cosmosException = (CosmosException) exception; if (isIncorrectContainerRid(cosmosException)) { @@ -763,12 +778,19 @@ public CosmosAsyncContainer getCosmosAsyncContainer() { return container; } - byte[] cosmosSerializerToStream(T item) { - return EncryptionUtils.serializeJsonToByteArray(EncryptionUtils.getSimpleObjectMapper(), item); + byte[] cosmosSerializerToStream(T item, CosmosItemSerializer effectiveSerializer) { + return EncryptionUtils.serializeJsonToByteArray(effectiveSerializer, item); } - ItemDeserializer getItemDeserializer() { - return CosmosBridgeInternal.getAsyncDocumentClient(container.getDatabase()).getItemDeserializer(); + CosmosItemSerializer getEffectiveItemSerializer(CosmosItemRequestOptions requestOptions) { + return getEffectiveItemSerializer( + requestOptions != null ? requestOptions.getCustomSerializer() : null); + } + + CosmosItemSerializer getEffectiveItemSerializer(CosmosItemSerializer requestLevelItemSerializer) { + return CosmosBridgeInternal + .getAsyncDocumentClient(container.getDatabase()) + .getEffectiveItemSerializer(requestLevelItemSerializer); } Mono decryptResponseNode( @@ -825,15 +847,19 @@ private Mono> createItemHelper(byte[] streamPayload, Class itemClass, boolean isRetry) { this.setRequestHeaders(requestOptions); + CosmosItemSerializer effectiveItemSerializer = + cosmosEncryptionAsyncClient.getEffectiveItemSerializer(requestOptions.getCustomSerializer()); return this.encryptionProcessor.encrypt(streamPayload) .flatMap(encryptedPayload -> this.container.createItem( encryptedPayload, requestOptions) .publishOn(encryptionScheduler) .flatMap(cosmosItemResponse -> setByteArrayContent(cosmosItemResponse, - this.encryptionProcessor.decrypt(cosmosItemResponseBuilderAccessor.getByteArrayContent(cosmosItemResponse))) + this.encryptionProcessor.decrypt( + cosmosItemResponseBuilderAccessor.getByteArrayContent(cosmosItemResponse), + CosmosItemSerializer.DEFAULT_SERIALIZER)) .map(bytes -> this.responseFactory.createItemResponse(cosmosItemResponse, - itemClass))).onErrorResume(exception -> { + itemClass, effectiveItemSerializer))).onErrorResume(exception -> { if (!isRetry && exception instanceof CosmosException) { final CosmosException cosmosException = (CosmosException) exception; if (isIncorrectContainerRid(cosmosException)) { @@ -853,6 +879,15 @@ private Mono> createItemHelper(byte[] streamPayload, Class itemClass, boolean isRetry) { this.setRequestHeaders(requestOptions); + CosmosItemSerializer effectiveItemSerializer = + cosmosEncryptionAsyncClient.getEffectiveItemSerializer(requestOptions.getCustomSerializer()); + + // The actual replace happens on the already encrypted document + // so any custom serialization/deserialization happens here in the encryption wrapper + CosmosItemRequestOptions requestOptionsWithDefaultSerializer = ModelBridgeInternal + .clone(requestOptions) + .setCustomSerializer(CosmosItemSerializer.DEFAULT_SERIALIZER); + AtomicReference encryptedPK = new AtomicReference<>(); Mono encryptedPayloadMono = this.encryptionProcessor.initEncryptionSettingsIfNotInitializedAsync() @@ -867,12 +902,14 @@ private Mono> createItemHelper(byte[] streamPayload, .flatMap(encryptedPayload -> this.container.createItem( encryptedPayload, encryptedPK.get(), - requestOptions) + requestOptionsWithDefaultSerializer) .publishOn(encryptionScheduler) .flatMap(cosmosItemResponse -> setByteArrayContent(cosmosItemResponse, - this.encryptionProcessor.decrypt(cosmosItemResponseBuilderAccessor.getByteArrayContent(cosmosItemResponse))) + this.encryptionProcessor.decrypt( + cosmosItemResponseBuilderAccessor.getByteArrayContent(cosmosItemResponse), + CosmosItemSerializer.DEFAULT_SERIALIZER)) .map(bytes -> this.responseFactory.createItemResponse(cosmosItemResponse, - itemClass))).onErrorResume(exception -> { + itemClass, effectiveItemSerializer))).onErrorResume(exception -> { if (!isRetry && exception instanceof CosmosException) { final CosmosException cosmosException = (CosmosException) exception; if (isIncorrectContainerRid(cosmosException)) { @@ -891,14 +928,26 @@ private Mono> upsertItemHelper(byte[] streamPayload, Class itemClass, boolean isRetry) { this.setRequestHeaders(requestOptions); + + CosmosItemSerializer effectiveItemSerializer = + cosmosEncryptionAsyncClient.getEffectiveItemSerializer(requestOptions.getCustomSerializer()); + + // The actual replace happens on the already encrypted document + // so any custom serialization/deserialization happens her in the encryption wrapper + CosmosItemRequestOptions requestOptionsWithDefaultSerializer = ModelBridgeInternal + .clone(requestOptions) + .setCustomSerializer(CosmosItemSerializer.DEFAULT_SERIALIZER); + return this.encryptionProcessor.encrypt(streamPayload) .flatMap(encryptedPayload -> this.container.upsertItem( encryptedPayload, - requestOptions) + requestOptionsWithDefaultSerializer) .publishOn(encryptionScheduler) .flatMap(cosmosItemResponse -> setByteArrayContent(cosmosItemResponse, - this.encryptionProcessor.decrypt(cosmosItemResponseBuilderAccessor.getByteArrayContent(cosmosItemResponse))) - .map(bytes -> this.responseFactory.createItemResponse(cosmosItemResponse, itemClass))) + this.encryptionProcessor.decrypt( + cosmosItemResponseBuilderAccessor.getByteArrayContent(cosmosItemResponse), + CosmosItemSerializer.DEFAULT_SERIALIZER)) + .map(bytes -> this.responseFactory.createItemResponse(cosmosItemResponse, itemClass, effectiveItemSerializer))) .onErrorResume(exception -> { if (!isRetry && exception instanceof CosmosException) { final CosmosException cosmosException = (CosmosException) exception; @@ -919,6 +968,16 @@ private Mono> upsertItemHelper(byte[] streamPayload, Class itemClass, boolean isRetry) { this.setRequestHeaders(requestOptions); + + CosmosItemSerializer effectiveItemSerializer = + cosmosEncryptionAsyncClient.getEffectiveItemSerializer(requestOptions.getCustomSerializer()); + + // The actual replace happens on the already encrypted document + // so any custom serialization/deserialization happens her in the encryption wrapper + CosmosItemRequestOptions requestOptionsWithDefaultSerializer = ModelBridgeInternal + .clone(requestOptions) + .setCustomSerializer(CosmosItemSerializer.DEFAULT_SERIALIZER); + AtomicReference encryptedPK = new AtomicReference<>(); Mono encryptedPayloadMono = this.encryptionProcessor.initEncryptionSettingsIfNotInitializedAsync() .thenReturn(this.encryptionProcessor.getEncryptionSettings()) @@ -932,11 +991,13 @@ private Mono> upsertItemHelper(byte[] streamPayload, .flatMap(encryptedPayload -> this.container.upsertItem( encryptedPayload, encryptedPK.get(), - requestOptions) + requestOptionsWithDefaultSerializer) .publishOn(encryptionScheduler) .flatMap(cosmosItemResponse -> setByteArrayContent(cosmosItemResponse, - this.encryptionProcessor.decrypt(cosmosItemResponseBuilderAccessor.getByteArrayContent(cosmosItemResponse))) - .map(bytes -> this.responseFactory.createItemResponse(cosmosItemResponse, itemClass))) + this.encryptionProcessor.decrypt( + cosmosItemResponseBuilderAccessor.getByteArrayContent(cosmosItemResponse), + CosmosItemSerializer.DEFAULT_SERIALIZER)) + .map(bytes -> this.responseFactory.createItemResponse(cosmosItemResponse, itemClass, effectiveItemSerializer))) .onErrorResume(exception -> { if (!isRetry && exception instanceof CosmosException) { final CosmosException cosmosException = (CosmosException) exception; @@ -958,6 +1019,8 @@ private Mono> replaceItemHelper(byte[] streamPayload, Class itemClass, boolean isRetry) { this.setRequestHeaders(requestOptions); + CosmosItemSerializer effectiveItemSerializer = + cosmosEncryptionAsyncClient.getEffectiveItemSerializer(requestOptions.getCustomSerializer()); AtomicReference encryptedPK = new AtomicReference<>(); AtomicReference encryptedId = new AtomicReference<>(); Mono encryptedPayloadMono = this.encryptionProcessor.initEncryptionSettingsIfNotInitializedAsync() @@ -971,16 +1034,24 @@ private Mono> replaceItemHelper(byte[] streamPayload, return this.encryptionProcessor.encrypt(streamPayload); }); + // The actual replace happens on the already encrypted document + // so any custom serialization/deserialization happens her in the encryption wrapper + CosmosItemRequestOptions requestOptionsWithDefaultSerializer = ModelBridgeInternal + .clone(requestOptions) + .setCustomSerializer(CosmosItemSerializer.DEFAULT_SERIALIZER); + return encryptedPayloadMono .flatMap(encryptedPayload -> this.container.replaceItem( encryptedPayload, encryptedId.get(), encryptedPK.get(), - requestOptions) + requestOptionsWithDefaultSerializer) .publishOn(encryptionScheduler) .flatMap(cosmosItemResponse -> setByteArrayContent(cosmosItemResponse, - this.encryptionProcessor.decrypt(cosmosItemResponseBuilderAccessor.getByteArrayContent(cosmosItemResponse))) - .map(bytes -> this.responseFactory.createItemResponse(cosmosItemResponse, itemClass))) + this.encryptionProcessor.decrypt( + cosmosItemResponseBuilderAccessor.getByteArrayContent(cosmosItemResponse), + CosmosItemSerializer.DEFAULT_SERIALIZER)) + .map(bytes -> this.responseFactory.createItemResponse(cosmosItemResponse, itemClass, effectiveItemSerializer))) .onErrorResume(exception -> { if (!isRetry && exception instanceof CosmosException) { final CosmosException cosmosException = (CosmosException) exception; @@ -1000,13 +1071,14 @@ private CosmosPagedFlux queryItemsHelper(SqlQuerySpec sqlQuerySpec, Class classType, boolean isRetry) { + CosmosItemSerializer effectiveSerializer = this + .getCosmosEncryptionAsyncClient() + .getEffectiveItemSerializer(options != null ? options.getCustomSerializer(): null); return UtilBridgeInternal.createCosmosPagedFlux(pagedFluxOptions -> { AtomicBoolean shouldRetry = new AtomicBoolean(!isRetry); - Transformer transformer = new CosmosEncryptionQueryTransformer( this.encryptionScheduler, this.getEncryptionProcessor(), - this.getItemDeserializer(), classType, false); @@ -1014,7 +1086,7 @@ private CosmosPagedFlux queryItemsHelper(SqlQuerySpec sqlQuerySpec, transformer, sqlQuerySpec, options, - pagedFluxOptions + effectiveSerializer ).apply(pagedFluxOptions); return result @@ -1034,7 +1106,7 @@ private CosmosPagedFlux queryItemsHelper(SqlQuerySpec sqlQuerySpec, transformer, sqlQuerySpec, options, - pagedFluxOptions + effectiveSerializer ).apply(pagedFluxOptions); }) ); @@ -1049,25 +1121,31 @@ private Function>> transformQue Transformer transformer, SqlQuerySpec sqlQuerySpec, CosmosQueryRequestOptions queryRequestOptions, - CosmosPagedFluxOptions pagedFluxOptions) { + CosmosItemSerializer effectiveSerializer) { - CosmosQueryRequestOptions finalOptions = setRequestHeaders(queryRequestOptions); + CosmosQueryRequestOptions finalOptions = setRequestHeaders(cosmosQueryRequestOptionsAccessor + .clone(queryRequestOptions) + .setCustomSerializer(CosmosItemSerializer.DEFAULT_SERIALIZER)); return transformer.transform( cosmosAsyncContainerAccessor.queryItemsInternalFunc( this.container, sqlQuerySpec, finalOptions, - JsonNode.class) + JsonNode.class), + effectiveSerializer ); } private Function>> transformQueryChangeFeedInternal( Transformer transformer, CosmosChangeFeedRequestOptions changeFeedRequestOptions, - CosmosPagedFluxOptions pagedFluxOptions) { + CosmosPagedFluxOptions pagedFluxOptions, + CosmosItemSerializer effectiveSerializer) { - CosmosChangeFeedRequestOptions finalOptions = setRequestHeaders(changeFeedRequestOptions);; + CosmosChangeFeedRequestOptions finalOptions = setRequestHeaders( + cosmosChangeFeedRequestOptionsAccessor.clone(changeFeedRequestOptions) + .setCustomSerializer(CosmosItemSerializer.DEFAULT_SERIALIZER)); getEffectiveCosmosChangeFeedRequestOptions(pagedFluxOptions, finalOptions); return transformer.transform( @@ -1075,7 +1153,8 @@ private Function>> transformQue .queryChangeFeedInternalFunc( this.container, finalOptions, - JsonNode.class) + JsonNode.class), + effectiveSerializer ); } @@ -1083,9 +1162,11 @@ private Function>> transformQue Transformer transformer, Mono sqlQuerySpecMono, CosmosQueryRequestOptions options, - CosmosPagedFluxOptions pagedFluxOptions) { + CosmosItemSerializer effectiveSerializer) { - CosmosQueryRequestOptions finalOptions = setRequestHeaders(options); + CosmosQueryRequestOptions finalOptions = setRequestHeaders(cosmosQueryRequestOptionsAccessor + .clone(options) + .setCustomSerializer(CosmosItemSerializer.DEFAULT_SERIALIZER)); return transformer.transform( cosmosAsyncContainerAccessor.queryItemsInternalFuncWithMonoSqlQuerySpec( @@ -1093,7 +1174,8 @@ private Function>> transformQue sqlQuerySpecMono, finalOptions, JsonNode.class - ) + ), + effectiveSerializer ); } @@ -1101,20 +1183,23 @@ private CosmosPagedFlux queryChangeFeedHelper(CosmosChangeFeedRequestOpti Class classType, boolean isRetry) { + CosmosItemSerializer effectiveSerializer = this + .getCosmosEncryptionAsyncClient() + .getEffectiveItemSerializer(options != null ? options.getCustomSerializer() : null); return UtilBridgeInternal.createCosmosPagedFlux(pagedFluxOptions -> { AtomicBoolean shouldRetry = new AtomicBoolean(!isRetry); Transformer transformer = new CosmosEncryptionQueryTransformer( this.encryptionScheduler, this.getEncryptionProcessor(), - this.getItemDeserializer(), classType, true); Flux> result = this.transformQueryChangeFeedInternal( transformer, options, - pagedFluxOptions + pagedFluxOptions, + effectiveSerializer ).apply(pagedFluxOptions); return result @@ -1133,7 +1218,8 @@ private CosmosPagedFlux queryChangeFeedHelper(CosmosChangeFeedRequestOpti return this.transformQueryChangeFeedInternal( transformer, options, - pagedFluxOptions + pagedFluxOptions, + effectiveSerializer ).apply(pagedFluxOptions); }) ); @@ -1150,13 +1236,16 @@ private CosmosPagedFlux queryItemsHelperWithMonoSqlQuerySpec(Mono classType, boolean isRetry) { + CosmosItemSerializer effectiveSerializer = this + .getCosmosEncryptionAsyncClient() + .getEffectiveItemSerializer(options != null ? options.getCustomSerializer(): null); + return UtilBridgeInternal.createCosmosPagedFlux(pagedFluxOptions -> { AtomicBoolean shouldRetry = new AtomicBoolean(!isRetry); Transformer transformer = new CosmosEncryptionQueryTransformer( this.encryptionScheduler, this.getEncryptionProcessor(), - this.getItemDeserializer(), classType, false); @@ -1164,7 +1253,7 @@ private CosmosPagedFlux queryItemsHelperWithMonoSqlQuerySpec(Mono CosmosPagedFlux queryItemsHelperWithMonoSqlQuerySpec(Mono { - return this.transformQueryItemsInternal( + Flux.defer(() -> this.transformQueryItemsInternal( transformer, specWithEncryptionAccessor.getSqlQuerySpec(sqlQuerySpecWithEncryption), options, - pagedFluxOptions - ).apply(pagedFluxOptions); - }) + effectiveSerializer + ).apply(pagedFluxOptions) + ) ); } } @@ -1262,6 +1350,9 @@ public Mono executeCosmosBatch(CosmosBatch cosmosBatch, Cos final CosmosBatchRequestOptions cosmosBatchRequestOptions = Optional.ofNullable(requestOptions) .orElse(new CosmosBatchRequestOptions()); + final CosmosItemSerializer effectiveItemSerializer = this + .getEffectiveItemSerializer(cosmosBatchRequestOptions.getCustomSerializer()); + List>> monoList = new ArrayList<>(); for (ItemBatchOperation itemBatchOperation : cosmosBatchAccessor.getOperationsInternal(cosmosBatch)) { Mono> itemBatchOperationMono = null; @@ -1270,18 +1361,26 @@ public Mono executeCosmosBatch(CosmosBatch cosmosBatch, Cos .thenReturn(this.encryptionProcessor.getEncryptionSettings()) .flatMap(encryptionSettings -> { try { - Field id = itemBatchOperation.getItem().getClass().getDeclaredField(Constants.PROPERTY_NAME_ID); - id.setAccessible(true); + String idValue = getIdValue(itemBatchOperation); return Mono.zip( - checkAndGetEncryptedId((String) id.get(itemBatchOperation.getItem()), encryptionSettings), + checkAndGetEncryptedId(idValue, encryptionSettings), checkAndGetEncryptedPartitionKey(itemBatchOperation.getPartitionKeyValue(), encryptionSettings)); } catch (IllegalAccessException | NoSuchFieldException e) { return Mono.error(e); } }) .flatMap(encryptedIdPartitionKeyTuple -> { - ObjectNode objectNode = - EncryptionUtils.getSimpleObjectMapper().valueToTree(itemBatchOperation.getItem()); + + + Map jsonTree = effectiveItemSerializer + .serialize( + itemBatchOperation.getItem() + ); + + ObjectNode objectNode = jsonTree instanceof ObjectNodeMap + ? ((ObjectNodeMap)jsonTree).getObjectNode().deepCopy() + : EncryptionUtils.getSimpleObjectMapper().valueToTree(jsonTree); + return encryptionProcessor.encryptObjectNode(objectNode).map(encryptedItem -> new ItemBatchOperation<>( itemBatchOperation.getOperationType(), encryptedIdPartitionKeyTuple.getT1(), @@ -1316,14 +1415,20 @@ public Mono executeCosmosBatch(CosmosBatch cosmosBatch, Cos CosmosBatch encryptedCosmosBatch = CosmosBatch.createCosmosBatch(cosmosBatch.getPartitionKeyValue()); + CosmosBatchRequestOptions batchRequestOptionsWithDefaultSerializer = cosmosBatchRequestOptionsAccessor + .clone(cosmosBatchRequestOptions) + .setCustomSerializer(CosmosItemSerializer.DEFAULT_SERIALIZER); + return encryptedOperationListMono.flatMap(itemBatchOperations -> { cosmosBatchAccessor.getOperationsInternal(encryptedCosmosBatch).addAll(itemBatchOperations); - return executeCosmosBatchHelper(encryptedCosmosBatch, cosmosBatchRequestOptions, false); + return executeCosmosBatchHelper( + encryptedCosmosBatch, batchRequestOptionsWithDefaultSerializer, effectiveItemSerializer, false); }); } private Mono executeCosmosBatchHelper(CosmosBatch encryptedCosmosBatch, CosmosBatchRequestOptions requestOptions, + CosmosItemSerializer effectiveItemSerializer, boolean isRetry) { setRequestHeaders(requestOptions); return this.container.executeCosmosBatch(encryptedCosmosBatch, requestOptions).flatMap(cosmosBatchResponse -> { @@ -1333,7 +1438,8 @@ private Mono executeCosmosBatchHelper(CosmosBatch encrypted if (!isRetry && cosmosBatchResponse.getSubStatusCode() == 1024) { this.encryptionProcessor.getIsEncryptionSettingsInitDone().set(false); return this.encryptionProcessor.initializeEncryptionSettingsAsync(true).then - (Mono.defer(() -> executeCosmosBatchHelper(encryptedCosmosBatch, requestOptions, true))); + (Mono.defer(() -> executeCosmosBatchHelper( + encryptedCosmosBatch, requestOptions, effectiveItemSerializer, true))); } List> decryptMonoList = new ArrayList<>(); @@ -1344,6 +1450,10 @@ private Mono executeCosmosBatchHelper(CosmosBatch encrypted if (objectNode != null) { decryptMonoList.add(encryptionProcessor.decryptJsonNode(objectNode).flatMap(jsonNode -> { cosmosBatchOperationResultAccessor.setResourceObject(cosmosBatchOperationResult, (ObjectNode) jsonNode); + cosmosBatchOperationResultAccessor.setEffectiveItemSerializer( + cosmosBatchOperationResult, + effectiveItemSerializer + ); return Mono.empty(); })); } @@ -1357,7 +1467,8 @@ private Mono executeCosmosBatchHelper(CosmosBatch encrypted if (isIncorrectContainerRid(cosmosException)) { this.encryptionProcessor.getIsEncryptionSettingsInitDone().set(false); return this.encryptionProcessor.initializeEncryptionSettingsAsync(true).then - (Mono.defer(() -> executeCosmosBatchHelper(encryptedCosmosBatch, requestOptions, true))); + (Mono.defer(() -> executeCosmosBatchHelper( + encryptedCosmosBatch, requestOptions, effectiveItemSerializer, true))); } } return Mono.error(exception); @@ -1390,6 +1501,29 @@ public Flux> executeBulkOperati return this.executeBulkOperations(operations, new CosmosBulkExecutionOptions()); } + private static String getIdValue(CosmosItemOperation itemOperation) + throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException { + + String idSnapshot = itemOperation.getId(); + if (!Strings.isNullOrEmpty(idSnapshot)) { + return idSnapshot; + } + + Class itemClass = itemOperation.getItem().getClass(); + if (ObjectNode.class.isAssignableFrom(itemClass)) { + return ((ObjectNode)itemOperation.getItem()).get("id").textValue(); + } + + if (JsonSerializable.class.isAssignableFrom(itemClass)) { + return ((JsonSerializable)itemOperation.getItem()).get(Constants.PROPERTY_NAME_ID).toString(); + } + + Field id = itemClass.getDeclaredField(Constants.PROPERTY_NAME_ID); + id.setAccessible(true); + + return (String) id.get(itemOperation.getItem()); + } + /** * Executes flux of operations in Bulk. * @@ -1420,6 +1554,8 @@ public Flux> executeBulkOperati final CosmosBulkExecutionOptions cosmosBulkExecutionOptions = Optional.ofNullable(bulkOptions) .orElse(new CosmosBulkExecutionOptions()); + CosmosItemSerializer effectiveItemSerializer = + this.getEffectiveItemSerializer(cosmosBulkExecutionOptions.getCustomSerializer()); Flux operationFlux = operations.flatMap(cosmosItemOperation -> { Mono cosmosItemOperationMono = null; if (cosmosItemOperation.getItem() != null) { @@ -1427,18 +1563,22 @@ public Flux> executeBulkOperati .thenReturn(this.encryptionProcessor.getEncryptionSettings()) .flatMap( encryptionSettings -> { try { - Field id = cosmosItemOperation.getItem().getClass().getDeclaredField(Constants.PROPERTY_NAME_ID); - id.setAccessible(true); + String idValue = getIdValue(cosmosItemOperation); return Mono.zip( - checkAndGetEncryptedId((String) id.get(cosmosItemOperation.getItem()), encryptionSettings), + checkAndGetEncryptedId(idValue, encryptionSettings), checkAndGetEncryptedPartitionKey(cosmosItemOperation.getPartitionKeyValue(), encryptionSettings)); } catch (IllegalAccessException | NoSuchFieldException e) { return Mono.error(e); } }) .flatMap(encryptedIdPartitionKeyTuple -> { - ObjectNode objectNode = - EncryptionUtils.getSimpleObjectMapper().valueToTree(cosmosItemOperation.getItem()); + Map jsonTree = effectiveItemSerializer + .serialize(cosmosItemOperation.getItem()); + + ObjectNode objectNode = jsonTree instanceof ObjectNodeMap + ? ((ObjectNodeMap)jsonTree).getObjectNode().deepCopy() + : EncryptionUtils.getSimpleObjectMapper().valueToTree(jsonTree); + assert cosmosItemOperation instanceof ItemBulkOperation; return this.encryptionProcessor.encryptObjectNode(objectNode).map(encryptedItem -> new ItemBulkOperation<>( cosmosItemOperation.getOperationType(), @@ -1471,13 +1611,19 @@ public Flux> executeBulkOperati Mono> listMono = operationFlux.collectList(); setRequestHeaders(cosmosBulkExecutionOptions); operationFlux = listMono.flatMapMany(Flux::fromIterable); - return executeBulkOperationsHelper(operationFlux, cosmosBulkExecutionOptions, false); + + CosmosBulkExecutionOptions executionOptionsWithDefaultSerializer = cosmosBulkExecutionOptionsAccessor + .clone(cosmosBulkExecutionOptions) + .setCustomSerializer(CosmosItemSerializer.DEFAULT_SERIALIZER); + + return executeBulkOperationsHelper( + operationFlux, executionOptionsWithDefaultSerializer, effectiveItemSerializer); } @SuppressWarnings("unchecked") private Flux> executeBulkOperationsHelper(Flux operations, CosmosBulkExecutionOptions bulkOptions, - boolean isRetry) { + CosmosItemSerializer effectiveItemSerializer) { return this.container.executeBulkOperations(operations, bulkOptions).flatMap(cosmosBulkOperationResponse -> { CosmosBulkItemResponse cosmosBulkItemResponse = cosmosBulkOperationResponse.getResponse(); @@ -1487,6 +1633,7 @@ private Flux> executeBulkOperat Mono jsonNodeMono = encryptionProcessor.decryptJsonNode(objectNode).flatMap(jsonNode -> { cosmosBulkItemResponseAccessor.setResourceObject(cosmosBulkItemResponse, (ObjectNode) jsonNode); + cosmosBulkItemResponseAccessor.setEffectiveItemSerializer(cosmosBulkItemResponse, effectiveItemSerializer); return Mono.just(jsonNode); }); return jsonNodeMono.flux().flatMap(jsonNode -> Flux.just((CosmosBulkOperationResponse) cosmosBulkOperationResponse)); diff --git a/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/implementation/CosmosEncryptionQueryTransformer.java b/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/implementation/CosmosEncryptionQueryTransformer.java index c46cb04e00cf..46af091da846 100644 --- a/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/implementation/CosmosEncryptionQueryTransformer.java +++ b/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/implementation/CosmosEncryptionQueryTransformer.java @@ -3,49 +3,58 @@ package com.azure.cosmos.encryption.implementation; import com.azure.cosmos.BridgeInternal; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.CosmosPagedFluxOptions; -import com.azure.cosmos.implementation.ItemDeserializer; +import com.azure.cosmos.implementation.ObjectNodeMap; +import com.azure.cosmos.implementation.PrimitiveJsonNodeMap; +import com.azure.cosmos.implementation.Utils; import com.azure.cosmos.implementation.query.Transformer; import com.azure.cosmos.models.FeedResponse; import com.azure.cosmos.models.ModelBridgeInternal; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.scheduler.Scheduler; import java.util.List; +import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; +import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; + public class CosmosEncryptionQueryTransformer implements Transformer { private final Scheduler encryptionScheduler; private final EncryptionProcessor encryptionProcessor; - private final ItemDeserializer itemDeserializer; private final Class classType; private final boolean isChangeFeed; public CosmosEncryptionQueryTransformer( Scheduler encryptionScheduler, EncryptionProcessor encryptionProcessor, - ItemDeserializer itemDeserializer, Class classType, Boolean isChangeFeed) { + this.encryptionScheduler = encryptionScheduler; this.encryptionProcessor = encryptionProcessor; - this.itemDeserializer = itemDeserializer; this.classType = classType; this.isChangeFeed = isChangeFeed; } @Override - public Function>> transform(Function>> func) { - return queryDecryptionTransformer(this.classType, this.isChangeFeed, func); + public Function>> transform( + Function>> func, + CosmosItemSerializer effectiveSerializer) { + + return queryDecryptionTransformer(this.classType, this.isChangeFeed, func, effectiveSerializer); } - private Function>> queryDecryptionTransformer( - Class classType, + private Function>> queryDecryptionTransformer( + Class classType, boolean isChangeFeed, - Function>> func) { + Function>> func, + CosmosItemSerializer effectiveSerializer) { return func.andThen(flux -> flux.publishOn(encryptionScheduler) .flatMap( @@ -55,9 +64,27 @@ private Function>> queryDecrypt ModelBridgeInternal.getNoChangesFromFeedResponse(page) : false; List> jsonNodeArrayMonoList = - page.getResults().stream().map(jsonNode -> decryptResponseNode(jsonNode)).collect(Collectors.toList()); + page.getResults().stream().map(jsonNode -> decryptResponseNode(jsonNode)) + .collect(Collectors.toList()); return Flux.concat(jsonNodeArrayMonoList).map( - item -> this.itemDeserializer.convert(classType, item) + item -> { + Map decryptedJsonTree; + + if (item instanceof ObjectNode) { + decryptedJsonTree = new ObjectNodeMap((ObjectNode)item); + } else if (item.isValueNode()) { + decryptedJsonTree = new PrimitiveJsonNodeMap(item); + } else { + return Utils.getSimpleObjectMapper() + .convertValue( + item, + classType); + } + + return effectiveSerializer.deserialize( + decryptedJsonTree, + classType); + } ).collectList().map(itemList -> BridgeInternal.createFeedResponseWithQueryMetrics(itemList, page.getResponseHeaders(), BridgeInternal.queryMetricsFromFeedResponse(page), diff --git a/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/implementation/CosmosResponseFactory.java b/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/implementation/CosmosResponseFactory.java index 73d36fe08ed3..db139cac9541 100644 --- a/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/implementation/CosmosResponseFactory.java +++ b/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/implementation/CosmosResponseFactory.java @@ -3,9 +3,9 @@ package com.azure.cosmos.encryption.implementation; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.ImplementationBridgeHelpers; import com.azure.cosmos.implementation.ImplementationBridgeHelpers.CosmosItemResponseHelper.CosmosItemResponseBuilderAccessor; -import com.azure.cosmos.implementation.ItemDeserializer; import com.azure.cosmos.models.CosmosItemResponse; public class CosmosResponseFactory { @@ -17,10 +17,11 @@ public CosmosResponseFactory() { } public CosmosItemResponse createItemResponse(CosmosItemResponse responseMessage, - Class classType) { + Class classType, + CosmosItemSerializer effectiveItemSerializer) { return cosmosItemResponseBuilderAccessor.createCosmosItemResponse( responseMessage, classType, - new ItemDeserializer.JsonDeserializer()); + effectiveItemSerializer); } } diff --git a/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/implementation/EncryptionProcessor.java b/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/implementation/EncryptionProcessor.java index 36e631ee7d79..cc244b496708 100644 --- a/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/implementation/EncryptionProcessor.java +++ b/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/implementation/EncryptionProcessor.java @@ -5,6 +5,7 @@ import com.azure.cosmos.BridgeInternal; import com.azure.cosmos.CosmosAsyncContainer; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.encryption.CosmosEncryptionAsyncClient; import com.azure.cosmos.encryption.implementation.keyprovider.EncryptionKeyStoreProviderImpl; import com.azure.cosmos.encryption.implementation.mdesrc.cryptography.EncryptionType; @@ -54,10 +55,10 @@ public class EncryptionProcessor { private final static Logger LOGGER = LoggerFactory.getLogger(EncryptionProcessor.class); - private CosmosEncryptionAsyncClient encryptionCosmosClient; - private CosmosAsyncContainer cosmosAsyncContainer; - private EncryptionSettings encryptionSettings; - private AtomicBoolean isEncryptionSettingsInitDone; + private final CosmosEncryptionAsyncClient encryptionCosmosClient; + private final CosmosAsyncContainer cosmosAsyncContainer; + private final EncryptionSettings encryptionSettings; + private final AtomicBoolean isEncryptionSettingsInitDone; private ClientEncryptionPolicy clientEncryptionPolicy; private String containerRid; private String databaseRid; @@ -254,12 +255,15 @@ public Mono encrypt(byte[] payload) { payload == null ? null : payload.length, Thread.currentThread().getName()); } - ObjectNode itemJObj = Utils.parse(payload, ObjectNode.class); + ObjectNode itemJObj = Utils.parse(payload, ObjectNode.class, CosmosItemSerializer.DEFAULT_SERIALIZER); return encrypt(itemJObj); } public Mono encrypt(JsonNode itemJObj) { - return encryptObjectNode(itemJObj).map(encryptedObjectNode -> EncryptionUtils.serializeJsonToByteArray(EncryptionUtils.getSimpleObjectMapper(), encryptedObjectNode)); + return encryptObjectNode(itemJObj).map( + encryptedObjectNode -> EncryptionUtils.serializeJsonToByteArray( + CosmosItemSerializer.DEFAULT_SERIALIZER, + encryptedObjectNode)); } public Mono encryptPatchNode(JsonNode itemObj, String patchPropertyPath) { @@ -273,7 +277,8 @@ public Mono encryptPatchNode(JsonNode itemObj, String patchPropertyPat for (ClientEncryptionIncludedPath includedPath : this.clientEncryptionPolicy.getIncludedPaths()) { String propertyName = includedPath.getPath().substring(1); - if (patchPropertyPath.substring(1).equals(propertyName)) { + String relativePatchPropertyPath = patchPropertyPath.substring(1); + if (relativePatchPropertyPath.equals(propertyName) || relativePatchPropertyPath.startsWith(propertyName + "/")) { if (itemObj.isValueNode()) { return this.encryptionSettings.getEncryptionSettingForPropertyAsync(propertyName, this).flatMap(settings -> { @@ -497,7 +502,7 @@ public byte[] encryptAndSerializeValue(EncryptionSettings encryptionSettings, Ob return cipherTextWithTypeMarker; } - public Mono> decrypt(byte[] input) { + public Mono> decrypt(byte[] input, CosmosItemSerializer itemSerializer) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Encrypting byte[] of size [{}] on thread [{}]", input == null ? null : input.length, @@ -508,13 +513,13 @@ public Mono> decrypt(byte[] input) { return Mono.empty(); } - ObjectNode itemJObj = Utils.parse(input, ObjectNode.class); - return decrypt(itemJObj); + ObjectNode itemJObj = Utils.parse(input, ObjectNode.class, CosmosItemSerializer.DEFAULT_SERIALIZER); + return decrypt(itemJObj, itemSerializer); } - public Mono> decrypt(JsonNode itemJObj) { + public Mono> decrypt(JsonNode itemJObj, CosmosItemSerializer itemSerializer) { return decryptJsonNode(itemJObj).map(decryptedObjectNode -> Pair.of( - EncryptionUtils.serializeJsonToByteArray(EncryptionUtils.getSimpleObjectMapper(), decryptedObjectNode), + EncryptionUtils.serializeJsonToByteArray(itemSerializer, decryptedObjectNode), decryptedObjectNode)); } diff --git a/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/implementation/EncryptionUtils.java b/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/implementation/EncryptionUtils.java index c2cb21f3cb9e..b05ff8c44987 100644 --- a/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/implementation/EncryptionUtils.java +++ b/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/implementation/EncryptionUtils.java @@ -3,6 +3,7 @@ package com.azure.cosmos.encryption.implementation; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.Utils; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationFeature; @@ -21,8 +22,8 @@ public class EncryptionUtils { EncryptionUtils.simpleObjectMapper.configure(DeserializationFeature.ACCEPT_FLOAT_AS_INT, false); } - public static byte[] serializeJsonToByteArray(ObjectMapper objectMapper, Object object) { - return toByteArray(Utils.serializeJsonToByteBuffer(objectMapper, object)); + public static byte[] serializeJsonToByteArray(CosmosItemSerializer itemSerializer, Object object) { + return toByteArray(Utils.serializeJsonToByteBuffer(itemSerializer, object, null)); } public static ObjectMapper getSimpleObjectMapper() { diff --git a/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/models/SqlQuerySpecWithEncryption.java b/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/models/SqlQuerySpecWithEncryption.java index 938d749a1894..21007204d622 100644 --- a/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/models/SqlQuerySpecWithEncryption.java +++ b/sdk/cosmos/azure-cosmos-encryption/src/main/java/com/azure/cosmos/encryption/models/SqlQuerySpecWithEncryption.java @@ -3,6 +3,7 @@ package com.azure.cosmos.encryption.models; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.encryption.CosmosEncryptionAsyncContainer; import com.azure.cosmos.encryption.implementation.Constants; import com.azure.cosmos.encryption.implementation.EncryptionImplementationBridgeHelpers; @@ -27,8 +28,8 @@ * Represents a SQL query with encryption parameters in the Azure Cosmos DB database service. */ public final class SqlQuerySpecWithEncryption { - private SqlQuerySpec sqlQuerySpec; - private HashMap encryptionParamMap = new HashMap<>(); + private final SqlQuerySpec sqlQuerySpec; + private final HashMap encryptionParamMap = new HashMap<>(); private final EncryptionImplementationBridgeHelpers.CosmosEncryptionAsyncContainerHelper.CosmosEncryptionAsyncContainerAccessor cosmosEncryptionAsyncContainerAccessor = EncryptionImplementationBridgeHelpers.CosmosEncryptionAsyncContainerHelper.getCosmosEncryptionAsyncContainerAccessor(); /** @@ -83,9 +84,9 @@ Mono addEncryptionParameterAsync(String path, SqlParameter sqlParameter, } } byte[] valueByte = - EncryptionUtils.serializeJsonToByteArray(EncryptionUtils.getSimpleObjectMapper(), + EncryptionUtils.serializeJsonToByteArray(CosmosItemSerializer.DEFAULT_SERIALIZER, sqlParameter.getValue(Object.class)); - JsonNode itemJObj = Utils.parse(valueByte, JsonNode.class); + JsonNode itemJObj = Utils.parse(valueByte, JsonNode.class, CosmosItemSerializer.DEFAULT_SERIALIZER); Pair typeMarkerPair = EncryptionProcessor.toByteArray(itemJObj); byte[] cipherText = diff --git a/sdk/cosmos/azure-cosmos-encryption/src/main/java/module-info.java b/sdk/cosmos/azure-cosmos-encryption/src/main/java/module-info.java index 3d7120dec3f2..cadb2b2b67d4 100644 --- a/sdk/cosmos/azure-cosmos-encryption/src/main/java/module-info.java +++ b/sdk/cosmos/azure-cosmos-encryption/src/main/java/module-info.java @@ -10,4 +10,5 @@ // public API surface area exports com.azure.cosmos.encryption; exports com.azure.cosmos.encryption.models; + opens com.azure.cosmos.encryption to com.fasterxml.jackson.databind, com.fasterxml.jackson.module.afterburner; } diff --git a/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/CosmosEncryptionAsyncClientTest.java b/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/CosmosEncryptionAsyncClientTest.java index 06c9182d24e8..e4856585a9d2 100644 --- a/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/CosmosEncryptionAsyncClientTest.java +++ b/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/CosmosEncryptionAsyncClientTest.java @@ -17,7 +17,6 @@ import java.lang.reflect.Method; public abstract class CosmosEncryptionAsyncClientTest implements ITest { - private static final ImplementationBridgeHelpers.CosmosClientBuilderHelper.CosmosClientBuilderAccessor cosmosClientBuilderAccessor = ImplementationBridgeHelpers.CosmosClientBuilderHelper.getCosmosClientBuilderAccessor(); @@ -36,17 +35,13 @@ public final CosmosClientBuilder getClientBuilder() { return this.clientBuilder; } - public final ConnectionPolicy getConnectionPolicy() { - return cosmosClientBuilderAccessor.getConnectionPolicy(this.clientBuilder); - } - @Override public final String getTestName() { return this.testName; } @BeforeMethod(alwaysRun = true) - public final void setTestName(Method method) { + public final void setTestName(Method method, Object[] row) { String testClassAndMethodName = Strings.lenientFormat("%s::%s", method.getDeclaringClass().getSimpleName(), method.getName()); @@ -66,10 +61,19 @@ public final void setTestName(Method method) { } else { this.testName = testClassAndMethodName; } + + String suffix = this.resolveTestNameSuffix(row); + if (suffix != null && !suffix.isEmpty()) { + this.testName += "(" + suffix + ")"; + } } @AfterMethod(alwaysRun = true) public final void unsetTestName() { this.testName = null; } + + public String resolveTestNameSuffix(Object[] row) { + return ""; + } } diff --git a/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/CosmosEncryptionItemSerializerTest.java b/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/CosmosEncryptionItemSerializerTest.java new file mode 100644 index 000000000000..2cfc6d90dc89 --- /dev/null +++ b/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/CosmosEncryptionItemSerializerTest.java @@ -0,0 +1,819 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + * + */ +package com.azure.cosmos.encryption; + +import com.azure.core.cryptography.KeyEncryptionKeyResolver; +import com.azure.cosmos.CosmosClient; +import com.azure.cosmos.CosmosClientBuilder; +import com.azure.cosmos.CosmosException; +import com.azure.cosmos.CosmosItemSerializer; +import com.azure.cosmos.encryption.models.CosmosEncryptionAlgorithm; +import com.azure.cosmos.encryption.models.CosmosEncryptionType; +import com.azure.cosmos.implementation.ImplementationBridgeHelpers; +import com.azure.cosmos.models.ClientEncryptionIncludedPath; +import com.azure.cosmos.models.ClientEncryptionPolicy; +import com.azure.cosmos.models.CosmosBatch; +import com.azure.cosmos.models.CosmosBatchOperationResult; +import com.azure.cosmos.models.CosmosBatchRequestOptions; +import com.azure.cosmos.models.CosmosBatchResponse; +import com.azure.cosmos.models.CosmosBulkExecutionOptions; +import com.azure.cosmos.models.CosmosBulkOperationResponse; +import com.azure.cosmos.models.CosmosBulkOperations; +import com.azure.cosmos.models.CosmosChangeFeedRequestOptions; +import com.azure.cosmos.models.CosmosContainerProperties; +import com.azure.cosmos.models.CosmosItemOperation; +import com.azure.cosmos.models.CosmosItemRequestOptions; +import com.azure.cosmos.models.CosmosItemResponse; +import com.azure.cosmos.models.CosmosPatchItemRequestOptions; +import com.azure.cosmos.models.CosmosPatchOperations; +import com.azure.cosmos.models.CosmosQueryRequestOptions; +import com.azure.cosmos.models.FeedRange; +import com.azure.cosmos.models.PartitionKey; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +public class CosmosEncryptionItemSerializerTest extends TestSuiteBase { + private final static ObjectMapper objectMapper = new ObjectMapper() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true) + .configure(JsonParser.Feature.ALLOW_TRAILING_COMMA, true) + .configure(DeserializationFeature.ACCEPT_FLOAT_AS_INT, false); + + private CosmosEncryptionClient client; + private CosmosEncryptionContainer container; + private final boolean isContentOnWriteEnabled; + private final boolean nonIdempotentWriteRetriesEnabled; + private final boolean useTrackingIdForCreateAndReplace; + + private final static String containerIdWithEncryption = "enc_" + UUID.randomUUID(); + + @Factory(dataProvider = "clientBuildersWithDirectSessionIncludeComputeGatewayAndDifferentItemSerializers") + public CosmosEncryptionItemSerializerTest( + CosmosClientBuilder clientBuilder, + boolean inContentOnWriteEnabled, + boolean nonIdempotentWriteRetriesEnabled, + boolean useTrackingIdForCreateAndReplace) { + super(clientBuilder); + + this.isContentOnWriteEnabled = inContentOnWriteEnabled; + this.nonIdempotentWriteRetriesEnabled = nonIdempotentWriteRetriesEnabled; + this.useTrackingIdForCreateAndReplace = useTrackingIdForCreateAndReplace; + } + + @DataProvider + public static Object[][] clientBuildersWithDirectSessionIncludeComputeGatewayAndDifferentItemSerializers() { + boolean[] contentResponseOnWriteValues = new boolean[] { true, false }; + boolean[] nonIdempotentWriteRetriesEnabledValues = new boolean[] { true, false }; + boolean[] trackingIdUsageForWriteRetriesEnabledValues = new boolean[] { true, false }; + + CosmosItemSerializer[] itemSerializers = new CosmosItemSerializer[] { + null, + CosmosItemSerializer.DEFAULT_SERIALIZER, + EnvelopWrappingItemSerializer.INSTANCE_NO_TRACKING_ID_VALIDATION + }; + + List providers = new ArrayList<>(); + for (CosmosItemSerializer serializer : itemSerializers) { + for (boolean isContentResponseOnWriteEnabled : contentResponseOnWriteValues) { + for (boolean nonIdempotentWriteRetriesEnabled : nonIdempotentWriteRetriesEnabledValues) { + for (boolean trackingIdUsageForWriteRetriesEnabled : trackingIdUsageForWriteRetriesEnabledValues) { + if (!nonIdempotentWriteRetriesEnabled && trackingIdUsageForWriteRetriesEnabled) { + continue; + } + + Object[][] originalProviders = clientBuildersWithDirectSession( + isContentResponseOnWriteEnabled, + toArray(protocols)); + List providersCurrentTestCase = new ArrayList<>(); + + for (Object[] current : originalProviders) { + Object[] injectedProviderParameters = new Object[4]; + injectedProviderParameters[0] = current[0]; + + injectedProviderParameters[1] = isContentResponseOnWriteEnabled; + injectedProviderParameters[2] = nonIdempotentWriteRetriesEnabled; + injectedProviderParameters[3] = trackingIdUsageForWriteRetriesEnabled; + providersCurrentTestCase.add(injectedProviderParameters); + } + + for (Object[] wrappedProvider : providersCurrentTestCase) { + CosmosClientBuilder clientBuilder = (CosmosClientBuilder) wrappedProvider[0]; + clientBuilder.customSerializer(serializer); + clientBuilder.nonIdempotentWriteRetryPolicy( + nonIdempotentWriteRetriesEnabled, + trackingIdUsageForWriteRetriesEnabled); + } + + providers.addAll(providersCurrentTestCase); + } + } + } + } + + Object[][] array = new Object[providers.size()][]; + + return providers.toArray(array); + } + + @BeforeClass(groups = { "encryption" }, timeOut = SETUP_TIMEOUT) + public void before_CosmosItemTest() { + assertThat(this.client).isNull(); + CosmosClient client = getClientBuilder().buildClient(); + KeyEncryptionKeyResolver keyEncryptionKeyResolver = new TestKeyEncryptionKeyResolver(); + CosmosEncryptionClient cosmosEncryptionClient = new CosmosEncryptionClientBuilder().cosmosClient(client).keyEncryptionKeyResolver( + keyEncryptionKeyResolver).keyEncryptionKeyResolverName("TEST_KEY_RESOLVER").buildClient(); + + CosmosEncryptionDatabase cosmosEncryptionDatabase = getSharedEncryptionDatabase(cosmosEncryptionClient); + List encryptedProperties= new ArrayList<>(); + encryptedProperties.add(new ClientEncryptionIncludedPath() + .setClientEncryptionKeyId("key1") + .setPath("/someStringArray") + .setEncryptionType(CosmosEncryptionType.DETERMINISTIC.getName()) + .setEncryptionAlgorithm(CosmosEncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA256.getName()) + ); + + encryptedProperties.add(new ClientEncryptionIncludedPath() + .setClientEncryptionKeyId("key1") + .setPath("/someNumber") + .setEncryptionType(CosmosEncryptionType.DETERMINISTIC.getName()) + .setEncryptionAlgorithm(CosmosEncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA256.getName()) + ); + + encryptedProperties.add(new ClientEncryptionIncludedPath() + .setClientEncryptionKeyId("key1") + .setPath("/wrappedContent") + .setEncryptionType(CosmosEncryptionType.DETERMINISTIC.getName()) + .setEncryptionAlgorithm(CosmosEncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA256.getName()) + ); + + CosmosEncryptionContainer originalContainer = getSharedEncryptionContainer(cosmosEncryptionClient); + ClientEncryptionPolicy clientEncryptionPolicy = new ClientEncryptionPolicy(encryptedProperties, 2); + CosmosContainerProperties properties = originalContainer.getCosmosContainer().read().getProperties(); + logger.info("Original container: {}, container with encryption: {}", + originalContainer.getCosmosContainer().getId(), containerIdWithEncryption); + properties.setClientEncryptionPolicy(clientEncryptionPolicy); + properties.setId(containerIdWithEncryption); + try { + cosmosEncryptionDatabase.getCosmosDatabase().createContainerIfNotExists(properties); + logger.info("Ensured existence of Container: {}", properties.getId()); + } catch (CosmosException error) { + logger.error("Can't create container with encrypted properties.", error); + + throw error; + } + this.client = cosmosEncryptionClient; + this.container = cosmosEncryptionDatabase.getCosmosEncryptionContainer(containerIdWithEncryption); + } + + @AfterClass(groups = { "encryption" }, timeOut = 100 * SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + assertThat(this.client).isNotNull(); + this.client.close(); + } + + @DataProvider(name = "testConfigs_requestLevelSerializer") + public Object[][] testConfigs_requestLevelSerializer() { + return new Object[][] { + new Object[] { + CosmosItemSerializer.DEFAULT_SERIALIZER + }, + + new Object[] { + EnvelopWrappingItemSerializer.INSTANCE_NO_TRACKING_ID_VALIDATION + }, + + new Object[] { + null + } + }; + } + + @Override + public String resolveTestNameSuffix(Object[] row) { + String prefix = nonIdempotentWriteRetriesEnabled + ? useTrackingIdForCreateAndReplace ? "WriteRetriesWithTrackingId|" : "WriteRetriesNoTrackingId|" + : "NoWriteRetries|"; + + CosmosItemSerializer requestOptionsSerializer = (CosmosItemSerializer) row[0]; + if (requestOptionsSerializer == CosmosItemSerializer.DEFAULT_SERIALIZER) { + prefix += "RequestOptions_DEFAULT"; + } else if (requestOptionsSerializer == null) { + prefix += "RequestOptions_NULL"; + } else { + prefix += "RequestOptions_" + requestOptionsSerializer.getClass().getSimpleName(); + } + + CosmosItemSerializer customSerializer = ImplementationBridgeHelpers + .CosmosClientBuilderHelper + .getCosmosClientBuilderAccessor() + .getDefaultCustomSerializer(this.getClientBuilder()); + if (customSerializer == null) { + return prefix + "|Client_NULL"; + } else if (customSerializer == CosmosItemSerializer.DEFAULT_SERIALIZER) { + return prefix + "|Client_DEFAULT"; + } + + return prefix + "|Client_" + customSerializer.getClass().getSimpleName(); + } + + @Test(groups = { "fast", "emulator" }, dataProvider = "testConfigs_requestLevelSerializer", timeOut = TIMEOUT) + public void pointOperationsAndQueryWithPojo(CosmosItemSerializer requestLevelSerializer) { + String id = UUID.randomUUID().toString(); + TestDocument doc = TestDocument.create(id); + Consumer onBeforeReplace = item -> item.someNumber = 999; + BiFunction onBeforePatch = (item, isEnvelopeWrapped) -> { + + doc.someNumber = 555; + if (!isEnvelopeWrapped) { + return CosmosPatchOperations + .create() + .add("/someNumber", 555); + } else { + return CosmosPatchOperations + .create() + .add("/wrappedContent/someNumber", 555); + } + }; + + runPointOperationAndQueryTestCase( + doc, + id, + onBeforeReplace, + onBeforePatch, + requestLevelSerializer, + TestDocument.class); + } + + @Test(groups = { "fast", "emulator" }, dataProvider = "testConfigs_requestLevelSerializer", timeOut = TIMEOUT * 1000000) + public void pointOperationsAndQueryWithObjectNode(CosmosItemSerializer requestLevelSerializer) { + String id = UUID.randomUUID().toString(); + ObjectNode doc = TestDocument.createAsObjectNode(id); + Consumer onBeforeReplace = item -> item.put("someNumber", 999); + BiFunction onBeforePatch = (item, isEnvelopeWrapped) -> { + + item.put("someNumber", 555); + + if (!isEnvelopeWrapped) { + return CosmosPatchOperations + .create() + .add("/someNumber", 555); + } else { + return CosmosPatchOperations + .create() + .add("/wrappedContent/someNumber", 555); + } + }; + + runPointOperationAndQueryTestCase( + doc, + id, + onBeforeReplace, + onBeforePatch, + requestLevelSerializer, + ObjectNode.class); + } + + private void runPointOperationAndQueryTestCase( + T doc, + String id, + Consumer beforeReplace, + BiFunction beforePatch, + CosmosItemSerializer requestLevelSerializer, + Class classType) { + + CosmosItemSerializer customSerializer = ImplementationBridgeHelpers + .CosmosClientBuilderHelper + .getCosmosClientBuilderAccessor() + .getDefaultCustomSerializer(this.getClientBuilder()); + + boolean useEnvelopeWrapper = + requestLevelSerializer == EnvelopWrappingItemSerializer.INSTANCE_NO_TRACKING_ID_VALIDATION + || (requestLevelSerializer == null + && customSerializer == EnvelopWrappingItemSerializer.INSTANCE_NO_TRACKING_ID_VALIDATION); + + if (requestLevelSerializer == EnvelopWrappingItemSerializer.INSTANCE_NO_TRACKING_ID_VALIDATION + && isContentOnWriteEnabled + && nonIdempotentWriteRetriesEnabled + && useTrackingIdForCreateAndReplace) { + + requestLevelSerializer = EnvelopWrappingItemSerializer.INSTANCE_WITH_TRACKING_ID_VALIDATION; + } + + CosmosItemRequestOptions requestOptions = new CosmosItemRequestOptions() + .setCustomSerializer(requestLevelSerializer); + CosmosItemResponse pojoResponse = container.createItem(doc, new PartitionKey(id), requestOptions); + + if (this.isContentOnWriteEnabled) { + assertSameDocument(doc, pojoResponse.getItem()); + } else { + assertThat(pojoResponse.getItem()).isNull(); + } + + container.deleteItem(doc, requestOptions); + + pojoResponse = container.createItem(doc, requestOptions); + + if (this.isContentOnWriteEnabled) { + assertSameDocument(doc, pojoResponse.getItem()); + } else { + assertThat(pojoResponse.getItem()).isNull(); + } + + pojoResponse = container.readItem(id, new PartitionKey(id), requestOptions, classType); + assertSameDocument(doc, pojoResponse.getItem()); + + beforeReplace.accept(doc); + pojoResponse = container.replaceItem(doc, id, new PartitionKey(id), requestOptions); + if (this.isContentOnWriteEnabled) { + assertSameDocument(doc, pojoResponse.getItem()); + } else { + assertThat(pojoResponse.getItem()).isNull(); + } + + CosmosPatchOperations patchOperations = beforePatch.apply(doc, useEnvelopeWrapper); + CosmosPatchItemRequestOptions patchRequestOptions = new CosmosPatchItemRequestOptions(); + if (useEnvelopeWrapper) { + patchRequestOptions.setCustomSerializer(EnvelopWrappingItemSerializer.INSTANCE_FOR_PATCH); + } else { + patchRequestOptions.setCustomSerializer(requestLevelSerializer); + } + + pojoResponse = container.patchItem(id, new PartitionKey(id), patchOperations, patchRequestOptions, classType); + if (this.isContentOnWriteEnabled) { + assertSameDocument(doc, pojoResponse.getItem()); + } else { + assertThat(pojoResponse.getItem()).isNull(); + } + + pojoResponse = container.readItem(id, new PartitionKey(id), requestOptions, classType); + assertSameDocument(doc, pojoResponse.getItem()); + + beforeReplace.accept(doc); + if (requestLevelSerializer == EnvelopWrappingItemSerializer.INSTANCE_WITH_TRACKING_ID_VALIDATION) { + requestLevelSerializer = EnvelopWrappingItemSerializer.INSTANCE_NO_TRACKING_ID_VALIDATION; + } + CosmosItemRequestOptions upsertRequestOptions = new CosmosItemRequestOptions(); + if (useEnvelopeWrapper) { + upsertRequestOptions.setCustomSerializer(EnvelopWrappingItemSerializer.INSTANCE_NO_TRACKING_ID_VALIDATION); + } else { + upsertRequestOptions.setCustomSerializer(requestOptions.getCustomSerializer()); + } + pojoResponse = container.upsertItem(doc, new PartitionKey(id), upsertRequestOptions); + if (this.isContentOnWriteEnabled) { + assertSameDocument(doc, pojoResponse.getItem()); + } else { + assertThat(pojoResponse.getItem()).isNull(); + } + + CosmosQueryRequestOptions queryRequestOptions = new CosmosQueryRequestOptions(); + if (useEnvelopeWrapper) { + queryRequestOptions.setCustomSerializer(EnvelopWrappingItemSerializer.INSTANCE_NO_TRACKING_ID_VALIDATION); + } else { + queryRequestOptions.setCustomSerializer(requestOptions.getCustomSerializer()); + } + List results = container + .queryItems("SELECT * FROM c where c.id = '" + id + "'", queryRequestOptions, classType) + .stream().collect(Collectors.toList()); + assertThat(results).isNotNull(); + assertThat(results).hasSize(1); + assertSameDocument(doc, results.get(0)); + } + + @Test(groups = { "fast", "emulator" }, dataProvider = "testConfigs_requestLevelSerializer", timeOut = TIMEOUT * 1000000) + public void bulkAndReadManyWithObjectNode(CosmosItemSerializer requestLevelSerializer) { + + runBulkAndReadManyTestCase( + id -> TestDocument.createAsObjectNode(id), + requestLevelSerializer, + ObjectNode.class + ); + } + + @Test(groups = { "fast", "emulator" }, dataProvider = "testConfigs_requestLevelSerializer", timeOut = TIMEOUT * 1000000) + public void bulkAndReadManyWithPojo(CosmosItemSerializer requestLevelSerializer) { + + runBulkAndReadManyTestCase( + id -> TestDocument.create(id), + requestLevelSerializer, + TestDocument.class + ); + } + + private void runBulkAndReadManyTestCase( + Function docGenerator, + CosmosItemSerializer requestLevelSerializer, + Class classType) { + + CosmosBulkExecutionOptions bulkExecOptions = new CosmosBulkExecutionOptions() + .setCustomSerializer(requestLevelSerializer); + + List bulkOperations = new ArrayList<>(); + Map inputItems = new HashMap<>(); + for (int i = 0; i < 10; i++) { + String id = UUID.randomUUID().toString(); + T doc = docGenerator.apply(id); + inputItems.put(id, doc); + bulkOperations.add(CosmosBulkOperations.getCreateItemOperation( + doc, + new PartitionKey(id), + id)); + } + + Iterable> responseFlux = + container.executeBulkOperations(bulkOperations, bulkExecOptions); + for(CosmosBulkOperationResponse response: responseFlux) { + assertThat(response.getException()).isNull(); + assertThat(response.getResponse()).isNotNull(); + assertThat(response.getResponse().getStatusCode()).isBetween(200, 201); + assertThat(response.getOperation().getContext()).isNotNull(); + String id = response.getOperation().getContext(); + assertThat(inputItems.containsKey(id)).isTrue(); + T responseItem = response.getResponse().getItem(classType); + + if (isContentOnWriteEnabled) { + assertSameDocument(inputItems.get(id), responseItem); + } else { + assertThat(responseItem).isNull(); + } + } + + // TODO - re-enable the read many validation after adding readMany API for azure-cosmos-encryption + // See https://github.com/Azure/azure-sdk-for-java/issues/39842 + /* + List readManyTuples = new ArrayList<>(); + for (String id: inputItems.keySet().stream().limit(3).toArray(count -> new String[count])) { + readManyTuples.add(new CosmosItemIdentity(new PartitionKey(id), id)); + } + + CosmosReadManyRequestOptions readManyRequestOptions = new CosmosReadManyRequestOptions() + .setCustomSerializer(requestLevelSerializer); + + FeedResponse response = container.readMany(readManyTuples, readManyRequestOptions, classType); + assertThat(response).isNotNull(); + Object[] items = response.getElements().stream().toArray(); + assertThat(items).isNotNull(); + assertThat(items).hasSize(3); + for(Object responseItem: items) { + assertThat(responseItem).isNotNull(); + if (responseItem instanceof TestDocument) { + TestDocument doc = (TestDocument) responseItem; + assertThat(inputItems.containsKey(doc.id)).isTrue(); + assertSameDocument(inputItems.get(doc.id), doc); + } else if (responseItem instanceof ObjectNode) { + ObjectNode doc = (ObjectNode) responseItem; + String id = doc.get("id").asText(); + assertThat(inputItems.containsKey(id)).isTrue(); + assertSameDocument(inputItems.get(id), doc); + } else { + fail("Unexpected response item type '" + responseItem.getClass().getSimpleName() + "'."); + } + } + */ + } + + @Test(groups = { "fast", "emulator" }, dataProvider = "testConfigs_requestLevelSerializer", timeOut = TIMEOUT * 1000000) + public void batchAndChangeFeedWithObjectNode(CosmosItemSerializer requestLevelSerializer) { + + runBatchAndChangeFeedTestCase( + pk -> TestDocument.createAsObjectNode(UUID.randomUUID().toString(), pk), + requestLevelSerializer, + ObjectNode.class + ); + } + + @Test(groups = { "fast", "emulator" }, dataProvider = "testConfigs_requestLevelSerializer", timeOut = TIMEOUT * 1000000) + public void batchAndChangeFeedWithPojo(CosmosItemSerializer requestLevelSerializer) { + + runBatchAndChangeFeedTestCase( + pk -> TestDocument.create(UUID.randomUUID().toString(), pk), + requestLevelSerializer, + TestDocument.class + ); + } + + private void runBatchAndChangeFeedTestCase( + Function docGenerator, + CosmosItemSerializer requestLevelSerializer, + Class classType) { + + String pkValue = UUID.randomUUID().toString(); + CosmosBatch batch = CosmosBatch.createCosmosBatch(new PartitionKey(pkValue)); + List inputItems = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + T doc = docGenerator.apply(pkValue); + inputItems.add(doc); + batch.createItemOperation(doc); + } + + CosmosBatchRequestOptions batchRequestOptions = new CosmosBatchRequestOptions() + .setCustomSerializer(requestLevelSerializer); + + CosmosBatchResponse response = container.executeCosmosBatch(batch, batchRequestOptions); + assertThat(response).isNotNull(); + assertThat(response.getStatusCode()).isEqualTo(200); + assertThat(response.getErrorMessage()).isNull(); + assertThat(response.getResults()).isNotNull(); + assertThat(response.getResults()).hasSize(10); + for (CosmosBatchOperationResult result: response.getResults()) { + T responseItem = result.getItem(classType); + if (isContentOnWriteEnabled) { + boolean found = false; + for (T inputItem: inputItems) { + if (hasSameId(inputItem, responseItem)) { + assertSameDocument(inputItem, responseItem); + found = true; + break; + } + } + + assertThat(found).isTrue(); + + } else { + assertThat(responseItem).isNull(); + } + } + + CosmosChangeFeedRequestOptions changeFeedRequestOptions = CosmosChangeFeedRequestOptions + .createForProcessingFromBeginning( + FeedRange.forLogicalPartition(new PartitionKey(pkValue)) + ) + .setCustomSerializer(requestLevelSerializer); + + List results = container + .queryChangeFeed(changeFeedRequestOptions, classType) + .stream().collect(Collectors.toList()); + assertThat(results).isNotNull(); + assertThat(results).hasSize(10); + for (T responseItem: results) { + boolean found = false; + for (T inputItem: inputItems) { + if (hasSameId(inputItem, responseItem)) { + assertSameDocument(inputItem, responseItem); + found = true; + break; + } + } + + assertThat(found).isTrue(); + } + } + + private static class TestChildObject { + public String childId; + + public Integer someNumber; + } + + private static class TestDocument { + public String id; + + public String mypk; + + public Integer someNumber; + + public String[] someStringArray; + + public Integer[] someNumberArray; + + public TestChildObject someChildObject; + + public TestChildObject[] someChildObjectArray; + + public static TestDocument create(String id) { + return create(id, id); + } + + public static TestDocument create(String id, String pk) { + TestDocument doc = new TestDocument(); + doc.id = id; + doc.mypk = pk; + doc.someNumber = 5; + doc.someStringArray = new String[] { id, "someString2", "someString3" }; + doc.someNumberArray = new Integer[] { 1, 3, 5 }; + TestChildObject child = new TestChildObject(); + child.childId = "C1_" + id; + child.someNumber = 9; + doc.someChildObject = child; + doc.someChildObjectArray = new TestChildObject[] { child, child }; + + return doc; + } + + public static ObjectNode createAsObjectNode(String id) { + return createAsObjectNode(id, id); + } + + public static ObjectNode createAsObjectNode(String id, String pk) { + ObjectNode node = objectMapper.createObjectNode(); + node.put("id", id); + node.put("mypk", pk); + node.put("someNumber", 5); + node.put("someStringArray", objectMapper.createArrayNode().add(id).add("someString2").add("someString3")); + node.put("someNumberArray", objectMapper.createArrayNode().add(1).add(3).add(5)); + ObjectNode child = objectMapper.createObjectNode(); + child.put("childId", "C1_" + id); + child.put("someNumber", 9); + node.put("someChildObject", child); + node.put("someChildObjectArray", objectMapper.createArrayNode().add(child).add(child)); + + return node; + } + + public static TestDocument parse(ObjectNode node) { + try { + return objectMapper.treeToValue(node, TestDocument.class); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + } + + private static boolean hasSameId(Object doc, Object deserializedDoc) { + assertThat(doc).isNotNull(); + assertThat(deserializedDoc).isNotNull(); + + if (doc instanceof TestDocument) { + return hasSameId((TestDocument) doc, (TestDocument) deserializedDoc); + } + + return hasSameId((ObjectNode) doc, (ObjectNode) deserializedDoc); + } + + private static void assertSameDocument(Object doc, Object deserializedDoc) { + assertThat(doc).isNotNull(); + assertThat(deserializedDoc).isNotNull(); + + if (doc instanceof TestDocument) { + assertSameDocument((TestDocument) doc, (TestDocument) deserializedDoc); + return; + } + + assertSameDocument((ObjectNode) doc, (ObjectNode) deserializedDoc); + } + + private static boolean hasSameId(ObjectNode doc, ObjectNode deserializedDoc) { + assertThat(doc).isNotNull(); + assertThat(deserializedDoc).isNotNull(); + + return doc.get("id").textValue().equals(deserializedDoc.get("id").textValue()); + } + + private static void assertSameDocument(ObjectNode doc, ObjectNode deserializedDoc) { + assertThat(doc).isNotNull(); + assertThat(deserializedDoc).isNotNull(); + + assertSameDocument(TestDocument.parse(doc), TestDocument.parse(deserializedDoc)); + } + + private static boolean hasSameId(TestDocument doc, TestDocument deserializedDoc) { + assertThat(doc).isNotNull(); + assertThat(deserializedDoc).isNotNull(); + return doc.id.equals(deserializedDoc.id); + } + + private static void assertSameDocument(TestDocument doc, TestDocument deserializedDoc) { + + assertThat(doc).isNotNull(); + assertThat(deserializedDoc).isNotNull(); + assertThat(deserializedDoc.id).isEqualTo(doc.id); + assertThat(deserializedDoc.mypk).isEqualTo(doc.mypk); + assertThat(deserializedDoc.someNumber).isEqualTo(doc.someNumber); + if (doc.someStringArray == null) { + assertThat(deserializedDoc.someStringArray).isNull(); + } else { + assertThat(deserializedDoc.someStringArray).isNotNull(); + assertThat(deserializedDoc.someStringArray.length).isEqualTo(doc.someStringArray.length); + assertThat(deserializedDoc.someStringArray).containsAll(Arrays.stream(doc.someStringArray).collect(Collectors.toList())); + } + + if (doc.someNumberArray == null) { + assertThat(deserializedDoc.someNumberArray).isNull(); + } else { + assertThat(deserializedDoc.someNumberArray).isNotNull(); + assertThat(deserializedDoc.someNumberArray.length).isEqualTo(doc.someNumberArray.length); + assertThat(deserializedDoc.someNumberArray).containsAll(Arrays.stream(doc.someNumberArray).collect(Collectors.toList())); + } + + if (doc.someChildObject == null) { + assertThat(deserializedDoc.someChildObject).isNull(); + } else { + assertThat(deserializedDoc.someChildObject).isNotNull(); + assertThat(deserializedDoc.someChildObject.childId).isEqualTo(doc.someChildObject.childId); + assertThat(deserializedDoc.someChildObject.someNumber).isEqualTo(doc.someChildObject.someNumber); + } + + if (doc.someChildObjectArray == null) { + assertThat(deserializedDoc.someChildObjectArray).isNull(); + } else { + assertThat(deserializedDoc.someChildObjectArray).isNotNull(); + assertThat(deserializedDoc.someChildObjectArray.length).isEqualTo(doc.someChildObjectArray.length); + for (int i = 0; i < doc.someChildObjectArray.length; i++) { + assertThat(deserializedDoc.someChildObjectArray[i].childId).isEqualTo(doc.someChildObjectArray[i].childId); + assertThat(deserializedDoc.someChildObjectArray[i].someNumber).isEqualTo(doc.someChildObjectArray[i].someNumber); + } + } + } + + private static class TestDocumentWrappedInEnvelope { + public String id; + + public String mypk; + + public ObjectNode wrappedContent; + } + + private static class EnvelopWrappingItemSerializer extends CosmosItemSerializer { + public static final CosmosItemSerializer INSTANCE_NO_TRACKING_ID_VALIDATION = new EnvelopWrappingItemSerializer(false, false); + public static final CosmosItemSerializer INSTANCE_WITH_TRACKING_ID_VALIDATION = new EnvelopWrappingItemSerializer(true, false); + public static final CosmosItemSerializer INSTANCE_FOR_PATCH = new EnvelopWrappingItemSerializer(false, true); + + private final static Class mapClass = new ConcurrentHashMap().getClass(); + + private final boolean shouldValidateTrackingId; + private final boolean passThroughOnSerialize; + + public EnvelopWrappingItemSerializer(boolean enabledTrackingIdValidation, boolean passThroughOnSerialize) { + this.shouldValidateTrackingId = enabledTrackingIdValidation; + this.passThroughOnSerialize = passThroughOnSerialize; + } + + @Override + public Map serialize(T item) { + if (item == null) { + return null; + } + + if (passThroughOnSerialize) { + return CosmosItemSerializer.DEFAULT_SERIALIZER.serialize(item); + } + + Map unwrappedJsonTree = CosmosItemSerializer.DEFAULT_SERIALIZER.serialize(item); + if (unwrappedJsonTree.containsKey("wrappedContent")) { + throw new IllegalStateException("Double wrapping"); + } + + Map wrappedJsonTree = new ConcurrentHashMap<>(); + wrappedJsonTree.put("id", unwrappedJsonTree.get("id")); + wrappedJsonTree.put("mypk", unwrappedJsonTree.get("mypk")); + wrappedJsonTree.put("wrappedContent", unwrappedJsonTree); + + return wrappedJsonTree; + } + + @Override + @SuppressWarnings("unchecked") + public T deserialize(Map jsonNodeMap, Class classType) { + if (jsonNodeMap == null) { + return null; + } + + if (shouldValidateTrackingId) { + assertThat(jsonNodeMap.containsKey("_trackingId")).isEqualTo(true); + assertThat(jsonNodeMap.get("_trackingId")).isNotNull(); + } + + TestDocumentWrappedInEnvelope envelope = + CosmosItemSerializer.DEFAULT_SERIALIZER.deserialize(jsonNodeMap, TestDocumentWrappedInEnvelope.class); + + if (envelope == null || envelope.wrappedContent == null) { + return null; + } + + Map unwrappedContent = + (Map) objectMapper.convertValue(envelope.wrappedContent, mapClass); + + if (unwrappedContent.containsKey("wrappedContent")) { + throw new IllegalStateException("Double wrapped"); + } + + return CosmosItemSerializer.DEFAULT_SERIALIZER.deserialize( + unwrappedContent, + classType); + } + } +} diff --git a/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/TestSuiteBase.java b/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/TestSuiteBase.java index 81ce7236c34c..520b047b0076 100644 --- a/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/TestSuiteBase.java +++ b/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/TestSuiteBase.java @@ -14,6 +14,7 @@ import com.azure.cosmos.CosmosBridgeInternal; import com.azure.cosmos.CosmosClient; import com.azure.cosmos.CosmosClientBuilder; +import com.azure.cosmos.CosmosContainer; import com.azure.cosmos.CosmosDatabase; import com.azure.cosmos.CosmosException; import com.azure.cosmos.DirectConnectionConfig; @@ -46,7 +47,6 @@ import com.azure.cosmos.models.EncryptionKeyWrapMetadata; import com.azure.cosmos.models.IncludedPath; import com.azure.cosmos.models.IndexingPolicy; -import com.azure.cosmos.models.ModelBridgeInternal; import com.azure.cosmos.models.PartitionKey; import com.azure.cosmos.models.PartitionKeyDefinition; import com.azure.cosmos.models.SqlQuerySpec; @@ -103,7 +103,7 @@ public class TestSuiteBase extends CosmosEncryptionAsyncClientTest { protected final static ConsistencyLevel accountConsistency; protected static final ImmutableList preferredLocations; private static final ImmutableList desiredConsistencies; - private static final ImmutableList protocols; + protected static final ImmutableList protocols; protected static final AzureKeyCredential credential; @@ -136,10 +136,20 @@ protected static CosmosEncryptionAsyncContainer getSharedEncryptionContainer(Cos return encryptionAsyncDatabase.getCosmosEncryptionAsyncContainer(SHARED_ENCRYPTION_CONTAINER.getCosmosAsyncContainer().getId()); } + protected static CosmosEncryptionContainer getSharedEncryptionContainer(CosmosEncryptionClient client) { + CosmosEncryptionDatabase encryptionDatabase = + client.getCosmosEncryptionDatabase(SHARED_ENCRYPTION_DATABASE.getCosmosAsyncDatabase().getId()); + return encryptionDatabase.getCosmosEncryptionContainer(SHARED_ENCRYPTION_CONTAINER.getCosmosAsyncContainer().getId()); + } + protected static CosmosEncryptionAsyncDatabase getSharedEncryptionDatabase(CosmosEncryptionAsyncClient client) { return client.getCosmosEncryptionAsyncDatabase(SHARED_ENCRYPTION_DATABASE.getCosmosAsyncDatabase().getId()); } + protected static CosmosEncryptionDatabase getSharedEncryptionDatabase(CosmosEncryptionClient client) { + return client.getCosmosEncryptionDatabase(SHARED_ENCRYPTION_DATABASE.getCosmosAsyncDatabase().getId()); + } + protected static CosmosEncryptionContainer getSharedSyncEncryptionContainer(CosmosEncryptionClient client) { CosmosEncryptionDatabase cosmosEncryptionDatabase = client.getCosmosEncryptionDatabase(SHARED_ENCRYPTION_DATABASE.getCosmosAsyncDatabase().getId()); @@ -282,7 +292,7 @@ protected static void truncateCollection(CosmosAsyncContainer cosmosContainer) { Object propertyValue = null; if (paths != null && !paths.isEmpty()) { List pkPath = PathParser.getPathParts(paths.get(0)); - propertyValue = ModelBridgeInternal.getObjectByPathFromJsonSerializable(doc, pkPath); + propertyValue = doc.getObjectByPath(pkPath); if (propertyValue == null) { partitionKey = PartitionKey.NONE; } else { @@ -734,6 +744,31 @@ static protected void safeDeleteAllCollections(CosmosAsyncDatabase database) { } } + static protected void safeDeleteAllCollections(CosmosDatabase database) { + if (database != null) { + List collections = + database.readAllContainers().stream().collect(Collectors.toList()); + + for (CosmosContainerProperties collection : collections) { + safeDeleteCollection(database.getContainer(collection.getId())); + } + } + } + + static protected void safeDeleteAllCollectionsWithPrefix(CosmosDatabase database, String prefix) { + if (database != null) { + List collections = + database.readAllContainers().stream().collect(Collectors.toList()); + + for (CosmosContainerProperties collection : collections) { + if (!collection.getId().startsWith(prefix)) { + continue; + } + safeDeleteCollection(database.getContainer(collection.getId())); + } + } + } + static protected void safeDeleteCollection(CosmosAsyncContainer collection) { if (collection != null) { try { @@ -743,6 +778,15 @@ static protected void safeDeleteCollection(CosmosAsyncContainer collection) { } } + static protected void safeDeleteCollection(CosmosContainer collection) { + if (collection != null) { + try { + collection.delete(); + } catch (Exception e) { + } + } + } + static protected void safeDeleteCollection(CosmosAsyncDatabase database, String collectionId) { if (database != null && collectionId != null) { try { @@ -1025,7 +1069,7 @@ static Protocol[] toArray(List protocols) { return protocols.toArray(new Protocol[protocols.size()]); } - private static Object[][] clientBuildersWithDirectSession(boolean contentResponseOnWriteEnabled, Protocol... protocols) { + protected static Object[][] clientBuildersWithDirectSession(boolean contentResponseOnWriteEnabled, Protocol... protocols) { return clientBuildersWithDirect(new ArrayList() {{ add(ConsistencyLevel.SESSION); }}, contentResponseOnWriteEnabled, protocols); diff --git a/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/implementation/EncryptionProcessorAndSettingsTest.java b/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/implementation/EncryptionProcessorAndSettingsTest.java index 103fcceac3c1..26281a6245b0 100644 --- a/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/implementation/EncryptionProcessorAndSettingsTest.java +++ b/sdk/cosmos/azure-cosmos-encryption/src/test/java/com/azure/cosmos/encryption/implementation/EncryptionProcessorAndSettingsTest.java @@ -4,6 +4,7 @@ package com.azure.cosmos.encryption.implementation; import com.azure.cosmos.CosmosAsyncContainer; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.encryption.CosmosEncryptionAsyncClient; import com.azure.cosmos.encryption.EncryptionAsyncApiCrudTest; import com.azure.cosmos.encryption.implementation.keyprovider.EncryptionKeyStoreProviderImpl; @@ -267,7 +268,9 @@ public void encryptEmptyArray() throws Exception { encryptionProcessor.setClientEncryptionPolicy(new ClientEncryptionPolicy(paths)); JsonNode document = OBJECT_MAPPER.readValue(json, ObjectNode.class); - String output = new String(encryptionProcessor.decrypt(encryptionProcessor.encryptObjectNode(document).block()).block().getLeft()); + String output = new String(encryptionProcessor.decrypt( + encryptionProcessor.encryptObjectNode(document).block(), + CosmosItemSerializer.DEFAULT_SERIALIZER).block().getLeft()); assertThat(output).isEqualTo(json); } } diff --git a/sdk/cosmos/azure-cosmos-spark_3_2-12/src/main/scala/com/azure/cosmos/SparkBridgeInternal.scala b/sdk/cosmos/azure-cosmos-spark_3_2-12/src/main/scala/com/azure/cosmos/SparkBridgeInternal.scala index 850a6677c185..8773aab1132c 100644 --- a/sdk/cosmos/azure-cosmos-spark_3_2-12/src/main/scala/com/azure/cosmos/SparkBridgeInternal.scala +++ b/sdk/cosmos/azure-cosmos-spark_3_2-12/src/main/scala/com/azure/cosmos/SparkBridgeInternal.scala @@ -82,7 +82,7 @@ private[cosmos] object SparkBridgeInternal { val link = container.getLinkWithoutTrailingSlash; val obsoleteValue = new DocumentCollection - ModelBridgeInternal.setResourceId(obsoleteValue, obsoleteRid) + obsoleteValue.setResourceId(obsoleteRid) clientWrapper .getCollectionCache() diff --git a/sdk/cosmos/azure-cosmos-spark_3_2-12/src/main/scala/com/azure/cosmos/spark/ChangeFeedPartitionReader.scala b/sdk/cosmos/azure-cosmos-spark_3_2-12/src/main/scala/com/azure/cosmos/spark/ChangeFeedPartitionReader.scala index 787d5402d4ca..99409d54808e 100644 --- a/sdk/cosmos/azure-cosmos-spark_3_2-12/src/main/scala/com/azure/cosmos/spark/ChangeFeedPartitionReader.scala +++ b/sdk/cosmos/azure-cosmos-spark_3_2-12/src/main/scala/com/azure/cosmos/spark/ChangeFeedPartitionReader.scala @@ -3,15 +3,15 @@ package com.azure.cosmos.spark -import com.azure.cosmos.SparkBridgeInternal +import com.azure.cosmos.{CosmosItemSerializer, SparkBridgeInternal} import com.azure.cosmos.implementation.spark.OperationContextAndListenerTuple -import com.azure.cosmos.implementation.{ChangeFeedSparkRowItem, ImplementationBridgeHelpers, SparkBridgeImplementationInternal, Strings} +import com.azure.cosmos.implementation.{ChangeFeedSparkRowItem, ImplementationBridgeHelpers, ObjectNodeMap, SparkBridgeImplementationInternal, Strings, Utils} import com.azure.cosmos.models.{CosmosChangeFeedRequestOptions, ModelBridgeInternal, PartitionKeyDefinition} import com.azure.cosmos.spark.ChangeFeedPartitionReader.LsnPropertyName import com.azure.cosmos.spark.CosmosPredicates.requireNotNull import com.azure.cosmos.spark.CosmosTableSchemaInferrer.LsnAttributeName import com.azure.cosmos.spark.diagnostics.{DetailedFeedDiagnosticsProvider, DiagnosticsContext, DiagnosticsLoader, LoggerHelper, SparkTaskContext} -import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.node.ObjectNode import org.apache.spark.TaskContext import org.apache.spark.broadcast.Broadcast import org.apache.spark.sql.Row @@ -20,6 +20,8 @@ import org.apache.spark.sql.catalyst.encoders.ExpressionEncoder import org.apache.spark.sql.connector.read.PartitionReader import org.apache.spark.sql.types.StructType +import java.util + private object ChangeFeedPartitionReader { val LsnPropertyName: String = LsnAttributeName } @@ -85,59 +87,96 @@ private case class ChangeFeedPartitionReader private val cosmosRowConverter = CosmosRowConverter.get(cosmosSerializationConfig) private val cosmosChangeFeedConfig = CosmosChangeFeedConfig.parseCosmosChangeFeedConfig(config) - private val changeFeedRequestOptions = { + private def changeFeedItemFactoryMethod(objectNode: ObjectNode): ChangeFeedSparkRowItem = { + val pkValue = partitionKeyDefinition match { + case Some(pkDef) => Some(PartitionKeyHelper.getPartitionKeyPath(objectNode, pkDef)) + case None => None + } - val startLsn = - SparkBridgeImplementationInternal.extractLsnFromChangeFeedContinuation(this.partition.continuationState.get) - log.logDebug( - s"Request options for Range '${partition.feedRange.min}-${partition.feedRange.max}' LSN '$startLsn'") + val row = cosmosRowConverter.fromObjectNodeToRow(readSchema, + objectNode, + readConfig.schemaConversionMode) - val options = CosmosChangeFeedRequestOptions - .createForProcessingFromContinuation(this.partition.continuationState.get) - .setMaxItemCount(readConfig.maxItemCount) - ThroughputControlHelper.populateThroughputControlGroupName(options, readConfig.throughputControlConfig) + ChangeFeedSparkRowItem(row, pkValue, objectNode.get(LsnPropertyName).asText()) + } - var factoryMethod: java.util.function.Function[JsonNode, _] = (_: JsonNode) => {} - cosmosChangeFeedConfig.changeFeedMode match { - case ChangeFeedModes.Incremental | ChangeFeedModes.LatestVersion => - factoryMethod = (jsonNode: JsonNode) => changeFeedItemFactoryMethod(jsonNode) - case ChangeFeedModes.FullFidelity | ChangeFeedModes.AllVersionsAndDeletes => - factoryMethod = (jsonNode: JsonNode) => changeFeedItemFactoryMethodV1(jsonNode) + private def changeFeedItemFactoryMethodV1(objectNode: ObjectNode): ChangeFeedSparkRowItem = { + val pkValue = partitionKeyDefinition match { + case Some(pkDef) => Some(PartitionKeyHelper.getPartitionKeyPath(objectNode, pkDef)) + case None => None } + val row = cosmosRowConverter.fromObjectNodeToChangeFeedRowV1(readSchema, + objectNode, + readConfig.schemaConversionMode) + ChangeFeedSparkRowItem(row, pkValue, cosmosRowConverter.getChangeFeedLsn(objectNode)) + } - ImplementationBridgeHelpers - .CosmosChangeFeedRequestOptionsHelper - .getCosmosChangeFeedRequestOptionsAccessor - .setItemFactoryMethod( - options, - factoryMethod) - } + private val changeFeedItemDeserializer: CosmosItemSerializer = new CosmosItemSerializer { + override def serialize[T](item: T): util.Map[String, AnyRef] = ??? - private def changeFeedItemFactoryMethod(jsonNode: JsonNode): ChangeFeedSparkRowItem = { - val objectNode = cosmosRowConverter.ensureObjectNode(jsonNode) + override def deserialize[T](jsonNodeMap: util.Map[String, AnyRef], classType: Class[T]): T = { + if (jsonNodeMap == null) { + throw new IllegalStateException("The 'jsonNodeMap' should never be null here.") + } - val pkValue = partitionKeyDefinition match { - case Some(pkDef) => Some(PartitionKeyHelper.getPartitionKeyPath(objectNode, pkDef)) - case None => None + if (classType != classOf[ChangeFeedSparkRowItem]) { + throw new IllegalStateException("The 'classType' must be 'classOf[ChangeFeedSparkRowItem])' here.") } - val row = cosmosRowConverter.fromObjectNodeToRow(readSchema, - objectNode, - readConfig.schemaConversionMode) + val objectNode: ObjectNode = jsonNodeMap match { + case map: ObjectNodeMap => + map.getObjectNode + case _ => + Utils.getSimpleObjectMapper.convertValue(jsonNodeMap, classOf[ObjectNode]) + } - ChangeFeedSparkRowItem(row, pkValue, objectNode.get(LsnPropertyName).asText()) + changeFeedItemFactoryMethod(objectNode).asInstanceOf[T] } + } + + private val changeFeedItemDeserializerV1: CosmosItemSerializer = new CosmosItemSerializer { + override def serialize[T](item: T): util.Map[String, AnyRef] = ??? + + override def deserialize[T](jsonNodeMap: util.Map[String, AnyRef], classType: Class[T]): T = { + if (jsonNodeMap == null) { + throw new IllegalStateException("The 'jsonNodeMap' should never be null here.") + } - private def changeFeedItemFactoryMethodV1(jsonNode: JsonNode): ChangeFeedSparkRowItem = { - val objectNode = cosmosRowConverter.ensureObjectNode(jsonNode) - val pkValue = partitionKeyDefinition match { - case Some(pkDef) => Some(PartitionKeyHelper.getPartitionKeyPath(objectNode, pkDef)) - case None => None + if (classType != classOf[ChangeFeedSparkRowItem]) { + throw new IllegalStateException("The 'classType' must be 'classOf[ChangeFeedSparkRowItem])' here.") } - val row = cosmosRowConverter.fromObjectNodeToChangeFeedRowV1(readSchema, - objectNode, - readConfig.schemaConversionMode) - ChangeFeedSparkRowItem(row, pkValue, cosmosRowConverter.getChangeFeedLsn(objectNode)) + + val objectNode: ObjectNode = jsonNodeMap match { + case map: ObjectNodeMap => + map.getObjectNode + case _ => + Utils.getSimpleObjectMapper.convertValue(jsonNodeMap, classOf[ObjectNode]) + } + + changeFeedItemFactoryMethodV1(objectNode).asInstanceOf[T] + } + } + + private val changeFeedRequestOptions = { + + val startLsn = + SparkBridgeImplementationInternal.extractLsnFromChangeFeedContinuation(this.partition.continuationState.get) + log.logDebug( + s"Request options for Range '${partition.feedRange.min}-${partition.feedRange.max}' LSN '$startLsn'") + + val options = CosmosChangeFeedRequestOptions + .createForProcessingFromContinuation(this.partition.continuationState.get) + .setMaxItemCount(readConfig.maxItemCount) + ThroughputControlHelper.populateThroughputControlGroupName(options, readConfig.throughputControlConfig) + + val itemDeserializer: CosmosItemSerializer = cosmosChangeFeedConfig.changeFeedMode match { + case ChangeFeedModes.Incremental | ChangeFeedModes.LatestVersion => + changeFeedItemDeserializer + case ChangeFeedModes.FullFidelity | ChangeFeedModes.AllVersionsAndDeletes => + changeFeedItemDeserializerV1 + } + + options.setCustomSerializer(itemDeserializer) } private val rowSerializer: ExpressionEncoder.Serializer[Row] = RowSerializerPool.getOrCreateSerializer(readSchema) diff --git a/sdk/cosmos/azure-cosmos-spark_3_2-12/src/main/scala/com/azure/cosmos/spark/ItemsPartitionReader.scala b/sdk/cosmos/azure-cosmos-spark_3_2-12/src/main/scala/com/azure/cosmos/spark/ItemsPartitionReader.scala index 378212d672b9..eb9350235983 100644 --- a/sdk/cosmos/azure-cosmos-spark_3_2-12/src/main/scala/com/azure/cosmos/spark/ItemsPartitionReader.scala +++ b/sdk/cosmos/azure-cosmos-spark_3_2-12/src/main/scala/com/azure/cosmos/spark/ItemsPartitionReader.scala @@ -3,9 +3,9 @@ package com.azure.cosmos.spark -import com.azure.cosmos.SparkBridgeInternal -import com.azure.cosmos.implementation.spark.{OperationContextAndListenerTuple, OperationListener} -import com.azure.cosmos.implementation.{ImplementationBridgeHelpers, SparkBridgeImplementationInternal, SparkRowItem, Strings} +import com.azure.cosmos.{CosmosItemSerializer, SparkBridgeInternal} +import com.azure.cosmos.implementation.spark.OperationContextAndListenerTuple +import com.azure.cosmos.implementation.{ImplementationBridgeHelpers, ObjectNodeMap, SparkBridgeImplementationInternal, SparkRowItem, Strings, Utils} import com.azure.cosmos.models.{CosmosParameterizedQuery, CosmosQueryRequestOptions, ModelBridgeInternal, PartitionKey, PartitionKeyDefinition} import com.azure.cosmos.spark.BulkWriter.getThreadInfo import com.azure.cosmos.spark.CosmosTableSchemaInferrer.IdAttributeName @@ -19,6 +19,8 @@ import org.apache.spark.sql.catalyst.encoders.ExpressionEncoder import org.apache.spark.sql.connector.read.PartitionReader import org.apache.spark.sql.types.StructType +import java.util + // per spark task there will be one CosmosPartitionReader. // This provides iterator to read from the assigned spark partition // For now we are creating only one spark partition @@ -80,13 +82,13 @@ private case class ItemsPartitionReader } } - log.logTrace(s"Instantiated ${this.getClass.getSimpleName}, Context: ${operationContext.toString} ${getThreadInfo}") + log.logTrace(s"Instantiated ${this.getClass.getSimpleName}, Context: ${operationContext.toString} $getThreadInfo") private val containerTargetConfig = CosmosContainerConfig.parseCosmosContainerConfig(config) log.logInfo(s"Reading from feed range $feedRange of " + s"container ${containerTargetConfig.database}.${containerTargetConfig.container} - " + s"correlationActivityId ${diagnosticsContext.correlationActivityId}, " + - s"query: ${cosmosQuery.toString}, Context: ${operationContext.toString} ${getThreadInfo}") + s"query: ${cosmosQuery.toString}, Context: ${operationContext.toString} $getThreadInfo") private val clientCacheItem = CosmosClientCache( CosmosClientConfiguration(config, readConfig.forceEventualConsistency, sparkEnvironmentInfo), @@ -140,84 +142,73 @@ private case class ItemsPartitionReader diagnosticsConfig.mode.get.equalsIgnoreCase(classOf[DetailedFeedDiagnosticsProvider].getName) } - private def initializeOperationContext(): SparkTaskContext = { - val taskContext = TaskContext.get - - if (taskContext != null) { - val taskDiagnosticsContext = SparkTaskContext(diagnosticsContext.correlationActivityId, - taskContext.stageId(), - taskContext.partitionId(), - taskContext.taskAttemptId(), - feedRange.toString + " " + cosmosQuery.toString) + queryOptions.setFeedRange(SparkBridgeImplementationInternal.toFeedRange(feedRange)) - val listener: OperationListener = - DiagnosticsLoader.getDiagnosticsProvider(diagnosticsConfig).getLogger(this.getClass) + queryOptions + .setCustomSerializer( + new CosmosItemSerializer { + override def serialize[T](item: T): util.Map[String, AnyRef] = ??? - val operationContextAndListenerTuple = new OperationContextAndListenerTuple(taskDiagnosticsContext, listener) - ImplementationBridgeHelpers - .CosmosQueryRequestOptionsHelper - .getCosmosQueryRequestOptionsAccessor - .getImpl(queryOptions) - .setOperationContextAndListenerTuple(operationContextAndListenerTuple) - - taskDiagnosticsContext - } else{ - SparkTaskContext(diagnosticsContext.correlationActivityId, - -1, - -1, - -1, - "") - } - } + override def deserialize[T](jsonNodeMap: util.Map[String, AnyRef], classType: Class[T]): T = { + if (jsonNodeMap == null) { + throw new IllegalStateException("The 'jsonNodeMap' should never be null here.") + } - queryOptions.setFeedRange(SparkBridgeImplementationInternal.toFeedRange(feedRange)) + if (classType != classOf[SparkRowItem]) { + throw new IllegalStateException("The 'classType' must be 'classOf[SparkRowItem])' here.") + } - ImplementationBridgeHelpers - .CosmosQueryRequestOptionsHelper - .getCosmosQueryRequestOptionsAccessor - .getImpl(queryOptions) - .setItemFactoryMethod( - jsonNode => { - val objectNode = cosmosRowConverter.ensureObjectNode(jsonNode) + val objectNode: ObjectNode = jsonNodeMap match { + case map: ObjectNodeMap => + map.getObjectNode + case _ => + Utils.getSimpleObjectMapper.convertValue(jsonNodeMap, classOf[ObjectNode]) + } - if (effectiveReadManyFilteringConfigOpt.isEmpty || + if (effectiveReadManyFilteringConfigOpt.isEmpty || effectiveReadManyFilteringConfigOpt.get.readManyFilterProperty.equalsIgnoreCase(CosmosConstants.Properties.Id)) { - // no extra column to populate - val row = cosmosRowConverter.fromObjectNodeToRow(readSchema, - objectNode, - readConfig.schemaConversionMode) - - val pkValueOpt = { - if (shouldLogDetailedFeedDiagnostics()) { - Some(PartitionKeyHelper.getPartitionKeyPath(objectNode, partitionKeyDefinitionOpt.get)) - } else { - None + // no extra column to populate + val row = cosmosRowConverter.fromObjectNodeToRow(readSchema, + objectNode, + readConfig.schemaConversionMode) + + val pkValueOpt = { + if (shouldLogDetailedFeedDiagnostics()) { + Some(PartitionKeyHelper.getPartitionKeyPath(objectNode, partitionKeyDefinitionOpt.get)) + } else { + None + } } - } - SparkRowItem(row, pkValueOpt) - } else { - // id is not the partitionKey - // even though we can not use the readManyReader, but we still need to populate the readMany filtering property - val idValue = objectNode.get(IdAttributeName).asText() - val pkValue = PartitionKeyHelper.getPartitionKeyPath(objectNode, partitionKeyDefinitionOpt.get) - val computedColumnsMap = Map( - readConfig.readManyFilteringConfig.readManyFilterProperty -> - ((_: ObjectNode) => { - CosmosItemIdentityHelper.getCosmosItemIdentityValueString( - idValue, - ModelBridgeInternal.getPartitionKeyInternal(pkValue).toObjectArray.toList) - }) - ) - - val row = cosmosRowConverter.fromObjectNodeToRowWithComputedColumns(readSchema, - objectNode, - readConfig.schemaConversionMode, - computedColumnsMap) - - SparkRowItem(row, if (shouldLogDetailedFeedDiagnostics()) { Some(pkValue) } else { Option.empty[PartitionKey] }) + SparkRowItem(row, pkValueOpt).asInstanceOf[T] + } else { + // id is not the partitionKey + // even though we can not use the readManyReader, but we still need to populate the readMany filtering property + val idValue = objectNode.get(IdAttributeName).asText() + val pkValue = PartitionKeyHelper.getPartitionKeyPath(objectNode, partitionKeyDefinitionOpt.get) + val computedColumnsMap = Map( + readConfig.readManyFilteringConfig.readManyFilterProperty -> + ((_: ObjectNode) => { + CosmosItemIdentityHelper.getCosmosItemIdentityValueString( + idValue, + ModelBridgeInternal.getPartitionKeyInternal(pkValue).toObjectArray.toList) + }) + ) + + val row = cosmosRowConverter.fromObjectNodeToRowWithComputedColumns(readSchema, + objectNode, + readConfig.schemaConversionMode, + computedColumnsMap) + + SparkRowItem(row, if (shouldLogDetailedFeedDiagnostics()) { + Some(pkValue) + } else { + Option.empty[PartitionKey] + }).asInstanceOf[T] + } } - }) + } + ) private lazy val iterator = new TransientIOErrorsRetryingIterator( continuationToken => { diff --git a/sdk/cosmos/azure-cosmos-spark_3_2-12/src/main/scala/com/azure/cosmos/spark/ItemsPartitionReaderWithReadMany.scala b/sdk/cosmos/azure-cosmos-spark_3_2-12/src/main/scala/com/azure/cosmos/spark/ItemsPartitionReaderWithReadMany.scala index 8b107c0c0909..2847d7f1eeaa 100644 --- a/sdk/cosmos/azure-cosmos-spark_3_2-12/src/main/scala/com/azure/cosmos/spark/ItemsPartitionReaderWithReadMany.scala +++ b/sdk/cosmos/azure-cosmos-spark_3_2-12/src/main/scala/com/azure/cosmos/spark/ItemsPartitionReaderWithReadMany.scala @@ -3,9 +3,9 @@ package com.azure.cosmos.spark -import com.azure.cosmos.SparkBridgeInternal +import com.azure.cosmos.{CosmosItemSerializer, SparkBridgeInternal} import com.azure.cosmos.implementation.spark.OperationContextAndListenerTuple -import com.azure.cosmos.implementation.{ImplementationBridgeHelpers, SparkRowItem} +import com.azure.cosmos.implementation.{ImplementationBridgeHelpers, ObjectNodeMap, SparkRowItem, Utils} import com.azure.cosmos.models.{CosmosItemIdentity, CosmosReadManyRequestOptions, ModelBridgeInternal, PartitionKey, PartitionKeyDefinition} import com.azure.cosmos.spark.BulkWriter.getThreadInfo import com.azure.cosmos.spark.CosmosTableSchemaInferrer.IdAttributeName @@ -19,6 +19,8 @@ import org.apache.spark.sql.catalyst.encoders.ExpressionEncoder import org.apache.spark.sql.connector.read.PartitionReader import org.apache.spark.sql.types.StructType +import java.util + private[spark] case class ItemsPartitionReaderWithReadMany ( config: Map[String, String], @@ -70,7 +72,7 @@ private[spark] case class ItemsPartitionReaderWithReadMany } } - log.logTrace(s"Instantiated ${this.getClass.getSimpleName}, Context: ${operationContext.toString} ${getThreadInfo}") + log.logTrace(s"Instantiated ${this.getClass.getSimpleName}, Context: ${operationContext.toString} $getThreadInfo") private val containerTargetConfig = CosmosContainerConfig.parseCosmosContainerConfig(config) @@ -78,11 +80,11 @@ private[spark] case class ItemsPartitionReaderWithReadMany s"container ${containerTargetConfig.database}.${containerTargetConfig.container} - " + s"correlationActivityId ${diagnosticsContext.correlationActivityId}, " + s"readManyFilter: [feedRange: $feedRange], " + - s"Context: ${operationContext.toString} ${getThreadInfo}") + s"Context: ${operationContext.toString} $getThreadInfo") log.logTrace(s"container ${containerTargetConfig.database}.${containerTargetConfig.container} - " + s"readManyFilterDetails: [feedRange: $feedRange." + - s"Context: ${operationContext.toString} ${getThreadInfo}" + s"Context: ${operationContext.toString} $getThreadInfo" ) private val clientCacheItem = CosmosClientCache( @@ -121,41 +123,75 @@ private[spark] case class ItemsPartitionReaderWithReadMany partitionKeyDefinition) readManyOptionsImpl - .setItemFactoryMethod( - jsonNode => { - val objectNode = cosmosRowConverter.ensureObjectNode(jsonNode) - val idValue = objectNode.get(IdAttributeName).asText() - val partitionKey = PartitionKeyHelper.getPartitionKeyPath(objectNode, partitionKeyDefinition) - - this.effectiveReadManyFilteringConfig.readManyFilterProperty match { - case CosmosConstants.Properties.Id => { - // id is also the partition key, there is no need to dynamically populate it - val row = cosmosRowConverter.fromObjectNodeToRow(readSchema, - objectNode, - readConfig.schemaConversionMode) - - SparkRowItem(row, getPartitionKeyForFeedDiagnostics(partitionKey)) + .setCustomSerializer( + new CosmosItemSerializer { + /** + * Used to serialize a POJO into a json tree + * + * @param item the POJO to be serialized + * @return the json tree that will be used as payload in Cosmos DB items + * @param < T> The type of the POJO + */ + override def serialize[T](item: T): util.Map[String, AnyRef] = ??? + + /** + * Used to deserialize the json tree stored in the Cosmos DB item as a POJO + * + * @param jsonNodeMap the json tree from the Cosmos DB item + * @param classType The type of the POJO + * @return The deserialized POJO + * @param < T> The type of the POJO + */ + override def deserialize[T](jsonNodeMap: util.Map[String, AnyRef], classType: Class[T]): T = { + if (jsonNodeMap == null) { + throw new IllegalStateException("The 'jsonNodeMap' should never be null here.") + } + + if (classType != classOf[SparkRowItem]) { + throw new IllegalStateException("The 'classType' must be 'classOf[SparkRowItem])' here.") } - case _ => { - // id is not the partitionKey, dynamically computed the readMany filtering property - val computedColumnsMap = Map( - readConfig.readManyFilteringConfig.readManyFilterProperty -> - ((_: ObjectNode) => { - CosmosItemIdentityHelper.getCosmosItemIdentityValueString( - idValue, - ModelBridgeInternal.getPartitionKeyInternal(partitionKey).toObjectArray.toList) - }) - ) - - val row = cosmosRowConverter.fromObjectNodeToRowWithComputedColumns(readSchema, - objectNode, - readConfig.schemaConversionMode, - computedColumnsMap) - - SparkRowItem(row, getPartitionKeyForFeedDiagnostics(partitionKey)) + + val objectNode: ObjectNode = jsonNodeMap match { + case map: ObjectNodeMap => + map.getObjectNode + case _ => + Utils.getSimpleObjectMapper.convertValue(jsonNodeMap, classOf[ObjectNode]) + } + + val idValue = objectNode.get(IdAttributeName).asText() + val partitionKey = PartitionKeyHelper.getPartitionKeyPath(objectNode, partitionKeyDefinition) + + effectiveReadManyFilteringConfig.readManyFilterProperty match { + case CosmosConstants.Properties.Id => { + // id is also the partition key, there is no need to dynamically populate it + val row = cosmosRowConverter.fromObjectNodeToRow(readSchema, + objectNode, + readConfig.schemaConversionMode) + + SparkRowItem(row, getPartitionKeyForFeedDiagnostics(partitionKey)).asInstanceOf[T] + } + case _ => { + // id is not the partitionKey, dynamically computed the readMany filtering property + val computedColumnsMap = Map( + readConfig.readManyFilteringConfig.readManyFilterProperty -> + ((_: ObjectNode) => { + CosmosItemIdentityHelper.getCosmosItemIdentityValueString( + idValue, + ModelBridgeInternal.getPartitionKeyInternal(partitionKey).toObjectArray.toList) + }) + ) + + val row = cosmosRowConverter.fromObjectNodeToRowWithComputedColumns(readSchema, + objectNode, + readConfig.schemaConversionMode, + computedColumnsMap) + + SparkRowItem(row, getPartitionKeyForFeedDiagnostics(partitionKey)).asInstanceOf[T] + } } } - }) + } + ) private lazy val iterator = new TransientIOErrorsRetryingReadManyIterator[SparkRowItem]( cosmosAsyncContainer, diff --git a/sdk/cosmos/azure-cosmos-spark_3_2-12/src/test/scala/com/azure/cosmos/spark/TransientIOErrorsRetryingIteratorITest.scala b/sdk/cosmos/azure-cosmos-spark_3_2-12/src/test/scala/com/azure/cosmos/spark/TransientIOErrorsRetryingIteratorITest.scala index 3e39119cf92c..f0077ca30377 100644 --- a/sdk/cosmos/azure-cosmos-spark_3_2-12/src/test/scala/com/azure/cosmos/spark/TransientIOErrorsRetryingIteratorITest.scala +++ b/sdk/cosmos/azure-cosmos-spark_3_2-12/src/test/scala/com/azure/cosmos/spark/TransientIOErrorsRetryingIteratorITest.scala @@ -2,7 +2,8 @@ // Licensed under the MIT License. package com.azure.cosmos.spark -import com.azure.cosmos.implementation.{HttpConstants, ImplementationBridgeHelpers, ServiceUnavailableException, SparkRowItem, Strings, Utils} +import com.azure.cosmos.CosmosItemSerializer +import com.azure.cosmos.implementation.{HttpConstants, ObjectNodeMap, ServiceUnavailableException, SparkRowItem, Strings, Utils} import com.azure.cosmos.models.{CosmosQueryRequestOptions, ModelBridgeInternal} import com.azure.cosmos.spark.TransientIOErrorsRetryingIteratorITest.maxRetryCountPerIOOperation import com.azure.cosmos.spark.diagnostics.BasicLoggingTrait @@ -10,6 +11,7 @@ import com.azure.cosmos.util.CosmosPagedIterable import com.fasterxml.jackson.databind.node.ObjectNode import reactor.util.concurrent.Queues +import java.util import java.util.UUID import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.atomic.{AtomicLong, AtomicReference} @@ -54,19 +56,36 @@ class TransientIOErrorsRetryingIteratorITest val cosmosRowConverter = CosmosRowConverter.get(cosmosSerializationConfig) val queryOptions = new CosmosQueryRequestOptions() - ImplementationBridgeHelpers - .CosmosQueryRequestOptionsHelper - .getCosmosQueryRequestOptionsAccessor - .getImpl(queryOptions) - .setItemFactoryMethod( - jsonNode => { - val row = cosmosRowConverter.fromObjectNodeToRow( - ItemsTable.defaultSchemaForInferenceDisabled, - jsonNode.asInstanceOf[ObjectNode], - SchemaConversionModes.Strict) - - SparkRowItem(row, None) - }) + .setCustomSerializer( + new CosmosItemSerializer { + override def serialize[T](item: T): util.Map[String, AnyRef] = ??? + + override def deserialize[T](jsonNodeMap: util.Map[String, AnyRef], classType: Class[T]): T = { + if (jsonNodeMap == null) { + throw new IllegalStateException("The 'jsonNodeMap' should never be null here.") + } + + if (classType != classOf[SparkRowItem]) { + throw new IllegalStateException("The 'classType' must be 'classOf[SparkRowItem])' here.") + } + + val objectNode: ObjectNode = jsonNodeMap match { + case map: ObjectNodeMap => + map.getObjectNode + case _ => + Utils.getSimpleObjectMapper.convertValue(jsonNodeMap, classOf[ObjectNode]) + } + + val row = cosmosRowConverter.fromObjectNodeToRow( + ItemsTable.defaultSchemaForInferenceDisabled, + objectNode, + SchemaConversionModes.Strict) + + SparkRowItem(row, None).asInstanceOf[T] + } + } + ) + val retryingIterator = new TransientIOErrorsRetryingIterator( continuationToken => { if (!Strings.isNullOrWhiteSpace(continuationToken)) { @@ -180,19 +199,36 @@ class TransientIOErrorsRetryingIteratorITest ) val cosmosRowConverter = CosmosRowConverter.get(cosmosSerializationConfig) val queryOptions = new CosmosQueryRequestOptions() - ImplementationBridgeHelpers - .CosmosQueryRequestOptionsHelper - .getCosmosQueryRequestOptionsAccessor - .getImpl(queryOptions) - .setItemFactoryMethod( - jsonNode => { - val row = cosmosRowConverter.fromObjectNodeToRow( - ItemsTable.defaultSchemaForInferenceDisabled, - jsonNode.asInstanceOf[ObjectNode], - SchemaConversionModes.Strict) - - SparkRowItem(row, None) - }) + .setCustomSerializer( + new CosmosItemSerializer { + override def serialize[T](item: T): util.Map[String, AnyRef] = ??? + + override def deserialize[T](jsonNodeMap: util.Map[String, AnyRef], classType: Class[T]): T = { + if (jsonNodeMap == null) { + throw new IllegalStateException("The 'jsonNodeMap' should never be null here.") + } + + if (classType != classOf[SparkRowItem]) { + throw new IllegalStateException("The 'classType' must be 'classOf[SparkRowItem])' here.") + } + + val objectNode: ObjectNode = jsonNodeMap match { + case map: ObjectNodeMap => + map.getObjectNode + case _ => + Utils.getSimpleObjectMapper.convertValue(jsonNodeMap, classOf[ObjectNode]) + } + + val row = cosmosRowConverter.fromObjectNodeToRow( + ItemsTable.defaultSchemaForInferenceDisabled, + objectNode, + SchemaConversionModes.Strict) + + SparkRowItem(row, None).asInstanceOf[T] + } + } + ) + val retryingIterator = new TransientIOErrorsRetryingIterator( continuationToken => { if (!Strings.isNullOrWhiteSpace(continuationToken)) { diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/AzureKeyCredentialTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/AzureKeyCredentialTest.java index 3f8bbe144f72..1d3f1798240e 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/AzureKeyCredentialTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/AzureKeyCredentialTest.java @@ -59,7 +59,7 @@ public Object[][] crudArgProvider() { { UUID.randomUUID().toString()} , // with special characters in the name. - {"+ -_,:.|~" + UUID.randomUUID().toString() + " +-_,:.|~"} , + {"+ -_,:.|~" + UUID.randomUUID() + " +-_,:.|~"} , }; } @@ -205,9 +205,9 @@ public void readDocumentWithSecondaryKey(String documentId) throws InterruptedEx waitIfNeededForReplicasToCatchUp(getClientBuilder()); CosmosItemRequestOptions options = new CosmosItemRequestOptions(); - ModelBridgeInternal.setPartitionKey(options, new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(docDefinition, "mypk"))); + ModelBridgeInternal.setPartitionKey(options, new PartitionKey(docDefinition.get("mypk"))); Mono> readObservable = container.readItem(docDefinition.getId(), - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(docDefinition, "mypk")), + new PartitionKey(docDefinition.get("mypk")), options, InternalObjectNode.class); @@ -234,9 +234,9 @@ public void deleteDocumentWithSecondaryKey(String documentId) throws Interrupted container.createItem(docDefinition, new CosmosItemRequestOptions()).block(); CosmosItemRequestOptions options = new CosmosItemRequestOptions(); - ModelBridgeInternal.setPartitionKey(options, new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(docDefinition, "mypk"))); + ModelBridgeInternal.setPartitionKey(options, new PartitionKey(docDefinition.get("mypk"))); Mono> deleteObservable = container.deleteItem(docDefinition.getId(), - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(docDefinition, "mypk")), options); + new PartitionKey(docDefinition.get("mypk")), options); CosmosItemResponseValidator validator = new CosmosItemResponseValidator.Builder>() @@ -248,7 +248,7 @@ public void deleteDocumentWithSecondaryKey(String documentId) throws Interrupted waitIfNeededForReplicasToCatchUp(getClientBuilder()); Mono> readObservable = container.readItem(documentId, - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(docDefinition, "mypk")), + new PartitionKey(docDefinition.get("mypk")), options, InternalObjectNode.class); FailureValidator notFoundValidator = new FailureValidator.Builder().resourceNotFound().build(); validateItemFailure(readObservable, notFoundValidator); diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/ClientMetricsTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/ClientMetricsTest.java index ba40651a3fae..712d15a977f5 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/ClientMetricsTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/ClientMetricsTest.java @@ -380,7 +380,7 @@ public void readItem() throws Exception { container.createItem(properties); CosmosItemResponse readResponse1 = container.readItem(properties.getId(), - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(properties, "mypk")), + new PartitionKey(properties.get("mypk")), new CosmosItemRequestOptions(), InternalObjectNode.class); validateItemResponse(properties, readResponse1); @@ -423,7 +423,7 @@ private void runReadItemTestWithThresholds( container.createItem(properties); CosmosItemResponse readResponse1 = container.readItem(properties.getId(), - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(properties, "mypk")), + new PartitionKey(properties.get("mypk")), new CosmosItemRequestOptions(), InternalObjectNode.class); validateItemResponse(properties, readResponse1); @@ -468,15 +468,15 @@ public void replaceItem() throws Exception { validateItemResponse(properties, itemResponse); String newPropValue = UUID.randomUUID().toString(); - BridgeInternal.setProperty(properties, "newProp", newPropValue); + properties.set("newProp", newPropValue, CosmosItemSerializer.DEFAULT_SERIALIZER); CosmosItemRequestOptions options = new CosmosItemRequestOptions(); - ModelBridgeInternal.setPartitionKey(options, new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(properties, "mypk"))); + ModelBridgeInternal.setPartitionKey(options, new PartitionKey(properties.get("mypk"))); // replace document CosmosItemResponse replace = container.replaceItem(properties, properties.getId(), - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(properties, "mypk")), + new PartitionKey(properties.get("mypk")), options); - assertThat(ModelBridgeInternal.getObjectFromJsonSerializable(BridgeInternal.getProperties(replace), "newProp")).isEqualTo(newPropValue); + assertThat(BridgeInternal.getProperties(replace).get("newProp")).isEqualTo(newPropValue); this.validateMetrics( Tag.of(TagName.OperationStatusCode.toString(), "200"), @@ -506,7 +506,7 @@ public void deleteItem() throws Exception { CosmosItemRequestOptions options = new CosmosItemRequestOptions(); CosmosItemResponse deleteResponse = container.deleteItem(properties.getId(), - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(properties, "mypk")), + new PartitionKey(properties.get("mypk")), options); assertThat(deleteResponse.getStatusCode()).isEqualTo(204); diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/ClientTelemetryTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/ClientTelemetryTest.java index f166afb49560..9a7e7cdf32b2 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/ClientTelemetryTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/ClientTelemetryTest.java @@ -381,7 +381,7 @@ private InternalObjectNode getInternalObjectNode() { InternalObjectNode internalObjectNode = new InternalObjectNode(); String uuid = UUID.randomUUID().toString(); internalObjectNode.setId(uuid); - BridgeInternal.setProperty(internalObjectNode, "mypk", uuid); + internalObjectNode.set("mypk", uuid, CosmosItemSerializer.DEFAULT_SERIALIZER); return internalObjectNode; } diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/CosmosDatabaseForTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/CosmosDatabaseForTest.java index bfe136bac4c3..5055166eca39 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/CosmosDatabaseForTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/CosmosDatabaseForTest.java @@ -25,7 +25,7 @@ public class CosmosDatabaseForTest { private static Logger logger = LoggerFactory.getLogger(CosmosDatabaseForTest.class); public static final String SHARED_DB_ID_PREFIX = "RxJava.SDKTest.SharedDatabase"; - private static final Duration CLEANUP_THRESHOLD_DURATION = Duration.ofHours(2); + private static final Duration CLEANUP_THRESHOLD_DURATION = Duration.ofHours(8); private static final String DELIMITER = "_"; private static DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss"); diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/CosmosDiagnosticsTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/CosmosDiagnosticsTest.java index 22aeb65008b5..f49bc64cf3d6 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/CosmosDiagnosticsTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/CosmosDiagnosticsTest.java @@ -1586,7 +1586,7 @@ private InternalObjectNode getInternalObjectNode() { InternalObjectNode internalObjectNode = new InternalObjectNode(); String uuid = UUID.randomUUID().toString(); internalObjectNode.setId(uuid); - BridgeInternal.setProperty(internalObjectNode, "mypk", uuid); + internalObjectNode.set("mypk", uuid, CosmosItemSerializer.DEFAULT_SERIALIZER); return internalObjectNode; } @@ -1594,7 +1594,7 @@ private InternalObjectNode getInternalObjectNode(String pkValue) { InternalObjectNode internalObjectNode = new InternalObjectNode(); String uuid = UUID.randomUUID().toString(); internalObjectNode.setId(uuid); - BridgeInternal.setProperty(internalObjectNode, "mypk", pkValue); + internalObjectNode.set( "mypk", pkValue, CosmosItemSerializer.DEFAULT_SERIALIZER); return internalObjectNode; } diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/CosmosItemContentResponseOnWriteTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/CosmosItemContentResponseOnWriteTest.java index 37f08f02405c..7222de246a3b 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/CosmosItemContentResponseOnWriteTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/CosmosItemContentResponseOnWriteTest.java @@ -88,7 +88,7 @@ public void readItem_withContentResponseOnWriteDisabled() throws Exception { CosmosItemResponse itemResponse = container.createItem(properties, cosmosItemRequestOptions); CosmosItemResponse readResponse1 = container.readItem(properties.getId(), - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(properties, "mypk")), + new PartitionKey(properties.get("mypk")), cosmosItemRequestOptions, InternalObjectNode.class); // Read item should have full response irrespective of the flag - contentResponseOnWriteEnabled @@ -107,7 +107,7 @@ public void readItem_withContentResponseOnWriteEnabledThroughRequestOptions() th } CosmosItemResponse readResponse1 = container.readItem(properties.getId(), - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(properties, "mypk")), + new PartitionKey(properties.get("mypk")), cosmosItemRequestOptions, InternalObjectNode.class); // Read item should have full response irrespective of the flag - contentResponseOnWriteEnabled @@ -126,13 +126,13 @@ public void replaceItem_withContentResponseOnWriteDisabled() { validateMinimalItemResponse(properties, itemResponse, true); String newPropValue = UUID.randomUUID().toString(); - BridgeInternal.setProperty(properties, "newProp", newPropValue); + properties.set("newProp", newPropValue, CosmosItemSerializer.DEFAULT_SERIALIZER); ModelBridgeInternal.setPartitionKey(cosmosItemRequestOptions, - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(properties, "mypk"))); + new PartitionKey(properties.get("mypk"))); // replace document CosmosItemResponse replace = container.replaceItem(properties, properties.getId(), - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(properties, "mypk")), + new PartitionKey(properties.get("mypk")), cosmosItemRequestOptions); validateMinimalItemResponse(properties, replace, true); } @@ -148,13 +148,13 @@ public void replaceItem_withContentResponseOnWriteEnabledThroughRequestOptions() validateItemResponse(properties, itemResponse); String newPropValue = UUID.randomUUID().toString(); - BridgeInternal.setProperty(properties, "newProp", newPropValue); + properties.set("newProp", newPropValue, CosmosItemSerializer.DEFAULT_SERIALIZER); ModelBridgeInternal.setPartitionKey(cosmosItemRequestOptions, - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(properties, "mypk"))); + new PartitionKey(properties.get("mypk"))); // replace document CosmosItemResponse replace = container.replaceItem(properties, properties.getId(), - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(properties, "mypk")), + new PartitionKey(properties.get("mypk")), cosmosItemRequestOptions); validateItemResponse(properties, replace); } @@ -166,7 +166,7 @@ public void deleteItem_withContentResponseOnWriteDisabled() throws Exception { CosmosItemRequestOptions options = new CosmosItemRequestOptions(); CosmosItemResponse deleteResponse = container.deleteItem(properties.getId(), - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(properties, "mypk")), + new PartitionKey(properties.get("mypk")), options); assertThat(deleteResponse.getStatusCode()).isEqualTo(204); validateMinimalItemResponse(properties, deleteResponse, false); @@ -182,7 +182,7 @@ public void deleteItem_withContentResponseOnWriteEnabledThroughRequestOptions() } CosmosItemResponse deleteResponse = container.deleteItem(properties.getId(), - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(properties, "mypk")), + new PartitionKey(properties.get("mypk")), cosmosItemRequestOptions); assertThat(deleteResponse.getStatusCode()).isEqualTo(204); validateMinimalItemResponse(properties, deleteResponse, false); diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/CosmosItemSerializerTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/CosmosItemSerializerTest.java new file mode 100644 index 000000000000..6ebf8fbe225f --- /dev/null +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/CosmosItemSerializerTest.java @@ -0,0 +1,781 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + * + */ + +package com.azure.cosmos; + +import com.azure.cosmos.implementation.TestConfigurations; +import com.azure.cosmos.models.CosmosBatch; +import com.azure.cosmos.models.CosmosBatchOperationResult; +import com.azure.cosmos.models.CosmosBatchRequestOptions; +import com.azure.cosmos.models.CosmosBatchResponse; +import com.azure.cosmos.models.CosmosBulkExecutionOptions; +import com.azure.cosmos.models.CosmosBulkOperationResponse; +import com.azure.cosmos.models.CosmosBulkOperations; +import com.azure.cosmos.models.CosmosChangeFeedRequestOptions; +import com.azure.cosmos.models.CosmosItemIdentity; +import com.azure.cosmos.models.CosmosItemOperation; +import com.azure.cosmos.models.CosmosItemRequestOptions; +import com.azure.cosmos.models.CosmosItemResponse; +import com.azure.cosmos.models.CosmosPatchItemRequestOptions; +import com.azure.cosmos.models.CosmosPatchOperations; +import com.azure.cosmos.models.CosmosQueryRequestOptions; +import com.azure.cosmos.models.CosmosReadManyRequestOptions; +import com.azure.cosmos.models.FeedRange; +import com.azure.cosmos.models.FeedResponse; +import com.azure.cosmos.models.PartitionKey; +import com.azure.cosmos.rx.TestSuiteBase; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.testng.AssertJUnit.fail; + +public class CosmosItemSerializerTest extends TestSuiteBase { + private final static ObjectMapper objectMapper = new ObjectMapper() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true) + .configure(JsonParser.Feature.ALLOW_TRAILING_COMMA, true) + .configure(DeserializationFeature.ACCEPT_FLOAT_AS_INT, false); + + private CosmosClient client; + private CosmosContainer container; + private final boolean isContentOnWriteEnabled; + private final boolean nonIdempotentWriteRetriesEnabled; + private final boolean useTrackingIdForCreateAndReplace; + + @Factory(dataProvider = "clientBuildersWithDirectSessionIncludeComputeGatewayAndDifferentItemSerializers") + public CosmosItemSerializerTest( + CosmosClientBuilder clientBuilder, + boolean inContentOnWriteEnabled, + boolean nonIdempotentWriteRetriesEnabled, + boolean useTrackingIdForCreateAndReplace) { + super(clientBuilder); + + this.isContentOnWriteEnabled = inContentOnWriteEnabled; + this.nonIdempotentWriteRetriesEnabled = nonIdempotentWriteRetriesEnabled; + this.useTrackingIdForCreateAndReplace = useTrackingIdForCreateAndReplace; + } + + @DataProvider + public static Object[][] clientBuildersWithDirectSessionIncludeComputeGatewayAndDifferentItemSerializers() { + boolean[] contentResponseOnWriteValues = new boolean[] { true, false }; + boolean[] nonIdempotentWriteRetriesEnabledValues = new boolean[] { true, false }; + boolean[] trackingIdUsageForWriteRetriesEnabledValues = new boolean[] { true, false }; + + CosmosItemSerializer[] itemSerializers = new CosmosItemSerializer[] { + null, + CosmosItemSerializer.DEFAULT_SERIALIZER, + EnvelopWrappingItemSerializer.INSTANCE_NO_TRACKING_ID_VALIDATION + }; + + List providers = new ArrayList<>(); + for (CosmosItemSerializer serializer : itemSerializers) { + for (boolean isContentResponseOnWriteEnabled : contentResponseOnWriteValues) { + for (boolean nonIdempotentWriteRetriesEnabled : nonIdempotentWriteRetriesEnabledValues) { + for (boolean trackingIdUsageForWriteRetriesEnabled : trackingIdUsageForWriteRetriesEnabledValues) { + if (!nonIdempotentWriteRetriesEnabled && trackingIdUsageForWriteRetriesEnabled) { + continue; + } + + Object[][] originalProviders = clientBuildersWithDirectSession( + isContentResponseOnWriteEnabled, + true, + toArray(protocols)); + List providersCurrentTestCase = new ArrayList<>(); + + for (Object[] current : originalProviders) { + Object[] injectedProviderParameters = new Object[4]; + injectedProviderParameters[0] = current[0]; + + injectedProviderParameters[1] = isContentResponseOnWriteEnabled; + injectedProviderParameters[2] = nonIdempotentWriteRetriesEnabled; + injectedProviderParameters[3] = trackingIdUsageForWriteRetriesEnabled; + providersCurrentTestCase.add(injectedProviderParameters); + } + + CosmosClientBuilder builder = createGatewayRxDocumentClient( + TestConfigurations.HOST.replace(ROUTING_GATEWAY_EMULATOR_PORT, COMPUTE_GATEWAY_EMULATOR_PORT), + ConsistencyLevel.SESSION, + false, + null, + isContentResponseOnWriteEnabled, + true); + Object[] injectedProviderParameters = new Object[4]; + injectedProviderParameters[0] = builder; + injectedProviderParameters[1] = isContentResponseOnWriteEnabled; + injectedProviderParameters[2] = nonIdempotentWriteRetriesEnabled; + injectedProviderParameters[3] = trackingIdUsageForWriteRetriesEnabled; + providersCurrentTestCase.add(injectedProviderParameters); + + for (Object[] wrappedProvider : providersCurrentTestCase) { + CosmosClientBuilder clientBuilder = (CosmosClientBuilder) wrappedProvider[0]; + clientBuilder.customSerializer(serializer); + clientBuilder.nonIdempotentWriteRetryPolicy( + nonIdempotentWriteRetriesEnabled, + trackingIdUsageForWriteRetriesEnabled); + } + + providers.addAll(providersCurrentTestCase); + } + } + } + } + + Object[][] array = new Object[providers.size()][]; + + return providers.toArray(array); + } + + @BeforeClass(groups = { "fast", "emulator" }, timeOut = SETUP_TIMEOUT) + public void before_CosmosItemTest() { + assertThat(this.client).isNull(); + this.client = getClientBuilder().buildClient(); + CosmosAsyncContainer asyncContainer = getSharedMultiPartitionCosmosContainer(this.client.asyncClient()); + container = client.getDatabase(asyncContainer.getDatabase().getId()).getContainer(asyncContainer.getId()); + } + + @AfterClass(groups = { "fast", "emulator" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + assertThat(this.client).isNotNull(); + this.client.close(); + } + + @DataProvider(name = "testConfigs_requestLevelSerializer") + public Object[][] testConfigs_requestLevelSerializer() { + return new Object[][] { + new Object[] { + CosmosItemSerializer.DEFAULT_SERIALIZER + }, + + new Object[] { + EnvelopWrappingItemSerializer.INSTANCE_NO_TRACKING_ID_VALIDATION + }, + + new Object[] { + null + } + }; + } + + @Override + public String resolveTestNameSuffix(Object[] row) { + String prefix = nonIdempotentWriteRetriesEnabled + ? useTrackingIdForCreateAndReplace ? "WriteRetriesWithTrackingId|" : "WriteRetriesNoTrackingId|" + : "NoWriteRetries|"; + + CosmosItemSerializer requestOptionsSerializer = (CosmosItemSerializer) row[0]; + if (requestOptionsSerializer == CosmosItemSerializer.DEFAULT_SERIALIZER) { + prefix += "RequestOptions_DEFAULT"; + } else if (requestOptionsSerializer == null) { + prefix += "RequestOptions_NULL"; + } else { + prefix += "RequestOptions_" + requestOptionsSerializer.getClass().getSimpleName(); + } + + if (this.getClientBuilder().getCustomSerializer() == null) { + return prefix + "|Client_NULL"; + } else if (this.getClientBuilder().getCustomSerializer() == CosmosItemSerializer.DEFAULT_SERIALIZER) { + return prefix + "|Client_DEFAULT"; + } + + return prefix + "|Client_" + this.getClientBuilder().getCustomSerializer().getClass().getSimpleName(); + } + + @Test(groups = { "fast", "emulator" }, dataProvider = "testConfigs_requestLevelSerializer", timeOut = TIMEOUT * 1000000) + public void pointOperationsAndQueryWithPojo(CosmosItemSerializer requestLevelSerializer) { + String id = UUID.randomUUID().toString(); + TestDocument doc = TestDocument.create(id); + Consumer onBeforeReplace = item -> item.someNumber = 999; + BiFunction onBeforePatch = (item, isEnvelopeWrapped) -> { + + doc.someNumber = 555; + if (!isEnvelopeWrapped) { + return CosmosPatchOperations + .create() + .add("/someNumber", 555); + } else { + return CosmosPatchOperations + .create() + .add("/wrappedContent/someNumber", 555); + } + }; + + runPointOperationAndQueryTestCase( + doc, + id, + onBeforeReplace, + onBeforePatch, + requestLevelSerializer, + TestDocument.class); + } + + @Test(groups = { "fast", "emulator" }, dataProvider = "testConfigs_requestLevelSerializer", timeOut = TIMEOUT * 1000000) + public void pointOperationsAndQueryWithObjectNode(CosmosItemSerializer requestLevelSerializer) { + String id = UUID.randomUUID().toString(); + ObjectNode doc = TestDocument.createAsObjectNode(id); + Consumer onBeforeReplace = item -> item.put("someNumber", 999); + BiFunction onBeforePatch = (item, isEnvelopeWrapped) -> { + + item.put("someNumber", 555); + + if (!isEnvelopeWrapped) { + return CosmosPatchOperations + .create() + .add("/someNumber", 555); + } else { + return CosmosPatchOperations + .create() + .add("/wrappedContent/someNumber", 555); + } + }; + + runPointOperationAndQueryTestCase( + doc, + id, + onBeforeReplace, + onBeforePatch, + requestLevelSerializer, + ObjectNode.class); + } + + private void runPointOperationAndQueryTestCase( + T doc, + String id, + Consumer beforeReplace, + BiFunction beforePatch, + CosmosItemSerializer requestLevelSerializer, + Class classType) { + + boolean useEnvelopeWrapper = + requestLevelSerializer == EnvelopWrappingItemSerializer.INSTANCE_NO_TRACKING_ID_VALIDATION + || (requestLevelSerializer == null + && this.getClientBuilder() + .getCustomSerializer() == EnvelopWrappingItemSerializer.INSTANCE_NO_TRACKING_ID_VALIDATION); + if (requestLevelSerializer == EnvelopWrappingItemSerializer.INSTANCE_NO_TRACKING_ID_VALIDATION + && isContentOnWriteEnabled + && nonIdempotentWriteRetriesEnabled + && useTrackingIdForCreateAndReplace) { + + requestLevelSerializer = EnvelopWrappingItemSerializer.INSTANCE_WITH_TRACKING_ID_VALIDATION; + } + + CosmosItemRequestOptions requestOptions = new CosmosItemRequestOptions() + .setCustomSerializer(requestLevelSerializer); + CosmosItemResponse pojoResponse = container.createItem(doc, new PartitionKey(id), requestOptions); + + if (this.isContentOnWriteEnabled) { + assertSameDocument(doc, pojoResponse.getItem()); + } else { + assertThat(pojoResponse.getItem()).isNull(); + } + + container.deleteItem(doc, requestOptions); + + pojoResponse = container.createItem(doc, requestOptions); + + if (this.isContentOnWriteEnabled) { + assertSameDocument(doc, pojoResponse.getItem()); + } else { + assertThat(pojoResponse.getItem()).isNull(); + } + + pojoResponse = container.readItem(id, new PartitionKey(id), requestOptions, classType); + assertSameDocument(doc, pojoResponse.getItem()); + + beforeReplace.accept(doc); + pojoResponse = container.replaceItem(doc, id, new PartitionKey(id), requestOptions); + if (this.isContentOnWriteEnabled) { + assertSameDocument(doc, pojoResponse.getItem()); + } else { + assertThat(pojoResponse.getItem()).isNull(); + } + + CosmosPatchOperations patchOperations = beforePatch.apply(doc, useEnvelopeWrapper); + CosmosPatchItemRequestOptions patchRequestOptions = new CosmosPatchItemRequestOptions(); + if (useEnvelopeWrapper) { + patchRequestOptions.setCustomSerializer(EnvelopWrappingItemSerializer.INSTANCE_FOR_PATCH); + } else { + patchRequestOptions.setCustomSerializer(requestLevelSerializer); + } + + pojoResponse = container.patchItem(id, new PartitionKey(id), patchOperations, patchRequestOptions, classType); + if (this.isContentOnWriteEnabled) { + assertSameDocument(doc, pojoResponse.getItem()); + } else { + assertThat(pojoResponse.getItem()).isNull(); + } + + pojoResponse = container.readItem(id, new PartitionKey(id), requestOptions, classType); + assertSameDocument(doc, pojoResponse.getItem()); + + beforeReplace.accept(doc); + if (requestLevelSerializer == EnvelopWrappingItemSerializer.INSTANCE_WITH_TRACKING_ID_VALIDATION) { + requestLevelSerializer = EnvelopWrappingItemSerializer.INSTANCE_NO_TRACKING_ID_VALIDATION; + } + CosmosItemRequestOptions upsertRequestOptions = new CosmosItemRequestOptions(); + if (useEnvelopeWrapper) { + upsertRequestOptions.setCustomSerializer(EnvelopWrappingItemSerializer.INSTANCE_NO_TRACKING_ID_VALIDATION); + } else { + upsertRequestOptions.setCustomSerializer(requestOptions.getCustomSerializer()); + } + pojoResponse = container.upsertItem(doc, new PartitionKey(id), upsertRequestOptions); + if (this.isContentOnWriteEnabled) { + assertSameDocument(doc, pojoResponse.getItem()); + } else { + assertThat(pojoResponse.getItem()).isNull(); + } + + CosmosQueryRequestOptions queryRequestOptions = new CosmosQueryRequestOptions(); + if (useEnvelopeWrapper) { + queryRequestOptions.setCustomSerializer(EnvelopWrappingItemSerializer.INSTANCE_NO_TRACKING_ID_VALIDATION); + } else { + queryRequestOptions.setCustomSerializer(requestOptions.getCustomSerializer()); + } + List results = container + .queryItems("SELECT * FROM c where c.id = '" + id + "'", queryRequestOptions, classType) + .stream().collect(Collectors.toList()); + assertThat(results).isNotNull(); + assertThat(results).hasSize(1); + assertSameDocument(doc, results.get(0)); + + results = container.readAllItems(new PartitionKey(id), queryRequestOptions, classType) + .stream().collect(Collectors.toList()); + assertThat(results).isNotNull(); + assertThat(results).hasSize(1); + assertSameDocument(doc, results.get(0)); + } + + @Test(groups = { "fast", "emulator" }, dataProvider = "testConfigs_requestLevelSerializer", timeOut = TIMEOUT * 1000000) + public void bulkAndReadManyWithObjectNode(CosmosItemSerializer requestLevelSerializer) { + + runBulkAndReadManyTestCase( + id -> TestDocument.createAsObjectNode(id), + requestLevelSerializer, + ObjectNode.class + ); + } + + @Test(groups = { "fast", "emulator" }, dataProvider = "testConfigs_requestLevelSerializer", timeOut = TIMEOUT * 1000000) + public void bulkAndReadManyWithPojo(CosmosItemSerializer requestLevelSerializer) { + + runBulkAndReadManyTestCase( + id -> TestDocument.create(id), + requestLevelSerializer, + TestDocument.class + ); + } + + + private void runBulkAndReadManyTestCase( + Function docGenerator, + CosmosItemSerializer requestLevelSerializer, + Class classType) { + + CosmosBulkExecutionOptions bulkExecOptions = new CosmosBulkExecutionOptions() + .setCustomSerializer(requestLevelSerializer); + + List bulkOperations = new ArrayList<>(); + Map inputItems = new HashMap<>(); + for (int i = 0; i < 10; i++) { + String id = UUID.randomUUID().toString(); + T doc = docGenerator.apply(id); + inputItems.put(id, doc); + + bulkOperations.add(CosmosBulkOperations.getCreateItemOperation( + doc, + new PartitionKey(id), + id)); + } + + Iterable> responseFlux = + container.executeBulkOperations(bulkOperations, bulkExecOptions); + for(CosmosBulkOperationResponse response: responseFlux) { + assertThat(response.getException()).isNull(); + assertThat(response.getResponse()).isNotNull(); + assertThat(response.getResponse().getStatusCode()).isBetween(200, 201); + assertThat(response.getOperation().getContext()).isNotNull(); + String id = response.getOperation().getContext(); + assertThat(inputItems.containsKey(id)).isTrue(); + T responseItem = response.getResponse().getItem(classType); + + if (isContentOnWriteEnabled) { + assertSameDocument(inputItems.get(id), responseItem); + } else { + assertThat(responseItem).isNull(); + } + } + + List readManyTuples = new ArrayList<>(); + for (String id: inputItems.keySet().stream().limit(3).toArray(count -> new String[count])) { + readManyTuples.add(new CosmosItemIdentity(new PartitionKey(id), id)); + } + + CosmosReadManyRequestOptions readManyRequestOptions = new CosmosReadManyRequestOptions() + .setCustomSerializer(requestLevelSerializer); + + FeedResponse response = container.readMany(readManyTuples, readManyRequestOptions, classType); + assertThat(response).isNotNull(); + Object[] items = response.getElements().stream().toArray(); + assertThat(items).isNotNull(); + assertThat(items).hasSize(3); + for(Object responseItem: items) { + assertThat(responseItem).isNotNull(); + if (responseItem instanceof TestDocument) { + TestDocument doc = (TestDocument) responseItem; + assertThat(inputItems.containsKey(doc.id)).isTrue(); + assertSameDocument(inputItems.get(doc.id), doc); + } else if (responseItem instanceof ObjectNode) { + ObjectNode doc = (ObjectNode) responseItem; + String id = doc.get("id").asText(); + assertThat(inputItems.containsKey(id)).isTrue(); + assertSameDocument(inputItems.get(id), doc); + } else { + fail("Unexpected response item type '" + responseItem.getClass().getSimpleName() + "'."); + } + } + } + + @Test(groups = { "fast", "emulator" }, dataProvider = "testConfigs_requestLevelSerializer", timeOut = TIMEOUT * 1000000) + public void batchAndChangeFeedWithObjectNode(CosmosItemSerializer requestLevelSerializer) { + + runBatchAndChangeFeedTestCase( + pk -> TestDocument.createAsObjectNode(UUID.randomUUID().toString(), pk), + requestLevelSerializer, + ObjectNode.class + ); + } + + @Test(groups = { "fast", "emulator" }, dataProvider = "testConfigs_requestLevelSerializer", timeOut = TIMEOUT * 1000000) + public void batchAndChangeFeedWithPojo(CosmosItemSerializer requestLevelSerializer) { + + runBatchAndChangeFeedTestCase( + pk -> TestDocument.create(UUID.randomUUID().toString(), pk), + requestLevelSerializer, + TestDocument.class + ); + } + + + private void runBatchAndChangeFeedTestCase( + Function docGenerator, + CosmosItemSerializer requestLevelSerializer, + Class classType) { + + String pkValue = UUID.randomUUID().toString(); + CosmosBatch batch = CosmosBatch.createCosmosBatch(new PartitionKey(pkValue)); + List inputItems = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + T doc = docGenerator.apply(pkValue); + inputItems.add(doc); + batch.createItemOperation(doc); + } + + CosmosBatchRequestOptions batchRequestOptions = new CosmosBatchRequestOptions() + .setCustomSerializer(requestLevelSerializer); + + CosmosBatchResponse response = container.executeCosmosBatch(batch, batchRequestOptions); + assertThat(response).isNotNull(); + assertThat(response.getStatusCode()).isEqualTo(200); + assertThat(response.getErrorMessage()).isNull(); + assertThat(response.getResults()).isNotNull(); + assertThat(response.getResults()).hasSize(10); + for (CosmosBatchOperationResult result: response.getResults()) { + T responseItem = result.getItem(classType); + if (isContentOnWriteEnabled) { + boolean found = false; + for (T inputItem: inputItems) { + if (hasSameId(inputItem, responseItem)) { + assertSameDocument(inputItem, responseItem); + found = true; + break; + } + } + + assertThat(found).isTrue(); + + } else { + assertThat(responseItem).isNull(); + } + } + + CosmosChangeFeedRequestOptions changeFeedRequestOptions = CosmosChangeFeedRequestOptions + .createForProcessingFromBeginning( + FeedRange.forLogicalPartition(new PartitionKey(pkValue)) + ) + .setCustomSerializer(requestLevelSerializer); + + List results = container + .queryChangeFeed(changeFeedRequestOptions, classType) + .stream().collect(Collectors.toList()); + assertThat(results).isNotNull(); + assertThat(results).hasSize(10); + for (T responseItem: results) { + boolean found = false; + for (T inputItem: inputItems) { + if (hasSameId(inputItem, responseItem)) { + assertSameDocument(inputItem, responseItem); + found = true; + break; + } + } + + assertThat(found).isTrue(); + } + } + + private static class TestChildObject { + public String childId; + + public Integer someNumber; + } + + private static class TestDocument { + public String id; + + public String mypk; + + public Integer someNumber; + + public String[] someStringArray; + + public Integer[] someNumberArray; + + public TestChildObject someChildObject; + + public TestChildObject[] someChildObjectArray; + + public static TestDocument create(String id) { + return create(id, id); + } + + public static TestDocument create(String id, String pk) { + TestDocument doc = new TestDocument(); + doc.id = id; + doc.mypk = pk; + doc.someNumber = 5; + doc.someStringArray = new String[] { id, "someString2", "someString3" }; + doc.someNumberArray = new Integer[] { 1, 3, 5 }; + TestChildObject child = new TestChildObject(); + child.childId = "C1_" + id; + child.someNumber = 9; + doc.someChildObject = child; + doc.someChildObjectArray = new TestChildObject[] { child, child }; + + return doc; + } + + public static ObjectNode createAsObjectNode(String id) { + return createAsObjectNode(id, id); + } + + public static ObjectNode createAsObjectNode(String id, String pk) { + ObjectNode node = objectMapper.createObjectNode(); + node.put("id", id); + node.put("mypk", pk); + node.put("someNumber", 5); + node.put("someStringArray", objectMapper.createArrayNode().add(id).add("someString2").add("someString3")); + node.put("someNumberArray", objectMapper.createArrayNode().add(1).add(3).add(5)); + ObjectNode child = objectMapper.createObjectNode(); + child.put("childId", "C1_" + id); + child.put("someNumber", 9); + node.put("someChildObject", child); + node.put("someChildObjectArray", objectMapper.createArrayNode().add(child).add(child)); + + return node; + } + + public static TestDocument parse(ObjectNode node) { + try { + return objectMapper.treeToValue(node, TestDocument.class); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + } + + private static boolean hasSameId(Object doc, Object deserializedDoc) { + assertThat(doc).isNotNull(); + assertThat(deserializedDoc).isNotNull(); + + if (doc instanceof TestDocument) { + return hasSameId((TestDocument) doc, (TestDocument) deserializedDoc); + } + + return hasSameId((ObjectNode) doc, (ObjectNode) deserializedDoc); + } + + private static void assertSameDocument(Object doc, Object deserializedDoc) { + assertThat(doc).isNotNull(); + assertThat(deserializedDoc).isNotNull(); + + if (doc instanceof TestDocument) { + assertSameDocument((TestDocument) doc, (TestDocument) deserializedDoc); + return; + } + + assertSameDocument((ObjectNode) doc, (ObjectNode) deserializedDoc); + } + + private static boolean hasSameId(ObjectNode doc, ObjectNode deserializedDoc) { + assertThat(doc).isNotNull(); + assertThat(deserializedDoc).isNotNull(); + + return hasSameId(TestDocument.parse(doc), TestDocument.parse(deserializedDoc)); + } + + private static void assertSameDocument(ObjectNode doc, ObjectNode deserializedDoc) { + assertThat(doc).isNotNull(); + assertThat(deserializedDoc).isNotNull(); + + assertSameDocument(TestDocument.parse(doc), TestDocument.parse(deserializedDoc)); + } + + private static boolean hasSameId(TestDocument doc, TestDocument deserializedDoc) { + assertThat(doc).isNotNull(); + assertThat(deserializedDoc).isNotNull(); + return doc.id.equals(deserializedDoc.id); + } + + private static void assertSameDocument(TestDocument doc, TestDocument deserializedDoc) { + + assertThat(doc).isNotNull(); + assertThat(deserializedDoc).isNotNull(); + assertThat(deserializedDoc.id).isEqualTo(doc.id); + assertThat(deserializedDoc.mypk).isEqualTo(doc.mypk); + assertThat(deserializedDoc.someNumber).isEqualTo(doc.someNumber); + if (doc.someStringArray == null) { + assertThat(deserializedDoc.someStringArray).isNull(); + } else { + assertThat(deserializedDoc.someStringArray).isNotNull(); + assertThat(deserializedDoc.someStringArray.length).isEqualTo(doc.someStringArray.length); + assertThat(deserializedDoc.someStringArray).containsAll(Arrays.stream(doc.someStringArray).collect(Collectors.toList())); + } + + if (doc.someNumberArray == null) { + assertThat(deserializedDoc.someNumberArray).isNull(); + } else { + assertThat(deserializedDoc.someNumberArray).isNotNull(); + assertThat(deserializedDoc.someNumberArray.length).isEqualTo(doc.someNumberArray.length); + assertThat(deserializedDoc.someNumberArray).containsAll(Arrays.stream(doc.someNumberArray).collect(Collectors.toList())); + } + + if (doc.someChildObject == null) { + assertThat(deserializedDoc.someChildObject).isNull(); + } else { + assertThat(deserializedDoc.someChildObject).isNotNull(); + assertThat(deserializedDoc.someChildObject.childId).isEqualTo(doc.someChildObject.childId); + assertThat(deserializedDoc.someChildObject.someNumber).isEqualTo(doc.someChildObject.someNumber); + } + + if (doc.someChildObjectArray == null) { + assertThat(deserializedDoc.someChildObjectArray).isNull(); + } else { + assertThat(deserializedDoc.someChildObjectArray).isNotNull(); + assertThat(deserializedDoc.someChildObjectArray.length).isEqualTo(doc.someChildObjectArray.length); + for (int i = 0; i < doc.someChildObjectArray.length; i++) { + assertThat(deserializedDoc.someChildObjectArray[i].childId).isEqualTo(doc.someChildObjectArray[i].childId); + assertThat(deserializedDoc.someChildObjectArray[i].someNumber).isEqualTo(doc.someChildObjectArray[i].someNumber); + } + } + } + + private static class TestDocumentWrappedInEnvelope { + public String id; + + public String mypk; + + public ObjectNode wrappedContent; + } + + private static class EnvelopWrappingItemSerializer extends CosmosItemSerializer { + public static final CosmosItemSerializer INSTANCE_NO_TRACKING_ID_VALIDATION = new EnvelopWrappingItemSerializer(false, false); + public static final CosmosItemSerializer INSTANCE_WITH_TRACKING_ID_VALIDATION = new EnvelopWrappingItemSerializer(true, false); + public static final CosmosItemSerializer INSTANCE_FOR_PATCH = new EnvelopWrappingItemSerializer(false, true); + + private final static Class mapClass = new ConcurrentHashMap().getClass(); + + private final boolean shouldValidateTrackingId; + private final boolean passThroughOnSerialize; + + public EnvelopWrappingItemSerializer(boolean enabledTrackingIdValidation, boolean passThroughOnSerialize) { + this.shouldValidateTrackingId = enabledTrackingIdValidation; + this.passThroughOnSerialize = passThroughOnSerialize; + } + + @Override + public Map serialize(T item) { + if (item == null) { + return null; + } + + if (passThroughOnSerialize) { + return CosmosItemSerializer.DEFAULT_SERIALIZER.serialize(item); + } + + Map unwrappedJsonTree = CosmosItemSerializer.DEFAULT_SERIALIZER.serialize(item); + if (unwrappedJsonTree.containsKey("wrappedContent")) { + throw new IllegalStateException("Double wrapping"); + } + + Map wrappedJsonTree = new ConcurrentHashMap<>(); + wrappedJsonTree.put("id", unwrappedJsonTree.get("id")); + wrappedJsonTree.put("mypk", unwrappedJsonTree.get("mypk")); + wrappedJsonTree.put("wrappedContent", unwrappedJsonTree); + + return wrappedJsonTree; + } + + @Override + public T deserialize(Map jsonNodeMap, Class classType) { + if (jsonNodeMap == null) { + return null; + } + + if (shouldValidateTrackingId) { + assertThat(jsonNodeMap.containsKey("_trackingId")).isEqualTo(true); + assertThat(jsonNodeMap.get("_trackingId")).isNotNull(); + } + + TestDocumentWrappedInEnvelope envelope = + CosmosItemSerializer.DEFAULT_SERIALIZER.deserialize(jsonNodeMap, TestDocumentWrappedInEnvelope.class); + + if (envelope == null || envelope.wrappedContent == null) { + return null; + } + + Map unwrappedContent = + (Map) objectMapper.convertValue(envelope.wrappedContent, mapClass); + + if (unwrappedContent.containsKey("wrappedContent")) { + throw new IllegalStateException("Double wrapped"); + } + + return CosmosItemSerializer.DEFAULT_SERIALIZER.deserialize( + unwrappedContent, + classType); + } + } +} diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/CosmosItemTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/CosmosItemTest.java index 76c38fae37bb..020b845fae9d 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/CosmosItemTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/CosmosItemTest.java @@ -134,7 +134,7 @@ public void createLargeItem() throws Exception { //Keep size as ~ 1.5MB to account for size of other props int size = (int) (ONE_MB * 1.5); - BridgeInternal.setProperty(docDefinition, "largeString", StringUtils.repeat("x", size)); + docDefinition.set("largeString", StringUtils.repeat("x", size), CosmosItemSerializer.DEFAULT_SERIALIZER); CosmosItemResponse itemResponse = container.createItem(docDefinition, new CosmosItemRequestOptions()); @@ -148,7 +148,7 @@ public void createItemWithVeryLargePartitionKey() throws Exception { for(int i = 0; i < 100; i++) { sb.append(i).append("x"); } - BridgeInternal.setProperty(docDefinition, "mypk", sb.toString()); + docDefinition.set("mypk", sb.toString(), CosmosItemSerializer.DEFAULT_SERIALIZER); CosmosItemResponse itemResponse = container.createItem(docDefinition, new CosmosItemRequestOptions()); @@ -162,7 +162,7 @@ public void readItemWithVeryLargePartitionKey() throws Exception { for(int i = 0; i < 100; i++) { sb.append(i).append("x"); } - BridgeInternal.setProperty(docDefinition, "mypk", sb.toString()); + docDefinition.set("mypk", sb.toString(), CosmosItemSerializer.DEFAULT_SERIALIZER); CosmosItemResponse itemResponse = container.createItem(docDefinition); @@ -182,7 +182,7 @@ public void readItem() throws Exception { CosmosItemResponse itemResponse = container.createItem(properties); CosmosItemResponse readResponse1 = container.readItem(properties.getId(), - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(properties, "mypk")), + new PartitionKey(properties.get("mypk")), new CosmosItemRequestOptions(), InternalObjectNode.class); validateItemResponse(properties, readResponse1); @@ -199,7 +199,7 @@ public void readMany() throws Exception { InternalObjectNode document = getDocumentDefinition(UUID.randomUUID().toString()); container.createItem(document); - PartitionKey partitionKey = new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(document, "mypk")); + PartitionKey partitionKey = new PartitionKey(document.get("mypk")); CosmosItemIdentity cosmosItemIdentity = new CosmosItemIdentity(partitionKey, document.getId()); cosmosItemIdentities.add(cosmosItemIdentity); idSet.add(document.getId()); @@ -827,15 +827,15 @@ public void replaceItem() throws Exception{ validateItemResponse(properties, itemResponse); String newPropValue = UUID.randomUUID().toString(); - BridgeInternal.setProperty(properties, "newProp", newPropValue); + properties.set("newProp", newPropValue, CosmosItemSerializer.DEFAULT_SERIALIZER); CosmosItemRequestOptions options = new CosmosItemRequestOptions(); - ModelBridgeInternal.setPartitionKey(options, new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(properties, "mypk"))); + ModelBridgeInternal.setPartitionKey(options, new PartitionKey(properties.get("mypk"))); // replace document CosmosItemResponse replace = container.replaceItem(properties, properties.getId(), - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(properties, "mypk")), + new PartitionKey(properties.get("mypk")), options); - assertThat(ModelBridgeInternal.getObjectFromJsonSerializable(BridgeInternal.getProperties(replace), "newProp")).isEqualTo(newPropValue); + assertThat(BridgeInternal.getProperties(replace).get("newProp")).isEqualTo(newPropValue); } @Test(groups = { "fast" }, timeOut = TIMEOUT) @@ -845,7 +845,7 @@ public void deleteItem() throws Exception { CosmosItemRequestOptions options = new CosmosItemRequestOptions(); CosmosItemResponse deleteResponse = container.deleteItem(properties.getId(), - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(properties, "mypk")), + new PartitionKey(properties.get("mypk")), options); assertThat(deleteResponse.getStatusCode()).isEqualTo(204); } diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/CosmosItemWriteRetriesTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/CosmosItemWriteRetriesTest.java index 62d8608aaeac..38f2b0130a7d 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/CosmosItemWriteRetriesTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/CosmosItemWriteRetriesTest.java @@ -96,7 +96,7 @@ public CosmosAsyncContainer createClientAndGetContainer(WriteRetryPolicy clientW .clientTelemetryConfig(telemetryConfig); if (clientWideWriteRetryPolicy != null && clientWideWriteRetryPolicy.isEnabled()) { - builder.setNonIdempotentWriteRetryPolicy( + builder.nonIdempotentWriteRetryPolicy( true, clientWideWriteRetryPolicy.useTrackingIdProperty()); } else { builder.resetNonIdempotentWriteRetryPolicy(); diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/CosmosResponseValidator.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/CosmosResponseValidator.java index b50e9f0772a7..60e198b0b940 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/CosmosResponseValidator.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/CosmosResponseValidator.java @@ -131,7 +131,7 @@ public Builder withProperty(String propertyName, String value) { @Override public void validate(T cosmosResponse) { assertThat(getResource(cosmosResponse)).isNotNull(); - assertThat(ModelBridgeInternal.getObjectFromJsonSerializable(getResource(cosmosResponse), propertyName)).isEqualTo(value); + assertThat(getResource(cosmosResponse).get(propertyName)).isEqualTo(value); } }); return this; diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/DocumentTests.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/DocumentTests.java index 4b6a53f48077..03cdf00c9c67 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/DocumentTests.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/DocumentTests.java @@ -9,7 +9,6 @@ import java.time.OffsetDateTime; import java.time.ZoneOffset; -import static com.azure.cosmos.BridgeInternal.setTimestamp; import static org.assertj.core.api.Assertions.assertThat; public class DocumentTests { @@ -18,7 +17,7 @@ public class DocumentTests { public void timestamp() { Document d = new Document(); OffsetDateTime time = OffsetDateTime.of(2019, 8, 6, 12, 53, 29, 0, ZoneOffset.UTC); - setTimestamp(d, time.toInstant()); + d.setTimestamp(time.toInstant()); assertThat(d.getTimestamp()).isEqualTo(time.toInstant()); } } diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/FaultInjectionWithAvailabilityStrategyTests.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/FaultInjectionWithAvailabilityStrategyTests.java index 3e1af6448748..87602192845e 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/FaultInjectionWithAvailabilityStrategyTests.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/FaultInjectionWithAvailabilityStrategyTests.java @@ -5276,7 +5276,7 @@ private static CosmosAsyncClient buildCosmosClient( } if (nonIdempotentWriteRetriesEnabled != null) { - builder.setNonIdempotentWriteRetryPolicy( + builder.nonIdempotentWriteRetryPolicy( nonIdempotentWriteRetriesEnabled, true); } diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/MaxRetryCountTests.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/MaxRetryCountTests.java index a8cdfd91eb69..3d9464da4a22 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/MaxRetryCountTests.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/MaxRetryCountTests.java @@ -2559,7 +2559,7 @@ private static CosmosAsyncClient buildCosmosClient( } if (nonIdempotentWriteRetriesEnabled != null) { - builder.setNonIdempotentWriteRetryPolicy( + builder.nonIdempotentWriteRetryPolicy( nonIdempotentWriteRetriesEnabled, true); } diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/MultipleCosmosClientsWithTransportClientSharingTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/MultipleCosmosClientsWithTransportClientSharingTest.java index c2f1fb065e68..b55538a0ff47 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/MultipleCosmosClientsWithTransportClientSharingTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/MultipleCosmosClientsWithTransportClientSharingTest.java @@ -105,7 +105,7 @@ public void readItem() { InternalObjectNode properties1 = getDocumentDefinition(UUID.randomUUID().toString()); CosmosItemResponse itemResponse1 = container1.createItem(properties1); CosmosItemResponse readResponse1 = container1.readItem(properties1.getId(), - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(properties1, "mypk")), + new PartitionKey(properties1.get("mypk")), new CosmosItemRequestOptions(), InternalObjectNode.class); validateItemResponse(properties1, readResponse1); @@ -113,7 +113,7 @@ public void readItem() { InternalObjectNode properties2 = getDocumentDefinition(UUID.randomUUID().toString()); CosmosItemResponse itemResponse2 = container2.createItem(properties2); CosmosItemResponse readResponse2 = container2.readItem(properties2.getId(), - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(properties2, "mypk")), + new PartitionKey(properties2.get("mypk")), new CosmosItemRequestOptions(), InternalObjectNode.class); validateItemResponse(properties2, readResponse2); @@ -126,15 +126,15 @@ public void replaceItem() throws Exception{ validateItemResponse(properties, itemResponse); String newPropValue = UUID.randomUUID().toString(); - BridgeInternal.setProperty(properties, "newProp", newPropValue); + properties.set("newProp", newPropValue, CosmosItemSerializer.DEFAULT_SERIALIZER); CosmosItemRequestOptions options = new CosmosItemRequestOptions(); - ModelBridgeInternal.setPartitionKey(options, new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(properties, "mypk"))); + ModelBridgeInternal.setPartitionKey(options, new PartitionKey(properties.get("mypk"))); // replace document CosmosItemResponse replace = container1.replaceItem(properties, properties.getId(), - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(properties, "mypk")), + new PartitionKey(properties.get("mypk")), options); - assertThat(ModelBridgeInternal.getObjectFromJsonSerializable(BridgeInternal.getProperties(replace), "newProp")).isEqualTo(newPropValue); + assertThat(BridgeInternal.getProperties(replace).get("newProp")).isEqualTo(newPropValue); } @Test(groups = { "fast" }, timeOut = TIMEOUT) @@ -144,7 +144,7 @@ public void deleteItem() { CosmosItemRequestOptions options = new CosmosItemRequestOptions(); CosmosItemResponse deleteResponse = container1.deleteItem(properties.getId(), - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(properties, "mypk")), + new PartitionKey(properties.get("mypk")), options); assertThat(deleteResponse.getStatusCode()).isEqualTo(204); } diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/ConsistencyTests2.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/ConsistencyTests2.java index c9c1d8ec48c7..0aae0bed7698 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/ConsistencyTests2.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/ConsistencyTests2.java @@ -3,9 +3,9 @@ package com.azure.cosmos.implementation; -import com.azure.cosmos.BridgeInternal; import com.azure.cosmos.ConsistencyLevel; import com.azure.cosmos.CosmosException; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.DirectConnectionConfig; import com.azure.cosmos.GatewayConnectionConfig; import com.azure.cosmos.implementation.clienttelemetry.ClientTelemetry; @@ -260,7 +260,10 @@ public void validateSessionTokenAsync() { List documents = new ArrayList<>(); for (int i = 0; i < 1000; i++) { Document documentDefinition = getDocumentDefinition(); - BridgeInternal.setProperty(documentDefinition, UUID.randomUUID().toString(), UUID.randomUUID().toString()); + documentDefinition.set( + UUID.randomUUID().toString(), + UUID.randomUUID().toString(), + CosmosItemSerializer.DEFAULT_SERIALIZER); documents.add(documentDefinition); } diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/ConsistencyTestsBase.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/ConsistencyTestsBase.java index cea5534b7bd1..8f46f081f1ac 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/ConsistencyTestsBase.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/ConsistencyTestsBase.java @@ -4,6 +4,7 @@ package com.azure.cosmos.implementation; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.DirectConnectionConfig; import com.azure.cosmos.GatewayConnectionConfig; import com.azure.cosmos.implementation.apachecommons.collections.map.UnmodifiableMap; @@ -62,7 +63,7 @@ void validateStrongConsistency(Resource resourceToWorkWith) throws Exception { updatedResource = this.writeClient.upsertUser(createdDatabase.getSelfLink(), (User) writeResource, null).block().getResource(); } else if (resourceToWorkWith instanceof Document) { RequestOptions options = new RequestOptions(); - options.setPartitionKey(new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(resourceToWorkWith, "mypk"))); + options.setPartitionKey(new PartitionKey(resourceToWorkWith.get("mypk"))); updatedResource = this.writeClient.upsertDocument(createdCollection.getSelfLink(), (Document) writeResource, options, false).block().getResource(); } assertThat(updatedResource.getTimestamp().isAfter(sourceTimestamp)).isTrue(); @@ -75,7 +76,7 @@ void validateStrongConsistency(Resource resourceToWorkWith) throws Exception { void validateConsistentLSN() { Document documentDefinition = getDocumentDefinition(); RequestOptions options = new RequestOptions(); - options.setPartitionKey(new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(documentDefinition, "mypk"))); + options.setPartitionKey(new PartitionKey(documentDefinition.get("mypk"))); Document document = createDocument(this.writeClient, createdDatabase.getId(), createdCollection.getId(), documentDefinition); ResourceResponse response = this.writeClient.deleteDocument(document.getSelfLink(), options).block(); assertThat(response.getStatusCode()).isEqualTo(204); @@ -90,7 +91,7 @@ void validateConsistentLSN() { void validateConsistentLSNAndQuorumAckedLSN() { Document documentDefinition = getDocumentDefinition(); RequestOptions options = new RequestOptions(); - options.setPartitionKey(new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(documentDefinition, "mypk"))); + options.setPartitionKey(new PartitionKey(documentDefinition.get("mypk"))); Document document = createDocument(this.writeClient, createdDatabase.getId(), createdCollection.getId(), documentDefinition); ResourceResponse response = this.writeClient.deleteDocument(document.getSelfLink(), options).block(); assertThat(response.getStatusCode()).isEqualTo(204); @@ -156,7 +157,7 @@ void validateStrongConsistency(Document documentToWorkWith) throws InterruptedEx Instant sourceTimestamp = writeDocument.getTimestamp(); Thread.sleep(1000);//Timestamp is in granularity of seconds. RequestOptions options = new RequestOptions(); - options.setPartitionKey(new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(documentToWorkWith, "mypk"))); + options.setPartitionKey(new PartitionKey(documentToWorkWith.get("mypk"))); Document updatedDocument = this.writeClient.replaceDocument(writeDocument, options).block().getResource(); assertThat(updatedDocument.getTimestamp().isAfter(sourceTimestamp)).isTrue(); @@ -222,7 +223,7 @@ void validateSessionContainerAfterCollectionCreateReplace(boolean useGateway) { { Document document2 = new Document(); document2.setId("test" + UUID.randomUUID().toString()); - BridgeInternal.setProperty(document2, "customerid", 2); + document2.set("customerid", 2, CosmosItemSerializer.DEFAULT_SERIALIZER); // name link ResourceResponse document = writeClient.createDocument(BridgeInternal.getAltLink(coll), document2, null, false) @@ -236,7 +237,7 @@ void validateSessionContainerAfterCollectionCreateReplace(boolean useGateway) { { Document document2 = new Document(); document2.setId("test" + UUID.randomUUID().toString()); - BridgeInternal.setProperty(document2, "customerid", 3); + document2.set("customerid", 3, CosmosItemSerializer.DEFAULT_SERIALIZER); // name link ResourceResponse document = writeClient.createDocument(BridgeInternal.getAltLink(coll), document2, null, false) @@ -283,7 +284,7 @@ boolean validateConsistentPrefix(Resource resourceToWorkWith) throws Interrupted .getResource(); } else if (resourceToWorkWith instanceof Document) { RequestOptions options = new RequestOptions(); - options.setPartitionKey(new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(resourceToWorkWith, "mypk"))); + options.setPartitionKey(new PartitionKey(resourceToWorkWith.get("mypk"))); readResource = this.readClient.readDocument(resourceToWorkWith.getSelfLink(), options) .block() .getResource(); @@ -318,7 +319,7 @@ boolean validateReadSession(Resource resourceToWorkWith) throws InterruptedExcep Resource readResource = null; RequestOptions requestOptions = new RequestOptions(); - requestOptions.setPartitionKey(new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(resourceToWorkWith, "mypk"))); + requestOptions.setPartitionKey(new PartitionKey(resourceToWorkWith.get("mypk"))); if (resourceToWorkWith instanceof Document) { readResource = this.readClient.readDocument(resourceToWorkWith.getSelfLink(), requestOptions).block().getResource(); } @@ -350,7 +351,7 @@ boolean validateWriteSession(Resource resourceToWorkWith) throws InterruptedExce Resource readResource = null; RequestOptions requestOptions = new RequestOptions(); - requestOptions.setPartitionKey(new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(resourceToWorkWith, "mypk"))); + requestOptions.setPartitionKey(new PartitionKey(resourceToWorkWith.get("mypk"))); if (resourceToWorkWith instanceof Document) { readResource = this.readClient.readDocument(resourceToWorkWith.getSelfLink(), requestOptions) @@ -427,7 +428,7 @@ void validateSessionContainerAfterCollectionDeletion(boolean useGateway) throws documentDefinition.setId(documentId); Document documentCreated = client2.createDocument(collection.getSelfLink(), documentDefinition, null, true).block().getResource(); RequestOptions requestOptions = new RequestOptions(); - requestOptions.setPartitionKey(new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(documentCreated, "mypk"))); + requestOptions.setPartitionKey(new PartitionKey(documentCreated.get("mypk"))); client2.readDocument(BridgeInternal.getAltLink(documentCreated), requestOptions).block(); client2.readDocument(documentCreated.getSelfLink(), requestOptions).block(); } @@ -460,7 +461,7 @@ void validateSessionContainerAfterCollectionDeletion(boolean useGateway) throws databaseDefinition2.setId(documentId1); Document createdDocument = client1.createDocument(collectionSameName.getSelfLink(), databaseDefinition2, null, true).block().getResource(); RequestOptions requestOptions = new RequestOptions(); - requestOptions.setPartitionKey(new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(createdDocument, "mypk"))); + requestOptions.setPartitionKey(new PartitionKey(createdDocument.get("mypk"))); ResourceResponseValidator successValidator = new ResourceResponseValidator.Builder() .withId(createdDocument.getId()) .build(); @@ -479,7 +480,7 @@ void validateSessionContainerAfterCollectionDeletion(boolean useGateway) throws String higherLsnToken = this.getDifferentLSNToken(token, 2000); RequestOptions requestOptions1 = new RequestOptions(); requestOptions1.setSessionToken(higherLsnToken); - requestOptions1.setPartitionKey(new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(createdDocument, "mypk"))); + requestOptions1.setPartitionKey(new PartitionKey(createdDocument.get("mypk"))); readObservable = client2.readDocument(BridgeInternal.getAltLink(createdDocument), requestOptions1); FailureValidator failureValidator = new FailureValidator.Builder().subStatusCode(1002).build(); validateFailure(readObservable, failureValidator); @@ -502,7 +503,7 @@ void validateSessionContainerAfterCollectionDeletion(boolean useGateway) throws Document documentTest = client1.createDocument(BridgeInternal.getAltLink(collectionSameName), getDocumentDefinition(), null, true).block().getResource(); RequestOptions options = new RequestOptions(); - options.setPartitionKey(new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(documentTest, "mypk"))); + options.setPartitionKey(new PartitionKey(documentTest.get("mypk"))); successValidator = new ResourceResponseValidator.Builder() .withId(documentTest.getId()) .build(); @@ -556,13 +557,13 @@ void validateSessionTokenWithPreConditionFailure(boolean useGateway) throws Exce // write a document, and upsert to it to update etag. ResourceResponse documentResponse = writeClient.createDocument(BridgeInternal.getAltLink(createdCollection), getDocumentDefinition(), null, true).block(); RequestOptions requestOptions = new RequestOptions(); - requestOptions.setPartitionKey(new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(documentResponse.getResource(), "mypk"))); + requestOptions.setPartitionKey(new PartitionKey(documentResponse.getResource().get("mypk"))); ResourceResponse upsertResponse = writeClient.upsertDocument(BridgeInternal.getAltLink(createdCollection), documentResponse.getResource(), requestOptions, true).block(); // create a conditioned read request, with first write request's etag, so the read fails with PreconditionFailure RequestOptions requestOptions1 = new RequestOptions(); - requestOptions.setPartitionKey(new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(documentResponse.getResource(), "mypk"))); + requestOptions.setPartitionKey(new PartitionKey(documentResponse.getResource().get("mypk"))); requestOptions1.setIfMatchETag(documentResponse.getResource().getETag()); Mono> preConditionFailureResponseObservable = validationClient.upsertDocument(BridgeInternal.getAltLink(createdCollection), documentResponse.getResource(), requestOptions1, true); @@ -613,7 +614,7 @@ void validateSessionTokenWithDocumentNotFoundException(boolean useGateway) throw FailureValidator failureValidator = new FailureValidator.Builder().statusCode(HttpConstants.StatusCodes.NOTFOUND).build(); RequestOptions requestOptions = new RequestOptions(); - requestOptions.setPartitionKey(new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(documentResponse.getResource(), "mypk"))); + requestOptions.setPartitionKey(new PartitionKey(documentResponse.getResource().get("mypk"))); // try to read a non existent document in the same partition that we previously wrote to Mono> readObservable = validationClient.readDocument(BridgeInternal.getAltLink(documentResponse.getResource()) + "dummy", requestOptions); validateFailure(readObservable, failureValidator); @@ -651,7 +652,7 @@ void validateSessionTokenWithExpectedException(boolean useGateway) throws Except String higherLsnToken = this.getDifferentLSNToken(token, 2000); FailureValidator failureValidator = new FailureValidator.Builder().subStatusCode(HttpConstants.SubStatusCodes.READ_SESSION_NOT_AVAILABLE).build(); RequestOptions requestOptions = new RequestOptions(); - requestOptions.setPartitionKey(new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(documentResponse.getResource(), "mypk"))); + requestOptions.setPartitionKey(new PartitionKey(documentResponse.getResource().get(("mypk")))); requestOptions.setSessionToken(higherLsnToken); // try to read a non existent document in the same partition that we previously wrote to Mono> readObservable = writeClient.readDocument(BridgeInternal.getAltLink(documentResponse.getResource()), @@ -737,7 +738,7 @@ void validateSessionTokenMultiPartitionCollection(boolean useGateway) throws Exc // Document to lock pause/resume clients Document document1 = new Document(); document1.setId("test" + UUID.randomUUID().toString()); - BridgeInternal.setProperty(document1, "mypk", 1); + document1.set("mypk", 1, CosmosItemSerializer.DEFAULT_SERIALIZER); ResourceResponse childResource1 = writeClient.createDocument(createdCollection.getSelfLink(), document1, null, true).block(); logger.info("Created {} child resource", childResource1.getResource().getResourceId()); assertThat(childResource1.getSessionToken()).isNotNull(); @@ -748,7 +749,7 @@ void validateSessionTokenMultiPartitionCollection(boolean useGateway) throws Exc // Document to lock pause/resume clients Document document2 = new Document(); document2.setId("test" + UUID.randomUUID().toString()); - BridgeInternal.setProperty(document2, "mypk", 2); + document2.set("mypk", 2, CosmosItemSerializer.DEFAULT_SERIALIZER); ResourceResponse childResource2 = writeClient.createDocument(createdCollection.getSelfLink(), document2, null, true).block(); assertThat(childResource2.getSessionToken()).isNotNull(); assertThat(childResource2.getSessionToken().contains(":")).isTrue(); @@ -815,7 +816,7 @@ void validateSessionTokenFromCollectionReplaceIsServerToken(boolean useGateway) try { Document doc = client1.createDocument(createdCollection.getSelfLink(), getDocumentDefinition(), null, true).block().getResource(); RequestOptions requestOptions = new RequestOptions(); - requestOptions.setPartitionKey(new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(doc, "mypk"))); + requestOptions.setPartitionKey(new PartitionKey(doc.get("mypk"))); Document doc1 = client1.readDocument(BridgeInternal.getAltLink(doc), requestOptions).block().getResource(); String token1 = ((SessionContainer) client1.getSession()).getSessionToken(createdCollection.getSelfLink()); diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/FailureValidator.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/FailureValidator.java index 7c442c3d5e86..55283fd53104 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/FailureValidator.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/FailureValidator.java @@ -117,8 +117,8 @@ public Builder error(CosmosError cosmosError) { public void validate(Throwable t) { assertThat(t).isNotNull(); assertThat(t).isInstanceOf(CosmosException.class); - assertThat(ModelBridgeInternal.toJsonFromJsonSerializable(BridgeInternal.getCosmosError((CosmosException) t))) - .isEqualTo(ModelBridgeInternal.toJsonFromJsonSerializable(cosmosError)); + assertThat(BridgeInternal.getCosmosError((CosmosException) t).toJson()) + .isEqualTo(cosmosError.toJson()); } }); return this; diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/FeedResponseListValidator.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/FeedResponseListValidator.java index 65a9b253710f..1b3973a2ca9f 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/FeedResponseListValidator.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/FeedResponseListValidator.java @@ -294,20 +294,20 @@ public void validate(List> feedList) { paths.add(compositeIndexIterator.next().getPath().replace("/", "")); } for (int i = 0; i < resultOrderedList.size(); i ++) { - ArrayNode resultValues = (ArrayNode) ModelBridgeInternal.getObjectFromJsonSerializable(resultOrderedList.get(i), "$1"); + ArrayNode resultValues = (ArrayNode) resultOrderedList.get(i).get("$1"); assertThat(resultValues.size()).isEqualTo(paths.size()); for (int j = 0; j < paths.size(); j++) { if (paths.get(j).contains("number")) { - assertThat(ModelBridgeInternal.getIntFromJsonSerializable(expectedOrderedList.get(i), paths.get(j))) + assertThat(expectedOrderedList.get(i).get(paths.get(j))) .isEqualTo(resultValues.get(j).intValue()); } else if (paths.get(j).toLowerCase().contains("string")) { - assertThat(ModelBridgeInternal.getStringFromJsonSerializable(expectedOrderedList.get(i), paths.get(j))) + assertThat(expectedOrderedList.get(i).getString(paths.get(j))) .isEqualTo(resultValues.get(j).asText()); } else if (paths.get(j).contains("bool")) { - assertThat(ModelBridgeInternal.getBooleanFromJsonSerializable(expectedOrderedList.get(i), paths.get(j))).isEqualTo(resultValues.get(j).asBoolean()); + assertThat(expectedOrderedList.get(i).getBoolean(paths.get(j))).isEqualTo(resultValues.get(j).asBoolean()); } else { assertThat(resultValues.get(j).isNull()).isTrue(); - assertThat(ModelBridgeInternal.getObjectFromJsonSerializable(expectedOrderedList.get(i), "nullField")).isNull(); + assertThat(expectedOrderedList.get(i).getObject("nullField")).isNull(); } } } diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/GoneAndRetryPolicyWithSpyClientTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/GoneAndRetryPolicyWithSpyClientTest.java index 367f29598288..79bcaa41a886 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/GoneAndRetryPolicyWithSpyClientTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/GoneAndRetryPolicyWithSpyClientTest.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation; import com.azure.cosmos.BridgeInternal; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.DirectConnectionConfig; import com.azure.cosmos.ConsistencyLevel; import com.azure.cosmos.implementation.apachecommons.lang.StringUtils; @@ -443,8 +444,8 @@ private String getCollectionLink() { private Document getDocumentDefinition() { Document doc = new Document(); doc.setId(UUID.randomUUID().toString()); - BridgeInternal.setProperty(doc, PARTITION_KEY_FIELD_NAME, UUID.randomUUID().toString()); - BridgeInternal.setProperty(doc, "name", "Hafez"); + doc.set(PARTITION_KEY_FIELD_NAME, UUID.randomUUID().toString(), CosmosItemSerializer.DEFAULT_SERIALIZER); + doc.set("name", "Hafez", CosmosItemSerializer.DEFAULT_SERIALIZER); return doc; } } diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/InternalObjectNodeTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/InternalObjectNodeTest.java index 8046b60e0260..5142523a0bc6 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/InternalObjectNodeTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/InternalObjectNodeTest.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.TestPojo; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -21,7 +22,7 @@ public class InternalObjectNodeTest { public void PojoWithTrackingId() throws IOException { String expectedTrackingId = UUID.randomUUID().toString(); TestPojo pojo = new TestPojo(); - ByteBuffer buffer = InternalObjectNode.serializeJsonToByteBuffer(pojo, MAPPER, expectedTrackingId); + ByteBuffer buffer = InternalObjectNode.serializeJsonToByteBuffer(pojo, CosmosItemSerializer.DEFAULT_SERIALIZER, expectedTrackingId); byte[] blob = new byte[buffer.remaining()]; buffer.get(blob); validateTrackingId(blob, expectedTrackingId); @@ -32,7 +33,7 @@ public void ByteArrayWithTrackingId() throws IOException { String expectedTrackingId = UUID.randomUUID().toString(); ObjectNode objectNode = MAPPER.createObjectNode(); objectNode.put("id", "myId"); - ByteBuffer buffer = InternalObjectNode.serializeJsonToByteBuffer(objectNode, MAPPER, expectedTrackingId); + ByteBuffer buffer = InternalObjectNode.serializeJsonToByteBuffer(objectNode, CosmosItemSerializer.DEFAULT_SERIALIZER, expectedTrackingId); byte[] blob = blob = new byte[buffer.remaining()]; buffer.get(blob); validateTrackingId(blob, expectedTrackingId); @@ -42,8 +43,8 @@ public void ByteArrayWithTrackingId() throws IOException { public void internalObjectNodeWithTrackingId() throws IOException { String expectedTrackingId = UUID.randomUUID().toString(); InternalObjectNode intenalObjectNode = new InternalObjectNode(); - intenalObjectNode.set("id", "myId"); - ByteBuffer buffer = InternalObjectNode.serializeJsonToByteBuffer(intenalObjectNode, MAPPER, expectedTrackingId); + intenalObjectNode.set("id", "myId", CosmosItemSerializer.DEFAULT_SERIALIZER); + ByteBuffer buffer = InternalObjectNode.serializeJsonToByteBuffer(intenalObjectNode, CosmosItemSerializer.DEFAULT_SERIALIZER, expectedTrackingId); byte[] blob = new byte[buffer.remaining()]; buffer.get(blob); validateTrackingId(blob, expectedTrackingId); @@ -54,7 +55,7 @@ public void objectNodeWithTrackingId() throws IOException { String expectedTrackingId = UUID.randomUUID().toString(); ObjectNode objectNode = MAPPER.createObjectNode(); objectNode.put("id", "myId"); - ByteBuffer buffer = InternalObjectNode.serializeJsonToByteBuffer(objectNode, MAPPER, expectedTrackingId); + ByteBuffer buffer = InternalObjectNode.serializeJsonToByteBuffer(objectNode, CosmosItemSerializer.DEFAULT_SERIALIZER, expectedTrackingId); byte[] blob = new byte[buffer.remaining()]; buffer.get(blob); validateTrackingId(blob, expectedTrackingId); diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/RenameCollectionAwareClientRetryPolicyTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/RenameCollectionAwareClientRetryPolicyTest.java index d5576e4cf44e..dc21e6116ef5 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/RenameCollectionAwareClientRetryPolicyTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/RenameCollectionAwareClientRetryPolicyTest.java @@ -97,7 +97,7 @@ public void shouldRetryWithNotFoundStatusCodeAndReadSessionNotAvailableSubStatus Integer.toString(HttpConstants.SubStatusCodes.READ_SESSION_NOT_AVAILABLE)); DocumentCollection documentCollection = new DocumentCollection(); - ModelBridgeInternal.setResourceId(documentCollection, "rid_1"); + documentCollection.setResourceId("rid_1"); Mockito.when(rxClientCollectionCache.resolveCollectionAsync(BridgeInternal.getMetaDataDiagnosticContext(request.requestContext.cosmosDiagnostics), request)).thenReturn(Mono.just(new Utils.ValueHolder<>(documentCollection))); diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/RequestHeadersSpyWireTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/RequestHeadersSpyWireTest.java index 9286deaf7b30..f304657d325a 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/RequestHeadersSpyWireTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/RequestHeadersSpyWireTest.java @@ -2,6 +2,7 @@ // Licensed under the MIT License. package com.azure.cosmos.implementation; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.AsyncDocumentClient.Builder; import com.azure.cosmos.implementation.http.HttpRequest; import com.azure.cosmos.models.CosmosItemRequestOptions; @@ -25,6 +26,8 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; public class RequestHeadersSpyWireTest extends TestSuiteBase { + private static final ImplementationBridgeHelpers.CosmosItemRequestOptionsHelper.CosmosItemRequestOptionsAccessor + itemOptionsAccessor = ImplementationBridgeHelpers.CosmosItemRequestOptionsHelper.getCosmosItemRequestOptionsAccessor(); private static final String DOCUMENT_ID = UUID.randomUUID().toString(); @@ -201,7 +204,9 @@ public void readItemWithMaxIntegratedCacheStaleness(CosmosItemRequestOptions cos client.clearCapturedRequests(); - RequestOptions requestOptions = ModelBridgeInternal.toRequestOptions(cosmosItemRequestOptions); + RequestOptions requestOptions = itemOptionsAccessor.toRequestOptions( + cosmosItemRequestOptions, + CosmosItemSerializer.DEFAULT_SERIALIZER); requestOptions.setPartitionKey(new PartitionKey(DOCUMENT_ID)); client.readDocument(documentLink, requestOptions).block(); @@ -222,7 +227,9 @@ public void readItemWithMaxIntegratedCacheStalenessInNanoseconds() { String documentLink = getDocumentLink(); client.clearCapturedRequests(); - RequestOptions requestOptions = ModelBridgeInternal.toRequestOptions(cosmosItemRequestOptions); + RequestOptions requestOptions = itemOptionsAccessor.toRequestOptions( + cosmosItemRequestOptions, + CosmosItemSerializer.DEFAULT_SERIALIZER); requestOptions.setPartitionKey(new PartitionKey(DOCUMENT_ID)); assertThatThrownBy(() -> client.readDocument(documentLink, requestOptions).block()) @@ -240,7 +247,9 @@ public void readItemWithMaxIntegratedCacheStalenessInNegative() { String documentLink = getDocumentLink(); client.clearCapturedRequests(); - RequestOptions requestOptions = ModelBridgeInternal.toRequestOptions(cosmosItemRequestOptions); + RequestOptions requestOptions = itemOptionsAccessor.toRequestOptions( + cosmosItemRequestOptions, + CosmosItemSerializer.DEFAULT_SERIALIZER); requestOptions.setPartitionKey(new PartitionKey(DOCUMENT_ID)); assertThatThrownBy(() -> client.readDocument(documentLink, requestOptions).block()) @@ -261,7 +270,9 @@ public void readItemWithCacheBypass(boolean cacheBypass) { client.clearCapturedRequests(); - RequestOptions requestOptions = ModelBridgeInternal.toRequestOptions(cosmosItemRequestOptions); + RequestOptions requestOptions = itemOptionsAccessor.toRequestOptions( + cosmosItemRequestOptions, + CosmosItemSerializer.DEFAULT_SERIALIZER); requestOptions.setPartitionKey(new PartitionKey(DOCUMENT_ID)); ResourceResponse response = client.readDocument(documentLink, requestOptions).block(); if (cacheBypass) { diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/ResourceResponseValidator.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/ResourceResponseValidator.java index fe61c709f90e..55f3e6b51527 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/ResourceResponseValidator.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/ResourceResponseValidator.java @@ -75,7 +75,7 @@ public Builder withProperty(String propertyName, Condition validating @Override public void validate(ResourceResponse resourceResponse) { assertThat(resourceResponse.getResource()).isNotNull(); - assertThat(ModelBridgeInternal.getObjectFromJsonSerializable(resourceResponse.getResource(), propertyName)).is(validatingCondition); + assertThat(resourceResponse.getResource().get(propertyName)).is(validatingCondition); } }); return this; @@ -87,7 +87,7 @@ public Builder withProperty(String propertyName, Object value) { @Override public void validate(ResourceResponse resourceResponse) { assertThat(resourceResponse.getResource()).isNotNull(); - assertThat(ModelBridgeInternal.getObjectFromJsonSerializable(resourceResponse.getResource(), propertyName)).isEqualTo(value); + assertThat(resourceResponse.getResource().get(propertyName)).isEqualTo(value); } }); return this; @@ -245,7 +245,7 @@ public Builder validatePropertyCondition(String key, Condition condit @Override public void validate(ResourceResponse resourceResponse) { assertThat(resourceResponse.getResource()).isNotNull(); - assertThat(ModelBridgeInternal.getObjectFromJsonSerializable(resourceResponse.getResource(), key)).is(condition); + assertThat(resourceResponse.getResource().get(key)).is(condition); } }); diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/ResourceValidator.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/ResourceValidator.java index c307f4c23564..bc4c298e84f3 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/ResourceValidator.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/ResourceValidator.java @@ -34,14 +34,14 @@ public Builder areEqual(T expectedValue) { @Override public void validate(T v) { - assertThat(ModelBridgeInternal.getMapFromJsonSerializable(v).keySet()) + assertThat(v.getMap().keySet()) .describedAs("number of fields") - .hasSize(ModelBridgeInternal.getMapFromJsonSerializable(expectedValue).keySet().size()); - ModelBridgeInternal.getMapFromJsonSerializable(expectedValue).keySet(); - for(String key: ModelBridgeInternal.getMapFromJsonSerializable(expectedValue).keySet()) { - assertThat(ModelBridgeInternal.getObjectFromJsonSerializable(expectedValue, key)) + .hasSize(expectedValue.getMap().keySet().size()); + expectedValue.getMap().keySet(); + for(String key: expectedValue.getMap().keySet()) { + assertThat(expectedValue.get(key)) .describedAs("value for " + key) - .isEqualTo(ModelBridgeInternal.getObjectFromJsonSerializable(expectedValue, key)); + .isEqualTo(expectedValue.get(key)); } } }); diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/RxDocumentClientImplTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/RxDocumentClientImplTest.java index 9b9f7995b904..a494dcb8059a 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/RxDocumentClientImplTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/RxDocumentClientImplTest.java @@ -9,6 +9,7 @@ import com.azure.cosmos.CosmosContainerProactiveInitConfig; import com.azure.cosmos.CosmosDiagnostics; import com.azure.cosmos.CosmosEndToEndOperationLatencyPolicyConfig; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.SessionRetryOptions; import com.azure.cosmos.implementation.apachecommons.lang.tuple.ImmutablePair; import com.azure.cosmos.implementation.caches.RxClientCollectionCache; @@ -83,6 +84,7 @@ public class RxDocumentClientImplTest { private CosmosEndToEndOperationLatencyPolicyConfig endToEndOperationLatencyPolicyConfig; private SessionRetryOptions sessionRetryOptionsMock; private CosmosContainerProactiveInitConfig containerProactiveInitConfigMock; + private CosmosItemSerializer defaultItemSerializer; @BeforeClass(groups = "unit") public void setUp() { @@ -105,6 +107,7 @@ public void setUp() { this.endToEndOperationLatencyPolicyConfig = Mockito.mock(CosmosEndToEndOperationLatencyPolicyConfig.class); this.sessionRetryOptionsMock = Mockito.mock(SessionRetryOptions.class); this.containerProactiveInitConfigMock = Mockito.mock(CosmosContainerProactiveInitConfig.class); + this.defaultItemSerializer = Mockito.mock(CosmosItemSerializer.class); } @Test(groups = {"unit"}) @@ -226,7 +229,8 @@ public void readMany() { this.clientCorrelationIdMock, this.endToEndOperationLatencyPolicyConfig, this.sessionRetryOptionsMock, - this.containerProactiveInitConfigMock); + this.containerProactiveInitConfigMock, + this.defaultItemSerializer); try { ReflectionUtils.setCollectionCache(rxDocumentClient, this.collectionCacheMock); @@ -385,7 +389,7 @@ private static IDocumentQueryExecutionContext dummyExecutionContextForQue results .stream() .map(str -> new Document(str)) - .map(document -> ModelBridgeInternal.toObjectFromJsonSerializable(document, klass)) + .map(document -> document.toObject(klass)) .collect(Collectors.toList()); return () -> Flux.just(ModelBridgeInternal.createFeedResponse(documentResults, headers)); diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/RxDocumentClientUnderTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/RxDocumentClientUnderTest.java index a57d71754e9f..b2e8d2b720e6 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/RxDocumentClientUnderTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/RxDocumentClientUnderTest.java @@ -58,6 +58,7 @@ public RxDocumentClientUnderTest(URI serviceEndpoint, null, null, null, + null, null); init(null, null); } diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/SessionTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/SessionTest.java index 8663514dde43..b95958874add 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/SessionTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/SessionTest.java @@ -2,9 +2,9 @@ // Licensed under the MIT License. package com.azure.cosmos.implementation; -import com.azure.cosmos.BridgeInternal; import com.azure.cosmos.ConnectionMode; import com.azure.cosmos.ConsistencyLevel; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.batch.ItemBatchOperation; import com.azure.cosmos.implementation.batch.SinglePartitionKeyServerBatchRequest; import com.azure.cosmos.implementation.directconnectivity.ReflectionUtils; @@ -154,7 +154,7 @@ public void partitionedSessionToken(boolean isNameBased) throws NoSuchMethodExce RequestOptions requestOptions = new RequestOptions(); for (int i = 0; i < 10; i++) { Document document = newDocument(); - document.set("mypk", document.getId()); + document.set("mypk", document.getId(), CosmosItemSerializer.DEFAULT_SERIALIZER); requestOptions.setPartitionKey(new PartitionKey(document.getId())); documentCreated = spyClient.createDocument(getCollectionLink(isNameBased), document, requestOptions, false) .block().getResource(); @@ -285,7 +285,7 @@ public void partitionedSessionToken(boolean isNameBased) throws NoSuchMethodExce if(isNameBased) { // Batch only work with name based url spyClient.clearCapturedRequests(); Document document = newDocument(); - document.set("mypk", document.getId()); + document.set("mypk", document.getId(), CosmosItemSerializer.DEFAULT_SERIALIZER); ItemBatchOperation itemBatchOperation = new ItemBatchOperation(CosmosItemOperationType.CREATE, documentCreated.getId(), new PartitionKey(documentCreated.getId()), new RequestOptions(), document); List> itemBatchOperations = new ArrayList<>(); @@ -318,7 +318,7 @@ public void sessionTokenNotRequired(boolean isNameBased) { RequestOptions requestOptions = new RequestOptions(); for (int i = 0; i < 10; i++) { Document document = newDocument(); - document.set("mypk", document.getId()); + document.set("mypk", document.getId(), CosmosItemSerializer.DEFAULT_SERIALIZER); requestOptions.setPartitionKey(new PartitionKey(document.getId())); documentCreated = spyClient.createDocument(getCollectionLink(isNameBased), document, requestOptions, false) .block().getResource(); @@ -373,7 +373,7 @@ public void sessionTokenForCreateOnMultiMaster(boolean isNameBased) { RequestOptions requestOptions = new RequestOptions(); for (int i = 0; i < 10; i++) { Document document = newDocument(); - document.set("mypk", document.getId()); + document.set("mypk", document.getId(), CosmosItemSerializer.DEFAULT_SERIALIZER); requestOptions.setPartitionKey(new PartitionKey(document.getId())); spyClient.createDocument(getCollectionLink(isNameBased), document, requestOptions, false) .block().getResource(); @@ -388,7 +388,7 @@ public void sessionTokenForCreateOnMultiMaster(boolean isNameBased) { public void sessionTokenInDocumentRead(boolean isNameBased) throws UnsupportedEncodingException { Document document = new Document(); document.setId(UUID.randomUUID().toString()); - BridgeInternal.setProperty(document, "pk", "pk"); + document.set("pk", "pk", CosmosItemSerializer.DEFAULT_SERIALIZER); document = spyClient.createDocument(getCollectionLink(isNameBased), document, null, false) .block() .getResource(); diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/SpyClientUnderTestFactory.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/SpyClientUnderTestFactory.java index cad0e7e7b177..a68259e09bf5 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/SpyClientUnderTestFactory.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/SpyClientUnderTestFactory.java @@ -5,7 +5,6 @@ import com.azure.core.credential.AzureKeyCredential; import com.azure.cosmos.ConnectionMode; import com.azure.cosmos.ConsistencyLevel; -import com.azure.cosmos.implementation.clienttelemetry.TagName; import com.azure.cosmos.implementation.directconnectivity.Protocol; import com.azure.cosmos.implementation.directconnectivity.ReflectionUtils; import com.azure.cosmos.implementation.http.HttpClient; @@ -24,7 +23,6 @@ import java.time.Duration; import java.util.ArrayList; import java.util.Collections; -import java.util.EnumSet; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Future; @@ -64,6 +62,7 @@ public SpyBaseClass( null, null, null, + null, null); } diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/TestSuiteBase.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/TestSuiteBase.java index 43876eda4d79..66a6c021a3ac 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/TestSuiteBase.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/TestSuiteBase.java @@ -208,7 +208,7 @@ protected static void truncateCollection(DocumentCollection collection) { if (paths != null && !paths.isEmpty()) { List pkPath = PathParser.getPathParts(paths.get(0)); - Object propertyValue = ModelBridgeInternal.getObjectByPathFromJsonSerializable(doc, pkPath); + Object propertyValue = doc.getObjectByPath(pkPath); if (propertyValue == null) { propertyValue = Undefined.value(); } diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/UtilsTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/UtilsTest.java index a7437ffddd9e..925a59186ff1 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/UtilsTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/UtilsTest.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.apachecommons.lang.RandomStringUtils; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -23,14 +24,14 @@ public class UtilsTest { @Test(groups = {"unit"}) public void parsingByteArrayAsObjectNode() { byte[] source = "{ 'a' : 'b' }".getBytes(StandardCharsets.UTF_8); - ObjectNode objectNode = Utils.parse(source, ObjectNode.class); + ObjectNode objectNode = Utils.parse(source, ObjectNode.class, CosmosItemSerializer.DEFAULT_SERIALIZER); assertThat(objectNode.get("a").asText()).isEqualTo("b"); } @Test(groups = {"unit"}) public void parsingByteArrayAsJsonNode() { byte[] source = "5".getBytes(StandardCharsets.UTF_8); - JsonNode jsonNode = Utils.parse(source, JsonNode.class); + JsonNode jsonNode = Utils.parse(source, JsonNode.class, CosmosItemSerializer.DEFAULT_SERIALIZER); assertThat(jsonNode.asInt()).isEqualTo(5); } @@ -41,7 +42,7 @@ public void errorMessageOnParsingByteArrayContainsOriginalContent() { System.arraycopy(source, 0, data, 0, data.length); try { - Utils.parse(data, ObjectNode.class); + Utils.parse(data, ObjectNode.class, CosmosItemSerializer.DEFAULT_SERIALIZER); fail("expected to fail"); } catch (Exception e) { assertThat(e.getMessage()).isEqualTo("Failed to parse byte-array " + new String(data, StandardCharsets.UTF_8) + " to POJO."); diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/batch/BatchResponsePayloadWriter.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/batch/BatchResponsePayloadWriter.java index a3d0c91bd633..03d5342edb59 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/batch/BatchResponsePayloadWriter.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/batch/BatchResponsePayloadWriter.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation.batch; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.JsonSerializable; import com.azure.cosmos.implementation.Utils; import com.azure.cosmos.models.CosmosBatchOperationResult; @@ -36,13 +37,13 @@ private ArrayNode writeOperationResult() { private JsonSerializable writeResult(CosmosBatchOperationResult result) { JsonSerializable jsonSerializable = new JsonSerializable(); - jsonSerializable.set(BatchRequestResponseConstants.FIELD_STATUS_CODE, result.getStatusCode()); - jsonSerializable.set(BatchRequestResponseConstants.FIELD_SUBSTATUS_CODE, result.getSubStatusCode()); - jsonSerializable.set(BatchRequestResponseConstants.FIELD_ETAG, result.getETag()); - jsonSerializable.set(BatchRequestResponseConstants.FIELD_REQUEST_CHARGE, result.getRequestCharge()); + jsonSerializable.set(BatchRequestResponseConstants.FIELD_STATUS_CODE, result.getStatusCode(), CosmosItemSerializer.DEFAULT_SERIALIZER); + jsonSerializable.set(BatchRequestResponseConstants.FIELD_SUBSTATUS_CODE, result.getSubStatusCode(), CosmosItemSerializer.DEFAULT_SERIALIZER); + jsonSerializable.set(BatchRequestResponseConstants.FIELD_ETAG, result.getETag(), CosmosItemSerializer.DEFAULT_SERIALIZER); + jsonSerializable.set(BatchRequestResponseConstants.FIELD_REQUEST_CHARGE, result.getRequestCharge(), CosmosItemSerializer.DEFAULT_SERIALIZER); if(result.getRetryAfterDuration() != null) { - jsonSerializable.set(BatchRequestResponseConstants.FIELD_RETRY_AFTER_MILLISECONDS, result.getRetryAfterDuration().toMillis()); + jsonSerializable.set(BatchRequestResponseConstants.FIELD_RETRY_AFTER_MILLISECONDS, result.getRetryAfterDuration().toMillis(), CosmosItemSerializer.DEFAULT_SERIALIZER); } return jsonSerializable; diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/batch/CosmosBulkItemResponseTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/batch/CosmosBulkItemResponseTest.java index fc5c5c74ecaf..2047eaac5cb0 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/batch/CosmosBulkItemResponseTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/batch/CosmosBulkItemResponseTest.java @@ -51,7 +51,8 @@ public void validateAllSetValuesInCosmosBulkItemResponse() { PartitionKey.NONE.toString(), Arrays.asList(arrayOperations), BatchRequestResponseConstants.DEFAULT_MAX_DIRECT_MODE_BATCH_REQUEST_BODY_SIZE_IN_BYTES, - BatchRequestResponseConstants.MAX_OPERATIONS_IN_DIRECT_MODE_BATCH_REQUEST); + BatchRequestResponseConstants.MAX_OPERATIONS_IN_DIRECT_MODE_BATCH_REQUEST, + null); // Create dummy result CosmosBatchOperationResult transactionalBatchOperationResult = ModelBridgeInternal.createCosmosBatchResult( @@ -140,7 +141,8 @@ public void validateEmptyHeaderInCosmosBulkItemResponse() { PartitionKey.NONE.toString(), Arrays.asList(arrayOperations), BatchRequestResponseConstants.DEFAULT_MAX_DIRECT_MODE_BATCH_REQUEST_BODY_SIZE_IN_BYTES, - BatchRequestResponseConstants.MAX_OPERATIONS_IN_DIRECT_MODE_BATCH_REQUEST); + BatchRequestResponseConstants.MAX_OPERATIONS_IN_DIRECT_MODE_BATCH_REQUEST, + null); // Create dummy result diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/batch/PartitionKeyRangeServerBatchRequestTests.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/batch/PartitionKeyRangeServerBatchRequestTests.java index b8ada12f1793..4faf0f6b9fd5 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/batch/PartitionKeyRangeServerBatchRequestTests.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/batch/PartitionKeyRangeServerBatchRequestTests.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation.batch; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.JsonSerializable; import com.azure.cosmos.implementation.apachecommons.lang.StringUtils; import com.azure.cosmos.models.CosmosItemOperation; @@ -43,7 +44,8 @@ public void fitsAllOperations() { "0", operations, 200000, - 2); + 2, + null); assertThat(serverOperationBatchRequest.getBatchRequest().getOperations().size()).isEqualTo(operations.size()); assertThat(serverOperationBatchRequest.getBatchRequest().getOperations()).isEqualTo(operations); @@ -63,7 +65,8 @@ public void overflowsBasedOnCount() { "0", operations, 200000, - 0); + 0, + null); assertThat(serverOperationBatchRequest.getBatchRequest().getOperations().size()).isEqualTo(1); assertThat(serverOperationBatchRequest.getBatchRequest().getOperations().get(0).getId()).isEqualTo(operations.get(0).getId()); @@ -86,7 +89,8 @@ public void overflowsBasedOnCountWithOffset() { "0", operations.subList(1, 3), 200000, - 1); + 1, + null); assertThat(serverOperationBatchRequest.getBatchRequest().getOperations().size()).isEqualTo(1); @@ -151,7 +155,7 @@ private static ServerOperationBatchRequest getBatchWithCreateOperationsAsync( for (int i = 0; i < operationCount; i++) { JsonSerializable jsonSerializable = new JsonSerializable(); - jsonSerializable.set("abc", StringUtils.repeat("x", docSizeInBytes - 10));// {"abc":" + "} = 10 + jsonSerializable.set("abc", StringUtils.repeat("x", docSizeInBytes - 10), CosmosItemSerializer.DEFAULT_SERIALIZER);// {"abc":" + "} = 10 ItemBulkOperation operation = new ItemBulkOperation<>( CosmosItemOperationType.CREATE, @@ -169,6 +173,7 @@ private static ServerOperationBatchRequest getBatchWithCreateOperationsAsync( "0", operations, maxServerRequestBodyLength, - maxServerRequestOperationCount); + maxServerRequestOperationCount, + null); } } diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/batch/TransactionalBatchResponseTests.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/batch/TransactionalBatchResponseTests.java index e244fadb6c9d..37dd12cb99ca 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/batch/TransactionalBatchResponseTests.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/batch/TransactionalBatchResponseTests.java @@ -47,7 +47,8 @@ public void validateAllSetValuesInResponse() { arrayOperations[0] = operation; SinglePartitionKeyServerBatchRequest batchRequest = SinglePartitionKeyServerBatchRequest.createBatchRequest( PartitionKey.NONE, - Arrays.asList(arrayOperations)); + Arrays.asList(arrayOperations), + null); // Create dummy result CosmosBatchOperationResult transactionalBatchOperationResult = ModelBridgeInternal.createCosmosBatchResult( @@ -118,7 +119,8 @@ public void validateEmptyHeaderInResponse() { arrayOperations[0] = operation; SinglePartitionKeyServerBatchRequest batchRequest = SinglePartitionKeyServerBatchRequest.createBatchRequest( PartitionKey.NONE, - Arrays.asList(arrayOperations)); + Arrays.asList(arrayOperations), + null); // Create dummy result CosmosBatchOperationResult transactionalBatchOperationResult = ModelBridgeInternal.createCosmosBatchResult( diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/directconnectivity/AddressResolverTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/directconnectivity/AddressResolverTest.java index ad8ae1693e52..046c88a73a52 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/directconnectivity/AddressResolverTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/directconnectivity/AddressResolverTest.java @@ -80,14 +80,14 @@ public void before_AddressResolverTest() throws Exception { this.collection1 = new DocumentCollection(); this.collection1.setId("coll"); - ModelBridgeInternal.setResourceId(this.collection1, "rid1"); + this.collection1.setResourceId("rid1"); PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); partitionKeyDef.setPaths(ImmutableList.of("/field1")); this.collection1.setPartitionKey(partitionKeyDef); this.collection2 = new DocumentCollection(); this.collection2.setId("coll"); - ModelBridgeInternal.setResourceId(this.collection2, "rid2"); + this.collection2.setResourceId("rid2"); new PartitionKeyDefinition(); partitionKeyDef.setPaths(ImmutableList.of("/field1")); this.collection2.setPartitionKey(partitionKeyDef); diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/directconnectivity/BarrierRequestHelperTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/directconnectivity/BarrierRequestHelperTest.java index b6ff757fbfcd..c05f2fe77973 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/directconnectivity/BarrierRequestHelperTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/directconnectivity/BarrierRequestHelperTest.java @@ -8,7 +8,6 @@ import com.azure.core.credential.TokenRequestContext; import com.azure.cosmos.implementation.AsyncDocumentClient; import com.azure.cosmos.implementation.AuthorizationTokenType; -import com.azure.cosmos.implementation.ImplementationBridgeHelpers; import com.azure.cosmos.implementation.clienttelemetry.ClientTelemetry; import com.azure.cosmos.models.CosmosClientTelemetryConfig; import com.azure.cosmos.implementation.Configs; @@ -21,7 +20,6 @@ import com.azure.cosmos.implementation.RxDocumentServiceRequest; import com.azure.cosmos.implementation.TestConfigurations; import com.azure.cosmos.implementation.Utils; -import com.azure.cosmos.implementation.clienttelemetry.TagName; import com.azure.cosmos.implementation.routing.PartitionKeyRangeIdentity; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -29,10 +27,8 @@ import java.net.URI; import java.net.URISyntaxException; -import java.time.Duration; import java.time.OffsetDateTime; import java.time.ZonedDateTime; -import java.util.EnumSet; import java.util.Map; import java.util.UUID; @@ -183,6 +179,7 @@ public void barrierWithAadAuthorizationTokenProviderType() throws URISyntaxExcep null, null, null, + null, null); ResourceType resourceType = ResourceType.DocumentCollection; diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/directconnectivity/DCDocumentCrudTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/directconnectivity/DCDocumentCrudTest.java index aab22fd0c56b..d3383227620e 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/directconnectivity/DCDocumentCrudTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/directconnectivity/DCDocumentCrudTest.java @@ -4,6 +4,7 @@ import com.azure.cosmos.BridgeInternal; import com.azure.cosmos.ConsistencyLevel; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.DirectConnectionConfig; import com.azure.cosmos.implementation.AsyncDocumentClient.Builder; import com.azure.cosmos.implementation.ImplementationBridgeHelpers; @@ -197,7 +198,7 @@ public void upsert() throws Exception { String propName = "newProp"; String propValue = "hello"; - BridgeInternal.setProperty(document, propName, propValue); + document.set(propName, propValue, CosmosItemSerializer.DEFAULT_SERIALIZER); ResourceResponseValidator validator = ResourceResponseValidator.builder() .withProperty(propName, propValue) @@ -328,8 +329,8 @@ private String getCollectionLink() { private Document getDocumentDefinition() { Document doc = new Document(); doc.setId(UUID.randomUUID().toString()); - BridgeInternal.setProperty(doc, PARTITION_KEY_FIELD_NAME, UUID.randomUUID().toString()); - BridgeInternal.setProperty(doc, "name", "Hafez"); + doc.set(PARTITION_KEY_FIELD_NAME, UUID.randomUUID().toString(), CosmosItemSerializer.DEFAULT_SERIALIZER); + doc.set("name", "Hafez", CosmosItemSerializer.DEFAULT_SERIALIZER); return doc; } diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/directconnectivity/GlobalAddressResolverTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/directconnectivity/GlobalAddressResolverTest.java index ca2f80545f7f..e890168543cc 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/directconnectivity/GlobalAddressResolverTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/directconnectivity/GlobalAddressResolverTest.java @@ -162,7 +162,7 @@ public void submitOpenConnectionTasksAndInitCaches() { DocumentCollection documentCollection = new DocumentCollection(); documentCollection.setId("TestColl"); - ModelBridgeInternal.setResourceId(documentCollection, "IXYFAOHEBPM="); + documentCollection.setResourceId("IXYFAOHEBPM="); documentCollection.setSelfLink("dbs/testDb/colls/TestColl"); PartitionKeyRange range = new PartitionKeyRange( diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/query/DocumentProducerTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/query/DocumentProducerTest.java index bee53a8ad198..7edd63274342 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/query/DocumentProducerTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/query/DocumentProducerTest.java @@ -4,6 +4,7 @@ import com.azure.cosmos.BridgeInternal; import com.azure.cosmos.CosmosException; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.ConnectionPolicy; import com.azure.cosmos.implementation.CosmosError; import com.azure.cosmos.implementation.DiagnosticsClientContext; @@ -789,12 +790,12 @@ private List> mockFeedResponsesPartiallySorted(FeedRangeE Document d = getDocumentDefinition(); if (isOrderby) { - BridgeInternal.setProperty(d, OrderByIntFieldName, orderByFieldInitialVal + RandomUtils.nextInt(0, 3)); - BridgeInternal.setProperty(d, DocumentPartitionKeyRangeIdFieldName, feedRangeEpk.getRange().toString()); + d.set(OrderByIntFieldName, orderByFieldInitialVal + RandomUtils.nextInt(0, 3), CosmosItemSerializer.DEFAULT_SERIALIZER); + d.set(DocumentPartitionKeyRangeIdFieldName, feedRangeEpk.getRange().toString(), CosmosItemSerializer.DEFAULT_SERIALIZER); PartitionKeyRange pkr = mockPartitionKeyRange(feedRangeEpk.getRange().toString(), feedRangeEpk.getRange()); - BridgeInternal.setProperty(d, DocumentPartitionKeyRangeMinInclusiveFieldName, pkr.getMinInclusive()); - BridgeInternal.setProperty(d, DocumentPartitionKeyRangeMaxExclusiveFieldName, pkr.getMaxExclusive()); + d.set(DocumentPartitionKeyRangeMinInclusiveFieldName, pkr.getMinInclusive(), CosmosItemSerializer.DEFAULT_SERIALIZER); + d.set(DocumentPartitionKeyRangeMaxExclusiveFieldName, pkr.getMaxExclusive(), CosmosItemSerializer.DEFAULT_SERIALIZER); QueryItem qi = new QueryItem("{ \"item\": " + d.getInt(OrderByIntFieldName) + " }"); diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/query/FeedResponseBuilder.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/query/FeedResponseBuilder.java index d3a4ebb6c970..76836999e626 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/query/FeedResponseBuilder.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/query/FeedResponseBuilder.java @@ -4,6 +4,7 @@ package com.azure.cosmos.implementation.query; import com.azure.cosmos.BridgeInternal; +import com.azure.cosmos.implementation.ImplementationBridgeHelpers; import com.azure.cosmos.models.FeedResponse; import com.azure.cosmos.implementation.Resource; import com.azure.cosmos.implementation.HttpConstants; @@ -66,9 +67,15 @@ public FeedResponse build() { if (isChangeFeed) { when(rsp.getStatusCode()).thenReturn(noMoreChangesInChangeFeed? HttpConstants.StatusCodes.NOT_MODIFIED : 200); - return BridgeInternal.toChangeFeedResponsePage(rsp, null, klass); + return ImplementationBridgeHelpers + .FeedResponseHelper + .getFeedResponseAccessor() + .createChangeFeedResponse(rsp, null, klass); } else { - return BridgeInternal.toFeedResponsePage(rsp, null, klass); + return ImplementationBridgeHelpers + .FeedResponseHelper + .getFeedResponseAccessor() + .createFeedResponse(rsp, null, klass); } } diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/throughputControl/ThroughputControlTests.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/throughputControl/ThroughputControlTests.java index 869cb1e8c690..be0d563e54fc 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/throughputControl/ThroughputControlTests.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/implementation/throughputControl/ThroughputControlTests.java @@ -686,7 +686,7 @@ private void ensureContainer() { container.read().block(); } catch (CosmosException error) { if (error.getStatusCode() == 404) { - TestSuiteBase.beforeSuite(); + this.beforeSuite(); } throw error; diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/models/JsonSerializableTests.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/models/JsonSerializableTests.java index ba58c029cd4f..26a30cf1001b 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/models/JsonSerializableTests.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/models/JsonSerializableTests.java @@ -3,6 +3,7 @@ package com.azure.cosmos.models; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.Document; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; @@ -11,7 +12,6 @@ import java.io.Serializable; -import static com.azure.cosmos.BridgeInternal.setProperty; import static org.assertj.core.api.Assertions.assertThat; import static org.testng.Assert.fail; @@ -58,29 +58,29 @@ public enum enums { public void getObjectAndCastToClass() { Document document = new Document(); // numeric values - setProperty(document, "intValue", Integer.MAX_VALUE); - setProperty(document, "doubleValue", Double.MAX_VALUE); - setProperty(document, "longValue", Long.MAX_VALUE); + document.set("intValue", Integer.MAX_VALUE, CosmosItemSerializer.DEFAULT_SERIALIZER); + document.set("doubleValue", Double.MAX_VALUE, CosmosItemSerializer.DEFAULT_SERIALIZER); + document.set("longValue", Long.MAX_VALUE, CosmosItemSerializer.DEFAULT_SERIALIZER); assertThat(document.getObject("intValue", Integer.class).intValue()).isEqualTo(Integer.MAX_VALUE); assertThat(document.getObject("doubleValue", Double.class).doubleValue()).isEqualTo(Double.MAX_VALUE); assertThat(document.getObject("longValue", Long.class).longValue()).isEqualTo(Long.MAX_VALUE); // string - setProperty(document, "stringValue", "stringField"); + document.set("stringValue", "stringField", CosmosItemSerializer.DEFAULT_SERIALIZER); assertThat(document.getObject("stringValue", String.class)).isEqualTo("stringField"); // boolean - setProperty(document, "boolValue", true); + document.set("boolValue", true, CosmosItemSerializer.DEFAULT_SERIALIZER); assertThat(document.getObject("boolValue", Boolean.class)).isEqualTo(true); // enum - setProperty(document, "enumValue", "third"); + document.set("enumValue", "third", CosmosItemSerializer.DEFAULT_SERIALIZER); assertThat(document.getObject("enumValue", enums.class)).isEqualTo(enums.third); // Pojo Pojo pojo = new Pojo(1, 2); - setProperty(document, "pojoValue", pojo); + document.set( "pojoValue", pojo, CosmosItemSerializer.DEFAULT_SERIALIZER); Pojo readPojo = document.getObject("pojoValue", Pojo.class); assertThat(readPojo.getA()).isEqualTo(pojo.getA()); assertThat(readPojo.getB()).isEqualTo(pojo.getB()); @@ -88,7 +88,7 @@ public void getObjectAndCastToClass() { // JsonSerializable Document innerDocument = new Document(); innerDocument.setId("innerDocument"); - setProperty(document, "innerDocument", innerDocument); + document.set("innerDocument", innerDocument, CosmosItemSerializer.DEFAULT_SERIALIZER); Document readInnerDocument = document.getObject("innerDocument", Document.class); assertThat(readInnerDocument.getId()).isEqualTo(innerDocument.getId()); } diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/AggregateQueryTests.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/AggregateQueryTests.java index a182dbacab4a..37b2a138a432 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/AggregateQueryTests.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/AggregateQueryTests.java @@ -2,11 +2,11 @@ // Licensed under the MIT License. package com.azure.cosmos.rx; -import com.azure.cosmos.BridgeInternal; import com.azure.cosmos.CosmosAsyncClient; import com.azure.cosmos.CosmosAsyncContainer; import com.azure.cosmos.CosmosClientBuilder; import com.azure.cosmos.CosmosException; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.Document; import com.azure.cosmos.implementation.FeedResponseListValidator; import com.azure.cosmos.implementation.InternalObjectNode; @@ -125,15 +125,15 @@ public void generateTestData() { for (int i = 0; i < values.length; i++) { InternalObjectNode d = new InternalObjectNode(); d.setId(UUID.randomUUID().toString()); - BridgeInternal.setProperty(d, partitionKey, values[i]); + d.set(partitionKey, values[i], CosmosItemSerializer.DEFAULT_SERIALIZER); docs.add(d); } for (int i = 0; i < numberOfDocsWithSamePartitionKey; i++) { InternalObjectNode d = new InternalObjectNode(); - BridgeInternal.setProperty(d, partitionKey, uniquePartitionKey); - BridgeInternal.setProperty(d, "getResourceId", Integer.toString(i)); - BridgeInternal.setProperty(d, field, i + 1); + d.set(partitionKey, uniquePartitionKey, CosmosItemSerializer.DEFAULT_SERIALIZER); + d.set("getResourceId", Integer.toString(i), CosmosItemSerializer.DEFAULT_SERIALIZER); + d.set(field, i + 1, CosmosItemSerializer.DEFAULT_SERIALIZER); d.setId(UUID.randomUUID().toString()); docs.add(d); } @@ -141,7 +141,7 @@ public void generateTestData() { numberOfDocumentsWithNumericId = numberOfDocuments - values.length - numberOfDocsWithSamePartitionKey; for (int i = 0; i < numberOfDocumentsWithNumericId; i++) { InternalObjectNode d = new InternalObjectNode(); - BridgeInternal.setProperty(d, partitionKey, i + 1); + d.set(partitionKey, i + 1, CosmosItemSerializer.DEFAULT_SERIALIZER); d.setId(UUID.randomUUID().toString()); docs.add(d); } diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/ChangeFeedTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/ChangeFeedTest.java index 83c1f975c5ea..0c5792402d8a 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/ChangeFeedTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/ChangeFeedTest.java @@ -3,6 +3,7 @@ package com.azure.cosmos.rx; import com.azure.cosmos.BridgeInternal; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.AsyncDocumentClient; import com.azure.cosmos.implementation.Database; import com.azure.cosmos.implementation.Document; @@ -451,7 +452,7 @@ public void createDocument(AsyncDocumentClient client, String partitionKey) { public Document updateDocument(AsyncDocumentClient client, Document originalDocument) { String uuid = UUID.randomUUID().toString(); - BridgeInternal.setProperty(originalDocument, "prop", uuid); + originalDocument.set("prop", uuid, CosmosItemSerializer.DEFAULT_SERIALIZER); return client .replaceDocument(originalDocument.getSelfLink(), originalDocument, null) @@ -539,8 +540,8 @@ private static Document getDocumentDefinition(String partitionKey) { String uuid = UUID.randomUUID().toString(); Document doc = new Document(); doc.setId(uuid); - BridgeInternal.setProperty(doc, "mypk", partitionKey); - BridgeInternal.setProperty(doc, "prop", uuid); + doc.set("mypk", partitionKey, CosmosItemSerializer.DEFAULT_SERIALIZER); + doc.set("prop", uuid, CosmosItemSerializer.DEFAULT_SERIALIZER); return doc; } diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/CollectionCrudTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/CollectionCrudTest.java index de0aeb006891..6efee2ef96fa 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/CollectionCrudTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/CollectionCrudTest.java @@ -3,6 +3,7 @@ package com.azure.cosmos.rx; import com.azure.cosmos.BridgeInternal; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.HttpConstants; import com.azure.cosmos.models.CompositePath; import com.azure.cosmos.models.CompositePathSortOrder; @@ -313,8 +314,8 @@ public void sessionTokenConsistencyCollectionDeleteCreateSameName() { InternalObjectNode document = new InternalObjectNode(); document.setId("doc"); - BridgeInternal.setProperty(document, "name", "New Document"); - BridgeInternal.setProperty(document, "mypk", "mypkValue"); + document.set("name", "New Document", CosmosItemSerializer.DEFAULT_SERIALIZER); + document.set("mypk", "mypkValue", CosmosItemSerializer.DEFAULT_SERIALIZER); createDocument(collection, document); CosmosItemRequestOptions options = new CosmosItemRequestOptions(); CosmosItemResponse readDocumentResponse = @@ -322,7 +323,7 @@ public void sessionTokenConsistencyCollectionDeleteCreateSameName() { logger.info("Client 1 READ Document Client Side Request Statistics {}", readDocumentResponse.getDiagnostics()); logger.info("Client 1 READ Document Latency {}", readDocumentResponse.getDuration()); - BridgeInternal.setProperty(document, "name", "New Updated Document"); + document.set("name", "New Updated Document", CosmosItemSerializer.DEFAULT_SERIALIZER); CosmosItemResponse upsertDocumentResponse = collection.upsertItem(document).block(); logger.info("Client 1 Upsert Document Client Side Request Statistics {}", upsertDocumentResponse.getDiagnostics()); logger.info("Client 1 Upsert Document Latency {}", upsertDocumentResponse.getDuration()); @@ -334,14 +335,14 @@ public void sessionTokenConsistencyCollectionDeleteCreateSameName() { InternalObjectNode newDocument = new InternalObjectNode(); newDocument.setId("doc"); - BridgeInternal.setProperty(newDocument, "name", "New Created Document"); - BridgeInternal.setProperty(newDocument, "mypk", "mypk"); + newDocument.set("name", "New Created Document", CosmosItemSerializer.DEFAULT_SERIALIZER); + newDocument.set("mypk", "mypk", CosmosItemSerializer.DEFAULT_SERIALIZER); createDocument(collection2, newDocument); readDocumentResponse = client1.getDatabase(dbId) .getContainer(collectionId) .readItem(newDocument.getId(), - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(newDocument, "mypk")), + new PartitionKey(newDocument.get("mypk")), InternalObjectNode.class) .block(); logger.info("Client 2 READ Document Client Side Request Statistics {}", readDocumentResponse.getDiagnostics()); @@ -350,8 +351,8 @@ public void sessionTokenConsistencyCollectionDeleteCreateSameName() { InternalObjectNode readDocument = BridgeInternal.getProperties(readDocumentResponse); assertThat(readDocument.getId().equals(newDocument.getId())).isTrue(); - assertThat(ModelBridgeInternal.getObjectFromJsonSerializable(readDocument, "name") - .equals(ModelBridgeInternal.getObjectFromJsonSerializable(newDocument, "name"))).isTrue(); + assertThat(readDocument.get("name") + .equals(newDocument.get("name"))).isTrue(); } finally { safeDeleteDatabase(db); safeClose(client1); diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/CosmosItemResponseValidator.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/CosmosItemResponseValidator.java index 0af494bd977a..e10c7c759e58 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/CosmosItemResponseValidator.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/CosmosItemResponseValidator.java @@ -40,8 +40,8 @@ public Builder withProperty(String propertyName, String value) { @SuppressWarnings("rawtypes") public void validate(CosmosItemResponse itemResponse) { assertThat(itemResponse.getItem()).isNotNull(); - assertThat(ModelBridgeInternal - .getObjectFromJsonSerializable(InternalObjectNode.fromObject(itemResponse.getItem()), propertyName)) + assertThat(InternalObjectNode.fromObject(itemResponse.getItem()) + .get(propertyName)) .as("check property") .isEqualTo(value); } diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/DistinctQueryTests.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/DistinctQueryTests.java index eda2314fd412..062c891cf09d 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/DistinctQueryTests.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/DistinctQueryTests.java @@ -291,8 +291,7 @@ public void queryDocumentsForDistinctIntValues(Boolean qmEnabled) { List intpropList = itemPropertiesList .stream() .map(internalObjectNode -> - ModelBridgeInternal.getObjectFromJsonSerializable( - internalObjectNode, "intprop")) + internalObjectNode.get("intprop")) .collect(Collectors.toList()); // We insert two documents witn intprop as 5.0 and 5. Distinct should consider them as one assertThat(intpropList).containsExactlyInAnyOrder(null, 5); diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/DocumentCrudTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/DocumentCrudTest.java index 1920f4191b03..706f09c0d1b0 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/DocumentCrudTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/DocumentCrudTest.java @@ -8,6 +8,7 @@ import com.azure.cosmos.CosmosAsyncDatabase; import com.azure.cosmos.CosmosClientBuilder; import com.azure.cosmos.CosmosException; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.TestObject; import com.azure.cosmos.implementation.DatabaseForTest; import com.azure.cosmos.implementation.FailureValidator; @@ -103,7 +104,7 @@ public void readDocument(String documentId) throws InterruptedException { CosmosItemRequestOptions options = new CosmosItemRequestOptions(); Mono> readObservable = container.readItem(docDefinition.getId(), - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(docDefinition, "mypk")), + new PartitionKey(docDefinition.get("mypk")), options, InternalObjectNode.class); CosmosItemResponseValidator validator = @@ -125,7 +126,7 @@ public void timestamp(String documentId) throws Exception { CosmosItemRequestOptions options = new CosmosItemRequestOptions(); InternalObjectNode readDocument = BridgeInternal.getProperties(container.readItem(docDefinition.getId(), - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(docDefinition, "mypk")), + new PartitionKey(docDefinition.get("mypk")), options, InternalObjectNode.class) .block()); @@ -143,12 +144,12 @@ public void readDocument_DoesntExist(String documentId) throws InterruptedExcept container.createItem(docDefinition, new CosmosItemRequestOptions()).block(); CosmosItemRequestOptions options = new CosmosItemRequestOptions(); - container.deleteItem(docDefinition.getId(), new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(docDefinition, "mypk"))).block(); + container.deleteItem(docDefinition.getId(), new PartitionKey(docDefinition.get("mypk"))).block(); waitIfNeededForReplicasToCatchUp(getClientBuilder()); Mono> readObservable = container.readItem(docDefinition.getId(), - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(docDefinition, "mypk")), + new PartitionKey(docDefinition.get("mypk")), options, InternalObjectNode.class); FailureValidator validator = new FailureValidator.Builder() @@ -167,7 +168,7 @@ public void deleteDocument(String documentId) throws InterruptedException { CosmosItemRequestOptions options = new CosmosItemRequestOptions(); Mono> deleteObservable = container.deleteItem(documentId, - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(docDefinition, "mypk")), + new PartitionKey(docDefinition.get("mypk")), options); CosmosItemResponseValidator validator = @@ -180,7 +181,7 @@ public void deleteDocument(String documentId) throws InterruptedException { waitIfNeededForReplicasToCatchUp(getClientBuilder()); Mono> readObservable = container.readItem(documentId, - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(docDefinition, "mypk")), + new PartitionKey(docDefinition.get("mypk")), options, InternalObjectNode.class); FailureValidator notFoundValidator = new FailureValidator.Builder() .resourceNotFound() @@ -209,7 +210,7 @@ public void deleteDocumentUsingEntity(String documentId) throws InterruptedExcep waitIfNeededForReplicasToCatchUp(getClientBuilder()); Mono> readObservable = container.readItem(documentId, - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(docDefinition, "mypk")), + new PartitionKey(docDefinition.get("mypk")), options, InternalObjectNode.class); FailureValidator notFoundValidator = new FailureValidator.Builder() .resourceNotFound() @@ -253,7 +254,7 @@ public void deleteDocument_DoesntExist(String documentId) throws InterruptedExce CosmosItemRequestOptions options = new CosmosItemRequestOptions(); container.deleteItem(documentId, - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(docDefinition, "mypk")), + new PartitionKey(docDefinition.get("mypk")), options) .block(); @@ -274,14 +275,14 @@ public void replaceDocument(String documentId) throws InterruptedException { container.createItem(docDefinition, new CosmosItemRequestOptions()).block(); String newPropValue = UUID.randomUUID().toString(); - BridgeInternal.setProperty(docDefinition, "newProp", newPropValue); + docDefinition.set("newProp", newPropValue, CosmosItemSerializer.DEFAULT_SERIALIZER); CosmosItemRequestOptions options = new CosmosItemRequestOptions(); // replace document Mono> replaceObservable = container.replaceItem(docDefinition, documentId, - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(docDefinition, "mypk")), + new PartitionKey(docDefinition.get("mypk")), options); // validate @@ -319,7 +320,7 @@ public void upsertDocument_ReplaceDocument(String documentId) throws Throwable { BridgeInternal.getProperties(container.createItem(properties, new CosmosItemRequestOptions()).block()); String newPropValue = UUID.randomUUID().toString(); - BridgeInternal.setProperty(properties, "newProp", newPropValue); + properties.set("newProp", newPropValue, CosmosItemSerializer.DEFAULT_SERIALIZER); // Replace document diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/GroupByQueryTests.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/GroupByQueryTests.java index 1d3f0adc9b08..b9c72b3542fd 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/GroupByQueryTests.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/GroupByQueryTests.java @@ -5,6 +5,7 @@ import com.azure.cosmos.CosmosAsyncClient; import com.azure.cosmos.CosmosAsyncContainer; import com.azure.cosmos.CosmosClientBuilder; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.Document; import com.azure.cosmos.implementation.InternalObjectNode; import com.azure.cosmos.models.CosmosQueryRequestOptions; @@ -120,8 +121,8 @@ public void queryDocuments(Triple, Integer> gro resultMap.forEach((groupByObj, sum) -> { Document d = new Document(); - d.set("sum_age", sum); - d.set(groupByConfig.getLeft(), groupByObj); + d.set("sum_age", sum, CosmosItemSerializer.DEFAULT_SERIALIZER); + d.set(groupByConfig.getLeft(), groupByObj, CosmosItemSerializer.DEFAULT_SERIALIZER); expectedDocumentsList.add(d); }); diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/MultiOrderByQueryTests.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/MultiOrderByQueryTests.java index 09999cc53557..d37866658eba 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/MultiOrderByQueryTests.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/MultiOrderByQueryTests.java @@ -3,10 +3,10 @@ package com.azure.cosmos.rx; -import com.azure.cosmos.BridgeInternal; import com.azure.cosmos.CosmosAsyncClient; import com.azure.cosmos.CosmosAsyncContainer; import com.azure.cosmos.CosmosClientBuilder; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.FeedResponseListValidator; import com.azure.cosmos.implementation.InternalObjectNode; import com.azure.cosmos.models.CompositePath; @@ -14,7 +14,6 @@ import com.azure.cosmos.models.CosmosContainerProperties; import com.azure.cosmos.models.CosmosItemRequestOptions; import com.azure.cosmos.models.CosmosQueryRequestOptions; -import com.azure.cosmos.models.ModelBridgeInternal; import com.azure.cosmos.util.CosmosPagedFlux; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.collections4.ComparatorUtils; @@ -77,9 +76,9 @@ public CustomComparator(String path, CompositePathSortOrder order) { public int compare(InternalObjectNode doc1, InternalObjectNode doc2) { boolean isAsc = order == CompositePathSortOrder.ASCENDING; if (isNumericPath) { - if (ModelBridgeInternal.getIntFromJsonSerializable(doc1, path) < ModelBridgeInternal.getIntFromJsonSerializable(doc2, path)) + if (doc1.getInt(path) < doc2.getInt(path)) return isAsc ? -1 : 1; - else if (ModelBridgeInternal.getIntFromJsonSerializable(doc1, path) > ModelBridgeInternal.getIntFromJsonSerializable(doc2, path)) + else if (doc1.getInt(path) > doc2.getInt(path)) return isAsc ? 1 : -1; else return 0; @@ -89,14 +88,12 @@ else if (ModelBridgeInternal.getIntFromJsonSerializable(doc1, path) > ModelBridg doc1 = doc2; doc2 = temp; } - return ModelBridgeInternal.getStringFromJsonSerializable(doc1, path) - .compareTo(ModelBridgeInternal.getStringFromJsonSerializable(doc2, path)); + return doc1.getString(path) + .compareTo(doc2.getString(path)); } else if (isBooleanPath) { - if (!ModelBridgeInternal.getBooleanFromJsonSerializable(doc1, path) && - ModelBridgeInternal.getBooleanFromJsonSerializable(doc2, path)) + if (!doc1.getBoolean(path) && doc2.getBoolean(path)) return isAsc ? -1 : 1; - else if (ModelBridgeInternal.getBooleanFromJsonSerializable(doc1, path) && - !ModelBridgeInternal.getBooleanFromJsonSerializable(doc2, path)) + else if (doc1.getBoolean(path) && !doc2.getBoolean(path)) return isAsc ? 1 : -1; else return 0; @@ -130,7 +127,7 @@ public void before_MultiOrderByQueryTests() throws Exception { Random random = new Random(); for (int i = 0; i < numberOfDocuments; ++i) { InternalObjectNode multiOrderByDocument = generateMultiOrderByDocument(); - String multiOrderByDocumentString = ModelBridgeInternal.toJsonFromJsonSerializable(multiOrderByDocument); + String multiOrderByDocumentString = multiOrderByDocument.toJson(); int numberOfDuplicates = 5; for (int j = 0; j < numberOfDuplicates; j++) { @@ -141,23 +138,23 @@ public void before_MultiOrderByQueryTests() throws Exception { // Permute all the fields so that there are duplicates with tie breaks InternalObjectNode numberClone = new InternalObjectNode(multiOrderByDocumentString); - BridgeInternal.setProperty(numberClone, NUMBER_FIELD, random.nextInt(5)); + numberClone.set(NUMBER_FIELD, random.nextInt(5), CosmosItemSerializer.DEFAULT_SERIALIZER); numberClone.setId(UUID.randomUUID().toString()); this.documents.add(numberClone); InternalObjectNode stringClone = new InternalObjectNode(multiOrderByDocumentString); - BridgeInternal.setProperty(stringClone, STRING_FIELD, Integer.toString(random.nextInt(5))); + stringClone.set(STRING_FIELD, Integer.toString(random.nextInt(5)), CosmosItemSerializer.DEFAULT_SERIALIZER); stringClone.setId(UUID.randomUUID().toString()); this.documents.add(stringClone); InternalObjectNode boolClone = new InternalObjectNode(multiOrderByDocumentString); - BridgeInternal.setProperty(boolClone, BOOL_FIELD, random.nextInt(2) % 2 == 0); + boolClone.set(BOOL_FIELD, random.nextInt(2) % 2 == 0, CosmosItemSerializer.DEFAULT_SERIALIZER); boolClone.setId(UUID.randomUUID().toString()); this.documents.add(boolClone); // Also fuzz what partition it goes to InternalObjectNode partitionClone = new InternalObjectNode(multiOrderByDocumentString); - BridgeInternal.setProperty(partitionClone, PARTITION_KEY, random.nextInt(5)); + partitionClone.set(PARTITION_KEY, random.nextInt(5), CosmosItemSerializer.DEFAULT_SERIALIZER); partitionClone.setId(UUID.randomUUID().toString()); this.documents.add(partitionClone); } @@ -172,18 +169,18 @@ private InternalObjectNode generateMultiOrderByDocument() { Random random = new Random(); InternalObjectNode document = new InternalObjectNode(); document.setId(UUID.randomUUID().toString()); - BridgeInternal.setProperty(document, NUMBER_FIELD, random.nextInt(5)); - BridgeInternal.setProperty(document, NUMBER_FIELD_2, random.nextInt(5)); - BridgeInternal.setProperty(document, BOOL_FIELD, (random.nextInt() % 2) == 0); - BridgeInternal.setProperty(document, STRING_FIELD, Integer.toString(random.nextInt(5))); - BridgeInternal.setProperty(document, STRING_FIELD_2, Integer.toString(random.nextInt(5))); - BridgeInternal.setProperty(document, NULL_FIELD, null); - BridgeInternal.setProperty(document, OBJECT_FIELD, ""); - BridgeInternal.setProperty(document, ARRAY_FIELD, (new ObjectMapper()).createArrayNode()); - BridgeInternal.setProperty(document, SHORT_STRING_FIELD, "a" + random.nextInt(100)); - BridgeInternal.setProperty(document, MEDIUM_STRING_FIELD, "a" + random.nextInt(128) + 100); - BridgeInternal.setProperty(document, LONG_STRING_FIELD, "a" + random.nextInt(255) + 128); - BridgeInternal.setProperty(document, PARTITION_KEY, random.nextInt(5)); + document.set(NUMBER_FIELD, random.nextInt(5), CosmosItemSerializer.DEFAULT_SERIALIZER); + document.set(NUMBER_FIELD_2, random.nextInt(5), CosmosItemSerializer.DEFAULT_SERIALIZER); + document.set(BOOL_FIELD, (random.nextInt() % 2) == 0, CosmosItemSerializer.DEFAULT_SERIALIZER); + document.set(STRING_FIELD, Integer.toString(random.nextInt(5)), CosmosItemSerializer.DEFAULT_SERIALIZER); + document.set(STRING_FIELD_2, Integer.toString(random.nextInt(5)), CosmosItemSerializer.DEFAULT_SERIALIZER); + document.set(NULL_FIELD, null, CosmosItemSerializer.DEFAULT_SERIALIZER); + document.set(OBJECT_FIELD, "", CosmosItemSerializer.DEFAULT_SERIALIZER); + document.set(ARRAY_FIELD, (new ObjectMapper()).createArrayNode(), CosmosItemSerializer.DEFAULT_SERIALIZER); + document.set(SHORT_STRING_FIELD, "a" + random.nextInt(100), CosmosItemSerializer.DEFAULT_SERIALIZER); + document.set(MEDIUM_STRING_FIELD, "a" + random.nextInt(128) + 100, CosmosItemSerializer.DEFAULT_SERIALIZER); + document.set(LONG_STRING_FIELD, "a" + random.nextInt(255) + 128, CosmosItemSerializer.DEFAULT_SERIALIZER); + document.set(PARTITION_KEY, random.nextInt(5), CosmosItemSerializer.DEFAULT_SERIALIZER); return document; } @@ -271,7 +268,7 @@ public void queryDocumentsWithUndefinedValueAndMultiOrderby() { List documentWithEmptyFieldIds = new ArrayList<>(); for (int i = 0; i < documentWithUndefinedFiledSize; i++) { InternalObjectNode documentWithEmptyField = generateMultiOrderByDocument(); - BridgeInternal.remove(documentWithEmptyField, NUMBER_FIELD); + documentWithEmptyField.remove(NUMBER_FIELD); documentCollection.createItem(documentWithEmptyField, new CosmosItemRequestOptions()).block(); documentWithEmptyFieldIds.add(documentWithEmptyField.getId()); } @@ -328,7 +325,7 @@ private List filter(List cosmosItemSetti List result = new ArrayList(); if (hasFilter) { for (InternalObjectNode document : cosmosItemSettings) { - if (ModelBridgeInternal.getIntFromJsonSerializable(document, NUMBER_FIELD) % 2 == 0) { + if (document.getInt(NUMBER_FIELD) % 2 == 0) { result.add(document); } } diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/OffsetLimitQueryTests.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/OffsetLimitQueryTests.java index dba8435e7e96..43721b70b5bf 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/OffsetLimitQueryTests.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/OffsetLimitQueryTests.java @@ -3,11 +3,11 @@ package com.azure.cosmos.rx; -import com.azure.cosmos.BridgeInternal; import com.azure.cosmos.CosmosAsyncClient; import com.azure.cosmos.CosmosAsyncContainer; import com.azure.cosmos.CosmosAsyncDatabase; import com.azure.cosmos.CosmosClientBuilder; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.FeedResponseListValidator; import com.azure.cosmos.implementation.FeedResponseValidator; import com.azure.cosmos.implementation.InternalObjectNode; @@ -15,7 +15,6 @@ import com.azure.cosmos.implementation.query.OffsetContinuationToken; import com.azure.cosmos.models.CosmosQueryRequestOptions; import com.azure.cosmos.models.FeedResponse; -import com.azure.cosmos.models.ModelBridgeInternal; import com.azure.cosmos.util.CosmosPagedFlux; import com.fasterxml.jackson.databind.JsonNode; import io.reactivex.subscribers.TestSubscriber; @@ -250,12 +249,12 @@ public void queryDocumentsWithAggregate(Boolean qmEnabled) { // The pipeline execution sequence is Aggregrate, skip, and top/limit, hence finding the max from among the docs InternalObjectNode expectedDoc = docs .stream() - .max(Comparator.comparing(r -> ModelBridgeInternal.getIntFromJsonSerializable(r, field))) + .max(Comparator.comparing(r -> r.getInt(field))) .get(); FeedResponseListValidator validator = new FeedResponseListValidator.Builder() - .withAggregateValue(ModelBridgeInternal.getIntFromJsonSerializable(expectedDoc, field)) + .withAggregateValue(expectedDoc.getInt(field)) .numberOfPages(1) .hasValidQueryMetrics(qmEnabled) .build(); @@ -313,24 +312,24 @@ public void generateTestData() { for (int i = 0; i < 10; i++) { InternalObjectNode d = new InternalObjectNode(); d.setId(Integer.toString(i)); - BridgeInternal.setProperty(d, field, i); - BridgeInternal.setProperty(d, partitionKey, firstPk); + d.set(field, i, CosmosItemSerializer.DEFAULT_SERIALIZER); + d.set(partitionKey, firstPk, CosmosItemSerializer.DEFAULT_SERIALIZER); docs.add(d); } for (int i = 10; i < 20; i++) { InternalObjectNode d = new InternalObjectNode(); d.setId(Integer.toString(i)); - BridgeInternal.setProperty(d, field, i); - BridgeInternal.setProperty(d, partitionKey, secondPk); + d.set(field, i, CosmosItemSerializer.DEFAULT_SERIALIZER); + d.set(partitionKey, secondPk, CosmosItemSerializer.DEFAULT_SERIALIZER); docs.add(d); } for (int i = 20; i < 100; i++) { InternalObjectNode d = new InternalObjectNode(); d.setId(Integer.toString(i)); - BridgeInternal.setProperty(d, field, i); - BridgeInternal.setProperty(d, partitionKey, thirdPk); + d.set(field, i, CosmosItemSerializer.DEFAULT_SERIALIZER); + d.set(partitionKey, thirdPk, CosmosItemSerializer.DEFAULT_SERIALIZER); docs.add(d); } } diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/OrderbyDocumentQueryTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/OrderbyDocumentQueryTest.java index b5d809717481..c5a7929ffb99 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/OrderbyDocumentQueryTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/OrderbyDocumentQueryTest.java @@ -9,6 +9,7 @@ import com.azure.cosmos.CosmosBridgeInternal; import com.azure.cosmos.CosmosClientBuilder; import com.azure.cosmos.CosmosException; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.AsyncDocumentClient; import com.azure.cosmos.implementation.FeedResponseListValidator; import com.azure.cosmos.implementation.FeedResponseValidator; @@ -79,11 +80,11 @@ public void queryDocumentsValidateContent() throws Exception { // removes undefined InternalObjectNode expectedDocument = createdDocuments .stream() - .filter(d -> ModelBridgeInternal.getMapFromJsonSerializable(d).containsKey("propInt")) + .filter(d -> d.getMap().containsKey("propInt")) .min(Comparator.comparing(o -> String.valueOf(o.get("propInt")))).get(); String query = String.format("SELECT * from root r where r.propInt = %d ORDER BY r.propInt ASC" - , ModelBridgeInternal.getIntFromJsonSerializable(expectedDocument,"propInt")); + , expectedDocument.getInt("propInt")); CosmosQueryRequestOptions options = new CosmosQueryRequestOptions(); @@ -141,7 +142,7 @@ public void queryOrderBy(String sortOrder) throws Exception { CosmosPagedFlux queryObservable = createdCollection.queryItems(query, options, InternalObjectNode.class); Comparator validatorComparator = Comparator.nullsFirst(Comparator.naturalOrder()); - List expectedResourceIds = sortDocumentsAndCollectResourceIds("propInt", d -> ModelBridgeInternal.getIntFromJsonSerializable(d,"propInt"), validatorComparator); + List expectedResourceIds = sortDocumentsAndCollectResourceIds("propInt", d -> d.getInt("propInt"), validatorComparator); if ("DESC".equals(sortOrder)) { Collections.reverse(expectedResourceIds); } @@ -171,8 +172,7 @@ public void queryOrderByWithValue(String sortOrder) throws Exception { List expectedValues = sortDocumentsAndCollectValues("propInt", - d -> ModelBridgeInternal - .getIntFromJsonSerializable(d, "propInt"), + d -> d.getInt("propInt"), validatorComparator); if ("DESC".equals(sortOrder)) { Collections.reverse(expectedValues); @@ -205,8 +205,18 @@ public void queryOrderByWithValueAndCustomFactoryMethod(String sortOrder) throws // customers if we ever make the custom factory method public // For now in Spark don't need to worry about extracting values - we would need a wrapper to // allow inferring schema anyway. - .setItemFactoryMethod( - (node) -> node.get("_value").intValue()); + .setCustomSerializer( + new CosmosItemSerializer() { + @Override + public Map serialize(T item) { + return null; + } + + @Override + public T deserialize(Map jsonNodeMap, Class classType) { + return (T)(jsonNodeMap.get("_value")); + } + }); int pageSize = 3; CosmosPagedFlux queryObservable = createdCollection.queryItems(query, options, @@ -215,8 +225,7 @@ public void queryOrderByWithValueAndCustomFactoryMethod(String sortOrder) throws List expectedValues = sortDocumentsAndCollectValues("propInt", - d -> ModelBridgeInternal - .getIntFromJsonSerializable(d, "propInt"), + d -> d.getInt("propInt"), validatorComparator); if ("DESC".equals(sortOrder)) { Collections.reverse(expectedValues); @@ -244,7 +253,7 @@ public void queryOrderByInt() throws Exception { CosmosPagedFlux queryObservable = createdCollection.queryItems(query, options, InternalObjectNode.class); Comparator validatorComparator = Comparator.nullsFirst(Comparator.naturalOrder()); - List expectedResourceIds = sortDocumentsAndCollectResourceIds("propInt", d -> ModelBridgeInternal.getIntFromJsonSerializable(d,"propInt"), validatorComparator); + List expectedResourceIds = sortDocumentsAndCollectResourceIds("propInt", d -> d.getInt("propInt"), validatorComparator); int expectedPageSize = expectedNumberOfPages(expectedResourceIds.size(), pageSize); FeedResponseListValidator validator = new FeedResponseListValidator.Builder() @@ -267,7 +276,7 @@ public void queryOrderByString() throws Exception { CosmosPagedFlux queryObservable = createdCollection.queryItems(query, options, InternalObjectNode.class); Comparator validatorComparator = Comparator.nullsFirst(Comparator.naturalOrder()); - List expectedResourceIds = sortDocumentsAndCollectResourceIds("propStr", d -> ModelBridgeInternal.getStringFromJsonSerializable(d,"propStr"), validatorComparator); + List expectedResourceIds = sortDocumentsAndCollectResourceIds("propStr", d -> d.getString("propStr"), validatorComparator); int expectedPageSize = expectedNumberOfPages(expectedResourceIds.size(), pageSize); FeedResponseListValidator validator = new FeedResponseListValidator.Builder() @@ -407,7 +416,7 @@ public void queryOrderWithTop(int topValue) throws Exception { Comparator validatorComparator = Comparator.nullsFirst(Comparator.naturalOrder()); List expectedResourceIds = - sortDocumentsAndCollectResourceIds("propInt", d -> ModelBridgeInternal.getIntFromJsonSerializable(d,"propInt"), validatorComparator) + sortDocumentsAndCollectResourceIds("propInt", d -> d.getInt("propInt"), validatorComparator) .stream().limit(topValue).collect(Collectors.toList()); int expectedPageSize = expectedNumberOfPages(expectedResourceIds.size(), pageSize); @@ -425,7 +434,7 @@ public void queryOrderWithTop(int topValue) throws Exception { private List sortDocumentsAndCollectResourceIds(String propName, Function extractProp, Comparator comparer) { return createdDocuments.stream() - .filter(d -> ModelBridgeInternal.getMapFromJsonSerializable(d).containsKey(propName)) // removes undefined + .filter(d -> d.getMap().containsKey(propName)) // removes undefined .sorted((d1, d2) -> comparer.compare(extractProp.apply(d1), extractProp.apply(d2))) .map(Resource::getResourceId).collect(Collectors.toList()); } @@ -434,9 +443,9 @@ private List sortDocumentsAndCollectResourceIds(String propName, Fun private List sortDocumentsAndCollectValues(String propName, Function extractProp, Comparator comparer) { return createdDocuments.stream() - .filter(d -> ModelBridgeInternal.getMapFromJsonSerializable(d).containsKey(propName)) // removes undefined + .filter(d -> d.getMap().containsKey(propName)) // removes undefined .sorted((d1, d2) -> comparer.compare(extractProp.apply(d1), extractProp.apply(d2))) - .map(d -> (T)ModelBridgeInternal.getMapFromJsonSerializable(d).get(propName)) + .map(d -> (T)d.getMap().get(propName)) .collect(Collectors.toList()); } @@ -465,8 +474,8 @@ public void queryScopedToSinglePartition_StartWithContinuationToken() throws Exc queryObservable = createdCollection.queryItems(query, options, InternalObjectNode.class); List expectedDocs = createdDocuments.stream() - .filter(d -> (StringUtils.equals("duplicatePartitionKeyValue", ModelBridgeInternal.getStringFromJsonSerializable(d,"mypk")))) - .filter(d -> (ModelBridgeInternal.getIntFromJsonSerializable(d,"propScopedPartitionInt") > 2)).collect(Collectors.toList()); + .filter(d -> (StringUtils.equals("duplicatePartitionKeyValue", d.getString("mypk")))) + .filter(d -> (d.getInt("propScopedPartitionInt") > 2)).collect(Collectors.toList()); int expectedPageSize = (expectedDocs.size() + preferredPageSize - 1) / preferredPageSize; assertThat(expectedDocs).hasSize(10 - 3); @@ -475,8 +484,8 @@ public void queryScopedToSinglePartition_StartWithContinuationToken() throws Exc validator = new FeedResponseListValidator.Builder() .containsExactly(expectedDocs.stream() - .sorted((e1, e2) -> Integer.compare(ModelBridgeInternal.getIntFromJsonSerializable(e1,"propScopedPartitionInt"), - ModelBridgeInternal.getIntFromJsonSerializable(e2,"propScopedPartitionInt"))) + .sorted((e1, e2) -> Integer.compare(e1.getInt("propScopedPartitionInt"), + e2.getInt("propScopedPartitionInt"))) .map(d -> d.getResourceId()).collect(Collectors.toList())) .numberOfPages(expectedPageSize) .allPagesSatisfy(new FeedResponseValidator.Builder() @@ -538,7 +547,7 @@ public void queryDocumentsWithOrderByContinuationTokensInteger(String sortOrder) Comparator order = sortOrder.equals("ASC")?Comparator.naturalOrder():Comparator.reverseOrder(); Comparator validatorComparator = Comparator.nullsFirst(order); - List expectedResourceIds = sortDocumentsAndCollectResourceIds("propInt", d -> ModelBridgeInternal.getIntFromJsonSerializable(d,"propInt"), validatorComparator); + List expectedResourceIds = sortDocumentsAndCollectResourceIds("propInt", d -> d.getInt("propInt"), validatorComparator); this.queryWithContinuationTokensAndPageSizes(query, new int[] { 1, 5, 10, 100}, expectedResourceIds); } @@ -551,7 +560,7 @@ public void queryDocumentsWithOrderByContinuationTokensString(String sortOrder) Comparator order = sortOrder.equals("ASC")?Comparator.naturalOrder():Comparator.reverseOrder(); Comparator validatorComparator = Comparator.nullsFirst(order); - List expectedResourceIds = sortDocumentsAndCollectResourceIds("id", d -> ModelBridgeInternal.getStringFromJsonSerializable(d,"id"), validatorComparator); + List expectedResourceIds = sortDocumentsAndCollectResourceIds("id", d -> d.getString("id"), validatorComparator); this.queryWithContinuationTokensAndPageSizes(query, new int[] { 1, 5, 10, 100 }, expectedResourceIds); } @@ -567,7 +576,7 @@ public void queryDocumentsWithInvalidOrderByContinuationTokensString(String sort }else{ validatorComparator = Comparator.nullsFirst(Comparator.reverseOrder()); } - List expectedResourceIds = sortDocumentsAndCollectResourceIds("id", d -> ModelBridgeInternal.getStringFromJsonSerializable(d,"id"), validatorComparator); + List expectedResourceIds = sortDocumentsAndCollectResourceIds("id", d -> d.getString("id"), validatorComparator); this.assertInvalidContinuationToken(query, new int[] { 1, 5, 10, 100 }, expectedResourceIds); } @@ -711,11 +720,11 @@ public void queryDocumentsValidateContentWithObjectNode() throws Exception { // removes undefined InternalObjectNode expectedDocument = createdDocuments .stream() - .filter(d -> ModelBridgeInternal.getMapFromJsonSerializable(d).containsKey("propInt")) + .filter(d -> d.getMap().containsKey("propInt")) .min(Comparator.comparing(o -> String.valueOf(o.get("propInt")))).get(); String query = String.format("SELECT * from root r where r.propInt = %d ORDER BY r.propInt ASC" - , ModelBridgeInternal.getIntFromJsonSerializable(expectedDocument,"propInt")); + , expectedDocument.getInt("propInt")); CosmosQueryRequestOptions options = new CosmosQueryRequestOptions(); diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/ParallelDocumentQueryTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/ParallelDocumentQueryTest.java index 3a6f824f6654..d4e0e4a60abd 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/ParallelDocumentQueryTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/ParallelDocumentQueryTest.java @@ -9,6 +9,7 @@ import com.azure.cosmos.CosmosBridgeInternal; import com.azure.cosmos.CosmosClientBuilder; import com.azure.cosmos.CosmosException; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.FailureValidator; import com.azure.cosmos.implementation.FeedResponseListValidator; import com.azure.cosmos.implementation.FeedResponseValidator; @@ -19,6 +20,7 @@ import com.azure.cosmos.implementation.Resource; import com.azure.cosmos.implementation.TestUtils; import com.azure.cosmos.implementation.Utils.ValueHolder; +import com.azure.cosmos.implementation.apachecommons.lang.NotImplementedException; import com.azure.cosmos.implementation.apachecommons.lang.tuple.Pair; import com.azure.cosmos.implementation.guava25.base.Function; import com.azure.cosmos.implementation.guava27.Strings; @@ -28,7 +30,6 @@ import com.azure.cosmos.models.CosmosQueryRequestOptions; import com.azure.cosmos.models.CosmosReadManyRequestOptions; import com.azure.cosmos.models.FeedResponse; -import com.azure.cosmos.models.ModelBridgeInternal; import com.azure.cosmos.models.PartitionKey; import com.azure.cosmos.util.CosmosPagedFlux; import com.fasterxml.jackson.databind.JsonNode; @@ -93,7 +94,7 @@ public void queryDocuments(Boolean qmEnabled) { options.setMaxDegreeOfParallelism(2); CosmosPagedFlux queryObservable = createdCollection.queryItems(query, options, InternalObjectNode.class); - List expectedDocs = createdDocuments.stream().filter(d -> 99 == ModelBridgeInternal.getIntFromJsonSerializable(d,"prop") ).collect(Collectors.toList()); + List expectedDocs = createdDocuments.stream().filter(d -> 99 == d.getInt("prop") ).collect(Collectors.toList()); assertThat(expectedDocs).isNotEmpty(); FeedResponseListValidator validator = new FeedResponseListValidator.Builder() @@ -354,7 +355,7 @@ public void queryDocumentsIntegerValue(){ options.setMaxDegreeOfParallelism(2); - List expectedValues = createdDocuments.stream().map(d -> ModelBridgeInternal.getIntFromJsonSerializable(d,"prop")).collect(Collectors.toList()); + List expectedValues = createdDocuments.stream().map(d -> d.getInt("prop")).collect(Collectors.toList()); String query = "Select value c.prop from c"; @@ -374,7 +375,7 @@ public void queryDocumentsBooleanValue() { List expectedValues = createdDocuments .stream() - .map(d -> ModelBridgeInternal.getBooleanFromJsonSerializable(d, "boolProp")) + .map(d -> d.getBoolean("boolProp")) .collect(Collectors.toList()); String query = "Select value c.boolProp from c"; @@ -394,7 +395,7 @@ public void queryDocumentsDoubleValue() { options.setMaxDegreeOfParallelism(2); List expectedValues = createdDocuments.stream() - .map(d -> ModelBridgeInternal.getDoubleFromJsonSerializable(d, "_value")) + .map(d ->d.getDouble("_value")) .collect(Collectors.toList()); String query = "Select value c._value from c"; @@ -437,9 +438,9 @@ public void queryDocumentsPojo(){ List assertTuples = createdDocuments.stream() .map(internalObjectNode -> tuple(internalObjectNode.getId(), - ModelBridgeInternal.getObjectFromJsonSerializable(internalObjectNode, "mypk"), - ModelBridgeInternal.getObjectFromJsonSerializable(internalObjectNode, "prop"), - ModelBridgeInternal.getObjectFromJsonSerializable(internalObjectNode, "boolProp"))) + internalObjectNode.get("mypk"), + internalObjectNode.get("prop"), + internalObjectNode.get("boolProp"))) .collect(Collectors.toList()); assertThat(fetchedResults).extracting(TestObject::getId, @@ -456,7 +457,7 @@ public void queryDocumentsNestedPropValue(){ options.setMaxDegreeOfParallelism(2); List expectedValues = createdDocuments.stream() - .map(d -> ModelBridgeInternal.toObjectFromJsonSerializable(d,TestObject.class)) + .map(d -> d.toObject(TestObject.class)) .map(d -> d.getNestedProp()).collect(Collectors.toList()); String query = "Select value c.nestedProp from c"; @@ -691,7 +692,7 @@ public void readManyWithItemOperations() { List> pairList = new ArrayList<>(); for (int i = 0; i < createdDocuments.size(); i = i + 3) { pairList.add(Pair.of(createdDocuments.get(i).getId(), - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(createdDocuments.get(i), "mypk")))); + new PartitionKey(createdDocuments.get(i).get("mypk")))); } FeedResponse documentFeedResponse = ItemOperations.readManyAsync(createdCollection, pairList, JsonNode.class).block(); @@ -706,7 +707,7 @@ public void readMany() { for (int i = 0; i < createdDocuments.size(); i = i + 3) { itemIdentities.add( new CosmosItemIdentity( - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(createdDocuments.get(i), "mypk")), + new PartitionKey(createdDocuments.get(i).get("mypk")), createdDocuments.get(i).getId())); } FeedResponse documentFeedResponse = @@ -725,7 +726,7 @@ public void readManyIdSameAsPartitionKey() { for (int i = 0; i < newItems.size(); i = i + 3) { itemIdentities.add( new CosmosItemIdentity( - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(newItems.get(i), "id")), + new PartitionKey(newItems.get(i).get("id")), newItems.get(i).getId())); } FeedResponse documentFeedResponse = @@ -741,7 +742,7 @@ public void readManyWithFactoryMethod() { for (int i = 0; i < createdDocuments.size(); i = i + 3) { itemIdentities.add( new CosmosItemIdentity( - new PartitionKey(ModelBridgeInternal.getObjectFromJsonSerializable(createdDocuments.get(i), "mypk")), + new PartitionKey(createdDocuments.get(i).get("mypk")), createdDocuments.get(i).getId())); } @@ -751,7 +752,22 @@ public void readManyWithFactoryMethod() { .CosmosReadManyRequestOptionsHelper .getCosmosReadManyRequestOptionsAccessor() .getImpl(queryRequestOptions) - .setItemFactoryMethod(factoryMethod); + .setCustomSerializer( + new CosmosItemSerializer() { + @Override + public Map serialize(T item) { + throw new NotImplementedException("Not supported"); + } + + @Override + public T deserialize(Map jsonNodeMap, Class classType) { + if (classType == String.class) { + return (T)jsonNodeMap.get("id"); + } + + return CosmosItemSerializer.DEFAULT_SERIALIZER.deserialize(jsonNodeMap, classType); + } + }); FeedResponse documentFeedResponse = ImplementationBridgeHelpers diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/SimpleSerializationTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/SimpleSerializationTest.java index 7d23d9c91d59..d5e17481a6a8 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/SimpleSerializationTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/SimpleSerializationTest.java @@ -31,7 +31,7 @@ private static class TestObject { public static class BadSerializer extends JsonSerializer { @Override public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) { - throw new NotImplementedException("bad"); + throw new NotImplementedException("BadSerializer: bad"); } } @@ -62,7 +62,7 @@ public void createDocument() throws InterruptedException { createdCollection.createItem(testObject).block(); Assert.fail(); } catch (IllegalArgumentException e) { - assertThat(e.getMessage()).contains("Failed to serialize the object into json"); + assertThat(e.getMessage()).startsWith("BadSerializer"); assertThat(e.getCause()).isInstanceOf(JsonMappingException.class); assertThat(e.getCause().getMessage()).contains("bad"); } diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/SinglePartitionDocumentQueryTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/SinglePartitionDocumentQueryTest.java index 432407f8e43e..71b426c44bc9 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/SinglePartitionDocumentQueryTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/SinglePartitionDocumentQueryTest.java @@ -71,7 +71,7 @@ public void queryDocuments(Boolean qmEnabled) throws Exception { CosmosPagedFlux queryObservable = createdCollection.queryItems(query, options, InternalObjectNode.class); - List expectedDocs = createdDocuments.stream().filter(d -> 99 == ModelBridgeInternal.getIntFromJsonSerializable(d,"prop") ).collect(Collectors.toList()); + List expectedDocs = createdDocuments.stream().filter(d -> 99 == d.getInt("prop") ).collect(Collectors.toList()); assertThat(expectedDocs).isNotEmpty(); int expectedPageSize = (expectedDocs.size() + maxItemCount - 1) / maxItemCount; @@ -134,7 +134,7 @@ public void queryDocuments_ParameterizedQueryWithInClause() throws Exception { CosmosPagedFlux queryObservable = createdCollection.queryItems(sqs, options, InternalObjectNode.class); - List expectedDocs = createdDocuments.stream().filter(d -> (3 == ModelBridgeInternal.getIntFromJsonSerializable(d,"prop") || 4 == ModelBridgeInternal.getIntFromJsonSerializable(d,"prop"))).collect(Collectors.toList()); + List expectedDocs = createdDocuments.stream().filter(d -> (3 == d.getInt("prop") || 4 == d.getInt("prop"))).collect(Collectors.toList()); assertThat(expectedDocs).isNotEmpty(); int expectedPageSize = (expectedDocs.size() + maxItemCount - 1) / maxItemCount; @@ -160,7 +160,7 @@ public void queryDocuments_ParameterizedQuery() throws Exception { CosmosPagedFlux queryObservable = createdCollection.queryItems(sqs, options, InternalObjectNode.class); - List expectedDocs = createdDocuments.stream().filter(d -> 3 == ModelBridgeInternal.getIntFromJsonSerializable(d,"prop")).collect(Collectors.toList()); + List expectedDocs = createdDocuments.stream().filter(d -> 3 == d.getInt("prop")).collect(Collectors.toList()); assertThat(expectedDocs).isNotEmpty(); int expectedPageSize = (expectedDocs.size() + maxItemCount - 1) / maxItemCount; @@ -233,8 +233,8 @@ public void queryOrderBy() throws Exception { FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .containsExactly(createdDocuments.stream() - .sorted((e1, e2) -> Integer.compare(ModelBridgeInternal.getIntFromJsonSerializable(e1, "prop"), - ModelBridgeInternal.getIntFromJsonSerializable(e2, "prop"))) + .sorted((e1, e2) -> Integer.compare(e1.getInt("prop"), + e2.getInt("prop"))) .map(d -> d.getResourceId()).collect(Collectors.toList())) .numberOfPages(expectedPageSize) .allPagesSatisfy(new FeedResponseValidator.Builder() @@ -267,15 +267,15 @@ public void continuationToken() throws Exception { queryObservable = createdCollection.queryItems(query, options, InternalObjectNode.class); - List expectedDocs = createdDocuments.stream().filter(d -> (ModelBridgeInternal.getIntFromJsonSerializable(d,"prop") > 2)).collect(Collectors.toList()); + List expectedDocs = createdDocuments.stream().filter(d -> (d.getInt("prop") > 2)).collect(Collectors.toList()); int expectedPageSize = (expectedDocs.size() + maxItemCount - 1) / maxItemCount; assertThat(expectedDocs).hasSize(createdDocuments.size() -3); FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .containsExactly(expectedDocs.stream() - .sorted((e1, e2) -> Integer.compare(ModelBridgeInternal.getIntFromJsonSerializable(e1,"prop"), - ModelBridgeInternal.getIntFromJsonSerializable(e2, "prop"))) + .sorted((e1, e2) -> Integer.compare(e1.getInt("prop"), + e2.getInt("prop"))) .map(d -> d.getResourceId()).collect(Collectors.toList())) .numberOfPages(expectedPageSize) .allPagesSatisfy(new FeedResponseValidator.Builder() diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/TestSuiteBase.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/TestSuiteBase.java index a72a161ad2d0..8d83b68956c5 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/TestSuiteBase.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/TestSuiteBase.java @@ -113,7 +113,7 @@ public class TestSuiteBase extends CosmosAsyncClientTest { protected final static ConsistencyLevel accountConsistency; protected static final ImmutableList preferredLocations; private static final ImmutableList desiredConsistencies; - private static final ImmutableList protocols; + protected static final ImmutableList protocols; protected static final AzureKeyCredential credential; @@ -203,7 +203,7 @@ public CosmosAsyncDatabase getDatabase(String id) { } @BeforeSuite(groups = {"fast", "long", "direct", "multi-region", "multi-master", "flaky-multi-master", "emulator", "split", "query", "cfp-split"}, timeOut = SUITE_SETUP_TIMEOUT) - public static void beforeSuite() { + public void beforeSuite() { logger.info("beforeSuite Started"); @@ -219,7 +219,7 @@ public static void beforeSuite() { } @AfterSuite(groups = {"fast", "long", "direct", "multi-region", "multi-master", "flaky-multi-master", "emulator", "split", "query", "cfp-split"}, timeOut = SUITE_SHUTDOWN_TIMEOUT) - public static void afterSuite() { + public void afterSuite() { logger.info("afterSuite Started"); @@ -253,7 +253,7 @@ protected static void cleanUpContainer(CosmosAsyncContainer cosmosContainer) { Object propertyValue = null; if (paths != null && !paths.isEmpty()) { List pkPath = PathParser.getPathParts(paths.get(0)); - propertyValue = ModelBridgeInternal.getObjectByPathFromJsonSerializable(doc, pkPath); + propertyValue = doc.getObjectByPath(pkPath); if (propertyValue == null) { partitionKey = PartitionKey.NONE; } else { @@ -293,7 +293,7 @@ protected static void truncateCollection(CosmosAsyncContainer cosmosContainer) { Object propertyValue = null; if (paths != null && !paths.isEmpty()) { List pkPath = PathParser.getPathParts(paths.get(0)); - propertyValue = ModelBridgeInternal.getObjectByPathFromJsonSerializable(doc, pkPath); + propertyValue = doc.getObjectByPath(pkPath); if (propertyValue == null) { partitionKey = PartitionKey.NONE; } else { @@ -1267,11 +1267,11 @@ public static Object[][] simpleClientBuilderGatewaySession() { return clientBuildersWithDirectSession(true, true); } - static Protocol[] toArray(List protocols) { + protected static Protocol[] toArray(List protocols) { return protocols.toArray(new Protocol[protocols.size()]); } - private static Object[][] clientBuildersWithDirectSession(boolean contentResponseOnWriteEnabled, boolean retryOnThrottledRequests, Protocol... protocols) { + protected static Object[][] clientBuildersWithDirectSession(boolean contentResponseOnWriteEnabled, boolean retryOnThrottledRequests, Protocol... protocols) { return clientBuildersWithDirect(new ArrayList() {{ add(ConsistencyLevel.SESSION); }}, contentResponseOnWriteEnabled, retryOnThrottledRequests, protocols); diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/TopQueryTests.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/TopQueryTests.java index db892b9c270c..90233a668ce1 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/TopQueryTests.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/TopQueryTests.java @@ -2,10 +2,10 @@ // Licensed under the MIT License. package com.azure.cosmos.rx; -import com.azure.cosmos.BridgeInternal; import com.azure.cosmos.CosmosAsyncClient; import com.azure.cosmos.CosmosAsyncContainer; import com.azure.cosmos.CosmosClientBuilder; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.query.LimitContinuationToken; import com.azure.cosmos.util.CosmosPagedFlux; import com.azure.cosmos.implementation.InternalObjectNode; @@ -224,16 +224,16 @@ public void generateTestData() { for (int i = 0; i < 10; i++) { InternalObjectNode d = new InternalObjectNode(); d.setId(Integer.toString(i)); - BridgeInternal.setProperty(d, field, i); - BridgeInternal.setProperty(d, partitionKey, firstPk); + d.set(field, i, CosmosItemSerializer.DEFAULT_SERIALIZER); + d.set(partitionKey, firstPk, CosmosItemSerializer.DEFAULT_SERIALIZER); docs.add(d); } for (int i = 10; i < 20; i++) { InternalObjectNode d = new InternalObjectNode(); d.setId(Integer.toString(i)); - BridgeInternal.setProperty(d, field, i); - BridgeInternal.setProperty(d, partitionKey, secondPk); + d.set(field, i, CosmosItemSerializer.DEFAULT_SERIALIZER); + d.set(partitionKey, secondPk, CosmosItemSerializer.DEFAULT_SERIALIZER); docs.add(d); } } diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/UniqueIndexTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/UniqueIndexTest.java index 25f801b57844..dfe29f213e6e 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/UniqueIndexTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/UniqueIndexTest.java @@ -138,7 +138,7 @@ public void replaceAndDeleteWithUniqueIndex() throws Exception { InternalObjectNode doc2Inserted = BridgeInternal.getProperties(collection .createItem(doc2, new CosmosItemRequestOptions()) .block()); - InternalObjectNode doc2Replacement = new InternalObjectNode(ModelBridgeInternal.toJsonFromJsonSerializable(doc1Inserted)); + InternalObjectNode doc2Replacement = new InternalObjectNode(doc1Inserted.toJson()); doc2Replacement.setId( doc2Inserted.getId()); try { diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/VeryLargeDocumentQueryTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/VeryLargeDocumentQueryTest.java index 12fa07c758d6..a404d8a76064 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/VeryLargeDocumentQueryTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/VeryLargeDocumentQueryTest.java @@ -5,6 +5,7 @@ import com.azure.cosmos.BridgeInternal; import com.azure.cosmos.CosmosAsyncClient; import com.azure.cosmos.CosmosAsyncContainer; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.models.CosmosItemResponse; import com.azure.cosmos.CosmosClientBuilder; import com.azure.cosmos.util.CosmosPagedFlux; @@ -69,7 +70,7 @@ private void createLargeDocument() { //Keep size as ~ 1.999MB to account for size of other props int size = (int) (ONE_MB * 1.999); - BridgeInternal.setProperty(docDefinition, "largeString", StringUtils.repeat("x", size)); + docDefinition.set("largeString", StringUtils.repeat("x", size), CosmosItemSerializer.DEFAULT_SERIALIZER); Mono> createObservable = createdCollection.createItem(docDefinition, new CosmosItemRequestOptions()); diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/changefeed/epkversion/IncrementalChangeFeedProcessorTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/changefeed/epkversion/IncrementalChangeFeedProcessorTest.java index 6d6a943f1e8b..e836852b7bfb 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/changefeed/epkversion/IncrementalChangeFeedProcessorTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/changefeed/epkversion/IncrementalChangeFeedProcessorTest.java @@ -101,9 +101,9 @@ public class IncrementalChangeFeedProcessorTest extends TestSuiteBase { private final int FEED_COLLECTION_THROUGHPUT = 400; private final int FEED_COLLECTION_THROUGHPUT_FOR_SPLIT = 10100; private final int LEASE_COLLECTION_THROUGHPUT = 400; - private final String MULTI_WRITE_DATABASE_NAME = "multi-write-test-database"; - private final String MULTI_WRITE_MONITORED_COLLECTION_NAME = "multi-write-test-monitored-container"; - private final String MULTI_WRITE_LEASE_COLLECTION_NAME = "multi-write-test-lease-container"; + private final String MULTI_WRITE_DATABASE_NAME = "multi-write-test-database" + UUID.randomUUID(); + private final String MULTI_WRITE_MONITORED_COLLECTION_NAME = "multi-write-test-monitored-container" + UUID.randomUUID(); + private final String MULTI_WRITE_LEASE_COLLECTION_NAME = "multi-write-test-lease-container" + UUID.randomUUID(); private CosmosAsyncClient client; diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/changefeed/pkversion/IncrementalChangeFeedProcessorTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/changefeed/pkversion/IncrementalChangeFeedProcessorTest.java index e5bf60e9420b..e85caba7dad4 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/changefeed/pkversion/IncrementalChangeFeedProcessorTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/changefeed/pkversion/IncrementalChangeFeedProcessorTest.java @@ -86,9 +86,9 @@ public class IncrementalChangeFeedProcessorTest extends TestSuiteBase { private final int FEED_COLLECTION_THROUGHPUT = 400; private final int FEED_COLLECTION_THROUGHPUT_FOR_SPLIT = 10100; private final int LEASE_COLLECTION_THROUGHPUT = 400; - private final String MULTI_WRITE_DATABASE_NAME = "multi-write-test-database"; - private final String MULTI_WRITE_MONITORED_COLLECTION_NAME = "multi-write-test-monitored-container"; - private final String MULTI_WRITE_LEASE_COLLECTION_NAME = "multi-write-test-lease-container"; + private final String MULTI_WRITE_DATABASE_NAME = "multi-write-test-database"+ UUID.randomUUID(); + private final String MULTI_WRITE_MONITORED_COLLECTION_NAME = "multi-write-test-monitored-container"+ UUID.randomUUID(); + private final String MULTI_WRITE_LEASE_COLLECTION_NAME = "multi-write-test-lease-container"+ UUID.randomUUID(); private CosmosAsyncClient client; diff --git a/sdk/cosmos/azure-cosmos/CHANGELOG.md b/sdk/cosmos/azure-cosmos/CHANGELOG.md index 385f7962bc8d..8657d901fbc7 100644 --- a/sdk/cosmos/azure-cosmos/CHANGELOG.md +++ b/sdk/cosmos/azure-cosmos/CHANGELOG.md @@ -3,7 +3,8 @@ ### 4.59.0-beta.1 (Unreleased) #### Features Added - +* Added public APIs `getCustomeSerializer` and `setCustomSerializer` to allow customers to specify custom payload transformations or serialization settings. - See [PR 38997](https://github.com/Azure/azure-sdk-for-java/pull/38997) + #### Breaking Changes #### Bugs Fixed diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/BridgeInternal.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/BridgeInternal.java index bdc8299a907b..e1394f429fd0 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/BridgeInternal.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/BridgeInternal.java @@ -9,12 +9,10 @@ import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.CosmosError; import com.azure.cosmos.implementation.DatabaseAccount; -import com.azure.cosmos.implementation.Document; import com.azure.cosmos.implementation.FeedResponseDiagnostics; import com.azure.cosmos.implementation.GlobalEndpointManager; import com.azure.cosmos.implementation.ImplementationBridgeHelpers; import com.azure.cosmos.implementation.InternalObjectNode; -import com.azure.cosmos.implementation.JsonSerializable; import com.azure.cosmos.implementation.MetadataDiagnosticsContext; import com.azure.cosmos.implementation.QueryMetrics; import com.azure.cosmos.implementation.ReplicationPolicy; @@ -43,21 +41,16 @@ import com.azure.cosmos.models.ModelBridgeInternal; import com.azure.cosmos.models.PartitionKey; import com.azure.cosmos.models.SqlQuerySpec; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; import io.micrometer.core.instrument.MeterRegistry; import java.net.URI; import java.time.Duration; -import java.time.Instant; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentMap; -import java.util.function.Function; import static com.azure.cosmos.implementation.Warning.INTERNAL_USE_ONLY_WARNING; @@ -88,11 +81,6 @@ public static String getServiceEndpoint(CosmosAsyncClient cosmosAsyncClient) { return cosmosAsyncClient.getServiceEndpoint(); } - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static Document documentFromObject(Object document, ObjectMapper mapper) { - return Document.fromObject(document, mapper); - } - @Warning(value = INTERNAL_USE_ONLY_WARNING) public static void monitorTelemetry(MeterRegistry registry) { CosmosAsyncClient.setMonitorTelemetry(registry); @@ -104,18 +92,6 @@ public static ResourceResponse toResourceResponse(RxDocu return new ResourceResponse<>(response, cls); } - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static FeedResponse toFeedResponsePage( - RxDocumentServiceResponse response, - Function factoryMethod, - Class cls) { - - FeedResponse feedResponse = ModelBridgeInternal.toFeedResponsePage(response, factoryMethod, cls); - applyDiagnosticsToFeedResponse(response.getCosmosDiagnostics(), feedResponse); - - return feedResponse; - } - private static FeedResponse applyDiagnosticsToFeedResponse(CosmosDiagnostics diagnostics, FeedResponse response) { if (diagnostics == null || diagnostics == response.getCosmosDiagnostics()) { return response; @@ -149,18 +125,6 @@ public static FeedResponse toFeedResponsePage( return feedResponseWithQueryMetrics; } - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static FeedResponse toChangeFeedResponsePage( - RxDocumentServiceResponse response, - Function factoryMethod, - Class cls) { - - FeedResponse feedResponse = ModelBridgeInternal.toChangeFeedResponsePage(response, factoryMethod, cls); - applyDiagnosticsToFeedResponse(response.getCosmosDiagnostics(), feedResponse); - - return feedResponse; - } - @Warning(value = INTERNAL_USE_ONLY_WARNING) public static StoredProcedureResponse toStoredProcedureResponse(RxDocumentServiceResponse response) { return new StoredProcedureResponse(response); @@ -370,12 +334,12 @@ public static Map getRequestHeaders( @Warning(value = INTERNAL_USE_ONLY_WARNING) public static String getAltLink(Resource resource) { - return ModelBridgeInternal.getAltLink(resource); + return resource.getAltLink(); } @Warning(value = INTERNAL_USE_ONLY_WARNING) public static void setAltLink(Resource resource, String altLink) { - ModelBridgeInternal.setAltLink(resource, altLink); + resource.setAltLink(altLink); } @Warning(value = INTERNAL_USE_ONLY_WARNING) @@ -419,31 +383,11 @@ public static PartitionKey getPartitionKey(PartitionKeyInternal partitionKeyInte return new PartitionKey(partitionKeyInternal); } - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static void setProperty(JsonSerializable jsonSerializable, String propertyName, T value) { - ModelBridgeInternal.setProperty(jsonSerializable, propertyName, value); - } - - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static ObjectNode getObject(JsonSerializable jsonSerializable, String propertyName) { - return ModelBridgeInternal.getObjectNodeFromJsonSerializable(jsonSerializable, propertyName); - } - - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static void remove(JsonSerializable jsonSerializable, String propertyName) { - ModelBridgeInternal.removeFromJsonSerializable(jsonSerializable, propertyName); - } - @Warning(value = INTERNAL_USE_ONLY_WARNING) public static CosmosStoredProcedureProperties createCosmosStoredProcedureProperties(String jsonString) { return ModelBridgeInternal.createCosmosStoredProcedureProperties(jsonString); } - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static Object getValue(JsonNode value) { - return ModelBridgeInternal.getValue(value); - } - @Warning(value = INTERNAL_USE_ONLY_WARNING) public static CosmosException setCosmosDiagnostics( CosmosException cosmosException, @@ -460,7 +404,10 @@ public static CosmosException createCosmosException(int statusCode) { public static CosmosException createCosmosException(int statusCode, String errorMessage) { CosmosException cosmosException = new CosmosException(statusCode, errorMessage, null, null); cosmosException.setError(new CosmosError()); - ModelBridgeInternal.setProperty(cosmosException.getError(), Constants.Properties.MESSAGE, errorMessage); + cosmosException.getError().set( + Constants.Properties.MESSAGE, + errorMessage, + CosmosItemSerializer.DEFAULT_SERIALIZER); return cosmosException; } @@ -513,16 +460,6 @@ public static String extractContainerSelfLink(CosmosAsyncContainer container) { return container.getLink(); } - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static void setResourceSelfLink(Resource resource, String selfLink) { - ModelBridgeInternal.setResourceSelfLink(resource, selfLink); - } - - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static void setTimestamp(Resource resource, Instant date) { - ModelBridgeInternal.setTimestamp(resource, date); - } - @Warning(value = INTERNAL_USE_ONLY_WARNING) public static ClientSideRequestStatistics getClientSideRequestStatics(CosmosDiagnostics cosmosDiagnostics) { ClientSideRequestStatistics clientSideRequestStatistics = null; diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java index ec9f0053f86b..d4a289a48b00 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncClient.java @@ -105,6 +105,7 @@ public final class CosmosAsyncClient implements Closeable { ImplementationBridgeHelpers.CosmosContainerIdentityHelper.getCosmosContainerIdentityAccessor(); private final ConsistencyLevel accountConsistencyLevel; private final WriteRetryPolicy nonIdempotentWriteRetryPolicy; + private final CosmosItemSerializer defaultCustomSerializer; CosmosAsyncClient(CosmosClientBuilder builder) { // Async Cosmos client wrapper @@ -121,6 +122,7 @@ public final class CosmosAsyncClient implements Closeable { boolean enableTransportClientSharing = builder.isConnectionSharingAcrossClientsEnabled(); this.proactiveContainerInitConfig = builder.getProactiveContainerInitConfig(); this.nonIdempotentWriteRetryPolicy = builder.getNonIdempotentWriteRetryPolicy(); + this.defaultCustomSerializer = builder.getCustomSerializer(); CosmosEndToEndOperationLatencyPolicyConfig endToEndOperationLatencyPolicyConfig = builder.getEndToEndOperationConfig(); SessionRetryOptions sessionRetryOptions = builder.getSessionRetryOptions(); @@ -167,6 +169,7 @@ public final class CosmosAsyncClient implements Closeable { .withEndToEndOperationLatencyPolicyConfig(endToEndOperationLatencyPolicyConfig) .withSessionRetryOptions(sessionRetryOptions) .withContainerProactiveInitConfig(this.proactiveContainerInitConfig) + .withDefaultSerializer(this.defaultCustomSerializer) .build(); this.accountConsistencyLevel = this.asyncDocumentClient.getDefaultConsistencyLevelOfAccount(); @@ -761,6 +764,10 @@ CosmosDiagnosticsThresholds getEffectiveDiagnosticsThresholds( return clientLevelThresholds != null ? clientLevelThresholds : new CosmosDiagnosticsThresholds(); } + CosmosItemSerializer getEffectiveItemSerializer(CosmosItemSerializer requestOptionsItemSerializer) { + return this.asyncDocumentClient.getEffectiveItemSerializer(requestOptionsItemSerializer); + } + boolean isTransportLevelTracingEnabled() { CosmosClientTelemetryConfig effectiveConfig = this.clientTelemetryConfig != null ? @@ -894,6 +901,11 @@ public CosmosDiagnosticsThresholds getEffectiveDiagnosticsThresholds( public DiagnosticsProvider getDiagnosticsProvider(CosmosAsyncClient client) { return client.getDiagnosticsProvider(); } + + @Override + public CosmosItemSerializer getEffectiveItemSerializer(CosmosAsyncClient client, CosmosItemSerializer requestOptionsItemSerializer) { + return client.getEffectiveItemSerializer(requestOptionsItemSerializer); + } } ); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncContainer.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncContainer.java index 3503abe940e7..499b02c591ca 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncContainer.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncContainer.java @@ -14,7 +14,6 @@ import com.azure.cosmos.implementation.HttpConstants; import com.azure.cosmos.implementation.ImplementationBridgeHelpers; import com.azure.cosmos.implementation.InternalObjectNode; -import com.azure.cosmos.implementation.ItemDeserializer; import com.azure.cosmos.implementation.Offer; import com.azure.cosmos.implementation.OperationType; import com.azure.cosmos.implementation.PartitionKeyHelper; @@ -395,8 +394,8 @@ private Mono> replaceItemWithTrackingId(Class itemT .readDocument(getItemLink(itemId), requestOptions) .map(response -> { mergeDiagnostics(response, cosmosException); - return ModelBridgeInternal - .createCosmosAsyncItemResponse(response, itemType, getItemDeserializer()); + return itemResponseAccessor + .createCosmosItemResponse(response, itemType, requestOptions.getEffectiveItemSerializer()); }) .single(); @@ -477,9 +476,9 @@ private Mono> createItemWithTrackingId( return clientWrapper.readDocument(getItemLink(itemId), readRequestOptions) .map(response -> { mergeDiagnostics(response, cosmosException); - return ModelBridgeInternal - .createCosmosAsyncItemResponse( - response, itemType, getItemDeserializer()); + return itemResponseAccessor + .createCosmosItemResponse( + response, itemType, readRequestOptions.getEffectiveItemSerializer()); }).single(); }); @@ -527,8 +526,11 @@ private Mono> createItemInternal(T item, CosmosItemReq Mono> responseMono; String trackingId = null; CosmosItemRequestOptions effectiveOptions = getEffectiveOptions(nonIdempotentWriteRetryPolicy, options); + CosmosItemSerializer effectiveItemSerializer = + this.database.getClient().getEffectiveItemSerializer(effectiveOptions.getCustomSerializer()); + RequestOptions requestOptions = + itemOptionsAccessor.toRequestOptions(effectiveOptions, effectiveItemSerializer); - RequestOptions requestOptions = ModelBridgeInternal.toRequestOptions(effectiveOptions); if (nonIdempotentWriteRetryPolicy.isEnabled() && nonIdempotentWriteRetryPolicy.useTrackingIdProperty()) { trackingId = UUID.randomUUID().toString(); responseMono = createItemWithTrackingId(item, requestOptions, trackingId); @@ -567,7 +569,7 @@ private Mono> createItemInternalCore( item, requestOptions, true) - .map(response -> ModelBridgeInternal.createCosmosAsyncItemResponse(response, itemType, getItemDeserializer())) + .map(response -> itemResponseAccessor.createCosmosItemResponse(response, itemType, requestOptions.getEffectiveItemSerializer())) .single(); } @@ -1358,7 +1360,10 @@ public Mono> readItem( } ModelBridgeInternal.setPartitionKey(options, partitionKey); - RequestOptions requestOptions = ModelBridgeInternal.toRequestOptions(options); + CosmosItemSerializer effectiveItemSerializer = + this.database.getClient().getEffectiveItemSerializer(options.getCustomSerializer()); + RequestOptions requestOptions = + itemOptionsAccessor.toRequestOptions(options, effectiveItemSerializer); return withContext(context -> readItemInternal(itemId, requestOptions, itemType, context)); } @@ -1823,7 +1828,10 @@ public Mono> deleteAllItemsByPartitionKey(PartitionKe options = new CosmosItemRequestOptions(); } ModelBridgeInternal.setPartitionKey(options, partitionKey); - RequestOptions requestOptions = ModelBridgeInternal.toRequestOptions(options); + CosmosItemSerializer effectiveItemSerializer = + this.database.getClient().getEffectiveItemSerializer(options.getCustomSerializer()); + RequestOptions requestOptions = + itemOptionsAccessor.toRequestOptions(options, effectiveItemSerializer); return withContext(context -> deleteAllItemsByPartitionKeyInternal(partitionKey, requestOptions, context)); } @@ -2074,7 +2082,10 @@ private Mono> deleteItemInternal( CosmosItemRequestOptions effectiveOptions = getEffectiveOptions(nonIdempotentWriteRetryPolicy, options); - RequestOptions requestOptions = ModelBridgeInternal.toRequestOptions(effectiveOptions); + CosmosItemSerializer effectiveItemSerializer = + this.database.getClient().getEffectiveItemSerializer(effectiveOptions.getCustomSerializer()); + RequestOptions requestOptions = + itemOptionsAccessor.toRequestOptions(effectiveOptions, effectiveItemSerializer); return this.deleteItemInternalCore(itemId, internalObjectNode, requestOptions, context); } @@ -2087,7 +2098,7 @@ private Mono> deleteItemInternalCore( Mono> responseMono = this.getDatabase() .getDocClientWrapper() .deleteDocument(getItemLink(itemId), internalObjectNode, requestOptions) - .map(response -> ModelBridgeInternal.createCosmosAsyncItemResponseWithObjectType(response)) + .map(response -> itemResponseAccessor.createCosmosItemResponse(response, Object.class, CosmosItemSerializer.DEFAULT_SERIALIZER)) .single(); CosmosAsyncClient client = database.getClient(); return client @@ -2113,7 +2124,7 @@ private Mono> deleteAllItemsByPartitionKeyInternal( Mono> responseMono = this.getDatabase() .getDocClientWrapper() .deleteAllDocumentsByPartitionKey(getLink(), partitionKey, requestOptions) - .map(response -> ModelBridgeInternal.createCosmosAsyncItemResponseWithObjectType(response)) + .map(response -> itemResponseAccessor.createCosmosItemResponse(response, Object.class, CosmosItemSerializer.DEFAULT_SERIALIZER)) .single(); CosmosAsyncClient client = database.getClient(); return client @@ -2144,7 +2155,7 @@ private Mono> replaceItemInternalCore( return this.getDatabase() .getDocClientWrapper() .replaceDocument(getItemLink(itemId), doc, requestOptions) - .map(response -> ModelBridgeInternal.createCosmosAsyncItemResponse(response, itemType, getItemDeserializer())) + .map(response -> itemResponseAccessor.createCosmosItemResponse(response, itemType, requestOptions.getEffectiveItemSerializer())) .single(); } @@ -2187,7 +2198,10 @@ private Mono> replaceItemInternal( true); CosmosItemRequestOptions effectiveOptions = getEffectiveOptions(nonIdempotentWriteRetryPolicy, options); - RequestOptions requestOptions = ModelBridgeInternal.toRequestOptions(effectiveOptions); + CosmosItemSerializer effectiveItemSerializer = + this.database.getClient().getEffectiveItemSerializer(effectiveOptions.getCustomSerializer()); + RequestOptions requestOptions = + itemOptionsAccessor.toRequestOptions(effectiveOptions, effectiveItemSerializer); Mono> responseMono; String trackingId = null; @@ -2228,8 +2242,9 @@ private Mono> patchItemInternal( options, this.database.getClient().getNonIdempotentWriteRetryPolicy(), false); - - RequestOptions requestOptions = ModelBridgeInternal.toRequestOptions(options); + CosmosItemSerializer effectiveItemSerializer = + this.database.getClient().getEffectiveItemSerializer(options != null ? options.getCustomSerializer() : null); + RequestOptions requestOptions = itemOptionsAccessor.toRequestOptions(options, effectiveItemSerializer); if (nonIdempotentWriteRetryPolicy.isEnabled()) { requestOptions.setNonIdempotentWriteRetriesEnabled(true); } @@ -2237,7 +2252,7 @@ private Mono> patchItemInternal( Mono> responseMono = this.getDatabase() .getDocClientWrapper() .patchDocument(getItemLink(itemId), cosmosPatchOperations, requestOptions) - .map(response -> ModelBridgeInternal.createCosmosAsyncItemResponse(response, itemType, getItemDeserializer())); + .map(response -> itemResponseAccessor.createCosmosItemResponse(response, itemType, requestOptions.getEffectiveItemSerializer())); CosmosAsyncClient client = database .getClient(); @@ -2268,15 +2283,17 @@ private Mono> upsertItemInternal(T item, CosmosItemReq true); CosmosItemRequestOptions effectiveOptions = getEffectiveOptions(nonIdempotentWriteRetryPolicy, options); - - RequestOptions requestOptions = ModelBridgeInternal.toRequestOptions(effectiveOptions); + CosmosItemSerializer effectiveItemSerializer = + this.database.getClient().getEffectiveItemSerializer(effectiveOptions.getCustomSerializer()); + RequestOptions requestOptions = + itemOptionsAccessor.toRequestOptions(effectiveOptions, effectiveItemSerializer); Mono> responseMono = this.getDatabase().getDocClientWrapper() .upsertDocument(this.getLink(), item, requestOptions, true) - .map(response -> ModelBridgeInternal.createCosmosAsyncItemResponse( - response, itemType, getItemDeserializer())) + .map(response -> itemResponseAccessor.createCosmosItemResponse( + response, itemType, requestOptions.getEffectiveItemSerializer())) .single(); CosmosAsyncClient client = database .getClient(); @@ -2302,7 +2319,7 @@ private Mono> readItemInternal( Context context) { Mono> responseMono = this.getDatabase().getDocClientWrapper() .readDocument(getItemLink(itemId), requestOptions) - .map(response -> ModelBridgeInternal.createCosmosAsyncItemResponse(response, itemType, getItemDeserializer())) + .map(response -> itemResponseAccessor.createCosmosItemResponse(response, itemType, requestOptions.getEffectiveItemSerializer())) .single(); CosmosAsyncClient client = database .getClient(); @@ -2530,10 +2547,6 @@ private Mono replaceThroughputInternal(Mono CosmosPagedFlux queryChangeFeedInternal( - CosmosAsyncContainer container, - CosmosChangeFeedRequestOptions changeFeedRequestOptions, - Transformer transformer) { - - return UtilBridgeInternal.createCosmosPagedFlux( - transformer.transform( - container.queryChangeFeedInternalFunc( - changeFeedRequestOptions, - JsonNode.class))); - } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosClientBuilder.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosClientBuilder.java index 87a9731c6eff..5b5722a14905 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosClientBuilder.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosClientBuilder.java @@ -143,6 +143,7 @@ public class CosmosClientBuilder implements private CosmosEndToEndOperationLatencyPolicyConfig cosmosEndToEndOperationLatencyPolicyConfig; private SessionRetryOptions sessionRetryOptions; private Supplier cosmosExcludedRegionsSupplier; + private CosmosItemSerializer defaultCustomSerializer; /** * Instantiates a new Cosmos client builder. @@ -743,7 +744,7 @@ public CosmosClientBuilder readRequestsFallbackEnabled(boolean readRequestsFallb * on their own. * @return the CosmosItemRequestOptions */ - CosmosClientBuilder setNonIdempotentWriteRetryPolicy( + public CosmosClientBuilder nonIdempotentWriteRetryPolicy( boolean nonIdempotentWriteRetriesEnabled, boolean useTrackingIdPropertyForCreateAndReplace) { @@ -1062,6 +1063,23 @@ public CosmosClientBuilder clientTelemetryConfig(CosmosClientTelemetryConfig tel return this; } + /** + * Sets a custom serializer that should be used for conversion between POJOs and Json payload stored in the + * Cosmos DB service. The custom serializer can also be specified in request options. If defined here and + * in request options the serializer defined in request options will be used. + * @param serializer the custom serialzier to be used for payload transformations + * @return current CosmosClientBuilder + */ + public CosmosClientBuilder customSerializer(CosmosItemSerializer serializer) { + this.defaultCustomSerializer = serializer; + + return this; + } + + CosmosItemSerializer getCustomSerializer() { + return this.defaultCustomSerializer; + } + /** * Builds a cosmos async client with the provided properties * @@ -1298,6 +1316,11 @@ public ConsistencyLevel getConsistencyLevel(CosmosClientBuilder builder) { public String getEndpoint(CosmosClientBuilder builder) { return builder.getEndpoint(); } + + @Override + public CosmosItemSerializer getDefaultCustomSerializer(CosmosClientBuilder builder) { + return builder.getCustomSerializer(); + } }); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosException.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosException.java index 6eeb335be4d3..b53db5fb5465 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosException.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosException.java @@ -16,7 +16,6 @@ import com.azure.cosmos.implementation.directconnectivity.rntbd.RntbdChannelAcquisitionTimeline; import com.azure.cosmos.implementation.directconnectivity.rntbd.RntbdChannelStatistics; import com.azure.cosmos.implementation.directconnectivity.rntbd.RntbdEndpointStatistics; -import com.azure.cosmos.models.ModelBridgeInternal; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -184,7 +183,7 @@ protected CosmosException(int statusCode, String message, Map re protected CosmosException(int statusCode, String errorMessage) { this(statusCode, errorMessage, null, null); this.cosmosError = new CosmosError(); - ModelBridgeInternal.setProperty(cosmosError, Constants.Properties.MESSAGE, errorMessage); + cosmosError.set(Constants.Properties.MESSAGE, errorMessage, CosmosItemSerializer.DEFAULT_SERIALIZER); } /** @@ -309,9 +308,11 @@ public int getStatusCode() { } /** - * Gets the sub status code. + * Gets the sub status code. The sub status code is exposed for informational purposes only - new sub status codes + * can be added anytime and applications should never take a dependency on certain sub status codes. For + * applications treating errors based on status code is sufficient. * - * @return the status code. + * @return the sub status code. */ public int getSubStatusCode() { int code = HttpConstants.SubStatusCodes.UNKNOWN; @@ -489,8 +490,7 @@ String innerErrorMessage() { if (cosmosError != null) { innerErrorMessage = cosmosError.getMessage(); if (innerErrorMessage == null) { - innerErrorMessage = String.valueOf( - ModelBridgeInternal.getObjectFromJsonSerializable(cosmosError, "Errors")); + innerErrorMessage = String.valueOf(cosmosError.get("Errors")); } } // if cosmosError is null as well, try to get the underlying error from the internal cause diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosItemSerializer.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosItemSerializer.java new file mode 100644 index 000000000000..27f3130ec21d --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosItemSerializer.java @@ -0,0 +1,127 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos; + +import com.azure.cosmos.implementation.JsonSerializable; +import com.azure.cosmos.implementation.ObjectNodeMap; +import com.azure.cosmos.implementation.PrimitiveJsonNodeMap; +import com.azure.cosmos.implementation.Utils; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import java.io.IOException; +import java.util.Map; + +/** + * The {@link CosmosItemSerializer} allows customizing the serialization of Cosmos Items - either to transform payload (for + * example wrap/unwrap in custom envelopes) or use custom serialization settings or json serializer stacks. + */ +public abstract class CosmosItemSerializer { + private final static ObjectMapper objectMapper = Utils.getSimpleObjectMapper(); + + /** + * Gets the default Cosmos item serializer. This serializer is used by default when no custom serializer is + * specified on request options or the {@link CosmosClientBuilder} + */ + public final static CosmosItemSerializer DEFAULT_SERIALIZER = new DefaultCosmosItemSerializer(); + + /** + * Used to instantiate subclasses + */ + protected CosmosItemSerializer() { + } + + /** + * Used to serialize a POJO into a json tree + * @param item the POJO to be serialized + * @return the json tree that will be used as payload in Cosmos DB items + * @param The type of the POJO + */ + public abstract Map serialize(T item); + + /** + * Used to deserialize the json tree stored in the Cosmos DB item as a POJO + * @param jsonNodeMap the json tree from the Cosmos DB item + * @param classType The type of the POJO + * @return The deserialized POJO + * @param The type of the POJO + */ + public abstract T deserialize(Map jsonNodeMap, Class classType); + + private static class DefaultCosmosItemSerializer extends CosmosItemSerializer { + DefaultCosmosItemSerializer() { + super(); + } + + /** + * Used to serialize a POJO into a json tree + * @param item the POJO to be serialized + * @return the json tree that will be used as payload in Cosmos DB items + * @param The type of the POJO + */ + @Override + @SuppressWarnings("unchecked") + public Map serialize(T item) { + if (item == null) { + return null; + } + + if (item instanceof ObjectNode) { + return new ObjectNodeMap((ObjectNode)item); + } + + if (item instanceof JsonSerializable) { + return ((JsonSerializable)item).getMap(); + } + + JsonNode jsonNode = objectMapper.convertValue(item, JsonNode.class); + if (jsonNode == null) { + return null; + } + + if (jsonNode.isObject()) { + return new ObjectNodeMap((ObjectNode)jsonNode); + } + + return new PrimitiveJsonNodeMap(jsonNode); + } + + /** + * Used to deserialize the json tree stored in the Cosmos DB item as a POJO + * @param jsonNodeMap the json tree from the Cosmos DB item + * @param classType The type of the POJO + * @return The deserialized POJO + * @param The type of the POJO + */ + @Override + @SuppressWarnings("unchecked") + public T deserialize(Map jsonNodeMap, Class classType) { + if (jsonNodeMap == null) { + return null; + } + + ObjectNode jsonNode = null; + try { + if (jsonNodeMap instanceof ObjectNodeMap) { + jsonNode = ((ObjectNodeMap)jsonNodeMap).getObjectNode(); + } else if (jsonNodeMap instanceof PrimitiveJsonNodeMap) { + return objectMapper.convertValue( + ((PrimitiveJsonNodeMap)jsonNodeMap).getPrimitiveJsonNode(), + classType); + } else { + jsonNode = objectMapper.convertValue(jsonNodeMap, ObjectNode.class); + } + + if (JsonSerializable.class.isAssignableFrom(classType)) { + return (T)JsonSerializable.instantiateFromObjectNodeAndType(jsonNode, classType); + } + + return objectMapper.treeToValue(jsonNode, classType); + } catch (IOException e) { + throw new IllegalStateException(String.format("Unable to parse JSON %s as %s", jsonNode, classType.getName()), e); + } + } + } +} diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/AsyncDocumentClient.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/AsyncDocumentClient.java index a9a197055f57..50c2aacdd05d 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/AsyncDocumentClient.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/AsyncDocumentClient.java @@ -7,6 +7,7 @@ import com.azure.cosmos.ConsistencyLevel; import com.azure.cosmos.CosmosContainerProactiveInitConfig; import com.azure.cosmos.CosmosEndToEndOperationLatencyPolicyConfig; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.SessionRetryOptions; import com.azure.cosmos.implementation.apachecommons.lang.StringUtils; import com.azure.cosmos.implementation.batch.ServerBatchRequest; @@ -104,6 +105,7 @@ class Builder { private CosmosEndToEndOperationLatencyPolicyConfig cosmosEndToEndOperationLatencyPolicyConfig; private SessionRetryOptions sessionRetryOptions; private CosmosContainerProactiveInitConfig containerProactiveInitConfig; + private CosmosItemSerializer defaultCustomSerializer; public Builder withServiceEndpoint(String serviceEndpoint) { try { @@ -114,6 +116,12 @@ public Builder withServiceEndpoint(String serviceEndpoint) { return this; } + public Builder withDefaultSerializer( CosmosItemSerializer defaultCustomSerializer) { + this.defaultCustomSerializer = defaultCustomSerializer; + + return this; + } + public Builder withState(CosmosClientMetadataCachesSnapshot state) { this.state = state; return this; @@ -290,7 +298,8 @@ public AsyncDocumentClient build() { clientCorrelationId, cosmosEndToEndOperationLatencyPolicyConfig, sessionRetryOptions, - containerProactiveInitConfig); + containerProactiveInitConfig, + defaultCustomSerializer); client.init(state, null); return client; @@ -1576,7 +1585,7 @@ Flux> readAllDocuments( */ void close(); - ItemDeserializer getItemDeserializer(); + CosmosItemSerializer getEffectiveItemSerializer(CosmosItemSerializer requestOptionsItemSerializer); /** * Enable throughput control group. diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ChangeFeedQueryImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ChangeFeedQueryImpl.java index 1f4b462ebdcd..4b9f14b103ac 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ChangeFeedQueryImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ChangeFeedQueryImpl.java @@ -3,10 +3,10 @@ package com.azure.cosmos.implementation; import com.azure.cosmos.BridgeInternal; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.changefeed.common.ChangeFeedState; import com.azure.cosmos.implementation.changefeed.common.ChangeFeedStateV1; import com.azure.cosmos.implementation.feedranges.FeedRangeInternal; -import com.azure.cosmos.implementation.query.DocumentQueryExecutionContextBase; import com.azure.cosmos.implementation.query.Paginator; import com.azure.cosmos.implementation.spark.OperationContext; import com.azure.cosmos.implementation.spark.OperationContextAndListenerTuple; @@ -14,7 +14,6 @@ import com.azure.cosmos.models.CosmosChangeFeedRequestOptions; import com.azure.cosmos.models.FeedResponse; import com.azure.cosmos.models.ModelBridgeInternal; -import com.fasterxml.jackson.databind.JsonNode; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -27,6 +26,10 @@ class ChangeFeedQueryImpl { + private final static + ImplementationBridgeHelpers.FeedResponseHelper.FeedResponseAccessor feedResponseAccessor = + ImplementationBridgeHelpers.FeedResponseHelper.getFeedResponseAccessor(); + private static final int INITIAL_TOP_VALUE = -1; private final RxDocumentClientImpl client; @@ -39,7 +42,7 @@ class ChangeFeedQueryImpl { private final ResourceType resourceType; private final ChangeFeedState changeFeedState; private final OperationContextAndListenerTuple operationContextAndListener; - private final Function factoryMethod; + private final CosmosItemSerializer itemSerializer; public ChangeFeedQueryImpl( RxDocumentClientImpl client, @@ -72,8 +75,7 @@ public ChangeFeedQueryImpl( this.klass = klass; this.documentsLink = Utils.joinPath(collectionLink, Paths.DOCUMENTS_PATH_SEGMENT); this.options = requestOptions; - this.factoryMethod = DocumentQueryExecutionContextBase - .getEffectiveFactoryMethod(options, klass); + this.itemSerializer = client.getEffectiveItemSerializer(requestOptions.getCustomSerializer()); this.operationContextAndListener = ImplementationBridgeHelpers .CosmosChangeFeedRequestOptionsHelper .getCosmosChangeFeedRequestOptionsAccessor() @@ -140,9 +142,7 @@ private RxDocumentServiceRequest createDocumentServiceRequest() { private Mono> executeRequestAsync(RxDocumentServiceRequest request) { if (this.operationContextAndListener == null) { return client.readFeed(request) - .map(rsp -> { - return BridgeInternal.toChangeFeedResponsePage(rsp, this.factoryMethod, klass); - }); + .map(rsp -> feedResponseAccessor.createChangeFeedResponse(rsp, this.itemSerializer, klass)); } else { final OperationListener listener = operationContextAndListener.getOperationListener(); final OperationContext operationContext = operationContextAndListener.getOperationContext(); @@ -155,8 +155,8 @@ private Mono> executeRequestAsync(RxDocumentServiceRequest reque .map(rsp -> { listener.responseListener(operationContext, rsp); - final FeedResponse feedResponse = BridgeInternal.toChangeFeedResponsePage( - rsp, this.factoryMethod, klass); + final FeedResponse feedResponse = feedResponseAccessor.createChangeFeedResponse( + rsp, this.itemSerializer, klass); Map rspHeaders = feedResponse.getResponseHeaders(); String requestPkRangeId = null; diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ClientEncryptionKey.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ClientEncryptionKey.java index 68d13be0571a..f3652f3ecade 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ClientEncryptionKey.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ClientEncryptionKey.java @@ -3,7 +3,7 @@ package com.azure.cosmos.implementation; -import com.azure.cosmos.BridgeInternal; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.models.EncryptionKeyWrapMetadata; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -44,8 +44,10 @@ public String getEncryptionAlgorithm() { public void setEncryptionAlgorithm(String encryptionAlgorithm) { this.encryptionAlgorithm = encryptionAlgorithm; - BridgeInternal.setProperty(this, Constants.Properties.ENCRYPTION_ALGORITHM, - encryptionAlgorithm); + this.set( + Constants.Properties.ENCRYPTION_ALGORITHM, + encryptionAlgorithm, + CosmosItemSerializer.DEFAULT_SERIALIZER); } public byte[] getWrappedDataEncryptionKey() { @@ -60,8 +62,10 @@ public byte[] getWrappedDataEncryptionKey() { public void setWrappedDataEncryptionKey(byte[] wrappedDataEncryptionKey) { this.wrappedDataEncryptionKey = wrappedDataEncryptionKey; - BridgeInternal.setProperty(this, Constants.Properties.WRAPPED_DATA_ENCRYPTION_KEY, - this.wrappedDataEncryptionKey); + this.set( + Constants.Properties.WRAPPED_DATA_ENCRYPTION_KEY, + this.wrappedDataEncryptionKey, + CosmosItemSerializer.DEFAULT_SERIALIZER); } public EncryptionKeyWrapMetadata getEncryptionKeyWrapMetadata() { @@ -76,8 +80,10 @@ public EncryptionKeyWrapMetadata getEncryptionKeyWrapMetadata() { public void setEncryptionKeyWrapMetadata(EncryptionKeyWrapMetadata encryptionKeyWrapMetadata) { this.encryptionKeyWrapMetadata = encryptionKeyWrapMetadata; - BridgeInternal.setProperty(this, Constants.Properties.KEY_WRAP_METADATA, - this.encryptionKeyWrapMetadata); + this.set( + Constants.Properties.KEY_WRAP_METADATA, + this.encryptionKeyWrapMetadata, + CosmosItemSerializer.DEFAULT_SERIALIZER); } @Override diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ConsistencyPolicy.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ConsistencyPolicy.java index 87e14889d0d1..8f8b8a23c3da 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ConsistencyPolicy.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ConsistencyPolicy.java @@ -6,6 +6,7 @@ import com.azure.cosmos.BridgeInternal; import com.azure.cosmos.ConsistencyLevel; +import com.azure.cosmos.CosmosItemSerializer; import com.fasterxml.jackson.databind.node.ObjectNode; import java.time.Duration; @@ -76,7 +77,10 @@ public ConsistencyLevel getDefaultConsistencyLevel() { */ public ConsistencyPolicy setDefaultConsistencyLevel(ConsistencyLevel level) { this.consistencyLevel = level; - super.set(Constants.Properties.DEFAULT_CONSISTENCY_LEVEL, level.toString()); + super.set( + Constants.Properties.DEFAULT_CONSISTENCY_LEVEL, + level.toString(), + CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } @@ -102,7 +106,10 @@ public int getMaxStalenessPrefix() { * @return the ConsistencyPolicy. */ public ConsistencyPolicy setMaxStalenessPrefix(int maxStalenessPrefix) { - super.set(Constants.Properties.MAX_STALENESS_PREFIX, maxStalenessPrefix); + super.set( + Constants.Properties.MAX_STALENESS_PREFIX, + maxStalenessPrefix, + CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } @@ -131,7 +138,10 @@ public ConsistencyPolicy setMaxStalenessInterval(Duration maxStalenessInterval) if (maxStalenessInterval == null) { throw new IllegalArgumentException("maxStalenessInterval should not be null"); } - super.set(Constants.Properties.MAX_STALENESS_INTERVAL_IN_SECONDS, maxStalenessInterval.getSeconds()); + super.set( + Constants.Properties.MAX_STALENESS_INTERVAL_IN_SECONDS, + maxStalenessInterval.getSeconds(), + CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/CosmosError.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/CosmosError.java index b9d3913912a2..87d41d077984 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/CosmosError.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/CosmosError.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation; +import com.azure.cosmos.CosmosItemSerializer; import com.fasterxml.jackson.databind.node.ObjectNode; /** @@ -74,7 +75,7 @@ public String getCode() { * @param code the error code. */ private void setCode(String code) { - super.set(Constants.Properties.CODE, code); + super.set(Constants.Properties.CODE, code, CosmosItemSerializer.DEFAULT_SERIALIZER); } /** @@ -92,7 +93,7 @@ public String getMessage() { * @param message the error message. */ private void setMessage(String message) { - super.set(Constants.Properties.MESSAGE, message); + super.set(Constants.Properties.MESSAGE, message, CosmosItemSerializer.DEFAULT_SERIALIZER); } /** @@ -110,7 +111,10 @@ public String getErrorDetails() { * @param additionalErrorInfo the partitioned query execution info. */ private void setAdditionalErrorInfo(String additionalErrorInfo) { - super.set(Constants.Properties.ADDITIONAL_ERROR_INFO, additionalErrorInfo); + super.set( + Constants.Properties.ADDITIONAL_ERROR_INFO, + additionalErrorInfo, + CosmosItemSerializer.DEFAULT_SERIALIZER); } /** diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/CosmosQueryRequestOptionsBase.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/CosmosQueryRequestOptionsBase.java index c1f23dab09a3..0461a6babf46 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/CosmosQueryRequestOptionsBase.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/CosmosQueryRequestOptionsBase.java @@ -6,18 +6,17 @@ import com.azure.cosmos.ConsistencyLevel; import com.azure.cosmos.CosmosDiagnosticsThresholds; import com.azure.cosmos.CosmosEndToEndOperationLatencyPolicyConfig; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.apachecommons.collections.list.UnmodifiableList; import com.azure.cosmos.implementation.spark.OperationContextAndListenerTuple; import com.azure.cosmos.models.CosmosQueryRequestOptions; import com.azure.cosmos.models.DedicatedGatewayRequestOptions; -import com.fasterxml.jackson.databind.JsonNode; import java.time.Duration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; -import java.util.function.Function; /** * Specifies the options associated with readMany methods @@ -39,9 +38,9 @@ public abstract class CosmosQueryRequestOptionsBase customOptions; private boolean indexMetricsEnabled; private UUID correlationActivityId; - private Function itemFactoryMethod; private CosmosEndToEndOperationLatencyPolicyConfig cosmosEndToEndOperationLatencyPolicyConfig; private List excludeRegions; + private CosmosItemSerializer customSerializer; /** * Instantiates a new query request options. @@ -68,11 +67,11 @@ protected CosmosQueryRequestOptionsBase(CosmosQueryRequestOptionsBase options this.customOptions = options.customOptions; this.indexMetricsEnabled = options.indexMetricsEnabled; this.correlationActivityId = options.correlationActivityId; - this.itemFactoryMethod = options.itemFactoryMethod; this.thresholds = options.thresholds; this.cosmosEndToEndOperationLatencyPolicyConfig = options.cosmosEndToEndOperationLatencyPolicyConfig; this.excludeRegions = options.excludeRegions; this.properties = options.properties; + this.customSerializer = options.customSerializer; } public void setOperationContextAndListenerTuple(OperationContextAndListenerTuple operationContextAndListenerTuple) { @@ -419,29 +418,36 @@ public Map getHeaders() { return this.customOptions; } - public Function getItemFactoryMethod() { return this.itemFactoryMethod; } + public CosmosDiagnosticsThresholds getThresholds() { + return this.thresholds; + } - @SuppressWarnings("unchecked") - public Function getItemFactoryMethod(Class classOfT) { + public CosmosEndToEndOperationLatencyPolicyConfig getEndToEndOperationLatencyConfig() { + return cosmosEndToEndOperationLatencyPolicyConfig; + } - return (Function)this.itemFactoryMethod; + /** + * Gets the custom item serializer defined for this instance of request options + * @return the custom item serializer + */ + public CosmosItemSerializer getCustomSerializer() { + return this.customSerializer; } + /** + * Allows specifying a custom item serializer to be used for this operation. If the serializer + * on the request options is null, the serializer on CosmosClientBuilder is used. If both serializers + * are null (the default), an internal Jackson ObjectMapper is ued for serialization/deserialization. + * @param itemSerializerOverride the custom item serializer for this operation + * @return the CosmosItemRequestOptions. + */ @SuppressWarnings("unchecked") - public T setItemFactoryMethod(Function factoryMethod) { - this.itemFactoryMethod = factoryMethod; + public T setCustomSerializer(CosmosItemSerializer itemSerializerOverride) { + this.customSerializer = itemSerializerOverride; return (T)this; } - public CosmosDiagnosticsThresholds getThresholds() { - return this.thresholds; - } - - public CosmosEndToEndOperationLatencyPolicyConfig getEndToEndOperationLatencyConfig() { - return cosmosEndToEndOperationLatencyPolicyConfig; - } - public RequestOptions applyToRequestOptions(RequestOptions requestOptions) { requestOptions.setConsistencyLevel(this.getConsistencyLevel()); requestOptions.setSessionToken(this.getSessionToken()); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/DatabaseAccount.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/DatabaseAccount.java index e202817cea61..0c24c2d7722f 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/DatabaseAccount.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/DatabaseAccount.java @@ -3,8 +3,7 @@ package com.azure.cosmos.implementation; -import com.azure.cosmos.BridgeInternal; -import com.fasterxml.jackson.core.type.TypeReference; +import com.azure.cosmos.CosmosItemSerializer; import com.fasterxml.jackson.databind.node.ObjectNode; import com.azure.cosmos.implementation.apachecommons.lang.ObjectUtils; import com.azure.cosmos.implementation.apachecommons.lang.StringUtils; @@ -39,7 +38,7 @@ public DatabaseAccount(ObjectNode objectNode) { * Constructor. */ public DatabaseAccount() { - BridgeInternal.setResourceSelfLink(this, ""); + this.setSelfLink(""); } /** @@ -66,7 +65,7 @@ String getDatabasesLink() { * @param databasesLink the databases link. */ void setDatabasesLink(String databasesLink) { - BridgeInternal.setProperty(this, Constants.Properties.DATABASES_LINK, databasesLink); + this.set(Constants.Properties.DATABASES_LINK, databasesLink, CosmosItemSerializer.DEFAULT_SERIALIZER); } /** @@ -84,7 +83,7 @@ String getMediaLink() { * @param medialink the media link. */ void setMediaLink(String medialink) { - BridgeInternal.setProperty(this, Constants.Properties.MEDIA_LINK, medialink); + this.set(Constants.Properties.MEDIA_LINK, medialink, CosmosItemSerializer.DEFAULT_SERIALIZER); } /** @@ -102,7 +101,7 @@ String getAddressesLink() { * @param addresseslink the addresses link. */ void setAddressesLink(String addresseslink) { - BridgeInternal.setProperty(this, Constants.Properties.ADDRESS_LINK, addresseslink); + this.set(Constants.Properties.ADDRESS_LINK, addresseslink, CosmosItemSerializer.DEFAULT_SERIALIZER); } /** @@ -197,11 +196,10 @@ public Map getQueryEngineConfiguration() { String queryEngineConfigurationJsonString = super.getObject(Constants.Properties.QUERY_ENGINE_CONFIGURATION, String.class); if (StringUtils.isNotEmpty(queryEngineConfigurationJsonString)) { - TypeReference> typeRef = new TypeReference>() { - }; try { - this.queryEngineConfiguration = Utils.getSimpleObjectMapper() - .readValue(queryEngineConfigurationJsonString, typeRef); + this.queryEngineConfiguration = Utils + .getSimpleObjectMapper() + .readValue(queryEngineConfigurationJsonString, ObjectNodeMap.JACKSON_MAP_TYPE); } catch (IOException e) { throw new IllegalArgumentException(e); } @@ -231,7 +229,7 @@ public Iterable getWritableLocations() { * @param locations the list of writable locations. */ public void setWritableLocations(Iterable locations) { - BridgeInternal.setProperty(this, Constants.Properties.WRITABLE_LOCATIONS, locations); + this.set(Constants.Properties.WRITABLE_LOCATIONS, locations, CosmosItemSerializer.DEFAULT_SERIALIZER); } /** @@ -251,7 +249,7 @@ public Iterable getReadableLocations() { * @param locations the list of readable locations. */ public void setReadableLocations(Iterable locations) { - BridgeInternal.setProperty(this, Constants.Properties.READABLE_LOCATIONS, locations); + this.set(Constants.Properties.READABLE_LOCATIONS, locations, CosmosItemSerializer.DEFAULT_SERIALIZER); } /** @@ -264,14 +262,17 @@ public boolean getEnableMultipleWriteLocations() { } public void setEnableMultipleWriteLocations(boolean value) { - BridgeInternal.setProperty(this, Constants.Properties.ENABLE_MULTIPLE_WRITE_LOCATIONS, value); + this.set(Constants.Properties.ENABLE_MULTIPLE_WRITE_LOCATIONS, value, CosmosItemSerializer.DEFAULT_SERIALIZER); } public void populatePropertyBag() { super.populatePropertyBag(); if (this.consistencyPolicy != null) { this.consistencyPolicy.populatePropertyBag(); - BridgeInternal.setProperty(this, Constants.Properties.USER_CONSISTENCY_POLICY, this.consistencyPolicy); + this.set( + Constants.Properties.USER_CONSISTENCY_POLICY, + this.consistencyPolicy, + CosmosItemSerializer.DEFAULT_SERIALIZER); } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/DatabaseAccountLocation.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/DatabaseAccountLocation.java index 6e5e93a2cb50..f9da5b1bda94 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/DatabaseAccountLocation.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/DatabaseAccountLocation.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation; +import com.azure.cosmos.CosmosItemSerializer; import com.fasterxml.jackson.databind.node.ObjectNode; /** @@ -52,7 +53,7 @@ public String getName() { * @param name the name of the database account location. */ public void setName(String name) { - super.set( Constants.Properties.Name, name); + super.set( Constants.Properties.Name, name, CosmosItemSerializer.DEFAULT_SERIALIZER); } /** @@ -70,6 +71,6 @@ public String getEndpoint() { * @param endpoint the endpoint of the database account location. */ public void setEndpoint(String endpoint) { - super.set(Constants.Properties.DATABASE_ACCOUNT_ENDPOINT, endpoint); + super.set(Constants.Properties.DATABASE_ACCOUNT_ENDPOINT, endpoint, CosmosItemSerializer.DEFAULT_SERIALIZER); } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Document.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Document.java index 13d00ecb655e..8d3f71e52635 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Document.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Document.java @@ -3,12 +3,12 @@ package com.azure.cosmos.implementation; +import com.azure.cosmos.CosmosItemSerializer; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; -import java.io.IOException; +import java.util.Map; -import static com.azure.cosmos.BridgeInternal.setProperty; /** * Represents a document in the Azure Cosmos DB database service. *

@@ -17,6 +17,7 @@ * can be authorized using the master key or resource keys. */ public class Document extends Resource { + private final static ObjectMapper OBJECT_MAPPER = Utils.getSimpleObjectMapper(); /** * Constructor. @@ -63,16 +64,20 @@ public Document(String jsonString) { super(jsonString); } - public static Document fromObject(Object document, ObjectMapper objectMapper) { + public static Document fromObject(Object document, CosmosItemSerializer itemSerializer) { Document typedDocument; if (document instanceof Document) { typedDocument = (Document) document; } else { - try { - return new Document(objectMapper.writeValueAsString(document)); - } catch (IOException e) { - throw new IllegalArgumentException("Can't serialize the object into the json string", e); + Map jsonTreeMap = itemSerializer.serialize(document); + ObjectNode objectNode = null; + if (jsonTreeMap instanceof ObjectNodeMap) { + objectNode = ((ObjectNodeMap)jsonTreeMap).getObjectNode(); + } else { + objectNode = OBJECT_MAPPER.convertValue(jsonTreeMap, ObjectNode.class); } + + return new Document(objectNode); } return typedDocument; } @@ -110,9 +115,9 @@ public void setTimeToLive(Integer timeToLive) { // a "null" value is represented as a missing element on the wire. // setting timeToLive to null should remove the property from the property bag. if (timeToLive != null) { - setProperty(this, Constants.Properties.TTL, timeToLive); + this.set(Constants.Properties.TTL, timeToLive, CosmosItemSerializer.DEFAULT_SERIALIZER); } else if (super.has(Constants.Properties.TTL)) { - remove(Constants.Properties.TTL); + this.remove(Constants.Properties.TTL); } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/DocumentCollection.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/DocumentCollection.java index 7728781e0665..678bdb90378c 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/DocumentCollection.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/DocumentCollection.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.apachecommons.lang.StringUtils; import com.azure.cosmos.implementation.caches.SerializableWrapper; import com.azure.cosmos.models.ClientEncryptionPolicy; @@ -23,8 +24,6 @@ import java.util.Collection; import java.util.Collections; -import static com.azure.cosmos.BridgeInternal.setProperty; - /** * Represents a document collection in the Azure Cosmos DB database service. A collection is a named logical container * for documents. @@ -173,7 +172,7 @@ public void setDefaultTimeToLive(Integer timeToLive) { // a "null" value is represented as a missing element on the wire. // setting timeToLive to null should remove the property from the property bag. if (timeToLive != null) { - setProperty(this, Constants.Properties.DEFAULT_TTL, timeToLive); + this.set(Constants.Properties.DEFAULT_TTL, timeToLive, CosmosItemSerializer.DEFAULT_SERIALIZER); } else if (super.has(Constants.Properties.DEFAULT_TTL)) { remove(Constants.Properties.DEFAULT_TTL); } @@ -193,7 +192,7 @@ public void setAnalyticalStoreTimeToLiveInSeconds(Integer timeToLive) { // a "null" value is represented as a missing element on the wire. // setting timeToLive to null should remove the property from the property bag. if (timeToLive != null) { - super.set(Constants.Properties.ANALYTICAL_STORAGE_TTL, timeToLive); + super.set(Constants.Properties.ANALYTICAL_STORAGE_TTL, timeToLive, CosmosItemSerializer.DEFAULT_SERIALIZER); } else if (super.has(Constants.Properties.ANALYTICAL_STORAGE_TTL)) { super.remove(Constants.Properties.ANALYTICAL_STORAGE_TTL); } @@ -241,7 +240,7 @@ public void setUniqueKeyPolicy(UniqueKeyPolicy uniqueKeyPolicy) { } this.uniqueKeyPolicy = uniqueKeyPolicy; - setProperty(this, Constants.Properties.UNIQUE_KEY_POLICY, uniqueKeyPolicy); + this.set(Constants.Properties.UNIQUE_KEY_POLICY, uniqueKeyPolicy, CosmosItemSerializer.DEFAULT_SERIALIZER); } /** @@ -265,7 +264,7 @@ public void setConflictResolutionPolicy(ConflictResolutionPolicy value) { throw new IllegalArgumentException("CONFLICT_RESOLUTION_POLICY cannot be null."); } - setProperty(this, Constants.Properties.CONFLICT_RESOLUTION_POLICY, value); + this.set(Constants.Properties.CONFLICT_RESOLUTION_POLICY, value, CosmosItemSerializer.DEFAULT_SERIALIZER); } /** @@ -293,7 +292,7 @@ public void setChangeFeedPolicy(ChangeFeedPolicy value) { throw new IllegalArgumentException("CHANGE_FEED_POLICY cannot be null."); } - setProperty(this, Constants.Properties.CHANGE_FEED_POLICY, value); + this.set(Constants.Properties.CHANGE_FEED_POLICY, value, CosmosItemSerializer.DEFAULT_SERIALIZER); } /** @@ -326,7 +325,7 @@ public void setComputedProperties(Collection computedPropertie } }); - setProperty(this, Constants.Properties.COMPUTED_PROPERTIES, computedProperties); + this.set(Constants.Properties.COMPUTED_PROPERTIES, computedProperties, CosmosItemSerializer.DEFAULT_SERIALIZER); } /** @@ -408,7 +407,7 @@ public void setClientEncryptionPolicy(ClientEncryptionPolicy value) { throw new IllegalArgumentException("ClientEncryptionPolicy cannot be null."); } - setProperty(this, Constants.Properties.CLIENT_ENCRYPTION_POLICY, value); + this.set(Constants.Properties.CLIENT_ENCRYPTION_POLICY, value, CosmosItemSerializer.DEFAULT_SERIALIZER); } public void populatePropertyBag() { @@ -422,13 +421,16 @@ public void populatePropertyBag() { if (this.partitionKeyDefinition != null) { ModelBridgeInternal.populatePropertyBag(this.partitionKeyDefinition); - setProperty(this, Constants.Properties.PARTITION_KEY, this.partitionKeyDefinition); + this.set( + Constants.Properties.PARTITION_KEY, + this.partitionKeyDefinition, + CosmosItemSerializer.DEFAULT_SERIALIZER); } ModelBridgeInternal.populatePropertyBag(this.indexingPolicy); ModelBridgeInternal.populatePropertyBag(this.uniqueKeyPolicy); - setProperty(this, Constants.Properties.INDEXING_POLICY, this.indexingPolicy); - setProperty(this, Constants.Properties.UNIQUE_KEY_POLICY, this.uniqueKeyPolicy); + this.set(Constants.Properties.INDEXING_POLICY, this.indexingPolicy, CosmosItemSerializer.DEFAULT_SERIALIZER); + this.set(Constants.Properties.UNIQUE_KEY_POLICY, this.uniqueKeyPolicy, CosmosItemSerializer.DEFAULT_SERIALIZER); } @Override diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/HashIndex.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/HashIndex.java index b5994edf61c3..73c47991f86a 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/HashIndex.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/HashIndex.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.apachecommons.lang.StringUtils; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -87,7 +88,7 @@ public DataType getDataType() { * @return the Hash Index. */ public HashIndex setDataType(DataType dataType) { - super.set(Constants.Properties.DATA_TYPE, dataType.toString()); + super.set(Constants.Properties.DATA_TYPE, dataType.toString(), CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } @@ -107,7 +108,7 @@ public int getPrecision() { * @return the Hash Index. */ public HashIndex setPrecision(int precision) { - super.set(Constants.Properties.PRECISION, precision); + super.set(Constants.Properties.PRECISION, precision, CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ImplementationBridgeHelpers.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ImplementationBridgeHelpers.java index 0df099761729..034026a007da 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ImplementationBridgeHelpers.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ImplementationBridgeHelpers.java @@ -21,6 +21,7 @@ import com.azure.cosmos.CosmosEndToEndOperationLatencyPolicyConfig; import com.azure.cosmos.CosmosException; import com.azure.cosmos.CosmosRegionSwitchHint; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.DirectConnectionConfig; import com.azure.cosmos.GlobalThroughputControlConfig; import com.azure.cosmos.SessionRetryOptions; @@ -37,10 +38,8 @@ import com.azure.cosmos.implementation.directconnectivity.Uri; import com.azure.cosmos.implementation.directconnectivity.rntbd.RntbdChannelStatistics; import com.azure.cosmos.implementation.faultinjection.IFaultInjectorProvider; -import com.azure.cosmos.implementation.feedranges.FeedRangeEpkImpl; import com.azure.cosmos.implementation.patch.PatchOperation; import com.azure.cosmos.implementation.routing.PartitionKeyInternal; -import com.azure.cosmos.implementation.routing.Range; import com.azure.cosmos.implementation.spark.OperationContextAndListenerTuple; import com.azure.cosmos.models.CosmosBatch; import com.azure.cosmos.models.CosmosBatchOperationResult; @@ -58,6 +57,7 @@ import com.azure.cosmos.models.CosmosItemRequestOptions; import com.azure.cosmos.models.CosmosItemResponse; import com.azure.cosmos.models.CosmosMetricName; +import com.azure.cosmos.models.CosmosPatchItemRequestOptions; import com.azure.cosmos.models.CosmosPatchOperations; import com.azure.cosmos.models.CosmosQueryRequestOptions; import com.azure.cosmos.models.CosmosReadManyRequestOptions; @@ -147,6 +147,8 @@ void setCosmosClientMetadataCachesSnapshot(CosmosClientBuilder builder, ConsistencyLevel getConsistencyLevel(CosmosClientBuilder builder); String getEndpoint(CosmosClientBuilder builder); + + CosmosItemSerializer getDefaultCustomSerializer(CosmosClientBuilder builder); } } @@ -350,11 +352,11 @@ public interface CosmosChangeFeedRequestOptionsAccessor { Map getHeader(CosmosChangeFeedRequestOptions changeFeedRequestOptions); void setOperationContext(CosmosChangeFeedRequestOptions changeFeedRequestOptions, OperationContextAndListenerTuple operationContext); OperationContextAndListenerTuple getOperationContext(CosmosChangeFeedRequestOptions changeFeedRequestOptions); - Function getItemFactoryMethod(CosmosChangeFeedRequestOptions queryRequestOptions, Class classOfT); - CosmosChangeFeedRequestOptions setItemFactoryMethod(CosmosChangeFeedRequestOptions queryRequestOptions, Function factoryMethod); CosmosDiagnosticsThresholds getDiagnosticsThresholds(CosmosChangeFeedRequestOptions options); List getExcludeRegions(CosmosChangeFeedRequestOptions cosmosChangeFeedRequestOptions); CosmosChangeFeedRequestOptions createForProcessingFromContinuation(String continuation, FeedRange targetRange, String continuationLsn); + + CosmosChangeFeedRequestOptions clone(CosmosChangeFeedRequestOptions toBeCloned); } } @@ -388,6 +390,7 @@ public static CosmosItemRequestOptionsAccessor getCosmosItemRequestOptionsAccess } public interface CosmosItemRequestOptionsAccessor { + RequestOptions toRequestOptions(CosmosItemRequestOptions itemRequestOptions, CosmosItemSerializer effectiveItemSerializer); void setOperationContext(CosmosItemRequestOptions queryRequestOptions, OperationContextAndListenerTuple operationContext); OperationContextAndListenerTuple getOperationContext(CosmosItemRequestOptions queryRequestOptions); CosmosItemRequestOptions clone(CosmosItemRequestOptions options); @@ -405,6 +408,8 @@ WriteRetryPolicy calculateAndGetEffectiveNonIdempotentRetriesEnabled( CosmosEndToEndOperationLatencyPolicyConfig getEndToEndOperationLatencyPolicyConfig( CosmosItemRequestOptions options); + + CosmosPatchItemRequestOptions clonePatchItemRequestOptions(CosmosPatchItemRequestOptions options); } } @@ -478,6 +483,8 @@ CosmosBulkExecutionOptions setHeader(CosmosBulkExecutionOptions cosmosBulkExecut int getMaxMicroBatchSize(CosmosBulkExecutionOptions cosmosBulkExecutionOptions); void setDiagnosticsTracker(CosmosBulkExecutionOptions cosmosBulkExecutionOptions, BulkExecutorDiagnosticsTracker tracker); BulkExecutorDiagnosticsTracker getDiagnosticsTracker(CosmosBulkExecutionOptions cosmosBulkExecutionOptions); + + CosmosBulkExecutionOptions clone(CosmosBulkExecutionOptions toBeCloned); } } @@ -515,7 +522,11 @@ public static CosmosItemResponseBuilderAccessor getCosmosItemResponseBuilderAcce public interface CosmosItemResponseBuilderAccessor { CosmosItemResponse createCosmosItemResponse(CosmosItemResponse response, Class classType, - ItemDeserializer itemDeserializer); + CosmosItemSerializer serializer); + + CosmosItemResponse createCosmosItemResponse(ResourceResponse response, + Class classType, + CosmosItemSerializer serializer); CosmosItemResponse withRemappedStatusCode( @@ -989,6 +1000,13 @@ public static FeedResponseAccessor getFeedResponseAccessor() { } public interface FeedResponseAccessor { + FeedResponse createFeedResponse(RxDocumentServiceResponse response, + CosmosItemSerializer itemSerializer, + Class cls); + + FeedResponse createChangeFeedResponse(RxDocumentServiceResponse response, + CosmosItemSerializer itemSerializer, + Class cls); boolean getNoChanges(FeedResponse feedResponse); FeedResponse convertGenericType(FeedResponse feedResponse, Function conversion); FeedResponse createFeedResponse( @@ -1033,6 +1051,8 @@ CosmosBatchRequestOptions setConsistencyLevel(CosmosBatchRequestOptions cosmosBa CosmosBatchRequestOptions setHeader(CosmosBatchRequestOptions cosmosItemRequestOptions, String name, String value); Map getHeader(CosmosBatchRequestOptions cosmosItemRequestOptions); List getExcludeRegions(CosmosBatchRequestOptions cosmosBatchRequestOptions); + + CosmosBatchRequestOptions clone(CosmosBatchRequestOptions toBeCloned); } } @@ -1069,6 +1089,8 @@ public static void setCosmosBatchOperationResultAccessor(final CosmosBatchOperat public interface CosmosBatchOperationResultAccessor { ObjectNode getResourceObject(CosmosBatchOperationResult cosmosBatchOperationResult); void setResourceObject(CosmosBatchOperationResult cosmosBatchOperationResult, ObjectNode objectNode); + void setEffectiveItemSerializer(CosmosBatchOperationResult cosmosBatchOperationResult, + CosmosItemSerializer effectiveItemSerializer); } } @@ -1177,6 +1199,9 @@ public interface CosmosBulkItemResponseAccessor { void setResourceObject(CosmosBulkItemResponse cosmosBulkItemResponse, ObjectNode objectNode); + + void setEffectiveItemSerializer(CosmosBulkItemResponse cosmosBulkItemResponse, + CosmosItemSerializer effectiveItemSerializer); } } @@ -1306,6 +1331,10 @@ CosmosDiagnosticsThresholds getEffectiveDiagnosticsThresholds( CosmosDiagnosticsThresholds operationLevelThresholds); DiagnosticsProvider getDiagnosticsProvider(CosmosAsyncClient client); + + CosmosItemSerializer getEffectiveItemSerializer( + CosmosAsyncClient client, + CosmosItemSerializer requestOptionsItemSerializer); } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Index.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Index.java index 3afb7413ad0c..b877a19376c8 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Index.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Index.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.apachecommons.lang.StringUtils; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -135,7 +136,7 @@ IndexKind getKind() { * @param indexKind the index kind. */ private Index setKind(IndexKind indexKind) { - super.set(Constants.Properties.INDEX_KIND, indexKind.toString()); + super.set(Constants.Properties.INDEX_KIND, indexKind.toString(), CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/InternalObjectNode.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/InternalObjectNode.java index 5d1ee74bfdb7..58fac984228e 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/InternalObjectNode.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/InternalObjectNode.java @@ -2,17 +2,19 @@ // Licensed under the MIT License. package com.azure.cosmos.implementation; -import com.azure.cosmos.models.ModelBridgeInternal; +import com.azure.cosmos.CosmosItemSerializer; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; -import com.fasterxml.jackson.databind.type.MapType; import java.io.IOException; import java.nio.ByteBuffer; -import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; +import java.util.function.Consumer; import java.util.stream.Collectors; +import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; + public class InternalObjectNode extends Resource { private static final ObjectMapper MAPPER = Utils.getSimpleObjectMapper(); @@ -105,47 +107,47 @@ public static Document fromObject(Object cosmosItem) { } } - public static ByteBuffer serializeJsonToByteBuffer(Object cosmosItem, ObjectMapper objectMapper, String trackingId) { + public static ByteBuffer serializeJsonToByteBuffer(Object cosmosItem, CosmosItemSerializer itemSerializer, String trackingId) { + checkNotNull(itemSerializer, "Argument 'itemSerializer' must not be null."); if (cosmosItem instanceof InternalObjectNode) { InternalObjectNode internalObjectNode = ((InternalObjectNode) cosmosItem); + Consumer> onAfterSerialization = null; if (trackingId != null) { - internalObjectNode.set(Constants.Properties.TRACKING_ID, trackingId); + onAfterSerialization = (node) -> node.put(Constants.Properties.TRACKING_ID, trackingId); } - return internalObjectNode.serializeJsonToByteBuffer(); + return internalObjectNode.serializeJsonToByteBuffer(itemSerializer, onAfterSerialization); } else if (cosmosItem instanceof Document) { Document doc = (Document) cosmosItem; + Consumer> onAfterSerialization = null; if (trackingId != null) { - doc.set(Constants.Properties.TRACKING_ID, trackingId); + onAfterSerialization = (node) -> node.put(Constants.Properties.TRACKING_ID, trackingId); } - return ModelBridgeInternal.serializeJsonToByteBuffer(doc); + return doc.serializeJsonToByteBuffer(itemSerializer, onAfterSerialization); } else if (cosmosItem instanceof ObjectNode) { ObjectNode objectNode = (ObjectNode)cosmosItem; + Consumer> onAfterSerialization = null; if (trackingId != null) { - objectNode.put(Constants.Properties.TRACKING_ID, trackingId); + onAfterSerialization = (node) -> node.put(Constants.Properties.TRACKING_ID, trackingId); } - return (new InternalObjectNode(objectNode).serializeJsonToByteBuffer()); + return (new InternalObjectNode(objectNode).serializeJsonToByteBuffer(itemSerializer, onAfterSerialization)); } else if (cosmosItem instanceof byte[]) { if (trackingId != null) { InternalObjectNode internalObjectNode = new InternalObjectNode((byte[]) cosmosItem); - internalObjectNode.set(Constants.Properties.TRACKING_ID, trackingId); - return internalObjectNode.serializeJsonToByteBuffer(); + return internalObjectNode.serializeJsonToByteBuffer(itemSerializer, (node) -> node.put(Constants.Properties.TRACKING_ID, trackingId)); } return ByteBuffer.wrap((byte[]) cosmosItem); } else { - Object effectivePayload = cosmosItem; + Consumer> onAfterSerialization = null; if (trackingId != null) { - MapType mapType = objectMapper.getTypeFactory().constructMapType(LinkedHashMap.class, - String.class, Object.class); - LinkedHashMap node = objectMapper.convertValue(cosmosItem, mapType); - node.put(Constants.Properties.TRACKING_ID, trackingId); - effectivePayload = node; + onAfterSerialization = (node) -> node.put(Constants.Properties.TRACKING_ID, trackingId); } - return Utils.serializeJsonToByteBuffer(objectMapper, effectivePayload); + + return Utils.serializeJsonToByteBuffer(itemSerializer, cosmosItem, onAfterSerialization); } } static List getTypedResultsFromV2Results(List results, Class klass) { - return results.stream().map(document -> ModelBridgeInternal.toObjectFromJsonSerializable(document, klass)) + return results.stream().map(document -> document.toObject(klass)) .collect(Collectors.toList()); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ItemDeserializer.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ItemDeserializer.java deleted file mode 100644 index b63d9c6ccf7b..000000000000 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ItemDeserializer.java +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.cosmos.implementation; - -import com.fasterxml.jackson.databind.JsonNode; - -import java.io.IOException; -import java.util.function.Function; - -public interface ItemDeserializer { - T convert(Class classType, JsonNode objectNode); - - class JsonDeserializer implements ItemDeserializer { - private final Function factoryMethod; - public JsonDeserializer(Function factoryMethod) { - this.factoryMethod = factoryMethod; - } - - public JsonDeserializer() { - this.factoryMethod = null; - } - - @Override - @SuppressWarnings("unchecked") - public T convert(Class classType, JsonNode jsonNode) { - if (jsonNode == null) { - return null; - } - - if (this.factoryMethod != null) { - return (T) this.factoryMethod.apply(jsonNode); - } - - try { - return Utils.getSimpleObjectMapper().treeToValue(jsonNode, classType); - } catch (IOException e) { - throw new IllegalStateException(String.format("Unable to parse JSON %s", jsonNode), e); - } - } - } -} diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/JsonSerializable.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/JsonSerializable.java index 46d496386721..c64748ea9861 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/JsonSerializable.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/JsonSerializable.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.directconnectivity.Address; import com.azure.cosmos.implementation.query.PartitionedQueryExecutionInfoInternal; import com.azure.cosmos.implementation.query.QueryInfo; @@ -35,8 +36,6 @@ import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; -import java.math.BigDecimal; -import java.math.BigInteger; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; @@ -46,6 +45,10 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.function.Consumer; + +import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkArgument; +import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; /** * Represents a base resource that can be serialized to JSON in the Azure Cosmos DB database service. @@ -186,18 +189,6 @@ public static Object getValue(JsonNode value) { return value; } - private ObjectMapper getMapper() { - // TODO: Made package private due to #153. #171 adding custom serialization options back. - if (this.om != null) { - return this.om; - } - return OBJECT_MAPPER; - } - - void setMapper(ObjectMapper om) { - this.om = om; - } - @JsonIgnore public Logger getLogger() { return LOGGER; @@ -213,14 +204,14 @@ public void populatePropertyBag() { */ @SuppressWarnings("unchecked") public Map getMap() { - return getMapper().convertValue(this.propertyBag, HashMap.class); + return OBJECT_MAPPER.convertValue(this.propertyBag, HashMap.class); } @SuppressWarnings("unchecked") public Map getMap(String propertyKey) { if (this.propertyBag.has(propertyKey)) { Object value = this.get(propertyKey); - return (Map) getMapper().convertValue(value, HashMap.class); + return (Map) OBJECT_MAPPER.convertValue(value, HashMap.class); } return null; } @@ -252,29 +243,61 @@ public void remove(String propertyName) { * @param value the value of the property. */ @SuppressWarnings({"unchecked", "rawtypes"}) - public void set(String propertyName, T value) { + public void set(String propertyName, T value, CosmosItemSerializer itemSerializer) { + checkNotNull(itemSerializer, "Argument 'itemSerializer' must not be null."); + checkArgument( + itemSerializer == CosmosItemSerializer.DEFAULT_SERIALIZER, + "Argument 'itemSerializer' must be the DEFAULT_SERIALIZER when using this method."); + set(propertyName, value, itemSerializer, false); + } + + /** + * Sets the value of a property. + * + * @param the type of the object. + * @param propertyName the property to set. + * @param value the value of the property. + */ + @SuppressWarnings({"unchecked", "rawtypes"}) + public void set(String propertyName, T value, CosmosItemSerializer itemSerializer, boolean forceSerialization) { + checkNotNull(itemSerializer, "Argument 'itemSerializer' must not be null."); if (value == null) { // Sets null. this.propertyBag.putNull(propertyName); - } else if (value instanceof Collection) { + } else if (!forceSerialization && value instanceof Collection) { // Collection. ArrayNode jsonArray = propertyBag.arrayNode(); this.internalSetCollection(propertyName, (Collection) value, jsonArray); this.propertyBag.set(propertyName, jsonArray); - } else if (value instanceof JsonNode) { + } else if (!forceSerialization && value instanceof JsonNode) { this.propertyBag.set(propertyName, (JsonNode) value); - } else if (value instanceof JsonSerializable) { + } else if (!forceSerialization && value instanceof JsonSerializable) { // JsonSerializable JsonSerializable castedValue = (JsonSerializable) value; castedValue.populatePropertyBag(); this.propertyBag.set(propertyName, castedValue.propertyBag); - } else if (containsJsonSerializable(value.getClass())) { + } else if (!forceSerialization && containsJsonSerializable(value.getClass())) { ModelBridgeInternal.populatePropertyBag(value); this.propertyBag.set(propertyName, ModelBridgeInternal.getJsonSerializable(value).propertyBag); } else { - // POJO, ObjectNode, number (includes int, float, double etc), boolean, - // and string. - this.propertyBag.set(propertyName, getMapper().valueToTree(value)); + // Arrays, POJO, ObjectNode, number (includes int, float, double etc), boolean, + // and string + Map jsonTreeMap = itemSerializer.serialize(value); + if (jsonTreeMap instanceof ObjectNodeMap) { + this.propertyBag.set(propertyName, ((ObjectNodeMap) jsonTreeMap).getObjectNode()); + } else if (jsonTreeMap instanceof PrimitiveJsonNodeMap) { + this.propertyBag.set(propertyName, ((PrimitiveJsonNodeMap) jsonTreeMap).getPrimitiveJsonNode()); + } else { + if (jsonTreeMap.size() == 1 && jsonTreeMap.get(PrimitiveJsonNodeMap.VALUE_KEY) != null) { + this.propertyBag.set( + propertyName, + OBJECT_MAPPER.convertValue(jsonTreeMap.get(PrimitiveJsonNodeMap.VALUE_KEY), JsonNode.class)); + } else { + this.propertyBag.set( + propertyName, + OBJECT_MAPPER.convertValue(jsonTreeMap, ObjectNode.class)); + } + } } } @@ -295,15 +318,15 @@ private void internalSetCollection(String propertyName, Collection collec JsonSerializable castedValue = (JsonSerializable) childValue; castedValue.populatePropertyBag(); targetArray.add(castedValue.propertyBag != null ? castedValue.propertyBag - : this.getMapper().createObjectNode()); + : OBJECT_MAPPER.createObjectNode()); } else if (containsJsonSerializable(childValue.getClass())) { ModelBridgeInternal.populatePropertyBag(childValue); targetArray.add(ModelBridgeInternal.getJsonSerializable(childValue).propertyBag != null ? - ModelBridgeInternal.getJsonSerializable(childValue).propertyBag : this.getMapper().createObjectNode()); + ModelBridgeInternal.getJsonSerializable(childValue).propertyBag : OBJECT_MAPPER.createObjectNode()); } else { // POJO, JsonNode, NUMBER (includes Int, Float, Double etc), // Boolean, and STRING. - targetArray.add(this.getMapper().valueToTree(childValue)); + targetArray.add(OBJECT_MAPPER.valueToTree(childValue)); } } } @@ -437,7 +460,7 @@ public T getObject(String propertyName, Class c, boolean... convertFromCa // POJO JsonSerializable.checkForValidPOJO(c); try { - return this.getMapper().treeToValue(jsonObj, c); + return OBJECT_MAPPER.treeToValue(jsonObj, c); } catch (IOException e) { throw new IllegalStateException("Failed to get POJO.", e); } @@ -511,7 +534,7 @@ public List getList(String propertyName, Class c, boolean... convertFr } else { // POJO try { - result.add(this.getMapper().treeToValue(n, c)); + result.add(OBJECT_MAPPER.treeToValue(n, c)); } catch (IOException e) { throw new IllegalStateException("Failed to get POJO.", e); } @@ -607,7 +630,7 @@ public Object getObjectByPath(List propertyNames) { private ObjectNode fromJson(byte[] bytes) { try { - return (ObjectNode) getMapper().readTree(bytes); + return (ObjectNode) OBJECT_MAPPER.readTree(bytes); } catch (IOException e) { throw new IllegalArgumentException( String.format("Unable to parse JSON %s", Arrays.toString(bytes)), e); @@ -616,7 +639,7 @@ private ObjectNode fromJson(byte[] bytes) { private ObjectNode fromJson(String json) { try { - return (ObjectNode) getMapper().readTree(json); + return (ObjectNode) OBJECT_MAPPER.readTree(json); } catch (IOException e) { throw new IllegalArgumentException( String.format("Unable to parse JSON %s", json), e); @@ -625,29 +648,19 @@ private ObjectNode fromJson(String json) { private ObjectNode fromJson(ByteBuffer json) { try { - return (ObjectNode) getMapper().readTree(new ByteBufferBackedInputStream(json)); + return (ObjectNode) OBJECT_MAPPER.readTree(new ByteBufferBackedInputStream(json)); } catch (IOException e) { throw new IllegalArgumentException("Unable to parse JSON from ByteBuffer", e); } } - /** - * Serialize json to byte buffer byte buffer. - * - * @return the byte buffer - */ - public ByteBuffer serializeJsonToByteBuffer() { - this.populatePropertyBag(); - return Utils.serializeJsonToByteBuffer(getMapper(), propertyBag); - } - - public ByteBuffer serializeJsonToByteBuffer(ObjectMapper objectMapper) { + public ByteBuffer serializeJsonToByteBuffer(CosmosItemSerializer itemSerializer, Consumer> onAfterSerialization) { this.populatePropertyBag(); - return Utils.serializeJsonToByteBuffer(objectMapper, propertyBag); + return Utils.serializeJsonToByteBuffer(itemSerializer, propertyBag, onAfterSerialization); } private String toJson(Object object) { - return toJson(getMapper(), object); + return toJson(OBJECT_MAPPER, object); } private static String toJson(ObjectMapper mapper, Object object) { @@ -660,7 +673,7 @@ private static String toJson(ObjectMapper mapper, Object object) { private String toPrettyJson(Object object) { try { - return getMapper().writerWithDefaultPrettyPrinter().writeValueAsString(object); + return OBJECT_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(object); } catch (JsonProcessingException e) { throw new IllegalStateException("Unable to convert JSON to STRING", e); } @@ -695,7 +708,7 @@ public T toObject(Class c) { if (List.class.isAssignableFrom(c)) { Object o = this.get(Constants.Properties.VALUE); try { - return this.getMapper().readValue(o.toString(), c); + return OBJECT_MAPPER.readValue(o.toString(), c); } catch (IOException e) { throw new IllegalStateException("Failed to convert to collection.", e); } @@ -713,7 +726,7 @@ public T toObject(Class c) { // POJO JsonSerializable.checkForValidPOJO(c); try { - return this.getMapper().treeToValue(propertyBag, c); + return OBJECT_MAPPER.treeToValue(propertyBag, c); } catch (IOException e) { throw new IllegalStateException("Failed to get POJO.", e); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ObjectNodeMap.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ObjectNodeMap.java new file mode 100644 index 000000000000..aa453b12acb3 --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ObjectNodeMap.java @@ -0,0 +1,128 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.cosmos.implementation; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.type.MapType; + +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; + +public class ObjectNodeMap implements Map { + private final static ObjectMapper itemMapper = Utils.getSimpleObjectMapper(); + public final static MapType JACKSON_MAP_TYPE = itemMapper.getTypeFactory().constructMapType(LinkedHashMap.class, + String.class, Object.class); + private final Object thisLock = new Object(); + private final ObjectNode jsonNode; + private volatile LinkedHashMap jsonNodeAsMap = null; + + public ObjectNodeMap(ObjectNode jsonNode) { + checkNotNull(jsonNode, "Argument 'jsonNode' must not be null."); + + this.jsonNode = jsonNode; + } + + public ObjectNode getObjectNode() { + return this.jsonNode; + } + + @SuppressWarnings("unchecked") + private Map ensureJsonNodeAsMap() { + if (this.jsonNodeAsMap != null) { + return this.jsonNodeAsMap; + } + + synchronized (this.thisLock) { + if (this.jsonNodeAsMap != null) { + return this.jsonNodeAsMap; + } + + return this.jsonNodeAsMap = itemMapper.convertValue(this.jsonNode, JACKSON_MAP_TYPE); + } + } + + @Override + public int size() { + return this.ensureJsonNodeAsMap().size(); + } + + @Override + public boolean isEmpty() { + return this.ensureJsonNodeAsMap().isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return this.ensureJsonNodeAsMap().containsKey(key); + } + + @Override + public boolean containsValue(Object value) { + return this.ensureJsonNodeAsMap().containsValue(value); + } + + @Override + public Object get(Object key) { + return this.ensureJsonNodeAsMap().get(key); + } + + @Override + public Object put(String key, Object value) { + return this.ensureJsonNodeAsMap().put(key, value); + } + + @Override + public Object remove(Object key) { + return this.ensureJsonNodeAsMap().remove(key); + } + + @Override + public void putAll(Map m) { + this.ensureJsonNodeAsMap().putAll(m); + } + + @Override + public void clear() { + this.ensureJsonNodeAsMap().clear(); + } + + @Override + public Set keySet() { + return this.ensureJsonNodeAsMap().keySet(); + } + + @Override + public Collection values() { + return this.ensureJsonNodeAsMap().values(); + } + + @Override + public Set> entrySet() { + return this.ensureJsonNodeAsMap().entrySet(); + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + + if (!(o instanceof ObjectNodeMap)) { + return false; + } + + ObjectNodeMap other = (ObjectNodeMap)o; + + return this.jsonNode.equals(other.jsonNode); + } + + @Override + public int hashCode() { + return this.jsonNode.hashCode(); + } +} diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Offer.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Offer.java index 66654731a3e2..c83624d32176 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Offer.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Offer.java @@ -3,8 +3,7 @@ package com.azure.cosmos.implementation; -import com.azure.cosmos.BridgeInternal; -import com.azure.cosmos.models.ModelBridgeInternal; +import com.azure.cosmos.CosmosItemSerializer; import com.fasterxml.jackson.databind.node.ObjectNode; /** @@ -32,8 +31,7 @@ public Offer(int offerThroughput) { this.setOfferType(""); ObjectNode content = Utils.getSimpleObjectMapper().createObjectNode(); // content.put(Constants.Properties.OFFER_THROUGHPUT, null); - content.replace(Constants.Properties.AUTOPILOT_SETTINGS, ModelBridgeInternal - .getPropertyBagFromJsonSerializable(offerAutoscaleSettings)); + content.replace(Constants.Properties.AUTOPILOT_SETTINGS, offerAutoscaleSettings.getPropertyBag()); this.setContent(content); } @@ -135,7 +133,7 @@ public String getResourceLink() { * @param resourceLink the resource link. */ void setResourceLink(String resourceLink) { - BridgeInternal.setProperty(this, Constants.Properties.RESOURCE_LINK, resourceLink); + this.set(Constants.Properties.RESOURCE_LINK, resourceLink, CosmosItemSerializer.DEFAULT_SERIALIZER); } /** @@ -153,7 +151,7 @@ public String getOfferResourceId() { * @param resourceId the resource id. */ void setOfferResourceId(String resourceId) { - BridgeInternal.setProperty(this, Constants.Properties.OFFER_RESOURCE_ID, resourceId); + this.set(Constants.Properties.OFFER_RESOURCE_ID, resourceId, CosmosItemSerializer.DEFAULT_SERIALIZER); } /** @@ -171,7 +169,7 @@ public String getOfferType() { * @param offerType the offer type. */ public void setOfferType(String offerType) { - BridgeInternal.setProperty(this, Constants.Properties.OFFER_TYPE, offerType); + this.set(Constants.Properties.OFFER_TYPE, offerType, CosmosItemSerializer.DEFAULT_SERIALIZER); } /** @@ -189,7 +187,7 @@ public String getOfferVersion() { * @param offerVersion the version of the offer. */ public void setOfferVersion(String offerVersion) { - BridgeInternal.setProperty(this, Constants.Properties.OFFER_VERSION, offerVersion); + this.set(Constants.Properties.OFFER_VERSION, offerVersion, CosmosItemSerializer.DEFAULT_SERIALIZER); } /** @@ -220,11 +218,11 @@ public void setThroughput(int throughput) { } private ObjectNode getContent() { - return BridgeInternal.getObject(this, Constants.Properties.OFFER_CONTENT); + return this.getObject(Constants.Properties.OFFER_CONTENT); } private void setContent(ObjectNode offerContent) { - BridgeInternal.setProperty(this, Constants.Properties.OFFER_CONTENT, offerContent); + this.set(Constants.Properties.OFFER_CONTENT, offerContent, CosmosItemSerializer.DEFAULT_SERIALIZER); } @Override diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/OfferAutoscaleAutoUpgradeProperties.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/OfferAutoscaleAutoUpgradeProperties.java index 6a78587cec7d..007d080996a1 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/OfferAutoscaleAutoUpgradeProperties.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/OfferAutoscaleAutoUpgradeProperties.java @@ -2,6 +2,7 @@ // Licensed under the MIT License. package com.azure.cosmos.implementation; +import com.azure.cosmos.CosmosItemSerializer; import com.fasterxml.jackson.databind.node.ObjectNode; public class OfferAutoscaleAutoUpgradeProperties extends JsonSerializable { @@ -10,7 +11,10 @@ public class OfferAutoscaleAutoUpgradeProperties extends JsonSerializable { OfferAutoscaleAutoUpgradeProperties(int maxThroughputIncrementPercentage) { this.autoscaleThroughputProperties = new AutoscaleThroughputProperties(maxThroughputIncrementPercentage); - super.set(Constants.Properties.AUTOPILOT_AUTO_THROUGHPUT_POLICY, autoscaleThroughputProperties); + super.set( + Constants.Properties.AUTOPILOT_AUTO_THROUGHPUT_POLICY, + autoscaleThroughputProperties, + CosmosItemSerializer.DEFAULT_SERIALIZER); } OfferAutoscaleAutoUpgradeProperties(ObjectNode objectNode) { @@ -24,8 +28,10 @@ AutoscaleThroughputProperties getAutoscaleThroughputProperties() { public static class AutoscaleThroughputProperties extends JsonSerializable { AutoscaleThroughputProperties(int maxThroughputIncrementPercentage) { - super.set(Constants.Properties.AUTOPILOT_THROUGHPUT_POLICY_INCREMENT_PERCENT, - maxThroughputIncrementPercentage); + super.set( + Constants.Properties.AUTOPILOT_THROUGHPUT_POLICY_INCREMENT_PERCENT, + maxThroughputIncrementPercentage, + CosmosItemSerializer.DEFAULT_SERIALIZER); } /** diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/OfferAutoscaleSettings.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/OfferAutoscaleSettings.java index 5f4b7213fa57..f443a0325be4 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/OfferAutoscaleSettings.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/OfferAutoscaleSettings.java @@ -2,6 +2,7 @@ // Licensed under the MIT License. package com.azure.cosmos.implementation; +import com.azure.cosmos.CosmosItemSerializer; import com.fasterxml.jackson.databind.node.ObjectNode; public class OfferAutoscaleSettings extends JsonSerializable { @@ -10,8 +11,14 @@ public class OfferAutoscaleSettings extends JsonSerializable { OfferAutoscaleSettings(final int maxThroughput, int maxThroughputIncrementPercentage) { super(); offerAutoscaleAutoUpgradeProperties = new OfferAutoscaleAutoUpgradeProperties(maxThroughputIncrementPercentage); - super.set(Constants.Properties.AUTOPILOT_MAX_THROUGHPUT, maxThroughput); - super.set(Constants.Properties.AUTOPILOT_AUTO_UPGRADE_POLICY, offerAutoscaleAutoUpgradeProperties); + super.set( + Constants.Properties.AUTOPILOT_MAX_THROUGHPUT, + maxThroughput, + CosmosItemSerializer.DEFAULT_SERIALIZER); + super.set( + Constants.Properties.AUTOPILOT_AUTO_UPGRADE_POLICY, + offerAutoscaleAutoUpgradeProperties, + CosmosItemSerializer.DEFAULT_SERIALIZER); } OfferAutoscaleSettings(String json) { @@ -32,7 +39,10 @@ int getMaxThroughput() { } void setMaxThroughput(int maxAutoscaleThroughput) { - super.set(Constants.Properties.AUTOPILOT_MAX_THROUGHPUT, maxAutoscaleThroughput); + super.set( + Constants.Properties.AUTOPILOT_MAX_THROUGHPUT, + maxAutoscaleThroughput, + CosmosItemSerializer.DEFAULT_SERIALIZER); } /** diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/PartitionKeyHelper.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/PartitionKeyHelper.java index 5da54512458a..502dd2ff356a 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/PartitionKeyHelper.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/PartitionKeyHelper.java @@ -33,7 +33,7 @@ public static PartitionKey extractPartitionKeyFromDocument( String path = partitionKeyDefinition.getPaths().iterator().next(); List parts = PathParser.getPathParts(path); if (parts.size() >= 1) { - Object value = ModelBridgeInternal.getObjectByPathFromJsonSerializable(document, parts); + Object value = document.getObjectByPath(parts); if (value == null || value.getClass() == ObjectNode.class) { value = ModelBridgeInternal.getNonePartitionKey(partitionKeyDefinition); } @@ -56,7 +56,7 @@ public static PartitionKey extractPartitionKeyFromDocument( for(int pathIter = 0 ; pathIter < partitionKeyDefinition.getPaths().size(); pathIter++){ String partitionPath = partitionKeyDefinition.getPaths().get(pathIter); List partitionPathParts = PathParser.getPathParts(partitionPath); - partitionKeyValues[pathIter] = ModelBridgeInternal.getObjectByPathFromJsonSerializable(document, partitionPathParts); + partitionKeyValues[pathIter] = document.getObjectByPath(partitionPathParts); } return ImplementationBridgeHelpers diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/PartitionKeyRange.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/PartitionKeyRange.java index 8483b9b4ca8c..4c13385a09bf 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/PartitionKeyRange.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/PartitionKeyRange.java @@ -3,8 +3,8 @@ package com.azure.cosmos.implementation; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.routing.Range; -import com.azure.cosmos.BridgeInternal; import com.fasterxml.jackson.databind.node.ObjectNode; import java.util.List; @@ -75,7 +75,7 @@ public String getMinInclusive() { } public PartitionKeyRange setMinInclusive(String minInclusive) { - BridgeInternal.setProperty(this, "minInclusive", minInclusive); + this.set("minInclusive", minInclusive, CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } @@ -84,12 +84,12 @@ public String getMaxExclusive() { } public PartitionKeyRange setMaxExclusive(String maxExclusive) { - BridgeInternal.setProperty(this, "maxExclusive", maxExclusive); + this.set("maxExclusive", maxExclusive, CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } public Range toRange() { - return new Range(this.getMinInclusive(), this.getMaxExclusive(), true, false); + return new Range<>(this.getMinInclusive(), this.getMaxExclusive(), true, false); } @Override @@ -115,7 +115,7 @@ public int hashCode() { } public void setParents(List parents) { - BridgeInternal.setProperty(this, Constants.Properties.PARENTS, parents); + this.set(Constants.Properties.PARENTS, parents, CosmosItemSerializer.DEFAULT_SERIALIZER); } /** diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Permission.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Permission.java index e0eb1d05c91c..d3d5fa53988c 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Permission.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Permission.java @@ -3,7 +3,7 @@ package com.azure.cosmos.implementation; -import com.azure.cosmos.BridgeInternal; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.models.ModelBridgeInternal; import com.azure.cosmos.models.PartitionKey; import com.azure.cosmos.models.PermissionMode; @@ -62,7 +62,7 @@ public String getResourceLink() { * @param resourceLink the resource link. */ public void setResourceLink(String resourceLink) { - BridgeInternal.setProperty(this, Constants.Properties.RESOURCE_LINK, resourceLink); + this.set(Constants.Properties.RESOURCE_LINK, resourceLink, CosmosItemSerializer.DEFAULT_SERIALIZER); } /** @@ -81,8 +81,10 @@ public PermissionMode getPermissionMode() { * @param permissionMode the permission mode. */ public void setPermissionMode(PermissionMode permissionMode) { - BridgeInternal.setProperty(this, Constants.Properties.PERMISSION_MODE, - permissionMode.toString().toLowerCase(Locale.ROOT)); + this.set( + Constants.Properties.PERMISSION_MODE, + permissionMode.toString().toLowerCase(Locale.ROOT), + CosmosItemSerializer.DEFAULT_SERIALIZER); } /** @@ -104,7 +106,7 @@ public PartitionKey getResourcePartitionKey() { Object value = super.get(Constants.Properties.RESOURCE_PARTITION_KEY); if (value != null) { ArrayNode arrayValue = (ArrayNode) value; - key = new PartitionKey(BridgeInternal.getValue(arrayValue.get(0))); + key = new PartitionKey(JsonSerializable.getValue(arrayValue.get(0))); } return key; @@ -118,8 +120,9 @@ public PartitionKey getResourcePartitionKey() { public void setResourcePartitionKey(PartitionKey partitionkey) { checkNotNull(partitionkey, "Partition key can not be null"); - BridgeInternal.setProperty(this, + this.set( Constants.Properties.RESOURCE_PARTITION_KEY, - ModelBridgeInternal.getPartitionKeyInternal(partitionkey).toObjectArray()); + ModelBridgeInternal.getPartitionKeyInternal(partitionkey).toObjectArray(), + CosmosItemSerializer.DEFAULT_SERIALIZER); } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/PrimitiveJsonNodeMap.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/PrimitiveJsonNodeMap.java new file mode 100644 index 000000000000..04caf9f362a8 --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/PrimitiveJsonNodeMap.java @@ -0,0 +1,131 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.cosmos.implementation; + +import com.fasterxml.jackson.databind.JsonNode; + +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkArgument; +import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; + +public class PrimitiveJsonNodeMap implements Map { + public final static String VALUE_KEY = "__primitive_json-node_value__"; + private final Object thisLock = new Object(); + private final JsonNode primitiveJsonNode; + private volatile LinkedHashMap jsonNodeAsMap = null; + + public PrimitiveJsonNodeMap(JsonNode jsonNode) { + checkNotNull(jsonNode, "Argument 'jsonNode' must not be null."); + checkArgument( + !jsonNode.isObject(), + "Argument 'jsonNode' should not be an object - for objects use ObjectNodeMap."); + + this.primitiveJsonNode = jsonNode; + } + + public JsonNode getPrimitiveJsonNode() { + return this.primitiveJsonNode; + } + + @SuppressWarnings("unchecked") + private Map ensureJsonNodeAsMap() { + if (this.jsonNodeAsMap != null) { + return this.jsonNodeAsMap; + } + + synchronized (this.thisLock) { + if (this.jsonNodeAsMap != null) { + return this.jsonNodeAsMap; + } + + this.jsonNodeAsMap = new LinkedHashMap<>(); + this.jsonNodeAsMap.put(VALUE_KEY, this.primitiveJsonNode); + + return this.jsonNodeAsMap; + } + } + + @Override + public int size() { + return this.ensureJsonNodeAsMap().size(); + } + + @Override + public boolean isEmpty() { + return this.ensureJsonNodeAsMap().isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return this.ensureJsonNodeAsMap().containsKey(key); + } + + @Override + public boolean containsValue(Object value) { + return this.ensureJsonNodeAsMap().containsValue(value); + } + + @Override + public Object get(Object key) { + return this.ensureJsonNodeAsMap().get(key); + } + + @Override + public Object put(String key, Object value) { + return this.ensureJsonNodeAsMap().put(key, value); + } + + @Override + public Object remove(Object key) { + return this.ensureJsonNodeAsMap().remove(key); + } + + @Override + public void putAll(Map m) { + this.ensureJsonNodeAsMap().putAll(m); + } + + @Override + public void clear() { + this.ensureJsonNodeAsMap().clear(); + } + + @Override + public Set keySet() { + return this.ensureJsonNodeAsMap().keySet(); + } + + @Override + public Collection values() { + return this.ensureJsonNodeAsMap().values(); + } + + @Override + public Set> entrySet() { + return this.ensureJsonNodeAsMap().entrySet(); + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + + if (!(o instanceof PrimitiveJsonNodeMap)) { + return false; + } + + PrimitiveJsonNodeMap other = (PrimitiveJsonNodeMap) o; + + return this.primitiveJsonNode.equals(other.primitiveJsonNode); + } + + @Override + public int hashCode() { + return this.primitiveJsonNode.hashCode(); + } +} diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RangeIndex.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RangeIndex.java index 7abc9d353299..9dbb5edcd004 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RangeIndex.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RangeIndex.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.apachecommons.lang.StringUtils; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -83,7 +84,7 @@ public DataType getDataType() { * @return the RangeIndex. */ public RangeIndex setDataType(DataType dataType) { - super.set(Constants.Properties.DATA_TYPE, dataType.toString()); + super.set(Constants.Properties.DATA_TYPE, dataType.toString(), CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } @@ -103,7 +104,7 @@ public int getPrecision() { * @return the RangeIndex. */ public RangeIndex setPrecision(int precision) { - super.set(Constants.Properties.PRECISION, precision); + super.set(Constants.Properties.PRECISION, precision, CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ReplicationPolicy.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ReplicationPolicy.java index 786f0caf12df..7196b5e8aef1 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ReplicationPolicy.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ReplicationPolicy.java @@ -3,7 +3,7 @@ package com.azure.cosmos.implementation; -import com.azure.cosmos.BridgeInternal; +import com.azure.cosmos.CosmosItemSerializer; import com.fasterxml.jackson.databind.node.ObjectNode; /** @@ -57,7 +57,7 @@ public int getMaxReplicaSetSize() { } public void setMaxReplicaSetSize(int value) { - BridgeInternal.setProperty(this, Constants.Properties.MAX_REPLICA_SET_SIZE, value); + this.set(Constants.Properties.MAX_REPLICA_SET_SIZE, value, CosmosItemSerializer.DEFAULT_SERIALIZER); this.maxReplicaSetSize = value; } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RequestOptions.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RequestOptions.java index 38089dbe24a8..658e90672987 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RequestOptions.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RequestOptions.java @@ -7,6 +7,7 @@ import com.azure.cosmos.CosmosDiagnosticsContext; import com.azure.cosmos.CosmosDiagnosticsThresholds; import com.azure.cosmos.CosmosEndToEndOperationLatencyPolicyConfig; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.spark.OperationContextAndListenerTuple; import com.azure.cosmos.models.DedicatedGatewayRequestOptions; import com.azure.cosmos.models.IndexingDirective; @@ -17,7 +18,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; @@ -54,11 +54,14 @@ public class RequestOptions { private List excludeRegions; private Supplier diagnosticsCtxSupplier; + private CosmosItemSerializer effectiveItemSerializer; private final AtomicReference markE2ETimeoutInRequestContextCallbackHook; public RequestOptions() { + this.markE2ETimeoutInRequestContextCallbackHook = new AtomicReference<>(null); + this.effectiveItemSerializer = CosmosItemSerializer.DEFAULT_SERIALIZER; } public RequestOptions(RequestOptions toBeCloned) { @@ -85,6 +88,7 @@ public RequestOptions(RequestOptions toBeCloned) { this.endToEndOperationLatencyConfig = toBeCloned.endToEndOperationLatencyConfig; this.diagnosticsCtxSupplier = toBeCloned.diagnosticsCtxSupplier; this.markE2ETimeoutInRequestContextCallbackHook = new AtomicReference<>(null); + this.effectiveItemSerializer= toBeCloned.effectiveItemSerializer; if (toBeCloned.customOptions != null) { this.customOptions = new HashMap<>(toBeCloned.customOptions); @@ -536,4 +540,12 @@ public void setExcludeRegions(List excludeRegions) { public AtomicReference getMarkE2ETimeoutInRequestContextCallbackHook() { return this.markE2ETimeoutInRequestContextCallbackHook; } + + public CosmosItemSerializer getEffectiveItemSerializer() { + return this.effectiveItemSerializer; + } + + public void setEffectiveItemSerializer(CosmosItemSerializer serializer) { + this.effectiveItemSerializer = serializer; + } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Resource.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Resource.java index d18202d069b7..d8398d238b78 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Resource.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Resource.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation; +import com.azure.cosmos.CosmosItemSerializer; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.azure.cosmos.implementation.apachecommons.lang.StringUtils; @@ -117,7 +118,7 @@ public String getId() { * @return the resource. */ public Resource setId(String id) { - super.set(Constants.Properties.ID, id); + super.set(Constants.Properties.ID, id, CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } @@ -137,7 +138,7 @@ public String getResourceId() { * @return the resource. */ public Resource setResourceId(String resourceId) { - super.set(Constants.Properties.R_ID, resourceId); + super.set(Constants.Properties.R_ID, resourceId, CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } @@ -156,7 +157,7 @@ public String getSelfLink() { * @param selfLink the self link. */ public Resource setSelfLink(String selfLink) { - super.set(Constants.Properties.SELF_LINK, selfLink); + super.set(Constants.Properties.SELF_LINK, selfLink, CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } @@ -180,7 +181,7 @@ public Instant getTimestamp() { */ public Resource setTimestamp(Instant timestamp) { long seconds = timestamp.getEpochSecond(); - super.set(Constants.Properties.LAST_MODIFIED, seconds); + super.set(Constants.Properties.LAST_MODIFIED, seconds, CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } @@ -199,7 +200,7 @@ public String getETag() { * @param eTag the e tag. */ Resource setETag(String eTag) { - super.set(Constants.Properties.E_TAG, eTag); + super.set(Constants.Properties.E_TAG, eTag, CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentClientImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentClientImpl.java index 0199e70e5df7..609cee19b660 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentClientImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentClientImpl.java @@ -14,6 +14,7 @@ import com.azure.cosmos.CosmosDiagnosticsContext; import com.azure.cosmos.CosmosEndToEndOperationLatencyPolicyConfig; import com.azure.cosmos.CosmosException; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.DirectConnectionConfig; import com.azure.cosmos.SessionRetryOptions; import com.azure.cosmos.ThresholdBasedAvailabilityStrategy; @@ -66,6 +67,7 @@ import com.azure.cosmos.models.CosmosClientTelemetryConfig; import com.azure.cosmos.models.CosmosContainerIdentity; import com.azure.cosmos.models.CosmosItemIdentity; +import com.azure.cosmos.models.CosmosItemRequestOptions; import com.azure.cosmos.models.CosmosItemResponse; import com.azure.cosmos.models.CosmosPatchOperations; import com.azure.cosmos.models.CosmosQueryRequestOptions; @@ -77,7 +79,6 @@ import com.azure.cosmos.models.PartitionKind; import com.azure.cosmos.models.SqlParameter; import com.azure.cosmos.models.SqlQuerySpec; -import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import org.slf4j.Logger; @@ -115,18 +116,16 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiFunction; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; -import static com.azure.cosmos.BridgeInternal.documentFromObject; import static com.azure.cosmos.BridgeInternal.getAltLink; -import static com.azure.cosmos.BridgeInternal.toFeedResponsePage; import static com.azure.cosmos.BridgeInternal.toResourceResponse; import static com.azure.cosmos.BridgeInternal.toStoredProcedureResponse; import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkArgument; import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; -import static com.azure.cosmos.models.ModelBridgeInternal.serializeJsonToByteBuffer; /** * While this class is public, it is not part of our published public APIs. @@ -143,6 +142,10 @@ public class RxDocumentClientImpl implements AsyncDocumentClient, IAuthorization ImplementationBridgeHelpers.CosmosDiagnosticsHelper.CosmosDiagnosticsAccessor diagnosticsAccessor = ImplementationBridgeHelpers.CosmosDiagnosticsHelper.getCosmosDiagnosticsAccessor(); + private final static + ImplementationBridgeHelpers.FeedResponseHelper.FeedResponseAccessor feedResponseAccessor = + ImplementationBridgeHelpers.FeedResponseHelper.getFeedResponseAccessor(); + private final static ImplementationBridgeHelpers.CosmosClientTelemetryConfigHelper.CosmosClientTelemetryConfigAccessor telemetryCfgAccessor = ImplementationBridgeHelpers.CosmosClientTelemetryConfigHelper.getCosmosClientTelemetryConfigAccessor(); @@ -155,6 +158,10 @@ public class RxDocumentClientImpl implements AsyncDocumentClient, IAuthorization ImplementationBridgeHelpers.CosmosQueryRequestOptionsHelper.CosmosQueryRequestOptionsAccessor qryOptAccessor = ImplementationBridgeHelpers.CosmosQueryRequestOptionsHelper.getCosmosQueryRequestOptionsAccessor(); + private final static + ImplementationBridgeHelpers.CosmosItemResponseHelper.CosmosItemResponseBuilderAccessor itemResponseAccessor = + ImplementationBridgeHelpers.CosmosItemResponseHelper.getCosmosItemResponseBuilderAccessor(); + private static final String tempMachineId = "uuid:" + UUID.randomUUID(); private static final AtomicInteger activeClientsCnt = new AtomicInteger(0); private static final Map clientMap = new ConcurrentHashMap<>(); @@ -166,7 +173,7 @@ public class RxDocumentClientImpl implements AsyncDocumentClient, IAuthorization private static final String DUMMY_SQL_QUERY = "this is dummy and only used in creating " + "ParallelDocumentQueryExecutioncontext, but not used"; private final static ObjectMapper mapper = Utils.getSimpleObjectMapper(); - private final ItemDeserializer itemDeserializer = new ItemDeserializer.JsonDeserializer(); + private final CosmosItemSerializer defaultCustomSerializer; private final static Logger logger = LoggerFactory.getLogger(RxDocumentClientImpl.class); private final String masterKeyOrResourceToken; private final URI serviceEndpoint; @@ -250,7 +257,8 @@ public RxDocumentClientImpl(URI serviceEndpoint, String clientCorrelationId, CosmosEndToEndOperationLatencyPolicyConfig cosmosEndToEndOperationLatencyPolicyConfig, SessionRetryOptions sessionRetryOptions, - CosmosContainerProactiveInitConfig containerProactiveInitConfig) { + CosmosContainerProactiveInitConfig containerProactiveInitConfig, + CosmosItemSerializer defaultCustomSerializer) { this( serviceEndpoint, masterKeyOrResourceToken, @@ -269,7 +277,8 @@ public RxDocumentClientImpl(URI serviceEndpoint, clientCorrelationId, cosmosEndToEndOperationLatencyPolicyConfig, sessionRetryOptions, - containerProactiveInitConfig); + containerProactiveInitConfig, + defaultCustomSerializer); this.cosmosAuthorizationTokenResolver = cosmosAuthorizationTokenResolver; } @@ -291,7 +300,8 @@ public RxDocumentClientImpl(URI serviceEndpoint, String clientCorrelationId, CosmosEndToEndOperationLatencyPolicyConfig cosmosEndToEndOperationLatencyPolicyConfig, SessionRetryOptions sessionRetryOptions, - CosmosContainerProactiveInitConfig containerProactiveInitConfig) { + CosmosContainerProactiveInitConfig containerProactiveInitConfig, + CosmosItemSerializer defaultCustomSerializer) { this( serviceEndpoint, masterKeyOrResourceToken, @@ -310,7 +320,8 @@ public RxDocumentClientImpl(URI serviceEndpoint, clientCorrelationId, cosmosEndToEndOperationLatencyPolicyConfig, sessionRetryOptions, - containerProactiveInitConfig); + containerProactiveInitConfig, + defaultCustomSerializer); this.cosmosAuthorizationTokenResolver = cosmosAuthorizationTokenResolver; } @@ -331,7 +342,8 @@ private RxDocumentClientImpl(URI serviceEndpoint, String clientCorrelationId, CosmosEndToEndOperationLatencyPolicyConfig cosmosEndToEndOperationLatencyPolicyConfig, SessionRetryOptions sessionRetryOptions, - CosmosContainerProactiveInitConfig containerProactiveInitConfig) { + CosmosContainerProactiveInitConfig containerProactiveInitConfig, + CosmosItemSerializer defaultCustomSerializer) { this( serviceEndpoint, masterKeyOrResourceToken, @@ -349,7 +361,8 @@ private RxDocumentClientImpl(URI serviceEndpoint, clientCorrelationId, cosmosEndToEndOperationLatencyPolicyConfig, sessionRetryOptions, - containerProactiveInitConfig); + containerProactiveInitConfig, + defaultCustomSerializer); if (permissionFeed != null && permissionFeed.size() > 0) { this.resourceTokensMap = new HashMap<>(); @@ -409,7 +422,8 @@ private RxDocumentClientImpl(URI serviceEndpoint, String clientCorrelationId, CosmosEndToEndOperationLatencyPolicyConfig cosmosEndToEndOperationLatencyPolicyConfig, SessionRetryOptions sessionRetryOptions, - CosmosContainerProactiveInitConfig containerProactiveInitConfig) { + CosmosContainerProactiveInitConfig containerProactiveInitConfig, + CosmosItemSerializer defaultCustomSerializer) { assert(clientTelemetryConfig != null); Boolean clientTelemetryEnabled = ImplementationBridgeHelpers @@ -433,6 +447,7 @@ private RxDocumentClientImpl(URI serviceEndpoint, this.cosmosEndToEndOperationLatencyPolicyConfig = cosmosEndToEndOperationLatencyPolicyConfig; this.diagnosticsClientConfig.withEndToEndOperationLatencyPolicy(cosmosEndToEndOperationLatencyPolicyConfig); this.sessionRetryOptions = sessionRetryOptions; + this.defaultCustomSerializer = defaultCustomSerializer; logger.info( "Initializing DocumentClient [{}] with" @@ -829,7 +844,7 @@ private Mono> createDatabaseInternal(Database databas Map requestHeaders = this.getRequestHeaders(options, ResourceType.Database, OperationType.Create); Instant serializationStartTimeUTC = Instant.now(); - ByteBuffer byteBuffer = ModelBridgeInternal.serializeJsonToByteBuffer(database); + ByteBuffer byteBuffer = database.serializeJsonToByteBuffer(CosmosItemSerializer.DEFAULT_SERIALIZER, null); Instant serializationEndTimeUTC = Instant.now(); SerializationDiagnosticsContext.SerializationDiagnostics serializationDiagnostics = new SerializationDiagnosticsContext.SerializationDiagnostics( serializationStartTimeUTC, @@ -1236,7 +1251,7 @@ private Mono> createCollectionInternal(Stri Map requestHeaders = this.getRequestHeaders(options, ResourceType.DocumentCollection, OperationType.Create); Instant serializationStartTimeUTC = Instant.now(); - ByteBuffer byteBuffer = ModelBridgeInternal.serializeJsonToByteBuffer(collection); + ByteBuffer byteBuffer = collection.serializeJsonToByteBuffer(CosmosItemSerializer.DEFAULT_SERIALIZER, null); Instant serializationEndTimeUTC = Instant.now(); SerializationDiagnosticsContext.SerializationDiagnostics serializationDiagnostics = new SerializationDiagnosticsContext.SerializationDiagnostics( serializationStartTimeUTC, @@ -1287,7 +1302,7 @@ private Mono> replaceCollectionInternal(Doc String path = Utils.joinPath(collection.getSelfLink(), null); Map requestHeaders = this.getRequestHeaders(options, ResourceType.DocumentCollection, OperationType.Replace); Instant serializationStartTimeUTC = Instant.now(); - ByteBuffer byteBuffer = ModelBridgeInternal.serializeJsonToByteBuffer(collection); + ByteBuffer byteBuffer = collection.serializeJsonToByteBuffer(CosmosItemSerializer.DEFAULT_SERIALIZER, null); Instant serializationEndTimeUTC = Instant.now(); SerializationDiagnosticsContext.SerializationDiagnostics serializationDiagnostics = new SerializationDiagnosticsContext.SerializationDiagnostics( serializationStartTimeUTC, @@ -1474,7 +1489,7 @@ private static String serializeProcedureParams(List objectArray) { for (int i = 0; i < objectArray.size(); ++i) { Object object = objectArray.get(i); if (object instanceof JsonSerializable) { - stringArray[i] = ModelBridgeInternal.toJsonFromJsonSerializable((JsonSerializable) object); + stringArray[i] = ((JsonSerializable) object).toJson(); } else { // POJO, ObjectNode, number, STRING or Boolean @@ -1604,7 +1619,7 @@ private Map getRequestHeaders(RequestOptions options, ResourceTy headers.put(HttpConstants.HttpHeaders.OFFER_THROUGHPUT, String.valueOf(offer.getThroughput())); } else if (offer.getOfferAutoScaleSettings() != null) { headers.put(HttpConstants.HttpHeaders.OFFER_AUTOPILOT_SETTINGS, - ModelBridgeInternal.toJsonFromJsonSerializable(offer.getOfferAutoScaleSettings())); + offer.getOfferAutoScaleSettings().toJson()); } } } @@ -1731,7 +1746,7 @@ private Mono getCreateDocumentRequest(DocumentClientRe if (options != null) { trackingId = options.getTrackingId(); } - ByteBuffer content = InternalObjectNode.serializeJsonToByteBuffer(document, mapper, trackingId); + ByteBuffer content = InternalObjectNode.serializeJsonToByteBuffer(document, options.getEffectiveItemSerializer(), trackingId); Instant serializationEndTimeUTC = Instant.now(); SerializationDiagnosticsContext.SerializationDiagnostics serializationDiagnostics = new SerializationDiagnosticsContext.SerializationDiagnostics( @@ -2385,7 +2400,7 @@ private Mono> replaceDocumentInternal( throw new IllegalArgumentException("document"); } - Document typedDocument = documentFromObject(document, mapper); + Document typedDocument = Document.fromObject(document, options.getEffectiveItemSerializer()); return this.replaceDocumentInternal( documentLink, @@ -2480,15 +2495,16 @@ private Mono> replaceDocumentInternal( final Map requestHeaders = getRequestHeaders(options, ResourceType.Document, OperationType.Replace); Instant serializationStartTimeUTC = Instant.now(); + Consumer> onAfterSerialization = null; if (options != null) { String trackingId = options.getTrackingId(); if (trackingId != null && !trackingId.isEmpty()) { - document.set(Constants.Properties.TRACKING_ID, trackingId); + onAfterSerialization = (node) -> node.put(Constants.Properties.TRACKING_ID, trackingId); } } - ByteBuffer content = serializeJsonToByteBuffer(document); + ByteBuffer content = document.serializeJsonToByteBuffer(options.getEffectiveItemSerializer(), onAfterSerialization); Instant serializationEndTime = Instant.now(); SerializationDiagnosticsContext.SerializationDiagnostics serializationDiagnostics = new SerializationDiagnosticsContext.SerializationDiagnostics( @@ -3296,7 +3312,7 @@ private Flux> pointReadsForReadMany( // if there is any factory method being passed in, use the factory method to deserializ the object // else fallback to use the original way // typically used by spark trying to convert into SparkRowItem - ItemDeserializer effectiveItemDeserializer = getEffectiveItemDeserializer(queryRequestOptions, klass); + CosmosItemSerializer effectiveItemSerializer = getEffectiveItemSerializer(queryRequestOptions); return Flux.fromIterable(singleItemPartitionRequestMap.values()) .flatMap(cosmosItemIdentityList -> { @@ -3345,7 +3361,8 @@ private Flux> pointReadsForReadMany( BridgeInternal.getClientSideRequestStatics(cosmosException.getDiagnostics()))); } else { CosmosItemResponse cosmosItemResponse = - ModelBridgeInternal.createCosmosAsyncItemResponse(resourceResponse, klass, effectiveItemDeserializer); + itemResponseAccessor.createCosmosItemResponse(resourceResponse, klass, effectiveItemSerializer); + feedResponse = ModelBridgeInternal.createFeedResponse( Arrays.asList(cosmosItemResponse.getItem()), cosmosItemResponse.getResponseHeaders()); @@ -3367,18 +3384,33 @@ public Flux> queryDocuments( return queryDocuments(collectionLink, new SqlQuerySpec(query), state, classOfT); } - private ItemDeserializer getEffectiveItemDeserializer( - CosmosQueryRequestOptions queryRequestOptions, - Class klass) { - - Function factoryMethod = queryRequestOptions == null ? - null : qryOptAccessor.getImpl(queryRequestOptions).getItemFactoryMethod(klass); + @Override + public CosmosItemSerializer getEffectiveItemSerializer(CosmosItemSerializer requestOptionsItemSerializer) { + if (requestOptionsItemSerializer != null) { + return requestOptionsItemSerializer; + } - if (factoryMethod == null) { - return this.itemDeserializer; // using default itemDeserializer + if (this.defaultCustomSerializer != null) { + return this.defaultCustomSerializer; } - return new ItemDeserializer.JsonDeserializer(factoryMethod); + return CosmosItemSerializer.DEFAULT_SERIALIZER; + } + + private CosmosItemSerializer getEffectiveItemSerializer(CosmosQueryRequestOptions queryRequestOptions) { + + CosmosItemSerializer requestOptionsItemSerializer = + queryRequestOptions != null ? queryRequestOptions.getCustomSerializer() : null; + + return this.getEffectiveItemSerializer(requestOptionsItemSerializer); + } + + private CosmosItemSerializer getEffectiveItemSerializer(CosmosItemRequestOptions itemRequestOptions) { + + CosmosItemSerializer requestOptionsItemSerializer = + itemRequestOptions != null ? itemRequestOptions.getCustomSerializer() : null; + + return this.getEffectiveItemSerializer(requestOptionsItemSerializer); } private IDocumentQueryClient documentQueryClientImpl(RxDocumentClientImpl rxDocumentClientImpl, OperationContextAndListenerTuple operationContextAndListenerTuple) { @@ -3453,6 +3485,11 @@ public Mono executeFeedOperationWithAvailabilityStrategy( ); } + @Override + public CosmosItemSerializer getEffectiveItemSerializer(CosmosQueryRequestOptions queryRequestOptions) { + return RxDocumentClientImpl.this.getEffectiveItemSerializer(queryRequestOptions); + } + @Override public Mono readFeedAsync(RxDocumentServiceRequest request) { // TODO Auto-generated method stub @@ -4939,9 +4976,9 @@ private Flux> nonDocumentReadFeedInternal( Function>> executeFunc = request -> readFeed(request) - .map(response -> toFeedResponsePage( + .map(response -> feedResponseAccessor.createFeedResponse( response, - qryOptAccessor.getImpl(nonNullOptions).getItemFactoryMethod(klass), + CosmosItemSerializer.DEFAULT_SERIALIZER, klass)); return Paginator @@ -5130,12 +5167,6 @@ public void close() { logger.warn("Already shutdown!"); } } - - @Override - public ItemDeserializer getItemDeserializer() { - return this.itemDeserializer; - } - @Override public synchronized void enableThroughputControlGroup(ThroughputControlGroupInternal group, Mono throughputQueryMono) { checkNotNull(group, "Throughput control group can not be null"); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentServiceRequest.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentServiceRequest.java index df0bf4b865a0..2218f3d3c5b9 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentServiceRequest.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentServiceRequest.java @@ -4,6 +4,7 @@ package com.azure.cosmos.implementation; import com.azure.cosmos.CosmosDiagnostics; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.apachecommons.lang.StringUtils; import com.azure.cosmos.implementation.directconnectivity.WFConstants; import com.azure.cosmos.implementation.faultinjection.FaultInjectionRequestContext; @@ -386,7 +387,7 @@ public static RxDocumentServiceRequest create(DiagnosticsClientContext clientCon Object options) { RxDocumentServiceRequest request = new RxDocumentServiceRequest(clientContext, operation, resourceType, relativePath, - ModelBridgeInternal.serializeJsonToByteBuffer(resource), headers, AuthorizationTokenType.PrimaryMasterKey); + resource.serializeJsonToByteBuffer(CosmosItemSerializer.DEFAULT_SERIALIZER, null), headers, AuthorizationTokenType.PrimaryMasterKey); request.properties = getProperties(options); request.throughputControlGroupName = getThroughputControlGroupName(options); return request; @@ -571,7 +572,7 @@ public static RxDocumentServiceRequest create(DiagnosticsClientContext clientCon ResourceType resourceType, String relativePath, Map headers) { - ByteBuffer resourceContent = ModelBridgeInternal.serializeJsonToByteBuffer(resource); + ByteBuffer resourceContent = resource.serializeJsonToByteBuffer(CosmosItemSerializer.DEFAULT_SERIALIZER, null); return new RxDocumentServiceRequest(clientContext, operation, resourceType, relativePath, resourceContent, headers, AuthorizationTokenType.PrimaryMasterKey); } @@ -592,7 +593,7 @@ public static RxDocumentServiceRequest create(DiagnosticsClientContext clientCon String relativePath, Map headers, AuthorizationTokenType authorizationTokenType) { - ByteBuffer resourceContent = ModelBridgeInternal.serializeJsonToByteBuffer(resource); + ByteBuffer resourceContent = resource.serializeJsonToByteBuffer(CosmosItemSerializer.DEFAULT_SERIALIZER, null); return new RxDocumentServiceRequest(clientContext, operation, resourceType, relativePath, resourceContent, headers, authorizationTokenType); } @@ -647,7 +648,7 @@ public static RxDocumentServiceRequest create(DiagnosticsClientContext clientCon ResourceType resourceType, Resource resource, Map headers) { - ByteBuffer resourceContent = ModelBridgeInternal.serializeJsonToByteBuffer(resource); + ByteBuffer resourceContent = resource.serializeJsonToByteBuffer(CosmosItemSerializer.DEFAULT_SERIALIZER, null); return new RxDocumentServiceRequest(clientContext, operation, resourceId, resourceType, resourceContent, headers, false, AuthorizationTokenType.PrimaryMasterKey); } @@ -668,7 +669,7 @@ public static RxDocumentServiceRequest create(DiagnosticsClientContext clientCon Resource resource, Map headers, AuthorizationTokenType authorizationTokenType) { - ByteBuffer resourceContent = ModelBridgeInternal.serializeJsonToByteBuffer(resource); + ByteBuffer resourceContent = resource.serializeJsonToByteBuffer(CosmosItemSerializer.DEFAULT_SERIALIZER, null); return new RxDocumentServiceRequest(clientContext, operation, resourceId, resourceType, resourceContent, headers, false, authorizationTokenType); } @@ -722,7 +723,7 @@ public static RxDocumentServiceRequest createFromName( Resource resource, String resourceFullName, ResourceType resourceType) { - ByteBuffer resourceContent = ModelBridgeInternal.serializeJsonToByteBuffer(resource); + ByteBuffer resourceContent = resource.serializeJsonToByteBuffer(CosmosItemSerializer.DEFAULT_SERIALIZER, null); return new RxDocumentServiceRequest(clientContext, operationType, resourceFullName, @@ -741,7 +742,7 @@ public static RxDocumentServiceRequest createFromName( String resourceFullName, ResourceType resourceType, AuthorizationTokenType authorizationTokenType) { - ByteBuffer resourceContent = ModelBridgeInternal.serializeJsonToByteBuffer(resource); + ByteBuffer resourceContent = resource.serializeJsonToByteBuffer(CosmosItemSerializer.DEFAULT_SERIALIZER, null); return new RxDocumentServiceRequest(clientContext, operationType, resourceFullName, diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentServiceResponse.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentServiceResponse.java index 0f215a4a56d4..f9866f565957 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentServiceResponse.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentServiceResponse.java @@ -5,6 +5,7 @@ import com.azure.cosmos.BridgeInternal; import com.azure.cosmos.CosmosDiagnostics; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.apachecommons.lang.StringUtils; import com.azure.cosmos.implementation.directconnectivity.Address; import com.azure.cosmos.implementation.directconnectivity.StoreResponse; @@ -18,7 +19,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.Function; /** * This is core Transport/Connection agnostic response for the Azure Cosmos DB database service. @@ -165,7 +165,7 @@ private ArrayNode extractQueryResponseNodes(String resourceKey) { @SuppressWarnings("unchecked") // Given cls (where cls == Class), objectNode is first decoded to cls and then casted to T. public List getQueryResponse( - Function factoryMethod, + CosmosItemSerializer effectiveSerializer, Class c) { String resourceKey = RxDocumentServiceResponse.getResourceKey(c); @@ -185,9 +185,7 @@ public List getQueryResponse( ? (ObjectNode) fromJson(String.format("{\"%s\": %s}", Constants.Properties.VALUE, jToken)) : (ObjectNode) jToken; - T resource = factoryMethod == null ? - (T) JsonSerializable.instantiateFromObjectNodeAndType(resourceJson, c): - factoryMethod.apply(resourceJson); + T resource = Utils.parse(resourceJson, c, effectiveSerializer); queryResults.add(resource); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/SpatialIndex.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/SpatialIndex.java index 9243238be30d..ddea3b50aaeb 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/SpatialIndex.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/SpatialIndex.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.apachecommons.lang.StringUtils; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -70,7 +71,7 @@ public DataType getDataType() { * @return the SpatialIndex. */ public SpatialIndex setDataType(DataType dataType) { - super.set(Constants.Properties.DATA_TYPE, dataType.toString()); + super.set(Constants.Properties.DATA_TYPE, dataType.toString(), CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/StoredProcedure.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/StoredProcedure.java index 2e30e175f700..a8c69f0358a2 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/StoredProcedure.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/StoredProcedure.java @@ -3,7 +3,7 @@ package com.azure.cosmos.implementation; -import com.azure.cosmos.BridgeInternal; +import com.azure.cosmos.CosmosItemSerializer; import com.fasterxml.jackson.databind.node.ObjectNode; /** @@ -56,7 +56,7 @@ public String getBody() { * @param body the body of the stored procedure. */ public void setBody(String body) { - BridgeInternal.setProperty(this, Constants.Properties.BODY, body); + this.set(Constants.Properties.BODY, body, CosmosItemSerializer.DEFAULT_SERIALIZER); } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Trigger.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Trigger.java index a70c52fe2275..a4edad87308d 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Trigger.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Trigger.java @@ -3,7 +3,7 @@ package com.azure.cosmos.implementation; -import com.azure.cosmos.BridgeInternal; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.apachecommons.lang.StringUtils; import com.azure.cosmos.models.TriggerOperation; import com.azure.cosmos.models.TriggerType; @@ -48,7 +48,7 @@ public String getBody() { * @param body the body of the trigger. */ public void setBody(String body) { - BridgeInternal.setProperty(this, Constants.Properties.BODY, body); + this.set(Constants.Properties.BODY, body, CosmosItemSerializer.DEFAULT_SERIALIZER); } /** @@ -74,7 +74,7 @@ public TriggerType getTriggerType() { * @param triggerType the trigger type. */ public void setTriggerType(TriggerType triggerType) { - BridgeInternal.setProperty(this, Constants.Properties.TRIGGER_TYPE, triggerType.toString()); + this.set(Constants.Properties.TRIGGER_TYPE, triggerType.toString(), CosmosItemSerializer.DEFAULT_SERIALIZER); } /** @@ -100,6 +100,6 @@ public TriggerOperation getTriggerOperation() { * @param triggerOperation the trigger operation. */ public void setTriggerOperation(TriggerOperation triggerOperation) { - BridgeInternal.setProperty(this, Constants.Properties.TRIGGER_OPERATION, triggerOperation.toString()); + this.set(Constants.Properties.TRIGGER_OPERATION, triggerOperation.toString(), CosmosItemSerializer.DEFAULT_SERIALIZER); } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/UserDefinedFunction.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/UserDefinedFunction.java index 59b8a9f8fffc..2055423073d4 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/UserDefinedFunction.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/UserDefinedFunction.java @@ -3,7 +3,7 @@ package com.azure.cosmos.implementation; -import com.azure.cosmos.BridgeInternal; +import com.azure.cosmos.CosmosItemSerializer; import com.fasterxml.jackson.databind.node.ObjectNode; /** @@ -45,7 +45,7 @@ public String getBody() { * @param body the body. */ public void setBody(String body) { - BridgeInternal.setProperty(this, Constants.Properties.BODY, body); + this.set(Constants.Properties.BODY, body, CosmosItemSerializer.DEFAULT_SERIALIZER); } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Utils.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Utils.java index 05449ee1cdcf..011967d9edc4 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Utils.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Utils.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation; import com.azure.cosmos.ConsistencyLevel; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.apachecommons.lang.StringUtils; import com.azure.cosmos.implementation.uuid.EthernetAddress; import com.azure.cosmos.implementation.uuid.Generators; @@ -45,8 +46,10 @@ import java.util.Locale; import java.util.Map; import java.util.UUID; +import java.util.function.Consumer; import java.util.regex.Pattern; +import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkArgument; import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; /** @@ -573,30 +576,63 @@ public static ObjectNode parseJson(String itemResponseBodyAsString) { } } - public static T parse(byte[] item, Class itemClassType) { + public static T parse(byte[] item, Class itemClassType, CosmosItemSerializer itemSerializer) { if (Utils.isEmpty(item)) { return null; } try { - return getSimpleObjectMapper().readValue(item, itemClassType); + JsonNode jsonNode = getSimpleObjectMapper().readValue(item, JsonNode.class); + if (jsonNode instanceof ObjectNode) { + ObjectNode jsonTree = (ObjectNode)jsonNode; + CosmosItemSerializer effectiveSerializer = itemSerializer != null + ? itemSerializer + : CosmosItemSerializer.DEFAULT_SERIALIZER; + + T result = effectiveSerializer.deserialize( + getSimpleObjectMapper().convertValue(jsonTree, ObjectNodeMap.JACKSON_MAP_TYPE), + itemClassType); + return result; + } + + return getSimpleObjectMapper().convertValue(jsonNode, itemClassType); } catch (IOException e) { throw new IllegalStateException( String.format("Failed to parse byte-array %s to POJO.", new String(item, StandardCharsets.UTF_8)), e); } } - public static T parse(JsonNode jsonNode, Class itemClassType, ItemDeserializer itemDeserializer) { - ItemDeserializer effectiveDeserializer = itemDeserializer == null ? - new ItemDeserializer.JsonDeserializer() : itemDeserializer; + public static T parse(ObjectNode jsonNode, Class itemClassType, CosmosItemSerializer itemSerializer) { + CosmosItemSerializer effectiveItemSerializer= itemSerializer == null ? + CosmosItemSerializer.DEFAULT_SERIALIZER : itemSerializer; - return effectiveDeserializer.convert(itemClassType, jsonNode); + return effectiveItemSerializer.deserialize(new ObjectNodeMap(jsonNode), itemClassType); } - public static ByteBuffer serializeJsonToByteBuffer(ObjectMapper objectMapper, Object object) { + @SuppressWarnings("unchecked") + public static ByteBuffer serializeJsonToByteBuffer(CosmosItemSerializer serializer, Object object, Consumer> onAfterSerialization) { + checkArgument(serializer != null || object instanceof Map, "Argument 'serializer' must not be null."); try { ByteBufferOutputStream byteBufferOutputStream = new ByteBufferOutputStream(ONE_KB); - objectMapper.writeValue(byteBufferOutputStream, object); + Map jsonTreeMap = (object instanceof Map && serializer == null) + ? (Map) object + : serializer.serialize(object); + + if (onAfterSerialization != null) { + onAfterSerialization.accept(jsonTreeMap); + } + + JsonNode jsonNode; + + if (jsonTreeMap instanceof PrimitiveJsonNodeMap) { + jsonNode = ((PrimitiveJsonNodeMap)jsonTreeMap).getPrimitiveJsonNode(); + } else if (jsonTreeMap instanceof ObjectNodeMap && onAfterSerialization == null) { + jsonNode = ((ObjectNodeMap) jsonTreeMap).getObjectNode(); + } else { + jsonNode = simpleObjectMapper.convertValue(jsonTreeMap, JsonNode.class); + } + + simpleObjectMapper.writeValue(byteBufferOutputStream, jsonNode); return byteBufferOutputStream.asByteBuffer(); } catch (IOException e) { // TODO moderakh: on serialization/deserialization failure we should throw CosmosException here and elsewhere diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/BatchExecutor.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/BatchExecutor.java index c0189edcc267..a955686d083a 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/BatchExecutor.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/BatchExecutor.java @@ -6,6 +6,8 @@ import com.azure.cosmos.BridgeInternal; import com.azure.cosmos.CosmosAsyncContainer; import com.azure.cosmos.CosmosBridgeInternal; +import com.azure.cosmos.CosmosItemSerializer; +import com.azure.cosmos.implementation.AsyncDocumentClient; import com.azure.cosmos.models.CosmosBatch; import com.azure.cosmos.models.CosmosBatchRequestOptions; import com.azure.cosmos.models.CosmosBatchResponse; @@ -22,6 +24,8 @@ public final class BatchExecutor { private final CosmosAsyncContainer container; private final CosmosBatchRequestOptions options; private final CosmosBatch cosmosBatch; + private final CosmosItemSerializer effectiveItemSerializer; + public BatchExecutor( final CosmosAsyncContainer container, @@ -31,6 +35,10 @@ public BatchExecutor( this.container = container; this.cosmosBatch = cosmosBatch; this.options = options; + AsyncDocumentClient docClientWrapper = CosmosBridgeInternal.getAsyncDocumentClient(container.getDatabase()); + this.effectiveItemSerializer = docClientWrapper.getEffectiveItemSerializer( + this.options != null ? this.options.getCustomSerializer() : null + ); } /** @@ -38,14 +46,15 @@ public BatchExecutor( * * @return Response from the server. */ - public final Mono executeAsync() { + public Mono executeAsync() { List operations = this.cosmosBatch.getOperations(); checkArgument(operations.size() > 0, "Number of operations should be more than 0."); final SinglePartitionKeyServerBatchRequest request = SinglePartitionKeyServerBatchRequest.createBatchRequest( this.cosmosBatch.getPartitionKeyValue(), - operations); + operations, + this.effectiveItemSerializer); request.setAtomicBatch(true); request.setShouldContinueOnError(false); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/BulkExecutor.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/BulkExecutor.java index e53655ed395c..bc6cf162691f 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/BulkExecutor.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/BulkExecutor.java @@ -8,6 +8,7 @@ import com.azure.cosmos.CosmosAsyncContainer; import com.azure.cosmos.CosmosBridgeInternal; import com.azure.cosmos.CosmosException; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.ThrottlingRetryOptions; import com.azure.cosmos.implementation.AsyncDocumentClient; import com.azure.cosmos.implementation.CosmosSchedulers; @@ -108,7 +109,8 @@ public final class BulkExecutor implements Disposable { private final AtomicBoolean isShutdown = new AtomicBoolean(false); private final AtomicInteger totalCount; private final static Sinks.EmitFailureHandler serializedEmitFailureHandler = new SerializedEmitFailureHandler(); - private final static Sinks.EmitFailureHandler serializedCompleteEmitFailureHandler = new SerializedCompleteEmitFailureHandler();; + private final static Sinks.EmitFailureHandler serializedCompleteEmitFailureHandler = + new SerializedCompleteEmitFailureHandler(); private final Sinks.Many mainSink; private final List> groupSinks; private final CosmosAsyncClient cosmosClient; @@ -116,6 +118,7 @@ public final class BulkExecutor implements Disposable { private final AtomicReference scheduledFutureForFlush; private final String identifier = "BulkExecutor-" + instanceCount.incrementAndGet(); private final BulkExecutorDiagnosticsTracker diagnosticsTracker; + private final CosmosItemSerializer effectiveItemSerializer; public BulkExecutor(CosmosAsyncContainer container, Flux inputOperations, @@ -136,6 +139,7 @@ public BulkExecutor(CosmosAsyncContainer container, .CosmosAsyncDatabaseHelper .getCosmosAsyncDatabaseAccessor() .getCosmosAsyncClient(container.getDatabase()); + this.effectiveItemSerializer = this.docClientWrapper.getEffectiveItemSerializer(cosmosBulkOptions.getCustomSerializer()); this.throttlingRetryOptions = docClientWrapper.getConnectionPolicy().getThrottlingRetryOptions(); @@ -552,7 +556,7 @@ private Flux> executePartitionedGroup( private int calculateTotalSerializedLength(AtomicInteger currentTotalSerializedLength, CosmosItemOperation item) { if (item instanceof CosmosItemOperationBase) { return currentTotalSerializedLength.accumulateAndGet( - ((CosmosItemOperationBase) item).getSerializedLength(), + ((CosmosItemOperationBase) item).getSerializedLength(this.effectiveItemSerializer), Integer::sum); } @@ -571,7 +575,7 @@ private Flux> executeOperations( String pkRange = thresholds.getPartitionKeyRangeId(); ServerOperationBatchRequest serverOperationBatchRequest = - BulkExecutorUtil.createBatchRequest(operations, pkRange, this.maxMicroBatchPayloadSizeInBytes); + BulkExecutorUtil.createBatchRequest(operations, pkRange, this.maxMicroBatchPayloadSizeInBytes, this.effectiveItemSerializer); if (serverOperationBatchRequest.getBatchPendingOperations().size() > 0) { serverOperationBatchRequest.getBatchPendingOperations().forEach(groupSink::next); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/BulkExecutorUtil.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/BulkExecutorUtil.java index 71f0c48b0f38..0042bb612496 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/BulkExecutorUtil.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/BulkExecutorUtil.java @@ -6,6 +6,7 @@ import com.azure.cosmos.BridgeInternal; import com.azure.cosmos.CosmosAsyncContainer; import com.azure.cosmos.CosmosException; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.ThrottlingRetryOptions; import com.azure.cosmos.implementation.AsyncDocumentClient; import com.azure.cosmos.implementation.DocumentCollection; @@ -36,13 +37,18 @@ final class BulkExecutorUtil { - static ServerOperationBatchRequest createBatchRequest(List operations, String partitionKeyRangeId, int maxMicroBatchPayloadSizeInBytes) { + static ServerOperationBatchRequest createBatchRequest( + List operations, + String partitionKeyRangeId, + int maxMicroBatchPayloadSizeInBytes, + CosmosItemSerializer clientItemSerializer) { return PartitionKeyRangeServerBatchRequest.createBatchRequest( partitionKeyRangeId, operations, maxMicroBatchPayloadSizeInBytes, - Math.min(operations.size(), BatchRequestResponseConstants.MAX_OPERATIONS_IN_DIRECT_MODE_BATCH_REQUEST)); + Math.min(operations.size(), BatchRequestResponseConstants.MAX_OPERATIONS_IN_DIRECT_MODE_BATCH_REQUEST), + clientItemSerializer); } static void setRetryPolicyForBulk( diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/CosmosItemOperationBase.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/CosmosItemOperationBase.java index 6144593eeeeb..ebc68ea5aca2 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/CosmosItemOperationBase.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/CosmosItemOperationBase.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation.batch; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.JsonSerializable; import com.azure.cosmos.models.CosmosItemOperation; @@ -18,24 +19,26 @@ public CosmosItemOperationBase() { this.serializedOperation = new AtomicReference<>(null); } - abstract JsonSerializable getSerializedOperationInternal(); + public abstract CosmosItemSerializer getEffectiveItemSerializerForResult(); - public JsonSerializable getSerializedOperation() { + abstract JsonSerializable getSerializedOperationInternal(CosmosItemSerializer effectiveItemSerializer); + + public JsonSerializable getSerializedOperation(CosmosItemSerializer effectiveItemSerializer) { if (this.serializedOperation.get() == null) { - this.serializedOperation.compareAndSet(null, this.getSerializedOperationInternal()); + this.serializedOperation.compareAndSet(null, this.getSerializedOperationInternal(effectiveItemSerializer)); } return this.serializedOperation.get(); } - public int getSerializedLength() { + public int getSerializedLength(CosmosItemSerializer effectiveItemSerializer) { if (this.serializedLengthReference.get() == null) { - this.serializedLengthReference.compareAndSet(null, this.getSerializedLengthInternal()); + this.serializedLengthReference.compareAndSet(null, this.getSerializedLengthInternal(effectiveItemSerializer)); } return this.serializedLengthReference.get(); } - private int getSerializedLengthInternal() { - JsonSerializable operationSerializable = this.getSerializedOperation(); + private int getSerializedLengthInternal(CosmosItemSerializer effectiveItemSerializer) { + JsonSerializable operationSerializable = this.getSerializedOperation(effectiveItemSerializer); String serializedValue = operationSerializable.toString(); return serializedValue.codePointCount(0, serializedValue.length()); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/FlushBuffersItemOperation.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/FlushBuffersItemOperation.java index d15fa687ad1e..709c11cfc1c2 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/FlushBuffersItemOperation.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/FlushBuffersItemOperation.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation.batch; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.JsonSerializable; import com.azure.cosmos.models.CosmosItemOperationType; import com.azure.cosmos.models.PartitionKey; @@ -14,6 +15,11 @@ public class FlushBuffersItemOperation extends CosmosItemOperationBase { private FlushBuffersItemOperation() { } + @Override + public CosmosItemSerializer getEffectiveItemSerializerForResult() { + return CosmosItemSerializer.DEFAULT_SERIALIZER; + } + @Override public String getId() { return fixedId; @@ -40,7 +46,7 @@ public T getContext() { } @Override - JsonSerializable getSerializedOperationInternal() { + JsonSerializable getSerializedOperationInternal(CosmosItemSerializer effectiveItemSerializer) { throw new UnsupportedOperationException("Not supported."); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/ItemBatchOperation.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/ItemBatchOperation.java index c08d31c373d9..7eef76cef0ac 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/ItemBatchOperation.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/ItemBatchOperation.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation.batch; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.JsonSerializable; import com.azure.cosmos.implementation.RequestOptions; import com.azure.cosmos.implementation.apachecommons.lang.StringUtils; @@ -22,12 +23,13 @@ */ public final class ItemBatchOperation extends CosmosItemOperationBase { - private TInternal item; + private final TInternal item; private final String id; private final PartitionKey partitionKey; private final CosmosItemOperationType operationType; private final RequestOptions requestOptions; + private CosmosItemSerializer effectiveItemSerializerForResult; public ItemBatchOperation( final CosmosItemOperationType operationType, @@ -45,31 +47,47 @@ public ItemBatchOperation( this.requestOptions = requestOptions; } + @Override + public CosmosItemSerializer getEffectiveItemSerializerForResult() { + return this.effectiveItemSerializerForResult != null + ? this.effectiveItemSerializerForResult + : CosmosItemSerializer.DEFAULT_SERIALIZER; + } + /** * Writes a single operation to JsonSerializable. - * TODO(rakkuma): Similarly for hybrid row, operation needs to be written in Hybrid row. - * Issue: https://github.com/Azure/azure-sdk-for-java/issues/15856 * - * @return instance of JsonSerializable containing values for a operation. + * @return instance of JsonSerializable containing values for an operation. */ @Override - JsonSerializable getSerializedOperationInternal() { + JsonSerializable getSerializedOperationInternal(CosmosItemSerializer effectiveItemSerializer) { final JsonSerializable jsonSerializable = new JsonSerializable(); + this.effectiveItemSerializerForResult = effectiveItemSerializer; jsonSerializable.set( BatchRequestResponseConstants.FIELD_OPERATION_TYPE, - ModelBridgeInternal.getOperationValueForCosmosItemOperationType(this.getOperationType())); + ModelBridgeInternal.getOperationValueForCosmosItemOperationType(this.getOperationType()), + CosmosItemSerializer.DEFAULT_SERIALIZER); if (StringUtils.isNotEmpty(this.getId())) { - jsonSerializable.set(BatchRequestResponseConstants.FIELD_ID, this.getId()); + jsonSerializable.set( + BatchRequestResponseConstants.FIELD_ID, + this.getId(), + CosmosItemSerializer.DEFAULT_SERIALIZER); } if (this.getItemInternal() != null) { if (this.getOperationType() == CosmosItemOperationType.PATCH) { - jsonSerializable.set(BatchRequestResponseConstants.FIELD_RESOURCE_BODY, - PatchUtil.serializableBatchPatchOperation((CosmosPatchOperations) this.getItemInternal(), this.getRequestOptions())); + jsonSerializable.set( + BatchRequestResponseConstants.FIELD_RESOURCE_BODY, + PatchUtil.serializableBatchPatchOperation((CosmosPatchOperations) this.getItemInternal(), this.getRequestOptions()), + CosmosItemSerializer.DEFAULT_SERIALIZER); } else { - jsonSerializable.set(BatchRequestResponseConstants.FIELD_RESOURCE_BODY, this.getItemInternal()); + jsonSerializable.set( + BatchRequestResponseConstants.FIELD_RESOURCE_BODY, + this.getItemInternal(), + effectiveItemSerializer, + true); } } @@ -77,11 +95,17 @@ JsonSerializable getSerializedOperationInternal() { RequestOptions requestOptions = this.getRequestOptions(); if (StringUtils.isNotEmpty(requestOptions.getIfMatchETag())) { - jsonSerializable.set(BatchRequestResponseConstants.FIELD_IF_MATCH, requestOptions.getIfMatchETag()); + jsonSerializable.set( + BatchRequestResponseConstants.FIELD_IF_MATCH, + requestOptions.getIfMatchETag(), + CosmosItemSerializer.DEFAULT_SERIALIZER); } if (StringUtils.isNotEmpty(requestOptions.getIfNoneMatchETag())) { - jsonSerializable.set(BatchRequestResponseConstants.FIELD_IF_NONE_MATCH, requestOptions.getIfNoneMatchETag()); + jsonSerializable.set( + BatchRequestResponseConstants.FIELD_IF_NONE_MATCH, + requestOptions.getIfNoneMatchETag(), + CosmosItemSerializer.DEFAULT_SERIALIZER); } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/ItemBulkOperation.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/ItemBulkOperation.java index ff04ee0deb22..ccab373be9cb 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/ItemBulkOperation.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/ItemBulkOperation.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation.batch; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.JsonSerializable; import com.azure.cosmos.implementation.RequestOptions; import com.azure.cosmos.implementation.apachecommons.lang.StringUtils; @@ -30,6 +31,7 @@ public final class ItemBulkOperation extends CosmosItemOper private final RequestOptions requestOptions; private String partitionKeyJson; private BulkOperationRetryPolicy bulkOperationRetryPolicy; + private CosmosItemSerializer effectiveItemSerializerForResult; public ItemBulkOperation( CosmosItemOperationType operationType, @@ -49,6 +51,13 @@ public ItemBulkOperation( this.requestOptions = requestOptions; } + @Override + public CosmosItemSerializer getEffectiveItemSerializerForResult() { + return this.effectiveItemSerializerForResult != null + ? this.effectiveItemSerializerForResult + : CosmosItemSerializer.DEFAULT_SERIALIZER; + } + /** * Writes a single operation to JsonSerializable. * TODO(rakkuma): Similarly for hybrid row, operation needs to be written in Hybrid row. @@ -57,27 +66,47 @@ public ItemBulkOperation( * @return instance of JsonSerializable containing values for a operation. */ @Override - JsonSerializable getSerializedOperationInternal() { + JsonSerializable getSerializedOperationInternal(CosmosItemSerializer effectiveItemSerializer) { final JsonSerializable jsonSerializable = new JsonSerializable(); + this.effectiveItemSerializerForResult = effectiveItemSerializer; jsonSerializable.set( BatchRequestResponseConstants.FIELD_OPERATION_TYPE, - ModelBridgeInternal.getOperationValueForCosmosItemOperationType(this.getOperationType())); + ModelBridgeInternal.getOperationValueForCosmosItemOperationType(this.getOperationType()), + CosmosItemSerializer.DEFAULT_SERIALIZER, + false); if (StringUtils.isNotEmpty(this.getPartitionKeyJson())) { - jsonSerializable.set(BatchRequestResponseConstants.FIELD_PARTITION_KEY, this.getPartitionKeyJson()); + jsonSerializable.set( + BatchRequestResponseConstants.FIELD_PARTITION_KEY, + this.getPartitionKeyJson(), + CosmosItemSerializer.DEFAULT_SERIALIZER, + false); } if (StringUtils.isNotEmpty(this.getId())) { - jsonSerializable.set(BatchRequestResponseConstants.FIELD_ID, this.getId()); + jsonSerializable.set( + BatchRequestResponseConstants.FIELD_ID, + this.getId(), + CosmosItemSerializer.DEFAULT_SERIALIZER, + false); } if (this.getItemInternal() != null) { if (this.getOperationType() == CosmosItemOperationType.PATCH) { - jsonSerializable.set(BatchRequestResponseConstants.FIELD_RESOURCE_BODY, - PatchUtil.serializableBatchPatchOperation((CosmosPatchOperations) this.getItemInternal(), this.getRequestOptions())); + jsonSerializable.set( + BatchRequestResponseConstants.FIELD_RESOURCE_BODY, + PatchUtil.serializableBatchPatchOperation( + (CosmosPatchOperations) this.getItemInternal(), + this.getRequestOptions()), + CosmosItemSerializer.DEFAULT_SERIALIZER, + false); } else { - jsonSerializable.set(BatchRequestResponseConstants.FIELD_RESOURCE_BODY, this.getItemInternal()); + jsonSerializable.set( + BatchRequestResponseConstants.FIELD_RESOURCE_BODY, + this.getItemInternal(), + this.getEffectiveItemSerializerForResult(), + true); } } @@ -85,20 +114,31 @@ JsonSerializable getSerializedOperationInternal() { RequestOptions requestOptions = this.getRequestOptions(); if (StringUtils.isNotEmpty(requestOptions.getIfMatchETag())) { - jsonSerializable.set(BatchRequestResponseConstants.FIELD_IF_MATCH, requestOptions.getIfMatchETag()); + jsonSerializable.set( + BatchRequestResponseConstants.FIELD_IF_MATCH, + requestOptions.getIfMatchETag(), + CosmosItemSerializer.DEFAULT_SERIALIZER, + false); } if (StringUtils.isNotEmpty(requestOptions.getIfNoneMatchETag())) { - jsonSerializable.set(BatchRequestResponseConstants.FIELD_IF_NONE_MATCH, requestOptions.getIfNoneMatchETag()); + jsonSerializable.set( + BatchRequestResponseConstants.FIELD_IF_NONE_MATCH, + requestOptions.getIfNoneMatchETag(), + CosmosItemSerializer.DEFAULT_SERIALIZER, + false); } // If content response on write is not enabled, and operation is document write - then add // minimalReturnPreference field, Otherwise don't add this field, which means return the full response. if (requestOptions.isContentResponseOnWriteEnabled() != null) { if (!requestOptions.isContentResponseOnWriteEnabled() && BulkExecutorUtil.isWriteOperation(operationType)) { - jsonSerializable.set(BatchRequestResponseConstants.FIELD_MINIMAL_RETURN_PREFERENCE, true); + jsonSerializable.set( + BatchRequestResponseConstants.FIELD_MINIMAL_RETURN_PREFERENCE, + true, + CosmosItemSerializer.DEFAULT_SERIALIZER, + false); } - } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/PartitionKeyRangeServerBatchRequest.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/PartitionKeyRangeServerBatchRequest.java index aa44f7a41e03..5e9224ddd65c 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/PartitionKeyRangeServerBatchRequest.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/PartitionKeyRangeServerBatchRequest.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation.batch; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.models.CosmosItemOperation; import java.util.List; @@ -49,7 +50,8 @@ static ServerOperationBatchRequest createBatchRequest( final String partitionKeyRangeId, final List operations, final int maxBodyLength, - final int maxOperationCount) { + final int maxOperationCount, + final CosmosItemSerializer clientItemSerializer) { final PartitionKeyRangeServerBatchRequest request = new PartitionKeyRangeServerBatchRequest( partitionKeyRangeId, @@ -59,7 +61,7 @@ static ServerOperationBatchRequest createBatchRequest( request.setAtomicBatch(false); request.setShouldContinueOnError(true); - List pendingOperations = request.createBodyOfBatchRequest(operations); + List pendingOperations = request.createBodyOfBatchRequest(operations, clientItemSerializer); return new ServerOperationBatchRequest(request, pendingOperations); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/ServerBatchRequest.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/ServerBatchRequest.java index b98e2c73fe30..6748be3cb080 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/ServerBatchRequest.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/batch/ServerBatchRequest.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation.batch; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.JsonSerializable; import com.azure.cosmos.implementation.Utils; import com.azure.cosmos.implementation.apachecommons.collections.list.UnmodifiableList; @@ -49,7 +50,9 @@ public abstract class ServerBatchRequest { * * @return Any pending operations that were not included in the request. */ - final List createBodyOfBatchRequest(final List operations) { + final List createBodyOfBatchRequest( + final List operations, + final CosmosItemSerializer effectiveItemSerializer) { checkNotNull(operations, "expected non-null operations"); @@ -63,8 +66,8 @@ final List createBodyOfBatchRequest(final List operations) { + final List operations, + final CosmosItemSerializer effectiveItemSerializer) { checkNotNull(partitionKey, "expected non-null partitionKey"); checkNotNull(operations, "expected non-null operations"); final SinglePartitionKeyServerBatchRequest request = new SinglePartitionKeyServerBatchRequest(partitionKey); - request.createBodyOfBatchRequest(operations); + request.createBodyOfBatchRequest(operations, effectiveItemSerializer); return request; } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/caches/RxCollectionCache.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/caches/RxCollectionCache.java index 5cbc046082b5..b8db3cad7400 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/caches/RxCollectionCache.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/caches/RxCollectionCache.java @@ -15,7 +15,6 @@ import com.azure.cosmos.implementation.Utils; import com.azure.cosmos.implementation.apachecommons.lang.StringUtils; import com.azure.cosmos.implementation.routing.PartitionKeyRangeIdentity; -import com.azure.cosmos.models.ModelBridgeInternal; import reactor.core.Exceptions; import reactor.core.publisher.Mono; @@ -196,7 +195,7 @@ public Mono refreshAsync(MetadataDiagnosticsContext metaDataDiagnosticsCon if (request.requestContext.resolvedCollectionRid != null) { // Here we will issue backend call only if cache wasn't already refreshed (if whatever is there corresponds to previously resolved collection rid). DocumentCollection obsoleteValue = new DocumentCollection(); - ModelBridgeInternal.setResourceId(obsoleteValue, request.requestContext.resolvedCollectionRid); + obsoleteValue.setResourceId(request.requestContext.resolvedCollectionRid); mono = this.collectionInfoByNameCache.getAsync( resourceFullName, diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/common/ChangeFeedContextClientImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/common/ChangeFeedContextClientImpl.java index 019207172681..895c8a55b643 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/common/ChangeFeedContextClientImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/common/ChangeFeedContextClientImpl.java @@ -164,10 +164,7 @@ public Flux> createDocumentChangeFeedQuery(CosmosAsyncConta .map(response -> { List results = response.getResults() .stream() - .map(document -> - ModelBridgeInternal.toObjectFromJsonSerializable( - document, - klass)) + .map(document -> document.toObject(klass)) .collect(Collectors.toList()); return BridgeInternal.toFeedResponsePage( results, diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/common/ChangeFeedStartFromBeginningImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/common/ChangeFeedStartFromBeginningImpl.java index 4f4954fde1ac..73fd5a87a8ca 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/common/ChangeFeedStartFromBeginningImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/common/ChangeFeedStartFromBeginningImpl.java @@ -2,11 +2,10 @@ // Licensed under the MIT License. package com.azure.cosmos.implementation.changefeed.common; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.RxDocumentServiceRequest; -import static com.azure.cosmos.BridgeInternal.setProperty; - class ChangeFeedStartFromBeginningImpl extends ChangeFeedStartFromInternal { public ChangeFeedStartFromBeginningImpl() { super(); @@ -17,10 +16,10 @@ public void populatePropertyBag() { super.populatePropertyBag(); synchronized(this) { - setProperty( - this, + this.set( Constants.Properties.CHANGE_FEED_START_FROM_TYPE, - ChangeFeedStartFromTypes.BEGINNING); + ChangeFeedStartFromTypes.BEGINNING, + CosmosItemSerializer.DEFAULT_SERIALIZER); } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/common/ChangeFeedStartFromETagAndFeedRangeImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/common/ChangeFeedStartFromETagAndFeedRangeImpl.java index 521bfc43fc92..9fef58737ba0 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/common/ChangeFeedStartFromETagAndFeedRangeImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/common/ChangeFeedStartFromETagAndFeedRangeImpl.java @@ -3,12 +3,12 @@ package com.azure.cosmos.implementation.changefeed.common; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.HttpConstants; import com.azure.cosmos.implementation.RxDocumentServiceRequest; import com.azure.cosmos.implementation.feedranges.FeedRangeInternal; -import static com.azure.cosmos.BridgeInternal.setProperty; import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; /** @@ -86,15 +86,15 @@ public void populatePropertyBag() { super.populatePropertyBag(); synchronized(this) { - setProperty( - this, + this.set( Constants.Properties.CHANGE_FEED_START_FROM_TYPE, - ChangeFeedStartFromTypes.LEASE); + ChangeFeedStartFromTypes.LEASE, + CosmosItemSerializer.DEFAULT_SERIALIZER); - setProperty( - this, + this.set( Constants.Properties.CHANGE_FEED_START_FROM_ETAG, - this.eTag); + this.eTag, + CosmosItemSerializer.DEFAULT_SERIALIZER); this.feedRange.setProperties( this, diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/common/ChangeFeedStartFromLegacyContinuationImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/common/ChangeFeedStartFromLegacyContinuationImpl.java index 10dbaa69ce32..6ffc441932d0 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/common/ChangeFeedStartFromLegacyContinuationImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/common/ChangeFeedStartFromLegacyContinuationImpl.java @@ -2,11 +2,10 @@ // Licensed under the MIT License. package com.azure.cosmos.implementation.changefeed.common; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.RxDocumentServiceRequest; -import static com.azure.cosmos.BridgeInternal.setProperty; - class ChangeFeedStartFromLegacyContinuationImpl extends ChangeFeedStartFromInternal { public ChangeFeedStartFromLegacyContinuationImpl() { super(); @@ -17,10 +16,10 @@ public void populatePropertyBag() { super.populatePropertyBag(); synchronized (this) { - setProperty( - this, + this.set( Constants.Properties.CHANGE_FEED_START_FROM_TYPE, - ChangeFeedStartFromTypes.LEGACY_CHECKPOINT); + ChangeFeedStartFromTypes.LEGACY_CHECKPOINT, + CosmosItemSerializer.DEFAULT_SERIALIZER); } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/common/ChangeFeedStartFromNowImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/common/ChangeFeedStartFromNowImpl.java index f90cf9c2f4da..4612f601f63b 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/common/ChangeFeedStartFromNowImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/common/ChangeFeedStartFromNowImpl.java @@ -2,11 +2,11 @@ // Licensed under the MIT License. package com.azure.cosmos.implementation.changefeed.common; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.HttpConstants; import com.azure.cosmos.implementation.RxDocumentServiceRequest; -import static com.azure.cosmos.BridgeInternal.setProperty; import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; class ChangeFeedStartFromNowImpl extends ChangeFeedStartFromInternal { @@ -20,10 +20,10 @@ public void populatePropertyBag() { super.populatePropertyBag(); synchronized(this) { - setProperty( - this, + this.set( Constants.Properties.CHANGE_FEED_START_FROM_TYPE, - ChangeFeedStartFromTypes.NOW); + ChangeFeedStartFromTypes.NOW, + CosmosItemSerializer.DEFAULT_SERIALIZER); } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/common/ChangeFeedStartFromPointInTimeImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/common/ChangeFeedStartFromPointInTimeImpl.java index b67a6c3648ed..0a38fd42ca76 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/common/ChangeFeedStartFromPointInTimeImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/common/ChangeFeedStartFromPointInTimeImpl.java @@ -2,6 +2,7 @@ // Licensed under the MIT License. package com.azure.cosmos.implementation.changefeed.common; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.HttpConstants; import com.azure.cosmos.implementation.RxDocumentServiceRequest; @@ -9,7 +10,6 @@ import java.time.Instant; -import static com.azure.cosmos.BridgeInternal.setProperty; import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; class ChangeFeedStartFromPointInTimeImpl extends ChangeFeedStartFromInternal { @@ -50,15 +50,15 @@ public void populatePropertyBag() { super.populatePropertyBag(); synchronized(this) { - setProperty( - this, + this.set( com.azure.cosmos.implementation.Constants.Properties.CHANGE_FEED_START_FROM_TYPE, - ChangeFeedStartFromTypes.POINT_IN_TIME); + ChangeFeedStartFromTypes.POINT_IN_TIME, + CosmosItemSerializer.DEFAULT_SERIALIZER); - setProperty( - this, + this.set( Constants.Properties.CHANGE_FEED_START_FROM_POINT_IN_TIME_MS, - this.pointInTime.toEpochMilli()); + this.pointInTime.toEpochMilli(), + CosmosItemSerializer.DEFAULT_SERIALIZER); } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/common/ChangeFeedStateV1.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/common/ChangeFeedStateV1.java index 958783ab5dd3..562f76b8c6c8 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/common/ChangeFeedStateV1.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/common/ChangeFeedStateV1.java @@ -2,6 +2,7 @@ // Licensed under the MIT License. package com.azure.cosmos.implementation.changefeed.common; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.HttpConstants; import com.azure.cosmos.implementation.RxDocumentServiceRequest; @@ -12,7 +13,6 @@ import java.util.Objects; -import static com.azure.cosmos.BridgeInternal.setProperty; import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; public class ChangeFeedStateV1 extends ChangeFeedState { @@ -138,32 +138,32 @@ private void populateStartFrom( public void populatePropertyBag() { super.populatePropertyBag(); - setProperty( - this, + this.set( Constants.Properties.CHANGE_FEED_STATE_VERSION, - ChangeFeedStateVersions.V1); + ChangeFeedStateVersions.V1, + CosmosItemSerializer.DEFAULT_SERIALIZER); - setProperty( - this, + this.set( Constants.Properties.CHANGE_FEED_STATE_RESOURCE_ID, - this.containerRid); + this.containerRid, + CosmosItemSerializer.DEFAULT_SERIALIZER); - setProperty( - this, + this.set( Constants.Properties.CHANGE_FEED_STATE_MODE, - this.mode); + this.mode, + CosmosItemSerializer.DEFAULT_SERIALIZER); - setProperty( - this, + this.set( Constants.Properties.CHANGE_FEED_STATE_START_FROM, - this.startFromSettings); + this.startFromSettings, + CosmosItemSerializer.DEFAULT_SERIALIZER); if (this.continuation != null) { this.continuation.populatePropertyBag(); - setProperty( - this, + this.set( Constants.Properties.CHANGE_FEED_STATE_CONTINUATION, - this.continuation); + this.continuation, + CosmosItemSerializer.DEFAULT_SERIALIZER); this.feedRange.removeProperties(this); } else { this.feedRange.setProperties(this, true); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/epkversion/LeaseStoreImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/epkversion/LeaseStoreImpl.java index a9155cd7cf4e..581636dce72a 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/epkversion/LeaseStoreImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/epkversion/LeaseStoreImpl.java @@ -5,6 +5,7 @@ import com.azure.cosmos.BridgeInternal; import com.azure.cosmos.CosmosAsyncContainer; import com.azure.cosmos.CosmosException; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.Exceptions; import com.azure.cosmos.implementation.InternalObjectNode; @@ -100,7 +101,10 @@ public Mono acquireInitializationLock(Duration lockExpirationTime) { String lockId = this.getStoreLockName(); InternalObjectNode containerDocument = new InternalObjectNode(); containerDocument.setId(lockId); - BridgeInternal.setProperty(containerDocument, Constants.Properties.TTL, Long.valueOf(lockExpirationTime.getSeconds()).intValue()); + containerDocument.set( + Constants.Properties.TTL, + Long.valueOf(lockExpirationTime.getSeconds()).intValue(), + CosmosItemSerializer.DEFAULT_SERIALIZER); return this.client.createItem( this.leaseCollectionLink, diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/epkversion/LeaseStoreManagerImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/epkversion/LeaseStoreManagerImpl.java index 13c561e009ab..d52412bccf9c 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/epkversion/LeaseStoreManagerImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/epkversion/LeaseStoreManagerImpl.java @@ -196,8 +196,7 @@ public Mono createLeaseIfNotExist(FeedRangeEpkImpl feedRange, String cont return documentServiceLease .withId(document.getId()) .withETag(document.getETag()) - .withTs(ModelBridgeInternal.getStringFromJsonSerializable(document, - Constants.Properties.LAST_MODIFIED)); + .withTs(document.getString(Constants.Properties.LAST_MODIFIED)); }); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/epkversion/ServiceItemLeaseV1.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/epkversion/ServiceItemLeaseV1.java index fcd7851d52d2..468cfafaab84 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/epkversion/ServiceItemLeaseV1.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/epkversion/ServiceItemLeaseV1.java @@ -262,13 +262,12 @@ public static ServiceItemLeaseV1 fromDocument(InternalObjectNode document) { ServiceItemLeaseV1 lease = new ServiceItemLeaseV1() .withId(document.getId()) .withETag(document.getETag()) - .withTs(ModelBridgeInternal.getStringFromJsonSerializable(document, Constants.Properties.LAST_MODIFIED)) - .withOwner(ModelBridgeInternal.getStringFromJsonSerializable(document,PROPERTY_NAME_OWNER)) - .withLeaseToken(ModelBridgeInternal.getStringFromJsonSerializable(document,PROPERTY_NAME_LEASE_TOKEN)) - .withContinuationToken(ModelBridgeInternal.getStringFromJsonSerializable(document,PROPERTY_NAME_CONTINUATION_TOKEN)); + .withTs(document.getString(Constants.Properties.LAST_MODIFIED)) + .withOwner(document.getString(PROPERTY_NAME_OWNER)) + .withLeaseToken(document.getString(PROPERTY_NAME_LEASE_TOKEN)) + .withContinuationToken(document.getString(PROPERTY_NAME_CONTINUATION_TOKEN)); - Integer versionId = ModelBridgeInternal.getIntFromJsonSerializable(document, - PROPERTY_NAME_VERSION); + Integer versionId = document.getInt(PROPERTY_NAME_VERSION); if (versionId != null) { lease.withVersion(LeaseVersion.fromVersionId(versionId)); @@ -284,7 +283,7 @@ public static ServiceItemLeaseV1 fromDocument(InternalObjectNode document) { } } - String leaseTimestamp = ModelBridgeInternal.getStringFromJsonSerializable(document,PROPERTY_NAME_TIMESTAMP); + String leaseTimestamp = document.getString(PROPERTY_NAME_TIMESTAMP); if (leaseTimestamp != null) { return lease.withTimestamp(ZonedDateTime.parse(leaseTimestamp).toInstant()); } else { diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/pkversion/LeaseStoreImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/pkversion/LeaseStoreImpl.java index 9a2b93045785..fa9291a37da1 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/pkversion/LeaseStoreImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/pkversion/LeaseStoreImpl.java @@ -4,6 +4,7 @@ import com.azure.cosmos.BridgeInternal; import com.azure.cosmos.CosmosException; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.InternalObjectNode; import com.azure.cosmos.implementation.changefeed.common.ChangeFeedHelper; import com.azure.cosmos.implementation.changefeed.epkversion.ServiceItemLeaseV1; @@ -98,7 +99,10 @@ public Mono acquireInitializationLock(Duration lockExpirationTime) { String lockId = this.getStoreLockName(); InternalObjectNode containerDocument = new InternalObjectNode(); containerDocument.setId(lockId); - BridgeInternal.setProperty(containerDocument, Constants.Properties.TTL, Long.valueOf(lockExpirationTime.getSeconds()).intValue()); + containerDocument.set( + Constants.Properties.TTL, + Long.valueOf(lockExpirationTime.getSeconds()).intValue(), + CosmosItemSerializer.DEFAULT_SERIALIZER); return this.client.createItem( this.leaseCollectionLink, diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/pkversion/LeaseStoreManagerImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/pkversion/LeaseStoreManagerImpl.java index 06a77f883409..8854e82aa9ae 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/pkversion/LeaseStoreManagerImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/pkversion/LeaseStoreManagerImpl.java @@ -191,7 +191,7 @@ public Mono createLeaseIfNotExist(String leaseToken, String continuationT return documentServiceLease .withId(document.getId()) .withETag(document.getETag()) - .withTs(ModelBridgeInternal.getStringFromJsonSerializable(document, Constants.Properties.LAST_MODIFIED)); + .withTs(document.getString(Constants.Properties.LAST_MODIFIED)); }); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/pkversion/ServiceItemLease.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/pkversion/ServiceItemLease.java index 3daa73961a5d..2a693bcf2855 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/pkversion/ServiceItemLease.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/changefeed/pkversion/ServiceItemLease.java @@ -234,12 +234,12 @@ public static ServiceItemLease fromDocument(InternalObjectNode document) { ServiceItemLease lease = new ServiceItemLease() .withId(document.getId()) .withETag(document.getETag()) - .withTs(ModelBridgeInternal.getStringFromJsonSerializable(document, Constants.Properties.LAST_MODIFIED)) - .withOwner(ModelBridgeInternal.getStringFromJsonSerializable(document,PROPERTY_NAME_OWNER)) - .withLeaseToken(ModelBridgeInternal.getStringFromJsonSerializable(document,PROPERTY_NAME_LEASE_TOKEN)) - .withContinuationToken(ModelBridgeInternal.getStringFromJsonSerializable(document,PROPERTY_NAME_CONTINUATION_TOKEN)); + .withTs(document.getString(Constants.Properties.LAST_MODIFIED)) + .withOwner(document.getString(PROPERTY_NAME_OWNER)) + .withLeaseToken(document.getString(PROPERTY_NAME_LEASE_TOKEN)) + .withContinuationToken(document.getString(PROPERTY_NAME_CONTINUATION_TOKEN)); - String leaseTimestamp = ModelBridgeInternal.getStringFromJsonSerializable(document,PROPERTY_NAME_TIMESTAMP); + String leaseTimestamp = document.getString(PROPERTY_NAME_TIMESTAMP); if (leaseTimestamp != null) { return lease.withTimestamp(ZonedDateTime.parse(leaseTimestamp).toInstant()); } else { diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetry.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetry.java index 321a2e93ca28..855081b4c204 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetry.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/clienttelemetry/ClientTelemetry.java @@ -2,12 +2,11 @@ // Licensed under the MIT License. package com.azure.cosmos.implementation.clienttelemetry; -import com.azure.cosmos.BridgeInternal; import com.azure.cosmos.ConnectionMode; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.AuthorizationTokenType; import com.azure.cosmos.implementation.Configs; import com.azure.cosmos.implementation.Constants; -import com.azure.cosmos.implementation.CosmosDaemonThreadFactory; import com.azure.cosmos.implementation.CosmosSchedulers; import com.azure.cosmos.implementation.DiagnosticsClientContext; import com.azure.cosmos.implementation.HttpConstants; @@ -36,8 +35,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import reactor.core.publisher.Mono; -import reactor.core.scheduler.Scheduler; -import reactor.core.scheduler.Schedulers; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -51,7 +48,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; @@ -276,7 +272,7 @@ private Mono sendClientTelemetry() { URI targetEndpoint = new URI(endpoint); ByteBuffer byteBuffer = InternalObjectNode.serializeJsonToByteBuffer(this.clientTelemetryInfo, - ClientTelemetry.OBJECT_MAPPER, + CosmosItemSerializer.DEFAULT_SERIALIZER, null); byte[] tempBuffer = RxDocumentServiceRequest.toByteArray(byteBuffer); Map headers = new HashMap<>(); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/Address.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/Address.java index f092a25c142b..d17c49564a97 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/Address.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/Address.java @@ -4,6 +4,7 @@ package com.azure.cosmos.implementation.directconnectivity; import com.azure.cosmos.BridgeInternal; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.JsonSerializable; import com.azure.cosmos.implementation.Resource; import com.azure.cosmos.implementation.Constants; @@ -45,7 +46,7 @@ public boolean isPrimary() { } void setIsPrimary(boolean isPrimary) { - BridgeInternal.setProperty(this, Constants.Properties.IS_PRIMARY, isPrimary); + this.set(Constants.Properties.IS_PRIMARY, isPrimary, CosmosItemSerializer.DEFAULT_SERIALIZER); } public String getProtocolScheme() { @@ -53,7 +54,8 @@ public String getProtocolScheme() { } void setProtocol(String protocol) { - BridgeInternal.setProperty(this, Constants.Properties.PROTOCOL, protocol); + + this.set(Constants.Properties.PROTOCOL, protocol, CosmosItemSerializer.DEFAULT_SERIALIZER); } public String getLogicalUri() { @@ -61,7 +63,7 @@ public String getLogicalUri() { } void setLogicalUri(String logicalUri) { - BridgeInternal.setProperty(this, Constants.Properties.LOGICAL_URI, logicalUri); + this.set(Constants.Properties.LOGICAL_URI, logicalUri, CosmosItemSerializer.DEFAULT_SERIALIZER); } public String getPhyicalUri() { @@ -69,7 +71,7 @@ public String getPhyicalUri() { } void setPhysicalUri(String phyicalUri) { - BridgeInternal.setProperty(this, Constants.Properties.PHYISCAL_URI, phyicalUri); + this.set(Constants.Properties.PHYISCAL_URI, phyicalUri, CosmosItemSerializer.DEFAULT_SERIALIZER); } public String getPartitionIndex() { @@ -77,7 +79,7 @@ public String getPartitionIndex() { } void setPartitionIndex(String partitionIndex) { - BridgeInternal.setProperty(this, Constants.Properties.PARTITION_INDEX, partitionIndex); + this.set(Constants.Properties.PARTITION_INDEX, partitionIndex, CosmosItemSerializer.DEFAULT_SERIALIZER); } public String getParitionKeyRangeId() { @@ -85,7 +87,7 @@ public String getParitionKeyRangeId() { } public void setPartitionKeyRangeId(String partitionKeyRangeId) { - BridgeInternal.setProperty(this, Constants.Properties.PARTITION_KEY_RANGE_ID, partitionKeyRangeId); + this.set(Constants.Properties.PARTITION_KEY_RANGE_ID, partitionKeyRangeId, CosmosItemSerializer.DEFAULT_SERIALIZER); } @Override diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeCompositeContinuationImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeCompositeContinuationImpl.java index 6eaed0d689cf..7632118d4d17 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeCompositeContinuationImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeCompositeContinuationImpl.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation.feedranges; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.GoneException; import com.azure.cosmos.implementation.HttpConstants; @@ -30,7 +31,6 @@ import java.util.Objects; import java.util.Queue; -import static com.azure.cosmos.BridgeInternal.setProperty; import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; /** @@ -99,25 +99,25 @@ public FeedRangeCompositeContinuationImpl( public void populatePropertyBag() { super.populatePropertyBag(); - setProperty( - this, + this.set( Constants.Properties.FEED_RANGE_COMPOSITE_CONTINUATION_VERSION, - FeedRangeContinuationVersions.V1); + FeedRangeContinuationVersions.V1, + CosmosItemSerializer.DEFAULT_SERIALIZER); - setProperty( - this, + this.set( Constants.Properties.FEED_RANGE_COMPOSITE_CONTINUATION_RESOURCE_ID, - this.getContainerRid()); + this.getContainerRid(), + CosmosItemSerializer.DEFAULT_SERIALIZER); if (this.compositeContinuationTokens.size() > 0) { for (CompositeContinuationToken token : this.compositeContinuationTokens) { ModelBridgeInternal.populatePropertyBag(token); } - setProperty( - this, + this.set( Constants.Properties.FEED_RANGE_COMPOSITE_CONTINUATION_CONTINUATION, - this.compositeContinuationTokens); + this.compositeContinuationTokens, + CosmosItemSerializer.DEFAULT_SERIALIZER); } if (this.feedRange != null) { diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java index 8265cd89d38f..05d0611e1ac6 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java @@ -4,6 +4,7 @@ package com.azure.cosmos.implementation.feedranges; import com.azure.cosmos.BridgeInternal; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.DocumentCollection; import com.azure.cosmos.implementation.GoneException; @@ -29,7 +30,6 @@ import java.util.Objects; import java.util.stream.Collectors; -import static com.azure.cosmos.BridgeInternal.setProperty; import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; public final class FeedRangeEpkImpl extends FeedRangeInternal { @@ -258,7 +258,7 @@ public void setProperties(JsonSerializable serializable, boolean populatePropert if (this.range != null) { ModelBridgeInternal.populatePropertyBag(this.range); - setProperty(serializable, Constants.Properties.RANGE, this.range); + serializable.set(Constants.Properties.RANGE, this.range, CosmosItemSerializer.DEFAULT_SERIALIZER); } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java index 32c4654d5d2a..e2eba8fd77fa 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java @@ -4,6 +4,7 @@ package com.azure.cosmos.implementation.feedranges; import com.azure.cosmos.BridgeInternal; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.DocumentCollection; import com.azure.cosmos.implementation.HttpConstants; @@ -22,7 +23,6 @@ import java.util.List; import java.util.Objects; -import static com.azure.cosmos.BridgeInternal.setProperty; import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; public final class FeedRangePartitionKeyImpl extends FeedRangeInternal { @@ -192,8 +192,10 @@ public void setProperties(JsonSerializable serializable, boolean populatePropert } if (this.partitionKey != null) { - setProperty(serializable, Constants.Properties.FEED_RANGE_PARTITION_KEY, - this.partitionKey); + serializable.set( + Constants.Properties.FEED_RANGE_PARTITION_KEY, + this.partitionKey, + CosmosItemSerializer.DEFAULT_SERIALIZER); } } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java index 72faa22054f1..281adbb9e6d4 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java @@ -4,6 +4,7 @@ package com.azure.cosmos.implementation.feedranges; import com.azure.cosmos.BridgeInternal; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.DocumentCollection; import com.azure.cosmos.implementation.IRoutingMapProvider; @@ -21,7 +22,6 @@ import java.util.List; import java.util.Objects; -import static com.azure.cosmos.BridgeInternal.setProperty; import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; public final class FeedRangePartitionKeyRangeImpl extends FeedRangeInternal { @@ -174,10 +174,10 @@ public void setProperties(JsonSerializable serializable, boolean populatePropert } if (this.partitionKeyRangeId != null) { - setProperty( - serializable, + serializable.set( Constants.Properties.FEED_RANGE_PARTITION_KEY_RANGE_ID, - this.partitionKeyRangeId); + this.partitionKeyRangeId, + CosmosItemSerializer.DEFAULT_SERIALIZER); } } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/patch/PatchUtil.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/patch/PatchUtil.java index 20471c44b701..566cdc702def 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/patch/PatchUtil.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/patch/PatchUtil.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation.patch; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.JsonSerializable; import com.azure.cosmos.implementation.RequestOptions; import com.azure.cosmos.implementation.Utils; @@ -40,16 +41,31 @@ private static JsonSerializable cosmosPatchToJsonSerializable(CosmosPatchOperati for (PatchOperation patchOperation : patchOperationList) { JsonSerializable operationJsonSerializable = new JsonSerializable(); - operationJsonSerializable.set(PatchConstants.PropertyNames_OperationType, patchOperation.getOperationType().getOperationValue()); + operationJsonSerializable.set( + PatchConstants.PropertyNames_OperationType, + patchOperation.getOperationType().getOperationValue(), + CosmosItemSerializer.DEFAULT_SERIALIZER); if (patchOperation instanceof PatchOperationCore) { if (patchOperation.getOperationType() == PatchOperationType.MOVE) { - operationJsonSerializable.set(PatchConstants.PropertyNames_Path, ((PatchOperationCore)patchOperation).getPath()); - operationJsonSerializable.set(PatchConstants.PropertyNames_From, ((PatchOperationCore)patchOperation).getFrom()); + operationJsonSerializable.set( + PatchConstants.PropertyNames_Path, + ((PatchOperationCore)patchOperation).getPath(), + CosmosItemSerializer.DEFAULT_SERIALIZER); + operationJsonSerializable.set( + PatchConstants.PropertyNames_From, + ((PatchOperationCore)patchOperation).getFrom(), + CosmosItemSerializer.DEFAULT_SERIALIZER); } else { - operationJsonSerializable.set(PatchConstants.PropertyNames_Path, ((PatchOperationCore)patchOperation).getPath()); - operationJsonSerializable.set(PatchConstants.PropertyNames_Value, ((PatchOperationCore)patchOperation).getResource()); + operationJsonSerializable.set( + PatchConstants.PropertyNames_Path, + ((PatchOperationCore)patchOperation).getPath(), + CosmosItemSerializer.DEFAULT_SERIALIZER); + operationJsonSerializable.set( + PatchConstants.PropertyNames_Value, + ((PatchOperationCore)patchOperation).getResource(), + CosmosItemSerializer.DEFAULT_SERIALIZER); } } else { throw new IllegalArgumentException("Invalid patch operation type"); @@ -58,13 +74,19 @@ private static JsonSerializable cosmosPatchToJsonSerializable(CosmosPatchOperati operations.add(operationJsonSerializable.getPropertyBag()); } - jsonSerializable.set(PatchConstants.OPERATIONS, operations); + jsonSerializable.set( + PatchConstants.OPERATIONS, + operations, + CosmosItemSerializer.DEFAULT_SERIALIZER); if(requestOptions != null) { String filterPredicate = requestOptions.getFilterPredicate(); if(filterPredicate != null) { if (!filterPredicate.isEmpty()) { - jsonSerializable.set(PatchConstants.CONDITION, filterPredicate); + jsonSerializable.set( + PatchConstants.CONDITION, + filterPredicate, + CosmosItemSerializer.DEFAULT_SERIALIZER); } } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/CompositeContinuationToken.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/CompositeContinuationToken.java index e893d6b74505..c9bb528f715c 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/CompositeContinuationToken.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/CompositeContinuationToken.java @@ -3,8 +3,8 @@ package com.azure.cosmos.implementation.query; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.routing.Range; -import com.azure.cosmos.BridgeInternal; import com.azure.cosmos.implementation.JsonSerializable; import com.azure.cosmos.implementation.Utils.ValueHolder; import com.fasterxml.jackson.databind.JsonNode; @@ -12,8 +12,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static com.azure.cosmos.BridgeInternal.setProperty; - /** * While this class is public, but it is not part of our published public APIs. * This is meant to be internally used only by our sdk. @@ -95,7 +93,7 @@ public Range getRange() { // but converting it to the cleaner format if (rangeNode.isTextual()) { Range parsedRange = new Range<>(rangeNode.textValue()); - setProperty(this, RangePropertyName, parsedRange); + this.set(RangePropertyName, parsedRange, CosmosItemSerializer.DEFAULT_SERIALIZER); return parsedRange; } @@ -110,7 +108,7 @@ public Range getRange() { * the token to set */ public void setToken(String token) { - BridgeInternal.setProperty(this, TokenPropertyName, token); + this.set(TokenPropertyName, token, CosmosItemSerializer.DEFAULT_SERIALIZER); } /** @@ -118,7 +116,7 @@ public void setToken(String token) { * the range to set */ public void setRange(Range range) { - BridgeInternal.setProperty(this, RangePropertyName, range); + this.set(RangePropertyName, range, CosmosItemSerializer.DEFAULT_SERIALIZER); } @Override diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/DCountDocumentQueryExecutionContext.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/DCountDocumentQueryExecutionContext.java index cce4826b3ec2..97d0193f4f35 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/DCountDocumentQueryExecutionContext.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/DCountDocumentQueryExecutionContext.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation.query; import com.azure.cosmos.BridgeInternal; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.ClientSideRequestStatistics; import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.DistinctClientSideRequestStatisticsCollection; @@ -85,13 +86,13 @@ public Flux> drainAsync(int maxPageSize) { Document result = new Document(); if (Strings.isNullOrEmpty(info.getDCountAlias())) { if (info.hasSelectValue()) { - result.set(Constants.Properties.VALUE, count); + result.set(Constants.Properties.VALUE, count, CosmosItemSerializer.DEFAULT_SERIALIZER); } else { // Setting $1 as the key to be consistent with service results - result.set("$1", count); + result.set("$1", count, CosmosItemSerializer.DEFAULT_SERIALIZER); } } else { - result.set(info.getDCountAlias(), count); + result.set(info.getDCountAlias(), count, CosmosItemSerializer.DEFAULT_SERIALIZER); } headers.put(HttpConstants.HttpHeaders.REQUEST_CHARGE, Double.toString(requestCharge)); FeedResponse frp = diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/DefaultDocumentQueryExecutionContext.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/DefaultDocumentQueryExecutionContext.java index 5767c5c1ecd5..9072e25214c7 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/DefaultDocumentQueryExecutionContext.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/DefaultDocumentQueryExecutionContext.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation.query; import com.azure.cosmos.BridgeInternal; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.BackoffRetryUtility; import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.DiagnosticsClientContext; @@ -62,7 +63,7 @@ public class DefaultDocumentQueryExecutionContext extends DocumentQueryExecut private final SchedulingStopwatch fetchSchedulingMetrics; private final FetchExecutionRangeAccumulator fetchExecutionRangeAccumulator; private static final String DEFAULT_PARTITION_RANGE = "00-FF"; - private final Function factoryMethod; + private final CosmosItemSerializer itemSerializer; public DefaultDocumentQueryExecutionContext(DiagnosticsClientContext diagnosticsClientContext, IDocumentQueryClient client, ResourceType resourceTypeEnum, Class resourceType, SqlQuerySpec query, CosmosQueryRequestOptions cosmosQueryRequestOptions, String resourceLink, @@ -80,10 +81,10 @@ public DefaultDocumentQueryExecutionContext(DiagnosticsClientContext diagnostics this.fetchSchedulingMetrics = new SchedulingStopwatch(); this.fetchSchedulingMetrics.ready(); this.fetchExecutionRangeAccumulator = new FetchExecutionRangeAccumulator(DEFAULT_PARTITION_RANGE); - this.factoryMethod = DocumentQueryExecutionContextBase.getEffectiveFactoryMethod( - cosmosQueryRequestOptions, - false, - resourceType); + CosmosItemSerializer candidateSerializer = client.getEffectiveItemSerializer(this.cosmosQueryRequestOptions); + this.itemSerializer = candidateSerializer != CosmosItemSerializer.DEFAULT_SERIALIZER + ? candidateSerializer + : ValueUnwrapCosmosItemSerializer.create(false); } protected PartitionKeyInternal getPartitionKeyInternal() { @@ -196,7 +197,7 @@ private Mono> executeInternalFuncCore( return BackoffRetryUtility.executeRetry(() -> { this.retries.incrementAndGet(); return executeRequestAsync( - this.factoryMethod, + this.itemSerializer, req); }, finalRetryPolicyInstance) .map(tFeedResponse -> { diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/DistinctContinuationToken.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/DistinctContinuationToken.java index 2c37c110ec49..b0bf4487441a 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/DistinctContinuationToken.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/DistinctContinuationToken.java @@ -2,7 +2,7 @@ // Licensed under the MIT License. package com.azure.cosmos.implementation.query; -import com.azure.cosmos.BridgeInternal; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.Utils; import com.azure.cosmos.implementation.routing.UInt128; import com.azure.cosmos.implementation.JsonSerializable; @@ -61,7 +61,7 @@ String getSourceToken() { * @param sourceToken Value to set for property 'sourceToken'. */ public void setSourceToken(String sourceToken) { - BridgeInternal.setProperty(this, SOURCE_TOKEN_PROPERTY_NAME, sourceToken); + this.set(SOURCE_TOKEN_PROPERTY_NAME, sourceToken, CosmosItemSerializer.DEFAULT_SERIALIZER); } UInt128 getLastHash() { @@ -79,9 +79,9 @@ UInt128 getLastHash() { */ public void setLastHash(UInt128 lastHash) { if (lastHash != null) { - BridgeInternal.setProperty(this, LAST_HASH_PROPERTY_NAME, lastHash.toByteBuffer().array()); + this.set(LAST_HASH_PROPERTY_NAME, lastHash.toByteBuffer().array(), CosmosItemSerializer.DEFAULT_SERIALIZER); } else { - this.set(LAST_HASH_PROPERTY_NAME, null); + this.set(LAST_HASH_PROPERTY_NAME, null, CosmosItemSerializer.DEFAULT_SERIALIZER); } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/DistinctDocumentQueryExecutionContext.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/DistinctDocumentQueryExecutionContext.java index a88b9c573eae..df5deed55928 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/DistinctDocumentQueryExecutionContext.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/DistinctDocumentQueryExecutionContext.java @@ -98,7 +98,7 @@ public Flux> drainAsync(int maxPageSize) { new DistinctContinuationToken(this.lastHash.get(), sourceContinuationToken); headers.put(HttpConstants.HttpHeaders.CONTINUATION, - ModelBridgeInternal.toJsonFromJsonSerializable(distinctContinuationToken)); + distinctContinuationToken.toJson()); } return BridgeInternal.createFeedResponseWithQueryMetrics(distinctResults, diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/DocumentProducer.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/DocumentProducer.java index a5729909a16f..12b4d6518622 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/DocumentProducer.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/DocumentProducer.java @@ -8,6 +8,7 @@ import com.azure.cosmos.implementation.Exceptions; import com.azure.cosmos.implementation.HttpConstants; import com.azure.cosmos.implementation.ImplementationBridgeHelpers; +import com.azure.cosmos.implementation.JsonSerializable; import com.azure.cosmos.implementation.ObservableHelper; import com.azure.cosmos.implementation.OperationType; import com.azure.cosmos.implementation.PartitionKeyRange; @@ -267,7 +268,7 @@ private Flux feedRangeGoneProof(Flux private static final ImplementationBridgeHelpers.CosmosQueryRequestOptionsHelper.CosmosQueryRequestOptionsAccessor qryOptAccessor = ImplementationBridgeHelpers.CosmosQueryRequestOptionsHelper.getCosmosQueryRequestOptionsAccessor(); + private static final ImplementationBridgeHelpers.FeedResponseHelper.FeedResponseAccessor feedResponseAccessor = + ImplementationBridgeHelpers.FeedResponseHelper.getFeedResponseAccessor(); + protected final DiagnosticsClientContext diagnosticsClientContext; protected ResourceType resourceTypeEnum; protected String resourceLink; @@ -142,32 +142,32 @@ protected RxDocumentServiceRequest createDocumentServiceRequestWithFeedRange(Map } public Mono> executeRequestAsync( - Function factoryMethod, + CosmosItemSerializer itemSerializer, RxDocumentServiceRequest request) { - return (this.shouldExecuteQueryRequest ? this.executeQueryRequestAsync(factoryMethod, request) - : this.executeReadFeedRequestAsync(factoryMethod, request)); + return (this.shouldExecuteQueryRequest ? this.executeQueryRequestAsync(itemSerializer, request) + : this.executeReadFeedRequestAsync(itemSerializer, request)); } public Mono> executeQueryRequestAsync( - Function factoryMethod, + CosmosItemSerializer itemSerializer, RxDocumentServiceRequest request) { - return this.getFeedResponse(factoryMethod, this.executeQueryRequestInternalAsync(request)); + return this.getFeedResponse(itemSerializer, this.executeQueryRequestInternalAsync(request)); } public Mono> executeReadFeedRequestAsync( - Function factoryMethod, + CosmosItemSerializer itemSerializer, RxDocumentServiceRequest request) { - return this.getFeedResponse(factoryMethod, this.client.readFeedAsync(request)); + return this.getFeedResponse(itemSerializer, this.client.readFeedAsync(request)); } protected Mono> getFeedResponse( - Function factoryMethod, + CosmosItemSerializer itemSerializer, Mono response) { - return response.map(resp -> BridgeInternal.toFeedResponsePage(resp, factoryMethod, resourceType)); + return response.map(resp -> feedResponseAccessor.createFeedResponse(resp, itemSerializer, resourceType)); } public CosmosQueryRequestOptions getFeedOptions(String continuationToken, Integer maxPageSize) { @@ -353,44 +353,4 @@ private RxDocumentServiceRequest createReadFeedDocumentServiceRequest(Map Function getEffectiveFactoryMethod( - CosmosQueryRequestOptions cosmosQueryRequestOptions, - boolean hasSelectValue, - Class classOfT) { - - Function factoryMethodFromRequestOptions = cosmosQueryRequestOptions == null ? - null: qryOptAccessor.getImpl(cosmosQueryRequestOptions).getItemFactoryMethod(classOfT); - - return getEffectiveFactoryMethod(factoryMethodFromRequestOptions, hasSelectValue, classOfT); - } - - public static Function getEffectiveFactoryMethod( - CosmosChangeFeedRequestOptions cosmosChangeFeedRequestOptions, - Class classOfT) { - - Function factoryMethodFromRequestOptions = cosmosChangeFeedRequestOptions == null ? - null: - ImplementationBridgeHelpers - .CosmosChangeFeedRequestOptionsHelper - .getCosmosChangeFeedRequestOptionsAccessor() - .getItemFactoryMethod(cosmosChangeFeedRequestOptions, classOfT); - - return getEffectiveFactoryMethod(factoryMethodFromRequestOptions, false, classOfT); - } - - private static Function getEffectiveFactoryMethod( - Function factoryMethodFromRequestOptions, - boolean hasSelectValue, - Class classOfT) { - - return (node) -> { - if (factoryMethodFromRequestOptions != null) { - return factoryMethodFromRequestOptions.apply(node); - } - - return JsonSerializable.toObjectFromObjectNode( - node, hasSelectValue, classOfT); - }; - } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/GroupByDocumentQueryExecutionContext.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/GroupByDocumentQueryExecutionContext.java index 9b43be67197b..bad3bff57e21 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/GroupByDocumentQueryExecutionContext.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/GroupByDocumentQueryExecutionContext.java @@ -148,7 +148,7 @@ private FeedResponse createFeedResponseFromGroupingTable( private void aggregateGroupings(List superList) { for (Document d : superList) { RewrittenGroupByProjection rewrittenGroupByProjection = - new RewrittenGroupByProjection(ModelBridgeInternal.getPropertyBagFromJsonSerializable(d)); + new RewrittenGroupByProjection(d.getPropertyBag()); this.groupingTable.addPayLoad(rewrittenGroupByProjection); } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/IDocumentQueryClient.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/IDocumentQueryClient.java index 42583fb2d5be..77f5d7b3c09a 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/IDocumentQueryClient.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/IDocumentQueryClient.java @@ -2,6 +2,7 @@ // Licensed under the MIT License. package com.azure.cosmos.implementation.query; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.DocumentClientRetryPolicy; import com.azure.cosmos.implementation.OperationType; import com.azure.cosmos.implementation.ResourceType; @@ -11,6 +12,7 @@ import com.azure.cosmos.implementation.IRetryPolicyFactory; import com.azure.cosmos.implementation.RxDocumentServiceRequest; import com.azure.cosmos.implementation.RxDocumentServiceResponse; +import com.azure.cosmos.models.CosmosQueryRequestOptions; import reactor.core.publisher.Mono; import java.util.function.BiFunction; @@ -62,6 +64,8 @@ Mono executeFeedOperationWithAvailabilityStrategy( final RxDocumentServiceRequest req, final BiFunction, RxDocumentServiceRequest, Mono> feedOperation); + CosmosItemSerializer getEffectiveItemSerializer(CosmosQueryRequestOptions queryRequestOptions); + /// /// A client query compatibility mode when making query request. /// Can be used to force a specific query request format. diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/LimitContinuationToken.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/LimitContinuationToken.java index 1cf35a7f63d3..ea0076e1c80c 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/LimitContinuationToken.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/LimitContinuationToken.java @@ -4,6 +4,7 @@ package com.azure.cosmos.implementation.query; import com.azure.cosmos.BridgeInternal; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.JsonSerializable; import com.azure.cosmos.implementation.Utils.ValueHolder; import org.slf4j.Logger; @@ -61,11 +62,11 @@ public String getSourceToken() { } private void setLimitCount(int limitCount) { - BridgeInternal.setProperty(this, LIMIT_PROPERTY_NAME, limitCount); + this.set(LIMIT_PROPERTY_NAME, limitCount, CosmosItemSerializer.DEFAULT_SERIALIZER); } private void setSourceToken(String sourceToken) { - BridgeInternal.setProperty(this, SOURCE_TOKEN_PROPERTY_NAME, sourceToken); + this.set(SOURCE_TOKEN_PROPERTY_NAME, sourceToken, CosmosItemSerializer.DEFAULT_SERIALIZER); } @Override diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/OffsetContinuationToken.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/OffsetContinuationToken.java index 5b0ba84a85ba..184fcb02d614 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/OffsetContinuationToken.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/OffsetContinuationToken.java @@ -3,7 +3,7 @@ package com.azure.cosmos.implementation.query; -import com.azure.cosmos.BridgeInternal; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.JsonSerializable; import com.azure.cosmos.implementation.Utils; import com.azure.cosmos.implementation.apachecommons.lang.StringUtils; @@ -57,7 +57,7 @@ public String getSourceToken() { } private void setSourceToken(String sourceToken) { - BridgeInternal.setProperty(this, TOKEN_PROPERTY_NAME, sourceToken); + this.set(TOKEN_PROPERTY_NAME, sourceToken, CosmosItemSerializer.DEFAULT_SERIALIZER); } public int getOffset() { @@ -65,7 +65,7 @@ public int getOffset() { } private void setOffset(int offset) { - BridgeInternal.setProperty(this, OFFSET_PROPERTY_NAME, offset); + this.set(OFFSET_PROPERTY_NAME, offset, CosmosItemSerializer.DEFAULT_SERIALIZER); } @Override diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/OrderByContinuationToken.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/OrderByContinuationToken.java index d4405d480af2..a920ef40faad 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/OrderByContinuationToken.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/OrderByContinuationToken.java @@ -4,6 +4,7 @@ package com.azure.cosmos.implementation.query; import com.azure.cosmos.BridgeInternal; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.JsonSerializable; import com.azure.cosmos.implementation.Utils.ValueHolder; import com.azure.cosmos.implementation.routing.Range; @@ -121,19 +122,19 @@ public boolean getInclusive() { } private void setCompositeContinuationToken(CompositeContinuationToken compositeContinuationToken) { - BridgeInternal.setProperty(this, CompositeContinuationTokenPropertyName, compositeContinuationToken.toJson()); + this.set(CompositeContinuationTokenPropertyName, compositeContinuationToken.toJson(), CosmosItemSerializer.DEFAULT_SERIALIZER); } private void setOrderByItems(QueryItem[] orderByItems) { - BridgeInternal.setProperty(this, OrderByItemsPropetryName, Arrays.asList(orderByItems)); + this.set(OrderByItemsPropetryName, Arrays.asList(orderByItems), CosmosItemSerializer.DEFAULT_SERIALIZER); } private void setRid(String rid) { - BridgeInternal.setProperty(this, RidPropertyName, rid); + this.set(RidPropertyName, rid, CosmosItemSerializer.DEFAULT_SERIALIZER); } private void setInclusive(boolean inclusive) { - BridgeInternal.setProperty(this, InclusivePropertyName, inclusive); + this.set(InclusivePropertyName, inclusive, CosmosItemSerializer.DEFAULT_SERIALIZER); } @Override diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/OrderByUtils.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/OrderByUtils.java index ad7572401d38..18c0c29f5d6d 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/OrderByUtils.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/OrderByUtils.java @@ -116,7 +116,7 @@ public Flux> apply(Flux.Do // Once we do that we need to seek to the correct _rid within the term, // since there might be many documents with the same order by value we left off on. List queryItems = new ArrayList(); - ArrayNode arrayNode = (ArrayNode)ModelBridgeInternal.getObjectFromJsonSerializable(tOrderByRowResult, "orderByItems"); + ArrayNode arrayNode = (ArrayNode)tOrderByRowResult.get("orderByItems"); for (JsonNode jsonNode : arrayNode) { QueryItem queryItem = new QueryItem(jsonNode.toString()); queryItems.add(queryItem); @@ -170,7 +170,7 @@ public Flux> apply(Flux.Do Flux x = Flux.fromIterable(results); return x.map(r -> new OrderByRowResult( - ModelBridgeInternal.toJsonFromJsonSerializable(r), + r.toJson(), documentProducerFeedResponse.sourceFeedRange, documentProducerFeedResponse.pageResult.getContinuationToken())); }, 1); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/ParallelDocumentQueryExecutionContextBase.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/ParallelDocumentQueryExecutionContextBase.java index ecaacb5ec272..8bcacdf45078 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/ParallelDocumentQueryExecutionContextBase.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/ParallelDocumentQueryExecutionContextBase.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation.query; import com.azure.cosmos.BridgeInternal; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.DiagnosticsClientContext; import com.azure.cosmos.implementation.DocumentClientRetryPolicy; import com.azure.cosmos.implementation.DocumentCollection; @@ -17,7 +18,6 @@ import com.azure.cosmos.models.FeedResponse; import com.azure.cosmos.models.PartitionKey; import com.azure.cosmos.models.SqlQuerySpec; -import com.fasterxml.jackson.databind.JsonNode; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -40,7 +40,7 @@ public abstract class ParallelDocumentQueryExecutionContextBase protected final List> documentProducers; protected final SqlQuerySpec querySpec; protected int top = -1; - private final Function factoryMethod; + private final CosmosItemSerializer itemSerializer; protected ParallelDocumentQueryExecutionContextBase(DiagnosticsClientContext diagnosticsClientContext, IDocumentQueryClient client, @@ -49,8 +49,10 @@ protected ParallelDocumentQueryExecutionContextBase(DiagnosticsClientContext dia UUID correlatedActivityId, boolean shouldUnwrapSelectValue, AtomicBoolean isQueryCancelledOnTimeout) { super(diagnosticsClientContext, client, resourceTypeEnum, resourceType, query, cosmosQueryRequestOptions, resourceLink, correlatedActivityId, isQueryCancelledOnTimeout); - this.factoryMethod = DocumentQueryExecutionContextBase.getEffectiveFactoryMethod( - this.cosmosQueryRequestOptions, shouldUnwrapSelectValue, resourceType); + CosmosItemSerializer candidateSerializer = client.getEffectiveItemSerializer(this.cosmosQueryRequestOptions); + this.itemSerializer = candidateSerializer != CosmosItemSerializer.DEFAULT_SERIALIZER + ? candidateSerializer + : ValueUnwrapCosmosItemSerializer.create(shouldUnwrapSelectValue); documentProducers = new ArrayList<>(); if (!Strings.isNullOrEmpty(rewrittenQuery)) { this.querySpec = new SqlQuerySpec(rewrittenQuery, super.query.getParameters()); @@ -89,7 +91,7 @@ protected void initialize( }; Function>> executeFunc = (request) -> this.executeRequestAsync( - this.factoryMethod, + this.itemSerializer, request); final FeedRangeEpkImpl targetRange = entry.getKey(); final String continuationToken = entry.getValue(); @@ -159,7 +161,7 @@ protected void initializeReadMany( }; Function>> executeFunc = (request) -> this.executeRequestAsync( - this.factoryMethod, + this.itemSerializer, request); DocumentProducer dp = diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/PartitionedQueryExecutionInfo.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/PartitionedQueryExecutionInfo.java index 16e214a1333a..9db68384f08e 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/PartitionedQueryExecutionInfo.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/PartitionedQueryExecutionInfo.java @@ -3,9 +3,9 @@ package com.azure.cosmos.implementation.query; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.RequestTimeline; import com.azure.cosmos.implementation.routing.Range; -import com.azure.cosmos.BridgeInternal; import com.azure.cosmos.implementation.JsonSerializable; import com.azure.cosmos.implementation.Constants; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -28,9 +28,10 @@ public final class PartitionedQueryExecutionInfo extends JsonSerializable { this.queryInfo = queryInfo; this.queryRanges = queryRanges; - BridgeInternal.setProperty(this, - PartitionedQueryExecutionInfoInternal.PARTITIONED_QUERY_EXECUTION_INFO_VERSION_PROPERTY, - Constants.PartitionedQueryExecutionInfo.VERSION_1); + this.set( + PartitionedQueryExecutionInfoInternal.PARTITIONED_QUERY_EXECUTION_INFO_VERSION_PROPERTY, + Constants.PartitionedQueryExecutionInfo.VERSION_1, + CosmosItemSerializer.DEFAULT_SERIALIZER); } public PartitionedQueryExecutionInfo(ObjectNode content, RequestTimeline queryPlanRequestTimeline) { diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/PartitionedQueryExecutionInfoInternal.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/PartitionedQueryExecutionInfoInternal.java index 046fba4c6b32..13d2aefd40ec 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/PartitionedQueryExecutionInfoInternal.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/PartitionedQueryExecutionInfoInternal.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation.query; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.routing.PartitionKeyInternal; import com.azure.cosmos.implementation.routing.Range; import com.azure.cosmos.BridgeInternal; @@ -27,7 +28,10 @@ public final class PartitionedQueryExecutionInfoInternal extends JsonSerializabl private List> queryRanges; public PartitionedQueryExecutionInfoInternal() { - BridgeInternal.setProperty(this, PARTITIONED_QUERY_EXECUTION_INFO_VERSION_PROPERTY, Constants.PartitionedQueryExecutionInfo.VERSION_1); + this.set( + PARTITIONED_QUERY_EXECUTION_INFO_VERSION_PROPERTY, + Constants.PartitionedQueryExecutionInfo.VERSION_1, + CosmosItemSerializer.DEFAULT_SERIALIZER); } public PartitionedQueryExecutionInfoInternal(ObjectNode objectNode) { diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/PipelinedDocumentQueryExecutionContext.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/PipelinedDocumentQueryExecutionContext.java index ca27fd264ac7..5479b6286967 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/PipelinedDocumentQueryExecutionContext.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/PipelinedDocumentQueryExecutionContext.java @@ -2,18 +2,18 @@ // Licensed under the MIT License. package com.azure.cosmos.implementation.query; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.DiagnosticsClientContext; import com.azure.cosmos.implementation.DocumentCollection; import com.azure.cosmos.implementation.ImplementationBridgeHelpers; import com.azure.cosmos.implementation.Document; +import com.azure.cosmos.implementation.ObjectNodeMap; import com.azure.cosmos.models.CosmosQueryRequestOptions; import com.azure.cosmos.models.FeedResponse; import com.azure.cosmos.models.ModelBridgeInternal; -import com.fasterxml.jackson.databind.JsonNode; import reactor.core.publisher.Flux; import java.util.function.BiFunction; -import java.util.function.Function; /** * While this class is public, but it is not part of our published public APIs. @@ -31,9 +31,10 @@ private PipelinedDocumentQueryExecutionContext( IDocumentQueryExecutionComponent pipelinedComponent, int actualPageSize, QueryInfo queryInfo, - Function factoryMethod) { + CosmosItemSerializer itemSerializer, + Class classOfT) { - super(actualPageSize, queryInfo, factoryMethod); + super(actualPageSize, queryInfo, itemSerializer, classOfT); this.component = pipelinedComponent; } @@ -53,7 +54,7 @@ private static BiFunction, Flux, Flux { CosmosQueryRequestOptions parallelCosmosQueryRequestOptions = qryOptAccessor.clone(requestOptions); - qryOptAccessor.getImpl(parallelCosmosQueryRequestOptions).setItemFactoryMethod(null); + qryOptAccessor.getImpl(parallelCosmosQueryRequestOptions).setCustomSerializer(null); ModelBridgeInternal.setQueryRequestOptionsContinuationToken(parallelCosmosQueryRequestOptions, continuationToken); documentQueryParams.setCosmosQueryRequestOptions(parallelCosmosQueryRequestOptions); @@ -160,7 +161,8 @@ protected static Flux> createAsyncCore IDocumentQueryClient client, PipelinedDocumentQueryParams initParams, int pageSize, - Function factoryMethod, + CosmosItemSerializer itemSerializer, + Class classOfT, DocumentCollection collection) { // Use nested callback pattern to unwrap the continuation token and query params at each level. @@ -170,13 +172,12 @@ protected static Flux> createAsyncCore QueryInfo queryInfo = initParams.getQueryInfo(); CosmosQueryRequestOptions cosmosQueryRequestOptions = initParams.getCosmosQueryRequestOptions(); - return createPipelineComponentFunction .apply( ModelBridgeInternal.getRequestContinuationFromQueryRequestOptions(cosmosQueryRequestOptions), initParams.convertGenericType(Document.class)) .map(c -> new PipelinedDocumentQueryExecutionContext<>( - c, pageSize, queryInfo, factoryMethod)); + c, pageSize, queryInfo, itemSerializer, classOfT)); } @Override @@ -188,7 +189,7 @@ public Flux> executeAsync() { .FeedResponseHelper .getFeedResponseAccessor().convertGenericType( documentFeedResponse, - (document) -> this.factoryMethod.apply(document.getPropertyBag()) + (document) -> this.itemSerializer.deserialize(new ObjectNodeMap(document.getPropertyBag()), this.classOfT) ) ); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/PipelinedQueryExecutionContext.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/PipelinedQueryExecutionContext.java index 651b0e6cda1f..c7f67711fabd 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/PipelinedQueryExecutionContext.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/PipelinedQueryExecutionContext.java @@ -2,6 +2,7 @@ // Licensed under the MIT License. package com.azure.cosmos.implementation.query; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.DiagnosticsClientContext; import com.azure.cosmos.implementation.DocumentCollection; import com.azure.cosmos.implementation.ImplementationBridgeHelpers; @@ -11,14 +12,12 @@ import com.azure.cosmos.models.FeedResponse; import com.azure.cosmos.models.ModelBridgeInternal; import com.azure.cosmos.models.SqlQuerySpec; -import com.fasterxml.jackson.databind.JsonNode; import reactor.core.publisher.Flux; import java.util.Map; import java.util.UUID; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.BiFunction; -import java.util.function.Function; public final class PipelinedQueryExecutionContext extends PipelinedQueryExecutionContextBase { @@ -28,10 +27,11 @@ public final class PipelinedQueryExecutionContext extends PipelinedQueryExecu private final IDocumentQueryExecutionComponent component; private PipelinedQueryExecutionContext(IDocumentQueryExecutionComponent component, int actualPageSize, - QueryInfo queryInfo, - Function factoryMethod) { + QueryInfo queryInfo, + CosmosItemSerializer itemSerializer, + Class classOfT) { - super(actualPageSize, queryInfo, factoryMethod); + super(actualPageSize, queryInfo, itemSerializer, classOfT); this.component = component; } @@ -76,7 +76,8 @@ static Flux> createAsyncCore( IDocumentQueryClient client, PipelinedDocumentQueryParams initParams, int pageSize, - Function factoryMethod, + CosmosItemSerializer itemSerializer, + Class classOfT, DocumentCollection collection) { // Use nested callback pattern to unwrap the continuation token and query params at each level. @@ -94,7 +95,8 @@ static Flux> createAsyncCore( c, pageSize, queryInfo, - factoryMethod)); + itemSerializer, + classOfT)); } public static Flux> createReadManyAsync( @@ -113,15 +115,18 @@ public static Flux> createReadManyAsyn resourceTypeEnum, isQueryCancelledOnTimeout); - final Function factoryMethod = DocumentQueryExecutionContextBase.getEffectiveFactoryMethod( - cosmosQueryRequestOptions, false, klass); + CosmosItemSerializer candidateSerializer = queryClient.getEffectiveItemSerializer(cosmosQueryRequestOptions); + final CosmosItemSerializer itemSerializer = candidateSerializer != CosmosItemSerializer.DEFAULT_SERIALIZER + ? candidateSerializer + : ValueUnwrapCosmosItemSerializer.create(false); return documentQueryExecutionComponentFlux .map(c -> new PipelinedQueryExecutionContext<>( c, -1, null, - factoryMethod)); + itemSerializer, + klass)); } @Override diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/PipelinedQueryExecutionContextBase.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/PipelinedQueryExecutionContextBase.java index bb8b68d854fb..232f942b8590 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/PipelinedQueryExecutionContextBase.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/PipelinedQueryExecutionContextBase.java @@ -2,16 +2,15 @@ // Licensed under the MIT License. package com.azure.cosmos.implementation.query; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.DiagnosticsClientContext; import com.azure.cosmos.implementation.DocumentCollection; import com.azure.cosmos.implementation.Utils; import com.azure.cosmos.models.CosmosQueryRequestOptions; import com.azure.cosmos.models.ModelBridgeInternal; -import com.fasterxml.jackson.databind.JsonNode; import reactor.core.publisher.Flux; import java.util.function.BiFunction; -import java.util.function.Function; /** * While this class is public, but it is not part of our published public APIs. @@ -22,16 +21,19 @@ public abstract class PipelinedQueryExecutionContextBase protected final int actualPageSize; private final QueryInfo queryInfo; - protected final Function factoryMethod; + protected final CosmosItemSerializer itemSerializer; + protected final Class classOfT; protected PipelinedQueryExecutionContextBase( int actualPageSize, QueryInfo queryInfo, - Function factoryMethod) { + CosmosItemSerializer itemSerializer, + Class classOfT) { this.actualPageSize = actualPageSize; this.queryInfo = queryInfo; - this.factoryMethod = factoryMethod; + this.itemSerializer = itemSerializer; + this.classOfT = classOfT; } public static Flux> createAsync( @@ -52,8 +54,10 @@ public static Flux> createAsync( int pageSize = Math.min(actualPageSize, Utils.getValueOrDefault(queryInfo.getTop(), (actualPageSize))); - final Function factoryMethod = DefaultDocumentQueryExecutionContext - .getEffectiveFactoryMethod(cosmosQueryRequestOptions, queryInfo.hasSelectValue(), classOfT); + CosmosItemSerializer candidateSerializer = client.getEffectiveItemSerializer(cosmosQueryRequestOptions); + final CosmosItemSerializer itemSerializer = candidateSerializer != CosmosItemSerializer.DEFAULT_SERIALIZER + ? candidateSerializer + : ValueUnwrapCosmosItemSerializer.create(queryInfo.hasSelectValue()); if (queryInfo.hasOrderBy() || queryInfo.hasAggregates() @@ -66,7 +70,8 @@ public static Flux> createAsync( client, initParams, pageSize, - factoryMethod, + itemSerializer, + classOfT, collection); } @@ -75,7 +80,8 @@ public static Flux> createAsync( client, initParams, pageSize, - factoryMethod, + itemSerializer, + classOfT, collection); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/SingleGroupAggregator.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/SingleGroupAggregator.java index 670939bc3d37..3a851ca12ea2 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/SingleGroupAggregator.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/SingleGroupAggregator.java @@ -2,6 +2,7 @@ // Licensed under the MIT License. package com.azure.cosmos.implementation.query; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.Document; import com.azure.cosmos.implementation.Resource; @@ -109,7 +110,7 @@ public Document getResult() { } // This is for value queries.Need to append value property for scalar values (non key value pairs) // to make them a key value pair document as our impl is based on Document. - document.set(Constants.Properties.VALUE, result); + document.set(Constants.Properties.VALUE, result, CosmosItemSerializer.DEFAULT_SERIALIZER); } return document; } @@ -177,7 +178,7 @@ public Document getResult() { for (String alias : this.orderedAliases) { AggregateValue aggregateValue = this.aliasToValue.get(alias); if (aggregateValue.getResult() != null) { - aggregateDocument.set(alias, aggregateValue.getResult()); + aggregateDocument.set(alias, aggregateValue.getResult(), CosmosItemSerializer.DEFAULT_SERIALIZER); } } return aggregateDocument; diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/TopContinuationToken.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/TopContinuationToken.java index e01f6461abff..cdd8022d3a33 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/TopContinuationToken.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/TopContinuationToken.java @@ -4,6 +4,7 @@ package com.azure.cosmos.implementation.query; import com.azure.cosmos.BridgeInternal; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.JsonSerializable; import com.azure.cosmos.implementation.Utils.ValueHolder; import org.slf4j.Logger; @@ -61,11 +62,11 @@ public String getSourceToken() { } private void setTopCount(int topCount) { - BridgeInternal.setProperty(this, TOP_PROPERTY_NAME, topCount); + this.set(TOP_PROPERTY_NAME, topCount, CosmosItemSerializer.DEFAULT_SERIALIZER); } private void setSourceToken(String sourceToken) { - BridgeInternal.setProperty(this, SOURCE_TOKEN_PROPERTY_NAME, sourceToken); + this.set(SOURCE_TOKEN_PROPERTY_NAME, sourceToken, CosmosItemSerializer.DEFAULT_SERIALIZER); } @Override diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/Transformer.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/Transformer.java index 43b48124bf52..78e564169332 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/Transformer.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/Transformer.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation.query; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.CosmosPagedFluxOptions; import com.azure.cosmos.models.FeedResponse; import com.fasterxml.jackson.databind.JsonNode; @@ -11,5 +12,7 @@ import java.util.function.Function; public interface Transformer { - Function>> transform(Function>> func); + Function>> transform( + Function>> func, + CosmosItemSerializer effectiveSerializer); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/ValueUnwrapCosmosItemSerializer.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/ValueUnwrapCosmosItemSerializer.java new file mode 100644 index 000000000000..ea75e49d6987 --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/ValueUnwrapCosmosItemSerializer.java @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.cosmos.implementation.query; + +import com.azure.cosmos.CosmosItemSerializer; +import com.azure.cosmos.implementation.JsonSerializable; +import com.azure.cosmos.implementation.ObjectNodeMap; +import com.azure.cosmos.implementation.Utils; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import java.util.Map; + +public final class ValueUnwrapCosmosItemSerializer extends CosmosItemSerializer { + private static ValueUnwrapCosmosItemSerializer EnableUnwrapSingletonInstance = new ValueUnwrapCosmosItemSerializer(true); + private static ValueUnwrapCosmosItemSerializer DisableUnwrapSingletonInstance = new ValueUnwrapCosmosItemSerializer(false); + + public static CosmosItemSerializer create(boolean shouldUnwrapValue) { + if (shouldUnwrapValue) { + return EnableUnwrapSingletonInstance; + } + + return DisableUnwrapSingletonInstance; + } + + + private final boolean shouldUnwrapValue; + private ValueUnwrapCosmosItemSerializer(boolean shouldUnwrapValue) { + this.shouldUnwrapValue = shouldUnwrapValue; + } + + @Override + public Map serialize(T item) { + throw new IllegalStateException("Method 'serialize' is not implemented for this serializer"); + } + + @Override + public T deserialize(Map jsonNodeMap, Class classType) { + + if (jsonNodeMap == null) { + return null; + } + + ObjectNode jsonNode; + if (jsonNodeMap instanceof ObjectNodeMap) { + jsonNode = ((ObjectNodeMap)jsonNodeMap).getObjectNode(); + } else { + jsonNode = Utils.getSimpleObjectMapper().convertValue(jsonNodeMap, ObjectNode.class); + } + + return JsonSerializable.toObjectFromObjectNode(jsonNode, this.shouldUnwrapValue, classType); + } +} \ No newline at end of file diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/orderbyquery/OrderByRowResult.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/orderbyquery/OrderByRowResult.java index 9bd422eef9fd..1c0d8c0e2a6b 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/orderbyquery/OrderByRowResult.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/orderbyquery/OrderByRowResult.java @@ -3,13 +3,11 @@ package com.azure.cosmos.implementation.query.orderbyquery; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.Document; -import com.azure.cosmos.implementation.PartitionKeyRange; import com.azure.cosmos.implementation.feedranges.FeedRangeEpkImpl; import com.azure.cosmos.implementation.query.QueryItem; -import com.azure.cosmos.models.FeedRange; -import com.azure.cosmos.models.ModelBridgeInternal; import com.fasterxml.jackson.databind.node.ObjectNode; import java.util.List; @@ -45,7 +43,7 @@ public Document getPayload() { final Object object = super.get("payload"); if (!ObjectNode.class.isAssignableFrom(object.getClass())) { Document document = new Document(); - ModelBridgeInternal.setProperty(document, Constants.Properties.VALUE, object); + document.set(Constants.Properties.VALUE, object, CosmosItemSerializer.DEFAULT_SERIALIZER); payload = document; } else { this.payload = super.getObject("payload", Document.class); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/routing/Range.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/routing/Range.java index 3a7c4776aab4..edeb116f8ed6 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/routing/Range.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/routing/Range.java @@ -3,7 +3,7 @@ package com.azure.cosmos.implementation.routing; -import com.azure.cosmos.BridgeInternal; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.JsonSerializable; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -84,7 +84,7 @@ public T getMin() { public void setMin(T min) { this.minValue = min; - BridgeInternal.setProperty(this, Range.MIN_PROPERTY, min); + this.set(Range.MIN_PROPERTY, min, CosmosItemSerializer.DEFAULT_SERIALIZER); } @SuppressWarnings("unchecked") @@ -98,7 +98,7 @@ public T getMax() { public void setMax(T max) { this.maxValue = max; - BridgeInternal.setProperty(this, Range.MAX_PROPERTY, max); + this.set(Range.MAX_PROPERTY, max, CosmosItemSerializer.DEFAULT_SERIALIZER); } @JsonProperty("isMinInclusive") @@ -109,9 +109,9 @@ public boolean isMinInclusive() { public void setMinInclusive(boolean isMinInclusive) { if (isMinInclusive) { - BridgeInternal.remove(this, Range.IS_MIN_INCLUSIVE_PROPERTY); + this.remove(Range.IS_MIN_INCLUSIVE_PROPERTY); } else { - BridgeInternal.setProperty(this, Range.IS_MIN_INCLUSIVE_PROPERTY, false); + this.set(Range.IS_MIN_INCLUSIVE_PROPERTY, false, CosmosItemSerializer.DEFAULT_SERIALIZER); } } @@ -122,9 +122,9 @@ public boolean isMaxInclusive() { public void setMaxInclusive(boolean isMaxInclusive) { if (isMaxInclusive) { - BridgeInternal.setProperty(this, Range.IS_MAX_INCLUSIVE_PROPERTY, true); + this.set(Range.IS_MAX_INCLUSIVE_PROPERTY, true, CosmosItemSerializer.DEFAULT_SERIALIZER); } else { - BridgeInternal.remove(this, Range.IS_MAX_INCLUSIVE_PROPERTY); + this.remove(Range.IS_MAX_INCLUSIVE_PROPERTY); } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ChangeFeedPolicy.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ChangeFeedPolicy.java index 779aa07ca7b7..9ff875a4609c 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ChangeFeedPolicy.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ChangeFeedPolicy.java @@ -3,6 +3,7 @@ package com.azure.cosmos.models; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.JsonSerializable; import com.azure.cosmos.util.Beta; @@ -238,12 +239,14 @@ ChangeFeedPolicy setRetentionDurationForAllVersionsAndDeletesPolicyInMinutes(Int if (retentionDurationInMinutes == null || retentionDurationInMinutes <= 0) { this.jsonSerializable.set( Constants.Properties.LOG_RETENTION_DURATION, - 0); + 0, + CosmosItemSerializer.DEFAULT_SERIALIZER); } else { this.jsonSerializable.set( Constants.Properties.LOG_RETENTION_DURATION, - retentionDurationInMinutes); + retentionDurationInMinutes, + CosmosItemSerializer.DEFAULT_SERIALIZER); } return this; diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CompositePath.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CompositePath.java index f90b12091d5a..a278e0aa8f50 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CompositePath.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CompositePath.java @@ -3,6 +3,7 @@ package com.azure.cosmos.models; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.JsonSerializable; import com.azure.cosmos.implementation.apachecommons.lang.StringUtils; @@ -63,7 +64,7 @@ public String getPath() { */ public CompositePath setPath(String path) { this.jsonSerializable = new JsonSerializable(); - this.jsonSerializable.set(Constants.Properties.PATH, path); + this.jsonSerializable.set(Constants.Properties.PATH, path, CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } @@ -101,7 +102,7 @@ public CompositePathSortOrder getOrder() { * @return the CompositePath. */ public CompositePath setOrder(CompositePathSortOrder order) { - this.jsonSerializable.set(Constants.Properties.ORDER, order.toString()); + this.jsonSerializable.set(Constants.Properties.ORDER, order.toString(), CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ConflictResolutionPolicy.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ConflictResolutionPolicy.java index 06a074c1a39d..a514bea4f36d 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ConflictResolutionPolicy.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ConflictResolutionPolicy.java @@ -4,6 +4,7 @@ package com.azure.cosmos.models; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.JsonSerializable; import com.azure.cosmos.implementation.Paths; @@ -223,7 +224,7 @@ public ConflictResolutionMode getMode() { * @param mode One of the values of the {@link ConflictResolutionMode} enum. */ ConflictResolutionPolicy setMode(ConflictResolutionMode mode) { - this.jsonSerializable.set(Constants.Properties.MODE, mode.toString()); + this.jsonSerializable.set(Constants.Properties.MODE, mode.toString(), CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } @@ -258,7 +259,10 @@ public String getConflictResolutionPath() { * That path is a rooted path of the property in the item, such as "/name/first". */ ConflictResolutionPolicy setConflictResolutionPath(String value) { - this.jsonSerializable.set(Constants.Properties.CONFLICT_RESOLUTION_PATH, value); + this.jsonSerializable.set( + Constants.Properties.CONFLICT_RESOLUTION_PATH, + value, + CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } @@ -282,7 +286,10 @@ public String getConflictResolutionProcedure() { } ConflictResolutionPolicy setConflictResolutionProcedure(String value) { - this.jsonSerializable.set(Constants.Properties.CONFLICT_RESOLUTION_PROCEDURE, value); + this.jsonSerializable.set( + Constants.Properties.CONFLICT_RESOLUTION_PROCEDURE, + value, + CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosBatchOperationResult.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosBatchOperationResult.java index 60300fef0323..267006c604fd 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosBatchOperationResult.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosBatchOperationResult.java @@ -3,8 +3,11 @@ package com.azure.cosmos.models; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.ImplementationBridgeHelpers; import com.azure.cosmos.implementation.JsonSerializable; +import com.azure.cosmos.implementation.Utils; +import com.azure.cosmos.implementation.batch.CosmosItemOperationBase; import com.fasterxml.jackson.databind.node.ObjectNode; import java.time.Duration; @@ -22,6 +25,7 @@ public final class CosmosBatchOperationResult { private final Duration retryAfter; private final int subStatusCode; private final CosmosItemOperation cosmosItemOperation; + private CosmosItemSerializer effectiveItemSerializer; private ObjectNode resourceObject; /** @@ -44,6 +48,9 @@ public final class CosmosBatchOperationResult { this.retryAfter = retryAfter; this.subStatusCode = subStatusCode; this.cosmosItemOperation = cosmosItemOperation; + this.effectiveItemSerializer = cosmosItemOperation instanceof CosmosItemOperationBase + ? ((CosmosItemOperationBase)cosmosItemOperation).getEffectiveItemSerializerForResult() + : CosmosItemSerializer.DEFAULT_SERIALIZER; } /** @@ -82,7 +89,11 @@ public T getItem(final Class type) { T item = null; if (this.getResourceObject() != null) { - item = new JsonSerializable(this.getResourceObject()).toObject(type); + if (effectiveItemSerializer == CosmosItemSerializer.DEFAULT_SERIALIZER) { + item = new JsonSerializable(this.getResourceObject()).toObject(type); + } else { + item = Utils.parse(this.getResourceObject(), type, effectiveItemSerializer); + } } return item; @@ -128,6 +139,14 @@ ObjectNode getResourceObject() { return resourceObject; } + CosmosItemSerializer getEffectiveItemSerializer() { + return this.effectiveItemSerializer; + } + + void setEffectiveItemSerializer(CosmosItemSerializer effectiveItemSerializer) { + this.effectiveItemSerializer = effectiveItemSerializer; + } + /** * Gets the original operation for this result. * @@ -153,6 +172,13 @@ public void setResourceObject(CosmosBatchOperationResult cosmosBatchOperationRes ObjectNode objectNode) { cosmosBatchOperationResult.resourceObject = objectNode; } + + @Override + public void setEffectiveItemSerializer(CosmosBatchOperationResult cosmosBatchOperationResult, + CosmosItemSerializer effectiveItemSerializer) { + + cosmosBatchOperationResult.setEffectiveItemSerializer(effectiveItemSerializer); + } }); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosBatchRequestOptions.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosBatchRequestOptions.java index 192865dc8ee1..e0a2d90788f4 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosBatchRequestOptions.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosBatchRequestOptions.java @@ -5,10 +5,12 @@ import com.azure.cosmos.ConsistencyLevel; import com.azure.cosmos.CosmosDiagnosticsThresholds; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.ImplementationBridgeHelpers; import com.azure.cosmos.implementation.RequestOptions; import com.azure.cosmos.implementation.apachecommons.collections.list.UnmodifiableList; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -23,6 +25,27 @@ public final class CosmosBatchRequestOptions { private CosmosDiagnosticsThresholds thresholds = new CosmosDiagnosticsThresholds(); private List excludeRegions; + private CosmosItemSerializer customSerializer; + + /** + * Creates an instance of the CosmosBatchRequestOptions class + */ + public CosmosBatchRequestOptions() { + } + + + CosmosBatchRequestOptions(CosmosBatchRequestOptions toBeCloned) { + this.consistencyLevel = toBeCloned.consistencyLevel; + this.sessionToken = toBeCloned.sessionToken; + this.customOptions = toBeCloned.customOptions; + this.thresholds = toBeCloned.thresholds; + this.customSerializer = toBeCloned.customSerializer; + + if (toBeCloned.excludeRegions != null) { + this.excludeRegions = new ArrayList<>(toBeCloned.excludeRegions); + } + } + /** * Gets the consistency level required for the request. * @@ -90,6 +113,8 @@ RequestOptions toRequestOptions() { requestOptions.setConsistencyLevel(getConsistencyLevel()); requestOptions.setSessionToken(sessionToken); requestOptions.setDiagnosticsThresholds(thresholds); + requestOptions.setEffectiveItemSerializer(this.customSerializer); + if(this.customOptions != null) { for(Map.Entry entry : this.customOptions.entrySet()) { requestOptions.setHeader(entry.getKey(), entry.getValue()); @@ -141,6 +166,27 @@ public List getExcludedRegions() { return UnmodifiableList.unmodifiableList(this.excludeRegions); } + /** + * Gets the custom item serializer defined for this instance of request options + * @return the custom item serializer + */ + public CosmosItemSerializer getCustomSerializer() { + return this.customSerializer; + } + + /** + * Allows specifying a custom item serializer to be used for this operation. If the serializer + * on the request options is null, the serializer on CosmosClientBuilder is used. If both serializers + * are null (the default), an internal Jackson ObjectMapper is ued for serialization/deserialization. + * @param itemSerializerOverride the custom item serializer for this operation + * @return the CosmosItemRequestOptions. + */ + public CosmosBatchRequestOptions setCustomSerializer(CosmosItemSerializer itemSerializerOverride) { + this.customSerializer = itemSerializerOverride; + + return this; + } + /** * Gets the custom batch request options * @@ -181,6 +227,11 @@ public Map getHeader(CosmosBatchRequestOptions cosmosItemRequest public List getExcludeRegions(CosmosBatchRequestOptions cosmosBatchRequestOptions) { return cosmosBatchRequestOptions.excludeRegions; } + + @Override + public CosmosBatchRequestOptions clone(CosmosBatchRequestOptions toBeCloned) { + return new CosmosBatchRequestOptions(toBeCloned); + } } ); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosBulkExecutionOptions.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosBulkExecutionOptions.java index e32bf5a7e5e0..06c33219e27b 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosBulkExecutionOptions.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosBulkExecutionOptions.java @@ -3,6 +3,7 @@ package com.azure.cosmos.models; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.ImplementationBridgeHelpers; import com.azure.cosmos.implementation.apachecommons.collections.list.UnmodifiableList; import com.azure.cosmos.implementation.batch.BatchRequestResponseConstants; @@ -10,6 +11,7 @@ import com.azure.cosmos.implementation.spark.OperationContextAndListenerTuple; import java.time.Duration; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -38,8 +40,30 @@ public final class CosmosBulkExecutionOptions { private Map customOptions; private String throughputControlGroupName; private List excludeRegions; - private BulkExecutorDiagnosticsTracker diagnosticsTracker = null; + private CosmosItemSerializer customSerializer; + + + CosmosBulkExecutionOptions(CosmosBulkExecutionOptions toBeCloned) { + this.initialMicroBatchSize = toBeCloned.initialMicroBatchSize; + this.maxMicroBatchConcurrency = toBeCloned.maxMicroBatchConcurrency; + this.maxMicroBatchSize = toBeCloned.maxMicroBatchSize; + this.maxMicroBatchRetryRate = toBeCloned.maxMicroBatchRetryRate; + this.minMicroBatchRetryRate = toBeCloned.minMicroBatchRetryRate; + this.maxMicroBatchPayloadSizeInBytes = toBeCloned.maxMicroBatchPayloadSizeInBytes; + this.legacyBatchScopedContext = toBeCloned.legacyBatchScopedContext; + this.thresholds = toBeCloned.thresholds; + this.maxConcurrentCosmosPartitions = toBeCloned.maxConcurrentCosmosPartitions; + this.throughputControlGroupName = toBeCloned.throughputControlGroupName; + this.operationContextAndListenerTuple = toBeCloned.operationContextAndListenerTuple; + this.diagnosticsTracker = toBeCloned.diagnosticsTracker; + this.customSerializer = toBeCloned.customSerializer; + this.customOptions = toBeCloned.customOptions; + + if (toBeCloned.excludeRegions != null) { + this.excludeRegions = new ArrayList<>(toBeCloned.excludeRegions); + } + } /** * Constructor @@ -149,6 +173,27 @@ public CosmosBulkExecutionOptions setMaxMicroBatchSize(int maxMicroBatchSize) { return this; } + /** + * Gets the custom item serializer defined for this instance of request options + * @return the custom item serializer + */ + public CosmosItemSerializer getCustomSerializer() { + return this.customSerializer; + } + + /** + * Allows specifying a custom item serializer to be used for this operation. If the serializer + * on the request options is null, the serializer on CosmosClientBuilder is used. If both serializers + * are null (the default), an internal Jackson ObjectMapper is ued for serialization/deserialization. + * @param itemSerializerOverride the custom item serializer for this operation + * @return the CosmosItemRequestOptions. + */ + public CosmosBulkExecutionOptions setCustomSerializer(CosmosItemSerializer itemSerializerOverride) { + this.customSerializer = itemSerializerOverride; + + return this; + } + Integer getMaxConcurrentCosmosPartitions() { return this.maxConcurrentCosmosPartitions; } @@ -464,6 +509,11 @@ public void setDiagnosticsTracker(CosmosBulkExecutionOptions cosmosBulkExecution public BulkExecutorDiagnosticsTracker getDiagnosticsTracker(CosmosBulkExecutionOptions cosmosBulkExecutionOptions) { return cosmosBulkExecutionOptions.getDiagnosticsTracker(); } + + @Override + public CosmosBulkExecutionOptions clone(CosmosBulkExecutionOptions toBeCloned) { + return new CosmosBulkExecutionOptions(toBeCloned); + } }); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosBulkItemRequestOptions.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosBulkItemRequestOptions.java index 1b9f905b3553..7c2f108d896f 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosBulkItemRequestOptions.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosBulkItemRequestOptions.java @@ -11,7 +11,6 @@ * creating bulk request using {@link CosmosBulkOperations}. */ public final class CosmosBulkItemRequestOptions { - private String ifMatchETag; private String ifNoneMatchETag; private Boolean contentResponseOnWriteEnabled; @@ -65,14 +64,10 @@ public CosmosBulkItemRequestOptions setIfNoneMatchETag(final String ifNoneMatchE /** * Sets the boolean to only return the headers and status code in Cosmos DB response * in case of Create, Update and Delete operations in {@link CosmosItemOperation}. - * * If set to false, service doesn't return payload in the response. It reduces networking * and CPU load by not sending the payload back over the network and serializing it on the client. - * * This feature does not impact RU usage for read or write operations. - * * By-default, this is null. - * * NOTE: This flag is also present on {@link CosmosClientBuilder}, however if specified * here, it will override the value specified in {@link CosmosClientBuilder} for this request. * @@ -89,12 +84,9 @@ public CosmosBulkItemRequestOptions setContentResponseOnWriteEnabled(Boolean con /** * Gets the boolean to only return the headers and status code in Cosmos DB response * in case of Create, Update and Delete operations in {@link CosmosItemOperation}. - * * If set to false, service doesn't return payload in the response. It reduces networking * and CPU load by not sending the payload back over the network and serializing it on the client. - * * This feature does not impact RU usage for read or write operations. - * * By-default, this is null. * * @return a boolean indicating whether payload will be included in the response or not for this operation. @@ -108,6 +100,7 @@ RequestOptions toRequestOptions() { requestOptions.setIfMatchETag(this.ifMatchETag); requestOptions.setIfNoneMatchETag(this.ifNoneMatchETag); requestOptions.setContentResponseOnWriteEnabled(this.contentResponseOnWriteEnabled); + return requestOptions; } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosBulkItemResponse.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosBulkItemResponse.java index 944432fce4d5..73c6a5271bae 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosBulkItemResponse.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosBulkItemResponse.java @@ -5,8 +5,10 @@ import com.azure.cosmos.CosmosAsyncContainer; import com.azure.cosmos.CosmosDiagnostics; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.ImplementationBridgeHelpers; import com.azure.cosmos.implementation.JsonSerializable; +import com.azure.cosmos.implementation.Utils; import com.azure.cosmos.implementation.batch.BatchExecUtils; import com.fasterxml.jackson.databind.node.ObjectNode; import reactor.core.publisher.Flux; @@ -31,6 +33,7 @@ public final class CosmosBulkItemResponse { private final int subStatusCode; private final Map responseHeaders; private final CosmosDiagnostics cosmosDiagnostics; + private CosmosItemSerializer effectiveItemSerializer; /** * Initializes a new instance of the {@link CosmosBulkItemResponse} class. @@ -42,7 +45,8 @@ public final class CosmosBulkItemResponse { Duration retryAfter, int subStatusCode, Map responseHeaders, - CosmosDiagnostics cosmosDiagnostics) { + CosmosDiagnostics cosmosDiagnostics, + CosmosItemSerializer effectiveItemSerializer) { checkNotNull(responseHeaders, "expected non-null responseHeaders"); @@ -54,6 +58,7 @@ public final class CosmosBulkItemResponse { this.subStatusCode = subStatusCode; this.responseHeaders = responseHeaders; this.cosmosDiagnostics = cosmosDiagnostics; + this.effectiveItemSerializer = effectiveItemSerializer; } /** @@ -67,7 +72,6 @@ public String getActivityId() { /** * Gets the entity tag associated with the current item. - * * ETags are used for concurrency checking when updating resources. * * @return Entity tag associated with the current item. @@ -101,7 +105,11 @@ public T getItem(final Class type) { T item = null; if (this.getResourceObject() != null) { - item = new JsonSerializable(this.getResourceObject()).toObject(type); + if (effectiveItemSerializer == CosmosItemSerializer.DEFAULT_SERIALIZER) { + item = new JsonSerializable(this.getResourceObject()).toObject(type); + } else { + item = Utils.parse(this.getResourceObject(), type, effectiveItemSerializer); + } } return item; @@ -187,6 +195,10 @@ private ObjectNode getResourceObject() { return resourceObject; } + void setEffectiveItemSerializer(CosmosItemSerializer effectiveItemSerializer) { + this.effectiveItemSerializer = effectiveItemSerializer; + } + /////////////////////////////////////////////////////////////////////////////////////////// // the following helper/accessor only helps to access this class outside of this package.// /////////////////////////////////////////////////////////////////////////////////////////// @@ -204,6 +216,13 @@ public void setResourceObject(CosmosBulkItemResponse cosmosBulkItemResponse, ObjectNode objectNode) { cosmosBulkItemResponse.resourceObject = objectNode; } + + @Override + public void setEffectiveItemSerializer(CosmosBulkItemResponse cosmosBulkItemResponse, + CosmosItemSerializer effectiveItemSerializer) { + + cosmosBulkItemResponse.setEffectiveItemSerializer(effectiveItemSerializer); + } }); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosChangeFeedRequestOptions.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosChangeFeedRequestOptions.java index 61e34ed4d0fd..0834289bc147 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosChangeFeedRequestOptions.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosChangeFeedRequestOptions.java @@ -4,6 +4,7 @@ package com.azure.cosmos.models; import com.azure.cosmos.CosmosDiagnosticsThresholds; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.CosmosPagedFluxOptions; import com.azure.cosmos.implementation.HttpConstants; import com.azure.cosmos.implementation.ImplementationBridgeHelpers; @@ -20,14 +21,12 @@ import com.azure.cosmos.implementation.routing.Range; import com.azure.cosmos.implementation.spark.OperationContextAndListenerTuple; import com.azure.cosmos.util.Beta; -import com.fasterxml.jackson.databind.JsonNode; import java.time.Instant; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.Function; import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkArgument; import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; @@ -50,9 +49,27 @@ public final class CosmosChangeFeedRequestOptions { private String throughputControlGroupName; private Map customOptions; private OperationContextAndListenerTuple operationContextAndListenerTuple; - private Function itemFactoryMethod; private CosmosDiagnosticsThresholds thresholds; private List excludeRegions; + private CosmosItemSerializer customSerializer; + + CosmosChangeFeedRequestOptions(CosmosChangeFeedRequestOptions topBeCloned) { + this.continuationState = topBeCloned.continuationState; + this.feedRangeInternal = topBeCloned.feedRangeInternal; + this.properties = topBeCloned.properties; + this.maxItemCount = topBeCloned.maxItemCount; + this.maxPrefetchPageCount = topBeCloned.maxPrefetchPageCount; + this.mode = topBeCloned.mode; + this.startFromInternal = topBeCloned.startFromInternal; + this.isSplitHandlingDisabled = topBeCloned.isSplitHandlingDisabled; + this.quotaInfoEnabled = topBeCloned.quotaInfoEnabled; + this.throughputControlGroupName = topBeCloned.throughputControlGroupName; + this.customOptions = topBeCloned.customOptions; + this.operationContextAndListenerTuple = topBeCloned.operationContextAndListenerTuple; + this.thresholds = topBeCloned.thresholds; + this.excludeRegions = topBeCloned.excludeRegions; + this.customSerializer = topBeCloned.customSerializer; + } private CosmosChangeFeedRequestOptions( FeedRangeInternal feedRange, @@ -207,6 +224,27 @@ public CosmosDiagnosticsThresholds getDiagnosticsThresholds() { return this.thresholds; } + /** + * Gets the custom item serializer defined for this instance of request options + * @return the custom item serializer + */ + public CosmosItemSerializer getCustomSerializer() { + return this.customSerializer; + } + + /** + * Allows specifying a custom item serializer to be used for this operation. If the serializer + * on the request options is null, the serializer on CosmosClientBuilder is used. If both serializers + * are null (the default), an internal Jackson ObjectMapper is ued for serialization/deserialization. + * @param itemSerializerOverride the custom item serializer for this operation + * @return the CosmosChangeFeedRequestOptions. + */ + public CosmosChangeFeedRequestOptions setCustomSerializer(CosmosItemSerializer itemSerializerOverride) { + this.customSerializer = itemSerializerOverride; + + return this; + } + boolean isSplitHandlingDisabled() { return this.isSplitHandlingDisabled; } @@ -270,7 +308,6 @@ public static CosmosChangeFeedRequestOptions createForProcessingFromContinuation /*** * Creates a new {@link CosmosChangeFeedRequestOptions} instance to start processing * change feed items based on a previous continuation. - * * ONLY used by Kafka connector. * * @param continuation The continuation that was retrieved from a previously retrieved FeedResponse @@ -582,13 +619,6 @@ OperationContextAndListenerTuple getOperationContextAndListenerTuple() { return this.operationContextAndListenerTuple; } - Function getItemFactoryMethod() { return this.itemFactoryMethod; } - - CosmosChangeFeedRequestOptions setItemFactoryMethod(Function factoryMethod) { - this.itemFactoryMethod = factoryMethod; - return this; - } - private void addCustomOptionsForFullFidelityMode() { this.setHeader( HttpConstants.HttpHeaders.CHANGE_FEED_WIRE_FORMAT_VERSION, @@ -631,22 +661,6 @@ public Map getHeader(CosmosChangeFeedRequestOptions changeFeedRe return changeFeedRequestOptions.getOperationContextAndListenerTuple(); } - @Override - @SuppressWarnings("unchecked") - public Function getItemFactoryMethod( - CosmosChangeFeedRequestOptions options, Class classOfT) { - - return (Function)options.getItemFactoryMethod(); - } - - @Override - public CosmosChangeFeedRequestOptions setItemFactoryMethod( - CosmosChangeFeedRequestOptions options, - Function factoryMethod) { - - return options.setItemFactoryMethod(factoryMethod); - } - @Override public CosmosDiagnosticsThresholds getDiagnosticsThresholds(CosmosChangeFeedRequestOptions options) { return options.thresholds; @@ -665,6 +679,11 @@ public CosmosChangeFeedRequestOptions createForProcessingFromContinuation( return CosmosChangeFeedRequestOptions.createForProcessingFromContinuation(continuation, targetRange, continuationLsn); } + + @Override + public CosmosChangeFeedRequestOptions clone(CosmosChangeFeedRequestOptions toBeCloned) { + return new CosmosChangeFeedRequestOptions(toBeCloned); + } }); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosItemRequestOptions.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosItemRequestOptions.java index 2fc5df9b8235..fa069565a0c9 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosItemRequestOptions.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosItemRequestOptions.java @@ -6,6 +6,7 @@ import com.azure.cosmos.CosmosClientBuilder; import com.azure.cosmos.CosmosDiagnosticsThresholds; import com.azure.cosmos.CosmosEndToEndOperationLatencyPolicyConfig; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.ImplementationBridgeHelpers; import com.azure.cosmos.implementation.RequestOptions; import com.azure.cosmos.implementation.WriteRetryPolicy; @@ -43,6 +44,7 @@ public class CosmosItemRequestOptions { private boolean useTrackingIds; private CosmosEndToEndOperationLatencyPolicyConfig endToEndOperationLatencyPolicyConfig; private List excludeRegions; + private CosmosItemSerializer customSerializer; /** * copy constructor @@ -65,6 +67,7 @@ public class CosmosItemRequestOptions { useTrackingIds = options.useTrackingIds; endToEndOperationLatencyPolicyConfig = options.endToEndOperationLatencyPolicyConfig; excludeRegions = options.excludeRegions; + customSerializer = options.customSerializer; if (options.customOptions != null) { this.customOptions = new HashMap<>(options.customOptions); } @@ -303,7 +306,7 @@ CosmosEndToEndOperationLatencyPolicyConfig getCosmosEndToEndOperationLatencyPoli /** * Enables automatic retries for write operations even when the SDK can't * guarantee that they are idempotent. This is an override of the - * {@link CosmosClientBuilder#setNonIdempotentWriteRetryPolicy(boolean, boolean)} behavior for a specific request/operation. + * {@link CosmosClientBuilder#nonIdempotentWriteRetryPolicy(boolean, boolean)} behavior for a specific request/operation. *
* NOTE: the setting on the CosmosClientBuilder will determine the default behavior for Create, Replace, * Upsert and Delete operations. It can be overridden on per-request base in the request options. For patch @@ -422,7 +425,7 @@ CosmosItemRequestOptions setPartitionKey(PartitionKey partitionKey) { return this; } - RequestOptions toRequestOptions() { + RequestOptions toRequestOptions(CosmosItemSerializer effectiveItemSerializer) { RequestOptions requestOptions = new RequestOptions(); requestOptions.setIfMatchETag(getIfMatchETag()); requestOptions.setIfNoneMatchETag(getIfNoneMatchETag()); @@ -447,6 +450,7 @@ RequestOptions toRequestOptions() { requestOptions.setHeader(entry.getKey(), entry.getValue()); } } + requestOptions.setEffectiveItemSerializer(effectiveItemSerializer); return requestOptions; } @@ -534,6 +538,28 @@ public CosmosDiagnosticsThresholds getDiagnosticsThresholds() { return this.thresholds; } + /** + * Gets the custom item serializer defined for this instance of request options + * @return the custom item serializer + */ + public CosmosItemSerializer getCustomSerializer() { + return this.customSerializer; + } + + /** + * Allows specifying a custom item serializer to be used for this operation. If the serializer + * on the request options is null, the serializer on CosmosClientBuilder is used. If both serializers + * are null (the default), an internal Jackson ObjectMapper is ued for serialization/deserialization. + * @param itemSerializerOverride the custom item serializer for this operation + * @return the CosmosItemRequestOptions. + */ + public CosmosItemRequestOptions setCustomSerializer(CosmosItemSerializer itemSerializerOverride) { + this.customSerializer = itemSerializerOverride; + + return this; + } + + /** * Gets the custom item request options * @@ -558,6 +584,11 @@ static void initialize() { ImplementationBridgeHelpers.CosmosItemRequestOptionsHelper.setCosmosItemRequestOptionsAccessor( new ImplementationBridgeHelpers.CosmosItemRequestOptionsHelper.CosmosItemRequestOptionsAccessor() { + @Override + public RequestOptions toRequestOptions(CosmosItemRequestOptions itemRequestOptions, CosmosItemSerializer effectiveItemSerializer) { + return itemRequestOptions.toRequestOptions(effectiveItemSerializer); + } + @Override public void setOperationContext(CosmosItemRequestOptions itemRequestOptions, OperationContextAndListenerTuple operationContextAndListenerTuple) { @@ -648,6 +679,11 @@ public CosmosEndToEndOperationLatencyPolicyConfig getEndToEndOperationLatencyPol return options.getCosmosEndToEndOperationLatencyPolicyConfig(); } + + @Override + public CosmosPatchItemRequestOptions clonePatchItemRequestOptions(CosmosPatchItemRequestOptions options) { + return new CosmosPatchItemRequestOptions(options); + } } ); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosItemResponse.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosItemResponse.java index a7a549223955..3796e56442d5 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosItemResponse.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosItemResponse.java @@ -4,11 +4,11 @@ import com.azure.cosmos.BridgeInternal; import com.azure.cosmos.CosmosDiagnostics; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.Document; import com.azure.cosmos.implementation.ImplementationBridgeHelpers; import com.azure.cosmos.implementation.InternalObjectNode; -import com.azure.cosmos.implementation.ItemDeserializer; import com.azure.cosmos.implementation.ResourceResponse; import com.azure.cosmos.implementation.SerializationDiagnosticsContext; import com.azure.cosmos.implementation.Utils; @@ -32,7 +32,7 @@ */ public class CosmosItemResponse { private final Class itemClassType; - private final ItemDeserializer itemDeserializer; + private final CosmosItemSerializer itemSerializer; // Converting item to volatile to fix Double-checked locking - https://en.wikipedia.org/wiki/Double-checked_locking // http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html @@ -47,19 +47,19 @@ public class CosmosItemResponse { private final Supplier hasPayload; - CosmosItemResponse(ResourceResponse response, Class classType, ItemDeserializer itemDeserializer) { + CosmosItemResponse(ResourceResponse response, Class classType, CosmosItemSerializer itemSerializer) { this.itemClassType = classType; this.resourceResponse = response; - this.itemDeserializer = itemDeserializer; + this.itemSerializer = itemSerializer; this.item = null; - this.hasPayload = () -> response.hasPayload(); + this.hasPayload = response::hasPayload; this.itemBodyOverride = null; } - private CosmosItemResponse(ResourceResponse response, T item, JsonNode itemBodyOverride, Class classType, ItemDeserializer itemDeserializer) { + private CosmosItemResponse(ResourceResponse response, T item, JsonNode itemBodyOverride, Class classType, CosmosItemSerializer itemSerializer) { this.itemClassType = classType; this.resourceResponse = response; - this.itemDeserializer = itemDeserializer; + this.itemSerializer = itemSerializer; this.item = item; this.itemBodyOverride = itemBodyOverride; boolean hasPayloadStaticValue = item != null; @@ -141,7 +141,7 @@ public T getItem() { return item; } else { Instant serializationStartTime = Instant.now(); - item = Utils.parse(this.resourceResponse.getBody(), itemClassType, itemDeserializer); + item = Utils.parse((ObjectNode)this.resourceResponse.getBody(), itemClassType, itemSerializer); Instant serializationEndTime = Instant.now(); SerializationDiagnosticsContext.SerializationDiagnostics diagnostics = new SerializationDiagnosticsContext.SerializationDiagnostics( @@ -273,7 +273,6 @@ public Duration getDuration() { /** * Gets the ETag from the response headers. * This is only relevant when getting response from the server. - * * Null in case of delete operation. * * @return ETag @@ -298,7 +297,7 @@ CosmosItemResponse withRemappedStatusCode( } return new CosmosItemResponse<>( - mappedResourceResponse, payload, itemBodyOverride, this.itemClassType, this.itemDeserializer); + mappedResourceResponse, payload, itemBodyOverride, this.itemClassType, this.itemSerializer); } boolean hasTrackingId(String candidate) { @@ -330,12 +329,21 @@ static void initialize() { new ImplementationBridgeHelpers.CosmosItemResponseHelper.CosmosItemResponseBuilderAccessor() { public CosmosItemResponse createCosmosItemResponse(CosmosItemResponse response, Class classType, - ItemDeserializer itemDeserializer) { + CosmosItemSerializer serializer) { return new CosmosItemResponse<>( response.resourceResponse, - Utils.parse(response.getItemAsByteArray(), classType), + Utils.parse(response.getItemAsByteArray(), classType, serializer), response.itemBodyOverride, - classType, itemDeserializer); + classType, + serializer); + } + + @Override + public CosmosItemResponse createCosmosItemResponse(ResourceResponse response, Class classType, CosmosItemSerializer serializer) { + return new CosmosItemResponse<>( + response, + classType, + serializer); } @Override diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosPatchItemRequestOptions.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosPatchItemRequestOptions.java index 5bc66ed0712a..ca22f4928855 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosPatchItemRequestOptions.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosPatchItemRequestOptions.java @@ -3,6 +3,7 @@ package com.azure.cosmos.models; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.RequestOptions; /** @@ -46,8 +47,9 @@ public CosmosPatchItemRequestOptions setFilterPredicate(String filterPredicate) return this; } - RequestOptions toRequestOptions() { - RequestOptions requestOptions = super.toRequestOptions(); + @Override + RequestOptions toRequestOptions(CosmosItemSerializer effectiveItemSerializer) { + RequestOptions requestOptions = super.toRequestOptions(effectiveItemSerializer); requestOptions.setFilterPredicate(filterPredicate); return requestOptions; } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosQueryRequestOptions.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosQueryRequestOptions.java index b86911884aad..164683c19b7e 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosQueryRequestOptions.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosQueryRequestOptions.java @@ -7,6 +7,7 @@ import com.azure.cosmos.CosmosDiagnostics; import com.azure.cosmos.CosmosDiagnosticsThresholds; import com.azure.cosmos.CosmosEndToEndOperationLatencyPolicyConfig; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.CosmosQueryRequestOptionsBase; import com.azure.cosmos.implementation.CosmosQueryRequestOptionsImpl; import com.azure.cosmos.implementation.ImplementationBridgeHelpers; @@ -465,6 +466,27 @@ public CosmosQueryRequestOptions setQueryName(String queryName) { return this; } + /** + * Gets the custom item serializer defined for this instance of request options + * @return the custom item serializer + */ + public CosmosItemSerializer getCustomSerializer() { + return this.actualRequestOptions.getCustomSerializer(); + } + + /** + * Allows specifying a custom item serializer to be used for this operation. If the serializer + * on the request options is null, the serializer on CosmosClientBuilder is used. If both serializers + * are null (the default), an internal Jackson ObjectMapper is ued for serialization/deserialization. + * @param itemSerializerOverride the custom item serializer for this operation + * @return the CosmosItemRequestOptions. + */ + public CosmosQueryRequestOptions setCustomSerializer(CosmosItemSerializer itemSerializerOverride) { + this.actualRequestOptions.setCustomSerializer(itemSerializerOverride); + + return this; + } + CosmosQueryRequestOptionsBase getImpl() { return this.actualRequestOptions; } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosReadManyRequestOptions.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosReadManyRequestOptions.java index d03e30019950..f74bb0e54f44 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosReadManyRequestOptions.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosReadManyRequestOptions.java @@ -6,6 +6,7 @@ import com.azure.cosmos.ConsistencyLevel; import com.azure.cosmos.CosmosDiagnosticsThresholds; import com.azure.cosmos.CosmosEndToEndOperationLatencyPolicyConfig; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.CosmosQueryRequestOptionsBase; import com.azure.cosmos.implementation.CosmosReadManyRequestOptionsImpl; import com.azure.cosmos.implementation.ImplementationBridgeHelpers; @@ -289,6 +290,27 @@ public CosmosReadManyRequestOptions setIndexMetricsEnabled(boolean indexMetricsE return this; } + /** + * Gets the custom item serializer defined for this instance of request options + * @return the custom item serializer + */ + public CosmosItemSerializer getCustomSerializer() { + return this.actualRequestOptions.getCustomSerializer(); + } + + /** + * Allows specifying a custom item serializer to be used for this operation. If the serializer + * on the request options is null, the serializer on CosmosClientBuilder is used. If both serializers + * are null (the default), an internal Jackson ObjectMapper is ued for serialization/deserialization. + * @param itemSerializerOverride the custom item serializer for this operation + * @return the CosmosItemRequestOptions. + */ + public CosmosReadManyRequestOptions setCustomSerializer(CosmosItemSerializer itemSerializerOverride) { + this.actualRequestOptions.setCustomSerializer(itemSerializerOverride); + + return this; + } + CosmosQueryRequestOptionsBase getImpl() { return this.actualRequestOptions; } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ExcludedPath.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ExcludedPath.java index c80697a441f7..35eecef3603f 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ExcludedPath.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ExcludedPath.java @@ -3,6 +3,7 @@ package com.azure.cosmos.models; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.JsonSerializable; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -50,7 +51,10 @@ public String getPath() { * @return the excluded path. */ public ExcludedPath setPath(String path) { - this.jsonSerializable.set(Constants.Properties.PATH, path); + this.jsonSerializable.set( + Constants.Properties.PATH, + path, + CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/FeedResponse.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/FeedResponse.java index 0d55fb18d4d5..92ba73f78271 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/FeedResponse.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/FeedResponse.java @@ -7,6 +7,7 @@ import com.azure.core.util.paging.ContinuablePage; import com.azure.cosmos.BridgeInternal; import com.azure.cosmos.CosmosDiagnostics; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.ClientSideRequestStatistics; import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.HttpConstants; @@ -571,12 +572,28 @@ void setQueryPlanDiagnosticsContext(QueryInfo.QueryPlanDiagnosticsContext queryP BridgeInternal.setQueryPlanDiagnosticsContext(cosmosDiagnostics, queryPlanDiagnosticsContext); } + private static boolean noChanges(RxDocumentServiceResponse rsp) { + return rsp.getStatusCode() == HttpConstants.StatusCodes.NOT_MODIFIED; + } + /////////////////////////////////////////////////////////////////////////////////////////// // the following helper/accessor only helps to access this class outside of this package.// /////////////////////////////////////////////////////////////////////////////////////////// static void initialize() { ImplementationBridgeHelpers.FeedResponseHelper.setFeedResponseAccessor( new ImplementationBridgeHelpers.FeedResponseHelper.FeedResponseAccessor() { + @Override + public FeedResponse createFeedResponse(RxDocumentServiceResponse response, CosmosItemSerializer itemSerializer, Class cls) { + return new FeedResponse<>(response.getQueryResponse(itemSerializer, cls), response); + } + + @Override + public FeedResponse createChangeFeedResponse(RxDocumentServiceResponse response, CosmosItemSerializer itemSerializer, Class cls) { + return new FeedResponse<>( + noChanges(response) ? Collections.emptyList() : response.getQueryResponse(itemSerializer, cls), + response.getResponseHeaders(), noChanges(response)); + } + @Override public boolean getNoChanges(FeedResponse feedResponse) { return feedResponse.getNoChanges(); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/IncludedPath.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/IncludedPath.java index 68c0b7718071..b32db49c5b7c 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/IncludedPath.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/IncludedPath.java @@ -3,6 +3,7 @@ package com.azure.cosmos.models; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.HashIndex; import com.azure.cosmos.implementation.Index; @@ -61,7 +62,10 @@ public String getPath() { * @return the Included Path. */ public IncludedPath setPath(String path) { - this.jsonSerializable.set(Constants.Properties.PATH, path); + this.jsonSerializable.set( + Constants.Properties.PATH, + path, + CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } @@ -131,7 +135,10 @@ void populatePropertyBag() { index.populatePropertyBag(); } - this.jsonSerializable.set(Constants.Properties.INDEXES, this.indexes); + this.jsonSerializable.set( + Constants.Properties.INDEXES, + this.indexes, + CosmosItemSerializer.DEFAULT_SERIALIZER); } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/IndexingPolicy.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/IndexingPolicy.java index ea1247d2a2dc..4ee5153877f8 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/IndexingPolicy.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/IndexingPolicy.java @@ -3,6 +3,7 @@ package com.azure.cosmos.models; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.Index; import com.azure.cosmos.implementation.JsonSerializable; @@ -108,7 +109,7 @@ public Boolean isAutomatic() { * @return the Indexing Policy. */ public IndexingPolicy setAutomatic(boolean automatic) { - this.jsonSerializable.set(Constants.Properties.AUTOMATIC, automatic); + this.jsonSerializable.set(Constants.Properties.AUTOMATIC, automatic, CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } @@ -135,7 +136,7 @@ public IndexingMode getIndexingMode() { * @return the Indexing Policy. */ public IndexingPolicy setIndexingMode(IndexingMode indexingMode) { - this.jsonSerializable.set(Constants.Properties.INDEXING_MODE, indexingMode.toString()); + this.jsonSerializable.set(Constants.Properties.INDEXING_MODE, indexingMode.toString(), CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } @@ -229,7 +230,7 @@ public List> getCompositeIndexes() { */ public IndexingPolicy setCompositeIndexes(List> compositeIndexes) { this.compositeIndexes = compositeIndexes; - this.jsonSerializable.set(Constants.Properties.COMPOSITE_INDEXES, this.compositeIndexes); + this.jsonSerializable.set(Constants.Properties.COMPOSITE_INDEXES, this.compositeIndexes, CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } @@ -258,7 +259,10 @@ public List getSpatialIndexes() { */ public IndexingPolicy setSpatialIndexes(List spatialIndexes) { this.spatialIndexes = spatialIndexes; - this.jsonSerializable.set(Constants.Properties.SPATIAL_INDEXES, this.spatialIndexes); + this.jsonSerializable.set( + Constants.Properties.SPATIAL_INDEXES, + this.spatialIndexes, + CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } @@ -275,14 +279,20 @@ void populatePropertyBag() { for (IncludedPath includedPath : this.includedPaths) { includedPath.populatePropertyBag(); } - this.jsonSerializable.set(Constants.Properties.INCLUDED_PATHS, this.includedPaths); + this.jsonSerializable.set( + Constants.Properties.INCLUDED_PATHS, + this.includedPaths, + CosmosItemSerializer.DEFAULT_SERIALIZER); } if (this.excludedPaths != null) { for (ExcludedPath excludedPath : this.excludedPaths) { excludedPath.populatePropertyBag(); } - this.jsonSerializable.set(Constants.Properties.EXCLUDED_PATHS, this.excludedPaths); + this.jsonSerializable.set( + Constants.Properties.EXCLUDED_PATHS, + this.excludedPaths, + CosmosItemSerializer.DEFAULT_SERIALIZER); } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ModelBridgeInternal.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ModelBridgeInternal.java index 8a589d7cd421..a8f344ce4e2d 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ModelBridgeInternal.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ModelBridgeInternal.java @@ -5,19 +5,17 @@ import com.azure.cosmos.ConsistencyLevel; import com.azure.cosmos.CosmosDiagnostics; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.ClientEncryptionKey; import com.azure.cosmos.implementation.Conflict; import com.azure.cosmos.implementation.CosmosPagedFluxOptions; -import com.azure.cosmos.implementation.CosmosQueryRequestOptionsBase; import com.azure.cosmos.implementation.CosmosResourceType; import com.azure.cosmos.implementation.Database; import com.azure.cosmos.implementation.DatabaseAccount; -import com.azure.cosmos.implementation.Document; import com.azure.cosmos.implementation.DocumentCollection; import com.azure.cosmos.implementation.HttpConstants; import com.azure.cosmos.implementation.Index; import com.azure.cosmos.implementation.InternalObjectNode; -import com.azure.cosmos.implementation.ItemDeserializer; import com.azure.cosmos.implementation.JsonSerializable; import com.azure.cosmos.implementation.Offer; import com.azure.cosmos.implementation.Permission; @@ -40,19 +38,15 @@ import com.azure.cosmos.implementation.patch.PatchOperation; import com.azure.cosmos.implementation.query.QueryInfo; import com.azure.cosmos.implementation.routing.PartitionKeyInternal; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import java.lang.reflect.InvocationTargetException; import java.nio.ByteBuffer; import java.time.Duration; -import java.time.Instant; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentMap; -import java.util.function.Function; import static com.azure.cosmos.implementation.Warning.INTERNAL_USE_ONLY_WARNING; import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; @@ -87,16 +81,6 @@ public static CosmosDatabaseResponse createCosmosDatabaseResponse(ResourceRespon return new CosmosDatabaseResponse(response); } - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static CosmosItemResponse createCosmosAsyncItemResponse(ResourceResponse response, Class classType, ItemDeserializer itemDeserializer) { - return new CosmosItemResponse<>(response, classType, itemDeserializer); - } - - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static CosmosItemResponse createCosmosAsyncItemResponseWithObjectType(ResourceResponse response) { - return new CosmosItemResponse<>(response, Object.class, null); - } - @Warning(value = INTERNAL_USE_ONLY_WARNING) public static CosmosPermissionResponse createCosmosPermissionResponse(ResourceResponse response) { return new CosmosPermissionResponse(response); @@ -257,16 +241,6 @@ public static CosmosItemRequestOptions setPartitionKey(CosmosItemRequestOptions return cosmosItemRequestOptions.setPartitionKey(partitionKey); } - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static RequestOptions toRequestOptions(CosmosItemRequestOptions cosmosItemRequestOptions) { - return cosmosItemRequestOptions.toRequestOptions(); - } - - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static RequestOptions toRequestOptions(CosmosPatchItemRequestOptions cosmosPatchItemRequestOptions) { - return cosmosPatchItemRequestOptions.toRequestOptions(); - } - @Warning(value = INTERNAL_USE_ONLY_WARNING) public static CosmosItemRequestOptions createCosmosItemRequestOptions(PartitionKey partitionKey) { return new CosmosItemRequestOptions(partitionKey); @@ -321,41 +295,16 @@ public static CosmosQueryRequestOptions setPartitionKeyRangeIdInternal(CosmosQue return options; } - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static FeedResponse toFeedResponsePage( - RxDocumentServiceResponse response, - Function factoryMethod, - Class cls) { - - return new FeedResponse<>(response.getQueryResponse(factoryMethod, cls), response); - } - @Warning(value = INTERNAL_USE_ONLY_WARNING) public static FeedResponse toFeedResponsePage(List results, Map headers, boolean noChanges) { return new FeedResponse<>(results, headers, noChanges); } - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static FeedResponse toChangeFeedResponsePage( - RxDocumentServiceResponse response, - Function factoryMethod, - Class cls) { - - return new FeedResponse<>( - noChanges(response) ? Collections.emptyList() : response.getQueryResponse(factoryMethod, cls), - response.getResponseHeaders(), noChanges(response)); - } - @Warning(value = INTERNAL_USE_ONLY_WARNING) public static boolean noChanges(FeedResponse page) { return page.nochanges; } - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static boolean noChanges(RxDocumentServiceResponse rsp) { - return rsp.getStatusCode() == HttpConstants.StatusCodes.NOT_MODIFIED; - } - @Warning(value = INTERNAL_USE_ONLY_WARNING) public static FeedResponse createFeedResponse(List results, Map headers) { @@ -422,123 +371,11 @@ public static PartitionKey partitionKeyfromJsonString(String jsonString) { return PartitionKey.fromJsonString(jsonString); } - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static Object getPartitionKeyObject(PartitionKey right) { - throw new UnsupportedOperationException("getPartitionKeyObject is not supported"); - } - - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static String getAltLink(Resource resource) { - return resource.getAltLink(); - } - - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static void setAltLink(Resource resource, String altLink) { - resource.setAltLink(altLink); - } - - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static void setResourceId(Resource resource, String resourceId) { - resource.setResourceId(resourceId); - } - - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static void setResourceSelfLink(Resource resource, String selfLink) { - resource.setSelfLink(selfLink); - } - - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static void setTimestamp(Resource resource, Instant date) { - resource.setTimestamp(date); - } - - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static void setProperty(JsonSerializable jsonSerializable, String propertyName, T value) { - jsonSerializable.set(propertyName, value); - } - - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static ObjectNode getObjectNodeFromJsonSerializable(JsonSerializable jsonSerializable, String propertyName) { - return jsonSerializable.getObject(propertyName); - } - - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static void removeFromJsonSerializable(JsonSerializable jsonSerializable, String propertyName) { - jsonSerializable.remove(propertyName); - } - - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static Object getValue(JsonNode value) { - return JsonSerializable.getValue(value); - } - - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static Map getMapFromJsonSerializable(JsonSerializable jsonSerializable) { - return jsonSerializable.getMap(); - } - @Warning(value = INTERNAL_USE_ONLY_WARNING) public static CosmosResourceType fromServiceSerializedFormat(String cosmosResourceType) { return CosmosResourceType.fromServiceSerializedFormat(cosmosResourceType); } - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static Boolean getBooleanFromJsonSerializable(JsonSerializable jsonSerializable, String propertyName) { - return jsonSerializable.getBoolean(propertyName); - } - - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static Double getDoubleFromJsonSerializable(JsonSerializable jsonSerializable, String propertyName) { - return jsonSerializable.getDouble(propertyName); - } - - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static Object getObjectByPathFromJsonSerializable(JsonSerializable jsonSerializable, List propertyNames) { - return jsonSerializable.getObjectByPath(propertyNames); - } - - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static ByteBuffer serializeJsonToByteBuffer(JsonSerializable jsonSerializable) { - return jsonSerializable.serializeJsonToByteBuffer(); - } - - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static T toObjectFromJsonSerializable(JsonSerializable jsonSerializable, Class c) { - return jsonSerializable.toObject(c); - } - - public static ByteBuffer serializeJsonToByteBuffer(JsonSerializable jsonSerializable, ObjectMapper objectMapper) { - return jsonSerializable.serializeJsonToByteBuffer(objectMapper); - } - - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static Object getObjectFromJsonSerializable(JsonSerializable jsonSerializable, String propertyName) { - return jsonSerializable.get(propertyName); - } - - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static String getStringFromJsonSerializable(JsonSerializable jsonSerializable, String propertyName) { - return jsonSerializable.getString(propertyName); - } - - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static Integer getIntFromJsonSerializable(JsonSerializable jsonSerializable, String propertyName) { - return jsonSerializable.getInt(propertyName); - } - - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static String toJsonFromJsonSerializable(JsonSerializable jsonSerializable) { - return jsonSerializable.toJson(); - } - - @Warning(value = INTERNAL_USE_ONLY_WARNING) - public static ObjectNode getPropertyBagFromJsonSerializable(JsonSerializable jsonSerializable) { - if (jsonSerializable == null) { - return null; - } - return jsonSerializable.getPropertyBag(); - } - @Warning(value = INTERNAL_USE_ONLY_WARNING) public static void setQueryRequestOptionsContinuationTokenAndMaxItemCount(CosmosQueryRequestOptions options, String continuationToken, Integer maxItemCount) { options.setRequestContinuation(continuationToken); @@ -566,7 +403,7 @@ public static CosmosChangeFeedRequestOptions getEffectiveChangeFeedRequestOption @Warning(value = INTERNAL_USE_ONLY_WARNING) public static ByteBuffer serializeJsonToByteBuffer(SqlQuerySpec sqlQuerySpec) { sqlQuerySpec.populatePropertyBag(); - return sqlQuerySpec.getJsonSerializable().serializeJsonToByteBuffer(); + return sqlQuerySpec.getJsonSerializable().serializeJsonToByteBuffer(CosmosItemSerializer.DEFAULT_SERIALIZER, null); } @Warning(value = INTERNAL_USE_ONLY_WARNING) @@ -874,7 +711,8 @@ public static CosmosBulkItemResponse createCosmosBulkItemResponse( result.getRetryAfterDuration(), result.getSubStatusCode(), response.getResponseHeaders(), - response.getDiagnostics()); + response.getDiagnostics(), + result.getEffectiveItemSerializer()); } @Warning(value = INTERNAL_USE_ONLY_WARNING) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/PartitionKeyDefinition.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/PartitionKeyDefinition.java index 94bc2b81bbb1..29107f46e3a9 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/PartitionKeyDefinition.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/PartitionKeyDefinition.java @@ -3,6 +3,7 @@ package com.azure.cosmos.models; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.JsonSerializable; import com.azure.cosmos.implementation.Strings; @@ -179,14 +180,23 @@ PartitionKeyInternal getNonePartitionKeyValue() { void populatePropertyBag() { this.jsonSerializable.populatePropertyBag(); if (this.kind != null) { - this.jsonSerializable.set(Constants.Properties.PARTITION_KIND, kind.toString()); + this.jsonSerializable.set( + Constants.Properties.PARTITION_KIND, + kind.toString(), + CosmosItemSerializer.DEFAULT_SERIALIZER); } if (this.paths != null) { - this.jsonSerializable.set(Constants.Properties.PARTITION_KEY_PATHS, paths); + this.jsonSerializable.set( + Constants.Properties.PARTITION_KEY_PATHS, + paths, + CosmosItemSerializer.DEFAULT_SERIALIZER); } if (this.versionOptional != null && versionOptional.isPresent()) { - this.jsonSerializable.set(Constants.Properties.PARTITION_KEY_DEFINITION_VERSION, versionOptional.get().toString()); + this.jsonSerializable.set( + Constants.Properties.PARTITION_KEY_DEFINITION_VERSION, + versionOptional.get().toString(), + CosmosItemSerializer.DEFAULT_SERIALIZER); } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/SpatialSpec.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/SpatialSpec.java index d16bb06e4412..ffeebb9c908c 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/SpatialSpec.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/SpatialSpec.java @@ -3,6 +3,7 @@ package com.azure.cosmos.models; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.JsonSerializable; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -61,7 +62,10 @@ public String getPath() { * @return the SpatialSpec. */ public SpatialSpec setPath(String path) { - this.jsonSerializable.set(Constants.Properties.PATH, path); + this.jsonSerializable.set( + Constants.Properties.PATH, + path, + CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } @@ -94,7 +98,10 @@ public SpatialSpec setSpatialTypes(List spatialTypes) { for (SpatialType spatialType : this.spatialTypes) { spatialTypeNames.add(spatialType.toString()); } - this.jsonSerializable.set(Constants.Properties.TYPES, spatialTypeNames); + this.jsonSerializable.set( + Constants.Properties.TYPES, + spatialTypeNames, + CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/SqlParameter.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/SqlParameter.java index b82881c81967..be8d8977054d 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/SqlParameter.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/SqlParameter.java @@ -3,6 +3,7 @@ package com.azure.cosmos.models; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.JsonSerializable; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -59,7 +60,10 @@ public String getName() { * @return the SqlParameter. */ public SqlParameter setName(String name) { - this.jsonSerializable.set("name", name); + this.jsonSerializable.set( + "name", + name, + CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } @@ -81,7 +85,10 @@ public T getValue(Class classType) { * @return the SqlParameter. */ public SqlParameter setValue(Object value) { - this.jsonSerializable.set("value", value); + this.jsonSerializable.set( + "value", + value, + CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/SqlQuerySpec.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/SqlQuerySpec.java index 9cec02f3237b..18460dbe35f3 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/SqlQuerySpec.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/SqlQuerySpec.java @@ -3,6 +3,7 @@ package com.azure.cosmos.models; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.JsonSerializable; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -90,7 +91,7 @@ public String getQueryText() { * @return the SqlQuerySpec. */ public SqlQuerySpec setQueryText(String queryText) { - this.jsonSerializable.set("query", queryText); + this.jsonSerializable.set("query", queryText, CosmosItemSerializer.DEFAULT_SERIALIZER); return this; } @@ -128,7 +129,7 @@ void populatePropertyBag() { boolean defaultParameters = (this.parameters != null && this.parameters.size() != 0); if (defaultParameters) { - this.jsonSerializable.set("parameters", this.parameters); + this.jsonSerializable.set("parameters", this.parameters, CosmosItemSerializer.DEFAULT_SERIALIZER); } else { this.jsonSerializable.remove("parameters"); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ThroughputResponse.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ThroughputResponse.java index 199d0882da82..c431418cee46 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ThroughputResponse.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ThroughputResponse.java @@ -23,7 +23,7 @@ public class ThroughputResponse extends CosmosResponse { public ThroughputProperties getProperties(){ if (throughputProperties == null){ Offer offer = - new Offer(ModelBridgeInternal.getPropertyBagFromJsonSerializable(offerResourceResponse.getResource())); + new Offer(offerResourceResponse.getResource().getPropertyBag()); throughputProperties = new ThroughputProperties(offer); } return throughputProperties; diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/UniqueKey.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/UniqueKey.java index 1b4b1cd68428..8bde1a57ab9d 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/UniqueKey.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/UniqueKey.java @@ -2,6 +2,7 @@ // Licensed under the MIT License. package com.azure.cosmos.models; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.JsonSerializable; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -92,7 +93,7 @@ public UniqueKey setPaths(List paths) { void populatePropertyBag() { this.jsonSerializable.populatePropertyBag(); if (paths != null) { - this.jsonSerializable.set(Constants.Properties.PATHS, paths); + this.jsonSerializable.set(Constants.Properties.PATHS, paths, CosmosItemSerializer.DEFAULT_SERIALIZER); } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/UniqueKeyPolicy.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/UniqueKeyPolicy.java index c1e5cc30b887..c8d266c4e8e6 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/UniqueKeyPolicy.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/UniqueKeyPolicy.java @@ -2,6 +2,7 @@ // Licensed under the MIT License. package com.azure.cosmos.models; +import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.JsonSerializable; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -80,7 +81,10 @@ void populatePropertyBag() { for (UniqueKey uniqueKey : uniqueKeys) { uniqueKey.populatePropertyBag(); } - this.jsonSerializable.set(Constants.Properties.UNIQUE_KEYS, uniqueKeys); + this.jsonSerializable.set( + Constants.Properties.UNIQUE_KEYS, + uniqueKeys, + CosmosItemSerializer.DEFAULT_SERIALIZER); } }