diff --git a/java/fury-core/src/main/java/org/apache/fury/exception/DeserializationException.java b/java/fury-core/src/main/java/org/apache/fury/exception/DeserializationException.java index 11d9691ad2..562d18b058 100644 --- a/java/fury-core/src/main/java/org/apache/fury/exception/DeserializationException.java +++ b/java/fury-core/src/main/java/org/apache/fury/exception/DeserializationException.java @@ -48,7 +48,18 @@ public String getMessage() { if (readObjects == null) { return super.getMessage(); } else { - return "Deserialize failed, read objects are: " + readObjects; + try { + return "Deserialize failed, read objects are: " + readObjects; + } catch (Throwable e) { + StringBuilder builder = + new StringBuilder("Deserialize failed, type of read objects are: ["); + for (Object readObject : readObjects) { + builder.append(readObject == null ? null : readObject.getClass()).append(", "); + } + builder.delete(builder.length() - 2, 2); + builder.append("]"); + return builder.toString(); + } } } } diff --git a/java/fury-core/src/main/java/org/apache/fury/meta/ClassDef.java b/java/fury-core/src/main/java/org/apache/fury/meta/ClassDef.java index 35fb467d00..1b6177e004 100644 --- a/java/fury-core/src/main/java/org/apache/fury/meta/ClassDef.java +++ b/java/fury-core/src/main/java/org/apache/fury/meta/ClassDef.java @@ -23,6 +23,7 @@ import static org.apache.fury.type.TypeUtils.COLLECTION_TYPE; import static org.apache.fury.type.TypeUtils.MAP_TYPE; import static org.apache.fury.type.TypeUtils.collectionOf; +import static org.apache.fury.type.TypeUtils.getArrayComponent; import static org.apache.fury.type.TypeUtils.mapOf; import java.io.ObjectStreamClass; @@ -242,7 +243,8 @@ public List getDescriptors(ClassResolver resolver, Class cls) { if (rawType.isEnum() || rawType.isAssignableFrom(descriptor.getRawType()) || NonexistentClass.isNonexistent(rawType) - || rawType.isAssignableFrom(FinalObjectTypeStub.class)) { + || rawType == FinalObjectTypeStub.class + || (rawType.isArray() && getArrayComponent(rawType) == FinalObjectTypeStub.class)) { descriptor = descriptor.copyWithTypeName(newDesc.getTypeName()); descriptors.add(descriptor); } else { 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 186a60df18..3160850ceb 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 @@ -1560,6 +1560,10 @@ public void writeClassInternal(MemoryBuffer buffer, Class cls) { classInfo = new ClassInfo(this, cls, null, null, classId == null ? NO_CLASS_ID : classId); classInfoMap.put(cls, classInfo); } + writeClassInternal(buffer, classInfo); + } + + public void writeClassInternal(MemoryBuffer buffer, ClassInfo classInfo) { short classId = classInfo.classId; if (classId == REPLACE_STUB_ID) { // clear class id to avoid replaced class written as diff --git a/java/fury-core/src/main/java/org/apache/fury/serializer/ReplaceResolveSerializer.java b/java/fury-core/src/main/java/org/apache/fury/serializer/ReplaceResolveSerializer.java index dfac24d8dc..e958669e8e 100644 --- a/java/fury-core/src/main/java/org/apache/fury/serializer/ReplaceResolveSerializer.java +++ b/java/fury-core/src/main/java/org/apache/fury/serializer/ReplaceResolveSerializer.java @@ -268,7 +268,7 @@ public void write(MemoryBuffer buffer, Object value) { } private void writeObject(MemoryBuffer buffer, Object value, MethodInfoCache jdkMethodInfoCache) { - classResolver.writeClass(buffer, writeClassInfo); + classResolver.writeClassInternal(buffer, writeClassInfo); jdkMethodInfoCache.objectSerializer.write(buffer, value); } diff --git a/scala/build.sbt b/scala/build.sbt index 92a5c6b6ef..1addf1dfdb 100644 --- a/scala/build.sbt +++ b/scala/build.sbt @@ -45,4 +45,5 @@ resolvers += Resolver.ApacheMavenSnapshotsRepo libraryDependencies ++= Seq( "org.apache.fury" % "fury-core" % furyVersion, "org.scalatest" %% "scalatest" % "3.2.19" % Test, + "dev.zio" %% "zio" % "2.1.7" % Test, ) diff --git a/scala/src/test/scala/org/apache/fury/serializer/CollectionSerializerTest.scala b/scala/src/test/scala/org/apache/fury/serializer/scala/CollectionSerializerTest.scala similarity index 97% rename from scala/src/test/scala/org/apache/fury/serializer/CollectionSerializerTest.scala rename to scala/src/test/scala/org/apache/fury/serializer/scala/CollectionSerializerTest.scala index 772f60b4a1..b86662adee 100644 --- a/scala/src/test/scala/org/apache/fury/serializer/CollectionSerializerTest.scala +++ b/scala/src/test/scala/org/apache/fury/serializer/scala/CollectionSerializerTest.scala @@ -17,11 +17,10 @@ * under the License. */ -package org.apache.fury.serializer +package org.apache.fury.serializer.scala import org.apache.fury.Fury import org.apache.fury.config.Language -import org.apache.fury.serializer.scala.ScalaDispatcher import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec 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 new file mode 100644 index 0000000000..1b8afc8565 --- /dev/null +++ b/scala/src/test/scala/org/apache/fury/serializer/scala/CompatibleSingleObjectSerializerTest.scala @@ -0,0 +1,76 @@ +/* + * 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.config.CompatibleMode +import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpec +import zio.Chunk + +import scala.collection.immutable.ArraySeq + +object SingletonObject { + case object Query + + case class ArraySeqQuery(c: ArraySeq[Query.type]) + + case class ArrayQuery(c: Array[Query.type]) + + case class CaseChunk(c: Chunk[Int]) +} + +class CompatibleSingleObjectSerializerTest extends AnyWordSpec with Matchers { + def fury: Fury = { + org.apache.fury.Fury + .builder() + .withScalaOptimizationEnabled(true) + .requireClassRegistration(false) + .withRefTracking(true) + .withCompatibleMode(CompatibleMode.COMPATIBLE) + .build() + } + + "fury scala object support" should { + "serialize/deserialize" in { + fury.deserialize(fury.serialize(singleton)) shouldBe singleton + fury.deserialize(fury.serialize(Pair(singleton, singleton))) shouldEqual Pair(singleton, singleton) + } + "nested type serialization in object type" in { + val x = A.B.C("hello, world!") + val bytes = fury.serialize(x) + 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 + } + "testArrayQuery" in { + val o = SingletonObject.ArrayQuery(Array(SingletonObject.Query)) + fury.deserialize(fury.serialize(o)).getClass shouldEqual o.getClass + } + "testCaseChunk" in { + val o = SingletonObject.CaseChunk(Chunk(1)) + fury.deserialize(fury.serialize(o)) shouldEqual o + } + } +} diff --git a/scala/src/test/scala/org/apache/fury/serializer/ScalaTest.scala b/scala/src/test/scala/org/apache/fury/serializer/scala/ScalaTest.scala similarity index 98% rename from scala/src/test/scala/org/apache/fury/serializer/ScalaTest.scala rename to scala/src/test/scala/org/apache/fury/serializer/scala/ScalaTest.scala index b91f392932..9a391dce31 100644 --- a/scala/src/test/scala/org/apache/fury/serializer/ScalaTest.scala +++ b/scala/src/test/scala/org/apache/fury/serializer/scala/ScalaTest.scala @@ -17,7 +17,7 @@ * under the License. */ -package org.apache.fury.serializer +package org.apache.fury.serializer.scala import org.apache.fury.Fury import org.apache.fury.config.Language diff --git a/scala/src/test/scala/org/apache/fury/serializer/SingleObjectSerializerTest.scala b/scala/src/test/scala/org/apache/fury/serializer/scala/SingleObjectSerializerTest.scala similarity index 98% rename from scala/src/test/scala/org/apache/fury/serializer/SingleObjectSerializerTest.scala rename to scala/src/test/scala/org/apache/fury/serializer/scala/SingleObjectSerializerTest.scala index 5d7901e151..9976f67935 100644 --- a/scala/src/test/scala/org/apache/fury/serializer/SingleObjectSerializerTest.scala +++ b/scala/src/test/scala/org/apache/fury/serializer/scala/SingleObjectSerializerTest.scala @@ -17,7 +17,7 @@ * under the License. */ -package org.apache.fury.serializer +package org.apache.fury.serializer.scala import org.apache.fury.Fury import org.apache.fury.config.Language diff --git a/scala/src/test/scala/org/apache/fury/serializer/TupleTest.scala b/scala/src/test/scala/org/apache/fury/serializer/scala/TupleTest.scala similarity index 98% rename from scala/src/test/scala/org/apache/fury/serializer/TupleTest.scala rename to scala/src/test/scala/org/apache/fury/serializer/scala/TupleTest.scala index be129206c7..a02931f177 100644 --- a/scala/src/test/scala/org/apache/fury/serializer/TupleTest.scala +++ b/scala/src/test/scala/org/apache/fury/serializer/scala/TupleTest.scala @@ -17,7 +17,7 @@ * under the License. */ -package org.apache.fury.serializer +package org.apache.fury.serializer.scala import org.apache.fury.Fury import org.apache.fury.config.Language