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/fury.git
The following commit(s) were added to refs/heads/main by this push:
new e412cd46 feat(java): support register type by name in java (#2053)
e412cd46 is described below
commit e412cd46640e935715bcf196ff4ff1048837d845
Author: Shawn Yang <[email protected]>
AuthorDate: Sun Feb 9 23:18:37 2025 +0800
feat(java): support register type by name in java (#2053)
## What does this PR do?
support register type by name in java
## Related issues
Closes https://github.com/apache/fury/discussions/1969
## Does this PR introduce any user-facing change?
<!--
If any user-facing interface changes, please [open an
issue](https://github.com/apache/fury/issues/new/choose) describing the
need to do so and update the document if necessary.
-->
- [ ] 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.
-->
---
docs/guide/java_serialization_guide.md | 17 ++-
.../src/main/java/org/apache/fury/Fury.java | 7 +-
.../java/org/apache/fury/meta/ClassDefEncoder.java | 2 +-
.../java/org/apache/fury/resolver/ClassInfo.java | 38 +++---
.../org/apache/fury/resolver/ClassResolver.java | 146 +++++++++++++--------
.../{ClassNameBytes.java => TypeNameBytes.java} | 6 +-
.../org/apache/fury/resolver/XtypeResolver.java | 24 ++--
.../fury-core/native-image.properties | 4 +
.../org/apache/fury/resolver/ClassInfoTest.java | 4 +-
.../apache/fury/resolver/ClassResolverTest.java | 31 +++--
10 files changed, 172 insertions(+), 107 deletions(-)
diff --git a/docs/guide/java_serialization_guide.md
b/docs/guide/java_serialization_guide.md
index c4ee8f1d..be477b06 100644
--- a/docs/guide/java_serialization_guide.md
+++ b/docs/guide/java_serialization_guide.md
@@ -312,7 +312,7 @@ should have same registration order.
```java
Fury fury = xxx;
fury.register(SomeClass.class);
-fury.register(SomeClass1.class,200);
+fury.register(SomeClass1.class, 200);
```
If you invoke `FuryBuilder#requireClassRegistration(false)` to disable class
registration check,
@@ -342,6 +342,21 @@ simplify
the customization of class check mechanism. You can use this checker or
implement more sophisticated checker by
yourself.
+### Register class by name
+
+Register class by id will have better performance and smaller space overhead.
But in some cases, management for a bunch
+of type id is complex. In such cases, registering class by name using API
+`register(Class<?> cls, String namespace, String typeName)` is recommended.
+
+```java
+fury.register(Foo.class, "demo", "Foo");
+```
+
+If there are no duplicate name for type, `namespace` can be left as empty to
reduce serialized size.
+
+**Do not use this API to register class since it will increase serialized size
a lot compared to register
+class by id**
+
### Serializer Registration
You can also register a custom serializer for a class by
`Fury#registerSerializer` API.
diff --git a/java/fury-core/src/main/java/org/apache/fury/Fury.java
b/java/fury-core/src/main/java/org/apache/fury/Fury.java
index 5ccdafd4..3d567587 100644
--- a/java/fury-core/src/main/java/org/apache/fury/Fury.java
+++ b/java/fury-core/src/main/java/org/apache/fury/Fury.java
@@ -210,8 +210,11 @@ public final class Fury implements BaseFury {
}
public void register(Class<?> cls, String namespace, String typeName) {
- Preconditions.checkArgument(language != Language.JAVA);
- xtypeResolver.register(cls, namespace, typeName);
+ if (language == Language.JAVA) {
+ classResolver.register(cls, namespace, typeName);
+ } else {
+ xtypeResolver.register(cls, namespace, typeName);
+ }
}
@Override
diff --git
a/java/fury-core/src/main/java/org/apache/fury/meta/ClassDefEncoder.java
b/java/fury-core/src/main/java/org/apache/fury/meta/ClassDefEncoder.java
index d40dd53d..ce9d936a 100644
--- a/java/fury-core/src/main/java/org/apache/fury/meta/ClassDefEncoder.java
+++ b/java/fury-core/src/main/java/org/apache/fury/meta/ClassDefEncoder.java
@@ -141,7 +141,7 @@ class ClassDefEncoder {
// | num fields + register flag | header + package name | header + class
name
// | header + type id + field name | next field info | ... |
int currentClassHeader = (fields.size() << 1);
- if (classResolver.isRegistered(type)) {
+ if (classResolver.isRegisteredById(type)) {
currentClassHeader |= 1;
classDefBuf.writeVarUint32Small7(currentClassHeader);
classDefBuf.writeVarUint32Small7(classResolver.getRegisteredClassId(type));
diff --git
a/java/fury-core/src/main/java/org/apache/fury/resolver/ClassInfo.java
b/java/fury-core/src/main/java/org/apache/fury/resolver/ClassInfo.java
index 3ca0c855..0f34b4c3 100644
--- a/java/fury-core/src/main/java/org/apache/fury/resolver/ClassInfo.java
+++ b/java/fury-core/src/main/java/org/apache/fury/resolver/ClassInfo.java
@@ -39,9 +39,9 @@ import org.apache.fury.util.function.Functions;
*/
public class ClassInfo {
final Class<?> cls;
- final MetaStringBytes fullClassNameBytes;
- final MetaStringBytes packageNameBytes;
- final MetaStringBytes classNameBytes;
+ final MetaStringBytes fullNameBytes;
+ final MetaStringBytes namespaceBytes;
+ final MetaStringBytes typeNameBytes;
final boolean isDynamicGeneratedClass;
int xtypeId;
Serializer<?> serializer;
@@ -53,23 +53,23 @@ public class ClassInfo {
ClassInfo(
Class<?> cls,
- MetaStringBytes fullClassNameBytes,
- MetaStringBytes packageNameBytes,
- MetaStringBytes classNameBytes,
+ MetaStringBytes fullNameBytes,
+ MetaStringBytes namespaceBytes,
+ MetaStringBytes typeNameBytes,
boolean isDynamicGeneratedClass,
Serializer<?> serializer,
short classId,
short xtypeId) {
this.cls = cls;
- this.fullClassNameBytes = fullClassNameBytes;
- this.packageNameBytes = packageNameBytes;
- this.classNameBytes = classNameBytes;
+ this.fullNameBytes = fullNameBytes;
+ this.namespaceBytes = namespaceBytes;
+ this.typeNameBytes = typeNameBytes;
this.isDynamicGeneratedClass = isDynamicGeneratedClass;
this.xtypeId = xtypeId;
this.serializer = serializer;
this.classId = classId;
if (cls != null && classId == ClassResolver.NO_CLASS_ID) {
- Preconditions.checkArgument(classNameBytes != null);
+ Preconditions.checkArgument(typeNameBytes != null);
}
}
@@ -84,11 +84,11 @@ public class ClassInfo {
needToWriteClassDef = serializer != null &&
classResolver.needToWriteClassDef(serializer);
MetaStringResolver metaStringResolver =
classResolver.getMetaStringResolver();
if (cls != null && classResolver.getFury().getLanguage() != Language.JAVA)
{
- this.fullClassNameBytes =
+ this.fullNameBytes =
metaStringResolver.getOrCreateMetaStringBytes(
GENERIC_ENCODER.encode(cls.getName(), Encoding.UTF_8));
} else {
- this.fullClassNameBytes = null;
+ this.fullNameBytes = null;
}
// When `classId == ClassResolver.REPLACE_STUB_ID` was established,
// means only classes are serialized, not the instance. If we
@@ -97,13 +97,13 @@ public class ClassInfo {
&& (classId == ClassResolver.NO_CLASS_ID || classId ==
ClassResolver.REPLACE_STUB_ID)) {
// REPLACE_STUB_ID for write replace class in `ClassSerializer`.
Tuple2<String, String> tuple2 = Encoders.encodePkgAndClass(cls);
- this.packageNameBytes =
+ this.namespaceBytes =
metaStringResolver.getOrCreateMetaStringBytes(Encoders.encodePackage(tuple2.f0));
- this.classNameBytes =
+ this.typeNameBytes =
metaStringResolver.getOrCreateMetaStringBytes(Encoders.encodeTypeName(tuple2.f1));
} else {
- this.packageNameBytes = null;
- this.classNameBytes = null;
+ this.namespaceBytes = null;
+ this.typeNameBytes = null;
}
this.xtypeId = xtypeId;
this.classId = classId;
@@ -145,11 +145,11 @@ public class ClassInfo {
}
public String decodeNamespace() {
- return packageNameBytes.decode(PACKAGE_DECODER);
+ return namespaceBytes.decode(PACKAGE_DECODER);
}
public String decodeTypeName() {
- return classNameBytes.decode(TYPE_NAME_DECODER);
+ return typeNameBytes.decode(TYPE_NAME_DECODER);
}
@Override
@@ -158,7 +158,7 @@ public class ClassInfo {
+ "cls="
+ cls
+ ", fullClassNameBytes="
- + fullClassNameBytes
+ + fullNameBytes
+ ", isDynamicGeneratedClass="
+ isDynamicGeneratedClass
+ ", serializer="
diff --git
a/java/fury-core/src/main/java/org/apache/fury/resolver/ClassResolver.java
b/java/fury-core/src/main/java/org/apache/fury/resolver/ClassResolver.java
index 00286980..c62aa6bc 100644
--- a/java/fury-core/src/main/java/org/apache/fury/resolver/ClassResolver.java
+++ b/java/fury-core/src/main/java/org/apache/fury/resolver/ClassResolver.java
@@ -21,15 +21,20 @@ package org.apache.fury.resolver;
import static org.apache.fury.Fury.NOT_SUPPORT_XLANG;
import static org.apache.fury.meta.ClassDef.SIZE_TWO_BYTES_FLAG;
+import static org.apache.fury.meta.Encoders.GENERIC_ENCODER;
import static org.apache.fury.meta.Encoders.PACKAGE_DECODER;
import static org.apache.fury.meta.Encoders.PACKAGE_ENCODER;
import static org.apache.fury.meta.Encoders.TYPE_NAME_DECODER;
+import static org.apache.fury.meta.Encoders.encodePackage;
+import static org.apache.fury.meta.Encoders.encodeTypeName;
import static
org.apache.fury.serializer.CodegenSerializer.loadCodegenSerializer;
import static
org.apache.fury.serializer.CodegenSerializer.loadCompatibleCodegenSerializer;
import static
org.apache.fury.serializer.CodegenSerializer.supportCodegenForJavaSerialization;
import static org.apache.fury.type.TypeUtils.OBJECT_TYPE;
import static org.apache.fury.type.TypeUtils.getRawType;
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
import java.io.Externalizable;
import java.io.IOException;
import java.io.Serializable;
@@ -131,7 +136,6 @@ import org.apache.fury.serializer.Serializer;
import org.apache.fury.serializer.SerializerFactory;
import org.apache.fury.serializer.Serializers;
import org.apache.fury.serializer.StringSerializer;
-import org.apache.fury.serializer.StructSerializer;
import org.apache.fury.serializer.TimeSerializers;
import org.apache.fury.serializer.collection.ChildContainerSerializers;
import org.apache.fury.serializer.collection.CollectionSerializer;
@@ -153,6 +157,7 @@ import org.apache.fury.type.ScalaTypes;
import org.apache.fury.type.TypeUtils;
import org.apache.fury.util.GraalvmSupport;
import org.apache.fury.util.Preconditions;
+import org.apache.fury.util.StringUtils;
import org.apache.fury.util.function.Functions;
/**
@@ -222,7 +227,7 @@ public class ClassResolver {
new IdentityMap<>(estimatedNumRegistered, furyMapLoadFactor);
private ClassInfo classInfoCache;
// Every deserialization for unregistered class will query it, performance
is important.
- private final ObjectMap<ClassNameBytes, ClassInfo>
compositeClassNameBytes2ClassInfo =
+ private final ObjectMap<TypeNameBytes, ClassInfo>
compositeNameBytes2ClassInfo =
new ObjectMap<>(16, furyMapLoadFactor);
private final MetaStringResolver metaStringResolver;
private final boolean metaContextShareEnabled;
@@ -240,7 +245,8 @@ public class ClassResolver {
private SerializerFactory serializerFactory;
private final IdentityMap<Class<?>, Short> registeredClassIdMap =
new IdentityMap<>(estimatedNumRegistered);
- private final Map<String, Class<?>> registeredClasses = new
HashMap<>(estimatedNumRegistered);
+ private final BiMap<String, Class<?>> registeredClasses =
+ HashBiMap.create(estimatedNumRegistered);
// avoid potential recursive call for seq codec generation.
// ex. A->field1: B, B.field1: A
private final Set<Class<?>> getClassCtx = new HashSet<>();
@@ -427,17 +433,6 @@ public class ClassResolver {
}
}
- /** register class with given type tag which will be used for cross-language
serialization. */
- public void register(Class<?> cls, String typeTag) {
- if (fury.getLanguage() == Language.JAVA) {
- throw new IllegalArgumentException(
- "Java serialization should register class by "
- + "Fury#register(Class) or Fury.register(Class<?>, Short)");
- }
- register(cls);
- addSerializer(cls, new StructSerializer<>(fury, cls));
- }
-
/**
* Register class with specified id. Currently class id must be `classId >=
0 && classId < 32767`.
* In the future this limitation may be relaxed.
@@ -445,25 +440,8 @@ public class ClassResolver {
public void register(Class<?> cls, int classId) {
// 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);
- if (extRegistry.registeredClassIdMap.containsKey(cls)) {
- throw new IllegalArgumentException(
- String.format(
- "Class %s already registered with id %s.",
- cls, extRegistry.registeredClassIdMap.get(cls)));
- }
- if (extRegistry.registeredClasses.containsKey(cls.getName())) {
- throw new IllegalArgumentException(
- String.format(
- "Class %s with name %s has been registered, registering class
with same name are not allowed.",
- extRegistry.registeredClasses.get(cls.getName()),
cls.getName()));
- }
short id = (short) classId;
- if (id < registeredId2ClassInfo.length && registeredId2ClassInfo[id] !=
null) {
- throw new IllegalArgumentException(
- String.format(
- "Class %s with id %s has been registered, registering class %s
with same id are not allowed.",
- registeredId2ClassInfo[id].getCls(), id, cls.getName()));
- }
+ checkRegistration(cls, id, cls.getName());
extRegistry.registeredClassIdMap.put(cls, id);
if (registeredId2ClassInfo.length <= id) {
ClassInfo[] tmp = new ClassInfo[(id + 1) * 2];
@@ -500,7 +478,62 @@ public class ClassResolver {
register(loadClass(className, false, 0, false), classId, createSerializer);
}
- public boolean isRegistered(Class<?> cls) {
+ /**
+ * Register class with specified namespace and name. If a simpler namespace
or type name is
+ * registered, the serialized class will have smaller payload size. In many
cases, it type name
+ * has no conflict, namespace can be left as empty.
+ */
+ public void register(Class<?> cls, String namespace, String name) {
+ Preconditions.checkArgument(!Functions.isLambda(cls));
+ Preconditions.checkArgument(!ReflectionUtils.isJdkProxy(cls));
+ Preconditions.checkArgument(!cls.isArray());
+ String fullname = name;
+ if (namespace == null) {
+ namespace = "";
+ }
+ if (!StringUtils.isBlank(namespace)) {
+ fullname = namespace + "." + name;
+ }
+ checkRegistration(cls, (short) -1, fullname);
+ MetaStringBytes fullNameBytes =
+ metaStringResolver.getOrCreateMetaStringBytes(
+ GENERIC_ENCODER.encode(fullname, MetaString.Encoding.UTF_8));
+ MetaStringBytes nsBytes =
+
metaStringResolver.getOrCreateMetaStringBytes(encodePackage(namespace));
+ MetaStringBytes nameBytes =
metaStringResolver.getOrCreateMetaStringBytes(encodeTypeName(name));
+ ClassInfo classInfo =
+ new ClassInfo(cls, fullNameBytes, nsBytes, nameBytes, false, null,
NO_CLASS_ID, (short) -1);
+ classInfoMap.put(cls, classInfo);
+ compositeNameBytes2ClassInfo.put(
+ new TypeNameBytes(nsBytes.hashCode, nameBytes.hashCode), classInfo);
+ extRegistry.registeredClasses.put(fullname, cls);
+ }
+
+ private void checkRegistration(Class<?> cls, short classId, String name) {
+ if (extRegistry.registeredClassIdMap.containsKey(cls)) {
+ throw new IllegalArgumentException(
+ String.format(
+ "Class %s already registered with id %s.",
+ cls, extRegistry.registeredClassIdMap.get(cls)));
+ }
+ if (classId > 0
+ && classId < registeredId2ClassInfo.length
+ && registeredId2ClassInfo[classId] != null) {
+ throw new IllegalArgumentException(
+ String.format(
+ "Class %s with id %s has been registered, registering class %s
with same id are not allowed.",
+ registeredId2ClassInfo[classId].getCls(), classId,
cls.getName()));
+ }
+ if (extRegistry.registeredClasses.containsKey(name)
+ || extRegistry.registeredClasses.inverse().containsKey(cls)) {
+ throw new IllegalArgumentException(
+ String.format(
+ "Class %s with name %s has been registered, registering class %s
with same name are not allowed.",
+ extRegistry.registeredClasses.get(name), name, cls));
+ }
+ }
+
+ public boolean isRegisteredById(Class<?> cls) {
return extRegistry.registeredClassIdMap.get(cls) != null;
}
@@ -1267,7 +1300,7 @@ public class ClassResolver {
}
private boolean isSecure(Class<?> cls) {
- if (extRegistry.registeredClassIdMap.containsKey(cls) ||
shimDispatcher.contains(cls)) {
+ if (extRegistry.registeredClasses.inverse().containsKey(cls) ||
shimDispatcher.contains(cls)) {
return true;
}
if (cls.isArray()) {
@@ -1326,10 +1359,10 @@ public class ClassResolver {
if (classInfo.classId == NO_CLASS_ID) { // no class id provided.
// use classname
// if it's null, it's a bug.
- assert classInfo.packageNameBytes != null;
- metaStringResolver.writeMetaStringBytesWithFlag(buffer,
classInfo.packageNameBytes);
- assert classInfo.classNameBytes != null;
- metaStringResolver.writeMetaStringBytes(buffer,
classInfo.classNameBytes);
+ assert classInfo.namespaceBytes != null;
+ metaStringResolver.writeMetaStringBytesWithFlag(buffer,
classInfo.namespaceBytes);
+ assert classInfo.typeNameBytes != null;
+ metaStringResolver.writeMetaStringBytes(buffer,
classInfo.typeNameBytes);
} else {
// use classId
buffer.writeVarUint32(classInfo.classId << 1);
@@ -1650,8 +1683,8 @@ public class ClassResolver {
} else {
// let the lowermost bit of next byte be set, so the deserialization can
know
// whether need to read class by name in advance
- metaStringResolver.writeMetaStringBytesWithFlag(buffer,
classInfo.packageNameBytes);
- metaStringResolver.writeMetaStringBytes(buffer,
classInfo.classNameBytes);
+ metaStringResolver.writeMetaStringBytesWithFlag(buffer,
classInfo.namespaceBytes);
+ metaStringResolver.writeMetaStringBytes(buffer, classInfo.typeNameBytes);
}
classInfo.classId = classId;
}
@@ -1749,25 +1782,24 @@ public class ClassResolver {
private ClassInfo readClassInfoFromBytes(
MemoryBuffer buffer, ClassInfo classInfoCache, int header) {
- MetaStringBytes simpleClassNameBytesCache = classInfoCache.classNameBytes;
- MetaStringBytes packageBytes;
+ MetaStringBytes typeNameBytesCache = classInfoCache.typeNameBytes;
+ MetaStringBytes namespaceBytes;
MetaStringBytes simpleClassNameBytes;
- if (simpleClassNameBytesCache != null) {
- MetaStringBytes packageNameBytesCache = classInfoCache.packageNameBytes;
- packageBytes =
+ if (typeNameBytesCache != null) {
+ MetaStringBytes packageNameBytesCache = classInfoCache.namespaceBytes;
+ namespaceBytes =
metaStringResolver.readMetaStringBytesWithFlag(buffer,
packageNameBytesCache, header);
assert packageNameBytesCache != null;
- simpleClassNameBytes =
- metaStringResolver.readMetaStringBytes(buffer,
simpleClassNameBytesCache);
- if (simpleClassNameBytesCache.hashCode == simpleClassNameBytes.hashCode
- && packageNameBytesCache.hashCode == packageBytes.hashCode) {
+ simpleClassNameBytes = metaStringResolver.readMetaStringBytes(buffer,
typeNameBytesCache);
+ if (typeNameBytesCache.hashCode == simpleClassNameBytes.hashCode
+ && packageNameBytesCache.hashCode == namespaceBytes.hashCode) {
return classInfoCache;
}
} else {
- packageBytes = metaStringResolver.readMetaStringBytesWithFlag(buffer,
header);
+ namespaceBytes = metaStringResolver.readMetaStringBytesWithFlag(buffer,
header);
simpleClassNameBytes = metaStringResolver.readMetaStringBytes(buffer);
}
- ClassInfo classInfo = loadBytesToClassInfo(packageBytes,
simpleClassNameBytes);
+ ClassInfo classInfo = loadBytesToClassInfo(namespaceBytes,
simpleClassNameBytes);
if (classInfo.serializer == null) {
return getClassInfo(classInfo.cls);
}
@@ -1776,17 +1808,17 @@ public class ClassResolver {
ClassInfo loadBytesToClassInfo(
MetaStringBytes packageBytes, MetaStringBytes simpleClassNameBytes) {
- ClassNameBytes classNameBytes =
- new ClassNameBytes(packageBytes.hashCode,
simpleClassNameBytes.hashCode);
- ClassInfo classInfo =
compositeClassNameBytes2ClassInfo.get(classNameBytes);
+ TypeNameBytes typeNameBytes =
+ new TypeNameBytes(packageBytes.hashCode,
simpleClassNameBytes.hashCode);
+ ClassInfo classInfo = compositeNameBytes2ClassInfo.get(typeNameBytes);
if (classInfo == null) {
- classInfo = populateBytesToClassInfo(classNameBytes, packageBytes,
simpleClassNameBytes);
+ classInfo = populateBytesToClassInfo(typeNameBytes, packageBytes,
simpleClassNameBytes);
}
return classInfo;
}
private ClassInfo populateBytesToClassInfo(
- ClassNameBytes classNameBytes,
+ TypeNameBytes typeNameBytes,
MetaStringBytes packageBytes,
MetaStringBytes simpleClassNameBytes) {
String packageName = packageBytes.decode(PACKAGE_DECODER);
@@ -1816,7 +1848,7 @@ public class ClassResolver {
classInfoMap.put(cls, classInfo);
}
}
- compositeClassNameBytes2ClassInfo.put(classNameBytes, classInfo);
+ compositeNameBytes2ClassInfo.put(typeNameBytes, classInfo);
return classInfo;
}
diff --git
a/java/fury-core/src/main/java/org/apache/fury/resolver/ClassNameBytes.java
b/java/fury-core/src/main/java/org/apache/fury/resolver/TypeNameBytes.java
similarity index 91%
rename from
java/fury-core/src/main/java/org/apache/fury/resolver/ClassNameBytes.java
rename to
java/fury-core/src/main/java/org/apache/fury/resolver/TypeNameBytes.java
index ab2c01dd..80f5c4eb 100644
--- a/java/fury-core/src/main/java/org/apache/fury/resolver/ClassNameBytes.java
+++ b/java/fury-core/src/main/java/org/apache/fury/resolver/TypeNameBytes.java
@@ -19,11 +19,11 @@
package org.apache.fury.resolver;
-class ClassNameBytes {
+class TypeNameBytes {
private final long packageHash;
private final long classNameHash;
- ClassNameBytes(long packageHash, long classNameHash) {
+ TypeNameBytes(long packageHash, long classNameHash) {
this.packageHash = packageHash;
this.classNameHash = classNameHash;
}
@@ -31,7 +31,7 @@ class ClassNameBytes {
@Override
public boolean equals(Object o) {
// ClassNameBytes is used internally, skip
- ClassNameBytes that = (ClassNameBytes) o;
+ TypeNameBytes that = (TypeNameBytes) o;
return packageHash == that.packageHash && classNameHash ==
that.classNameHash;
}
diff --git
a/java/fury-core/src/main/java/org/apache/fury/resolver/XtypeResolver.java
b/java/fury-core/src/main/java/org/apache/fury/resolver/XtypeResolver.java
index 873d7d0e..f74a0491 100644
--- a/java/fury-core/src/main/java/org/apache/fury/resolver/XtypeResolver.java
+++ b/java/fury-core/src/main/java/org/apache/fury/resolver/XtypeResolver.java
@@ -89,7 +89,7 @@ public class XtypeResolver {
// IdentityMap has better lookup performance, when loadFactor is 0.05f,
performance is better
private final IdentityMap<Class<?>, ClassInfo> classInfoMap = new
IdentityMap<>(64, loadFactor);
// Every deserialization for unregistered class will query it, performance
is important.
- private final ObjectMap<ClassNameBytes, ClassInfo>
compositeClassNameBytes2ClassInfo =
+ private final ObjectMap<TypeNameBytes, ClassInfo>
compositeClassNameBytes2ClassInfo =
new ObjectMap<>(16, loadFactor);
private final ObjectMap<String, ClassInfo> qualifiedType2ClassInfo =
new ObjectMap<>(16, loadFactor);
@@ -168,7 +168,7 @@ public class XtypeResolver {
Serializer<?> serializer = null;
if (classInfo != null) {
serializer = classInfo.serializer;
- if (classInfo.classNameBytes != null) {
+ if (classInfo.typeNameBytes != null) {
String prevNamespace = classInfo.decodeNamespace();
String prevTypeName = classInfo.decodeTypeName();
if (!namespace.equals(prevNamespace) || typeName.equals(prevTypeName))
{
@@ -365,10 +365,10 @@ public class XtypeResolver {
case Types.NAMED_POLYMORPHIC_COMPATIBLE_STRUCT:
case Types.NAMED_EXT:
case Types.NAMED_POLYMORPHIC_EXT:
- assert classInfo.packageNameBytes != null;
- metaStringResolver.writeMetaStringBytes(buffer,
classInfo.packageNameBytes);
- assert classInfo.classNameBytes != null;
- metaStringResolver.writeMetaStringBytes(buffer,
classInfo.classNameBytes);
+ assert classInfo.namespaceBytes != null;
+ metaStringResolver.writeMetaStringBytes(buffer,
classInfo.namespaceBytes);
+ assert classInfo.typeNameBytes != null;
+ metaStringResolver.writeMetaStringBytes(buffer,
classInfo.typeNameBytes);
break;
default:
break;
@@ -424,20 +424,20 @@ public class XtypeResolver {
private ClassInfo loadBytesToClassInfo(
int internalTypeId, MetaStringBytes packageBytes, MetaStringBytes
simpleClassNameBytes) {
- ClassNameBytes classNameBytes =
- new ClassNameBytes(packageBytes.hashCode,
simpleClassNameBytes.hashCode);
- ClassInfo classInfo =
compositeClassNameBytes2ClassInfo.get(classNameBytes);
+ TypeNameBytes typeNameBytes =
+ new TypeNameBytes(packageBytes.hashCode,
simpleClassNameBytes.hashCode);
+ ClassInfo classInfo = compositeClassNameBytes2ClassInfo.get(typeNameBytes);
if (classInfo == null) {
classInfo =
populateBytesToClassInfo(
- internalTypeId, classNameBytes, packageBytes,
simpleClassNameBytes);
+ internalTypeId, typeNameBytes, packageBytes,
simpleClassNameBytes);
}
return classInfo;
}
private ClassInfo populateBytesToClassInfo(
int typeId,
- ClassNameBytes classNameBytes,
+ TypeNameBytes typeNameBytes,
MetaStringBytes packageBytes,
MetaStringBytes simpleClassNameBytes) {
String namespace = packageBytes.decode(PACKAGE_DECODER);
@@ -484,7 +484,7 @@ public class XtypeResolver {
classInfo.serializer = NonexistentClassSerializers.getSerializer(fury,
qualifiedName, type);
}
}
- compositeClassNameBytes2ClassInfo.put(classNameBytes, classInfo);
+ compositeClassNameBytes2ClassInfo.put(typeNameBytes, classInfo);
return classInfo;
}
diff --git
a/java/fury-core/src/main/resources/META-INF/native-image/org.apache.fury/fury-core/native-image.properties
b/java/fury-core/src/main/resources/META-INF/native-image/org.apache.fury/fury-core/native-image.properties
index 7c751490..3d5ae0bd 100644
---
a/java/fury-core/src/main/resources/META-INF/native-image/org.apache.fury/fury-core/native-image.properties
+++
b/java/fury-core/src/main/resources/META-INF/native-image/org.apache.fury/fury-core/native-image.properties
@@ -63,6 +63,9 @@
Args=--initialize-at-build-time=org.apache.fury.memory.MemoryBuffer,\
com.google.common.collect.SingletonImmutableBiMap,\
com.google.common.collect.SingletonImmutableList,\
com.google.common.collect.SingletonImmutableSet,\
+ com.google.common.collect.HashBiMap,\
+ com.google.common.collect.HashBiMap$BiEntry,\
+ com.google.common.collect.HashBiMap$Inverse,\
com.google.common.math.IntMath$1,\
com.google.common.primitives.Primitives,\
com.google.common.util.concurrent.AbstractFuture$UnsafeAtomicHelper,\
@@ -274,6 +277,7 @@
Args=--initialize-at-build-time=org.apache.fury.memory.MemoryBuffer,\
org.apache.fury.resolver.MetaStringResolver,\
org.apache.fury.resolver.NoRefResolver,\
org.apache.fury.resolver.SerializationContext,\
+ org.apache.fury.resolver.TypeNameBytes,\
org.apache.fury.serializer.ArraySerializers$BooleanArraySerializer,\
org.apache.fury.serializer.ArraySerializers$ByteArraySerializer,\
org.apache.fury.serializer.ArraySerializers$CharArraySerializer,\
diff --git
a/java/fury-core/src/test/java/org/apache/fury/resolver/ClassInfoTest.java
b/java/fury-core/src/test/java/org/apache/fury/resolver/ClassInfoTest.java
index ad189935..c606b85b 100644
--- a/java/fury-core/src/test/java/org/apache/fury/resolver/ClassInfoTest.java
+++ b/java/fury-core/src/test/java/org/apache/fury/resolver/ClassInfoTest.java
@@ -30,7 +30,7 @@ public class ClassInfoTest {
public void testEncodePackageNameAndTypeName() {
Fury fury1 =
Fury.builder().withLanguage(Language.JAVA).requireClassRegistration(false).build();
ClassInfo info1 =
fury1.getClassResolver().getClassInfo(org.apache.fury.test.bean.Foo.class);
- assertNotNull(info1.packageNameBytes);
- assertNotNull(info1.classNameBytes);
+ assertNotNull(info1.namespaceBytes);
+ assertNotNull(info1.typeNameBytes);
}
}
diff --git
a/java/fury-core/src/test/java/org/apache/fury/resolver/ClassResolverTest.java
b/java/fury-core/src/test/java/org/apache/fury/resolver/ClassResolverTest.java
index ecb35305..3a0e59cf 100644
---
a/java/fury-core/src/test/java/org/apache/fury/resolver/ClassResolverTest.java
+++
b/java/fury-core/src/test/java/org/apache/fury/resolver/ClassResolverTest.java
@@ -92,19 +92,30 @@ public class ClassResolverTest extends FuryTestBase {
}
@Test
- public void testRegisterClass() {
- Fury fury =
Fury.builder().withLanguage(Language.JAVA).requireClassRegistration(false).build();
+ public void testRegisterClassByName() {
+ Fury fury =
Fury.builder().withLanguage(Language.JAVA).requireClassRegistration(true).build();
ClassResolver classResolver = fury.getClassResolver();
- classResolver.register(org.apache.fury.test.bean.Foo.class);
- Assert.assertThrows(
- IllegalArgumentException.class,
- () -> classResolver.register(org.apache.fury.test.bean.Foo.class,
100));
+ classResolver.register(C1.class, "ns", "C1");
Assert.assertThrows(
- IllegalArgumentException.class,
- () ->
classResolver.register(org.apache.fury.test.bean.Foo.createCompatibleClass1()));
- classResolver.register(Interface1.class, 200);
+ IllegalArgumentException.class, () -> classResolver.register(C1.class,
"ns", "C1"));
Assert.assertThrows(
- IllegalArgumentException.class, () ->
classResolver.register(Interface2.class, 200));
+ IllegalArgumentException.class, () -> classResolver.register(C1.class,
200));
+ Assert.assertTrue(fury.serialize(C1.class).length < 12);
+ serDeCheck(fury, C1.class);
+
+ classResolver.register(C2.class, "", "C2");
+ Assert.assertTrue(fury.serialize(C2.class).length < 12);
+ serDeCheck(fury, C2.class);
+
+ classResolver.register(Foo.class, "ns", "Foo");
+ Foo foo = new Foo();
+ foo.f1 = 10;
+ serDeCheck(fury, foo);
+ }
+
+ @Test
+ public void testRegisterClass() {
+ Fury fury =
Fury.builder().withLanguage(Language.JAVA).requireClassRegistration(false).build();
}
@Test
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]