diff --git a/core/src/main/java/com/arangodb/internal/ArangoExecutor.java b/core/src/main/java/com/arangodb/internal/ArangoExecutor.java index 3f491f701..69ce79ba8 100644 --- a/core/src/main/java/com/arangodb/internal/ArangoExecutor.java +++ b/core/src/main/java/com/arangodb/internal/ArangoExecutor.java @@ -25,6 +25,7 @@ import com.arangodb.internal.config.ArangoConfig; import com.arangodb.internal.net.CommunicationProtocol; import com.arangodb.internal.serde.InternalSerde; +import com.arangodb.serde.SerdeContext; import java.io.IOException; import java.lang.reflect.Type; @@ -58,8 +59,8 @@ public void setJwt(String jwt) { protocol.setJwt(jwt); } - protected T createResult(final Type type, final InternalResponse response) { - return serde.deserialize(response.getBody(), type); + protected T createResult(final Type type, final InternalResponse response, final SerdeContext ctx) { + return serde.deserialize(response.getBody(), type, ctx); } protected final void interceptResponse(InternalResponse response) { @@ -79,6 +80,6 @@ public QueueTimeMetrics getQueueTimeMetrics() { } public interface ResponseDeserializer { - T deserialize(InternalResponse response); + T deserialize(InternalResponse response, SerdeContext ctx); } } diff --git a/core/src/main/java/com/arangodb/internal/ArangoExecutorAsync.java b/core/src/main/java/com/arangodb/internal/ArangoExecutorAsync.java index 88c50ac2a..b09d1bc81 100644 --- a/core/src/main/java/com/arangodb/internal/ArangoExecutorAsync.java +++ b/core/src/main/java/com/arangodb/internal/ArangoExecutorAsync.java @@ -24,6 +24,8 @@ import com.arangodb.internal.config.ArangoConfig; import com.arangodb.internal.net.CommunicationProtocol; import com.arangodb.internal.net.HostHandle; +import com.arangodb.internal.serde.SerdeUtils; +import com.arangodb.serde.SerdeContext; import java.lang.reflect.Type; import java.util.concurrent.CompletableFuture; @@ -48,7 +50,7 @@ public CompletableFuture execute(final Supplier requestS } public CompletableFuture execute(final Supplier requestSupplier, final Type type, final HostHandle hostHandle) { - return execute(requestSupplier, response -> createResult(type, response), hostHandle); + return execute(requestSupplier, (response, ctx) -> createResult(type, response, ctx), hostHandle); } public CompletableFuture execute(final Supplier requestSupplier, final ResponseDeserializer responseDeserializer) { @@ -62,13 +64,16 @@ public CompletableFuture execute( CompletableFuture cf = CompletableFuture.completedFuture(requestSupplier) .thenApply(Supplier::get) - .thenCompose(request -> protocol.executeAsync(interceptRequest(request), hostHandle)) + .thenCompose(request -> protocol + .executeAsync(interceptRequest(request), hostHandle) + .thenApply(resp -> new ResponseWithContext(resp, SerdeUtils.createSerdeContext(request))) + ) .handle((r, e) -> { if (e != null) { throw ArangoDBException.of(e); } else { - interceptResponse(r); - return responseDeserializer.deserialize(r); + interceptResponse(r.response); + return responseDeserializer.deserialize(r.response, r.context); } }); @@ -79,4 +84,15 @@ public CompletableFuture execute( } } + private static class ResponseWithContext { + final InternalResponse response; + final SerdeContext context; + + ResponseWithContext(InternalResponse response, SerdeContext context) { + this.response = response; + this.context = context; + } + } + + } diff --git a/core/src/main/java/com/arangodb/internal/ArangoExecutorSync.java b/core/src/main/java/com/arangodb/internal/ArangoExecutorSync.java index 9da32958e..a34750aa0 100644 --- a/core/src/main/java/com/arangodb/internal/ArangoExecutorSync.java +++ b/core/src/main/java/com/arangodb/internal/ArangoExecutorSync.java @@ -23,6 +23,7 @@ import com.arangodb.internal.config.ArangoConfig; import com.arangodb.internal.net.CommunicationProtocol; import com.arangodb.internal.net.HostHandle; +import com.arangodb.internal.serde.SerdeUtils; import java.lang.reflect.Type; @@ -40,7 +41,7 @@ public T execute(final InternalRequest request, final Type type) { } public T execute(final InternalRequest request, final Type type, final HostHandle hostHandle) { - return execute(request, response -> createResult(type, response), hostHandle); + return execute(request, (response, ctx) -> createResult(type, response, ctx), hostHandle); } public T execute(final InternalRequest request, final ResponseDeserializer responseDeserializer) { @@ -54,7 +55,7 @@ public T execute( final InternalResponse response = protocol.execute(interceptRequest(request), hostHandle); interceptResponse(response); - return responseDeserializer.deserialize(response); + return responseDeserializer.deserialize(response, SerdeUtils.createSerdeContext(request)); } } diff --git a/core/src/main/java/com/arangodb/internal/InternalArangoCollection.java b/core/src/main/java/com/arangodb/internal/InternalArangoCollection.java index a6e308d33..8df197f64 100644 --- a/core/src/main/java/com/arangodb/internal/InternalArangoCollection.java +++ b/core/src/main/java/com/arangodb/internal/InternalArangoCollection.java @@ -110,7 +110,7 @@ private InternalRequest createInsertDocumentRequest(final DocumentCreateOptions } protected ResponseDeserializer>> insertDocumentsResponseDeserializer(Class userDataClass) { - return response -> { + return (response, ctx) -> { final MultiDocumentEntity> multiDocument = new MultiDocumentEntity<>(); final List> docs = new ArrayList<>(); final List errors = new ArrayList<>(); @@ -119,12 +119,12 @@ protected ResponseDeserializer>> for (final JsonNode next : body) { JsonNode isError = next.get(ArangoResponseField.ERROR_FIELD_NAME); if (isError != null && isError.booleanValue()) { - final ErrorEntity error = getSerde().deserialize(next, ErrorEntity.class); + final ErrorEntity error = getSerde().deserialize(next, ErrorEntity.class, ctx); errors.add(error); documentsAndErrors.add(error); } else { Type type = constructParametricType(DocumentCreateEntity.class, userDataClass); - final DocumentCreateEntity doc = getSerde().deserialize(next, type); + final DocumentCreateEntity doc = getSerde().deserialize(next, type, ctx); docs.add(doc); documentsAndErrors.add(doc); } @@ -168,7 +168,7 @@ protected InternalRequest getDocumentRequest(final String key, final DocumentRea } protected ResponseDeserializer getDocumentResponseDeserializer(final Class type) { - return response -> getSerde().deserializeUserData(response.getBody(), type); + return (response, ctx) -> getSerde().deserializeUserData(response.getBody(), type, ctx); } protected InternalRequest getDocumentsRequest(final Iterable keys, final DocumentReadOptions options) { @@ -186,7 +186,7 @@ protected InternalRequest getDocumentsRequest(final Iterable keys, final protected ResponseDeserializer> getDocumentsResponseDeserializer( final Class type) { - return response -> { + return (response, ctx) -> { final MultiDocumentEntity multiDocument = new MultiDocumentEntity<>(); boolean potentialDirtyRead = Boolean.parseBoolean(response.getMeta("X-Arango-Potential-Dirty-Read")); multiDocument.setPotentialDirtyRead(potentialDirtyRead); @@ -197,11 +197,11 @@ protected ResponseDeserializer> getDocumentsResponseD for (final JsonNode next : body) { JsonNode isError = next.get(ArangoResponseField.ERROR_FIELD_NAME); if (isError != null && isError.booleanValue()) { - final ErrorEntity error = getSerde().deserialize(next, ErrorEntity.class); + final ErrorEntity error = getSerde().deserialize(next, ErrorEntity.class, ctx); errors.add(error); documentsAndErrors.add(error); } else { - final T doc = getSerde().deserializeUserData(getSerde().serialize(next), type); + final T doc = getSerde().deserializeUserData(getSerde().serialize(next), type, ctx); docs.add(doc); documentsAndErrors.add(doc); } @@ -249,7 +249,7 @@ private InternalRequest createReplaceDocumentRequest(final DocumentReplaceOption protected ResponseDeserializer>> replaceDocumentsResponseDeserializer( final Class returnType) { - return response -> { + return (response, ctx) -> { final MultiDocumentEntity> multiDocument = new MultiDocumentEntity<>(); final List> docs = new ArrayList<>(); final List errors = new ArrayList<>(); @@ -258,12 +258,12 @@ protected ResponseDeserializer>> for (final JsonNode next : body) { JsonNode isError = next.get(ArangoResponseField.ERROR_FIELD_NAME); if (isError != null && isError.booleanValue()) { - final ErrorEntity error = getSerde().deserialize(next, ErrorEntity.class); + final ErrorEntity error = getSerde().deserialize(next, ErrorEntity.class, ctx); errors.add(error); documentsAndErrors.add(error); } else { Type type = constructParametricType(DocumentUpdateEntity.class, returnType); - final DocumentUpdateEntity doc = getSerde().deserialize(next, type); + final DocumentUpdateEntity doc = getSerde().deserialize(next, type, ctx); docs.add(doc); documentsAndErrors.add(doc); } @@ -312,7 +312,7 @@ private InternalRequest createUpdateDocumentRequest(final DocumentUpdateOptions protected ResponseDeserializer>> updateDocumentsResponseDeserializer( final Class returnType) { - return response -> { + return (response, ctx) -> { final MultiDocumentEntity> multiDocument = new MultiDocumentEntity<>(); final List> docs = new ArrayList<>(); final List errors = new ArrayList<>(); @@ -321,12 +321,12 @@ protected ResponseDeserializer>> for (final JsonNode next : body) { JsonNode isError = next.get(ArangoResponseField.ERROR_FIELD_NAME); if (isError != null && isError.booleanValue()) { - final ErrorEntity error = getSerde().deserialize(next, ErrorEntity.class); + final ErrorEntity error = getSerde().deserialize(next, ErrorEntity.class, ctx); errors.add(error); documentsAndErrors.add(error); } else { Type type = constructParametricType(DocumentUpdateEntity.class, returnType); - final DocumentUpdateEntity doc = getSerde().deserialize(next, type); + final DocumentUpdateEntity doc = getSerde().deserialize(next, type, ctx); docs.add(doc); documentsAndErrors.add(doc); } @@ -368,7 +368,7 @@ private InternalRequest createDeleteDocumentRequest(final DocumentDeleteOptions protected ResponseDeserializer>> deleteDocumentsResponseDeserializer( final Class userDataClass) { - return response -> { + return (response, ctx) -> { final MultiDocumentEntity> multiDocument = new MultiDocumentEntity<>(); final List> docs = new ArrayList<>(); final List errors = new ArrayList<>(); @@ -377,12 +377,12 @@ protected ResponseDeserializer>> for (final JsonNode next : body) { JsonNode isError = next.get(ArangoResponseField.ERROR_FIELD_NAME); if (isError != null && isError.booleanValue()) { - final ErrorEntity error = getSerde().deserialize(next, ErrorEntity.class); + final ErrorEntity error = getSerde().deserialize(next, ErrorEntity.class, ctx); errors.add(error); documentsAndErrors.add(error); } else { Type type = constructParametricType(DocumentDeleteEntity.class, userDataClass); - final DocumentDeleteEntity doc = getSerde().deserialize(next, type); + final DocumentDeleteEntity doc = getSerde().deserialize(next, type, ctx); docs.add(doc); documentsAndErrors.add(doc); } @@ -413,7 +413,7 @@ protected InternalRequest deleteIndexRequest(final String id) { } protected ResponseDeserializer deleteIndexResponseDeserializer() { - return response -> getSerde().deserialize(response.getBody(), "/id", String.class); + return (response, ctx) -> getSerde().deserialize(response.getBody(), "/id", String.class, ctx); } private String createIndexId(final String id) { @@ -495,11 +495,11 @@ protected InternalRequest getIndexesRequest() { } protected ResponseDeserializer> getIndexesResponseDeserializer() { - return response -> { + return (response, ctx) -> { Collection indexes = new ArrayList<>(); for (JsonNode idx : getSerde().parse(response.getBody(), "/indexes")) { if (!"inverted".equals(idx.get("type").textValue())) { - indexes.add(getSerde().deserialize(idx, IndexEntity.class)); + indexes.add(getSerde().deserialize(idx, IndexEntity.class, ctx)); } } return indexes; @@ -507,11 +507,11 @@ protected ResponseDeserializer> getIndexesResponseDeseri } protected ResponseDeserializer> getInvertedIndexesResponseDeserializer() { - return response -> { + return (response, ctx) -> { Collection indexes = new ArrayList<>(); for (JsonNode idx : getSerde().parse(response.getBody(), "/indexes")) { if ("inverted".equals(idx.get("type").textValue())) { - indexes.add(getSerde().deserialize(idx, InvertedIndexEntity.class)); + indexes.add(getSerde().deserialize(idx, InvertedIndexEntity.class, ctx)); } } return indexes; @@ -583,8 +583,8 @@ protected InternalRequest getPermissionsRequest(final String user) { } protected ResponseDeserializer getPermissionsResponseDeserialzer() { - return response -> getSerde().deserialize(response.getBody(), ArangoResponseField.RESULT_JSON_POINTER, - Permissions.class); + return (response, ctx) -> getSerde().deserialize(response.getBody(), ArangoResponseField.RESULT_JSON_POINTER, + Permissions.class, ctx); } } diff --git a/core/src/main/java/com/arangodb/internal/InternalArangoDB.java b/core/src/main/java/com/arangodb/internal/InternalArangoDB.java index 9ddd14da5..47cd5b085 100644 --- a/core/src/main/java/com/arangodb/internal/InternalArangoDB.java +++ b/core/src/main/java/com/arangodb/internal/InternalArangoDB.java @@ -66,11 +66,11 @@ protected InternalRequest getServerIdRequest() { } protected ResponseDeserializer getRoleResponseDeserializer() { - return response -> getSerde().deserialize(response.getBody(), "/role", ServerRole.class); + return (response, ctx) -> getSerde().deserialize(response.getBody(), "/role", ServerRole.class, ctx); } protected ResponseDeserializer getServerIdResponseDeserializer() { - return response -> getSerde().deserialize(response.getBody(), "/id", String.class); + return (response, ctx) -> getSerde().deserialize(response.getBody(), "/id", String.class, ctx); } protected InternalRequest createDatabaseRequest(final DBCreateOptions options) { @@ -81,8 +81,8 @@ protected InternalRequest createDatabaseRequest(final DBCreateOptions options) { } protected ResponseDeserializer createDatabaseResponseDeserializer() { - return response -> getSerde().deserialize(response.getBody(), ArangoResponseField.RESULT_JSON_POINTER, - Boolean.class); + return (response, ctx) -> getSerde().deserialize(response.getBody(), ArangoResponseField.RESULT_JSON_POINTER, + Boolean.class, ctx); } protected InternalRequest getDatabasesRequest(final String dbName) { @@ -90,8 +90,8 @@ protected InternalRequest getDatabasesRequest(final String dbName) { } protected ResponseDeserializer> getDatabaseResponseDeserializer() { - return response -> getSerde().deserialize(response.getBody(), ArangoResponseField.RESULT_JSON_POINTER, - constructListType(String.class)); + return (response, ctx) -> getSerde().deserialize(response.getBody(), ArangoResponseField.RESULT_JSON_POINTER, + constructListType(String.class), ctx); } protected InternalRequest getAccessibleDatabasesForRequest(final String dbName, final String user) { @@ -99,7 +99,7 @@ protected InternalRequest getAccessibleDatabasesForRequest(final String dbName, } protected ResponseDeserializer> getAccessibleDatabasesForResponseDeserializer() { - return response -> { + return (response, ctx) -> { Iterator names = getSerde().parse(response.getBody(), ArangoResponseField.RESULT_JSON_POINTER).fieldNames(); final Collection dbs = new ArrayList<>(); @@ -136,8 +136,8 @@ protected InternalRequest getUserRequest(final String dbName, final String user) } protected ResponseDeserializer> getUsersResponseDeserializer() { - return response -> getSerde().deserialize(response.getBody(), ArangoResponseField.RESULT_JSON_POINTER, - constructListType(UserEntity.class)); + return (response, ctx) -> getSerde().deserialize(response.getBody(), ArangoResponseField.RESULT_JSON_POINTER, + constructListType(UserEntity.class), ctx); } protected InternalRequest updateUserRequest(final String dbName, final String user, final UserUpdateOptions options) { @@ -173,10 +173,10 @@ protected InternalRequest executeRequest(final Request request) { } protected ResponseDeserializer> responseDeserializer(Class type) { - return response -> new Response<>( + return (response, ctx) -> new Response<>( response.getResponseCode(), response.getMeta(), - getSerde().deserializeUserData(response.getBody(), type) + getSerde().deserializeUserData(response.getBody(), type, ctx) ); } diff --git a/core/src/main/java/com/arangodb/internal/InternalArangoDatabase.java b/core/src/main/java/com/arangodb/internal/InternalArangoDatabase.java index e9b7da8e0..5ad1fc963 100644 --- a/core/src/main/java/com/arangodb/internal/InternalArangoDatabase.java +++ b/core/src/main/java/com/arangodb/internal/InternalArangoDatabase.java @@ -70,8 +70,8 @@ public String name() { } protected ResponseDeserializer> getDatabaseResponseDeserializer() { - return response -> getSerde().deserialize(response.getBody(), ArangoResponseField.RESULT_JSON_POINTER, - constructListType(String.class)); + return (response, ctx) -> getSerde().deserialize(response.getBody(), ArangoResponseField.RESULT_JSON_POINTER, + constructListType(String.class), ctx); } protected InternalRequest getAccessibleDatabasesRequest() { @@ -103,8 +103,8 @@ protected InternalRequest getCollectionsRequest(final CollectionsReadOptions opt } protected ResponseDeserializer> getCollectionsResponseDeserializer() { - return response -> getSerde().deserialize(response.getBody(), ArangoResponseField.RESULT_JSON_POINTER, - constructListType(CollectionEntity.class)); + return (response, ctx) -> getSerde().deserialize(response.getBody(), ArangoResponseField.RESULT_JSON_POINTER, + constructListType(CollectionEntity.class), ctx); } protected InternalRequest dropRequest() { @@ -112,8 +112,8 @@ protected InternalRequest dropRequest() { } protected ResponseDeserializer createDropResponseDeserializer() { - return response -> getSerde().deserialize(response.getBody(), ArangoResponseField.RESULT_JSON_POINTER, - Boolean.class); + return (response, ctx) -> getSerde().deserialize(response.getBody(), ArangoResponseField.RESULT_JSON_POINTER, + Boolean.class, ctx); } protected InternalRequest grantAccessRequest(final String user, final Permissions permissions) { @@ -136,8 +136,8 @@ protected InternalRequest getPermissionsRequest(final String user) { } protected ResponseDeserializer getPermissionsResponseDeserialzer() { - return response -> getSerde().deserialize(response.getBody(), ArangoResponseField.RESULT_JSON_POINTER, - Permissions.class); + return (response, ctx) -> getSerde().deserialize(response.getBody(), ArangoResponseField.RESULT_JSON_POINTER, + Permissions.class, ctx); } protected InternalRequest queryRequest(final String query, final Map bindVars, @@ -232,8 +232,8 @@ protected InternalRequest deleteAqlFunctionRequest(final String name, final AqlF } public ResponseDeserializer> cursorEntityDeserializer(final Class type) { - return response -> { - CursorEntity e = getSerde().deserialize(response.getBody(), constructParametricType(CursorEntity.class, type)); + return (response, ctx) -> { + CursorEntity e = getSerde().deserialize(response.getBody(), constructParametricType(CursorEntity.class, type), ctx); boolean potentialDirtyRead = Boolean.parseBoolean(response.getMeta("X-Arango-Potential-Dirty-Read")); e.setPotentialDirtyRead(potentialDirtyRead); return e; @@ -241,7 +241,7 @@ public ResponseDeserializer> cursorEntityDeserializer(final } protected ResponseDeserializer deleteAqlFunctionResponseDeserializer() { - return response -> getSerde().deserialize(response.getBody(), "/deletedCount", Integer.class); + return (response, ctx) -> getSerde().deserialize(response.getBody(), "/deletedCount", Integer.class, ctx); } protected InternalRequest getAqlFunctionsRequest(final AqlFunctionGetOptions options) { @@ -252,8 +252,8 @@ protected InternalRequest getAqlFunctionsRequest(final AqlFunctionGetOptions opt } protected ResponseDeserializer> getAqlFunctionsResponseDeserializer() { - return response -> getSerde().deserialize(response.getBody(), ArangoResponseField.RESULT_JSON_POINTER, - constructListType(AqlFunctionEntity.class)); + return (response, ctx) -> getSerde().deserialize(response.getBody(), ArangoResponseField.RESULT_JSON_POINTER, + constructListType(AqlFunctionEntity.class), ctx); } protected InternalRequest createGraphRequest(final String name, final Iterable edgeDefinitions, @@ -265,7 +265,7 @@ protected InternalRequest createGraphRequest(final String name, final Iterable createGraphResponseDeserializer() { - return response -> getSerde().deserialize(response.getBody(), "/graph", GraphEntity.class); + return (response, ctx) -> getSerde().deserialize(response.getBody(), "/graph", GraphEntity.class, ctx); } protected InternalRequest getGraphsRequest() { @@ -273,8 +273,8 @@ protected InternalRequest getGraphsRequest() { } protected ResponseDeserializer> getGraphsResponseDeserializer() { - return response -> getSerde().deserialize(response.getBody(), "/graphs", - constructListType(GraphEntity.class)); + return (response, ctx) -> getSerde().deserialize(response.getBody(), "/graphs", + constructListType(GraphEntity.class), ctx); } protected InternalRequest transactionRequest(final String action, final TransactionOptions options) { @@ -282,9 +282,9 @@ protected InternalRequest transactionRequest(final String action, final Transact } protected ResponseDeserializer transactionResponseDeserializer(final Class type) { - return response -> { + return (response, ctx) -> { byte[] userContent = getSerde().extract(response.getBody(), ArangoResponseField.RESULT_JSON_POINTER); - return getSerde().deserializeUserData(userContent, type); + return getSerde().deserializeUserData(userContent, type, ctx); }; } @@ -310,8 +310,8 @@ protected InternalRequest getStreamTransactionRequest(String id) { } protected ResponseDeserializer> transactionsResponseDeserializer() { - return response -> getSerde().deserialize(response.getBody(), "/transactions", - constructListType(TransactionEntity.class)); + return (response, ctx) -> getSerde().deserialize(response.getBody(), "/transactions", + constructListType(TransactionEntity.class), ctx); } protected InternalRequest commitStreamTransactionRequest(String id) { @@ -319,8 +319,8 @@ protected InternalRequest commitStreamTransactionRequest(String id) { } protected ResponseDeserializer streamTransactionResponseDeserializer() { - return response -> getSerde().deserialize(response.getBody(), ArangoResponseField.RESULT_JSON_POINTER, - StreamTransactionEntity.class); + return (response, ctx) -> getSerde().deserialize(response.getBody(), ArangoResponseField.RESULT_JSON_POINTER, + StreamTransactionEntity.class, ctx); } protected InternalRequest getInfoRequest() { @@ -328,8 +328,8 @@ protected InternalRequest getInfoRequest() { } protected ResponseDeserializer getInfoResponseDeserializer() { - return response -> getSerde().deserialize(response.getBody(), ArangoResponseField.RESULT_JSON_POINTER, - DatabaseEntity.class); + return (response, ctx) -> getSerde().deserialize(response.getBody(), ArangoResponseField.RESULT_JSON_POINTER, + DatabaseEntity.class, ctx); } protected InternalRequest reloadRoutingRequest() { @@ -341,8 +341,8 @@ protected InternalRequest getViewsRequest() { } protected ResponseDeserializer> getViewsResponseDeserializer() { - return response -> getSerde().deserialize(response.getBody(), ArangoResponseField.RESULT_JSON_POINTER, - constructListType(ViewEntity.class)); + return (response, ctx) -> getSerde().deserialize(response.getBody(), ArangoResponseField.RESULT_JSON_POINTER, + constructListType(ViewEntity.class), ctx); } protected InternalRequest createViewRequest(final String name, final ViewType type) { @@ -367,8 +367,8 @@ protected InternalRequest getAnalyzersRequest() { } protected ResponseDeserializer> getSearchAnalyzersResponseDeserializer() { - return response -> getSerde().deserialize(response.getBody(), ArangoResponseField.RESULT_JSON_POINTER, - constructListType(SearchAnalyzer.class)); + return (response, ctx) -> getSerde().deserialize(response.getBody(), ArangoResponseField.RESULT_JSON_POINTER, + constructListType(SearchAnalyzer.class), ctx); } protected InternalRequest createAnalyzerRequest(final SearchAnalyzer options) { diff --git a/core/src/main/java/com/arangodb/internal/InternalArangoEdgeCollection.java b/core/src/main/java/com/arangodb/internal/InternalArangoEdgeCollection.java index df42d2480..c0497771f 100644 --- a/core/src/main/java/com/arangodb/internal/InternalArangoEdgeCollection.java +++ b/core/src/main/java/com/arangodb/internal/InternalArangoEdgeCollection.java @@ -79,7 +79,7 @@ protected InternalRequest insertEdgeRequest(final T value, final EdgeCreateO } protected ResponseDeserializer insertEdgeResponseDeserializer() { - return response -> getSerde().deserialize(response.getBody(), EDGE_JSON_POINTER, EdgeEntity.class); + return (response, ctx) -> getSerde().deserialize(response.getBody(), EDGE_JSON_POINTER, EdgeEntity.class, ctx); } protected InternalRequest getEdgeRequest(final String key, final GraphDocumentReadOptions options) { @@ -96,7 +96,7 @@ protected InternalRequest getEdgeRequest(final String key, final GraphDocumentRe } protected ResponseDeserializer getEdgeResponseDeserializer(final Class type) { - return response -> getSerde().deserializeUserData(getSerde().extract(response.getBody(), EDGE_JSON_POINTER), type); + return (response, ctx) -> getSerde().deserializeUserData(getSerde().extract(response.getBody(), EDGE_JSON_POINTER), type, ctx); } protected InternalRequest replaceEdgeRequest(final String key, final T value, final EdgeReplaceOptions options) { @@ -111,7 +111,7 @@ protected InternalRequest replaceEdgeRequest(final String key, final T value } protected ResponseDeserializer replaceEdgeResponseDeserializer() { - return response -> getSerde().deserialize(response.getBody(), EDGE_JSON_POINTER, EdgeUpdateEntity.class); + return (response, ctx) -> getSerde().deserialize(response.getBody(), EDGE_JSON_POINTER, EdgeUpdateEntity.class, ctx); } protected InternalRequest updateEdgeRequest(final String key, final T value, final EdgeUpdateOptions options) { @@ -128,7 +128,7 @@ protected InternalRequest updateEdgeRequest(final String key, final T value, } protected ResponseDeserializer updateEdgeResponseDeserializer() { - return response -> getSerde().deserialize(response.getBody(), EDGE_JSON_POINTER, EdgeUpdateEntity.class); + return (response, ctx) -> getSerde().deserialize(response.getBody(), EDGE_JSON_POINTER, EdgeUpdateEntity.class, ctx); } protected InternalRequest deleteEdgeRequest(final String key, final EdgeDeleteOptions options) { diff --git a/core/src/main/java/com/arangodb/internal/InternalArangoGraph.java b/core/src/main/java/com/arangodb/internal/InternalArangoGraph.java index 85d3e90ad..ff0bd6578 100644 --- a/core/src/main/java/com/arangodb/internal/InternalArangoGraph.java +++ b/core/src/main/java/com/arangodb/internal/InternalArangoGraph.java @@ -79,8 +79,8 @@ protected InternalRequest getVertexCollectionsRequest() { } protected ResponseDeserializer> getVertexCollectionsResponseDeserializer() { - return response -> getSerde().deserialize(response.getBody(), "/collections", - constructListType(String.class)); + return (response, ctx) -> getSerde().deserialize(response.getBody(), "/collections", + constructListType(String.class), ctx); } protected InternalRequest addVertexCollectionRequest(final String name, final VertexCollectionCreateOptions options) { @@ -98,8 +98,8 @@ protected InternalRequest getEdgeDefinitionsRequest() { } protected ResponseDeserializer> getEdgeDefinitionsDeserializer() { - return response -> getSerde().deserialize(response.getBody(), "/collections", - constructListType(String.class)); + return (response, ctx) -> getSerde().deserialize(response.getBody(), "/collections", + constructListType(String.class), ctx); } protected InternalRequest addEdgeDefinitionRequest(final EdgeDefinition definition) { @@ -109,7 +109,7 @@ protected InternalRequest addEdgeDefinitionRequest(final EdgeDefinition definiti } protected ResponseDeserializer addEdgeDefinitionResponseDeserializer() { - return response -> getSerde().deserialize(response.getBody(), GRAPH, GraphEntity.class); + return (response, ctx) -> getSerde().deserialize(response.getBody(), GRAPH, GraphEntity.class, ctx); } protected InternalRequest replaceEdgeDefinitionRequest(final EdgeDefinition definition, final ReplaceEdgeDefinitionOptions options) { @@ -122,7 +122,7 @@ protected InternalRequest replaceEdgeDefinitionRequest(final EdgeDefinition defi } protected ResponseDeserializer replaceEdgeDefinitionResponseDeserializer() { - return response -> getSerde().deserialize(response.getBody(), GRAPH, GraphEntity.class); + return (response, ctx) -> getSerde().deserialize(response.getBody(), GRAPH, GraphEntity.class, ctx); } } diff --git a/core/src/main/java/com/arangodb/internal/InternalArangoVertexCollection.java b/core/src/main/java/com/arangodb/internal/InternalArangoVertexCollection.java index 644f4a609..ed1ec87d0 100644 --- a/core/src/main/java/com/arangodb/internal/InternalArangoVertexCollection.java +++ b/core/src/main/java/com/arangodb/internal/InternalArangoVertexCollection.java @@ -77,7 +77,7 @@ protected InternalRequest insertVertexRequest(final T value, final VertexCre } protected ResponseDeserializer insertVertexResponseDeserializer() { - return response -> getSerde().deserialize(response.getBody(), VERTEX_JSON_POINTER, VertexEntity.class); + return (response, ctx) -> getSerde().deserialize(response.getBody(), VERTEX_JSON_POINTER, VertexEntity.class, ctx); } protected InternalRequest getVertexRequest(final String key, final GraphDocumentReadOptions options) { @@ -94,7 +94,7 @@ protected InternalRequest getVertexRequest(final String key, final GraphDocument } protected ResponseDeserializer getVertexResponseDeserializer(final Class type) { - return response -> getSerde().deserializeUserData(getSerde().extract(response.getBody(), VERTEX_JSON_POINTER), type); + return (response, ctx) -> getSerde().deserializeUserData(getSerde().extract(response.getBody(), VERTEX_JSON_POINTER), type, ctx); } protected InternalRequest replaceVertexRequest(final String key, final T value, final VertexReplaceOptions options) { @@ -109,7 +109,7 @@ protected InternalRequest replaceVertexRequest(final String key, final T val } protected ResponseDeserializer replaceVertexResponseDeserializer() { - return response -> getSerde().deserialize(response.getBody(), VERTEX_JSON_POINTER, VertexUpdateEntity.class); + return (response, ctx) -> getSerde().deserialize(response.getBody(), VERTEX_JSON_POINTER, VertexUpdateEntity.class, ctx); } protected InternalRequest updateVertexRequest(final String key, final T value, final VertexUpdateOptions options) { @@ -126,7 +126,7 @@ protected InternalRequest updateVertexRequest(final String key, final T valu } protected ResponseDeserializer updateVertexResponseDeserializer() { - return response -> getSerde().deserialize(response.getBody(), VERTEX_JSON_POINTER, VertexUpdateEntity.class); + return (response, ctx) -> getSerde().deserialize(response.getBody(), VERTEX_JSON_POINTER, VertexUpdateEntity.class, ctx); } protected InternalRequest deleteVertexRequest(final String key, final VertexDeleteOptions options) { diff --git a/core/src/main/java/com/arangodb/internal/net/ExtendedHostResolver.java b/core/src/main/java/com/arangodb/internal/net/ExtendedHostResolver.java index 5f778349e..3dd8e9c40 100644 --- a/core/src/main/java/com/arangodb/internal/net/ExtendedHostResolver.java +++ b/core/src/main/java/com/arangodb/internal/net/ExtendedHostResolver.java @@ -133,11 +133,11 @@ private Collection resolveFromServer() { try { response = executor.execute( new InternalRequest(ArangoRequestParam.SYSTEM, RequestType.GET, "/_api/cluster/endpoints"), - response1 -> { - final List> tmp = arangoSerialization.deserialize(response1.getBody(), + (r, ctx) -> { + final List> tmp = arangoSerialization.deserialize(r.getBody(), "/endpoints", constructParametricType(List.class, - constructParametricType(Map.class, String.class, String.class))); + constructParametricType(Map.class, String.class, String.class)), ctx); Collection endpoints = new ArrayList<>(); for (final Map map : tmp) { endpoints.add(map.get("endpoint")); diff --git a/core/src/main/java/com/arangodb/internal/serde/InternalSerde.java b/core/src/main/java/com/arangodb/internal/serde/InternalSerde.java index 758cc550a..e5ab9d689 100644 --- a/core/src/main/java/com/arangodb/internal/serde/InternalSerde.java +++ b/core/src/main/java/com/arangodb/internal/serde/InternalSerde.java @@ -3,6 +3,7 @@ import com.arangodb.arch.UsedInApi; import com.arangodb.serde.ArangoSerde; import com.arangodb.ContentType; +import com.arangodb.serde.SerdeContext; import com.fasterxml.jackson.databind.JsonNode; import java.lang.reflect.Type; @@ -34,19 +35,21 @@ public interface InternalSerde extends ArangoSerde { * * @param content byte array to deserialize * @param type target data type + * @param ctx serde context * @return deserialized object */ - T deserialize(byte[] content, Type type); + T deserialize(byte[] content, Type type, SerdeContext ctx); /** * Deserializes the parsed json node and binds it to the target data type. * * @param node parsed json node * @param clazz class of target data type + * @param ctx serde context * @return deserialized object */ - default T deserialize(JsonNode node, Class clazz) { - return deserialize(node, (Type) clazz); + default T deserialize(JsonNode node, Class clazz, SerdeContext ctx) { + return deserialize(node, (Type) clazz, ctx); } /** @@ -54,9 +57,10 @@ default T deserialize(JsonNode node, Class clazz) { * * @param node parsed json node * @param type target data type + * @param ctx serde context * @return deserialized object */ - T deserialize(JsonNode node, Type type); + T deserialize(JsonNode node, Type type, SerdeContext ctx); /** * Parses the content. @@ -82,10 +86,11 @@ default T deserialize(JsonNode node, Class clazz) { * @param content byte array to deserialize * @param jsonPointer location of data to be deserialized * @param clazz class of target data type + * @param ctx serde context * @return deserialized object */ - default T deserialize(byte[] content, String jsonPointer, Class clazz) { - return deserialize(content, jsonPointer, (Type) clazz); + default T deserialize(byte[] content, String jsonPointer, Class clazz, SerdeContext ctx) { + return deserialize(content, jsonPointer, (Type) clazz, ctx); } /** @@ -95,10 +100,11 @@ default T deserialize(byte[] content, String jsonPointer, Class clazz) { * @param content byte array to deserialize * @param jsonPointer location of data to be deserialized * @param type target data type + * @param ctx serde context * @return deserialized object */ - default T deserialize(byte[] content, String jsonPointer, Type type) { - return deserialize(parse(content, jsonPointer), type); + default T deserialize(byte[] content, String jsonPointer, Type type, SerdeContext ctx) { + return deserialize(parse(content, jsonPointer), type, ctx); } /** @@ -122,28 +128,31 @@ default T deserialize(byte[] content, String jsonPointer, Type type) { * * @param content byte array to deserialize * @param clazz class of target data type + * @param ctx serde context * @return deserialized object */ - T deserializeUserData(byte[] content, Class clazz); + T deserializeUserData(byte[] content, Class clazz, SerdeContext ctx); /** * Deserializes the content and binds it to the target data type, using the user serde. * * @param content byte array to deserialize * @param type target data type + * @param ctx serde context * @return deserialized object */ - T deserializeUserData(byte[] content, Type type); + T deserializeUserData(byte[] content, Type type, SerdeContext ctx); /** * Deserializes the parsed json node and binds it to the target data type, using the user serde. * * @param node parsed json node * @param clazz class of target data type + * @param ctx serde context * @return deserialized object */ - default T deserializeUserData(JsonNode node, Class clazz) { - return deserializeUserData(node, (Type) clazz); + default T deserializeUserData(JsonNode node, Class clazz, SerdeContext ctx) { + return deserializeUserData(node, (Type) clazz, ctx); } /** @@ -151,9 +160,10 @@ default T deserializeUserData(JsonNode node, Class clazz) { * * @param node parsed json node * @param type target data type + * @param ctx serde context * @return deserialized object */ - T deserializeUserData(JsonNode node, Type type); + T deserializeUserData(JsonNode node, Type type, SerdeContext ctx); /** * @return the user serde diff --git a/core/src/main/java/com/arangodb/internal/serde/InternalSerdeImpl.java b/core/src/main/java/com/arangodb/internal/serde/InternalSerdeImpl.java index 7340f7073..0c8f5d092 100644 --- a/core/src/main/java/com/arangodb/internal/serde/InternalSerdeImpl.java +++ b/core/src/main/java/com/arangodb/internal/serde/InternalSerdeImpl.java @@ -4,6 +4,7 @@ import com.arangodb.entity.BaseDocument; import com.arangodb.entity.BaseEdgeDocument; import com.arangodb.serde.ArangoSerde; +import com.arangodb.serde.SerdeContext; import com.arangodb.util.RawBytes; import com.arangodb.util.RawJson; import com.fasterxml.jackson.annotation.JsonInclude; @@ -12,13 +13,16 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.Module; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.cfg.ContextAttributes; import java.io.IOException; import java.lang.reflect.Type; import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; import java.util.stream.StreamSupport; +import static com.arangodb.internal.serde.SerdeUtils.SERDE_CONTEXT_ATTRIBUTE_NAME; import static com.arangodb.internal.serde.SerdeUtils.checkSupportedJacksonVersion; final class InternalSerdeImpl implements InternalSerde { @@ -57,7 +61,13 @@ public byte[] serialize(final Object value) { @Override public T deserialize(byte[] content, Class clazz) { - return deserialize(content, (Type) clazz); + throw new IllegalArgumentException("Deserialization without context should never be invoked."); + } + + @Override + public T deserialize(byte[] content, Class clazz, SerdeContext ctx) { + Objects.requireNonNull(ctx); + return deserialize(content, (Type) clazz, ctx); } @Override @@ -120,27 +130,27 @@ public byte[] serializeCollectionUserData(Iterable value) { } @Override - public T deserializeUserData(byte[] content, Class clazz) { + public T deserializeUserData(byte[] content, Class clazz, SerdeContext ctx) { if (isManagedClass(clazz)) { - return deserialize(content, clazz); + return deserialize(content, clazz, SerdeContextImpl.EMPTY); } else { - return userSerde.deserialize(content, clazz); + return userSerde.deserialize(content, clazz, ctx); } } @Override @SuppressWarnings("unchecked") - public T deserializeUserData(byte[] content, Type type) { + public T deserializeUserData(byte[] content, Type type, SerdeContext ctx) { if (type instanceof Class) { - return deserializeUserData(content, (Class) type); + return deserializeUserData(content, (Class) type, ctx); } else { throw new UnsupportedOperationException(); } } @Override - public T deserializeUserData(JsonNode node, Type type) { - return deserializeUserData(serialize(node), type); + public T deserializeUserData(JsonNode node, Type type, SerdeContext ctx) { + return deserializeUserData(serialize(node), type, ctx); } @Override @@ -149,21 +159,25 @@ public ArangoSerde getUserSerde() { } @Override - public T deserialize(final JsonNode node, final Type type) { + public T deserialize(final JsonNode node, final Type type, final SerdeContext ctx) { try { - return mapper.readerFor(mapper.constructType(type)).readValue(node); + return mapper.readerFor(mapper.constructType(type)) + .with(ContextAttributes.getEmpty().withPerCallAttribute(SERDE_CONTEXT_ATTRIBUTE_NAME, ctx)) + .readValue(node); } catch (IOException e) { throw ArangoDBException.of(e); } } @Override - public T deserialize(final byte[] content, final Type type) { + public T deserialize(final byte[] content, final Type type, final SerdeContext ctx) { if (content == null) { return null; } try { - return mapper.readerFor(mapper.constructType(type)).readValue(content); + return mapper.readerFor(mapper.constructType(type)) + .with(ContextAttributes.getEmpty().withPerCallAttribute(SERDE_CONTEXT_ATTRIBUTE_NAME, ctx)) + .readValue(content); } catch (IOException e) { throw ArangoDBException.of(e); } diff --git a/core/src/main/java/com/arangodb/internal/serde/SerdeContextImpl.java b/core/src/main/java/com/arangodb/internal/serde/SerdeContextImpl.java new file mode 100644 index 000000000..0d866407b --- /dev/null +++ b/core/src/main/java/com/arangodb/internal/serde/SerdeContextImpl.java @@ -0,0 +1,17 @@ +package com.arangodb.internal.serde; + +import com.arangodb.serde.SerdeContext; + +public class SerdeContextImpl implements SerdeContext { + public static final SerdeContext EMPTY = new SerdeContextImpl(null); + private final String streamTransactionId; + + public SerdeContextImpl(String streamTransactionId) { + this.streamTransactionId = streamTransactionId; + } + + @Override + public String getStreamTransactionId() { + return streamTransactionId; + } +} diff --git a/core/src/main/java/com/arangodb/internal/serde/SerdeUtils.java b/core/src/main/java/com/arangodb/internal/serde/SerdeUtils.java index 94b0659a6..93d6bedb9 100644 --- a/core/src/main/java/com/arangodb/internal/serde/SerdeUtils.java +++ b/core/src/main/java/com/arangodb/internal/serde/SerdeUtils.java @@ -1,6 +1,10 @@ package com.arangodb.internal.serde; import com.arangodb.ArangoDBException; +import com.arangodb.Request; +import com.arangodb.internal.InternalRequest; +import com.arangodb.model.TransactionalOptions; +import com.arangodb.serde.SerdeContext; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.JsonNode; @@ -17,7 +21,9 @@ public enum SerdeUtils { INSTANCE; + public static final String SERDE_CONTEXT_ATTRIBUTE_NAME = "arangoSerdeContext"; private static final Logger LOGGER = LoggerFactory.getLogger(SerdeUtils.class); + private static final String TRANSACTION_ID = "x-arango-trx-id"; private final ObjectMapper jsonMapper = new ObjectMapper(); @@ -55,6 +61,10 @@ static void checkSupportedJacksonVersion() { }); } + public static SerdeContext createSerdeContext(InternalRequest request) { + return new SerdeContextImpl(request.getHeaderParam().get(TRANSACTION_ID)); + } + /** * Parse a JSON string. * diff --git a/core/src/main/java/com/arangodb/internal/serde/UserDataDeserializer.java b/core/src/main/java/com/arangodb/internal/serde/UserDataDeserializer.java index 91220088b..221658dc2 100644 --- a/core/src/main/java/com/arangodb/internal/serde/UserDataDeserializer.java +++ b/core/src/main/java/com/arangodb/internal/serde/UserDataDeserializer.java @@ -1,5 +1,6 @@ package com.arangodb.internal.serde; +import com.arangodb.serde.SerdeContext; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.BeanProperty; import com.fasterxml.jackson.databind.DeserializationContext; @@ -10,7 +11,9 @@ import java.io.IOException; import java.lang.reflect.Type; +import java.util.Objects; +import static com.arangodb.internal.serde.SerdeUtils.SERDE_CONTEXT_ATTRIBUTE_NAME; import static com.arangodb.internal.serde.SerdeUtils.convertToType; class UserDataDeserializer extends JsonDeserializer implements ContextualDeserializer { @@ -29,7 +32,9 @@ private UserDataDeserializer(final JavaType targetType, final InternalSerde serd @Override public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { - return serde.deserializeUserData(p.readValueAsTree(), targetType); + SerdeContext serdeContext = (SerdeContext) ctxt.getAttribute(SERDE_CONTEXT_ATTRIBUTE_NAME); + Objects.requireNonNull(serdeContext); + return serde.deserializeUserData(p.readValueAsTree(), targetType, serdeContext); } @Override diff --git a/core/src/main/java/com/arangodb/internal/util/ResponseUtils.java b/core/src/main/java/com/arangodb/internal/util/ResponseUtils.java index f664f5986..1220d4887 100644 --- a/core/src/main/java/com/arangodb/internal/util/ResponseUtils.java +++ b/core/src/main/java/com/arangodb/internal/util/ResponseUtils.java @@ -27,6 +27,7 @@ import com.arangodb.internal.net.ArangoDBUnavailableException; import com.arangodb.internal.serde.InternalSerde; import com.arangodb.internal.InternalResponse; +import com.arangodb.internal.serde.SerdeContextImpl; import java.util.concurrent.TimeoutException; @@ -53,7 +54,7 @@ public static ArangoDBException translateError(final InternalSerde util, final I response.getMeta(HEADER_ENDPOINT)); } if (response.getBody() != null) { - final ErrorEntity errorEntity = util.deserialize(response.getBody(), ErrorEntity.class); + final ErrorEntity errorEntity = util.deserialize(response.getBody(), ErrorEntity.class, SerdeContextImpl.EMPTY); if (errorEntity.getCode() == ERROR_INTERNAL && errorEntity.getErrorNum() == ERROR_INTERNAL) { return ArangoDBUnavailableException.from(errorEntity); } diff --git a/core/src/main/java/com/arangodb/model/AqlQueryOptions.java b/core/src/main/java/com/arangodb/model/AqlQueryOptions.java index 06162c9c7..91c551d14 100644 --- a/core/src/main/java/com/arangodb/model/AqlQueryOptions.java +++ b/core/src/main/java/com/arangodb/model/AqlQueryOptions.java @@ -28,7 +28,7 @@ * @author Mark Vollmary * @author Michele Rastelli */ -public final class AqlQueryOptions implements Cloneable { +public final class AqlQueryOptions extends TransactionalOptions implements Cloneable { private Boolean count; private Integer ttl; @@ -39,7 +39,11 @@ public final class AqlQueryOptions implements Cloneable { private String query; private Options options; private Boolean allowDirtyRead; - private String streamTransactionId; + + @Override + AqlQueryOptions getThis() { + return this; + } public Boolean getCount() { return count; @@ -469,20 +473,6 @@ public Boolean getAllowDirtyRead() { return allowDirtyRead; } - public String getStreamTransactionId() { - return streamTransactionId; - } - - /** - * @param streamTransactionId If set, the operation will be executed within the transaction. - * @return options - * @since ArangoDB 3.5.0 - */ - public AqlQueryOptions streamTransactionId(final String streamTransactionId) { - this.streamTransactionId = streamTransactionId; - return this; - } - public Boolean getAllowRetry() { return getOptions().allowRetry; } diff --git a/core/src/main/java/com/arangodb/model/CollectionCountOptions.java b/core/src/main/java/com/arangodb/model/CollectionCountOptions.java index edfc64eaa..0c3d2f6f6 100644 --- a/core/src/main/java/com/arangodb/model/CollectionCountOptions.java +++ b/core/src/main/java/com/arangodb/model/CollectionCountOptions.java @@ -23,25 +23,10 @@ /** * @author Michele Rastelli */ -public final class CollectionCountOptions { +public final class CollectionCountOptions extends TransactionalOptions { - private String streamTransactionId; - - public CollectionCountOptions() { - super(); - } - - public String getStreamTransactionId() { - return streamTransactionId; - } - - /** - * @param streamTransactionId If set, the operation will be executed within the transaction. - * @return options - * @since ArangoDB 3.5.0 - */ - public CollectionCountOptions streamTransactionId(final String streamTransactionId) { - this.streamTransactionId = streamTransactionId; + @Override + CollectionCountOptions getThis() { return this; } diff --git a/core/src/main/java/com/arangodb/model/CollectionTruncateOptions.java b/core/src/main/java/com/arangodb/model/CollectionTruncateOptions.java index 1b089533e..f95012ac1 100644 --- a/core/src/main/java/com/arangodb/model/CollectionTruncateOptions.java +++ b/core/src/main/java/com/arangodb/model/CollectionTruncateOptions.java @@ -23,25 +23,10 @@ /** * @author Michele Rastelli */ -public final class CollectionTruncateOptions { +public final class CollectionTruncateOptions extends TransactionalOptions { - private String streamTransactionId; - - public CollectionTruncateOptions() { - super(); - } - - public String getStreamTransactionId() { - return streamTransactionId; - } - - /** - * @param streamTransactionId If set, the operation will be executed within the transaction. - * @return options - * @since ArangoDB 3.5.0 - */ - public CollectionTruncateOptions streamTransactionId(final String streamTransactionId) { - this.streamTransactionId = streamTransactionId; + @Override + CollectionTruncateOptions getThis() { return this; } diff --git a/core/src/main/java/com/arangodb/model/DocumentCreateOptions.java b/core/src/main/java/com/arangodb/model/DocumentCreateOptions.java index 6753755b4..31217673b 100644 --- a/core/src/main/java/com/arangodb/model/DocumentCreateOptions.java +++ b/core/src/main/java/com/arangodb/model/DocumentCreateOptions.java @@ -24,21 +24,21 @@ * @author Mark Vollmary * @author Michele Rastelli */ -public final class DocumentCreateOptions { +public final class DocumentCreateOptions extends TransactionalOptions { private Boolean waitForSync; private Boolean returnNew; private Boolean returnOld; private OverwriteMode overwriteMode; private Boolean silent; - private String streamTransactionId; private Boolean mergeObjects; private Boolean keepNull; private Boolean refillIndexCaches; private String versionAttribute; - public DocumentCreateOptions() { - super(); + @Override + DocumentCreateOptions getThis() { + return this; } public Boolean getWaitForSync() { @@ -111,20 +111,6 @@ public DocumentCreateOptions silent(final Boolean silent) { return this; } - public String getStreamTransactionId() { - return streamTransactionId; - } - - /** - * @param streamTransactionId If set, the operation will be executed within the transaction. - * @return options - * @since ArangoDB 3.5.0 - */ - public DocumentCreateOptions streamTransactionId(final String streamTransactionId) { - this.streamTransactionId = streamTransactionId; - return this; - } - public Boolean getMergeObjects() { return mergeObjects; } diff --git a/core/src/main/java/com/arangodb/model/DocumentDeleteOptions.java b/core/src/main/java/com/arangodb/model/DocumentDeleteOptions.java index c69af6444..28259d657 100644 --- a/core/src/main/java/com/arangodb/model/DocumentDeleteOptions.java +++ b/core/src/main/java/com/arangodb/model/DocumentDeleteOptions.java @@ -24,17 +24,17 @@ * @author Mark Vollmary * @author Michele Rastelli */ -public final class DocumentDeleteOptions { +public final class DocumentDeleteOptions extends TransactionalOptions { private Boolean waitForSync; private String ifMatch; private Boolean returnOld; private Boolean silent; - private String streamTransactionId; private Boolean refillIndexCaches; - public DocumentDeleteOptions() { - super(); + @Override + DocumentDeleteOptions getThis() { + return this; } public Boolean getWaitForSync() { @@ -92,20 +92,6 @@ public DocumentDeleteOptions silent(final Boolean silent) { return this; } - public String getStreamTransactionId() { - return streamTransactionId; - } - - /** - * @param streamTransactionId If set, the operation will be executed within the transaction. - * @return options - * @since ArangoDB 3.5.0 - */ - public DocumentDeleteOptions streamTransactionId(final String streamTransactionId) { - this.streamTransactionId = streamTransactionId; - return this; - } - public Boolean getRefillIndexCaches() { return refillIndexCaches; } diff --git a/core/src/main/java/com/arangodb/model/DocumentExistsOptions.java b/core/src/main/java/com/arangodb/model/DocumentExistsOptions.java index 6fc4166d8..03c533017 100644 --- a/core/src/main/java/com/arangodb/model/DocumentExistsOptions.java +++ b/core/src/main/java/com/arangodb/model/DocumentExistsOptions.java @@ -24,14 +24,14 @@ * @author Mark Vollmary * @author Michele Rastelli */ -public final class DocumentExistsOptions { +public final class DocumentExistsOptions extends TransactionalOptions { private String ifNoneMatch; private String ifMatch; - private String streamTransactionId; - public DocumentExistsOptions() { - super(); + @Override + DocumentExistsOptions getThis() { + return this; } public String getIfNoneMatch() { @@ -60,18 +60,4 @@ public DocumentExistsOptions ifMatch(final String ifMatch) { return this; } - public String getStreamTransactionId() { - return streamTransactionId; - } - - /** - * @param streamTransactionId If set, the operation will be executed within the transaction. - * @return options - * @since ArangoDB 3.5.0 - */ - public DocumentExistsOptions streamTransactionId(final String streamTransactionId) { - this.streamTransactionId = streamTransactionId; - return this; - } - } diff --git a/core/src/main/java/com/arangodb/model/DocumentReadOptions.java b/core/src/main/java/com/arangodb/model/DocumentReadOptions.java index 9ae476a35..74b976aae 100644 --- a/core/src/main/java/com/arangodb/model/DocumentReadOptions.java +++ b/core/src/main/java/com/arangodb/model/DocumentReadOptions.java @@ -24,15 +24,15 @@ * @author Mark Vollmary * @author Michele Rastelli */ -public final class DocumentReadOptions { +public final class DocumentReadOptions extends TransactionalOptions { private String ifNoneMatch; private String ifMatch; private Boolean allowDirtyRead; - private String streamTransactionId; - public DocumentReadOptions() { - super(); + @Override + DocumentReadOptions getThis() { + return this; } public String getIfNoneMatch() { @@ -77,18 +77,4 @@ public Boolean getAllowDirtyRead() { return allowDirtyRead; } - public String getStreamTransactionId() { - return streamTransactionId; - } - - /** - * @param streamTransactionId If set, the operation will be executed within the transaction. - * @return options - * @since ArangoDB 3.5.0 - */ - public DocumentReadOptions streamTransactionId(final String streamTransactionId) { - this.streamTransactionId = streamTransactionId; - return this; - } - } diff --git a/core/src/main/java/com/arangodb/model/DocumentReplaceOptions.java b/core/src/main/java/com/arangodb/model/DocumentReplaceOptions.java index 5812a98c4..f24d7fe13 100644 --- a/core/src/main/java/com/arangodb/model/DocumentReplaceOptions.java +++ b/core/src/main/java/com/arangodb/model/DocumentReplaceOptions.java @@ -24,7 +24,7 @@ * @author Mark Vollmary * @author Michele Rastelli */ -public final class DocumentReplaceOptions { +public final class DocumentReplaceOptions extends TransactionalOptions { private Boolean waitForSync; private Boolean ignoreRevs; @@ -32,12 +32,12 @@ public final class DocumentReplaceOptions { private Boolean returnNew; private Boolean returnOld; private Boolean silent; - private String streamTransactionId; private Boolean refillIndexCaches; private String versionAttribute; - public DocumentReplaceOptions() { - super(); + @Override + DocumentReplaceOptions getThis() { + return this; } public Boolean getWaitForSync() { @@ -125,20 +125,6 @@ public DocumentReplaceOptions silent(final Boolean silent) { return this; } - public String getStreamTransactionId() { - return streamTransactionId; - } - - /** - * @param streamTransactionId If set, the operation will be executed within the transaction. - * @return options - * @since ArangoDB 3.5.0 - */ - public DocumentReplaceOptions streamTransactionId(final String streamTransactionId) { - this.streamTransactionId = streamTransactionId; - return this; - } - public Boolean getRefillIndexCaches() { return refillIndexCaches; } diff --git a/core/src/main/java/com/arangodb/model/DocumentUpdateOptions.java b/core/src/main/java/com/arangodb/model/DocumentUpdateOptions.java index bdb002a06..9987e20f8 100644 --- a/core/src/main/java/com/arangodb/model/DocumentUpdateOptions.java +++ b/core/src/main/java/com/arangodb/model/DocumentUpdateOptions.java @@ -24,7 +24,7 @@ * @author Mark Vollmary * @author Michele Rastelli */ -public final class DocumentUpdateOptions { +public final class DocumentUpdateOptions extends TransactionalOptions { private Boolean keepNull; private Boolean mergeObjects; @@ -34,12 +34,12 @@ public final class DocumentUpdateOptions { private Boolean returnNew; private Boolean returnOld; private Boolean silent; - private String streamTransactionId; private Boolean refillIndexCaches; private String versionAttribute; - public DocumentUpdateOptions() { - super(); + @Override + DocumentUpdateOptions getThis() { + return this; } public Boolean getKeepNull() { @@ -160,20 +160,6 @@ public DocumentUpdateOptions silent(final Boolean silent) { return this; } - public String getStreamTransactionId() { - return streamTransactionId; - } - - /** - * @param streamTransactionId If set, the operation will be executed within the transaction. - * @return options - * @since ArangoDB 3.5.0 - */ - public DocumentUpdateOptions streamTransactionId(final String streamTransactionId) { - this.streamTransactionId = streamTransactionId; - return this; - } - public Boolean getRefillIndexCaches() { return refillIndexCaches; } diff --git a/core/src/main/java/com/arangodb/model/EdgeCreateOptions.java b/core/src/main/java/com/arangodb/model/EdgeCreateOptions.java index 1410feb59..5523a7dab 100644 --- a/core/src/main/java/com/arangodb/model/EdgeCreateOptions.java +++ b/core/src/main/java/com/arangodb/model/EdgeCreateOptions.java @@ -23,13 +23,13 @@ /** * @author Mark Vollmary */ -public final class EdgeCreateOptions { +public final class EdgeCreateOptions extends TransactionalOptions { private Boolean waitForSync; - private String streamTransactionId; - public EdgeCreateOptions() { - super(); + @Override + EdgeCreateOptions getThis() { + return this; } public Boolean getWaitForSync() { @@ -45,18 +45,4 @@ public EdgeCreateOptions waitForSync(final Boolean waitForSync) { return this; } - public String getStreamTransactionId() { - return streamTransactionId; - } - - /** - * @param streamTransactionId If set, the operation will be executed within the transaction. - * @return options - * @since ArangoDB 3.5.1 - */ - public EdgeCreateOptions streamTransactionId(final String streamTransactionId) { - this.streamTransactionId = streamTransactionId; - return this; - } - } diff --git a/core/src/main/java/com/arangodb/model/EdgeDeleteOptions.java b/core/src/main/java/com/arangodb/model/EdgeDeleteOptions.java index ec1d19efd..25d7fab4f 100644 --- a/core/src/main/java/com/arangodb/model/EdgeDeleteOptions.java +++ b/core/src/main/java/com/arangodb/model/EdgeDeleteOptions.java @@ -23,14 +23,14 @@ /** * @author Mark Vollmary */ -public final class EdgeDeleteOptions { +public final class EdgeDeleteOptions extends TransactionalOptions { private Boolean waitForSync; private String ifMatch; - private String streamTransactionId; - public EdgeDeleteOptions() { - super(); + @Override + EdgeDeleteOptions getThis() { + return this; } public Boolean getWaitForSync() { @@ -59,18 +59,4 @@ public EdgeDeleteOptions ifMatch(final String ifMatch) { return this; } - public String getStreamTransactionId() { - return streamTransactionId; - } - - /** - * @param streamTransactionId If set, the operation will be executed within the transaction. - * @return options - * @since ArangoDB 3.5.1 - */ - public EdgeDeleteOptions streamTransactionId(final String streamTransactionId) { - this.streamTransactionId = streamTransactionId; - return this; - } - } diff --git a/core/src/main/java/com/arangodb/model/EdgeReplaceOptions.java b/core/src/main/java/com/arangodb/model/EdgeReplaceOptions.java index a2367d820..7e298d963 100644 --- a/core/src/main/java/com/arangodb/model/EdgeReplaceOptions.java +++ b/core/src/main/java/com/arangodb/model/EdgeReplaceOptions.java @@ -23,14 +23,14 @@ /** * @author Mark Vollmary */ -public final class EdgeReplaceOptions { +public final class EdgeReplaceOptions extends TransactionalOptions { private Boolean waitForSync; private String ifMatch; - private String streamTransactionId; - public EdgeReplaceOptions() { - super(); + @Override + EdgeReplaceOptions getThis() { + return this; } public Boolean getWaitForSync() { @@ -59,18 +59,4 @@ public EdgeReplaceOptions ifMatch(final String ifMatch) { return this; } - public String getStreamTransactionId() { - return streamTransactionId; - } - - /** - * @param streamTransactionId If set, the operation will be executed within the transaction. - * @return options - * @since ArangoDB 3.5.1 - */ - public EdgeReplaceOptions streamTransactionId(final String streamTransactionId) { - this.streamTransactionId = streamTransactionId; - return this; - } - } diff --git a/core/src/main/java/com/arangodb/model/EdgeUpdateOptions.java b/core/src/main/java/com/arangodb/model/EdgeUpdateOptions.java index f4f4aaec6..03b2e00a1 100644 --- a/core/src/main/java/com/arangodb/model/EdgeUpdateOptions.java +++ b/core/src/main/java/com/arangodb/model/EdgeUpdateOptions.java @@ -23,15 +23,15 @@ /** * @author Mark Vollmary */ -public final class EdgeUpdateOptions { +public final class EdgeUpdateOptions extends TransactionalOptions { private Boolean keepNull; private Boolean waitForSync; private String ifMatch; - private String streamTransactionId; - public EdgeUpdateOptions() { - super(); + @Override + EdgeUpdateOptions getThis() { + return this; } public Boolean getKeepNull() { @@ -76,18 +76,4 @@ public EdgeUpdateOptions ifMatch(final String ifMatch) { return this; } - public String getStreamTransactionId() { - return streamTransactionId; - } - - /** - * @param streamTransactionId If set, the operation will be executed within the transaction. - * @return options - * @since ArangoDB 3.5.1 - */ - public EdgeUpdateOptions streamTransactionId(final String streamTransactionId) { - this.streamTransactionId = streamTransactionId; - return this; - } - } diff --git a/core/src/main/java/com/arangodb/model/GraphDocumentReadOptions.java b/core/src/main/java/com/arangodb/model/GraphDocumentReadOptions.java index 1368a6cd2..d68cdba7a 100644 --- a/core/src/main/java/com/arangodb/model/GraphDocumentReadOptions.java +++ b/core/src/main/java/com/arangodb/model/GraphDocumentReadOptions.java @@ -23,15 +23,15 @@ /** * @author Mark Vollmary */ -public final class GraphDocumentReadOptions { +public final class GraphDocumentReadOptions extends TransactionalOptions { private String ifNoneMatch; private String ifMatch; private Boolean allowDirtyRead; - private String streamTransactionId; - public GraphDocumentReadOptions() { - super(); + @Override + GraphDocumentReadOptions getThis() { + return this; } public String getIfNoneMatch() { @@ -76,18 +76,4 @@ public Boolean getAllowDirtyRead() { return allowDirtyRead; } - public String getStreamTransactionId() { - return streamTransactionId; - } - - /** - * @param streamTransactionId If set, the operation will be executed within the transaction. - * @return options - * @since ArangoDB 3.5.1 - */ - public GraphDocumentReadOptions streamTransactionId(final String streamTransactionId) { - this.streamTransactionId = streamTransactionId; - return this; - } - } diff --git a/core/src/main/java/com/arangodb/model/TransactionalOptions.java b/core/src/main/java/com/arangodb/model/TransactionalOptions.java new file mode 100644 index 000000000..c4a564c68 --- /dev/null +++ b/core/src/main/java/com/arangodb/model/TransactionalOptions.java @@ -0,0 +1,25 @@ +package com.arangodb.model; + +import com.arangodb.arch.NoRawTypesInspection; + +@NoRawTypesInspection +public abstract class TransactionalOptions> { + + abstract T getThis(); + + private String streamTransactionId; + + public String getStreamTransactionId() { + return streamTransactionId; + } + + /** + * @param streamTransactionId If set, the operation will be executed within the transaction. + * @return options + */ + public T streamTransactionId(final String streamTransactionId) { + this.streamTransactionId = streamTransactionId; + return getThis(); + } + +} diff --git a/core/src/main/java/com/arangodb/model/VertexCreateOptions.java b/core/src/main/java/com/arangodb/model/VertexCreateOptions.java index 2ac6998b5..36cd2395b 100644 --- a/core/src/main/java/com/arangodb/model/VertexCreateOptions.java +++ b/core/src/main/java/com/arangodb/model/VertexCreateOptions.java @@ -23,13 +23,13 @@ /** * @author Mark Vollmary */ -public final class VertexCreateOptions { +public final class VertexCreateOptions extends TransactionalOptions { private Boolean waitForSync; - private String streamTransactionId; - public VertexCreateOptions() { - super(); + @Override + VertexCreateOptions getThis() { + return this; } public Boolean getWaitForSync() { @@ -45,18 +45,4 @@ public VertexCreateOptions waitForSync(final Boolean waitForSync) { return this; } - public String getStreamTransactionId() { - return streamTransactionId; - } - - /** - * @param streamTransactionId If set, the operation will be executed within the transaction. - * @return options - * @since ArangoDB 3.5.1 - */ - public VertexCreateOptions streamTransactionId(final String streamTransactionId) { - this.streamTransactionId = streamTransactionId; - return this; - } - } diff --git a/core/src/main/java/com/arangodb/model/VertexDeleteOptions.java b/core/src/main/java/com/arangodb/model/VertexDeleteOptions.java index 9d7a25705..82fba23aa 100644 --- a/core/src/main/java/com/arangodb/model/VertexDeleteOptions.java +++ b/core/src/main/java/com/arangodb/model/VertexDeleteOptions.java @@ -23,14 +23,14 @@ /** * @author Mark Vollmary */ -public final class VertexDeleteOptions { +public final class VertexDeleteOptions extends TransactionalOptions { private Boolean waitForSync; private String ifMatch; - private String streamTransactionId; - public VertexDeleteOptions() { - super(); + @Override + VertexDeleteOptions getThis() { + return this; } public Boolean getWaitForSync() { @@ -59,18 +59,4 @@ public VertexDeleteOptions ifMatch(final String ifMatch) { return this; } - public String getStreamTransactionId() { - return streamTransactionId; - } - - /** - * @param streamTransactionId If set, the operation will be executed within the transaction. - * @return options - * @since ArangoDB 3.5.1 - */ - public VertexDeleteOptions streamTransactionId(final String streamTransactionId) { - this.streamTransactionId = streamTransactionId; - return this; - } - } diff --git a/core/src/main/java/com/arangodb/model/VertexReplaceOptions.java b/core/src/main/java/com/arangodb/model/VertexReplaceOptions.java index af72037fb..6d4dd12ea 100644 --- a/core/src/main/java/com/arangodb/model/VertexReplaceOptions.java +++ b/core/src/main/java/com/arangodb/model/VertexReplaceOptions.java @@ -23,14 +23,14 @@ /** * @author Mark Vollmary */ -public final class VertexReplaceOptions { +public final class VertexReplaceOptions extends TransactionalOptions { private Boolean waitForSync; private String ifMatch; - private String streamTransactionId; - public VertexReplaceOptions() { - super(); + @Override + VertexReplaceOptions getThis() { + return this; } public Boolean getWaitForSync() { @@ -59,18 +59,4 @@ public VertexReplaceOptions ifMatch(final String ifMatch) { return this; } - public String getStreamTransactionId() { - return streamTransactionId; - } - - /** - * @param streamTransactionId If set, the operation will be executed within the transaction. - * @return options - * @since ArangoDB 3.5.1 - */ - public VertexReplaceOptions streamTransactionId(final String streamTransactionId) { - this.streamTransactionId = streamTransactionId; - return this; - } - } diff --git a/core/src/main/java/com/arangodb/model/VertexUpdateOptions.java b/core/src/main/java/com/arangodb/model/VertexUpdateOptions.java index 34638bd02..f1d0e5bf7 100644 --- a/core/src/main/java/com/arangodb/model/VertexUpdateOptions.java +++ b/core/src/main/java/com/arangodb/model/VertexUpdateOptions.java @@ -23,15 +23,15 @@ /** * @author Mark Vollmary */ -public final class VertexUpdateOptions { +public final class VertexUpdateOptions extends TransactionalOptions { private Boolean keepNull; private Boolean waitForSync; private String ifMatch; - private String streamTransactionId; - public VertexUpdateOptions() { - super(); + @Override + VertexUpdateOptions getThis() { + return this; } public Boolean getKeepNull() { @@ -76,17 +76,4 @@ public VertexUpdateOptions ifMatch(final String ifMatch) { return this; } - public String getStreamTransactionId() { - return streamTransactionId; - } - - /** - * @param streamTransactionId If set, the operation will be executed within the transaction. - * @return options - * @since ArangoDB 3.5.1 - */ - public VertexUpdateOptions streamTransactionId(final String streamTransactionId) { - this.streamTransactionId = streamTransactionId; - return this; - } } diff --git a/core/src/main/java/com/arangodb/serde/ArangoSerde.java b/core/src/main/java/com/arangodb/serde/ArangoSerde.java index 9e15ce097..bec68395a 100644 --- a/core/src/main/java/com/arangodb/serde/ArangoSerde.java +++ b/core/src/main/java/com/arangodb/serde/ArangoSerde.java @@ -2,6 +2,8 @@ import com.arangodb.ContentType; +import java.util.Objects; + /** * Contract for serialization/deserialization of user data. * Implementations of this interface could be used for customizing serialization/deserialization of user related data @@ -32,4 +34,17 @@ public interface ArangoSerde { */ T deserialize(byte[] content, Class clazz); + /** + * Deserializes the content and binds it to the target data type. + * For data type {@link ContentType#JSON}, the byte array is the JSON string encoded using the UTF-8 charset. + * + * @param content byte array to deserialize + * @param clazz class of target data type + * @param ctx serde context, cannot be null + * @return deserialized object + */ + default T deserialize(byte[] content, Class clazz, SerdeContext ctx) { + Objects.requireNonNull(ctx); + return deserialize(content, clazz); + } } diff --git a/core/src/main/java/com/arangodb/serde/SerdeContext.java b/core/src/main/java/com/arangodb/serde/SerdeContext.java new file mode 100644 index 000000000..2f4a4a99a --- /dev/null +++ b/core/src/main/java/com/arangodb/serde/SerdeContext.java @@ -0,0 +1,11 @@ +package com.arangodb.serde; + +/** + * Context holding information about the current request and response. + */ +public interface SerdeContext { + /** + * @return the stream transaction id of the request (if any) or {@code null} + */ + String getStreamTransactionId(); +} diff --git a/driver/src/test/java/com/arangodb/ArangoCollectionAsyncTest.java b/driver/src/test/java/com/arangodb/ArangoCollectionAsyncTest.java index e715418fa..562b1b605 100644 --- a/driver/src/test/java/com/arangodb/ArangoCollectionAsyncTest.java +++ b/driver/src/test/java/com/arangodb/ArangoCollectionAsyncTest.java @@ -21,6 +21,7 @@ package com.arangodb; import com.arangodb.entity.*; +import com.arangodb.internal.serde.SerdeContextImpl; import com.arangodb.internal.serde.SerdeUtils; import com.arangodb.model.*; import com.arangodb.model.DocumentImportOptions.OnDuplicate; @@ -557,7 +558,7 @@ void insertDocumentAsBytes(ArangoCollectionAsync collection) throws ExecutionExc assertThat(createEntity.getRev()).isNotNull(); assertThat(createEntity.getNew()).isNotNull().isInstanceOf(RawBytes.class); Map newDoc = collection.getSerde().deserializeUserData(createEntity.getNew().get(), - Map.class); + Map.class, SerdeContextImpl.EMPTY); assertThat(newDoc).containsAllEntriesOf(doc); } diff --git a/driver/src/test/java/com/arangodb/ArangoCollectionTest.java b/driver/src/test/java/com/arangodb/ArangoCollectionTest.java index 99f54c43c..cb6f9dc6e 100644 --- a/driver/src/test/java/com/arangodb/ArangoCollectionTest.java +++ b/driver/src/test/java/com/arangodb/ArangoCollectionTest.java @@ -21,6 +21,7 @@ package com.arangodb; import com.arangodb.entity.*; +import com.arangodb.internal.serde.SerdeContextImpl; import com.arangodb.internal.serde.SerdeUtils; import com.arangodb.model.*; import com.arangodb.model.DocumentImportOptions.OnDuplicate; @@ -561,7 +562,7 @@ void insertDocumentAsBytes(ArangoCollection collection) { assertThat(createEntity.getRev()).isNotNull(); assertThat(createEntity.getNew()).isNotNull().isInstanceOf(RawBytes.class); Map newDoc = collection.getSerde().deserializeUserData(createEntity.getNew().get(), - Map.class); + Map.class, SerdeContextImpl.EMPTY); assertThat(newDoc).containsAllEntriesOf(doc); } diff --git a/driver/src/test/java/com/arangodb/BaseJunit5.java b/driver/src/test/java/com/arangodb/BaseJunit5.java index 800c45e55..230b6ab87 100644 --- a/driver/src/test/java/com/arangodb/BaseJunit5.java +++ b/driver/src/test/java/com/arangodb/BaseJunit5.java @@ -19,8 +19,9 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import static com.arangodb.util.TestUtils.TEST_DB; + public class BaseJunit5 { - private static final String TEST_DB = "java_driver_test_db"; protected static final ArangoConfigProperties config = ConfigUtils.loadConfig(); private static final ArangoDB adb = new ArangoDB.Builder() .loadProperties(config) diff --git a/driver/src/test/java/com/arangodb/JacksonSerdeContextTest.java b/driver/src/test/java/com/arangodb/JacksonSerdeContextTest.java new file mode 100644 index 000000000..f68b67da9 --- /dev/null +++ b/driver/src/test/java/com/arangodb/JacksonSerdeContextTest.java @@ -0,0 +1,121 @@ +/* + * DISCLAIMER + * + * Copyright 2016 ArangoDB GmbH, Cologne, Germany + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright holder is ArangoDB GmbH, Cologne, Germany + */ + +package com.arangodb; + +import com.arangodb.config.ConfigUtils; +import com.arangodb.entity.BaseDocument; +import com.arangodb.entity.DocumentCreateEntity; +import com.arangodb.entity.StreamTransactionEntity; +import com.arangodb.model.DocumentReadOptions; +import com.arangodb.model.StreamTransactionOptions; +import com.arangodb.serde.jackson.JacksonSerde; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.module.SimpleModule; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.Collections; + +import static com.arangodb.util.TestUtils.TEST_DB; +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Michele Rastelli + */ +class JacksonSerdeContextTest { + + private static final String COLLECTION_NAME = "JacksonSerdeContextTest_collection"; + + private static ArangoDB arangoDB; + private static ArangoDatabase db; + private static ArangoCollection collection; + + @BeforeAll + static void init() { + JacksonSerde serde = JacksonSerde.of(ContentType.JSON) + .configure((mapper) -> { + SimpleModule module = new SimpleModule("PersonModule"); + module.addDeserializer(Person.class, new PersonDeserializer()); + mapper.registerModule(module); + }); + arangoDB = new ArangoDB.Builder() + .loadProperties(ConfigUtils.loadConfig()) + .serde(serde).build(); + + db = arangoDB.db(TEST_DB); + if (!db.exists()) { + db.create(); + } + + collection = db.collection(COLLECTION_NAME); + if (!collection.exists()) { + collection.create(); + } + } + + @AfterAll + static void shutdown() { + if (db.exists()) + db.drop(); + } + + static class PersonDeserializer extends JsonDeserializer { + @Override + public Person deserialize(JsonParser parser, DeserializationContext ctx) throws IOException { + JsonNode rootNode = parser.getCodec().readTree(parser); + Person person = new Person(rootNode.get("name").asText()); + person.txId = JacksonSerde.getSerdeContext(ctx).getStreamTransactionId(); + return person; + } + } + + static class Person { + String name; + String txId; + + Person(String name) { + this.name = name; + } + } + + @Test + void getDocumentWithinTx() { + DocumentCreateEntity doc = collection.insertDocument( + new BaseDocument(Collections.singletonMap("name", "foo")), null); + + StreamTransactionEntity tx = db + .beginStreamTransaction(new StreamTransactionOptions().readCollections(COLLECTION_NAME)); + + Person read = collection.getDocument(doc.getKey(), Person.class, + new DocumentReadOptions().streamTransactionId(tx.getId())); + + assertThat(read.name).isEqualTo("foo"); + assertThat(read.txId).isEqualTo(tx.getId()); + + db.abortStreamTransaction(tx.getId()); + } + +} diff --git a/driver/src/test/java/com/arangodb/SerdeContextTest.java b/driver/src/test/java/com/arangodb/SerdeContextTest.java new file mode 100644 index 000000000..d056a2d40 --- /dev/null +++ b/driver/src/test/java/com/arangodb/SerdeContextTest.java @@ -0,0 +1,137 @@ +/* + * DISCLAIMER + * + * Copyright 2016 ArangoDB GmbH, Cologne, Germany + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright holder is ArangoDB GmbH, Cologne, Germany + */ + +package com.arangodb; + +import com.arangodb.config.ConfigUtils; +import com.arangodb.entity.BaseDocument; +import com.arangodb.entity.DocumentCreateEntity; +import com.arangodb.entity.StreamTransactionEntity; +import com.arangodb.model.DocumentReadOptions; +import com.arangodb.model.StreamTransactionOptions; +import com.arangodb.serde.ArangoSerde; +import com.arangodb.serde.SerdeContext; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.Collections; +import java.util.Objects; + +import static com.arangodb.util.TestUtils.TEST_DB; +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Michele Rastelli + */ +class SerdeContextTest { + + private static final String COLLECTION_NAME = "SerdeContextTest_collection"; + + private static ArangoDB arangoDB; + private static ArangoDatabase db; + private static ArangoCollection collection; + + @BeforeAll + static void init() { + ArangoSerde serde = new ArangoSerde() { + private ObjectMapper mapper = new ObjectMapper() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + @Override + public byte[] serialize(Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public T deserialize(byte[] content, Class clazz) { + throw new UnsupportedOperationException(); + } + + @Override + public T deserialize(byte[] content, Class clazz, SerdeContext ctx) { + Objects.requireNonNull(ctx); + + if (clazz != Person.class) { + throw new UnsupportedOperationException(); + } + + try { + Person res = mapper.readValue(content, Person.class); + res.txId = ctx.getStreamTransactionId(); + return (T) res; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + }; + + arangoDB = new ArangoDB.Builder() + .loadProperties(ConfigUtils.loadConfig()) + .serde(serde).build(); + + db = arangoDB.db(TEST_DB); + if (!db.exists()) { + db.create(); + } + + collection = db.collection(COLLECTION_NAME); + if (!collection.exists()) { + collection.create(); + } + } + + @AfterAll + static void shutdown() { + if (db.exists()) + db.drop(); + } + + static class Person { + String name; + String txId; + + Person(@JsonProperty("name") String name) { + this.name = name; + } + } + + @Test + void getDocumentWithinTx() { + DocumentCreateEntity doc = collection.insertDocument( + new BaseDocument(Collections.singletonMap("name", "foo")), null); + + StreamTransactionEntity tx = db + .beginStreamTransaction(new StreamTransactionOptions().readCollections(COLLECTION_NAME)); + + Person read = collection.getDocument(doc.getKey(), Person.class, + new DocumentReadOptions().streamTransactionId(tx.getId())); + + assertThat(read.name).isEqualTo("foo"); + assertThat(read.txId).isEqualTo(tx.getId()); + + db.abortStreamTransaction(tx.getId()); + } + +} diff --git a/driver/src/test/java/com/arangodb/StreamTransactionAsyncTest.java b/driver/src/test/java/com/arangodb/StreamTransactionAsyncTest.java index 8bfe3bcb2..5c28f8b40 100644 --- a/driver/src/test/java/com/arangodb/StreamTransactionAsyncTest.java +++ b/driver/src/test/java/com/arangodb/StreamTransactionAsyncTest.java @@ -470,7 +470,7 @@ void updateDocument(ArangoDatabaseAsync db) throws ExecutionException, Interrupt // update document from within the tx doc.updateAttribute("test", "bar"); collection - .updateDocument(createdDoc.getKey(), doc, new DocumentUpdateOptions().streamTransactionId(tx.getId())); + .updateDocument(createdDoc.getKey(), doc, new DocumentUpdateOptions().streamTransactionId(tx.getId())).get(); // assert that the document has not been updated from outside the tx assertThat(collection.getDocument(createdDoc.getKey(), BaseDocument.class, null).get() @@ -478,8 +478,7 @@ void updateDocument(ArangoDatabaseAsync db) throws ExecutionException, Interrupt // assert that the document has been updated from within the tx assertThat(collection.getDocument(createdDoc.getKey(), BaseDocument.class, - new DocumentReadOptions().streamTransactionId(tx.getId())).get().getProperties()).containsEntry("test", "bar") - ; + new DocumentReadOptions().streamTransactionId(tx.getId())).get().getProperties()).containsEntry("test", "bar"); db.commitStreamTransaction(tx.getId()).get(); diff --git a/driver/src/test/java/com/arangodb/example/document/GetDocumentExampleTest.java b/driver/src/test/java/com/arangodb/example/document/GetDocumentExampleTest.java index 8d220faab..520cd9a6e 100644 --- a/driver/src/test/java/com/arangodb/example/document/GetDocumentExampleTest.java +++ b/driver/src/test/java/com/arangodb/example/document/GetDocumentExampleTest.java @@ -22,6 +22,7 @@ import com.arangodb.entity.BaseDocument; import com.arangodb.example.ExampleBase; +import com.arangodb.internal.serde.SerdeContextImpl; import com.arangodb.util.RawBytes; import com.arangodb.util.RawJson; import com.fasterxml.jackson.databind.JsonNode; @@ -91,7 +92,7 @@ void getAsJson() { void getAsBytes() { final RawBytes doc = collection.getDocument(key, RawBytes.class); assertThat(doc.get()).isNotNull(); - Map mapDoc = collection.getSerde().deserializeUserData(doc.get(), Map.class); + Map mapDoc = collection.getSerde().deserializeUserData(doc.get(), Map.class, SerdeContextImpl.EMPTY); assertThat(mapDoc).containsEntry("foo", "bar"); } diff --git a/driver/src/test/java/com/arangodb/example/ssl/SslExampleTest.java b/driver/src/test/java/com/arangodb/example/ssl/SslExampleTest.java index ed2341cba..4fae3abe6 100644 --- a/driver/src/test/java/com/arangodb/example/ssl/SslExampleTest.java +++ b/driver/src/test/java/com/arangodb/example/ssl/SslExampleTest.java @@ -25,12 +25,17 @@ import com.arangodb.ArangoDBMultipleException; import com.arangodb.Protocol; import com.arangodb.entity.ArangoDBVersion; +import com.arangodb.util.TestUtils; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.condition.EnabledIfSystemProperty; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EnumSource; -import javax.net.ssl.*; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.TrustManagerFactory; import java.security.KeyStore; import java.util.List; @@ -57,10 +62,24 @@ class SslExampleTest { */ private static final String SSL_TRUSTSTORE = "/example.truststore"; private static final String SSL_TRUSTSTORE_PASSWORD = "12345678"; + private static ArangoDBVersion version; + + @BeforeAll + static void fetchVersion() throws Exception { + ArangoDB adb = new ArangoDB.Builder() + .host("localhost", 8529) + .password("test") + .useSsl(true) + .sslContext(createSslContext()) + .build(); + version = adb.getVersion(); + adb.shutdown(); + } @ParameterizedTest @EnumSource(Protocol.class) void connect(Protocol protocol) throws Exception { + assumeTrue(!protocol.equals(Protocol.VST) || TestUtils.isLessThanVersion(version.getVersion(), 3, 12, 0)); final ArangoDB arangoDB = new ArangoDB.Builder() .host("localhost", 8529) .password("test") @@ -70,12 +89,12 @@ void connect(Protocol protocol) throws Exception { .build(); final ArangoDBVersion version = arangoDB.getVersion(); assertThat(version).isNotNull(); - System.out.println(version.getVersion()); } @ParameterizedTest @EnumSource(Protocol.class) void noopHostnameVerifier(Protocol protocol) throws Exception { + assumeTrue(!protocol.equals(Protocol.VST) || TestUtils.isLessThanVersion(version.getVersion(), 3, 12, 0)); final ArangoDB arangoDB = new ArangoDB.Builder() .host("127.0.0.1", 8529) .password("test") @@ -86,7 +105,6 @@ void noopHostnameVerifier(Protocol protocol) throws Exception { .build(); final ArangoDBVersion version = arangoDB.getVersion(); assertThat(version).isNotNull(); - System.out.println(version.getVersion()); } @ParameterizedTest @@ -109,9 +127,9 @@ void hostnameVerifierFailure(Protocol protocol) throws Exception { exceptions.forEach(e -> assertThat(e).isInstanceOf(SSLHandshakeException.class)); } - private SSLContext createSslContext() throws Exception { + private static SSLContext createSslContext() throws Exception { final KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); - ks.load(this.getClass().getResourceAsStream(SSL_TRUSTSTORE), SSL_TRUSTSTORE_PASSWORD.toCharArray()); + ks.load(SslExampleTest.class.getResourceAsStream(SSL_TRUSTSTORE), SSL_TRUSTSTORE_PASSWORD.toCharArray()); final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(ks, SSL_TRUSTSTORE_PASSWORD.toCharArray()); diff --git a/driver/src/test/java/com/arangodb/serde/CustomSerdeAsyncTest.java b/driver/src/test/java/com/arangodb/serde/CustomSerdeAsyncTest.java index b01c030e8..cb9405503 100644 --- a/driver/src/test/java/com/arangodb/serde/CustomSerdeAsyncTest.java +++ b/driver/src/test/java/com/arangodb/serde/CustomSerdeAsyncTest.java @@ -24,6 +24,7 @@ import com.arangodb.*; import com.arangodb.config.ConfigUtils; import com.arangodb.internal.serde.InternalSerde; +import com.arangodb.internal.serde.SerdeContextImpl; import com.arangodb.model.DocumentCreateOptions; import com.arangodb.serde.jackson.JacksonSerde; import com.fasterxml.jackson.core.JsonGenerator; @@ -112,7 +113,7 @@ void manualCustomPersonDeserializer() { person.name = "Joe"; InternalSerde serialization = arangoDB.getSerde(); byte[] serialized = serialization.serializeUserData(person); - Person deserializedPerson = serialization.deserializeUserData(serialized, Person.class); + Person deserializedPerson = serialization.deserializeUserData(serialized, Person.class, SerdeContextImpl.EMPTY); assertThat(deserializedPerson.name).isEqualTo(PERSON_DESERIALIZER_ADDED_PREFIX + PERSON_SERIALIZER_ADDED_PREFIX + person.name); } @@ -209,7 +210,7 @@ void getDocument() throws ExecutionException, InterruptedException { @Test void parseNullString() { final String json = arangoDB.getSerde().deserializeUserData(arangoDB.getSerde().serializeUserData(null), - String.class); + String.class, SerdeContextImpl.EMPTY); assertThat(json).isNull(); } diff --git a/driver/src/test/java/com/arangodb/serde/CustomSerdeTest.java b/driver/src/test/java/com/arangodb/serde/CustomSerdeTest.java index 8d64d11a6..e7d65cac7 100644 --- a/driver/src/test/java/com/arangodb/serde/CustomSerdeTest.java +++ b/driver/src/test/java/com/arangodb/serde/CustomSerdeTest.java @@ -24,6 +24,7 @@ import com.arangodb.*; import com.arangodb.config.ConfigUtils; import com.arangodb.internal.serde.InternalSerde; +import com.arangodb.internal.serde.SerdeContextImpl; import com.arangodb.model.DocumentCreateOptions; import com.arangodb.serde.jackson.JacksonSerde; import com.fasterxml.jackson.core.JsonGenerator; @@ -109,7 +110,7 @@ void manualCustomPersonDeserializer() { person.name = "Joe"; InternalSerde serialization = arangoDB.getSerde(); byte[] serialized = serialization.serializeUserData(person); - Person deserializedPerson = serialization.deserializeUserData(serialized, Person.class); + Person deserializedPerson = serialization.deserializeUserData(serialized, Person.class, SerdeContextImpl.EMPTY); assertThat(deserializedPerson.name).isEqualTo(PERSON_DESERIALIZER_ADDED_PREFIX + PERSON_SERIALIZER_ADDED_PREFIX + person.name); } @@ -206,7 +207,7 @@ void getDocument() { @Test void parseNullString() { final String json = arangoDB.getSerde().deserializeUserData(arangoDB.getSerde().serializeUserData(null), - String.class); + String.class, SerdeContextImpl.EMPTY); assertThat(json).isNull(); } diff --git a/driver/src/test/java/com/arangodb/serde/JacksonConfigurationTest.java b/driver/src/test/java/com/arangodb/serde/JacksonConfigurationTest.java index 1a0f82122..d232e6a98 100644 --- a/driver/src/test/java/com/arangodb/serde/JacksonConfigurationTest.java +++ b/driver/src/test/java/com/arangodb/serde/JacksonConfigurationTest.java @@ -2,6 +2,7 @@ import com.arangodb.ContentType; import com.arangodb.internal.serde.InternalSerdeProvider; +import com.arangodb.internal.serde.SerdeContextImpl; import com.arangodb.serde.jackson.JacksonSerde; import com.arangodb.util.SlowTest; import org.junit.jupiter.params.ParameterizedTest; @@ -25,7 +26,7 @@ void bigStringInternalSerde(ContentType type) { } String in = sb.toString(); byte[] bytes = s.serialize(in); - String out = s.deserialize(bytes, String.class); + String out = s.deserialize(bytes, String.class, SerdeContextImpl.EMPTY); assertThat(out).isEqualTo(in); } diff --git a/driver/src/test/java/com/arangodb/serde/SerdeTest.java b/driver/src/test/java/com/arangodb/serde/SerdeTest.java index 7bc9009df..923fb0fc3 100644 --- a/driver/src/test/java/com/arangodb/serde/SerdeTest.java +++ b/driver/src/test/java/com/arangodb/serde/SerdeTest.java @@ -4,6 +4,7 @@ import com.arangodb.entity.BaseDocument; import com.arangodb.internal.serde.InternalSerde; import com.arangodb.internal.serde.InternalSerdeProvider; +import com.arangodb.internal.serde.SerdeContextImpl; import com.arangodb.internal.serde.SerdeUtils; import com.arangodb.util.RawBytes; import com.arangodb.util.RawJson; @@ -28,7 +29,7 @@ void rawJsonSerde(ContentType type) { ObjectNode node = JsonNodeFactory.instance.objectNode().put("foo", "bar"); RawJson raw = RawJson.of(SerdeUtils.INSTANCE.writeJson(node)); byte[] serialized = s.serialize(raw); - RawJson deserialized = s.deserialize(serialized, RawJson.class); + RawJson deserialized = s.deserialize(serialized, RawJson.class, SerdeContextImpl.EMPTY); assertThat(deserialized).isEqualTo(raw); } @@ -39,7 +40,7 @@ void rawBytesSerde(ContentType type) { ObjectNode node = JsonNodeFactory.instance.objectNode().put("foo", "bar"); RawBytes raw = RawBytes.of(s.serialize(node)); byte[] serialized = s.serialize(raw); - RawBytes deserialized = s.deserialize(serialized, RawBytes.class); + RawBytes deserialized = s.deserialize(serialized, RawBytes.class, SerdeContextImpl.EMPTY); assertThat(deserialized).isEqualTo(raw); } @@ -48,7 +49,7 @@ void rawBytesSerde(ContentType type) { void deserializeBaseDocumentWithNestedProperties(ContentType type) { InternalSerde s = new InternalSerdeProvider(type).create(); RawJson json = RawJson.of("{\"foo\":\"aaa\",\"properties\":{\"foo\":\"bbb\"}}"); - BaseDocument deserialized = s.deserialize(s.serialize(json), BaseDocument.class); + BaseDocument deserialized = s.deserialize(s.serialize(json), BaseDocument.class, SerdeContextImpl.EMPTY); assertThat(deserialized.getAttribute("foo")).isEqualTo("aaa"); assertThat(deserialized.getAttribute("properties")) .isInstanceOf(Map.class) @@ -64,7 +65,7 @@ void serializeBaseDocumentWithNestedProperties(ContentType type) { doc.addAttribute("foo", "aaa"); doc.addAttribute("properties", Collections.singletonMap("foo", "bbb")); byte[] ser = s.serialize(doc); - ObjectNode on = s.deserializeUserData(ser, ObjectNode.class); + ObjectNode on = s.deserializeUserData(ser, ObjectNode.class, SerdeContextImpl.EMPTY); assertThat(on.get("foo").textValue()).isEqualTo("aaa"); assertThat(on.get("properties").get("foo").textValue()).isEqualTo("bbb"); } diff --git a/driver/src/test/java/com/arangodb/util/TestUtils.java b/driver/src/test/java/com/arangodb/util/TestUtils.java index 895bba465..978fe29ee 100644 --- a/driver/src/test/java/com/arangodb/util/TestUtils.java +++ b/driver/src/test/java/com/arangodb/util/TestUtils.java @@ -31,7 +31,7 @@ * @author Michele Rastelli */ public final class TestUtils { - + public static final String TEST_DB = "java_driver_test_db"; private static final String[] allChars = TestUtils.generateAllInputChars(); private static final Random r = new Random(); diff --git a/driver/src/test/resources/META-INF/native-image/reflect-config.json b/driver/src/test/resources/META-INF/native-image/reflect-config.json index 220895362..dcd3b8e61 100644 --- a/driver/src/test/resources/META-INF/native-image/reflect-config.json +++ b/driver/src/test/resources/META-INF/native-image/reflect-config.json @@ -304,5 +304,11 @@ "allPublicMethods": true, "allDeclaredConstructors": true, "allDeclaredClasses": true + }, + { + "name": "com.arangodb.SerdeContextTest$Person", + "allDeclaredFields": true, + "allDeclaredMethods": true, + "allDeclaredConstructors": true } ] diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index fea1770a1..bd94a6fc8 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -184,7 +184,11 @@ ${project.build.directory}/generated-test-sources replacer - **/CustomSerdeTest.**,**/SerdeTest.**,**/SerializableTest.**,**/JacksonInterferenceTest.** + **/CustomSerdeTest.**, + **/SerdeTest.**, + **/SerializableTest.**, + **/JacksonInterferenceTest.**, + **/JacksonSerdeContextTest.** diff --git a/jackson-serde-json/src/main/java/com/arangodb/serde/jackson/JacksonSerde.java b/jackson-serde-json/src/main/java/com/arangodb/serde/jackson/JacksonSerde.java index 3e3246029..d954f11d7 100644 --- a/jackson-serde-json/src/main/java/com/arangodb/serde/jackson/JacksonSerde.java +++ b/jackson-serde-json/src/main/java/com/arangodb/serde/jackson/JacksonSerde.java @@ -1,8 +1,11 @@ package com.arangodb.serde.jackson; import com.arangodb.ContentType; +import com.arangodb.internal.serde.SerdeUtils; import com.arangodb.serde.ArangoSerde; +import com.arangodb.serde.SerdeContext; import com.arangodb.serde.jackson.internal.JacksonSerdeImpl; +import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.function.Consumer; @@ -32,6 +35,16 @@ static JacksonSerde create(final ObjectMapper mapper) { return new JacksonSerdeImpl(mapper); } + /** + * Extracts the {@link SerdeContext} from the current {@link DeserializationContext}. + * + * @param ctx current Jackson {@link DeserializationContext} + * @return current {@link SerdeContext} + */ + static SerdeContext getSerdeContext(DeserializationContext ctx) { + return (SerdeContext) ctx.getAttribute(SerdeUtils.SERDE_CONTEXT_ATTRIBUTE_NAME); + } + /** * Allows configuring the underlying Jackson ObjectMapper * diff --git a/jackson-serde-json/src/main/java/com/arangodb/serde/jackson/internal/JacksonSerdeImpl.java b/jackson-serde-json/src/main/java/com/arangodb/serde/jackson/internal/JacksonSerdeImpl.java index ab26a0a3c..b878ea8b6 100644 --- a/jackson-serde-json/src/main/java/com/arangodb/serde/jackson/internal/JacksonSerdeImpl.java +++ b/jackson-serde-json/src/main/java/com/arangodb/serde/jackson/internal/JacksonSerdeImpl.java @@ -1,13 +1,19 @@ package com.arangodb.serde.jackson.internal; +import com.arangodb.internal.serde.SerdeContextImpl; +import com.arangodb.serde.SerdeContext; import com.arangodb.serde.jackson.JacksonSerde; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.cfg.ContextAttributes; import java.io.IOException; +import java.util.Objects; import java.util.function.Consumer; +import static com.arangodb.internal.serde.SerdeUtils.SERDE_CONTEXT_ATTRIBUTE_NAME; + /** * Not shaded in arangodb-java-driver-shaded. */ @@ -32,8 +38,16 @@ public byte[] serialize(final Object value) { @Override public T deserialize(final byte[] content, final Class type) { + return deserialize(content, type, SerdeContextImpl.EMPTY); + } + + @Override + public T deserialize(byte[] content, Class type, SerdeContext ctx) { + Objects.requireNonNull(ctx); try { - return mapper.readerFor(mapper.constructType(type)).readValue(content); + return mapper.readerFor(mapper.constructType(type)) + .with(ContextAttributes.getEmpty().withPerCallAttribute(SERDE_CONTEXT_ATTRIBUTE_NAME, ctx)) + .readValue(content); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/vst/src/main/java/com/arangodb/vst/internal/VstConnectionAsync.java b/vst/src/main/java/com/arangodb/vst/internal/VstConnectionAsync.java index b740efa9f..9ad4ca58e 100644 --- a/vst/src/main/java/com/arangodb/vst/internal/VstConnectionAsync.java +++ b/vst/src/main/java/com/arangodb/vst/internal/VstConnectionAsync.java @@ -26,8 +26,8 @@ import com.arangodb.internal.InternalResponse; import com.arangodb.internal.config.ArangoConfig; import com.arangodb.internal.serde.InternalSerde; +import com.arangodb.internal.serde.SerdeContextImpl; import com.arangodb.velocypack.VPackSlice; -import com.arangodb.velocypack.exception.VPackException; import com.arangodb.velocypack.exception.VPackParserException; import com.arangodb.vst.internal.utils.CompletableFutureUtils; import org.slf4j.Logger; @@ -94,7 +94,7 @@ public CompletableFuture executeAsync(final InternalRequest re final InternalResponse response; try { response = createResponse(m); - } catch (final VPackParserException e) { + } catch (final Exception e) { rfuture.completeExceptionally(e); return; } @@ -104,7 +104,7 @@ public CompletableFuture executeAsync(final InternalRequest re rfuture.completeExceptionally(e); } }); - } catch (final VPackException e) { + } catch (Exception e) { LOGGER.error(e.getMessage(), e); rfuture.completeExceptionally(e); } @@ -152,7 +152,7 @@ private Collection buildChunks(final Message message) { } private InternalResponse createResponse(final Message message) throws VPackParserException { - final InternalResponse response = serde.deserialize(message.getHead().toByteArray(), InternalResponse.class); + InternalResponse response = serde.deserialize(message.getHead().toByteArray(), InternalResponse.class, SerdeContextImpl.EMPTY); if (message.getBody() != null) { response.setBody(message.getBody().toByteArray()); }