From ce6592d2d50b0f8e69b5cdb6004a63ba334ea643 Mon Sep 17 00:00:00 2001 From: Sebastian Mandrean Date: Thu, 26 Mar 2026 01:37:22 +0100 Subject: [PATCH 1/4] fix(java): fix async meta-shared layer jit bootstrap for ObjectStreamSerializer --- .../org/apache/fory/builder/CodecUtils.java | 44 ++++-- .../builder/MetaSharedLayerCodecBuilder.java | 28 ++-- .../ObjectStreamSerializerTest.java | 146 ++++++++++++++++++ 3 files changed, 192 insertions(+), 26 deletions(-) diff --git a/java/fory-core/src/main/java/org/apache/fory/builder/CodecUtils.java b/java/fory-core/src/main/java/org/apache/fory/builder/CodecUtils.java index eeb582fb2a..7a36cecd42 100644 --- a/java/fory-core/src/main/java/org/apache/fory/builder/CodecUtils.java +++ b/java/fory-core/src/main/java/org/apache/fory/builder/CodecUtils.java @@ -40,6 +40,10 @@ public class CodecUtils { // Cache key includes configHash to distinguish between xlang and non-xlang modes private static final ConcurrentHashMap, Integer>, Class> graalvmSerializers = new ConcurrentHashMap<>(); + // Generated layer serializers need the original layer metadata to bootstrap their delegate + // synchronously in the constructor. + private static final ConcurrentHashMap, MetaSharedLayerCodecContext> + metaSharedLayerCodecContexts = new ConcurrentHashMap<>(); // TODO(chaokunyang) how to uninstall org.apache.fory.codegen/builder classes for graalvm build // time @@ -78,16 +82,26 @@ public static Class> loadOrGenMetaSharedCodecClass( public static Class> loadOrGenMetaSharedLayerCodecClass( Class cls, Fory fory, TypeDef layerTypeDef, Class layerMarkerClass) { Preconditions.checkNotNull(fory); - return loadSerializer( - "loadOrGenMetaSharedLayerCodecClass", - cls, - fory, - () -> - loadOrGenCodecClass( - cls, - fory, - new MetaSharedLayerCodecBuilder( - TypeRef.of(cls), fory, layerTypeDef, layerMarkerClass))); + Class> serializerClass = + loadSerializer( + "loadOrGenMetaSharedLayerCodecClass", + cls, + fory, + () -> + loadOrGenCodecClass( + cls, + fory, + new MetaSharedLayerCodecBuilder( + TypeRef.of(cls), fory, layerTypeDef, layerMarkerClass))); + if (!GraalvmSupport.IN_GRAALVM_NATIVE_IMAGE) { + metaSharedLayerCodecContexts.putIfAbsent( + serializerClass, new MetaSharedLayerCodecContext(layerTypeDef, layerMarkerClass)); + } + return serializerClass; + } + + static MetaSharedLayerCodecContext getMetaSharedLayerCodecContext(Class serializerClass) { + return metaSharedLayerCodecContexts.get(serializerClass); } @SuppressWarnings("unchecked") @@ -171,4 +185,14 @@ private static Class> loadSerializer( throw new RuntimeException(e); } } + + static final class MetaSharedLayerCodecContext { + final TypeDef layerTypeDef; + final Class layerMarkerClass; + + MetaSharedLayerCodecContext(TypeDef layerTypeDef, Class layerMarkerClass) { + this.layerTypeDef = layerTypeDef; + this.layerMarkerClass = layerMarkerClass; + } + } } diff --git a/java/fory-core/src/main/java/org/apache/fory/builder/MetaSharedLayerCodecBuilder.java b/java/fory-core/src/main/java/org/apache/fory/builder/MetaSharedLayerCodecBuilder.java index 1c0d6faf84..1b49eb9f12 100644 --- a/java/fory-core/src/main/java/org/apache/fory/builder/MetaSharedLayerCodecBuilder.java +++ b/java/fory-core/src/main/java/org/apache/fory/builder/MetaSharedLayerCodecBuilder.java @@ -32,10 +32,8 @@ import org.apache.fory.memory.MemoryBuffer; import org.apache.fory.meta.TypeDef; import org.apache.fory.reflect.TypeRef; -import org.apache.fory.serializer.CodegenSerializer; import org.apache.fory.serializer.MetaSharedLayerSerializer; import org.apache.fory.serializer.MetaSharedLayerSerializerBase; -import org.apache.fory.serializer.Serializers; import org.apache.fory.type.Descriptor; import org.apache.fory.type.DescriptorGrouper; import org.apache.fory.util.ExceptionUtils; @@ -132,22 +130,20 @@ protected void addCommonImports() { @SuppressWarnings({"unchecked", "rawtypes"}) public static MetaSharedLayerSerializerBase setCodegenSerializer( Fory fory, Class cls, GeneratedMetaSharedLayerSerializer s) { - if (GraalvmSupport.isGraalRuntime()) { + if (GraalvmSupport.IN_GRAALVM_NATIVE_IMAGE) { return (MetaSharedLayerSerializerBase) typeResolver(fory, r -> r.getSerializer(s.getType())); } - // This method hold jit lock, so create jit serializer async to avoid block serialization. - // Use MetaSharedLayerSerializer as fallback since it's compatible with - // MetaSharedLayerSerializerBase - Class serializerClass = - fory.getJITContext() - .registerSerializerJITCallback( - () -> MetaSharedLayerSerializer.class, - () -> CodegenSerializer.loadCodegenSerializer(fory, s.getType()), - c -> - s.serializer = - (MetaSharedLayerSerializerBase) - Serializers.newSerializer(fory, s.getType(), c)); - return (MetaSharedLayerSerializerBase) Serializers.newSerializer(fory, cls, serializerClass); + // Layer serializers don't have a generic no-arg/newSerializer construction path. The + // outer ObjectStreamSerializer JIT step already resolved the layer TypeDef and marker, so + // generated serializers look up that cached context here and bootstrap the interpreter + // delegate synchronously in their constructor. + CodecUtils.MetaSharedLayerCodecContext context = + CodecUtils.getMetaSharedLayerCodecContext(s.getClass()); + Preconditions.checkNotNull( + context, "Missing layer codec context for generated serializer " + s.getClass()); + s.serializer = + new MetaSharedLayerSerializer(fory, cls, context.layerTypeDef, context.layerMarkerClass); + return s.serializer; } @Override diff --git a/java/fory-core/src/test/java/org/apache/fory/serializer/ObjectStreamSerializerTest.java b/java/fory-core/src/test/java/org/apache/fory/serializer/ObjectStreamSerializerTest.java index 35e4b2625f..de3fd54adc 100644 --- a/java/fory-core/src/test/java/org/apache/fory/serializer/ObjectStreamSerializerTest.java +++ b/java/fory-core/src/test/java/org/apache/fory/serializer/ObjectStreamSerializerTest.java @@ -39,14 +39,18 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.TreeMap; +import java.util.TreeSet; import java.util.Vector; import java.util.concurrent.ConcurrentHashMap; import lombok.EqualsAndHashCode; import org.apache.fory.Fory; import org.apache.fory.ForyTestBase; +import org.apache.fory.builder.Generated; import org.apache.fory.config.CompatibleMode; import org.apache.fory.config.Language; import org.apache.fory.memory.MemoryBuffer; +import org.apache.fory.reflect.ReflectionUtils; import org.apache.fory.util.Preconditions; import org.testng.Assert; import org.testng.annotations.DataProvider; @@ -1136,6 +1140,107 @@ public void testNestedObjectSerialization(CompatibleMode compatible) { assertEquals(result.nestedList.get(1).nestedValue, "list2"); } + public static class AsyncTreeSetSubclass extends TreeSet { + public AsyncTreeSetSubclass() {} + } + + public static class AsyncTreeMapSubclass extends TreeMap { + public AsyncTreeMapSubclass() {} + } + + @EqualsAndHashCode + public static class AsyncLayerJitContainer implements Serializable { + private String name; + private AsyncTreeSetSubclass values; + private AsyncTreeMapSubclass attributes; + + public AsyncLayerJitContainer() {} + + public AsyncLayerJitContainer( + String name, AsyncTreeSetSubclass values, AsyncTreeMapSubclass attributes) { + this.name = name; + this.values = values; + this.attributes = attributes; + } + + private void writeObject(ObjectOutputStream s) throws IOException { + s.defaultWriteObject(); + } + + private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { + s.defaultReadObject(); + } + } + + @Test(timeOut = 60000) + public void testAsyncCompilationNestedTreeCollectionsCompatibleMode() + throws InterruptedException { + Fory fory = newCompatibleAsyncObjectStreamFory(true); + fory.registerSerializer( + AsyncLayerJitContainer.class, + new ObjectStreamSerializer(fory, AsyncLayerJitContainer.class)); + fory.registerSerializer( + AsyncTreeSetSubclass.class, new ObjectStreamSerializer(fory, AsyncTreeSetSubclass.class)); + fory.registerSerializer( + AsyncTreeMapSubclass.class, new ObjectStreamSerializer(fory, AsyncTreeMapSubclass.class)); + + AsyncTreeSetSubclass values = new AsyncTreeSetSubclass(); + values.add("one"); + values.add("two"); + AsyncTreeMapSubclass attributes = new AsyncTreeMapSubclass(); + attributes.put("alpha", "A"); + attributes.put("beta", "B"); + AsyncLayerJitContainer obj = new AsyncLayerJitContainer("container", values, attributes); + + serDeCheckSerializer(fory, obj, "ObjectStreamSerializer"); + + waitForGeneratedLayerSerializer(fory, AsyncLayerJitContainer.class); + waitForGeneratedLayerSerializer(fory, AsyncTreeSetSubclass.class); + waitForGeneratedLayerSerializer(fory, AsyncTreeMapSubclass.class); + + serDeCheckSerializer(fory, obj, "ObjectStreamSerializer"); + } + + @Test(timeOut = 60000) + public void testAsyncCompilationTreeSetSubclassObjectStreamSerializer() + throws InterruptedException { + Fory fory = newCompatibleAsyncObjectStreamFory(true); + fory.registerSerializer( + AsyncTreeSetSubclass.class, new ObjectStreamSerializer(fory, AsyncTreeSetSubclass.class)); + + AsyncTreeSetSubclass values = new AsyncTreeSetSubclass(); + values.add("one"); + values.add("two"); + + serDeCheckSerializer(fory, values, "ObjectStreamSerializer"); + waitForGeneratedLayerSerializer(fory, AsyncTreeSetSubclass.class); + serDeCheckSerializer(fory, values, "ObjectStreamSerializer"); + } + + @Test + public void testTreeCollectionsStillWorkWithoutAsyncCompilation() { + Fory fory = newCompatibleAsyncObjectStreamFory(false); + fory.registerSerializer( + AsyncLayerJitContainer.class, + new ObjectStreamSerializer(fory, AsyncLayerJitContainer.class)); + fory.registerSerializer( + AsyncTreeSetSubclass.class, new ObjectStreamSerializer(fory, AsyncTreeSetSubclass.class)); + fory.registerSerializer( + AsyncTreeMapSubclass.class, new ObjectStreamSerializer(fory, AsyncTreeMapSubclass.class)); + + AsyncTreeSetSubclass values = new AsyncTreeSetSubclass(); + values.add("one"); + values.add("two"); + AsyncTreeMapSubclass attributes = new AsyncTreeMapSubclass(); + attributes.put("alpha", "A"); + attributes.put("beta", "B"); + + serDeCheckSerializer( + fory, + new AsyncLayerJitContainer("container", values, attributes), + "ObjectStreamSerializer"); + } + // ==================== Circular Reference in Custom Serialization ==================== /** Class with potential circular reference. */ @@ -1279,4 +1384,45 @@ public void testAllPrimitiveTypes(CompatibleMode compatible) { assertEquals(result.charVal, 'A'); assertEquals(result.boolVal, true); } + + private Fory newCompatibleAsyncObjectStreamFory(boolean asyncCompilation) { + return Fory.builder() + .withLanguage(Language.JAVA) + .requireClassRegistration(false) + .withRefTracking(true) + .withCodegen(true) + .withCompatibleMode(CompatibleMode.COMPATIBLE) + .withAsyncCompilation(asyncCompilation) + .build(); + } + + private void waitForGeneratedLayerSerializer(Fory fory, Class type) + throws InterruptedException { + long deadline = System.currentTimeMillis() + 30_000; + while (System.currentTimeMillis() < deadline) { + if (hasGeneratedLayerSerializer(fory, type)) { + return; + } + Thread.sleep(10); + } + Assert.fail("Timed out waiting for generated layer serializer for " + type.getName()); + } + + private boolean hasGeneratedLayerSerializer(Fory fory, Class type) { + Serializer serializer = fory.getTypeResolver().getSerializer(type); + if (!(serializer instanceof ObjectStreamSerializer)) { + return false; + } + Object[] slotsInfos = (Object[]) ReflectionUtils.getObjectFieldValue(serializer, "slotsInfos"); + if (slotsInfos.length == 0) { + return false; + } + for (Object slotsInfo : slotsInfos) { + Object slotsSerializer = ReflectionUtils.getObjectFieldValue(slotsInfo, "slotsSerializer"); + if (!(slotsSerializer instanceof Generated)) { + return false; + } + } + return true; + } } From 5b46630a4a30657584da870c0b198ff058c863b0 Mon Sep 17 00:00:00 2001 From: Sebastian Mandrean Date: Thu, 26 Mar 2026 11:49:57 +0100 Subject: [PATCH 2/4] docs: comment --- .../main/java/org/apache/fory/builder/CodecUtils.java | 2 ++ .../apache/fory/builder/MetaSharedLayerCodecBuilder.java | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/java/fory-core/src/main/java/org/apache/fory/builder/CodecUtils.java b/java/fory-core/src/main/java/org/apache/fory/builder/CodecUtils.java index 7a36cecd42..5313f72776 100644 --- a/java/fory-core/src/main/java/org/apache/fory/builder/CodecUtils.java +++ b/java/fory-core/src/main/java/org/apache/fory/builder/CodecUtils.java @@ -42,6 +42,8 @@ public class CodecUtils { graalvmSerializers = new ConcurrentHashMap<>(); // Generated layer serializers need the original layer metadata to bootstrap their delegate // synchronously in the constructor. + // This is a process-lifetime cache keyed by generated serializer class, which mirrors the + // existing codegen cache behavior and is populated only on the regular JVM path. private static final ConcurrentHashMap, MetaSharedLayerCodecContext> metaSharedLayerCodecContexts = new ConcurrentHashMap<>(); diff --git a/java/fory-core/src/main/java/org/apache/fory/builder/MetaSharedLayerCodecBuilder.java b/java/fory-core/src/main/java/org/apache/fory/builder/MetaSharedLayerCodecBuilder.java index 1b49eb9f12..7dc4dc1b61 100644 --- a/java/fory-core/src/main/java/org/apache/fory/builder/MetaSharedLayerCodecBuilder.java +++ b/java/fory-core/src/main/java/org/apache/fory/builder/MetaSharedLayerCodecBuilder.java @@ -130,6 +130,9 @@ protected void addCommonImports() { @SuppressWarnings({"unchecked", "rawtypes"}) public static MetaSharedLayerSerializerBase setCodegenSerializer( Fory fory, Class cls, GeneratedMetaSharedLayerSerializer s) { + // In native-image mode, including build time, do not rely on the cached layer bootstrap + // context. We only populate that cache on the regular JVM path, so native-image execution + // must resolve through the type resolver instead. if (GraalvmSupport.IN_GRAALVM_NATIVE_IMAGE) { return (MetaSharedLayerSerializerBase) typeResolver(fory, r -> r.getSerializer(s.getType())); } @@ -140,7 +143,11 @@ public static MetaSharedLayerSerializerBase setCodegenSerializer( CodecUtils.MetaSharedLayerCodecContext context = CodecUtils.getMetaSharedLayerCodecContext(s.getClass()); Preconditions.checkNotNull( - context, "Missing layer codec context for generated serializer " + s.getClass()); + context, + "Missing layer codec context for generated serializer " + + s.getClass() + + "; loadOrGenMetaSharedLayerCodecClass should cache it before serializer" + + " instantiation."); s.serializer = new MetaSharedLayerSerializer(fory, cls, context.layerTypeDef, context.layerMarkerClass); return s.serializer; From 22703293366e69bfdcee71a68737a4206c26af18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=85=95=E7=99=BD?= Date: Wed, 1 Apr 2026 22:47:39 +0800 Subject: [PATCH 3/4] fix(java): remove nested layer codec bootstrap JIT --- .../org/apache/fory/builder/CodecUtils.java | 46 ++++--------------- .../builder/MetaSharedLayerCodecBuilder.java | 46 +++++++++---------- 2 files changed, 31 insertions(+), 61 deletions(-) diff --git a/java/fory-core/src/main/java/org/apache/fory/builder/CodecUtils.java b/java/fory-core/src/main/java/org/apache/fory/builder/CodecUtils.java index 5313f72776..eeb582fb2a 100644 --- a/java/fory-core/src/main/java/org/apache/fory/builder/CodecUtils.java +++ b/java/fory-core/src/main/java/org/apache/fory/builder/CodecUtils.java @@ -40,12 +40,6 @@ public class CodecUtils { // Cache key includes configHash to distinguish between xlang and non-xlang modes private static final ConcurrentHashMap, Integer>, Class> graalvmSerializers = new ConcurrentHashMap<>(); - // Generated layer serializers need the original layer metadata to bootstrap their delegate - // synchronously in the constructor. - // This is a process-lifetime cache keyed by generated serializer class, which mirrors the - // existing codegen cache behavior and is populated only on the regular JVM path. - private static final ConcurrentHashMap, MetaSharedLayerCodecContext> - metaSharedLayerCodecContexts = new ConcurrentHashMap<>(); // TODO(chaokunyang) how to uninstall org.apache.fory.codegen/builder classes for graalvm build // time @@ -84,26 +78,16 @@ public static Class> loadOrGenMetaSharedCodecClass( public static Class> loadOrGenMetaSharedLayerCodecClass( Class cls, Fory fory, TypeDef layerTypeDef, Class layerMarkerClass) { Preconditions.checkNotNull(fory); - Class> serializerClass = - loadSerializer( - "loadOrGenMetaSharedLayerCodecClass", - cls, - fory, - () -> - loadOrGenCodecClass( - cls, - fory, - new MetaSharedLayerCodecBuilder( - TypeRef.of(cls), fory, layerTypeDef, layerMarkerClass))); - if (!GraalvmSupport.IN_GRAALVM_NATIVE_IMAGE) { - metaSharedLayerCodecContexts.putIfAbsent( - serializerClass, new MetaSharedLayerCodecContext(layerTypeDef, layerMarkerClass)); - } - return serializerClass; - } - - static MetaSharedLayerCodecContext getMetaSharedLayerCodecContext(Class serializerClass) { - return metaSharedLayerCodecContexts.get(serializerClass); + return loadSerializer( + "loadOrGenMetaSharedLayerCodecClass", + cls, + fory, + () -> + loadOrGenCodecClass( + cls, + fory, + new MetaSharedLayerCodecBuilder( + TypeRef.of(cls), fory, layerTypeDef, layerMarkerClass))); } @SuppressWarnings("unchecked") @@ -187,14 +171,4 @@ private static Class> loadSerializer( throw new RuntimeException(e); } } - - static final class MetaSharedLayerCodecContext { - final TypeDef layerTypeDef; - final Class layerMarkerClass; - - MetaSharedLayerCodecContext(TypeDef layerTypeDef, Class layerMarkerClass) { - this.layerTypeDef = layerTypeDef; - this.layerMarkerClass = layerMarkerClass; - } - } } diff --git a/java/fory-core/src/main/java/org/apache/fory/builder/MetaSharedLayerCodecBuilder.java b/java/fory-core/src/main/java/org/apache/fory/builder/MetaSharedLayerCodecBuilder.java index 7dc4dc1b61..07c0979b89 100644 --- a/java/fory-core/src/main/java/org/apache/fory/builder/MetaSharedLayerCodecBuilder.java +++ b/java/fory-core/src/main/java/org/apache/fory/builder/MetaSharedLayerCodecBuilder.java @@ -37,7 +37,6 @@ import org.apache.fory.type.Descriptor; import org.apache.fory.type.DescriptorGrouper; import org.apache.fory.util.ExceptionUtils; -import org.apache.fory.util.GraalvmSupport; import org.apache.fory.util.Preconditions; import org.apache.fory.util.StringUtils; @@ -55,7 +54,6 @@ */ public class MetaSharedLayerCodecBuilder extends ObjectCodecBuilder { private final TypeDef layerTypeDef; - private final Class layerMarkerClass; public MetaSharedLayerCodecBuilder( TypeRef beanType, Fory fory, TypeDef layerTypeDef, Class layerMarkerClass) { @@ -64,7 +62,6 @@ public MetaSharedLayerCodecBuilder( !fory.getConfig().checkClassVersion(), "Class version check should be disabled when compatible mode is enabled."); this.layerTypeDef = layerTypeDef; - this.layerMarkerClass = layerMarkerClass; Collection descriptors = layerTypeDef.getDescriptors(typeResolver, beanClass); DescriptorGrouper grouper = typeResolver(r -> r.createDescriptorGrouper(descriptors, false)); objectCodecOptimizer = new ObjectCodecOptimizer(beanClass, grouper, false, ctx); @@ -101,13 +98,15 @@ public String genCode() { "" + "super(${fory}, ${cls});\n" + "this.${fory} = ${fory};\n" - + "${serializer} = ${builderClass}.setCodegenSerializer(${fory}, ${cls}, this);\n", + + "${serializer} = ${builderClass}.setCodegenSerializer(${fory}, ${cls}, ${layerTypeDefBytes});\n", "fory", FORY_NAME, "cls", POJO_CLASS_TYPE_NAME, "builderClass", MetaSharedLayerCodecBuilder.class.getName(), + "layerTypeDefBytes", + toByteArrayLiteral(layerTypeDef.getEncoded()), "serializer", SERIALIZER_FIELD_NAME); ctx.clearExprState(); @@ -129,28 +128,25 @@ protected void addCommonImports() { // Invoked by JIT. @SuppressWarnings({"unchecked", "rawtypes"}) public static MetaSharedLayerSerializerBase setCodegenSerializer( - Fory fory, Class cls, GeneratedMetaSharedLayerSerializer s) { - // In native-image mode, including build time, do not rely on the cached layer bootstrap - // context. We only populate that cache on the regular JVM path, so native-image execution - // must resolve through the type resolver instead. - if (GraalvmSupport.IN_GRAALVM_NATIVE_IMAGE) { - return (MetaSharedLayerSerializerBase) typeResolver(fory, r -> r.getSerializer(s.getType())); + Fory fory, Class cls, byte[] encodedLayerTypeDef) { + MemoryBuffer buffer = MemoryBuffer.fromByteArray(encodedLayerTypeDef); + TypeDef layerTypeDef = TypeDef.readTypeDef(fory, buffer, buffer.readInt64()); + return new MetaSharedLayerSerializer( + fory, cls, layerTypeDef, LayerMarkerClassGenerator.getOrCreate(fory, cls, 0)); + } + + private static String toByteArrayLiteral(byte[] bytes) { + if (bytes.length == 0) { + return "new byte[0]"; + } + StringBuilder builder = new StringBuilder("new byte[] {"); + for (int i = 0; i < bytes.length; i++) { + if (i > 0) { + builder.append(", "); + } + builder.append(bytes[i]); } - // Layer serializers don't have a generic no-arg/newSerializer construction path. The - // outer ObjectStreamSerializer JIT step already resolved the layer TypeDef and marker, so - // generated serializers look up that cached context here and bootstrap the interpreter - // delegate synchronously in their constructor. - CodecUtils.MetaSharedLayerCodecContext context = - CodecUtils.getMetaSharedLayerCodecContext(s.getClass()); - Preconditions.checkNotNull( - context, - "Missing layer codec context for generated serializer " - + s.getClass() - + "; loadOrGenMetaSharedLayerCodecClass should cache it before serializer" - + " instantiation."); - s.serializer = - new MetaSharedLayerSerializer(fory, cls, context.layerTypeDef, context.layerMarkerClass); - return s.serializer; + return builder.append("}").toString(); } @Override From c08b7338e9c811a966f5ca57ba9b1f7ae73b3b90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=85=95=E7=99=BD?= Date: Wed, 1 Apr 2026 23:29:47 +0800 Subject: [PATCH 4/4] Use cached TypeDef ids for layer codec bootstrap --- .../builder/MetaSharedLayerCodecBuilder.java | 32 ++++++------------- .../apache/fory/resolver/TypeResolver.java | 4 +++ 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/java/fory-core/src/main/java/org/apache/fory/builder/MetaSharedLayerCodecBuilder.java b/java/fory-core/src/main/java/org/apache/fory/builder/MetaSharedLayerCodecBuilder.java index b117f9c67b..eae9775272 100644 --- a/java/fory-core/src/main/java/org/apache/fory/builder/MetaSharedLayerCodecBuilder.java +++ b/java/fory-core/src/main/java/org/apache/fory/builder/MetaSharedLayerCodecBuilder.java @@ -60,9 +60,9 @@ public MetaSharedLayerCodecBuilder( Preconditions.checkArgument( !fory.getConfig().checkClassVersion(), "Class version check should be disabled when compatible mode is enabled."); - this.layerTypeDef = layerTypeDef; + this.layerTypeDef = fory.getTypeResolver().cacheTypeDef(layerTypeDef); DescriptorGrouper grouper = - typeResolver(r -> r.createDescriptorGrouper(layerTypeDef, beanClass)); + typeResolver(r -> r.createDescriptorGrouper(this.layerTypeDef, beanClass)); objectCodecOptimizer = new ObjectCodecOptimizer(beanClass, grouper, false, ctx); } @@ -97,15 +97,15 @@ public String genCode() { "" + "super(${fory}, ${cls});\n" + "this.${fory} = ${fory};\n" - + "${serializer} = ${builderClass}.setCodegenSerializer(${fory}, ${cls}, ${layerTypeDefBytes});\n", + + "${serializer} = ${builderClass}.setCodegenSerializer(${fory}, ${cls}, ${layerTypeDefId});\n", "fory", FORY_NAME, "cls", POJO_CLASS_TYPE_NAME, "builderClass", MetaSharedLayerCodecBuilder.class.getName(), - "layerTypeDefBytes", - toByteArrayLiteral(layerTypeDef.getEncoded()), + "layerTypeDefId", + layerTypeDef.getId() + "L", "serializer", SERIALIZER_FIELD_NAME); ctx.clearExprState(); @@ -127,27 +127,15 @@ protected void addCommonImports() { // Invoked by JIT. @SuppressWarnings({"unchecked", "rawtypes"}) public static MetaSharedLayerSerializerBase setCodegenSerializer( - Fory fory, Class cls, byte[] encodedLayerTypeDef) { - MemoryBuffer buffer = MemoryBuffer.fromByteArray(encodedLayerTypeDef); - TypeDef layerTypeDef = TypeDef.readTypeDef(fory, buffer, buffer.readInt64()); + Fory fory, Class cls, long layerTypeDefId) { + TypeDef layerTypeDef = + Preconditions.checkNotNull( + fory.getTypeResolver().getTypeDefById(layerTypeDefId), + "Missing cached layer TypeDef for id " + layerTypeDefId + " and class " + cls); return new MetaSharedLayerSerializer( fory, cls, layerTypeDef, LayerMarkerClassGenerator.getOrCreate(fory, cls, 0)); } - private static String toByteArrayLiteral(byte[] bytes) { - if (bytes.length == 0) { - return "new byte[0]"; - } - StringBuilder builder = new StringBuilder("new byte[] {"); - for (int i = 0; i < bytes.length; i++) { - if (i > 0) { - builder.append(", "); - } - builder.append(bytes[i]); - } - return builder.append("}").toString(); - } - @Override public Expression buildEncodeExpression() { throw new IllegalStateException("unreachable"); diff --git a/java/fory-core/src/main/java/org/apache/fory/resolver/TypeResolver.java b/java/fory-core/src/main/java/org/apache/fory/resolver/TypeResolver.java index 8adac5e2a7..17eee9a971 100644 --- a/java/fory-core/src/main/java/org/apache/fory/resolver/TypeResolver.java +++ b/java/fory-core/src/main/java/org/apache/fory/resolver/TypeResolver.java @@ -1119,6 +1119,10 @@ public final TypeDef cacheTypeDef(TypeDef typeDef) { return sharedRegistry.getOrCreateTypeDef(typeDef); } + public final TypeDef getTypeDefById(long typeDefId) { + return sharedRegistry.typeDefById.get(typeDefId); + } + public final boolean isSerializable(Class cls) { // Enums are always serializable, even if abstract (enums with abstract methods) if (cls.isEnum()) {