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/fory.git
The following commit(s) were added to refs/heads/main by this push:
new 93e47c68c fix(java): fix meta share deserialization for register
(#2667)
93e47c68c is described below
commit 93e47c68c81bf250a1718c9b0c763050dbfb516e
Author: Shawn Yang <[email protected]>
AuthorDate: Fri Sep 26 19:26:19 2025 +0800
fix(java): fix meta share deserialization for register (#2667)
## Why?
<!-- Describe the purpose of this PR. -->
## What does this PR do?
1. fix meta share deserialization for register
2. Add register by class name
## Related issues
Fixes #2666
Closes #2605
## Does this PR introduce any user-facing change?
<!--
If any user-facing interface changes, please [open an
issue](https://github.com/apache/fory/issues/new/choose) describing the
need to do so and update the document if necessary.
Delete section if not applicable.
-->
- [ ] 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.
Delete section if not applicable.
-->
---
docs/guide/graalvm_guide.md | 23 +++----
.../java/org/apache/fory/graalvm/ArrayExample.java | 3 +-
.../java/org/apache/fory/graalvm/Benchmark.java | 10 +--
.../org/apache/fory/graalvm/CompatibleExample.java | 3 +-
.../fory/graalvm/CompatibleThreadSafeExample.java | 3 +-
.../main/java/org/apache/fory/graalvm/Example.java | 3 +-
.../apache/fory/graalvm/ObjectStreamExample.java | 2 +-
.../java/org/apache/fory/graalvm/ProxyExample.java | 2 +-
.../fory/graalvm/ScopedCompatibleExample.java | 3 +-
.../org/apache/fory/graalvm/ThreadSafeExample.java | 3 +-
.../graalvm/record/CompatibleRecordExample.java | 3 +-
.../apache/fory/graalvm/record/RecordExample.java | 3 +-
.../apache/fory/graalvm/record/RecordExample2.java | 5 +-
.../org/apache/fory/AbstractThreadSafeFory.java | 16 +++++
.../src/main/java/org/apache/fory/BaseFory.java | 35 +++++++++--
.../src/main/java/org/apache/fory/Fory.java | 71 +++++++++-------------
.../main/java/org/apache/fory/meta/ClassDef.java | 25 ++++++--
.../org/apache/fory/resolver/ClassResolver.java | 56 +++++++++--------
.../org/apache/fory/resolver/TypeResolver.java | 36 +++++++++++
.../org/apache/fory/resolver/XtypeResolver.java | 3 +
.../fory/serializer/ObjectStreamSerializer.java | 4 ++
.../org/apache/fory/serializer/RegisterTest.java | 70 +++++++++++++++++++++
22 files changed, 278 insertions(+), 104 deletions(-)
diff --git a/docs/guide/graalvm_guide.md b/docs/guide/graalvm_guide.md
index 6c5174fd9..88b005552 100644
--- a/docs/guide/graalvm_guide.md
+++ b/docs/guide/graalvm_guide.md
@@ -42,7 +42,7 @@ Args =
--initialize-at-build-time=org.apache.fory.graalvm.Example
Fory achieves this by using **codegen instead of reflection** - all
serialization code is generated at build time when you call:
-- `fory.register(YourClass.class, true)` to register your classes
+- `fory.register(YourClass.class)` to register your classes
- `fory.ensureSerializersCompiled()` to compile serializers at build time
Note that Fory `asyncCompilationEnabled` option will be disabled automatically
for graalvm native image since graalvm
@@ -61,8 +61,10 @@ This means you need to register your class with Fory. **Do
NOT add it to reflect
```java
static {
fory = Fory.builder().build();
- fory.register(MyClass.class, true); // Enable codegen for this class
- fory.ensureSerializersCompiled(); // Compile at build time
+ // register class
+ fory.register(MyClass.class);
+ // ensure all serializers for registered classes being compiled by fory at
graalvm native image build time.
+ fory.ensureSerializersCompiled();
}
```
@@ -97,9 +99,9 @@ public class Example {
static {
fory = Fory.builder().build();
- // register and generate serializer code.
- fory.register(Record.class, true);
- // ensure lazy initialized serializers being compiled by fory.
+ // register class
+ fory.register(Record.class);
+ // ensure all serializers for registered classes being compiled by fory at
graalvm native image build time.
fory.ensureSerializersCompiled();
}
@@ -144,9 +146,9 @@ public class ThreadSafeExample {
static {
fory = new ThreadLocalFory(classLoader -> {
Fory f = Fory.builder().build();
- // register and generate serializer code.
- f.register(Foo.class, true);
- // ensure lazy initialized serializers being compiled by fory.
+ // register class
+ f.register(Foo.class);
+ // ensure all serializers for registered classes being compiled by fory
at graalvm native image build time.
fory.ensureSerializersCompiled();
return f;
});
@@ -175,8 +177,7 @@ Args =
--initialize-at-build-time=org.apache.fory.graalvm.ThreadSafeExample
For framework developers, if you want to integrate fory for serialization, you
can provided a configuration file to let
the users to list all the classes they want to serialize, then you can load
those classes and invoke
-`org.apache.fory.Fory.register(Class<?>, boolean)` to register those classes
in your Fory integration class, and configure that
-class be initialized at graalvm native image build time.
+`org.apache.fory.Fory.register(Class<?>)` to register those classes in your
Fory integration class. After all classes are registered, you need to invoke
`org.apache.fory.Fory.ensureSerializersCompiled()` to compile serializers at
build time, and configure that class be initialized at graalvm native image
build time.
## Benchmark
diff --git
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ArrayExample.java
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ArrayExample.java
index e002a5444..0d9da0861 100644
---
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ArrayExample.java
+++
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ArrayExample.java
@@ -28,7 +28,8 @@ public class ArrayExample {
private static final Fory FORY =
Fory.builder().registerGuavaTypes(false).build();
static {
- FORY.register(ArrayExample.class, true);
+ FORY.register(ArrayExample.class);
+ FORY.ensureSerializersCompiled();
}
byte[] bytes;
diff --git
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/Benchmark.java
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/Benchmark.java
index f27b1c91e..832f41b6b 100644
---
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/Benchmark.java
+++
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/Benchmark.java
@@ -74,11 +74,13 @@ public class Benchmark {
static {
fory1 = Fory.builder().withNumberCompressed(false).build();
- fory1.register(Foo.class, true);
- fory1.register(Struct.class, true);
+ fory1.register(Foo.class);
+ fory1.register(Struct.class);
+ fory1.ensureSerializersCompiled();
fory2 = Fory.builder().withNumberCompressed(true).build();
- fory2.register(Foo.class, true);
- fory2.register(Struct.class, true);
+ fory2.register(Foo.class);
+ fory2.register(Struct.class);
+ fory2.ensureSerializersCompiled();
}
public static void main(String[] args) {
diff --git
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/CompatibleExample.java
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/CompatibleExample.java
index 634b3e178..d5e40a854 100644
---
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/CompatibleExample.java
+++
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/CompatibleExample.java
@@ -37,7 +37,8 @@ public class CompatibleExample {
.withScopedMetaShare(false)
.build();
// register and generate serializer code.
- fory.register(Foo.class, true);
+ fory.register(Foo.class);
+ fory.ensureSerializersCompiled();
return fory;
}
diff --git
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/CompatibleThreadSafeExample.java
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/CompatibleThreadSafeExample.java
index a1a3fccc7..a63fbb4c4 100644
---
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/CompatibleThreadSafeExample.java
+++
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/CompatibleThreadSafeExample.java
@@ -38,7 +38,8 @@ public class CompatibleThreadSafeExample {
.withCompatibleMode(CompatibleMode.COMPATIBLE)
.build();
// register and generate serializer code.
- f.register(Foo.class, true);
+ f.register(Foo.class);
+ f.ensureSerializersCompiled();
return f;
});
System.out.println("Init fory at build time");
diff --git
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/Example.java
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/Example.java
index 86d357b7c..ee20eb123 100644
---
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/Example.java
+++
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/Example.java
@@ -30,7 +30,8 @@ public class Example {
static {
fory =
Fory.builder().withName(Example.class.getName()).requireClassRegistration(true).build();
// register and generate serializer code.
- fory.register(Foo.class, true);
+ fory.register(Foo.class);
+ fory.ensureSerializersCompiled();
}
static void test(Fory fory) {
diff --git
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ObjectStreamExample.java
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ObjectStreamExample.java
index 227ce126d..01a25ac79 100644
---
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ObjectStreamExample.java
+++
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ObjectStreamExample.java
@@ -33,7 +33,7 @@ public class ObjectStreamExample extends AbstractMap<Integer,
Integer> {
.build();
static {
- FORY.register(ObjectStreamExample.class, true);
+ FORY.register(ObjectStreamExample.class);
FORY.ensureSerializersCompiled();
}
diff --git
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ProxyExample.java
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ProxyExample.java
index 2fd195675..525efa95d 100644
---
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ProxyExample.java
+++
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ProxyExample.java
@@ -49,7 +49,7 @@ public class ProxyExample {
.requireClassRegistration(true)
.build();
// register and generate serializer code.
- fory.register(TestInvocationHandler.class, true);
+ fory.register(TestInvocationHandler.class);
fory.ensureSerializersCompiled();
return fory;
}
diff --git
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ScopedCompatibleExample.java
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ScopedCompatibleExample.java
index 903931622..674e1b11e 100644
---
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ScopedCompatibleExample.java
+++
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ScopedCompatibleExample.java
@@ -38,7 +38,8 @@ public class ScopedCompatibleExample {
.withScopedMetaShare(true)
.build();
// register and generate serializer code.
- fory.register(Foo.class, true);
+ fory.register(Foo.class);
+ fory.ensureSerializersCompiled();
return fory;
}
diff --git
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ThreadSafeExample.java
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ThreadSafeExample.java
index dfd5cb74d..dd45c3f29 100644
---
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ThreadSafeExample.java
+++
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/ThreadSafeExample.java
@@ -43,7 +43,8 @@ public class ThreadSafeExample {
.requireClassRegistration(true)
.build();
// register and generate serializer code.
- f.register(Foo.class, true);
+ f.register(Foo.class);
+ f.ensureSerializersCompiled();
return f;
});
System.out.println("Init fory at build time");
diff --git
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/record/CompatibleRecordExample.java
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/record/CompatibleRecordExample.java
index 5e99cf09c..938aaf12c 100644
---
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/record/CompatibleRecordExample.java
+++
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/record/CompatibleRecordExample.java
@@ -37,7 +37,8 @@ public class CompatibleRecordExample {
.withCompatibleMode(CompatibleMode.COMPATIBLE)
.build();
// register and generate serializer code.
- fory.register(RecordExample.Record.class, true);
+ fory.register(RecordExample.Record.class);
+ fory.ensureSerializersCompiled();
return fory;
}
diff --git
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/record/RecordExample.java
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/record/RecordExample.java
index 875154da3..16946f59f 100644
---
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/record/RecordExample.java
+++
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/record/RecordExample.java
@@ -40,7 +40,8 @@ public class RecordExample {
.requireClassRegistration(true)
.build();
// register and generate serializer code.
- fory.register(Record.class, true);
+ fory.register(Record.class);
+ fory.ensureSerializersCompiled();
return fory;
}
diff --git
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/record/RecordExample2.java
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/record/RecordExample2.java
index 2e464228b..7811b06f2 100644
---
a/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/record/RecordExample2.java
+++
b/integration_tests/graalvm_tests/src/main/java/org/apache/fory/graalvm/record/RecordExample2.java
@@ -40,8 +40,9 @@ public class RecordExample2 {
.requireClassRegistration(true)
.build();
// register and generate serializer code.
- fory.register(Record.class, true);
- fory.register(Foo.class, true);
+ fory.register(Record.class);
+ fory.register(Foo.class);
+ fory.ensureSerializersCompiled();
return fory;
}
diff --git
a/java/fory-core/src/main/java/org/apache/fory/AbstractThreadSafeFory.java
b/java/fory-core/src/main/java/org/apache/fory/AbstractThreadSafeFory.java
index 9e1f31118..a2aaf6e14 100644
--- a/java/fory-core/src/main/java/org/apache/fory/AbstractThreadSafeFory.java
+++ b/java/fory-core/src/main/java/org/apache/fory/AbstractThreadSafeFory.java
@@ -48,6 +48,7 @@ public abstract class AbstractThreadSafeFory implements
ThreadSafeFory {
registerCallback(fory -> fory.register(cls, id, createSerializer));
}
+ @Deprecated
@Override
public void register(Class<?> cls, String typeName) {
registerCallback(fory -> fory.register(cls, typeName));
@@ -58,6 +59,21 @@ public abstract class AbstractThreadSafeFory implements
ThreadSafeFory {
registerCallback(fory -> fory.register(cls, namespace, typeName));
}
+ @Override
+ public void register(String className) {
+ registerCallback(fory -> fory.register(className));
+ }
+
+ @Override
+ public void register(String className, int id) {
+ registerCallback(fory -> fory.register(className, id));
+ }
+
+ @Override
+ public void register(String className, String namespace, String typeName) {
+ registerCallback(fory -> fory.register(className, namespace, typeName));
+ }
+
@Override
public <T> void registerSerializer(Class<T> type, Class<? extends
Serializer> serializerClass) {
registerCallback(fory -> fory.registerSerializer(type, serializerClass));
diff --git a/java/fory-core/src/main/java/org/apache/fory/BaseFory.java
b/java/fory-core/src/main/java/org/apache/fory/BaseFory.java
index ff0b68c71..8d6b3c103 100644
--- a/java/fory-core/src/main/java/org/apache/fory/BaseFory.java
+++ b/java/fory-core/src/main/java/org/apache/fory/BaseFory.java
@@ -56,24 +56,46 @@ public interface BaseFory {
void register(Class<?> cls, boolean createSerializer);
/**
- * Register class with specified id.
+ * Register class with specified id. This method has been deprecated, please
use {@link
+ * #register(Class, int)} instead, and invoke {@link
#ensureSerializersCompiled} after all classes
+ * has been registered.
*
* @param cls class to register.
* @param id id for provided class.
* @param createSerializer whether to create serializer, if true and codegen
enabled, this will
- * generate the serializer code too.
+ * generate the serializer code too. this parameter has no effect
anymore on whether to
+ * generate code, please use {@link #ensureSerializersCompiled} to
trigger code generation
*/
+ @Deprecated
void register(Class<?> cls, int id, boolean createSerializer);
/** register class with given type name which will be used for
cross-language serialization. */
void register(Class<?> cls, String typeName);
/**
- * register class with given type namespace and name which will be used for
cross-language
- * serialization.
+ * register class with given type namespace and name. This can be used
mapping different classes
+ * into same type when deserializing.
*/
void register(Class<?> cls, String namespace, String typeName);
+ /**
+ * Register class and allocate an auto-grown ID for this class. Note that
the registration order
+ * is important. If registration order is inconsistent, the allocated ID
will be different, and
+ * the deserialization will failed.
+ *
+ * @param className full class name to register.
+ */
+ void register(String className);
+
+ /** register class with given id. */
+ void register(String className, int classId);
+
+ /**
+ * register class with given type namespace and name. This can be used
mapping different classes
+ * into same type when deserializing.
+ */
+ void register(String className, String namespace, String typeName);
+
/**
* Register a Serializer for a class, and allocate an auto-grown ID for this
class if it's not
* registered yet. Note that the registration order is important. If
registration order is
@@ -109,8 +131,11 @@ public interface BaseFory {
* Ensure all compilation for serializers and accessors even for lazy
initialized serializers.
* This method will block until all compilation is done.
*
- * <p>This method is mainly used for graalvm native image build time and
trigger compilation ahead
+ * <p>This method is mainly used for graalvm native image build time or
trigger compilation ahead
* for online service ahead to avoid cold start.
+ *
+ * <p>Note that this method should be invoked after all registrations and
invoked only once.
+ * Repeated invocations will have no effect.
*/
void ensureSerializersCompiled();
diff --git a/java/fory-core/src/main/java/org/apache/fory/Fory.java
b/java/fory-core/src/main/java/org/apache/fory/Fory.java
index 7b6c02920..9ec188021 100644
--- a/java/fory-core/src/main/java/org/apache/fory/Fory.java
+++ b/java/fory-core/src/main/java/org/apache/fory/Fory.java
@@ -176,41 +176,31 @@ public final class Fory implements BaseFory {
@Override
public void register(Class<?> cls) {
- if (!crossLanguage) {
- classResolver.register(cls);
- } else {
- xtypeResolver.register(cls);
- }
+ _getTypeResolver().register(cls);
}
@Override
public void register(Class<?> cls, int id) {
- if (!crossLanguage) {
- classResolver.register(cls, id);
- } else {
- xtypeResolver.register(cls, id);
- }
+ _getTypeResolver().register(cls, id);
}
+ @Deprecated
@Override
public void register(Class<?> cls, boolean createSerializer) {
- if (!crossLanguage) {
- classResolver.register(cls, createSerializer);
- } else {
- xtypeResolver.register(cls);
- }
+ _getTypeResolver().register(cls);
}
+ @Deprecated
@Override
public void register(Class<?> cls, int id, boolean createSerializer) {
- if (!crossLanguage) {
- classResolver.register(cls, id, createSerializer);
- } else {
- xtypeResolver.register(cls, id);
- }
+ _getTypeResolver().register(cls, id);
}
- /** register class with given type tag which will be used for cross-language
serialization. */
+ /**
+ * Register class with given type name, this method will have bigger
serialization time/space cost
+ * compared to register by id.
+ */
+ @Override
public void register(Class<?> cls, String typeName) {
int idx = typeName.lastIndexOf('.');
String namespace = "";
@@ -222,38 +212,37 @@ public final class Fory implements BaseFory {
}
public void register(Class<?> cls, String namespace, String typeName) {
- if (!crossLanguage) {
- classResolver.register(cls, namespace, typeName);
- } else {
- xtypeResolver.register(cls, namespace, typeName);
- }
+ _getTypeResolver().register(cls, namespace, typeName);
+ }
+
+ @Override
+ public void register(String className) {
+ _getTypeResolver().register(className);
+ }
+
+ @Override
+ public void register(String className, int classId) {
+ _getTypeResolver().register(className, classId);
+ }
+
+ @Override
+ public void register(String className, String namespace, String typeName) {
+ _getTypeResolver().register(className, namespace, typeName);
}
@Override
public <T> void registerSerializer(Class<T> type, Class<? extends
Serializer> serializerClass) {
- if (!crossLanguage) {
- classResolver.registerSerializer(type, serializerClass);
- } else {
- xtypeResolver.registerSerializer(type, serializerClass);
- }
+ _getTypeResolver().registerSerializer(type, serializerClass);
}
@Override
public void registerSerializer(Class<?> type, Serializer<?> serializer) {
- if (!crossLanguage) {
- classResolver.registerSerializer(type, serializer);
- } else {
- xtypeResolver.registerSerializer(type, serializer);
- }
+ _getTypeResolver().registerSerializer(type, serializer);
}
@Override
public void registerSerializer(Class<?> type, Function<Fory, Serializer<?>>
serializerCreator) {
- if (!crossLanguage) {
- classResolver.registerSerializer(type, serializerCreator.apply(this));
- } else {
- xtypeResolver.registerSerializer(type, serializerCreator.apply(this));
- }
+ _getTypeResolver().registerSerializer(type, serializerCreator.apply(this));
}
@Override
diff --git a/java/fory-core/src/main/java/org/apache/fory/meta/ClassDef.java
b/java/fory-core/src/main/java/org/apache/fory/meta/ClassDef.java
index a8c0f0294..826b10e81 100644
--- a/java/fory-core/src/main/java/org/apache/fory/meta/ClassDef.java
+++ b/java/fory-core/src/main/java/org/apache/fory/meta/ClassDef.java
@@ -23,7 +23,6 @@ import static
org.apache.fory.meta.ClassDefEncoder.buildFields;
import static org.apache.fory.type.TypeUtils.COLLECTION_TYPE;
import static org.apache.fory.type.TypeUtils.MAP_TYPE;
import static org.apache.fory.type.TypeUtils.collectionOf;
-import static org.apache.fory.type.TypeUtils.getArrayComponent;
import static org.apache.fory.type.TypeUtils.mapOf;
import java.io.ObjectStreamClass;
@@ -270,11 +269,7 @@ public class ClassDef implements Serializable {
if (descriptor != null) {
// Make DescriptorGrouper have consistent order whether field exist
or not
// fory builtin types skip
- if (rawType.isEnum()
- || rawType.isAssignableFrom(descriptor.getRawType())
- || NonexistentClass.isNonexistent(rawType)
- || rawType == FinalObjectTypeStub.class
- || (rawType.isArray() && getArrayComponent(rawType) ==
FinalObjectTypeStub.class)) {
+ if (useFieldType(rawType, descriptor)) {
descriptor = descriptor.copyWithTypeName(newDesc.getTypeName());
descriptors.add(descriptor);
} else {
@@ -293,6 +288,24 @@ public class ClassDef implements Serializable {
return descriptors;
}
+ /** Returns true if can use current field type. */
+ private static boolean useFieldType(Class<?> parsedType, Descriptor
descriptor) {
+ if (parsedType.isEnum()
+ || parsedType.isAssignableFrom(descriptor.getRawType())
+ || parsedType == FinalObjectTypeStub.class) {
+ return true;
+ }
+ if (parsedType.isArray()) {
+ Tuple2<Class<?>, Integer> info =
TypeUtils.getArrayComponentInfo(parsedType);
+ Field field = descriptor.getField();
+ if (!field.getType().isArray() ||
TypeUtils.getArrayDimensions(field.getType()) != info.f1) {
+ return false;
+ }
+ return info.f0 == FinalObjectTypeStub.class || info.f0.isEnum();
+ }
+ return false;
+ }
+
/**
* FieldInfo contains all necessary info of a field to execute
serialization/deserialization
* logic.
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 ca11984f1..453f4de3a 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
@@ -360,7 +360,12 @@ public class ClassResolver extends TypeResolver {
register(EnumSet.allOf(Language.class).getClass());
register(EnumSet.of(Language.JAVA).getClass());
register(SerializedLambda.class);
- register(Throwable.class, StackTraceElement.class, Exception.class,
RuntimeException.class);
+ register(
+ Throwable.class,
+ StackTraceElement.class,
+ StackTraceElement[].class,
+ Exception.class,
+ RuntimeException.class);
register(NullPointerException.class);
register(IOException.class);
register(IllegalArgumentException.class);
@@ -389,11 +394,13 @@ public class ClassResolver extends TypeResolver {
}
}
+ /**
+ * This method has been deprecated, please use {@link #register(Class)}
instead, and invoke {@link
+ * #ensureSerializersCompiled} after all classes has been registered.
+ */
+ @Deprecated
public void register(Class<?> cls, boolean createSerializer) {
register(cls);
- if (createSerializer) {
- createSerializerAhead(cls);
- }
}
/**
@@ -430,15 +437,13 @@ public class ClassResolver extends TypeResolver {
register(loadClass(className, false, 0, false), classId);
}
+ /**
+ * This method has been deprecated, please use {@link #register(Class, int)}
instead, and invoke
+ * {@link #ensureSerializersCompiled} after all classes has been registered.
+ */
+ @Deprecated
public void register(Class<?> cls, int id, boolean createSerializer) {
register(cls, id);
- if (createSerializer) {
- createSerializerAhead(cls);
- }
- }
-
- public void register(String className, Short classId, boolean
createSerializer) {
- register(loadClass(className, false, 0, false), classId, createSerializer);
}
/**
@@ -446,6 +451,7 @@ public class ClassResolver extends TypeResolver {
* registered, the serialized class will have smaller payload size. In many
cases, it type name
* has no conflict, namespace can be left as empty.
*/
+ @Override
public void register(Class<?> cls, String namespace, String name) {
Preconditions.checkArgument(!Functions.isLambda(cls));
Preconditions.checkArgument(!ReflectionUtils.isJdkProxy(cls));
@@ -1236,7 +1242,7 @@ public class ClassResolver extends TypeResolver {
if (!extRegistry.absClassInfo.isEmpty()) {
Class<?> tmpCls = cls;
while (tmpCls != null && tmpCls != Object.class) {
- ClassInfo absClass = null;
+ ClassInfo absClass;
if ((absClass = extRegistry.absClassInfo.get(tmpCls.getSuperclass()))
!= null) {
return absClass.serializer;
}
@@ -1257,15 +1263,6 @@ public class ClassResolver extends TypeResolver {
return serializer;
}
- private void createSerializerAhead(Class<?> cls) {
- try {
- fory.getJITContext().lock();
- createSerializer0(cls);
- } finally {
- fory.getJITContext().unlock();
- }
- }
-
private void createSerializer0(Class<?> cls) {
ClassInfo classInfo = getClassInfo(cls);
ClassInfo deserializationClassInfo;
@@ -1280,8 +1277,6 @@ public class ClassResolver extends TypeResolver {
.deserializerClassMap
.put(classDef.getId(),
getGraalvmSerializerClass(deserializationClassInfo.serializer));
Tuple2<ClassDef, ClassInfo> classDefTuple =
extRegistry.classIdToDef.get(classDef.getId());
- // empty serializer for graalvm build time
- classDefTuple.f1.serializer = null;
classInfoCache = NIL_CLASS_INFO;
extRegistry.classIdToDef.put(classDef.getId(),
Tuple2.of(classDefTuple.f0, null));
}
@@ -1291,7 +1286,6 @@ public class ClassResolver extends TypeResolver {
getGraalvmClassRegistry()
.serializerClassMap
.put(cls, getGraalvmSerializerClass(classInfo.serializer));
- classInfo.serializer = null;
classInfoCache = NIL_CLASS_INFO;
if (RecordUtils.isRecord(cls)) {
RecordUtils.getRecordConstructor(cls);
@@ -1783,8 +1777,15 @@ public class ClassResolver extends TypeResolver {
/**
* Ensure all compilation for serializers and accessors even for lazy
initialized serializers.
* This method will block until all compilation is done.
+ *
+ * <p>Note that this method should be invoked after all registrations and
invoked only once.
+ * Repeated invocations will have no effect.
*/
public void ensureSerializersCompiled() {
+ if (extRegistry.ensureSerializersCompiled) {
+ return;
+ }
+ extRegistry.ensureSerializersCompiled = true;
try {
fory.getJITContext().lock();
Serializers.newSerializer(fory, LambdaSerializer.STUB_LAMBDA_CLASS,
LambdaSerializer.class);
@@ -1793,7 +1794,12 @@ public class ClassResolver extends TypeResolver {
classInfoMap.forEach(
(cls, classInfo) -> {
if (classInfo.serializer == null) {
- getSerializer(classInfo.cls, isSerializable(classInfo.cls));
+ if (isSerializable(classInfo.cls)) {
+ createSerializer0(cls);
+ }
+ if (cls.isArray()) {
+ createSerializer0(TypeUtils.getArrayComponent(cls));
+ }
}
});
if (GraalvmSupport.isGraalBuildtime()) {
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 564aa0666..69ab9f209 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
@@ -111,6 +111,29 @@ public abstract class TypeResolver {
metaStringResolver = fory.getMetaStringResolver();
}
+ public abstract void register(Class<?> type);
+
+ public abstract void register(Class<?> type, int id);
+
+ public abstract void register(Class<?> type, String namespace, String
typeName);
+
+ public void register(String className) {
+ register(loadClass(className));
+ }
+
+ public void register(String className, int classId) {
+ register(loadClass(className), classId);
+ }
+
+ public void register(String className, String namespace, String typeName) {
+ register(loadClass(className), namespace, typeName);
+ }
+
+ public abstract void registerSerializer(Class<?> type, Serializer<?>
serializer);
+
+ public abstract <T> void registerSerializer(
+ Class<T> type, Class<? extends Serializer> serializerClass);
+
/**
* Whether to track reference for this type. If false, reference tracing of
subclasses may be
* ignored too.
@@ -369,6 +392,10 @@ public abstract class TypeResolver {
return loadClass(className, isEnum, arrayDims,
fory.getConfig().deserializeNonexistentClass());
}
+ final Class<?> loadClass(String className) {
+ return loadClass(className, false, -1, false);
+ }
+
final Class<?> loadClass(
String className, boolean isEnum, int arrayDims, boolean
deserializeNonexistentClass) {
extRegistry.typeChecker.checkType(this, className);
@@ -421,7 +448,15 @@ public abstract class TypeResolver {
return false;
}
try {
+ ClassInfo classInfo = classInfoMap.get(cls);
+ Serializer<?> serializer = null;
+ if (classInfo != null) {
+ serializer = classInfo.serializer;
+ }
getSerializerClass(cls, false);
+ if (classInfo != null && serializer == null) {
+ classInfo.serializer = null;
+ }
return true;
} catch (Throwable t) {
return false;
@@ -663,5 +698,6 @@ public abstract class TypeResolver {
final Map<Class, Map<String, GenericType>> classGenericTypes = new
HashMap<>();
final Map<List<ClassLoader>, CodeGenerator> codeGeneratorMap = new
HashMap<>();
final Set<ClassInfo> initialClassInfos = new HashSet<>();
+ boolean ensureSerializersCompiled;
}
}
diff --git
a/java/fory-core/src/main/java/org/apache/fory/resolver/XtypeResolver.java
b/java/fory-core/src/main/java/org/apache/fory/resolver/XtypeResolver.java
index 599a865c5..3250c24eb 100644
--- a/java/fory-core/src/main/java/org/apache/fory/resolver/XtypeResolver.java
+++ b/java/fory-core/src/main/java/org/apache/fory/resolver/XtypeResolver.java
@@ -149,6 +149,7 @@ public class XtypeResolver extends TypeResolver {
}
}
+ @Override
public void register(Class<?> type) {
while (registeredTypeIds.contains(xtypeIdGenerator)) {
xtypeIdGenerator++;
@@ -156,6 +157,7 @@ public class XtypeResolver extends TypeResolver {
register(type, xtypeIdGenerator++);
}
+ @Override
public void register(Class<?> type, int userTypeId) {
// ClassInfo[] has length of max type id. If the type id is too big, Fory
will waste many
// memory. We can relax this limit in the future.
@@ -204,6 +206,7 @@ public class XtypeResolver extends TypeResolver {
xtypeId);
}
+ @Override
public void register(Class<?> type, String namespace, String typeName) {
Preconditions.checkArgument(
!typeName.contains("."),
diff --git
a/java/fory-core/src/main/java/org/apache/fory/serializer/ObjectStreamSerializer.java
b/java/fory-core/src/main/java/org/apache/fory/serializer/ObjectStreamSerializer.java
index efc18543f..48d56e11d 100644
---
a/java/fory-core/src/main/java/org/apache/fory/serializer/ObjectStreamSerializer.java
+++
b/java/fory-core/src/main/java/org/apache/fory/serializer/ObjectStreamSerializer.java
@@ -333,6 +333,10 @@ public class ObjectStreamSerializer extends
AbstractObjectSerializer {
this.slotsSerializer =
(CompatibleSerializerBase)
Serializers.newSerializer(fory, type, c));
}
+ if (GraalvmSupport.isGraalBuildtime()) {
+ // trigger serializer constructor method handle generate.
+ Serializers.newSerializer(fory, type, sc);
+ }
if (sc == CompatibleSerializer.class ||
GraalvmSupport.isGraalBuildtime()) {
// skip init generated serializer at graalvm build time
this.slotsSerializer = new CompatibleSerializer(fory, type,
fieldResolver);
diff --git
a/java/fory-core/src/test/java/org/apache/fory/serializer/RegisterTest.java
b/java/fory-core/src/test/java/org/apache/fory/serializer/RegisterTest.java
new file mode 100644
index 000000000..8d4a560d7
--- /dev/null
+++ b/java/fory-core/src/test/java/org/apache/fory/serializer/RegisterTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.fory.serializer;
+
+import org.apache.fory.Fory;
+import org.apache.fory.ForyTestBase;
+import org.apache.fory.config.CompatibleMode;
+import org.apache.fory.config.ForyBuilder;
+import org.apache.fory.config.Language;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class RegisterTest extends ForyTestBase {
+
+ @Test(dataProvider = "enableCodegen")
+ public void testRegisterForCompatible(boolean enableCodegen) {
+ A a = new A();
+ a.setB(new B());
+ ForyBuilder builder =
+ Fory.builder()
+ .withLanguage(Language.JAVA)
+ .withCodegen(enableCodegen)
+ .withCompatibleMode(CompatibleMode.COMPATIBLE);
+
+ Fory fory1 = builder.build();
+ fory1.register(A.class, (short) 1000);
+
+ Fory fory2 = builder.build();
+ fory2.register(A.class, (short) 1000);
+ fory2.register(B.class, (short) 1001);
+
+ A a1 = fory1.deserialize(fory2.serialize(a), A.class);
+ Assert.assertNotNull(a1);
+ Assert.assertNull(a1.b);
+
+ Fory fory3 = builder.requireClassRegistration(false).build();
+ fory3.register(A.class, (short) 1000);
+
+ A a2 = fory2.deserialize(fory3.serialize(a), A.class);
+ Assert.assertNotNull(a2);
+ Assert.assertEquals(a2.b.getClass(), B.class);
+ }
+
+ public static class A {
+ private B b;
+
+ public void setB(B b) {
+ this.b = b;
+ }
+ }
+
+ public static class B {}
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]