Skip to content

[DE-837] added serdeProviderClass configuration property #575

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

Merged
merged 1 commit into from
Sep 5, 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
13 changes: 13 additions & 0 deletions core/src/main/java/com/arangodb/ArangoDB.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import com.arangodb.internal.util.HostUtils;
import com.arangodb.model.*;
import com.arangodb.serde.ArangoSerde;
import com.arangodb.serde.ArangoSerdeProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -636,6 +637,18 @@ public Builder serde(final ArangoSerde serde) {
return this;
}

/**
* Sets the serde provider to be used to instantiate the user data serde.
* Ignored if {@link Builder#serde(ArangoSerde)} is used.
*
* @param serdeProviderClass class of the serde provider, it must have a public no-args constructor
* @return {@link ArangoDB.Builder}
*/
public Builder serdeProviderClass(final Class<? extends ArangoSerdeProvider> serdeProviderClass) {
config.setUserDataSerdeProvider(serdeProviderClass);
return this;
}

/**
* Sets the downstream async executor that will be used to consume the responses of the async API, that are returned
* as {@link java.util.concurrent.CompletableFuture}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ default Optional<Integer> getCompressionLevel() {
return Optional.empty();
}

default Optional<Boolean> getReuseVertx() {
default Optional<String> getSerdeProviderClass() {
return Optional.empty();
}

Expand Down
32 changes: 29 additions & 3 deletions core/src/main/java/com/arangodb/internal/config/ArangoConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import com.fasterxml.jackson.databind.Module;

import javax.net.ssl.SSLContext;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;
Expand All @@ -40,6 +41,7 @@ public class ArangoConfig {
private LoadBalancingStrategy loadBalancingStrategy;
private InternalSerde internalSerde;
private ArangoSerde userDataSerde;
private Class<? extends ArangoSerdeProvider> serdeProviderClass;
private Integer responseQueueTimeSamples;
private Module protocolModule;
private Executor asyncExecutor;
Expand Down Expand Up @@ -81,6 +83,14 @@ public void loadProperties(final ArangoConfigProperties properties) {
compression = properties.getCompression().orElse(ArangoDefaults.DEFAULT_COMPRESSION);
compressionThreshold = properties.getCompressionThreshold().orElse(ArangoDefaults.DEFAULT_COMPRESSION_THRESHOLD);
compressionLevel = properties.getCompressionLevel().orElse(ArangoDefaults.DEFAULT_COMPRESSION_LEVEL);
serdeProviderClass = properties.getSerdeProviderClass().map((String className) -> {
try {
//noinspection unchecked
return (Class<? extends ArangoSerdeProvider>) Class.forName(className);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}).orElse(null);
}

public List<HostDescription> getHosts() {
Expand Down Expand Up @@ -237,11 +247,23 @@ public void setLoadBalancingStrategy(LoadBalancingStrategy loadBalancingStrategy
this.loadBalancingStrategy = loadBalancingStrategy;
}

public Class<? extends ArangoSerdeProvider> getSerdeProviderClass() {
return serdeProviderClass;
}

public ArangoSerde getUserDataSerde() {
if (userDataSerde == null) {
userDataSerde = ArangoSerdeProvider.of(ContentTypeFactory.of(getProtocol())).create();
if (userDataSerde != null) {
return userDataSerde;
} else if (serdeProviderClass != null) {
try {
return serdeProviderClass.getDeclaredConstructor().newInstance().create();
} catch (InstantiationException | IllegalAccessException | InvocationTargetException |
NoSuchMethodException e) {
throw new RuntimeException(e);
}
} else {
return ArangoSerdeProvider.of(ContentTypeFactory.of(getProtocol())).create();
}
return userDataSerde;
}

public InternalSerde getInternalSerde() {
Expand All @@ -255,6 +277,10 @@ public void setUserDataSerde(ArangoSerde userDataSerde) {
this.userDataSerde = userDataSerde;
}

public void setUserDataSerdeProvider(Class<? extends ArangoSerdeProvider> serdeProviderClass) {
this.serdeProviderClass = serdeProviderClass;
}

public Integer getResponseQueueTimeSamples() {
return responseQueueTimeSamples;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,4 +161,9 @@ public Optional<Integer> getCompressionLevel() {
return Optional.ofNullable(getProperty("compressionLevel")).map(Integer::valueOf);
}

@Override
public Optional<String> getSerdeProviderClass() {
return Optional.ofNullable(getProperty("serdeProviderClass"));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ void ArangoConfigDefaultValues() {
assertThat(cfg.getCompressionThreshold()).isEqualTo(ArangoDefaults.DEFAULT_COMPRESSION_THRESHOLD);
assertThat(cfg.getCompressionLevel()).isEqualTo(ArangoDefaults.DEFAULT_COMPRESSION_LEVEL);
assertThat(cfg.getProtocolConfig()).isNull();
assertThat(cfg.getSerdeProviderClass()).isNull();
}

@Test
Expand Down
19 changes: 0 additions & 19 deletions test-functional/src/test/resources/arangodb-config-test.properties

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public final class ArangoConfigPropertiesMPImpl implements ArangoConfigPropertie
private Optional<Compression> compression;
private Optional<Integer> compressionThreshold;
private Optional<Integer> compressionLevel;
private Optional<String> serdeProviderClass;

@Override
public Optional<List<HostDescription>> getHosts() {
Expand Down Expand Up @@ -129,22 +130,27 @@ public Optional<Integer> getCompressionLevel() {
return compressionLevel;
}

@Override
public Optional<String> getSerdeProviderClass() {
return serdeProviderClass;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ArangoConfigPropertiesMPImpl that = (ArangoConfigPropertiesMPImpl) o;
return Objects.equals(hosts, that.hosts) && Objects.equals(protocol, that.protocol) && Objects.equals(user, that.user) && Objects.equals(password, that.password) && Objects.equals(jwt, that.jwt) && Objects.equals(timeout, that.timeout) && Objects.equals(useSsl, that.useSsl) && Objects.equals(verifyHost, that.verifyHost) && Objects.equals(chunkSize, that.chunkSize) && Objects.equals(maxConnections, that.maxConnections) && Objects.equals(connectionTtl, that.connectionTtl) && Objects.equals(keepAliveInterval, that.keepAliveInterval) && Objects.equals(acquireHostList, that.acquireHostList) && Objects.equals(acquireHostListInterval, that.acquireHostListInterval) && Objects.equals(loadBalancingStrategy, that.loadBalancingStrategy) && Objects.equals(responseQueueTimeSamples, that.responseQueueTimeSamples) && Objects.equals(compression, that.compression) && Objects.equals(compressionThreshold, that.compressionThreshold) && Objects.equals(compressionLevel, that.compressionLevel);
return Objects.equals(hosts, that.hosts) && Objects.equals(protocol, that.protocol) && Objects.equals(user, that.user) && Objects.equals(password, that.password) && Objects.equals(jwt, that.jwt) && Objects.equals(timeout, that.timeout) && Objects.equals(useSsl, that.useSsl) && Objects.equals(verifyHost, that.verifyHost) && Objects.equals(chunkSize, that.chunkSize) && Objects.equals(maxConnections, that.maxConnections) && Objects.equals(connectionTtl, that.connectionTtl) && Objects.equals(keepAliveInterval, that.keepAliveInterval) && Objects.equals(acquireHostList, that.acquireHostList) && Objects.equals(acquireHostListInterval, that.acquireHostListInterval) && Objects.equals(loadBalancingStrategy, that.loadBalancingStrategy) && Objects.equals(responseQueueTimeSamples, that.responseQueueTimeSamples) && Objects.equals(compression, that.compression) && Objects.equals(compressionThreshold, that.compressionThreshold) && Objects.equals(compressionLevel, that.compressionLevel) && Objects.equals(serdeProviderClass, that.serdeProviderClass);
}

@Override
public int hashCode() {
return Objects.hash(hosts, protocol, user, password, jwt, timeout, useSsl, verifyHost, chunkSize, maxConnections, connectionTtl, keepAliveInterval, acquireHostList, acquireHostListInterval, loadBalancingStrategy, responseQueueTimeSamples, compression, compressionThreshold, compressionLevel);
return Objects.hash(hosts, protocol, user, password, jwt, timeout, useSsl, verifyHost, chunkSize, maxConnections, connectionTtl, keepAliveInterval, acquireHostList, acquireHostListInterval, loadBalancingStrategy, responseQueueTimeSamples, compression, compressionThreshold, compressionLevel, serdeProviderClass);
}

@Override
public String toString() {
return "ArangoConfigPropertiesImpl{" +
return "ArangoConfigPropertiesMPImpl{" +
"hosts=" + hosts +
", protocol=" + protocol +
", user=" + user +
Expand All @@ -164,6 +170,7 @@ public String toString() {
", compression=" + compression +
", compressionThreshold=" + compressionThreshold +
", compressionLevel=" + compressionLevel +
", serdeProviderClass=" + serdeProviderClass +
'}';
}
}
2 changes: 2 additions & 0 deletions test-non-functional/src/test/java/mp/ConfigMPTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class ConfigMPTest {
private final Compression compression = Compression.GZIP;
private final Integer compressionThreshold = 123456789;
private final Integer compressionLevel = 9;
private final String serdeProviderClass = "com.arangodb.serde.jsonb.JsonbSerdeProvider";

@Test
void readConfig() {
Expand Down Expand Up @@ -73,5 +74,6 @@ private void checkResult(ArangoConfigProperties config) {
assertThat(config.getCompression()).hasValue(compression);
assertThat(config.getCompressionThreshold()).hasValue(compressionThreshold);
assertThat(config.getCompressionLevel()).hasValue(compressionLevel);
assertThat(config.getSerdeProviderClass()).isPresent().hasValue(serdeProviderClass);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package serde;

import com.arangodb.ArangoDB;
import com.arangodb.config.ArangoConfigProperties;
import com.arangodb.serde.ArangoSerde;
import com.arangodb.serde.jackson.internal.JacksonSerdeImpl;
import com.arangodb.serde.jackson.json.JacksonJsonSerdeProvider;
import com.arangodb.serde.jackson.vpack.JacksonVPackSerdeProvider;
import com.arangodb.serde.jsonb.JsonbSerde;
import com.arangodb.serde.jsonb.JsonbSerdeProvider;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;

import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;

import static org.assertj.core.api.Assertions.assertThat;

public class SerdeConfigurationTest {
private final VarHandle JACKSON_SERDE_IMPL_MAPPER;
{
try {
JACKSON_SERDE_IMPL_MAPPER = MethodHandles
.privateLookupIn(JacksonSerdeImpl.class, MethodHandles.lookup())
.findVarHandle(JacksonSerdeImpl.class, "mapper", ObjectMapper.class);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}

@Test
void vpackSerdeProvider() {
ArangoDB adb = new ArangoDB.Builder()
.host("foo", 1111)
.serdeProviderClass(JacksonVPackSerdeProvider.class)
.build();

ArangoSerde serde = adb.getSerde().getUserSerde();
assertThat(serde).isInstanceOf(JacksonSerdeImpl.class);

ObjectMapper mapper = (ObjectMapper) JACKSON_SERDE_IMPL_MAPPER.get(serde);
assertThat(mapper.getFactory().getFormatName()).isEqualTo("Velocypack");
}

@Test
void jsonSerdeProvider() {
ArangoDB adb = new ArangoDB.Builder()
.host("foo", 1111)
.serdeProviderClass(JacksonJsonSerdeProvider.class)
.build();

ArangoSerde serde = adb.getSerde().getUserSerde();
assertThat(serde).isInstanceOf(JacksonSerdeImpl.class);

ObjectMapper mapper = (ObjectMapper) JACKSON_SERDE_IMPL_MAPPER.get(serde);
assertThat(mapper.getFactory().getFormatName()).isEqualTo("JSON");
}


@Test
void jsonBSerdeProvider() {
ArangoDB adb = new ArangoDB.Builder()
.host("foo", 1111)
.serdeProviderClass(JsonbSerdeProvider.class)
.build();

ArangoSerde serde = adb.getSerde().getUserSerde();
assertThat(serde).isInstanceOf(JsonbSerde.class);
}

@Test
void jsonBSerdeProviderFromConfigFile() {
ArangoDB adb = new ArangoDB.Builder()
.loadProperties(ArangoConfigProperties.fromFile("arangodb-serde-provider.properties"))
.build();

ArangoSerde serde = adb.getSerde().getUserSerde();
assertThat(serde).isInstanceOf(JsonbSerde.class);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ adb.responseQueueTimeSamples=12345678
adb.compression=GZIP
adb.compressionThreshold=123456789
adb.compressionLevel=9
adb.serdeProviderClass=com.arangodb.serde.jsonb.JsonbSerdeProvider
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
arangodb.hosts=172.28.0.1:8529
arangodb.password=test
arangodb.serdeProviderClass=com.arangodb.serde.jsonb.JsonbSerdeProvider