Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve serialization and deserialization of RawData #586

Merged
merged 1 commit into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,15 @@
import com.arangodb.entity.ReplicationFactor;
import com.arangodb.entity.arangosearch.CollectionLink;
import com.arangodb.entity.arangosearch.FieldLink;
import com.arangodb.util.RawBytes;
import com.arangodb.util.RawJson;
import com.arangodb.internal.InternalResponse;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.*;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
Expand All @@ -29,23 +26,10 @@ public final class InternalDeserializers {
static final JsonDeserializer<RawJson> RAW_JSON_DESERIALIZER = new JsonDeserializer<RawJson>() {
@Override
public RawJson deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
// TODO: find a way to access raw bytes directly
return RawJson.of(SerdeUtils.INSTANCE.writeJson(p.readValueAsTree()));
}
};

static final JsonDeserializer<RawBytes> RAW_BYTES_DESERIALIZER = new JsonDeserializer<RawBytes>() {
@Override
public RawBytes deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
// TODO: find a way to access raw bytes directly
ByteArrayOutputStream os = new ByteArrayOutputStream();
try (JsonGenerator g = p.getCodec().getFactory().createGenerator(os)) {
g.writeTree(p.readValueAsTree());
}
return RawBytes.of(os.toByteArray());
}
};

static final JsonDeserializer<CollectionStatus> COLLECTION_STATUS = new JsonDeserializer<CollectionStatus>() {
@Override
public CollectionStatus deserialize(final JsonParser p, final DeserializationContext ctxt) throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import com.arangodb.entity.CollectionType;
import com.arangodb.entity.InvertedIndexPrimarySort;
import com.arangodb.entity.ReplicationFactor;
import com.arangodb.util.RawBytes;
import com.arangodb.util.RawJson;
import com.arangodb.internal.InternalRequest;
import com.arangodb.internal.InternalResponse;
Expand All @@ -22,12 +21,10 @@ enum InternalModule implements Supplier<Module> {
module = new SimpleModule();

module.addSerializer(RawJson.class, InternalSerializers.RAW_JSON_SERIALIZER);
module.addSerializer(RawBytes.class, InternalSerializers.RAW_BYTES_SERIALIZER);
module.addSerializer(InternalRequest.class, InternalSerializers.REQUEST);
module.addSerializer(CollectionType.class, InternalSerializers.COLLECTION_TYPE);

module.addDeserializer(RawJson.class, InternalDeserializers.RAW_JSON_DESERIALIZER);
module.addDeserializer(RawBytes.class, InternalDeserializers.RAW_BYTES_DESERIALIZER);
module.addDeserializer(CollectionStatus.class, InternalDeserializers.COLLECTION_STATUS);
module.addDeserializer(CollectionType.class, InternalDeserializers.COLLECTION_TYPE);
module.addDeserializer(ReplicationFactor.class, InternalDeserializers.REPLICATION_FACTOR);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.arangodb.util.RawBytes;
import com.arangodb.util.RawJson;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
Expand All @@ -16,6 +17,7 @@

import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
Expand Down Expand Up @@ -104,7 +106,11 @@ public byte[] serializeUserData(Object value) {
return serialize(null);
}
Class<?> clazz = value.getClass();
if (isManagedClass(clazz)) {
if (RawBytes.class.equals(clazz)) {
return ((RawBytes) value).get();
} else if (RawJson.class.equals(clazz) && JsonFactory.FORMAT_NAME_JSON.equals(mapper.getFactory().getFormatName())) {
return ((RawJson) value).get().getBytes(StandardCharsets.UTF_8);
} else if (isManagedClass(clazz)) {
return serialize(value);
} else {
return userSerde.serialize(value);
Expand All @@ -121,8 +127,13 @@ public byte[] serializeCollectionUserData(Iterable<?> value) {
}

@Override
@SuppressWarnings("unchecked")
public <T> T deserializeUserData(byte[] content, Class<T> clazz) {
if (isManagedClass(clazz)) {
if (RawBytes.class.equals(clazz)) {
return (T) RawBytes.of(content);
} else if (RawJson.class.equals(clazz) && JsonFactory.FORMAT_NAME_JSON.equals(mapper.getFactory().getFormatName())) {
return (T) RawJson.of(new String(content, StandardCharsets.UTF_8));
} else if (isManagedClass(clazz)) {
return deserialize(content, clazz);
} else {
return userSerde.deserialize(content, clazz, RequestContextHolder.INSTANCE.getCtx());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@
import com.arangodb.entity.arangosearch.CollectionLink;
import com.arangodb.entity.arangosearch.FieldLink;
import com.arangodb.internal.ArangoRequestParam;
import com.arangodb.util.RawBytes;
import com.arangodb.util.RawJson;
import com.arangodb.internal.InternalRequest;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

Expand All @@ -26,16 +24,6 @@ public void serialize(RawJson value, JsonGenerator gen, SerializerProvider seria
gen.writeTree(SerdeUtils.INSTANCE.parseJson(value.get()));
}
};
static final JsonSerializer<RawBytes> RAW_BYTES_SERIALIZER = new JsonSerializer<RawBytes>() {
@Override
public void serialize(RawBytes value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
// TODO: find a way to append raw bytes directly
// see https://github.com/FasterXML/jackson-core/issues/914
try (JsonParser parser = gen.getCodec().getFactory().createParser(value.get())) {
gen.writeTree(parser.readValueAsTree());
}
}
};
static final JsonSerializer<InternalRequest> REQUEST = new JsonSerializer<InternalRequest>() {
@Override
public void serialize(InternalRequest value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
package com.arangodb;

import com.arangodb.entity.*;
import com.arangodb.entity.AqlExecutionExplainEntity.ExecutionPlan;
import com.arangodb.entity.QueryCachePropertiesEntity.CacheMode;
import com.arangodb.internal.serde.InternalSerde;
import com.arangodb.model.*;
import com.arangodb.util.MapBuilder;
import com.arangodb.util.RawBytes;
Expand Down Expand Up @@ -668,6 +668,19 @@ void queryWithTTL(ArangoDatabaseAsync db) throws InterruptedException, Execution
assertThat(ex.getMessage()).isEqualTo("Response: 404, Error: 1600 - cursor not found");
}

@ParameterizedTest
@MethodSource("asyncDbs")
void queryRawBytes(ArangoDatabaseAsync db) throws ExecutionException, InterruptedException {
InternalSerde serde = db.getSerde();
RawBytes doc = RawBytes.of(serde.serialize(Collections.singletonMap("value", 1)));
RawBytes res = db.query("RETURN @doc", RawBytes.class, Collections.singletonMap("doc", doc)).get()
.getResult().get(0);
JsonNode data = serde.parse(res.get());
assertThat(data.isObject()).isTrue();
assertThat(data.get("value").isNumber()).isTrue();
assertThat(data.get("value").numberValue()).isEqualTo(1);
}

@ParameterizedTest
@MethodSource("asyncDbs")
void changeQueryCache(ArangoDatabaseAsync db) throws ExecutionException, InterruptedException {
Expand Down
13 changes: 13 additions & 0 deletions test-functional/src/test/java/com/arangodb/ArangoDatabaseTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import com.arangodb.entity.*;
import com.arangodb.entity.QueryCachePropertiesEntity.CacheMode;
import com.arangodb.internal.serde.InternalSerde;
import com.arangodb.model.*;
import com.arangodb.util.*;
import com.fasterxml.jackson.databind.JsonNode;
Expand Down Expand Up @@ -736,6 +737,18 @@ void queryWithTTL(ArangoDatabase db) throws InterruptedException {
}
}

@ParameterizedTest
@MethodSource("dbs")
void queryRawBytes(ArangoDatabase db) {
InternalSerde serde = db.getSerde();
RawBytes doc = RawBytes.of(serde.serialize(Collections.singletonMap("value", 1)));
RawBytes res = db.query("RETURN @doc", RawBytes.class, Collections.singletonMap("doc", doc)).next();
JsonNode data = serde.parse(res.get());
assertThat(data.isObject()).isTrue();
assertThat(data.get("value").isNumber()).isTrue();
assertThat(data.get("value").numberValue()).isEqualTo(1);
}

@ParameterizedTest
@MethodSource("dbs")
void changeQueryCache(ArangoDatabase db) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ void rawBytesSerde(ContentType type) {
InternalSerde s = new InternalSerdeProvider(type).create();
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);
byte[] serialized = s.serializeUserData(raw);
RawBytes deserialized = s.deserializeUserData(serialized, RawBytes.class);
assertThat(deserialized).isEqualTo(raw);
}

Expand Down