diff --git a/java/fory-core/src/main/java/org/apache/fory/resolver/ClassResolver.java b/java/fory-core/src/main/java/org/apache/fory/resolver/ClassResolver.java index e53910260a..e9ed3df48a 100644 --- a/java/fory-core/src/main/java/org/apache/fory/resolver/ClassResolver.java +++ b/java/fory-core/src/main/java/org/apache/fory/resolver/ClassResolver.java @@ -1350,7 +1350,9 @@ public Class getSerializerClass(Class cls, boolean code if (serializerClass != null) { return serializerClass; } - if (requireJavaSerialization(cls) || useReplaceResolveSerializer(cls)) { + if (Externalizable.class.isAssignableFrom(cls) + || requireJavaSerialization(cls) + || useReplaceResolveSerializer(cls)) { return CollectionSerializers.JDKCompatibleCollectionSerializer.class; } if (!isCrossLanguage()) { @@ -1364,7 +1366,9 @@ public Class getSerializerClass(Class cls, boolean code if (serializerClass != null) { return serializerClass; } - if (requireJavaSerialization(cls) || useReplaceResolveSerializer(cls)) { + if (Externalizable.class.isAssignableFrom(cls) + || requireJavaSerialization(cls) + || useReplaceResolveSerializer(cls)) { return MapSerializers.JDKCompatibleMapSerializer.class; } if (!isCrossLanguage()) { diff --git a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/CollectionSerializers.java b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/CollectionSerializers.java index cc77cebe27..9d33c3acef 100644 --- a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/CollectionSerializers.java +++ b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/CollectionSerializers.java @@ -19,6 +19,7 @@ package org.apache.fory.serializer.collection; +import java.io.Externalizable; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.reflect.Field; @@ -60,6 +61,7 @@ import org.apache.fory.resolver.TypeInfo; import org.apache.fory.resolver.TypeInfoHolder; import org.apache.fory.resolver.TypeResolver; +import org.apache.fory.serializer.ExternalizableSerializer; import org.apache.fory.serializer.ReplaceResolveSerializer; import org.apache.fory.serializer.Serializer; import org.apache.fory.serializer.Serializers; @@ -949,7 +951,9 @@ public JDKCompatibleCollectionSerializer(TypeResolver typeResolver, Class cls Class serializerType = ClassResolver.useReplaceResolveSerializer(cls) ? ReplaceResolveSerializer.class - : config.getDefaultJDKStreamSerializerType(); + : Externalizable.class.isAssignableFrom(cls) + ? ExternalizableSerializer.class + : config.getDefaultJDKStreamSerializerType(); serializer = Serializers.newSerializer(typeResolver, cls, serializerType); } diff --git a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/MapSerializers.java b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/MapSerializers.java index cb44da66ca..ab8688d6aa 100644 --- a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/MapSerializers.java +++ b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/MapSerializers.java @@ -19,6 +19,7 @@ package org.apache.fory.serializer.collection; +import java.io.Externalizable; import java.lang.invoke.MethodHandle; import java.util.Collection; import java.util.Collections; @@ -43,6 +44,7 @@ import org.apache.fory.resolver.ClassResolver; import org.apache.fory.resolver.TypeInfo; import org.apache.fory.resolver.TypeResolver; +import org.apache.fory.serializer.ExternalizableSerializer; import org.apache.fory.serializer.ReplaceResolveSerializer; import org.apache.fory.serializer.Serializer; import org.apache.fory.serializer.Serializers; @@ -459,7 +461,9 @@ public JDKCompatibleMapSerializer(TypeResolver typeResolver, Class cls) { Class serializerType = ClassResolver.useReplaceResolveSerializer(cls) ? ReplaceResolveSerializer.class - : config.getDefaultJDKStreamSerializerType(); + : Externalizable.class.isAssignableFrom(cls) + ? ExternalizableSerializer.class + : config.getDefaultJDKStreamSerializerType(); serializer = Serializers.newSerializer(typeResolver, cls, serializerType); } diff --git a/java/fory-core/src/test/java/org/apache/fory/serializer/collection/MapSerializersTest.java b/java/fory-core/src/test/java/org/apache/fory/serializer/collection/MapSerializersTest.java index ca594b8849..b1548c7fc4 100644 --- a/java/fory-core/src/test/java/org/apache/fory/serializer/collection/MapSerializersTest.java +++ b/java/fory-core/src/test/java/org/apache/fory/serializer/collection/MapSerializersTest.java @@ -26,6 +26,10 @@ import static org.testng.Assert.assertEquals; import com.google.common.collect.ImmutableMap; +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; import java.io.Serializable; import java.util.AbstractMap; import java.util.ArrayList; @@ -832,6 +836,63 @@ public Object put(String key, Object value) { } } + public static class ExternalizableStringMap extends AbstractMap + implements Externalizable { + private transient Map data = new LinkedHashMap<>(); + + public ExternalizableStringMap() {} + + @Override + public Set> entrySet() { + return data.entrySet(); + } + + @Override + public String put(String key, String value) { + return data.put(key, value); + } + + @Override + public void writeExternal(ObjectOutput out) throws IOException { + out.writeInt(size()); + for (Map.Entry entry : entrySet()) { + out.writeObject(entry.getKey()); + out.writeObject(entry.getValue()); + } + } + + @Override + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + data = new LinkedHashMap<>(); + int size = in.readInt(); + for (int i = 0; i < size; i++) { + put((String) in.readObject(), (String) in.readObject()); + } + } + } + + public static class ExternalizableMapHolder { + public Map data = new ExternalizableStringMap(); + } + + @Test(dataProvider = "enableCodegen") + public void testExternalizableMapCompatibleMode(boolean enableCodegen) { + Fory fory = + builder() + .withLanguage(Language.JAVA) + .withCompatibleMode(CompatibleMode.COMPATIBLE) + .withCodegen(enableCodegen) + .requireClassRegistration(false) + .build(); + ExternalizableMapHolder holder = new ExternalizableMapHolder(); + holder.data.put("k", "v"); + + ExternalizableMapHolder deserialized = serDe(fory, holder); + Assert.assertEquals(deserialized.data.getClass(), ExternalizableStringMap.class); + Assert.assertEquals(deserialized.data, holder.data); + Assert.assertEquals(deserialized.data.get("k"), "v"); + } + @Test(dataProvider = "enableCodegen") public void testDefaultMapSerializer(boolean enableCodegen) { Fory fory =