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 d86dab5ee feat(java): separate user register type id with fory
registered type id (#3035)
d86dab5ee is described below
commit d86dab5ee4c8381ca1d89ec5398e48507a5afd00
Author: Shawn Yang <[email protected]>
AuthorDate: Wed Dec 10 18:25:26 2025 +0800
feat(java): separate user register type id with fory registered type id
(#3035)
## Why?
## What does this PR do?
## Related issues
Closes #2609
## Does this PR introduce any user-facing change?
- [ ] Does this PR introduce any public API change?
- [ ] Does this PR introduce any binary protocol compatibility change?
## Benchmark
---
docs/guide/java_serialization_guide.md | 2 +-
.../org/apache/fory/AbstractThreadSafeFory.java | 5 -
.../main/java/org/apache/fory/ThreadSafeFory.java | 5 +
.../org/apache/fory/resolver/ClassResolver.java | 380 ++++++++++++++-------
.../org/apache/fory/resolver/TypeResolver.java | 34 ++
.../apache/fory/serializer/ArraySerializers.java | 45 +--
.../fory/serializer/OptionalSerializers.java | 8 +-
.../fory/serializer/PrimitiveSerializers.java | 32 +-
.../org/apache/fory/serializer/Serializers.java | 28 +-
.../apache/fory/serializer/TimeSerializers.java | 34 +-
.../collection/CollectionSerializers.java | 47 +--
.../collection/GuavaCollectionSerializers.java | 34 +-
.../collection/ImmutableCollectionSerializers.java | 14 +-
.../fory/serializer/collection/MapSerializers.java | 21 +-
.../serializer/collection/SubListSerializers.java | 5 +-
.../collection/SynchronizedSerializers.java | 2 +-
.../collection/UnmodifiableSerializers.java | 2 +-
.../apache/fory/resolver/ClassResolverTest.java | 33 +-
.../serializer/CompressedArraySerializers.java | 32 +-
19 files changed, 495 insertions(+), 268 deletions(-)
diff --git a/docs/guide/java_serialization_guide.md
b/docs/guide/java_serialization_guide.md
index 324f9f50d..6b7bef3f5 100644
--- a/docs/guide/java_serialization_guide.md
+++ b/docs/guide/java_serialization_guide.md
@@ -1441,7 +1441,7 @@ should have same registration order.
```java
Fory fory = xxx;
fory.register(SomeClass.class);
-fory.register(SomeClass1.class, 200);
+fory.register(SomeClass1.class, 1);
```
If you invoke `ForyBuilder#requireClassRegistration(false)` to disable class
registration check,
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 a2aaf6e14..820b98a93 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
@@ -19,9 +19,7 @@
package org.apache.fory;
-import java.util.function.Consumer;
import java.util.function.Function;
-import org.apache.fory.annotation.Internal;
import org.apache.fory.resolver.ClassChecker;
import org.apache.fory.resolver.TypeChecker;
import org.apache.fory.serializer.Serializer;
@@ -113,7 +111,4 @@ public abstract class AbstractThreadSafeFory implements
ThreadSafeFory {
return null;
});
}
-
- @Internal
- public abstract void registerCallback(Consumer<Fory> callback);
}
diff --git a/java/fory-core/src/main/java/org/apache/fory/ThreadSafeFory.java
b/java/fory-core/src/main/java/org/apache/fory/ThreadSafeFory.java
index 8c39f918e..16c8d8126 100644
--- a/java/fory-core/src/main/java/org/apache/fory/ThreadSafeFory.java
+++ b/java/fory-core/src/main/java/org/apache/fory/ThreadSafeFory.java
@@ -20,7 +20,9 @@
package org.apache.fory;
import java.nio.ByteBuffer;
+import java.util.function.Consumer;
import java.util.function.Function;
+import org.apache.fory.annotation.Internal;
import org.apache.fory.resolver.ClassChecker;
import org.apache.fory.resolver.TypeChecker;
import org.apache.fory.serializer.SerializerFactory;
@@ -98,4 +100,7 @@ public interface ThreadSafeFory extends BaseFory {
* @see LoaderBinding#clearClassLoader(ClassLoader)
*/
void clearClassLoader(ClassLoader loader);
+
+ @Internal
+ void registerCallback(Consumer<Fory> callback);
}
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 9ca721200..fbc0a261c 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
@@ -158,16 +158,52 @@ import org.apache.fory.util.record.RecordUtils;
/**
* Class registry for types of serializing objects, responsible for
reading/writing types, setting
* up relations between serializer and types.
+ *
+ * <h2>Class ID Space</h2>
+ *
+ * <p>Fory separates user class IDs from internal class IDs to provide a clean
and intuitive API:
+ *
+ * <ul>
+ * <li><b>User ID space</b>: IDs specified via {@link #register(Class, int)}
start from 0. Valid
+ * range is [0, {@value Short#MAX_VALUE} - {@value #USER_ID_BASE} - 1]
(i.e., [0, 32510]).
+ * <li><b>Internal ID space</b>: Reserved for Fory's built-in types
(primitives, common
+ * collections, etc.). These IDs are in the range [0, {@value
#USER_ID_BASE} - 1] and are
+ * completely hidden from users.
+ * </ul>
+ *
+ * <p>When users register a class with ID N, Fory internally stores it as (N +
{@value
+ * #USER_ID_BASE}). This transformation is transparent to users - they only
work with their own
+ * 0-based ID space.
+ *
+ * <h2>Registration Methods</h2>
+ *
+ * <ul>
+ * <li>{@link #register(Class)} - Auto-assigns the next available user ID
+ * <li>{@link #register(Class, int)} - Registers with a user-specified ID
(0-based)
+ * <li>{@link #register(Class, String, String)} - Registers with namespace
and type name
+ * </ul>
+ *
+ * @see #register(Class)
+ * @see #register(Class, int)
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public class ClassResolver extends TypeResolver {
private static final Logger LOG =
LoggerFactory.getLogger(ClassResolver.class);
- // preserve 0 as flag for class id not set in ClassInfo`
+ /** Flag value indicating no class ID has been assigned. */
public static final short NO_CLASS_ID = TypeResolver.NO_CLASS_ID;
+
public static final short LAMBDA_STUB_ID = 1;
public static final short JDK_PROXY_STUB_ID = 2;
public static final short REPLACE_STUB_ID = 3;
+
+ /**
+ * Base offset for user-registered class IDs. User IDs are internally stored
as (userId + {@value
+ * #USER_ID_BASE}). The first {@value #USER_ID_BASE} IDs (0 to {@value
#USER_ID_BASE} - 1) are
+ * reserved for Fory's internal types.
+ */
+ public static final short USER_ID_BASE = 256;
+
// Note: following pre-defined class id should be continuous, since they may
be used based range.
public static final short PRIMITIVE_VOID_CLASS_ID = (short) (REPLACE_STUB_ID
+ 1);
public static final short PRIMITIVE_BOOLEAN_CLASS_ID = (short)
(PRIMITIVE_VOID_CLASS_ID + 1);
@@ -228,43 +264,43 @@ public class ClassResolver extends TypeResolver {
@Override
public void initialize() {
extRegistry.objectGenericType = buildGenericType(OBJECT_TYPE);
- register(LambdaSerializer.ReplaceStub.class, LAMBDA_STUB_ID);
- register(JdkProxySerializer.ReplaceStub.class, JDK_PROXY_STUB_ID);
- register(ReplaceResolveSerializer.ReplaceStub.class, REPLACE_STUB_ID);
- register(void.class, PRIMITIVE_VOID_CLASS_ID);
- register(boolean.class, PRIMITIVE_BOOLEAN_CLASS_ID);
- register(byte.class, PRIMITIVE_BYTE_CLASS_ID);
- register(char.class, PRIMITIVE_CHAR_CLASS_ID);
- register(short.class, PRIMITIVE_SHORT_CLASS_ID);
- register(int.class, PRIMITIVE_INT_CLASS_ID);
- register(float.class, PRIMITIVE_FLOAT_CLASS_ID);
- register(long.class, PRIMITIVE_LONG_CLASS_ID);
- register(double.class, PRIMITIVE_DOUBLE_CLASS_ID);
- register(Void.class, VOID_CLASS_ID);
- register(Boolean.class, BOOLEAN_CLASS_ID);
- register(Byte.class, BYTE_CLASS_ID);
- register(Character.class, CHAR_CLASS_ID);
- register(Short.class, SHORT_CLASS_ID);
- register(Integer.class, INTEGER_CLASS_ID);
- register(Float.class, FLOAT_CLASS_ID);
- register(Long.class, LONG_CLASS_ID);
- register(Double.class, DOUBLE_CLASS_ID);
- register(String.class, STRING_CLASS_ID);
- register(boolean[].class, PRIMITIVE_BOOLEAN_ARRAY_CLASS_ID);
- register(byte[].class, PRIMITIVE_BYTE_ARRAY_CLASS_ID);
- register(char[].class, PRIMITIVE_CHAR_ARRAY_CLASS_ID);
- register(short[].class, PRIMITIVE_SHORT_ARRAY_CLASS_ID);
- register(int[].class, PRIMITIVE_INT_ARRAY_CLASS_ID);
- register(float[].class, PRIMITIVE_FLOAT_ARRAY_CLASS_ID);
- register(long[].class, PRIMITIVE_LONG_ARRAY_CLASS_ID);
- register(double[].class, PRIMITIVE_DOUBLE_ARRAY_CLASS_ID);
- register(String[].class, STRING_ARRAY_CLASS_ID);
- register(Object[].class, OBJECT_ARRAY_CLASS_ID);
- register(ArrayList.class, ARRAYLIST_CLASS_ID);
- register(HashMap.class, HASHMAP_CLASS_ID);
- register(HashSet.class, HASHSET_CLASS_ID);
- register(Class.class, CLASS_CLASS_ID);
- register(Object.class, EMPTY_OBJECT_ID);
+ registerInternal(LambdaSerializer.ReplaceStub.class, LAMBDA_STUB_ID);
+ registerInternal(JdkProxySerializer.ReplaceStub.class, JDK_PROXY_STUB_ID);
+ registerInternal(ReplaceResolveSerializer.ReplaceStub.class,
REPLACE_STUB_ID);
+ registerInternal(void.class, PRIMITIVE_VOID_CLASS_ID);
+ registerInternal(boolean.class, PRIMITIVE_BOOLEAN_CLASS_ID);
+ registerInternal(byte.class, PRIMITIVE_BYTE_CLASS_ID);
+ registerInternal(char.class, PRIMITIVE_CHAR_CLASS_ID);
+ registerInternal(short.class, PRIMITIVE_SHORT_CLASS_ID);
+ registerInternal(int.class, PRIMITIVE_INT_CLASS_ID);
+ registerInternal(float.class, PRIMITIVE_FLOAT_CLASS_ID);
+ registerInternal(long.class, PRIMITIVE_LONG_CLASS_ID);
+ registerInternal(double.class, PRIMITIVE_DOUBLE_CLASS_ID);
+ registerInternal(Void.class, VOID_CLASS_ID);
+ registerInternal(Boolean.class, BOOLEAN_CLASS_ID);
+ registerInternal(Byte.class, BYTE_CLASS_ID);
+ registerInternal(Character.class, CHAR_CLASS_ID);
+ registerInternal(Short.class, SHORT_CLASS_ID);
+ registerInternal(Integer.class, INTEGER_CLASS_ID);
+ registerInternal(Float.class, FLOAT_CLASS_ID);
+ registerInternal(Long.class, LONG_CLASS_ID);
+ registerInternal(Double.class, DOUBLE_CLASS_ID);
+ registerInternal(String.class, STRING_CLASS_ID);
+ registerInternal(boolean[].class, PRIMITIVE_BOOLEAN_ARRAY_CLASS_ID);
+ registerInternal(byte[].class, PRIMITIVE_BYTE_ARRAY_CLASS_ID);
+ registerInternal(char[].class, PRIMITIVE_CHAR_ARRAY_CLASS_ID);
+ registerInternal(short[].class, PRIMITIVE_SHORT_ARRAY_CLASS_ID);
+ registerInternal(int[].class, PRIMITIVE_INT_ARRAY_CLASS_ID);
+ registerInternal(float[].class, PRIMITIVE_FLOAT_ARRAY_CLASS_ID);
+ registerInternal(long[].class, PRIMITIVE_LONG_ARRAY_CLASS_ID);
+ registerInternal(double[].class, PRIMITIVE_DOUBLE_ARRAY_CLASS_ID);
+ registerInternal(String[].class, STRING_ARRAY_CLASS_ID);
+ registerInternal(Object[].class, OBJECT_ARRAY_CLASS_ID);
+ registerInternal(ArrayList.class, ARRAYLIST_CLASS_ID);
+ registerInternal(HashMap.class, HASHMAP_CLASS_ID);
+ registerInternal(HashSet.class, HASHSET_CLASS_ID);
+ registerInternal(Class.class, CLASS_CLASS_ID);
+ registerInternal(Object.class, EMPTY_OBJECT_ID);
registerCommonUsedClasses();
registerDefaultClasses();
addDefaultSerializers();
@@ -319,7 +355,7 @@ public class ClassResolver extends TypeResolver {
Objects.requireNonNull(classInfoMap.get(NonexistentMetaShared.class)).classId;
Preconditions.checkArgument(classId > 63 && classId < 8192, classId);
} else {
- register(NonexistentSkip.class);
+ registerInternal(NonexistentSkip.class);
}
}
}
@@ -329,122 +365,121 @@ public class ClassResolver extends TypeResolver {
}
private void addDefaultSerializer(Class type, Serializer serializer) {
- registerSerializer(type, serializer);
- register(type);
+ registerInternalSerializer(type, serializer);
+ registerInternal(type);
}
/** Register common class ahead to get smaller class id for serialization. */
private void registerCommonUsedClasses() {
- register(LinkedList.class, TreeSet.class);
- register(LinkedHashMap.class, TreeMap.class);
- register(Date.class, Timestamp.class, LocalDateTime.class, Instant.class);
- register(BigInteger.class, BigDecimal.class);
- register(Optional.class, OptionalInt.class);
- register(Boolean[].class, Byte[].class, Short[].class, Character[].class);
- register(Integer[].class, Float[].class, Long[].class, Double[].class);
+ registerInternal(LinkedList.class, TreeSet.class);
+ registerInternal(LinkedHashMap.class, TreeMap.class);
+ registerInternal(Date.class, Timestamp.class, LocalDateTime.class,
Instant.class);
+ registerInternal(BigInteger.class, BigDecimal.class);
+ registerInternal(Optional.class, OptionalInt.class);
+ registerInternal(Boolean[].class, Byte[].class, Short[].class,
Character[].class);
+ registerInternal(Integer[].class, Float[].class, Long[].class,
Double[].class);
}
private void registerDefaultClasses() {
- register(Platform.HEAP_BYTE_BUFFER_CLASS);
- register(Platform.DIRECT_BYTE_BUFFER_CLASS);
- register(Comparator.naturalOrder().getClass());
- register(Comparator.reverseOrder().getClass());
- register(ConcurrentHashMap.class);
- register(ArrayBlockingQueue.class);
- register(LinkedBlockingQueue.class);
- register(AtomicBoolean.class);
- register(AtomicInteger.class);
- register(AtomicLong.class);
- register(AtomicReference.class);
- register(EnumSet.allOf(Language.class).getClass());
- register(EnumSet.of(Language.JAVA).getClass());
- register(SerializedLambda.class);
- register(
+ registerInternal(Platform.HEAP_BYTE_BUFFER_CLASS);
+ registerInternal(Platform.DIRECT_BYTE_BUFFER_CLASS);
+ registerInternal(Comparator.naturalOrder().getClass());
+ registerInternal(Comparator.reverseOrder().getClass());
+ registerInternal(ConcurrentHashMap.class);
+ registerInternal(ArrayBlockingQueue.class);
+ registerInternal(LinkedBlockingQueue.class);
+ registerInternal(AtomicBoolean.class);
+ registerInternal(AtomicInteger.class);
+ registerInternal(AtomicLong.class);
+ registerInternal(AtomicReference.class);
+ registerInternal(EnumSet.allOf(Language.class).getClass());
+ registerInternal(EnumSet.of(Language.JAVA).getClass());
+ registerInternal(SerializedLambda.class);
+ registerInternal(
Throwable.class,
StackTraceElement.class,
StackTraceElement[].class,
Exception.class,
RuntimeException.class);
- register(NullPointerException.class);
- register(IOException.class);
- register(IllegalArgumentException.class);
- register(IllegalStateException.class);
- register(IndexOutOfBoundsException.class,
ArrayIndexOutOfBoundsException.class);
+ registerInternal(NullPointerException.class);
+ registerInternal(IOException.class);
+ registerInternal(IllegalArgumentException.class);
+ registerInternal(IllegalStateException.class);
+ registerInternal(IndexOutOfBoundsException.class,
ArrayIndexOutOfBoundsException.class);
}
- /** register class. */
+ /**
+ * Registers a class with an auto-assigned user ID.
+ *
+ * <p>The ID is automatically assigned starting from 0 in the user ID space.
Each call assigns the
+ * next available ID. If the class is already registered, this method does
nothing.
+ *
+ * <p>Example:
+ *
+ * <pre>{@code
+ * fory.register(MyClass.class); // Gets user ID 0
+ * fory.register(AnotherClass.class); // Gets user ID 1
+ * }</pre>
+ *
+ * @param cls the class to register
+ */
+ @Override
public void register(Class<?> cls) {
if (!extRegistry.registeredClassIdMap.containsKey(cls)) {
- while (extRegistry.classIdGenerator < registeredId2ClassInfo.length
- && registeredId2ClassInfo[extRegistry.classIdGenerator] != null) {
- extRegistry.classIdGenerator++;
+ while (extRegistry.userIdGenerator + USER_ID_BASE <
registeredId2ClassInfo.length
+ && registeredId2ClassInfo[extRegistry.userIdGenerator +
USER_ID_BASE] != null) {
+ extRegistry.userIdGenerator++;
}
- register(cls, extRegistry.classIdGenerator);
- }
- }
-
- public void register(String className) {
- register(loadClass(className, false, 0, false));
- }
-
- public void register(Class<?>... classes) {
- for (Class<?> cls : classes) {
- register(cls);
+ register(cls, extRegistry.userIdGenerator);
}
}
/**
- * This method has been deprecated, please use {@link #register(Class)}
instead, and invoke {@link
- * #ensureSerializersCompiled} after all classes has been registered.
+ * Registers a class by its fully qualified name with an auto-assigned user
ID.
+ *
+ * @param className the fully qualified class name
+ * @see #register(Class)
*/
- @Deprecated
- public void register(Class<?> cls, boolean createSerializer) {
- register(cls);
+ @Override
+ public void register(String className) {
+ register(loadClass(className, false, 0, false));
}
/**
- * Register class with specified id. Currently class id must be `classId >=
0 && classId < 32767`.
- * In the future this limitation may be relaxed.
+ * Registers a class by its fully qualified name with a specified user ID.
+ *
+ * @param className the fully qualified class name
+ * @param classId the user ID to assign (0-based, in user ID space)
+ * @see #register(Class, int)
*/
- public void register(Class<?> cls, int classId) {
- checkRegisterAllowed();
- // class id must be less than Integer.MAX_VALUE/2 since we use bit 0 as
class id flag.
- Preconditions.checkArgument(classId >= 0 && classId < Short.MAX_VALUE);
- short id = (short) classId;
- checkRegistration(cls, id, cls.getName());
- extRegistry.registeredClassIdMap.put(cls, id);
- if (registeredId2ClassInfo.length <= id) {
- ClassInfo[] tmp = new ClassInfo[(id + 1) * 2];
- System.arraycopy(registeredId2ClassInfo, 0, tmp, 0,
registeredId2ClassInfo.length);
- registeredId2ClassInfo = tmp;
- }
- ClassInfo classInfo = classInfoMap.get(cls);
- if (classInfo != null) {
- classInfo.classId = id;
- } else {
- classInfo = new ClassInfo(this, cls, null, id, NOT_SUPPORT_XLANG);
- // make `extRegistry.registeredClassIdMap` and `classInfoMap` share same
classInfo
- // instances.
- classInfoMap.put(cls, classInfo);
- }
- // serializer will be set lazily in `addSerializer` method if it's null.
- registeredId2ClassInfo[id] = classInfo;
- extRegistry.registeredClasses.put(cls.getName(), cls);
- extRegistry.classIdGenerator++;
- GraalvmSupport.registerClass(cls, fory.getConfig().getConfigHash());
- }
-
+ @Override
public void register(String className, int classId) {
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.
+ * Registers a class with a user-specified ID.
+ *
+ * <p>The ID is in the user ID space, starting from 0. Fory internally
transforms this to an
+ * internal ID by adding {@link #USER_ID_BASE}. This separation ensures user
IDs never conflict
+ * with Fory's internal type IDs.
+ *
+ * <p>Valid user ID range: [0, 32510] (i.e., [0, Short.MAX_VALUE -
USER_ID_BASE - 1])
+ *
+ * <p>Example:
+ *
+ * <pre>{@code
+ * fory.register(MyClass.class, 0); // User ID 0 -> Internal ID 256
+ * fory.register(AnotherClass.class, 1); // User ID 1 -> Internal ID 257
+ * }</pre>
+ *
+ * @param cls the class to register
+ * @param id the user ID to assign (0-based)
+ * @throws IllegalArgumentException if the ID is out of valid range or
already in use
*/
- @Deprecated
- public void register(Class<?> cls, int id, boolean createSerializer) {
- register(cls, id);
+ @Override
+ public void register(Class<?> cls, int id) {
+ registerImpl(cls, id + USER_ID_BASE);
}
/**
@@ -481,6 +516,83 @@ public class ClassResolver extends TypeResolver {
GraalvmSupport.registerClass(cls, fory.getConfig().getConfigHash());
}
+ /**
+ * Registers multiple classes for internal use with auto-assigned internal
IDs.
+ *
+ * <p><b>Internal API</b>: This method is for Fory's internal use only.
Users should use {@link
+ * #register(Class)} instead.
+ *
+ * @param classes the classes to register
+ */
+ public void registerInternal(Class<?>... classes) {
+ for (Class<?> cls : classes) {
+ registerInternal(cls);
+ }
+ }
+
+ /**
+ * Registers a class for internal use with an auto-assigned internal ID.
+ *
+ * <p><b>Internal API</b>: This method is for Fory's internal use only.
Users should use {@link
+ * #register(Class)} instead. Internal IDs are in the range [0, {@link
#USER_ID_BASE} - 1].
+ *
+ * @param cls the class to register
+ */
+ public void registerInternal(Class<?> cls) {
+ if (!extRegistry.registeredClassIdMap.containsKey(cls)) {
+ while (extRegistry.classIdGenerator < registeredId2ClassInfo.length
+ && registeredId2ClassInfo[extRegistry.classIdGenerator] != null) {
+ extRegistry.classIdGenerator++;
+ }
+ registerInternal(cls, extRegistry.classIdGenerator);
+ }
+ }
+
+ /**
+ * Registers a class for internal use with a specified internal ID.
+ *
+ * <p><b>Internal API</b>: This method is for Fory's internal use only.
Users should use {@link
+ * #register(Class, int)} instead.
+ *
+ * <p>Internal IDs are reserved for Fory's built-in types and must be in the
range [0, {@link
+ * #USER_ID_BASE} - 1] (i.e., [0, 255]). User IDs start from {@link
#USER_ID_BASE} and above.
+ *
+ * @param cls the class to register
+ * @param classId the internal ID, must be in range [0, {@link
#USER_ID_BASE} - 1]
+ * @throws IllegalArgumentException if the ID is out of range or already in
use
+ */
+ public void registerInternal(Class<?> cls, int classId) {
+ Preconditions.checkArgument(classId >= 0 && classId < USER_ID_BASE);
+ registerImpl(cls, classId);
+ }
+
+ private void registerImpl(Class<?> cls, int classId) {
+ checkRegisterAllowed();
+ // class id must be less than Integer.MAX_VALUE/2 since we use bit 0 as
class id flag.
+ Preconditions.checkArgument(classId >= 0 && classId < Short.MAX_VALUE);
+ short id = (short) classId;
+ checkRegistration(cls, id, cls.getName());
+ extRegistry.registeredClassIdMap.put(cls, id);
+ if (registeredId2ClassInfo.length <= id) {
+ ClassInfo[] tmp = new ClassInfo[(id + 1) * 2];
+ System.arraycopy(registeredId2ClassInfo, 0, tmp, 0,
registeredId2ClassInfo.length);
+ registeredId2ClassInfo = tmp;
+ }
+ ClassInfo classInfo = classInfoMap.get(cls);
+ if (classInfo != null) {
+ classInfo.classId = id;
+ } else {
+ classInfo = new ClassInfo(this, cls, null, id, NOT_SUPPORT_XLANG);
+ // make `extRegistry.registeredClassIdMap` and `classInfoMap` share same
classInfo
+ // instances.
+ classInfoMap.put(cls, classInfo);
+ }
+ // serializer will be set lazily in `addSerializer` method if it's null.
+ registeredId2ClassInfo[id] = classInfo;
+ extRegistry.registeredClasses.put(cls.getName(), cls);
+ GraalvmSupport.registerClass(cls, fory.getConfig().getConfigHash());
+ }
+
private void checkRegistration(Class<?> cls, short classId, String name) {
if (extRegistry.registeredClassIdMap.containsKey(cls)) {
throw new IllegalArgumentException(
@@ -526,6 +638,7 @@ public class ClassResolver extends TypeResolver {
public Tuple2<String, String> getRegisteredNameTuple(Class<?> cls) {
String name = extRegistry.registeredClasses.inverse().get(cls);
+ Preconditions.checkNotNull(name);
int index = name.lastIndexOf(".");
if (index != -1) {
return Tuple2.of(name.substring(0, index), name.substring(index + 1));
@@ -671,23 +784,38 @@ public class ClassResolver extends TypeResolver {
* @param <T> type of class
*/
public <T> void registerSerializer(Class<T> type, Class<? extends
Serializer> serializerClass) {
- checkRegisterAllowed();
registerSerializer(type, Serializers.newSerializer(fory, type,
serializerClass));
}
+ @Override
+ public void registerSerializer(Class<?> type, Serializer<?> serializer) {
+ checkRegisterAllowed();
+ if
(!serializer.getClass().getPackage().getName().startsWith("org.apache.fory")) {
+ SerializationUtils.validate(type, serializer.getClass());
+ }
+ if (!extRegistry.registeredClassIdMap.containsKey(type) &&
!fory.isCrossLanguage()) {
+ register(type);
+ }
+ registerSerializerImpl(type, serializer);
+ }
+
/**
* If a serializer exists before, it will be replaced by new serializer.
*
* @param type class needed to be serialized/deserialized
* @param serializer serializer for object of {@code type}
*/
- public void registerSerializer(Class<?> type, Serializer<?> serializer) {
+ public void registerInternalSerializer(Class<?> type, Serializer<?>
serializer) {
+ registerSerializerImpl(type, serializer);
+ }
+
+ private void registerSerializerImpl(Class<?> type, Serializer<?> serializer)
{
checkRegisterAllowed();
if
(!serializer.getClass().getPackage().getName().startsWith("org.apache.fory")) {
SerializationUtils.validate(type, serializer.getClass());
}
if (!extRegistry.registeredClassIdMap.containsKey(type) &&
!fory.isCrossLanguage()) {
- register(type);
+ registerInternal(type);
}
addSerializer(type, serializer);
ClassInfo classInfo = classInfoMap.get(type);
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 5b90c7b73..935ee2364 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
@@ -117,26 +117,59 @@ public abstract class TypeResolver {
}
}
+ /**
+ * Registers a class with an auto-assigned user ID.
+ *
+ * @param type the class to register
+ */
public abstract void register(Class<?> type);
+ /**
+ * Registers a class with a user-specified ID. Valid ID range is [0, 32510].
+ *
+ * @param type the class to register
+ * @param id the user ID to assign (0-based)
+ */
public abstract void register(Class<?> type, int id);
+ /**
+ * Registers a class with a namespace and type name for cross-language
serialization.
+ *
+ * @param type the class to register
+ * @param namespace the namespace (can be empty if type name has no conflict)
+ * @param typeName the type name
+ */
public abstract void register(Class<?> type, String namespace, String
typeName);
+ /** Registers a class by name with an auto-assigned user ID. */
public void register(String className) {
register(loadClass(className));
}
+ /** Registers a class by name with a user-specified ID. */
public void register(String className, int classId) {
register(loadClass(className), classId);
}
+ /** Registers a class by name with a namespace and type name. */
public void register(String className, String namespace, String typeName) {
register(loadClass(className), namespace, typeName);
}
+ /**
+ * Registers a custom serializer for a type.
+ *
+ * @param type the class to register
+ * @param serializer the serializer instance to use
+ */
public abstract void registerSerializer(Class<?> type, Serializer<?>
serializer);
+ /**
+ * Registers a custom serializer class for a type.
+ *
+ * @param type the class to register
+ * @param serializerClass the serializer class (will be instantiated by Fory)
+ */
public abstract <T> void registerSerializer(
Class<T> type, Class<? extends Serializer> serializerClass);
@@ -664,6 +697,7 @@ public abstract class TypeResolver {
// Here we set it to 1 because `NO_CLASS_ID` is 0 to avoid calculating it
again in
// `register(Class<?> cls)`.
short classIdGenerator = 1;
+ short userIdGenerator = 0;
SerializerFactory serializerFactory;
final IdentityMap<Class<?>, Short> registeredClassIdMap =
new IdentityMap<>(estimatedNumRegistered);
diff --git
a/java/fory-core/src/main/java/org/apache/fory/serializer/ArraySerializers.java
b/java/fory-core/src/main/java/org/apache/fory/serializer/ArraySerializers.java
index 256207fbe..5042f8058 100644
---
a/java/fory-core/src/main/java/org/apache/fory/serializer/ArraySerializers.java
+++
b/java/fory-core/src/main/java/org/apache/fory/serializer/ArraySerializers.java
@@ -718,28 +718,35 @@ public class ArraySerializers {
public static void registerDefaultSerializers(Fory fory) {
ClassResolver resolver = fory.getClassResolver();
- resolver.registerSerializer(Object[].class, new
ObjectArraySerializer<>(fory, Object[].class));
- resolver.registerSerializer(Class[].class, new
ObjectArraySerializer<>(fory, Class[].class));
- resolver.registerSerializer(byte[].class, new ByteArraySerializer(fory));
- resolver.registerSerializer(Byte[].class, new
ObjectArraySerializer<>(fory, Byte[].class));
- resolver.registerSerializer(char[].class, new CharArraySerializer(fory));
- resolver.registerSerializer(
+ resolver.registerInternalSerializer(
+ Object[].class, new ObjectArraySerializer<>(fory, Object[].class));
+ resolver.registerInternalSerializer(
+ Class[].class, new ObjectArraySerializer<>(fory, Class[].class));
+ resolver.registerInternalSerializer(byte[].class, new
ByteArraySerializer(fory));
+ resolver.registerInternalSerializer(
+ Byte[].class, new ObjectArraySerializer<>(fory, Byte[].class));
+ resolver.registerInternalSerializer(char[].class, new
CharArraySerializer(fory));
+ resolver.registerInternalSerializer(
Character[].class, new ObjectArraySerializer<>(fory,
Character[].class));
- resolver.registerSerializer(short[].class, new ShortArraySerializer(fory));
- resolver.registerSerializer(Short[].class, new
ObjectArraySerializer<>(fory, Short[].class));
- resolver.registerSerializer(int[].class, new IntArraySerializer(fory));
- resolver.registerSerializer(
+ resolver.registerInternalSerializer(short[].class, new
ShortArraySerializer(fory));
+ resolver.registerInternalSerializer(
+ Short[].class, new ObjectArraySerializer<>(fory, Short[].class));
+ resolver.registerInternalSerializer(int[].class, new
IntArraySerializer(fory));
+ resolver.registerInternalSerializer(
Integer[].class, new ObjectArraySerializer<>(fory, Integer[].class));
- resolver.registerSerializer(long[].class, new LongArraySerializer(fory));
- resolver.registerSerializer(Long[].class, new
ObjectArraySerializer<>(fory, Long[].class));
- resolver.registerSerializer(float[].class, new FloatArraySerializer(fory));
- resolver.registerSerializer(Float[].class, new
ObjectArraySerializer<>(fory, Float[].class));
- resolver.registerSerializer(double[].class, new
DoubleArraySerializer(fory));
- resolver.registerSerializer(Double[].class, new
ObjectArraySerializer<>(fory, Double[].class));
- resolver.registerSerializer(boolean[].class, new
BooleanArraySerializer(fory));
- resolver.registerSerializer(
+ resolver.registerInternalSerializer(long[].class, new
LongArraySerializer(fory));
+ resolver.registerInternalSerializer(
+ Long[].class, new ObjectArraySerializer<>(fory, Long[].class));
+ resolver.registerInternalSerializer(float[].class, new
FloatArraySerializer(fory));
+ resolver.registerInternalSerializer(
+ Float[].class, new ObjectArraySerializer<>(fory, Float[].class));
+ resolver.registerInternalSerializer(double[].class, new
DoubleArraySerializer(fory));
+ resolver.registerInternalSerializer(
+ Double[].class, new ObjectArraySerializer<>(fory, Double[].class));
+ resolver.registerInternalSerializer(boolean[].class, new
BooleanArraySerializer(fory));
+ resolver.registerInternalSerializer(
Boolean[].class, new ObjectArraySerializer<>(fory, Boolean[].class));
- resolver.registerSerializer(String[].class, new
StringArraySerializer(fory));
+ resolver.registerInternalSerializer(String[].class, new
StringArraySerializer(fory));
}
// ########################## utils ##########################
diff --git
a/java/fory-core/src/main/java/org/apache/fory/serializer/OptionalSerializers.java
b/java/fory-core/src/main/java/org/apache/fory/serializer/OptionalSerializers.java
index a1ccffb6d..a19fde5ef 100644
---
a/java/fory-core/src/main/java/org/apache/fory/serializer/OptionalSerializers.java
+++
b/java/fory-core/src/main/java/org/apache/fory/serializer/OptionalSerializers.java
@@ -132,9 +132,9 @@ public final class OptionalSerializers {
public static void registerDefaultSerializers(Fory fory) {
ClassResolver resolver = fory.getClassResolver();
- resolver.registerSerializer(Optional.class, new OptionalSerializer(fory));
- resolver.registerSerializer(OptionalInt.class, new
OptionalIntSerializer(fory));
- resolver.registerSerializer(OptionalLong.class, new
OptionalLongSerializer(fory));
- resolver.registerSerializer(OptionalDouble.class, new
OptionalDoubleSerializer(fory));
+ resolver.registerInternalSerializer(Optional.class, new
OptionalSerializer(fory));
+ resolver.registerInternalSerializer(OptionalInt.class, new
OptionalIntSerializer(fory));
+ resolver.registerInternalSerializer(OptionalLong.class, new
OptionalLongSerializer(fory));
+ resolver.registerInternalSerializer(OptionalDouble.class, new
OptionalDoubleSerializer(fory));
}
}
diff --git
a/java/fory-core/src/main/java/org/apache/fory/serializer/PrimitiveSerializers.java
b/java/fory-core/src/main/java/org/apache/fory/serializer/PrimitiveSerializers.java
index 868ced0af..aecc0b56b 100644
---
a/java/fory-core/src/main/java/org/apache/fory/serializer/PrimitiveSerializers.java
+++
b/java/fory-core/src/main/java/org/apache/fory/serializer/PrimitiveSerializers.java
@@ -294,21 +294,21 @@ public class PrimitiveSerializers {
public static void registerDefaultSerializers(Fory fory) {
// primitive types will be boxed.
ClassResolver resolver = fory.getClassResolver();
- resolver.registerSerializer(boolean.class, new BooleanSerializer(fory,
boolean.class));
- resolver.registerSerializer(byte.class, new ByteSerializer(fory,
byte.class));
- resolver.registerSerializer(short.class, new ShortSerializer(fory,
short.class));
- resolver.registerSerializer(char.class, new CharSerializer(fory,
char.class));
- resolver.registerSerializer(int.class, new IntSerializer(fory, int.class));
- resolver.registerSerializer(long.class, new LongSerializer(fory,
long.class));
- resolver.registerSerializer(float.class, new FloatSerializer(fory,
float.class));
- resolver.registerSerializer(double.class, new DoubleSerializer(fory,
double.class));
- resolver.registerSerializer(Boolean.class, new BooleanSerializer(fory,
Boolean.class));
- resolver.registerSerializer(Byte.class, new ByteSerializer(fory,
Byte.class));
- resolver.registerSerializer(Short.class, new ShortSerializer(fory,
Short.class));
- resolver.registerSerializer(Character.class, new CharSerializer(fory,
Character.class));
- resolver.registerSerializer(Integer.class, new IntSerializer(fory,
Integer.class));
- resolver.registerSerializer(Long.class, new LongSerializer(fory,
Long.class));
- resolver.registerSerializer(Float.class, new FloatSerializer(fory,
Float.class));
- resolver.registerSerializer(Double.class, new DoubleSerializer(fory,
Double.class));
+ resolver.registerInternalSerializer(boolean.class, new
BooleanSerializer(fory, boolean.class));
+ resolver.registerInternalSerializer(byte.class, new ByteSerializer(fory,
byte.class));
+ resolver.registerInternalSerializer(short.class, new ShortSerializer(fory,
short.class));
+ resolver.registerInternalSerializer(char.class, new CharSerializer(fory,
char.class));
+ resolver.registerInternalSerializer(int.class, new IntSerializer(fory,
int.class));
+ resolver.registerInternalSerializer(long.class, new LongSerializer(fory,
long.class));
+ resolver.registerInternalSerializer(float.class, new FloatSerializer(fory,
float.class));
+ resolver.registerInternalSerializer(double.class, new
DoubleSerializer(fory, double.class));
+ resolver.registerInternalSerializer(Boolean.class, new
BooleanSerializer(fory, Boolean.class));
+ resolver.registerInternalSerializer(Byte.class, new ByteSerializer(fory,
Byte.class));
+ resolver.registerInternalSerializer(Short.class, new ShortSerializer(fory,
Short.class));
+ resolver.registerInternalSerializer(Character.class, new
CharSerializer(fory, Character.class));
+ resolver.registerInternalSerializer(Integer.class, new IntSerializer(fory,
Integer.class));
+ resolver.registerInternalSerializer(Long.class, new LongSerializer(fory,
Long.class));
+ resolver.registerInternalSerializer(Float.class, new FloatSerializer(fory,
Float.class));
+ resolver.registerInternalSerializer(Double.class, new
DoubleSerializer(fory, Double.class));
}
}
diff --git
a/java/fory-core/src/main/java/org/apache/fory/serializer/Serializers.java
b/java/fory-core/src/main/java/org/apache/fory/serializer/Serializers.java
index d1a46d7cb..a75da3ded 100644
--- a/java/fory-core/src/main/java/org/apache/fory/serializer/Serializers.java
+++ b/java/fory-core/src/main/java/org/apache/fory/serializer/Serializers.java
@@ -591,19 +591,19 @@ public class Serializers {
public static void registerDefaultSerializers(Fory fory) {
ClassResolver resolver = fory.getClassResolver();
- resolver.registerSerializer(Class.class, new ClassSerializer(fory));
- resolver.registerSerializer(StringBuilder.class, new
StringBuilderSerializer(fory));
- resolver.registerSerializer(StringBuffer.class, new
StringBufferSerializer(fory));
- resolver.registerSerializer(BigInteger.class, new
BigIntegerSerializer(fory));
- resolver.registerSerializer(BigDecimal.class, new
BigDecimalSerializer(fory));
- resolver.registerSerializer(AtomicBoolean.class, new
AtomicBooleanSerializer(fory));
- resolver.registerSerializer(AtomicInteger.class, new
AtomicIntegerSerializer(fory));
- resolver.registerSerializer(AtomicLong.class, new
AtomicLongSerializer(fory));
- resolver.registerSerializer(AtomicReference.class, new
AtomicReferenceSerializer(fory));
- resolver.registerSerializer(Currency.class, new CurrencySerializer(fory));
- resolver.registerSerializer(URI.class, new URISerializer(fory));
- resolver.registerSerializer(Pattern.class, new RegexSerializer(fory));
- resolver.registerSerializer(UUID.class, new UUIDSerializer(fory));
- resolver.registerSerializer(Object.class, new EmptyObjectSerializer(fory));
+ resolver.registerInternalSerializer(Class.class, new
ClassSerializer(fory));
+ resolver.registerInternalSerializer(StringBuilder.class, new
StringBuilderSerializer(fory));
+ resolver.registerInternalSerializer(StringBuffer.class, new
StringBufferSerializer(fory));
+ resolver.registerInternalSerializer(BigInteger.class, new
BigIntegerSerializer(fory));
+ resolver.registerInternalSerializer(BigDecimal.class, new
BigDecimalSerializer(fory));
+ resolver.registerInternalSerializer(AtomicBoolean.class, new
AtomicBooleanSerializer(fory));
+ resolver.registerInternalSerializer(AtomicInteger.class, new
AtomicIntegerSerializer(fory));
+ resolver.registerInternalSerializer(AtomicLong.class, new
AtomicLongSerializer(fory));
+ resolver.registerInternalSerializer(AtomicReference.class, new
AtomicReferenceSerializer(fory));
+ resolver.registerInternalSerializer(Currency.class, new
CurrencySerializer(fory));
+ resolver.registerInternalSerializer(URI.class, new URISerializer(fory));
+ resolver.registerInternalSerializer(Pattern.class, new
RegexSerializer(fory));
+ resolver.registerInternalSerializer(UUID.class, new UUIDSerializer(fory));
+ resolver.registerInternalSerializer(Object.class, new
EmptyObjectSerializer(fory));
}
}
diff --git
a/java/fory-core/src/main/java/org/apache/fory/serializer/TimeSerializers.java
b/java/fory-core/src/main/java/org/apache/fory/serializer/TimeSerializers.java
index f0b4d99ae..a328b65c5 100644
---
a/java/fory-core/src/main/java/org/apache/fory/serializer/TimeSerializers.java
+++
b/java/fory-core/src/main/java/org/apache/fory/serializer/TimeSerializers.java
@@ -709,22 +709,22 @@ public class TimeSerializers {
public static void registerDefaultSerializers(Fory fory) {
ClassResolver resolver = fory.getClassResolver();
- resolver.registerSerializer(Date.class, new DateSerializer(fory));
- resolver.registerSerializer(java.sql.Date.class, new
SqlDateSerializer(fory));
- resolver.registerSerializer(Time.class, new SqlTimeSerializer(fory));
- resolver.registerSerializer(Timestamp.class, new
TimestampSerializer(fory));
- resolver.registerSerializer(LocalDate.class, new
LocalDateSerializer(fory));
- resolver.registerSerializer(LocalTime.class, new
LocalTimeSerializer(fory));
- resolver.registerSerializer(LocalDateTime.class, new
LocalDateTimeSerializer(fory));
- resolver.registerSerializer(Instant.class, new InstantSerializer(fory));
- resolver.registerSerializer(Duration.class, new DurationSerializer(fory));
- resolver.registerSerializer(ZoneOffset.class, new
ZoneOffsetSerializer(fory));
- resolver.registerSerializer(ZonedDateTime.class, new
ZonedDateTimeSerializer(fory));
- resolver.registerSerializer(Year.class, new YearSerializer(fory));
- resolver.registerSerializer(YearMonth.class, new
YearMonthSerializer(fory));
- resolver.registerSerializer(MonthDay.class, new MonthDaySerializer(fory));
- resolver.registerSerializer(Period.class, new PeriodSerializer(fory));
- resolver.registerSerializer(OffsetTime.class, new
OffsetTimeSerializer(fory));
- resolver.registerSerializer(OffsetDateTime.class, new
OffsetDateTimeSerializer(fory));
+ resolver.registerInternalSerializer(Date.class, new DateSerializer(fory));
+ resolver.registerInternalSerializer(java.sql.Date.class, new
SqlDateSerializer(fory));
+ resolver.registerInternalSerializer(Time.class, new
SqlTimeSerializer(fory));
+ resolver.registerInternalSerializer(Timestamp.class, new
TimestampSerializer(fory));
+ resolver.registerInternalSerializer(LocalDate.class, new
LocalDateSerializer(fory));
+ resolver.registerInternalSerializer(LocalTime.class, new
LocalTimeSerializer(fory));
+ resolver.registerInternalSerializer(LocalDateTime.class, new
LocalDateTimeSerializer(fory));
+ resolver.registerInternalSerializer(Instant.class, new
InstantSerializer(fory));
+ resolver.registerInternalSerializer(Duration.class, new
DurationSerializer(fory));
+ resolver.registerInternalSerializer(ZoneOffset.class, new
ZoneOffsetSerializer(fory));
+ resolver.registerInternalSerializer(ZonedDateTime.class, new
ZonedDateTimeSerializer(fory));
+ resolver.registerInternalSerializer(Year.class, new YearSerializer(fory));
+ resolver.registerInternalSerializer(YearMonth.class, new
YearMonthSerializer(fory));
+ resolver.registerInternalSerializer(MonthDay.class, new
MonthDaySerializer(fory));
+ resolver.registerInternalSerializer(Period.class, new
PeriodSerializer(fory));
+ resolver.registerInternalSerializer(OffsetTime.class, new
OffsetTimeSerializer(fory));
+ resolver.registerInternalSerializer(OffsetDateTime.class, new
OffsetDateTimeSerializer(fory));
}
}
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 2aae03677..a7a7225bb 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
@@ -1002,55 +1002,58 @@ public class CollectionSerializers {
public static void registerDefaultSerializers(Fory fory) {
ClassResolver resolver = fory.getClassResolver();
- resolver.registerSerializer(ArrayList.class, new
ArrayListSerializer(fory));
+ resolver.registerInternalSerializer(ArrayList.class, new
ArrayListSerializer(fory));
Class arrayAsListClass = Arrays.asList(1, 2).getClass();
- resolver.registerSerializer(
+ resolver.registerInternalSerializer(
arrayAsListClass, new ArraysAsListSerializer(fory, arrayAsListClass));
- resolver.registerSerializer(
+ resolver.registerInternalSerializer(
LinkedList.class, new CollectionSerializer(fory, LinkedList.class,
true));
- resolver.registerSerializer(HashSet.class, new HashSetSerializer(fory));
- resolver.registerSerializer(LinkedHashSet.class, new
LinkedHashSetSerializer(fory));
- resolver.registerSerializer(TreeSet.class, new SortedSetSerializer<>(fory,
TreeSet.class));
- resolver.registerSerializer(
+ resolver.registerInternalSerializer(HashSet.class, new
HashSetSerializer(fory));
+ resolver.registerInternalSerializer(LinkedHashSet.class, new
LinkedHashSetSerializer(fory));
+ resolver.registerInternalSerializer(
+ TreeSet.class, new SortedSetSerializer<>(fory, TreeSet.class));
+ resolver.registerInternalSerializer(
Collections.EMPTY_LIST.getClass(),
new EmptyListSerializer(fory, (Class<List<?>>)
Collections.EMPTY_LIST.getClass()));
- resolver.registerSerializer(
+ resolver.registerInternalSerializer(
Collections.emptySortedSet().getClass(),
new EmptySortedSetSerializer(
fory, (Class<SortedSet<?>>)
Collections.emptySortedSet().getClass()));
- resolver.registerSerializer(
+ resolver.registerInternalSerializer(
Collections.EMPTY_SET.getClass(),
new EmptySetSerializer(fory, (Class<Set<?>>)
Collections.EMPTY_SET.getClass()));
- resolver.registerSerializer(
+ resolver.registerInternalSerializer(
Collections.singletonList(null).getClass(),
new CollectionsSingletonListSerializer(
fory, (Class<List<?>>)
Collections.singletonList(null).getClass()));
- resolver.registerSerializer(
+ resolver.registerInternalSerializer(
Collections.singleton(null).getClass(),
new CollectionsSingletonSetSerializer(
fory, (Class<Set<?>>) Collections.singleton(null).getClass()));
- resolver.registerSerializer(
+ resolver.registerInternalSerializer(
ConcurrentSkipListSet.class,
new ConcurrentSkipListSetSerializer(fory,
ConcurrentSkipListSet.class));
- resolver.registerSerializer(Vector.class, new VectorSerializer(fory,
Vector.class));
- resolver.registerSerializer(ArrayDeque.class, new
ArrayDequeSerializer(fory, ArrayDeque.class));
- resolver.registerSerializer(BitSet.class, new BitSetSerializer(fory,
BitSet.class));
- resolver.registerSerializer(
+ resolver.registerInternalSerializer(Vector.class, new
VectorSerializer(fory, Vector.class));
+ resolver.registerInternalSerializer(
+ ArrayDeque.class, new ArrayDequeSerializer(fory, ArrayDeque.class));
+ resolver.registerInternalSerializer(BitSet.class, new
BitSetSerializer(fory, BitSet.class));
+ resolver.registerInternalSerializer(
PriorityQueue.class, new PriorityQueueSerializer(fory,
PriorityQueue.class));
- resolver.registerSerializer(
+ resolver.registerInternalSerializer(
ArrayBlockingQueue.class, new ArrayBlockingQueueSerializer(fory,
ArrayBlockingQueue.class));
- resolver.registerSerializer(
+ resolver.registerInternalSerializer(
LinkedBlockingQueue.class,
new LinkedBlockingQueueSerializer(fory, LinkedBlockingQueue.class));
- resolver.registerSerializer(
+ resolver.registerInternalSerializer(
CopyOnWriteArrayList.class,
new CopyOnWriteArrayListSerializer(fory, CopyOnWriteArrayList.class));
final Class setFromMapClass = Collections.newSetFromMap(new
HashMap<>()).getClass();
- resolver.registerSerializer(setFromMapClass, new
SetFromMapSerializer(fory, setFromMapClass));
- resolver.registerSerializer(
+ resolver.registerInternalSerializer(
+ setFromMapClass, new SetFromMapSerializer(fory, setFromMapClass));
+ resolver.registerInternalSerializer(
ConcurrentHashMap.KeySetView.class,
new ConcurrentHashMapKeySetViewSerializer(fory,
ConcurrentHashMap.KeySetView.class));
- resolver.registerSerializer(
+ resolver.registerInternalSerializer(
CopyOnWriteArraySet.class,
new CopyOnWriteArraySetSerializer(fory, CopyOnWriteArraySet.class));
}
diff --git
a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/GuavaCollectionSerializers.java
b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/GuavaCollectionSerializers.java
index 1b7ab42ad..535178886 100644
---
a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/GuavaCollectionSerializers.java
+++
b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/GuavaCollectionSerializers.java
@@ -404,63 +404,63 @@ public class GuavaCollectionSerializers {
ClassResolver resolver = fory.getClassResolver();
Class cls =
loadClass(pkg + ".RegularImmutableBiMap", ImmutableBiMap.of("k1", 1,
"k2", 4).getClass());
- resolver.registerSerializer(cls, new ImmutableBiMapSerializer(fory, cls));
+ resolver.registerInternalSerializer(cls, new
ImmutableBiMapSerializer(fory, cls));
cls = loadClass(pkg + ".SingletonImmutableBiMap", ImmutableBiMap.of(1,
2).getClass());
- resolver.registerSerializer(cls, new ImmutableBiMapSerializer(fory, cls));
+ resolver.registerInternalSerializer(cls, new
ImmutableBiMapSerializer(fory, cls));
cls = loadClass(pkg + ".RegularImmutableMap", ImmutableMap.of("k1", 1,
"k2", 2).getClass());
- resolver.registerSerializer(cls, new ImmutableMapSerializer(fory, cls));
+ resolver.registerInternalSerializer(cls, new ImmutableMapSerializer(fory,
cls));
cls = loadClass(pkg + ".RegularImmutableList",
ImmutableList.of().getClass());
- resolver.registerSerializer(cls, new RegularImmutableListSerializer(fory,
cls));
+ resolver.registerInternalSerializer(cls, new
RegularImmutableListSerializer(fory, cls));
cls = loadClass(pkg + ".SingletonImmutableList",
ImmutableList.of(1).getClass());
- resolver.registerSerializer(cls, new ImmutableListSerializer(fory, cls));
+ resolver.registerInternalSerializer(cls, new ImmutableListSerializer(fory,
cls));
cls = loadClass(pkg + ".RegularImmutableSet", ImmutableSet.of(1,
2).getClass());
- resolver.registerSerializer(cls, new ImmutableSetSerializer(fory, cls));
+ resolver.registerInternalSerializer(cls, new ImmutableSetSerializer(fory,
cls));
cls = loadClass(pkg + ".SingletonImmutableSet",
ImmutableSet.of(1).getClass());
- resolver.registerSerializer(cls, new ImmutableSetSerializer(fory, cls));
+ resolver.registerInternalSerializer(cls, new ImmutableSetSerializer(fory,
cls));
// sorted set/map doesn't support xlang.
cls = loadClass(pkg + ".RegularImmutableSortedSet",
ImmutableSortedSet.of(1, 2).getClass());
- resolver.registerSerializer(cls, new ImmutableSortedSetSerializer<>(fory,
cls));
+ resolver.registerInternalSerializer(cls, new
ImmutableSortedSetSerializer<>(fory, cls));
cls = loadClass(pkg + ".ImmutableSortedMap", ImmutableSortedMap.of(1,
2).getClass());
- resolver.registerSerializer(cls, new ImmutableSortedMapSerializer<>(fory,
cls));
+ resolver.registerInternalSerializer(cls, new
ImmutableSortedMapSerializer<>(fory, cls));
// Guava version before 19.0, of() return
//
EmptyImmutableSet/EmptyImmutableBiMap/EmptyImmutableSortedMap/EmptyImmutableSortedSet
// we register if class exist or register empty to deserialize.
if (checkClassExist(pkg + ".EmptyImmutableSet")) {
cls = loadClass(pkg + ".EmptyImmutableSet",
ImmutableSet.of().getClass());
- resolver.registerSerializer(cls, new ImmutableSetSerializer(fory, cls));
+ resolver.registerInternalSerializer(cls, new
ImmutableSetSerializer(fory, cls));
} else {
class GuavaEmptySet {}
cls = GuavaEmptySet.class;
- resolver.registerSerializer(cls, new ImmutableSetSerializer(fory, cls));
+ resolver.registerInternalSerializer(cls, new
ImmutableSetSerializer(fory, cls));
}
if (checkClassExist(pkg + ".EmptyImmutableBiMap")) {
cls = loadClass(pkg + ".EmptyImmutableBiMap",
ImmutableBiMap.of().getClass());
- resolver.registerSerializer(cls, new ImmutableMapSerializer(fory, cls));
+ resolver.registerInternalSerializer(cls, new
ImmutableMapSerializer(fory, cls));
} else {
class GuavaEmptyBiMap {}
cls = GuavaEmptyBiMap.class;
- resolver.registerSerializer(cls, new ImmutableMapSerializer(fory, cls));
+ resolver.registerInternalSerializer(cls, new
ImmutableMapSerializer(fory, cls));
}
if (checkClassExist(pkg + ".EmptyImmutableSortedSet")) {
cls = loadClass(pkg + ".EmptyImmutableSortedSet",
ImmutableSortedSet.of().getClass());
- resolver.registerSerializer(cls, new ImmutableSortedSetSerializer(fory,
cls));
+ resolver.registerInternalSerializer(cls, new
ImmutableSortedSetSerializer(fory, cls));
} else {
class GuavaEmptySortedSet {}
cls = GuavaEmptySortedSet.class;
- resolver.registerSerializer(cls, new ImmutableSortedSetSerializer(fory,
cls));
+ resolver.registerInternalSerializer(cls, new
ImmutableSortedSetSerializer(fory, cls));
}
if (checkClassExist(pkg + ".EmptyImmutableSortedMap")) {
cls = loadClass(pkg + ".EmptyImmutableSortedMap",
ImmutableSortedMap.of().getClass());
- resolver.registerSerializer(cls, new ImmutableSortedMapSerializer(fory,
cls));
+ resolver.registerInternalSerializer(cls, new
ImmutableSortedMapSerializer(fory, cls));
} else {
class GuavaEmptySortedMap {}
cls = GuavaEmptySortedMap.class;
- resolver.registerSerializer(cls, new ImmutableSortedMapSerializer(fory,
cls));
+ resolver.registerInternalSerializer(cls, new
ImmutableSortedMapSerializer(fory, cls));
}
}
diff --git
a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/ImmutableCollectionSerializers.java
b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/ImmutableCollectionSerializers.java
index 4664ea1e2..32e051cb3 100644
---
a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/ImmutableCollectionSerializers.java
+++
b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/ImmutableCollectionSerializers.java
@@ -261,12 +261,12 @@ public class ImmutableCollectionSerializers {
public static void registerSerializers(Fory fory) {
ClassResolver resolver = fory.getClassResolver();
- resolver.registerSerializer(List12, new ImmutableListSerializer(fory,
List12));
- resolver.registerSerializer(ListN, new ImmutableListSerializer(fory,
ListN));
- resolver.registerSerializer(SubList, new ImmutableListSerializer(fory,
SubList));
- resolver.registerSerializer(Set12, new ImmutableSetSerializer(fory,
Set12));
- resolver.registerSerializer(SetN, new ImmutableSetSerializer(fory, SetN));
- resolver.registerSerializer(Map1, new ImmutableMapSerializer(fory, Map1));
- resolver.registerSerializer(MapN, new ImmutableMapSerializer(fory, MapN));
+ resolver.registerInternalSerializer(List12, new
ImmutableListSerializer(fory, List12));
+ resolver.registerInternalSerializer(ListN, new
ImmutableListSerializer(fory, ListN));
+ resolver.registerInternalSerializer(SubList, new
ImmutableListSerializer(fory, SubList));
+ resolver.registerInternalSerializer(Set12, new
ImmutableSetSerializer(fory, Set12));
+ resolver.registerInternalSerializer(SetN, new ImmutableSetSerializer(fory,
SetN));
+ resolver.registerInternalSerializer(Map1, new ImmutableMapSerializer(fory,
Map1));
+ resolver.registerInternalSerializer(MapN, new ImmutableMapSerializer(fory,
MapN));
}
}
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 d61462239..1a05377dc 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
@@ -495,27 +495,28 @@ public class MapSerializers {
// TODO(chaokunyang) support ConcurrentSkipListMap.SubMap mo efficiently.
public static void registerDefaultSerializers(Fory fory) {
ClassResolver resolver = fory.getClassResolver();
- resolver.registerSerializer(HashMap.class, new HashMapSerializer(fory));
+ resolver.registerInternalSerializer(HashMap.class, new
HashMapSerializer(fory));
fory.getClassResolver()
- .registerSerializer(LinkedHashMap.class, new
LinkedHashMapSerializer(fory));
- resolver.registerSerializer(TreeMap.class, new SortedMapSerializer<>(fory,
TreeMap.class));
- resolver.registerSerializer(
+ .registerInternalSerializer(LinkedHashMap.class, new
LinkedHashMapSerializer(fory));
+ resolver.registerInternalSerializer(
+ TreeMap.class, new SortedMapSerializer<>(fory, TreeMap.class));
+ resolver.registerInternalSerializer(
Collections.EMPTY_MAP.getClass(),
new EmptyMapSerializer(fory, (Class<Map<?, ?>>)
Collections.EMPTY_MAP.getClass()));
- resolver.registerSerializer(
+ resolver.registerInternalSerializer(
Collections.emptySortedMap().getClass(),
new EmptySortedMapSerializer(
fory, (Class<SortedMap<?, ?>>)
Collections.emptySortedMap().getClass()));
- resolver.registerSerializer(
+ resolver.registerInternalSerializer(
Collections.singletonMap(null, null).getClass(),
new SingletonMapSerializer(
fory, (Class<Map<?, ?>>) Collections.singletonMap(null,
null).getClass()));
- resolver.registerSerializer(
+ resolver.registerInternalSerializer(
ConcurrentHashMap.class, new ConcurrentHashMapSerializer(fory,
ConcurrentHashMap.class));
- resolver.registerSerializer(
+ resolver.registerInternalSerializer(
ConcurrentSkipListMap.class,
new ConcurrentSkipListMapSerializer(fory,
ConcurrentSkipListMap.class));
- resolver.registerSerializer(EnumMap.class, new EnumMapSerializer(fory));
- resolver.registerSerializer(LazyMap.class, new LazyMapSerializer(fory));
+ resolver.registerInternalSerializer(EnumMap.class, new
EnumMapSerializer(fory));
+ resolver.registerInternalSerializer(LazyMap.class, new
LazyMapSerializer(fory));
}
}
diff --git
a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/SubListSerializers.java
b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/SubListSerializers.java
index 4cec75f4c..27da62670 100644
---
a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/SubListSerializers.java
+++
b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/SubListSerializers.java
@@ -70,9 +70,10 @@ public class SubListSerializers {
for (Class<?> cls :
new Class[] {SubListClass, RandomAccessSubListClass,
ArrayListSubListClass}) {
if (fory.trackingRef() && preserveView && !fory.isCrossLanguage()) {
- classResolver.registerSerializer(cls, new SubListViewSerializer(fory,
cls));
+ classResolver.registerInternalSerializer(cls, new
SubListViewSerializer(fory, cls));
} else {
- classResolver.registerSerializer(cls, new SubListSerializer(fory,
(Class<List>) cls));
+ classResolver.registerInternalSerializer(
+ cls, new SubListSerializer(fory, (Class<List>) cls));
}
}
}
diff --git
a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/SynchronizedSerializers.java
b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/SynchronizedSerializers.java
index 782233bb1..9c8bf2c66 100644
---
a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/SynchronizedSerializers.java
+++
b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/SynchronizedSerializers.java
@@ -214,7 +214,7 @@ public class SynchronizedSerializers {
try {
ClassResolver resolver = fory.getClassResolver();
for (Tuple2<Class<?>, Function> factory : synchronizedFactories()) {
- resolver.registerSerializer(factory.f0, createSerializer(fory,
factory));
+ resolver.registerInternalSerializer(factory.f0, createSerializer(fory,
factory));
}
} catch (Throwable e) {
ExceptionUtils.ignore(e);
diff --git
a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/UnmodifiableSerializers.java
b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/UnmodifiableSerializers.java
index 5ef3ff33d..cc6797158 100644
---
a/java/fory-core/src/main/java/org/apache/fory/serializer/collection/UnmodifiableSerializers.java
+++
b/java/fory-core/src/main/java/org/apache/fory/serializer/collection/UnmodifiableSerializers.java
@@ -212,7 +212,7 @@ public class UnmodifiableSerializers {
try {
ClassResolver resolver = fory.getClassResolver();
for (Tuple2<Class<?>, Function> factory : unmodifiableFactories()) {
- resolver.registerSerializer(factory.f0, createSerializer(fory,
factory));
+ resolver.registerInternalSerializer(factory.f0, createSerializer(fory,
factory));
}
} catch (Throwable e) {
ExceptionUtils.ignore(e);
diff --git
a/java/fory-core/src/test/java/org/apache/fory/resolver/ClassResolverTest.java
b/java/fory-core/src/test/java/org/apache/fory/resolver/ClassResolverTest.java
index 34fcc589c..1328536e6 100644
---
a/java/fory-core/src/test/java/org/apache/fory/resolver/ClassResolverTest.java
+++
b/java/fory-core/src/test/java/org/apache/fory/resolver/ClassResolverTest.java
@@ -98,7 +98,7 @@ public class ClassResolverTest extends ForyTestBase {
Assert.assertThrows(
IllegalArgumentException.class, () -> classResolver.register(C1.class,
"ns", "C1"));
Assert.assertThrows(
- IllegalArgumentException.class, () -> classResolver.register(C1.class,
200));
+ IllegalArgumentException.class, () ->
classResolver.registerInternal(C1.class, 200));
classResolver.register(C2.class, "", "C2");
classResolver.register(Foo.class, "ns", "Foo");
@@ -118,6 +118,35 @@ public class ClassResolverTest extends ForyTestBase {
Fory fory =
Fory.builder().withLanguage(Language.JAVA).requireClassRegistration(false).build();
}
+ @Test
+ public void testRegisterClassWithUserIds() {
+ // Test that user IDs 0 and 1 work correctly (mapped to internal IDs 256
and 257)
+ Fory fory =
Fory.builder().withLanguage(Language.JAVA).requireClassRegistration(true).build();
+ ClassResolver classResolver = fory.getClassResolver();
+
+ // Register with user ID 0
+ classResolver.register(Foo.class, 0);
+ // Register with user ID 1
+ classResolver.register(Bar.class, 1);
+
+ // Verify internal IDs are offset by USER_ID_BASE (256)
+ assertEquals(
+ classResolver.getRegisteredClassId(Foo.class).shortValue(),
ClassResolver.USER_ID_BASE);
+ assertEquals(
+ classResolver.getRegisteredClassId(Bar.class).shortValue(),
+ (short) (ClassResolver.USER_ID_BASE + 1));
+
+ // Verify serialization/deserialization works
+ Foo foo = new Foo();
+ foo.f1 = 42;
+ serDeCheck(fory, foo);
+
+ Bar bar = new Bar();
+ bar.f1 = 10;
+ bar.f2 = 100L;
+ serDeCheck(fory, bar);
+ }
+
@Test
public void testGetSerializerClass() throws ClassNotFoundException {
{
@@ -322,7 +351,7 @@ public class ClassResolverTest extends ForyTestBase {
assertSame(classInfo.getSerializer().getClass(), ObjectSerializer.class);
}
{
- classResolver.register(Bar.class);
+ classResolver.registerInternal(Bar.class);
ClassInfo classInfo = classResolver.getClassInfo(Bar.class);
classResolver.setSerializer(Bar.class, new ObjectSerializer<>(fory,
Bar.class));
Assert.assertSame(classResolver.getClassInfo(Bar.class), classInfo);
diff --git
a/java/fory-simd/src/main/java/org/apache/fory/serializer/CompressedArraySerializers.java
b/java/fory-simd/src/main/java/org/apache/fory/serializer/CompressedArraySerializers.java
index e329afd00..7c7fe3edc 100644
---
a/java/fory-simd/src/main/java/org/apache/fory/serializer/CompressedArraySerializers.java
+++
b/java/fory-simd/src/main/java/org/apache/fory/serializer/CompressedArraySerializers.java
@@ -21,6 +21,7 @@ package org.apache.fory.serializer;
import java.util.Arrays;
import org.apache.fory.Fory;
+import org.apache.fory.ThreadSafeFory;
import org.apache.fory.memory.MemoryBuffer;
import org.apache.fory.memory.Platform;
import org.apache.fory.resolver.ClassResolver;
@@ -73,13 +74,31 @@ public final class CompressedArraySerializers {
boolean compressLong = fory.getConfig().compressLongArray();
if (compressInt) {
- resolver.registerSerializer(int[].class, new
CompressedIntArraySerializer(fory));
+ resolver.registerInternalSerializer(int[].class, new
CompressedIntArraySerializer(fory));
}
if (compressLong) {
- resolver.registerSerializer(long[].class, new
CompressedLongArraySerializer(fory));
+ resolver.registerInternalSerializer(long[].class, new
CompressedLongArraySerializer(fory));
}
}
+ /**
+ * Register compressed array serializers with the given Fory instance.
+ *
+ * <p>Example usage:
+ *
+ * <pre>{@code
+ * ThreadSafeFory fory = Fory.builder()
+ * .withConfig(Config.compressIntArray(true).compressLongArray(true))
+ * .buildThreadSafeFory();
+ * CompressedArraySerializers.registerSerializers(fory);
+ * }</pre>
+ *
+ * @param fory the ThreadSafeFory instance to register serializers with
+ */
+ public static void registerIfEnabled(ThreadSafeFory fory) {
+ fory.registerCallback(CompressedArraySerializers::registerIfEnabled);
+ }
+
/**
* Register compressed array serializers with the given Fory instance.
*
@@ -91,8 +110,13 @@ public final class CompressedArraySerializers {
*/
public static void register(Fory fory) {
ClassResolver resolver = fory.getClassResolver();
- resolver.registerSerializer(int[].class, new
CompressedIntArraySerializer(fory));
- resolver.registerSerializer(long[].class, new
CompressedLongArraySerializer(fory));
+ resolver.registerInternalSerializer(int[].class, new
CompressedIntArraySerializer(fory));
+ resolver.registerInternalSerializer(long[].class, new
CompressedLongArraySerializer(fory));
+ }
+
+ /** Register compressed array serializers with the given Fory instance. */
+ public static void register(ThreadSafeFory fory) {
+ fory.registerCallback(CompressedArraySerializers::register);
}
public static final class CompressedIntArraySerializer extends
PrimitiveArraySerializer<int[]> {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]