diff --git a/ChangeLog.md b/ChangeLog.md
index ac54b93..62c5057 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
## [Unreleased]
+- added useTypeHint option to VPack.Builder
+
## [2.3.1] - 2020-05-05
- shaded jackson dependency
diff --git a/pom.xml b/pom.xml
index 538a878..bae10de 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.arangodb
velocypack
- 2.3.1
+ 2.4.0-SNAPSHOT
2017
jar
diff --git a/src/main/java/com/arangodb/velocypack/VPack.java b/src/main/java/com/arangodb/velocypack/VPack.java
index 0e46fac..929b52d 100644
--- a/src/main/java/com/arangodb/velocypack/VPack.java
+++ b/src/main/java/com/arangodb/velocypack/VPack.java
@@ -49,6 +49,7 @@ public class VPack {
private static final String ATTR_KEY = "key";
private static final String ATTR_VALUE = "value";
private static final String DEFAULT_TYPE_KEY = "_class";
+ private static final boolean DEFAULT_USE_TYPE_HINTS = true;
private final Map> serializers;
private final Map> enclosingSerializers;
@@ -65,6 +66,7 @@ public class VPack {
private final VPackDeserializationContext deserializationContext;
private final boolean serializeNullValues;
private final String typeKey;
+ private final boolean useTypeHints;
private final VPackBuilderUtils builderUtils;
private final VPackCreatorMethodUtils vPackCreatorMethodUtils;
@@ -83,6 +85,7 @@ public static class Builder implements VPackSetupContext {
private final Map, VPackAnnotationFieldNaming extends Annotation>> annotationFieldNaming;
private final Map> keyMapAdapters;
private String typeKey;
+ private Boolean useTypeHints;
public Builder() {
super();
@@ -99,6 +102,7 @@ public Builder() {
annotationFieldNaming = new HashMap<>();
keyMapAdapters = new HashMap<>();
typeKey = null;
+ useTypeHints = null;
instanceCreators.put(Iterable.class, VPackInstanceCreators.ITERABLE);
instanceCreators.put(Collection.class, VPackInstanceCreators.COLLECTION);
@@ -319,11 +323,24 @@ public Builder registerKeyMapAdapter(final Type type, final VPackKeyMapAdapter
* @param typeKey Name of the field with type information
* @return {@link VPack.Builder}
*/
- public Builder typeKey(final String typeKey) {
+ @Override
+ public VPack.Builder typeKey(final String typeKey) {
this.typeKey = typeKey;
return this;
}
+ /**
+ * Enables storing type information of the serialized object
+ *
+ * @param useTypeHints (default: {@code true})
+ * @return {@link VPack.Builder}
+ */
+ @Override
+ public VPack.Builder useTypeHints(final boolean useTypeHints) {
+ this.useTypeHints = useTypeHints;
+ return this;
+ }
+
public synchronized VPack build() {
return new VPack(new HashMap<>(serializers), new HashMap<>(enclosingSerializers), new HashMap<>(deserializers),
new HashMap<>(deserializersWithSelfNullHandle),
@@ -331,7 +348,10 @@ public synchronized VPack build() {
fieldNamingStrategy, new HashMap<>(deserializersByName),
new HashMap<>(deserializersByNameWithSelfNullHandle),
new HashMap<>(annotationFieldFilter), new HashMap<>(annotationFieldNaming),
- keyMapAdapters, typeKey != null ? typeKey : DEFAULT_TYPE_KEY);
+ keyMapAdapters,
+ typeKey != null ? typeKey : DEFAULT_TYPE_KEY,
+ useTypeHints != null ? useTypeHints : DEFAULT_USE_TYPE_HINTS
+ );
}
}
@@ -345,7 +365,7 @@ private VPack(final Map> serializers,
final Map>> deserializersByNameWithSelfNullHandle,
final Map, VPackAnnotationFieldFilter extends Annotation>> annotationFieldFilter,
final Map, VPackAnnotationFieldNaming extends Annotation>> annotationFieldNaming,
- final Map> keyMapAdapters, final String typeKey) {
+ final Map> keyMapAdapters, final String typeKey, final boolean useTypeHints) {
super();
this.serializers = serializers;
this.enclosingSerializers = enclosingSerializers;
@@ -358,6 +378,7 @@ private VPack(final Map> serializers,
this.deserializersByNameWithSelfNullHandle = deserializersByNameWithSelfNullHandle;
this.keyMapAdapters = keyMapAdapters;
this.typeKey = typeKey;
+ this.useTypeHints = useTypeHints;
builderUtils = new VPackBuilderUtils();
vPackCreatorMethodUtils = new VPackCreatorMethodUtils();
@@ -480,7 +501,7 @@ private T deserializeObject(
}
private Type determineType(final VPackSlice vpack, final Type type) {
- if (!vpack.isObject()) {
+ if (!useTypeHints || !vpack.isObject()) {
return type;
}
final VPackSlice clazz = vpack.get(typeKey);
@@ -933,6 +954,12 @@ private void addValue(
} else if (shouldAddTypeHint(type, value, fieldInfo)) {
addValue(name, value.getClass(), value, builder, fieldInfo,
Collections.singletonMap(typeKey, value.getClass().getName()));
+ } else if (value instanceof Iterable) {
+ serializeIterable(name, value, builder, null);
+ } else if (value instanceof Map) {
+ serializeMap(name, value, builder, String.class, additionalFields);
+ } else if (value.getClass().isArray()) {
+ serializeArray(name, value, builder, null);
} else {
serializeObject(name, value, builder, additionalFields);
}
@@ -944,6 +971,9 @@ private boolean shouldAddTypeHint(
final Object value,
final FieldInfo fieldInfo
) {
+ if (!useTypeHints) {
+ return false;
+ }
final AnnotatedElement referencingElement = fieldInfo != null ? fieldInfo.getReferencingElement() : null;
final BuilderInfo builderInfo = builderUtils.getBuilderInfo(type, referencingElement);
if (builderInfo != null) {
diff --git a/src/main/java/com/arangodb/velocypack/VPackSetupContext.java b/src/main/java/com/arangodb/velocypack/VPackSetupContext.java
index 1839655..7598b51 100644
--- a/src/main/java/com/arangodb/velocypack/VPackSetupContext.java
+++ b/src/main/java/com/arangodb/velocypack/VPackSetupContext.java
@@ -60,8 +60,8 @@ C annotationFieldFilter(
final VPackAnnotationFieldFilter fieldFilter);
C annotationFieldNaming(
- final Class type,
- final VPackAnnotationFieldNaming fieldNaming);
+ final Class type,
+ final VPackAnnotationFieldNaming fieldNaming);
C registerKeyMapAdapter(final Type type, final VPackKeyMapAdapter> adapter);
@@ -69,4 +69,8 @@ C annotationFieldNaming(
C registerModules(VPackModule... modules);
+ C typeKey(final String typeKey);
+
+ C useTypeHints(final boolean useTypeHints);
+
}
diff --git a/src/test/java/com/arangodb/velocypack/VPackWithoutTypeHintTest.java b/src/test/java/com/arangodb/velocypack/VPackWithoutTypeHintTest.java
new file mode 100644
index 0000000..aa3846a
--- /dev/null
+++ b/src/test/java/com/arangodb/velocypack/VPackWithoutTypeHintTest.java
@@ -0,0 +1,320 @@
+/*
+ * 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.velocypack;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.*;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
+
+/**
+ * @author Michele Rastelli
+ */
+@RunWith(Parameterized.class)
+public class VPackWithoutTypeHintTest {
+
+ private final boolean useTypeHints;
+
+ @Parameterized.Parameters
+ public static Collection useTypeHint() {
+ return Arrays.asList(true, false);
+ }
+
+ public VPackWithoutTypeHintTest(final boolean useTypeHints) {
+ this.useTypeHints = useTypeHints;
+ }
+
+ public static class NestedArray {
+ public String[] value;
+ }
+
+ @Test
+ public void nestedArrayWithoutTypeInformation() {
+ NestedArray input = new NestedArray();
+ input.value = new String[]{"a", "b", "c"};
+
+ final VPack vpack = new VPack.Builder().useTypeHints(useTypeHints).build();
+ final VPackSlice slice = vpack.serialize(input);
+
+ assertThat(slice.isObject(), is(true));
+ assertThat(slice.get("value").isArray(), is(true));
+ if (!useTypeHints)
+ assertThat(slice.get("_class").isNone(), is(true));
+
+ NestedArray output = vpack.deserialize(slice, NestedArray.class);
+ assertThat(output.value, instanceOf(String[].class));
+
+ assertThat(output.value, equalTo(input.value));
+ }
+
+ public static class NestedIterable {
+ public Iterable value;
+ }
+
+ @Test
+ public void nestedIterableWithoutTypeInformation() {
+ NestedIterable input = new NestedIterable();
+ input.value = Arrays.asList("a", "b", "c");
+
+ final VPack vpack = new VPack.Builder().useTypeHints(useTypeHints).build();
+ final VPackSlice slice = vpack.serialize(input);
+
+ assertThat(slice.isObject(), is(true));
+ assertThat(slice.get("value").isArray(), is(true));
+ if (!useTypeHints)
+ assertThat(slice.get("_class").isNone(), is(true));
+
+ NestedIterable output = vpack.deserialize(slice, NestedIterable.class);
+ assertThat(output.value, instanceOf(List.class));
+
+ assertThat(output.value, equalTo(input.value));
+ }
+
+ public static class NestedCollection {
+ public Collection value;
+ }
+
+ @Test
+ public void nestedCollectionWithoutTypeInformation() {
+ NestedCollection input = new NestedCollection();
+ input.value = Arrays.asList("a", "b", "c");
+
+ final VPack vpack = new VPack.Builder().useTypeHints(useTypeHints).build();
+ final VPackSlice slice = vpack.serialize(input);
+
+ assertThat(slice.isObject(), is(true));
+ assertThat(slice.get("value").isArray(), is(true));
+ if (!useTypeHints)
+ assertThat(slice.get("_class").isNone(), is(true));
+
+ NestedCollection output = vpack.deserialize(slice, NestedCollection.class);
+ assertThat(output.value, instanceOf(List.class));
+
+ assertThat(output.value, equalTo(input.value));
+ }
+
+ public static class NestedMap {
+ public Map value;
+ }
+
+ @Test
+ public void nestedMapWithoutTypeInformation() {
+ Map map = new HashMap<>();
+ map.put("a", "b");
+
+ NestedMap input = new NestedMap();
+ input.value = map;
+
+ final VPack vpack = new VPack.Builder().useTypeHints(useTypeHints).build();
+ final VPackSlice slice = vpack.serialize(input);
+
+ assertThat(slice.isObject(), is(true));
+ assertThat(slice.get("value").isObject(), is(true));
+ if (!useTypeHints) {
+ assertThat(slice.get("_class").isNone(), is(true));
+ assertThat(slice.get("value").get("_class").isNone(), is(true));
+ }
+ NestedMap output = vpack.deserialize(slice, NestedMap.class);
+ assertThat(output.value, instanceOf(Map.class));
+
+ assertThat(output.value, equalTo(input.value));
+ }
+
+ public static class NestedObject {
+ public Object value;
+ }
+
+ @Test
+ public void nestedObjectListWithoutTypeInformation() {
+ NestedObject input = new NestedObject();
+ input.value = Arrays.asList("a", "b", "c");
+
+ final VPack vpack = new VPack.Builder().useTypeHints(useTypeHints).build();
+ final VPackSlice slice = vpack.serialize(input);
+ assertThat(slice.isObject(), is(true));
+ assertThat(slice.get("value").isArray(), is(true));
+ if (!useTypeHints)
+ assertThat(slice.get("_class").isNone(), is(true));
+
+ NestedObject output = vpack.deserialize(slice, NestedObject.class);
+ assertThat(output.value, instanceOf(List.class));
+
+ assertThat(output.value, equalTo(input.value));
+ }
+
+ @Test
+ public void nestedObjectArrayWithoutTypeInformation() {
+ NestedObject input = new NestedObject();
+ input.value = new String[]{"a", "b", "c"};
+
+ final VPack vpack = new VPack.Builder().useTypeHints(useTypeHints).build();
+ final VPackSlice slice = vpack.serialize(input);
+ assertThat(slice.isObject(), is(true));
+ assertThat(slice.get("value").isArray(), is(true));
+ if (!useTypeHints)
+ assertThat(slice.get("_class").isNone(), is(true));
+
+ NestedObject output = vpack.deserialize(slice, NestedObject.class);
+ assertThat(output.value, instanceOf(List.class));
+
+ assertThat(((List>) output.value).toArray(), equalTo(input.value));
+ }
+
+ @Test
+ public void nestedObjectMapWithoutTypeInformation() {
+ Map map = new HashMap<>();
+ map.put("a", "b");
+
+ NestedObject input = new NestedObject();
+ input.value = map;
+
+ final VPack vpack = new VPack.Builder().useTypeHints(useTypeHints).build();
+ final VPackSlice slice = vpack.serialize(input);
+ assertThat(slice.isObject(), is(true));
+ assertThat(slice.get("value").isObject(), is(true));
+ if (!useTypeHints) {
+ assertThat(slice.get("_class").isNone(), is(true));
+ assertThat(slice.get("value").get("_class").isNone(), is(true));
+ }
+
+ NestedObject output = vpack.deserialize(slice, NestedObject.class);
+ assertThat(output.value, instanceOf(Map.class));
+
+ ((Map, ?>) output.value).remove("_class");
+ assertThat(output.value, equalTo(input.value));
+ }
+
+ public static class NestedGeneric {
+ public T value;
+ }
+
+ @Test
+ public void nestedGenericOfArrayWithoutTypeInformation() {
+ NestedGeneric input = new NestedGeneric<>();
+ input.value = new String[]{"a", "b", "c"};
+
+ final VPack vpack = new VPack.Builder().useTypeHints(useTypeHints).build();
+ final VPackSlice slice = vpack.serialize(input);
+
+ assertThat(slice.isObject(), is(true));
+ assertThat(slice.get("value").isArray(), is(true));
+ if (!useTypeHints)
+ assertThat(slice.get("_class").isNone(), is(true));
+
+ NestedGeneric> output = vpack.deserialize(slice, NestedGeneric.class);
+ assertThat(output.value, instanceOf(List.class));
+
+ assertThat(output.value, equalTo(Arrays.asList(input.value)));
+ }
+
+ @Test
+ public void nestedGenericOfIterableWithoutTypeInformation() {
+ NestedGeneric> input = new NestedGeneric<>();
+ input.value = Arrays.asList("a", "b", "c");
+
+ final VPack vpack = new VPack.Builder().useTypeHints(useTypeHints).build();
+ final VPackSlice slice = vpack.serialize(input);
+
+ assertThat(slice.isObject(), is(true));
+ assertThat(slice.get("value").isArray(), is(true));
+ if (!useTypeHints)
+ assertThat(slice.get("_class").isNone(), is(true));
+
+ NestedGeneric> output = vpack.deserialize(slice, NestedGeneric.class);
+ assertThat(output.value, instanceOf(List.class));
+
+ assertThat(output.value, equalTo(input.value));
+ }
+
+ @Test
+ public void nestedGenericOfCollectionWithoutTypeInformation() {
+ NestedGeneric> input = new NestedGeneric<>();
+ input.value = Arrays.asList("a", "b", "c");
+
+ final VPack vpack = new VPack.Builder().useTypeHints(useTypeHints).build();
+ final VPackSlice slice = vpack.serialize(input);
+
+ assertThat(slice.isObject(), is(true));
+ assertThat(slice.get("value").isArray(), is(true));
+ if (!useTypeHints)
+ assertThat(slice.get("_class").isNone(), is(true));
+
+ NestedGeneric> output = vpack.deserialize(slice, NestedGeneric.class);
+ assertThat(output.value, instanceOf(List.class));
+
+ assertThat(output.value, equalTo(input.value));
+ }
+
+ @Test
+ public void nestedGenericOfMapWithoutTypeInformation() {
+ Map map = new HashMap<>();
+ map.put("a", "b");
+
+ NestedGeneric