This is an automated email from the ASF dual-hosted git repository.
chaokunyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fury.git
The following commit(s) were added to refs/heads/main by this push:
new 3d559292 feat(scala): optimize scala class serialization (#1853)
3d559292 is described below
commit 3d559292233ae6734fef103703e6972eb39b7840
Author: Shawn Yang <[email protected]>
AuthorDate: Wed Sep 25 00:47:28 2024 -0700
feat(scala): optimize scala class serialization (#1853)
## What does this PR do?
- Optimize scala Iterable type serialization
- Reduce type name writing for msot scala collection and factory types
- Add serializers for ToFactory type
## Related issues
<!--
Is there any related issue? Please attach here.
- #xxxx0
- #xxxx1
- #xxxx2
-->
## Does this PR introduce any user-facing change?
<!--
If any user-facing interface changes, please [open an
issue](https://github.com/apache/fury/issues/new/choose) describing the
need to do so and update the document if necessary.
-->
- [ ] Does this PR introduce any public API change?
- [ ] Does this PR introduce any binary protocol compatibility change?
## Benchmark
<!--
When the PR has an impact on performance (if you don't know whether the
PR will have an impact on performance, you can submit the PR first, and
if it will have impact on performance, the code reviewer will explain
it), be sure to attach a benchmark data here.
-->
---
.../java/org/apache/fury/config/FuryBuilder.java | 11 ++
.../org/apache/fury/resolver/ClassResolver.java | 19 ++-
.../fury/serializer/scala/ScalaDispatcher.java | 2 +
.../fury/serializer/scala/ScalaSerializers.java | 172 +++++++++++++++++++++
.../serializer/scala/ToFactorySerializers.java | 97 ++++++++++++
.../scala/CollectionSerializerTest.scala | 7 +-
.../CompatibleSingleObjectSerializerTest.scala | 9 +-
...scala => MutableCollectionSerializerTest.scala} | 60 +++----
.../apache/fury/serializer/scala/ScalaTest.scala | 16 +-
9 files changed, 352 insertions(+), 41 deletions(-)
diff --git
a/java/fury-core/src/main/java/org/apache/fury/config/FuryBuilder.java
b/java/fury-core/src/main/java/org/apache/fury/config/FuryBuilder.java
index 1210c751..c27a6124 100644
--- a/java/fury-core/src/main/java/org/apache/fury/config/FuryBuilder.java
+++ b/java/fury-core/src/main/java/org/apache/fury/config/FuryBuilder.java
@@ -30,6 +30,7 @@ import org.apache.fury.memory.Platform;
import org.apache.fury.meta.DeflaterMetaCompressor;
import org.apache.fury.meta.MetaCompressor;
import org.apache.fury.pool.ThreadPoolFury;
+import org.apache.fury.reflect.ReflectionUtils;
import org.apache.fury.resolver.ClassResolver;
import org.apache.fury.serializer.JavaSerializer;
import org.apache.fury.serializer.ObjectStreamSerializer;
@@ -316,6 +317,16 @@ public final class FuryBuilder {
/** Whether enable scala-specific serialization optimization. */
public FuryBuilder withScalaOptimizationEnabled(boolean
enableScalaOptimization) {
this.scalaOptimizationEnabled = enableScalaOptimization;
+ if (enableScalaOptimization) {
+ try {
+ Class.forName(
+ ReflectionUtils.getPackage(Fury.class) +
".serializer.scala.ScalaSerializers");
+ } catch (ClassNotFoundException e) {
+ LOG.warn(
+ "`fury-scala` library is not in the classpath, please add it to
class path and invoke "
+ +
"`org.apache.fury.serializer.scala.ScalaSerializers.registerSerializers` for
peek performance");
+ }
+ }
return this;
}
diff --git
a/java/fury-core/src/main/java/org/apache/fury/resolver/ClassResolver.java
b/java/fury-core/src/main/java/org/apache/fury/resolver/ClassResolver.java
index 06748a04..21adfb76 100644
--- a/java/fury-core/src/main/java/org/apache/fury/resolver/ClassResolver.java
+++ b/java/fury-core/src/main/java/org/apache/fury/resolver/ClassResolver.java
@@ -409,6 +409,10 @@ public class ClassResolver {
}
}
+ public void register(String className) {
+ register(loadClass(className, false, 0, false));
+ }
+
public void register(Class<?>... classes) {
for (Class<?> cls : classes) {
register(cls);
@@ -481,6 +485,10 @@ public class ClassResolver {
extRegistry.classIdGenerator++;
}
+ public void register(String className, int classId) {
+ register(loadClass(className, false, 0, false), classId);
+ }
+
public void register(Class<?> cls, Short id, boolean createSerializer) {
register(cls, id);
if (createSerializer) {
@@ -488,6 +496,10 @@ public class ClassResolver {
}
}
+ public void register(String className, Short classId, boolean
createSerializer) {
+ register(loadClass(className, false, 0, false), classId, createSerializer);
+ }
+
public boolean isRegistered(Class<?> cls) {
return extRegistry.registeredClassIdMap.get(cls) != null;
}
@@ -1807,6 +1819,11 @@ public class ClassResolver {
}
private Class<?> loadClass(String className, boolean isEnum, int arrayDims) {
+ return loadClass(className, isEnum, arrayDims,
fury.getConfig().deserializeNonexistentClass());
+ }
+
+ private Class<?> loadClass(
+ String className, boolean isEnum, int arrayDims, boolean
deserializeNonexistentClass) {
extRegistry.classChecker.checkClass(this, className);
try {
return Class.forName(className, false, fury.getClassLoader());
@@ -1818,7 +1835,7 @@ public class ClassResolver {
String.format(
"Class %s not found from classloaders [%s, %s]",
className, fury.getClassLoader(),
Thread.currentThread().getContextClassLoader());
- if (fury.getConfig().deserializeNonexistentClass()) {
+ if (deserializeNonexistentClass) {
LOG.warn(msg);
return NonexistentClass.getNonexistentClass(
className, isEnum, arrayDims, metaContextShareEnabled);
diff --git
a/scala/src/main/java/org/apache/fury/serializer/scala/ScalaDispatcher.java
b/scala/src/main/java/org/apache/fury/serializer/scala/ScalaDispatcher.java
index 4f43f34b..34074606 100644
--- a/scala/src/main/java/org/apache/fury/serializer/scala/ScalaDispatcher.java
+++ b/scala/src/main/java/org/apache/fury/serializer/scala/ScalaDispatcher.java
@@ -51,6 +51,8 @@ public class ScalaDispatcher implements SerializerFactory {
return new ScalaSortedSetSerializer(fury, clz);
} else if (scala.collection.Seq.class.isAssignableFrom(clz)) {
return new ScalaSeqSerializer(fury, clz);
+ } else if (scala.collection.Iterable.class.isAssignableFrom(clz)) {
+ return new ScalaCollectionSerializer(fury, clz);
}
if (DefaultSerializable.class.isAssignableFrom(clz)) {
Method replaceMethod = JavaSerializer.getWriteReplaceMethod(clz);
diff --git
a/scala/src/main/java/org/apache/fury/serializer/scala/ScalaSerializers.java
b/scala/src/main/java/org/apache/fury/serializer/scala/ScalaSerializers.java
new file mode 100644
index 00000000..5cfdcd89
--- /dev/null
+++ b/scala/src/main/java/org/apache/fury/serializer/scala/ScalaSerializers.java
@@ -0,0 +1,172 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+package org.apache.fury.serializer.scala;
+
+import org.apache.fury.Fury;
+import org.apache.fury.resolver.ClassResolver;
+import org.apache.fury.serializer.Serializer;
+import org.apache.fury.serializer.SerializerFactory;
+import scala.collection.immutable.NumericRange;
+import scala.collection.immutable.Range;
+
+import static
org.apache.fury.serializer.scala.ToFactorySerializers.IterableToFactoryClass;
+import static
org.apache.fury.serializer.scala.ToFactorySerializers.MapToFactoryClass;
+
+public class ScalaSerializers {
+
+ public static void registerSerializers(Fury fury) {
+ ClassResolver resolver = setSerializerFactory(fury);
+
+ resolver.registerSerializer(IterableToFactoryClass, new
ToFactorySerializers.IterableToFactorySerializer(fury));
+ resolver.registerSerializer(MapToFactoryClass, new
ToFactorySerializers.MapToFactorySerializer(fury));
+
+ // Seq
+ resolver.register(scala.collection.immutable.Seq.class);
+ resolver.register(scala.collection.immutable.Nil$.class);
+ resolver.register(scala.collection.immutable.List$.class);
+ resolver.register(scala.collection.immutable.$colon$colon.class);
+ // StrictOptimizedSeqFactory -> ... extends -> IterableFactory
+ resolver.register(scala.collection.immutable.Vector$.class);
+ resolver.register("scala.collection.immutable.VectorImpl");
+ resolver.register("scala.collection.immutable.Vector0");
+ resolver.register("scala.collection.immutable.Vector1");
+ resolver.register("scala.collection.immutable.Vector2");
+ resolver.register("scala.collection.immutable.Vector3");
+ resolver.register("scala.collection.immutable.Vector4");
+ resolver.register("scala.collection.immutable.Vector5");
+ resolver.register("scala.collection.immutable.Vector6");
+ resolver.register(scala.collection.immutable.Queue.class);
+ resolver.register(scala.collection.immutable.Queue$.class);
+ resolver.register(scala.collection.immutable.LazyList.class);
+ resolver.register(scala.collection.immutable.LazyList$.class);
+ resolver.register(scala.collection.immutable.ArraySeq.class);
+ resolver.register(scala.collection.immutable.ArraySeq$.class);
+
+ // Set
+ resolver.register(scala.collection.immutable.Set.class);
+ // IterableFactory
+ resolver.register(scala.collection.immutable.Set$.class);
+ resolver.register(scala.collection.immutable.Set.Set1.class);
+ resolver.register(scala.collection.immutable.Set.Set2.class);
+ resolver.register(scala.collection.immutable.Set.Set3.class);
+ resolver.register(scala.collection.immutable.Set.Set4.class);
+ resolver.register(scala.collection.immutable.HashSet.class);
+ resolver.register(scala.collection.immutable.TreeSet.class);
+ // SortedIterableFactory
+ resolver.register(scala.collection.immutable.TreeSet$.class);
+ // IterableFactory
+ resolver.register(scala.collection.immutable.HashSet$.class);
+ resolver.register(scala.collection.immutable.ListSet.class);
+ resolver.register(scala.collection.immutable.ListSet$.class);
+ resolver.register("scala.collection.immutable.Set$EmptySet$");
+ resolver.register("scala.collection.immutable.SetBuilderImpl");
+
resolver.register("scala.collection.immutable.SortedMapOps$ImmutableKeySortedSet");
+
+ // Map
+ resolver.register(scala.collection.immutable.Map.class);
+ resolver.register(scala.collection.immutable.Map$.class);
+ resolver.register(scala.collection.immutable.Map.Map1.class);
+ resolver.register(scala.collection.immutable.Map.Map2.class);
+ resolver.register(scala.collection.immutable.Map.Map3.class);
+ resolver.register(scala.collection.immutable.Map.Map4.class);
+ resolver.register(scala.collection.immutable.Map.WithDefault.class);
+ resolver.register("scala.collection.immutable.MapBuilderImpl");
+ resolver.register("scala.collection.immutable.Map$EmptyMap$");
+ resolver.register("scala.collection.immutable.SeqMap$EmptySeqMap$");
+ resolver.register(scala.collection.immutable.HashMap.class);
+ resolver.register(scala.collection.immutable.HashMap$.class);
+ resolver.register(scala.collection.immutable.TreeMap.class);
+ resolver.register(scala.collection.immutable.TreeMap$.class);
+ resolver.register(scala.collection.immutable.SortedMap$.class);
+ resolver.register(scala.collection.immutable.TreeSeqMap.class);
+ resolver.register(scala.collection.immutable.TreeSeqMap$.class);
+ resolver.register(scala.collection.immutable.ListMap.class);
+ resolver.register(scala.collection.immutable.ListMap$.class);
+ resolver.register(scala.collection.immutable.IntMap.class);
+ resolver.register(scala.collection.immutable.IntMap$.class);
+ resolver.register(scala.collection.immutable.LongMap.class);
+ resolver.register(scala.collection.immutable.LongMap$.class);
+
+ // Range
+ resolver.register(Range.Inclusive.class);
+ resolver.register(Range.Exclusive.class);
+ resolver.register(NumericRange.class);
+ resolver.register(NumericRange.Inclusive.class);
+ resolver.register(NumericRange.Exclusive.class);
+
+ resolver.register(scala.collection.generic.SerializeEnd$.class);
+
resolver.register(scala.collection.generic.DefaultSerializationProxy.class);
+ resolver.register(scala.runtime.ModuleSerializationProxy.class);
+
+ // mutable collection types
+ resolver.register(scala.collection.mutable.StringBuilder.class);
+ resolver.register(scala.collection.mutable.ArrayBuffer.class);
+ resolver.register(scala.collection.mutable.ArrayBuffer$.class);
+ resolver.register(scala.collection.mutable.ArraySeq.class);
+ resolver.register(scala.collection.mutable.ArraySeq$.class);
+ resolver.register(scala.collection.mutable.ListBuffer.class);
+ resolver.register(scala.collection.mutable.ListBuffer$.class);
+ resolver.register(scala.collection.mutable.Buffer$.class);
+ resolver.register(scala.collection.mutable.ArrayDeque.class);
+ resolver.register(scala.collection.mutable.ArrayDeque$.class);
+
+ resolver.register(scala.collection.mutable.HashSet.class);
+ resolver.register(scala.collection.mutable.HashSet$.class);
+ resolver.register(scala.collection.mutable.TreeSet.class);
+ resolver.register(scala.collection.mutable.TreeSet$.class);
+
+ resolver.register(scala.collection.mutable.HashMap.class);
+ resolver.register(scala.collection.mutable.HashMap$.class);
+ resolver.register(scala.collection.mutable.TreeMap.class);
+ resolver.register(scala.collection.mutable.TreeMap$.class);
+ resolver.register(scala.collection.mutable.LinkedHashMap.class);
+ resolver.register(scala.collection.mutable.LinkedHashMap$.class);
+ resolver.register(scala.collection.mutable.LinkedHashSet.class);
+ resolver.register(scala.collection.mutable.LinkedHashSet$.class);
+ resolver.register(scala.collection.mutable.LongMap.class);
+ resolver.register(scala.collection.mutable.LongMap$.class);
+
+ resolver.register(scala.collection.mutable.Queue.class);
+ resolver.register(scala.collection.mutable.Queue$.class);
+ resolver.register(scala.collection.mutable.Stack.class);
+ resolver.register(scala.collection.mutable.Stack$.class);
+ resolver.register(scala.collection.mutable.BitSet.class);
+ resolver.register(scala.collection.mutable.BitSet$.class);
+ }
+
+ private static ClassResolver setSerializerFactory(Fury fury) {
+ ClassResolver resolver = fury.getClassResolver();
+ ScalaDispatcher dispatcher = new ScalaDispatcher();
+ SerializerFactory factory = resolver.getSerializerFactory();
+ if (factory != null) {
+ SerializerFactory newFactory = (f, cls) -> {
+ Serializer serializer = factory.createSerializer(f, cls);
+ if (serializer == null) {
+ serializer = dispatcher.createSerializer(f, cls);
+ }
+ return serializer;
+ };
+ resolver.setSerializerFactory(newFactory);
+ } else {
+ resolver.setSerializerFactory(dispatcher);
+ }
+ return resolver;
+ }
+}
diff --git
a/scala/src/main/java/org/apache/fury/serializer/scala/ToFactorySerializers.java
b/scala/src/main/java/org/apache/fury/serializer/scala/ToFactorySerializers.java
new file mode 100644
index 00000000..a800b98a
--- /dev/null
+++
b/scala/src/main/java/org/apache/fury/serializer/scala/ToFactorySerializers.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+package org.apache.fury.serializer.scala;
+
+import org.apache.fury.Fury;
+import org.apache.fury.memory.MemoryBuffer;
+import org.apache.fury.memory.Platform;
+import org.apache.fury.reflect.ReflectionUtils;
+import org.apache.fury.serializer.Serializer;
+
+import java.lang.reflect.Field;
+
+public class ToFactorySerializers {
+ static final Class<?> IterableToFactoryClass = ReflectionUtils.loadClass(
+ "scala.collection.IterableFactory$ToFactory");
+ static final Class<?> MapToFactoryClass = ReflectionUtils.loadClass(
+ "scala.collection.MapFactory$ToFactory");
+
+ public static class IterableToFactorySerializer extends Serializer {
+ private static final long fieldOffset;
+
+ static {
+ try {
+ // for graalvm field offset auto rewrite
+ Field field =
Class.forName("scala.collection.IterableFactory$ToFactory").getDeclaredField("factory");
+ fieldOffset = Platform.objectFieldOffset(field);
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public IterableToFactorySerializer(Fury fury) {
+ super(fury, IterableToFactoryClass);
+ }
+
+ @Override
+ public void write(MemoryBuffer buffer, Object value) {
+ fury.writeRef(buffer, Platform.getObject(value, fieldOffset));
+ }
+
+ @Override
+ public Object read(MemoryBuffer buffer) {
+ Object o = Platform.newInstance(type);
+ Platform.putObject(o, fieldOffset, fury.readRef(buffer));
+ return o;
+ }
+ }
+
+ public static class MapToFactorySerializer extends Serializer {
+ private static final long fieldOffset;
+
+ static {
+ try {
+ // for graalvm field offset auto rewrite
+ Field field =
Class.forName("scala.collection.MapFactory$ToFactory").getDeclaredField("factory");
+ fieldOffset = Platform.objectFieldOffset(field);
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public MapToFactorySerializer(Fury fury) {
+ super(fury, MapToFactoryClass);
+ }
+
+ @Override
+ public void write(MemoryBuffer buffer, Object value) {
+ fury.writeRef(buffer, Platform.getObject(value, fieldOffset));
+ }
+
+ @Override
+ public Object read(MemoryBuffer buffer) {
+ Object o = Platform.newInstance(type);
+ Platform.putObject(o, fieldOffset, fury.readRef(buffer));
+ return o;
+ }
+ }
+
+
+}
diff --git
a/scala/src/test/scala/org/apache/fury/serializer/scala/CollectionSerializerTest.scala
b/scala/src/test/scala/org/apache/fury/serializer/scala/CollectionSerializerTest.scala
index b86662ad..041447bb 100644
---
a/scala/src/test/scala/org/apache/fury/serializer/scala/CollectionSerializerTest.scala
+++
b/scala/src/test/scala/org/apache/fury/serializer/scala/CollectionSerializerTest.scala
@@ -31,7 +31,10 @@ class CollectionSerializerTest extends AnyWordSpec with
Matchers {
.withLanguage(Language.JAVA)
.withRefTracking(true)
.withScalaOptimizationEnabled(setOpt)
- .requireClassRegistration(false).build()
+ .requireClassRegistration(false)
+ .suppressClassRegistrationWarnings(false)
+ .build()
+ ScalaSerializers.registerSerializers(fury1)
if (setFactory) {
fury1.getClassResolver.setSerializerFactory(new ScalaDispatcher())
}
@@ -43,6 +46,8 @@ class CollectionSerializerTest extends AnyWordSpec with
Matchers {
"serialize/deserialize List" in {
val list = List(100, 10000L)
fury1.deserialize(fury1.serialize(list)) shouldEqual list
+ val list2 = List(100, 10000L, 10000L, 10000L)
+ fury1.deserialize(fury1.serialize(list2)) shouldEqual list2
}
"serialize/deserialize empty List" in {
fury1.deserialize(fury1.serialize(List.empty)) shouldEqual List.empty
diff --git
a/scala/src/test/scala/org/apache/fury/serializer/scala/CompatibleSingleObjectSerializerTest.scala
b/scala/src/test/scala/org/apache/fury/serializer/scala/CompatibleSingleObjectSerializerTest.scala
index 1b8afc85..f9c5cf25 100644
---
a/scala/src/test/scala/org/apache/fury/serializer/scala/CompatibleSingleObjectSerializerTest.scala
+++
b/scala/src/test/scala/org/apache/fury/serializer/scala/CompatibleSingleObjectSerializerTest.scala
@@ -45,6 +45,7 @@ class CompatibleSingleObjectSerializerTest extends
AnyWordSpec with Matchers {
.requireClassRegistration(false)
.withRefTracking(true)
.withCompatibleMode(CompatibleMode.COMPATIBLE)
+ .suppressClassRegistrationWarnings(false)
.build()
}
@@ -59,10 +60,10 @@ class CompatibleSingleObjectSerializerTest extends
AnyWordSpec with Matchers {
fury.deserialize(bytes) shouldEqual A.B.C("hello, world!")
}
"testArraySeqQuery" in {
- val o = SingletonObject.ArraySeqQuery(ArraySeq(SingletonObject.Query))
- fury.deserialize(
- fury.serialize(
- o)) shouldEqual o
+ val o = SingletonObject.ArraySeqQuery(ArraySeq(SingletonObject.Query))
+ fury.deserialize(
+ fury.serialize(
+ o)) shouldEqual o
}
"testArrayQuery" in {
val o = SingletonObject.ArrayQuery(Array(SingletonObject.Query))
diff --git
a/scala/src/test/scala/org/apache/fury/serializer/scala/CollectionSerializerTest.scala
b/scala/src/test/scala/org/apache/fury/serializer/scala/MutableCollectionSerializerTest.scala
similarity index 55%
copy from
scala/src/test/scala/org/apache/fury/serializer/scala/CollectionSerializerTest.scala
copy to
scala/src/test/scala/org/apache/fury/serializer/scala/MutableCollectionSerializerTest.scala
index b86662ad..bea24cb1 100644
---
a/scala/src/test/scala/org/apache/fury/serializer/scala/CollectionSerializerTest.scala
+++
b/scala/src/test/scala/org/apache/fury/serializer/scala/MutableCollectionSerializerTest.scala
@@ -24,74 +24,78 @@ import org.apache.fury.config.Language
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpec
-class CollectionSerializerTest extends AnyWordSpec with Matchers {
- val params: Seq[(Boolean, Boolean)] = List((false, false), (false, true),
(true, false), (true, true))
+import scala.collection.{Seq, Map, Set, mutable}
+import scala.collection.mutable.ListBuffer
+
+class MutableCollectionSerializerTest extends AnyWordSpec with Matchers {
+ val params: Seq[(Boolean, Boolean)] = List( (true, true))
params.foreach{case (setOpt, setFactory) => {
val fury1: Fury = Fury.builder()
.withLanguage(Language.JAVA)
.withRefTracking(true)
.withScalaOptimizationEnabled(setOpt)
- .requireClassRegistration(false).build()
+ .requireClassRegistration(false)
+ .suppressClassRegistrationWarnings(false)
+ .build()
if (setFactory) {
- fury1.getClassResolver.setSerializerFactory(new ScalaDispatcher())
+ ScalaSerializers.registerSerializers(fury1)
}
s"fury scala collection support: setOpt $setOpt, setFactory $setFactory"
should {
"serialize/deserialize Seq" in {
- val seq = Seq(100, 10000L)
+ val seq = mutable.Seq(100, 10000L)
fury1.deserialize(fury1.serialize(seq)) shouldEqual seq
}
"serialize/deserialize List" in {
- val list = List(100, 10000L)
+ val list = mutable.ListBuffer(100, 10000L)
fury1.deserialize(fury1.serialize(list)) shouldEqual list
+ val list2 = mutable.ListBuffer(100, 10000L, 10000L, 10000L)
+ fury1.deserialize(fury1.serialize(list2)) shouldEqual list2
}
"serialize/deserialize empty List" in {
- fury1.deserialize(fury1.serialize(List.empty)) shouldEqual List.empty
- fury1.deserialize(fury1.serialize(Nil)) shouldEqual Nil
+ fury1.deserialize(fury1.serialize(ListBuffer.empty)) shouldEqual
ListBuffer.empty
}
"serialize/deserialize Set" in {
- val set = Set(100, 10000L)
+ val set = mutable.Set(100, 10000L)
fury1.deserialize(fury1.serialize(set)) shouldEqual set
}
- "serialize/deserialize CollectionStruct1" in {
- val struct = CollectionStruct1(List("a", "b"))
+ "serialize/deserialize CollectionStruct2" in {
+ val struct = CollectionStruct2(mutable.ListBuffer("a", "b"))
fury1.deserialize(fury1.serialize(struct)) shouldEqual struct
}
- "serialize/deserialize CollectionStruct1 with empty List" in {
- val struct1 = CollectionStruct1(List.empty)
+ "serialize/deserialize CollectionStruct2 with empty List" in {
+ val struct1 = CollectionStruct2(ListBuffer.empty)
fury1.deserialize(fury1.serialize(struct1)) shouldEqual struct1
- val struct2 = CollectionStruct1(Nil)
- fury1.deserialize(fury1.serialize(struct2)) shouldEqual struct2
}
- "serialize/deserialize NestedCollectionStruct" in {
- val struct = NestedCollectionStruct(List(List("a", "b"), List("a",
"b")), Set(Set("c", "d")))
+ "serialize/deserialize NestedCollectionStruct1" in {
+ val struct = NestedCollectionStruct1(ListBuffer(ListBuffer("a", "b"),
ListBuffer("a", "b")), mutable.Set(Set("c", "d")))
fury1.deserialize(fury1.serialize(struct)) shouldEqual struct
}
}
s"fury scala map support: setOpt $setOpt, setFactory $setFactory" should {
"serialize/deserialize Map" in {
- val map = Map("a" -> 100, "b" -> 10000L)
+ val map = mutable.Map("a" -> 100, "b" -> 10000L)
fury1.deserialize(fury1.serialize(map)) shouldEqual map
}
- "serialize/deserialize MapStruct1" in {
- val struct = MapStruct1(Map("k1" -> "v1", "k2" -> "v2"))
+ "serialize/deserialize MapStruct2" in {
+ val struct = MapStruct2(mutable.Map("k1" -> "v1", "k2" -> "v2"))
fury1.deserialize(fury1.serialize(struct)) shouldEqual struct
}
- "serialize/deserialize MapStruct1 with empty map" in {
- val struct = MapStruct1(Map.empty)
+ "serialize/deserialize MapStruct2 with empty map" in {
+ val struct = MapStruct2(mutable.Map.empty)
fury1.deserialize(fury1.serialize(struct)) shouldEqual struct
}
- "serialize/deserialize NestedMapStruct" in {
- val struct = NestedMapStruct(Map("K1" -> Map("k1" -> "v1", "k2" ->
"v2"), "K2" -> Map("k1" -> "v1")))
+ "serialize/deserialize NestedMapStruc1" in {
+ val struct = NestedMapStruc1(mutable.Map("K1" -> mutable.Map("k1" ->
"v1", "k2" -> "v2"), "K2" -> mutable.Map("k1" -> "v1")))
fury1.deserialize(fury1.serialize(struct)) shouldEqual struct
}
}
}}
}
-case class CollectionStruct1(list: List[String])
+case class CollectionStruct2(list: Seq[String])
-case class NestedCollectionStruct(list: List[List[String]], set:
Set[Set[String]])
+case class NestedCollectionStruct1(list: Seq[Seq[String]], set:
Set[Set[String]])
-case class MapStruct1(map: Map[String, String])
+case class MapStruct2(map: Map[String, String])
-case class NestedMapStruct(map: Map[String, Map[String, String]])
+case class NestedMapStruc1(map: Map[String, Map[String, String]])
diff --git
a/scala/src/test/scala/org/apache/fury/serializer/scala/ScalaTest.scala
b/scala/src/test/scala/org/apache/fury/serializer/scala/ScalaTest.scala
index 9a391dce..8e094ee9 100644
--- a/scala/src/test/scala/org/apache/fury/serializer/scala/ScalaTest.scala
+++ b/scala/src/test/scala/org/apache/fury/serializer/scala/ScalaTest.scala
@@ -29,14 +29,15 @@ package object SomePackageObject {
}
class ScalaTest extends AnyWordSpec with Matchers {
+ def fury: Fury = Fury.builder()
+ .withLanguage(Language.JAVA)
+ .withRefTracking(true)
+ .withScalaOptimizationEnabled(true)
+ .requireClassRegistration(false)
+ .suppressClassRegistrationWarnings(false).build()
+
"fury scala support" should {
"serialize/deserialize package object" in {
- val fury = Fury.builder()
- .withLanguage(Language.JAVA)
- .withRefTracking(true)
- .withScalaOptimizationEnabled(true)
- .requireClassRegistration(false).build()
-
val p = SomePackageObject.SomeClass(1)
fury.deserialize(fury.serialize(p)) shouldEqual p
}
@@ -61,7 +62,7 @@ object PkgObjectMain extends App {
.builder()
.withScalaOptimizationEnabled(true)
.requireClassRegistration(false)
- .withRefTracking(true)
+ .withRefTracking(true).suppressClassRegistrationWarnings(false)
.build()
import PkgObject._
@@ -81,6 +82,7 @@ object PkgObjectMain2 extends App {
.withScalaOptimizationEnabled(true)
.requireClassRegistration(false)
.withRefTracking(true)
+ .suppressClassRegistrationWarnings(false)
.build()
import PkgObject._
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]