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 5e0b8a9c perf(java): optimize pojo copy performance (#1739)
5e0b8a9c is described below
commit 5e0b8a9c535c954132baad1cd0bf580824f7226d
Author: Shawn Yang <[email protected]>
AuthorDate: Sat Jul 20 16:40:18 2024 +0800
perf(java): optimize pojo copy performance (#1739)
## What does this PR do?
optimize pojo copy performance by 1~4X and add copy benchmark
## Related issues
<!--
Is there any related issue? Please attach here.
- #xxxx0
- #xxxx1
- #xxxx2
-->
## 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
Before:
```java
Benchmark (bufferType) (objectType) (references) Mode
Cnt Score Error Units
CopyBenchmark.fury_copy array MEDIA_CONTENT false thrpt
3 1294614.644 ± 2103796.392 ops/s
CopyBenchmark.fury_copy array SAMPLE false thrpt
3 1909071.799 ± 2343118.356 ops/s
CopyBenchmark.fury_copy array STRUCT false thrpt
3 1220680.635 ± 1019806.837 ops/s
CopyBenchmark.fury_copy array STRUCT2 false thrpt
3 584429.541 ± 111229.502 ops/s
CopyBenchmark.kryo_copy array MEDIA_CONTENT false thrpt
3 1008490.635 ± 309047.316 ops/s
CopyBenchmark.kryo_copy array SAMPLE false thrpt
3 921863.274 ± 1082442.180 ops/s
CopyBenchmark.kryo_copy array STRUCT false thrpt
3 1336939.990 ± 795836.830 ops/s
CopyBenchmark.kryo_copy array STRUCT2 false thrpt
3 168367.000 ± 236966.711 ops/s
```
Java
```java
Benchmark (bufferType) (objectType) (references) Mode
Cnt Score Error Units
CopyBenchmark.fury_copy array MEDIA_CONTENT false thrpt
3 2201830.808 ± 4640532.805 ops/s
CopyBenchmark.fury_copy array SAMPLE false thrpt
3 4945272.027 ± 5429361.187 ops/s
CopyBenchmark.fury_copy array STRUCT false thrpt
3 4809373.970 ± 6803285.896 ops/s
CopyBenchmark.fury_copy array STRUCT2 false thrpt
3 2577391.052 ± 6682601.210 ops/s
CopyBenchmark.kryo_copy array MEDIA_CONTENT false thrpt
3 830059.189 ± 2509547.599 ops/s
CopyBenchmark.kryo_copy array SAMPLE false thrpt
3 696901.072 ± 525070.309 ops/s
CopyBenchmark.kryo_copy array STRUCT false thrpt
3 980635.311 ± 2495689.418 ops/s
CopyBenchmark.kryo_copy array STRUCT2 false thrpt
3 141996.627 ± 343339.930 ops/s
```
---
.../org/apache/fury/benchmark/CopyBenchmark.java | 55 ++++
.../src/main/java/org/apache/fury/Fury.java | 49 ++-
.../fury/serializer/AbstractObjectSerializer.java | 337 ++++++++++++++++++---
.../fury/serializer/MetaSharedSerializer.java | 2 +-
.../serializer/NonexistentClassSerializers.java | 2 +-
.../apache/fury/serializer/ObjectSerializer.java | 158 ----------
6 files changed, 396 insertions(+), 207 deletions(-)
diff --git
a/java/benchmark/src/main/java/org/apache/fury/benchmark/CopyBenchmark.java
b/java/benchmark/src/main/java/org/apache/fury/benchmark/CopyBenchmark.java
new file mode 100644
index 00000000..1940871f
--- /dev/null
+++ b/java/benchmark/src/main/java/org/apache/fury/benchmark/CopyBenchmark.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.fury.benchmark;
+
+import java.io.IOException;
+import org.apache.fury.benchmark.state.FuryState;
+import org.apache.fury.benchmark.state.KryoState;
+import org.openjdk.jmh.Main;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.CompilerControl;
+import org.openjdk.jmh.annotations.Mode;
+
+@BenchmarkMode(Mode.Throughput)
+@CompilerControl(value = CompilerControl.Mode.INLINE)
+public class CopyBenchmark {
+
+ @Benchmark
+ public Object fury_copy(FuryState.FuryUserTypeState state) {
+ return state.fury.copy(state.object);
+ }
+
+ @Benchmark
+ public Object kryo_copy(KryoState.KryoUserTypeState state) {
+ return state.kryo.copy(state.object);
+ }
+
+ public static void main(String[] args) throws IOException {
+ if (args.length == 0) {
+ String commandLine =
+ "org.apache.fury.*CopyBenchmark.* -f 1 -wi 3 -i 3 -t 1 -w 2s -r 2s
-rf csv "
+ + "-p bufferType=array -p references=false";
+ System.out.println(commandLine);
+ args = commandLine.split(" ");
+ }
+ Main.main(args);
+ }
+}
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 4cb45b21..87c635d7 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
@@ -1273,14 +1273,6 @@ public final class Fury implements BaseFury {
Object copy;
ClassInfo classInfo = classResolver.getOrUpdateClassInfo(obj.getClass());
switch (classInfo.getClassId()) {
- case ClassResolver.BOOLEAN_CLASS_ID:
- case ClassResolver.BYTE_CLASS_ID:
- case ClassResolver.CHAR_CLASS_ID:
- case ClassResolver.SHORT_CLASS_ID:
- case ClassResolver.INTEGER_CLASS_ID:
- case ClassResolver.FLOAT_CLASS_ID:
- case ClassResolver.LONG_CLASS_ID:
- case ClassResolver.DOUBLE_CLASS_ID:
case ClassResolver.PRIMITIVE_BOOLEAN_CLASS_ID:
case ClassResolver.PRIMITIVE_BYTE_CLASS_ID:
case ClassResolver.PRIMITIVE_CHAR_CLASS_ID:
@@ -1289,6 +1281,14 @@ public final class Fury implements BaseFury {
case ClassResolver.PRIMITIVE_FLOAT_CLASS_ID:
case ClassResolver.PRIMITIVE_LONG_CLASS_ID:
case ClassResolver.PRIMITIVE_DOUBLE_CLASS_ID:
+ case ClassResolver.BOOLEAN_CLASS_ID:
+ case ClassResolver.BYTE_CLASS_ID:
+ case ClassResolver.CHAR_CLASS_ID:
+ case ClassResolver.SHORT_CLASS_ID:
+ case ClassResolver.INTEGER_CLASS_ID:
+ case ClassResolver.FLOAT_CLASS_ID:
+ case ClassResolver.LONG_CLASS_ID:
+ case ClassResolver.DOUBLE_CLASS_ID:
case ClassResolver.STRING_CLASS_ID:
return obj;
case ClassResolver.PRIMITIVE_BOOLEAN_ARRAY_CLASS_ID:
@@ -1319,22 +1319,49 @@ public final class Fury implements BaseFury {
String[] stringArr = (String[]) obj;
return (T) Arrays.copyOf(stringArr, stringArr.length);
case ClassResolver.ARRAYLIST_CLASS_ID:
- copyDepth++;
copy = arrayListSerializer.copy((ArrayList) obj);
break;
case ClassResolver.HASHMAP_CLASS_ID:
- copyDepth++;
copy = hashMapSerializer.copy((HashMap) obj);
break;
// todo: add fastpath for other types.
default:
copyDepth++;
copy = classInfo.getSerializer().copy(obj);
+ copyDepth--;
}
- copyDepth--;
return (T) copy;
}
+ public <T> T copyObject(T obj, int classId) {
+ if (obj == null) {
+ return null;
+ }
+ // Fast path to avoid cost of query class map.
+ switch (classId) {
+ case ClassResolver.PRIMITIVE_BOOLEAN_CLASS_ID:
+ case ClassResolver.PRIMITIVE_BYTE_CLASS_ID:
+ case ClassResolver.PRIMITIVE_CHAR_CLASS_ID:
+ case ClassResolver.PRIMITIVE_SHORT_CLASS_ID:
+ case ClassResolver.PRIMITIVE_INT_CLASS_ID:
+ case ClassResolver.PRIMITIVE_FLOAT_CLASS_ID:
+ case ClassResolver.PRIMITIVE_LONG_CLASS_ID:
+ case ClassResolver.PRIMITIVE_DOUBLE_CLASS_ID:
+ case ClassResolver.BOOLEAN_CLASS_ID:
+ case ClassResolver.BYTE_CLASS_ID:
+ case ClassResolver.CHAR_CLASS_ID:
+ case ClassResolver.SHORT_CLASS_ID:
+ case ClassResolver.INTEGER_CLASS_ID:
+ case ClassResolver.FLOAT_CLASS_ID:
+ case ClassResolver.LONG_CLASS_ID:
+ case ClassResolver.DOUBLE_CLASS_ID:
+ case ClassResolver.STRING_CLASS_ID:
+ return obj;
+ default:
+ return (T)
classResolver.getOrUpdateClassInfo(obj.getClass()).getSerializer().copy(obj);
+ }
+ }
+
/**
* Track ref for copy.
*
diff --git
a/java/fury-core/src/main/java/org/apache/fury/serializer/AbstractObjectSerializer.java
b/java/fury-core/src/main/java/org/apache/fury/serializer/AbstractObjectSerializer.java
index c609ce30..8591c6c8 100644
---
a/java/fury-core/src/main/java/org/apache/fury/serializer/AbstractObjectSerializer.java
+++
b/java/fury-core/src/main/java/org/apache/fury/serializer/AbstractObjectSerializer.java
@@ -19,34 +19,47 @@
package org.apache.fury.serializer;
+import static org.apache.fury.type.DescriptorGrouper.createDescriptorGrouper;
+import static org.apache.fury.type.TypeUtils.getRawType;
+
import java.lang.invoke.MethodHandle;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import org.apache.fury.Fury;
+import org.apache.fury.collection.Tuple2;
+import org.apache.fury.collection.Tuple3;
import org.apache.fury.memory.Platform;
import org.apache.fury.reflect.FieldAccessor;
import org.apache.fury.reflect.ReflectionUtils;
+import org.apache.fury.reflect.TypeRef;
+import org.apache.fury.resolver.ClassInfo;
+import org.apache.fury.resolver.ClassInfoHolder;
import org.apache.fury.resolver.ClassResolver;
-import org.apache.fury.resolver.FieldResolver.FieldInfo;
import org.apache.fury.resolver.RefResolver;
+import org.apache.fury.type.Descriptor;
+import org.apache.fury.type.DescriptorGrouper;
+import org.apache.fury.type.FinalObjectTypeStub;
+import org.apache.fury.type.GenericType;
+import org.apache.fury.util.record.RecordComponent;
import org.apache.fury.util.record.RecordUtils;
public abstract class AbstractObjectSerializer<T> extends Serializer<T> {
-
protected final RefResolver refResolver;
protected final ClassResolver classResolver;
protected final boolean isRecord;
protected final MethodHandle constructor;
+ private InternalFieldInfo[] fieldInfos;
public AbstractObjectSerializer(Fury fury, Class<T> type) {
- super(fury, type);
- this.refResolver = fury.getRefResolver();
- this.classResolver = fury.getClassResolver();
- this.isRecord = RecordUtils.isRecord(type);
- if (isRecord) {
- this.constructor = RecordUtils.getRecordConstructor(type).f1;
- } else {
- this.constructor = ReflectionUtils.getCtrHandle(type, false);
- }
+ this(
+ fury,
+ type,
+ RecordUtils.isRecord(type)
+ ? RecordUtils.getRecordConstructor(type).f1
+ : ReflectionUtils.getCtrHandle(type, false));
}
public AbstractObjectSerializer(Fury fury, Class<T> type, MethodHandle
constructor) {
@@ -71,68 +84,167 @@ public abstract class AbstractObjectSerializer<T> extends
Serializer<T> {
}
return originObj;
}
- T newObj = newBean();
+ T newObj;
if (needToCopyRef) {
T copyObject = (T) fury.getCopyObject(originObj);
if (copyObject != null) {
return copyObject;
}
+ newObj = newBean();
fury.reference(originObj, newObj);
+ } else {
+ newObj = newBean();
}
copyFields(originObj, newObj);
return newObj;
}
private Object[] copyFields(T originObj) {
- return classResolver.getFieldResolver(type).getAllFieldsList().stream()
- .map(
- fieldInfo -> {
- FieldAccessor fieldAccessor = fieldInfo.getFieldAccessor();
- if (classResolver.isPrimitive(fieldInfo.getEmbeddedClassId())) {
- return fieldAccessor.get(originObj);
- }
- return fury.copyObject(fieldAccessor.get(originObj));
- })
- .toArray();
+ InternalFieldInfo[] fieldInfos = this.fieldInfos;
+ if (fieldInfos == null) {
+ fieldInfos = buildFieldsInfo();
+ }
+ Object[] fieldValues = new Object[fieldInfos.length];
+ for (int i = 0; i < fieldInfos.length; i++) {
+ InternalFieldInfo fieldInfo = fieldInfos[i];
+ FieldAccessor fieldAccessor = fieldInfo.fieldAccessor;
+ long fieldOffset = fieldAccessor.getFieldOffset();
+ if (fieldOffset != -1) {
+ fieldValues[i] = copyField(originObj, fieldOffset, fieldInfo.classId);
+ } else {
+ // field in record class has offset -1
+ Object fieldValue = fieldAccessor.get(originObj);
+ fieldValues[i] = fury.copyObject(fieldValue, fieldInfo.classId);
+ }
+ }
+ return fieldValues;
}
private void copyFields(T originObj, T newObj) {
- List<FieldInfo> fieldsList =
classResolver.getFieldResolver(type).getAllFieldsList();
- for (FieldInfo info : fieldsList) {
- FieldAccessor fieldAccessor = info.getFieldAccessor();
- long offset = fieldAccessor.getFieldOffset();
- switch (info.getEmbeddedClassId()) {
+ InternalFieldInfo[] fieldInfos = this.fieldInfos;
+ if (fieldInfos == null) {
+ fieldInfos = buildFieldsInfo();
+ }
+ for (InternalFieldInfo fieldInfo : fieldInfos) {
+ FieldAccessor fieldAccessor = fieldInfo.fieldAccessor;
+ long fieldOffset = fieldAccessor.getFieldOffset();
+ // record class won't go to this path;
+ assert fieldOffset != -1;
+ switch (fieldInfo.classId) {
case ClassResolver.PRIMITIVE_BYTE_CLASS_ID:
- Platform.putByte(newObj, offset, Platform.getByte(originObj,
offset));
+ Platform.putByte(newObj, fieldOffset, Platform.getByte(originObj,
fieldOffset));
break;
case ClassResolver.PRIMITIVE_CHAR_CLASS_ID:
- Platform.putChar(newObj, offset, Platform.getChar(originObj,
offset));
+ Platform.putChar(newObj, fieldOffset, Platform.getChar(originObj,
fieldOffset));
break;
case ClassResolver.PRIMITIVE_SHORT_CLASS_ID:
- Platform.putShort(newObj, offset, Platform.getShort(originObj,
offset));
+ Platform.putShort(newObj, fieldOffset, Platform.getShort(originObj,
fieldOffset));
break;
case ClassResolver.PRIMITIVE_INT_CLASS_ID:
- Platform.putInt(newObj, offset, Platform.getInt(originObj, offset));
+ Platform.putInt(newObj, fieldOffset, Platform.getInt(originObj,
fieldOffset));
break;
case ClassResolver.PRIMITIVE_LONG_CLASS_ID:
- Platform.putLong(newObj, offset, Platform.getLong(originObj,
offset));
+ Platform.putLong(newObj, fieldOffset, Platform.getLong(originObj,
fieldOffset));
break;
case ClassResolver.PRIMITIVE_FLOAT_CLASS_ID:
- Platform.putFloat(newObj, offset, Platform.getFloat(originObj,
offset));
+ Platform.putFloat(newObj, fieldOffset, Platform.getFloat(originObj,
fieldOffset));
break;
case ClassResolver.PRIMITIVE_DOUBLE_CLASS_ID:
- Platform.putDouble(newObj, offset, Platform.getDouble(originObj,
offset));
+ Platform.putDouble(newObj, fieldOffset,
Platform.getDouble(originObj, fieldOffset));
break;
case ClassResolver.PRIMITIVE_BOOLEAN_CLASS_ID:
- Platform.putBoolean(newObj, offset, Platform.getBoolean(originObj,
offset));
+ Platform.putBoolean(newObj, fieldOffset,
Platform.getBoolean(originObj, fieldOffset));
+ break;
+ case ClassResolver.BOOLEAN_CLASS_ID:
+ case ClassResolver.BYTE_CLASS_ID:
+ case ClassResolver.CHAR_CLASS_ID:
+ case ClassResolver.SHORT_CLASS_ID:
+ case ClassResolver.INTEGER_CLASS_ID:
+ case ClassResolver.FLOAT_CLASS_ID:
+ case ClassResolver.LONG_CLASS_ID:
+ case ClassResolver.DOUBLE_CLASS_ID:
+ case ClassResolver.STRING_CLASS_ID:
+ Platform.putObject(newObj, fieldOffset,
Platform.getObject(originObj, fieldOffset));
break;
default:
Platform.putObject(
- newObj, offset, fury.copyObject(Platform.getObject(originObj,
offset)));
+ newObj, fieldOffset,
fury.copyObject(Platform.getObject(originObj, fieldOffset)));
}
}
}
+ private Object copyField(Object targetObject, long fieldOffset, short
classId) {
+ switch (classId) {
+ case ClassResolver.PRIMITIVE_BOOLEAN_CLASS_ID:
+ return Platform.getBoolean(targetObject, fieldOffset);
+ case ClassResolver.PRIMITIVE_BYTE_CLASS_ID:
+ return Platform.getByte(targetObject, fieldOffset);
+ case ClassResolver.PRIMITIVE_CHAR_CLASS_ID:
+ return Platform.getChar(targetObject, fieldOffset);
+ case ClassResolver.PRIMITIVE_SHORT_CLASS_ID:
+ return Platform.getShort(targetObject, fieldOffset);
+ case ClassResolver.PRIMITIVE_INT_CLASS_ID:
+ return Platform.getInt(targetObject, fieldOffset);
+ case ClassResolver.PRIMITIVE_FLOAT_CLASS_ID:
+ return Platform.getFloat(targetObject, fieldOffset);
+ case ClassResolver.PRIMITIVE_LONG_CLASS_ID:
+ return Platform.getLong(targetObject, fieldOffset);
+ case ClassResolver.PRIMITIVE_DOUBLE_CLASS_ID:
+ return Platform.getDouble(targetObject, fieldOffset);
+ case ClassResolver.BOOLEAN_CLASS_ID:
+ case ClassResolver.BYTE_CLASS_ID:
+ case ClassResolver.CHAR_CLASS_ID:
+ case ClassResolver.SHORT_CLASS_ID:
+ case ClassResolver.INTEGER_CLASS_ID:
+ case ClassResolver.FLOAT_CLASS_ID:
+ case ClassResolver.LONG_CLASS_ID:
+ case ClassResolver.DOUBLE_CLASS_ID:
+ case ClassResolver.STRING_CLASS_ID:
+ return Platform.getObject(targetObject, fieldOffset);
+ default:
+ return fury.copyObject(Platform.getObject(targetObject, fieldOffset));
+ }
+ }
+
+ private InternalFieldInfo[] buildFieldsInfo() {
+ List<Descriptor> descriptors = new ArrayList<>();
+ if (RecordUtils.isRecord(type)) {
+ RecordComponent[] components = RecordUtils.getRecordComponents(type);
+ assert components != null;
+ try {
+ for (RecordComponent component : components) {
+ Field field = type.getDeclaredField(component.getName());
+ descriptors.add(
+ new Descriptor(
+ field, TypeRef.of(field.getGenericType()),
component.getAccessor(), null));
+ }
+ } catch (NoSuchFieldException e) {
+ // impossible
+ Platform.throwException(e);
+ }
+ } else {
+ for (Field field : ReflectionUtils.getFields(type, true)) {
+ if (!Modifier.isStatic(field.getModifiers())) {
+ descriptors.add(new Descriptor(field,
TypeRef.of(field.getGenericType()), null, null));
+ }
+ }
+ }
+ DescriptorGrouper descriptorGrouper =
+ createDescriptorGrouper(
+ fury.getClassResolver()::isMonomorphic,
+ descriptors,
+ false,
+ fury.compressInt(),
+ fury.compressLong());
+ Tuple3<Tuple2<FinalTypeField[], boolean[]>, GenericTypeField[],
GenericTypeField[]> infos =
+ buildFieldInfos(fury, descriptorGrouper);
+ fieldInfos = new InternalFieldInfo[descriptors.size()];
+ System.arraycopy(infos.f0.f0, 0, fieldInfos, 0, infos.f0.f0.length);
+ System.arraycopy(infos.f1, 0, fieldInfos, infos.f0.f0.length,
infos.f1.length);
+ System.arraycopy(infos.f2, 0, fieldInfos, fieldInfos.length -
infos.f2.length, infos.f2.length);
+ return fieldInfos;
+ }
+
protected T newBean() {
if (constructor != null) {
try {
@@ -143,4 +255,157 @@ public abstract class AbstractObjectSerializer<T> extends
Serializer<T> {
}
return Platform.newInstance(type);
}
+
+ static Tuple3<Tuple2<FinalTypeField[], boolean[]>, GenericTypeField[],
GenericTypeField[]>
+ buildFieldInfos(Fury fury, DescriptorGrouper grouper) {
+ // When a type is both Collection/Map and final, add it to collection/map
fields to keep
+ // consistent with jit.
+ Collection<Descriptor> primitives = grouper.getPrimitiveDescriptors();
+ Collection<Descriptor> boxed = grouper.getBoxedDescriptors();
+ Collection<Descriptor> finals = grouper.getFinalDescriptors();
+ FinalTypeField[] finalFields =
+ new FinalTypeField[primitives.size() + boxed.size() + finals.size()];
+ int cnt = 0;
+ for (Descriptor d : primitives) {
+ finalFields[cnt++] = buildFinalTypeField(fury, d);
+ }
+ for (Descriptor d : boxed) {
+ finalFields[cnt++] = buildFinalTypeField(fury, d);
+ }
+ // TODO(chaokunyang) Support Pojo<T> generics besides Map/Collection
subclass
+ // when it's supported in BaseObjectCodecBuilder.
+ for (Descriptor d : finals) {
+ finalFields[cnt++] = buildFinalTypeField(fury, d);
+ }
+ boolean[] isFinal = new boolean[finalFields.length];
+ for (int i = 0; i < isFinal.length; i++) {
+ ClassInfo classInfo = finalFields[i].classInfo;
+ isFinal[i] = classInfo != null &&
fury.getClassResolver().isMonomorphic(classInfo.getCls());
+ }
+ cnt = 0;
+ GenericTypeField[] otherFields = new
GenericTypeField[grouper.getOtherDescriptors().size()];
+ for (Descriptor descriptor : grouper.getOtherDescriptors()) {
+ GenericTypeField genericTypeField =
+ new GenericTypeField(
+ descriptor.getRawType(),
+ descriptor.getDeclaringClass() + "." + descriptor.getName(),
+ descriptor.getField() != null
+ ? FieldAccessor.createAccessor(descriptor.getField())
+ : null,
+ fury);
+ otherFields[cnt++] = genericTypeField;
+ }
+ cnt = 0;
+ Collection<Descriptor> collections = grouper.getCollectionDescriptors();
+ Collection<Descriptor> maps = grouper.getMapDescriptors();
+ GenericTypeField[] containerFields = new
GenericTypeField[collections.size() + maps.size()];
+ for (Descriptor d : collections) {
+ containerFields[cnt++] = buildContainerField(fury, d);
+ }
+ for (Descriptor d : maps) {
+ containerFields[cnt++] = buildContainerField(fury, d);
+ }
+ return Tuple3.of(Tuple2.of(finalFields, isFinal), otherFields,
containerFields);
+ }
+
+ private static FinalTypeField buildFinalTypeField(Fury fury, Descriptor d) {
+ return new FinalTypeField(
+ d.getRawType(),
+ d.getDeclaringClass() + "." + d.getName(),
+ // `d.getField()` will be null when peer class doesn't have this field.
+ d.getField() != null ? FieldAccessor.createAccessor(d.getField()) :
null,
+ fury);
+ }
+
+ private static GenericTypeField buildContainerField(Fury fury, Descriptor d)
{
+ return new GenericTypeField(
+ d.getTypeRef(),
+ d.getDeclaringClass() + "." + d.getName(),
+ d.getField() != null ? FieldAccessor.createAccessor(d.getField()) :
null,
+ fury);
+ }
+
+ static class InternalFieldInfo {
+ protected final short classId;
+ protected final String qualifiedFieldName;
+ protected final FieldAccessor fieldAccessor;
+
+ private InternalFieldInfo(
+ short classId, String qualifiedFieldName, FieldAccessor fieldAccessor)
{
+ this.classId = classId;
+ this.qualifiedFieldName = qualifiedFieldName;
+ this.fieldAccessor = fieldAccessor;
+ }
+
+ @Override
+ public String toString() {
+ return "InternalFieldInfo{"
+ + "classId="
+ + classId
+ + ", fieldName="
+ + qualifiedFieldName
+ + ", field="
+ + (fieldAccessor != null ? fieldAccessor.getField() : null)
+ + '}';
+ }
+ }
+
+ static final class FinalTypeField extends InternalFieldInfo {
+ final ClassInfo classInfo;
+
+ private FinalTypeField(Class<?> type, String fieldName, FieldAccessor
accessor, Fury fury) {
+ super(getRegisteredClassId(fury, type), fieldName, accessor);
+ // invoke `copy` to avoid ObjectSerializer construct clear serializer by
`clearSerializer`.
+ if (type == FinalObjectTypeStub.class) {
+ // `FinalObjectTypeStub` has no fields, using its `classInfo`
+ // will make deserialization failed.
+ classInfo = null;
+ } else {
+ classInfo = fury.getClassResolver().getClassInfo(type);
+ }
+ }
+ }
+
+ static final class GenericTypeField extends InternalFieldInfo {
+ final GenericType genericType;
+ final ClassInfoHolder classInfoHolder;
+ final boolean trackingRef;
+
+ private GenericTypeField(
+ Class<?> cls, String qualifiedFieldName, FieldAccessor accessor, Fury
fury) {
+ super(getRegisteredClassId(fury, cls), qualifiedFieldName, accessor);
+ // TODO support generics <T> in Pojo<T>, see
ComplexObjectSerializer.getGenericTypes
+ genericType = fury.getClassResolver().buildGenericType(cls);
+ classInfoHolder = fury.getClassResolver().nilClassInfoHolder();
+ trackingRef = fury.getClassResolver().needToWriteRef(cls);
+ }
+
+ private GenericTypeField(
+ TypeRef<?> typeRef, String qualifiedFieldName, FieldAccessor accessor,
Fury fury) {
+ super(getRegisteredClassId(fury, getRawType(typeRef)),
qualifiedFieldName, accessor);
+ // TODO support generics <T> in Pojo<T>, see
ComplexObjectSerializer.getGenericTypes
+ genericType = fury.getClassResolver().buildGenericType(typeRef);
+ classInfoHolder = fury.getClassResolver().nilClassInfoHolder();
+ trackingRef =
fury.getClassResolver().needToWriteRef(getRawType(typeRef));
+ }
+
+ @Override
+ public String toString() {
+ return "GenericTypeField{"
+ + "genericType="
+ + genericType
+ + ", classId="
+ + classId
+ + ", qualifiedFieldName="
+ + qualifiedFieldName
+ + ", field="
+ + (fieldAccessor != null ? fieldAccessor.getField() : null)
+ + '}';
+ }
+ }
+
+ private static short getRegisteredClassId(Fury fury, Class<?> cls) {
+ Short classId = fury.getClassResolver().getRegisteredClassId(cls);
+ return classId == null ? ClassResolver.NO_CLASS_ID : classId;
+ }
}
diff --git
a/java/fury-core/src/main/java/org/apache/fury/serializer/MetaSharedSerializer.java
b/java/fury-core/src/main/java/org/apache/fury/serializer/MetaSharedSerializer.java
index 77647d8e..1292fcbd 100644
---
a/java/fury-core/src/main/java/org/apache/fury/serializer/MetaSharedSerializer.java
+++
b/java/fury-core/src/main/java/org/apache/fury/serializer/MetaSharedSerializer.java
@@ -96,7 +96,7 @@ public class MetaSharedSerializer<T> extends
AbstractObjectSerializer<T> {
Tuple2<ObjectSerializer.FinalTypeField[], boolean[]>,
ObjectSerializer.GenericTypeField[],
ObjectSerializer.GenericTypeField[]>
- infos = ObjectSerializer.buildFieldInfos(fury, descriptorGrouper);
+ infos = AbstractObjectSerializer.buildFieldInfos(fury,
descriptorGrouper);
finalFields = infos.f0.f0;
isFinal = infos.f0.f1;
otherFields = infos.f1;
diff --git
a/java/fury-core/src/main/java/org/apache/fury/serializer/NonexistentClassSerializers.java
b/java/fury-core/src/main/java/org/apache/fury/serializer/NonexistentClassSerializers.java
index 974bef46..fa8768b9 100644
---
a/java/fury-core/src/main/java/org/apache/fury/serializer/NonexistentClassSerializers.java
+++
b/java/fury-core/src/main/java/org/apache/fury/serializer/NonexistentClassSerializers.java
@@ -167,7 +167,7 @@ public final class NonexistentClassSerializers {
Tuple2<ObjectSerializer.FinalTypeField[], boolean[]>,
ObjectSerializer.GenericTypeField[],
ObjectSerializer.GenericTypeField[]>
- tuple = ObjectSerializer.buildFieldInfos(fury, descriptorGrouper);
+ tuple = AbstractObjectSerializer.buildFieldInfos(fury,
descriptorGrouper);
int classVersionHash = 0;
if (fury.checkClassVersion()) {
classVersionHash = ObjectSerializer.computeVersionHash(descriptors);
diff --git
a/java/fury-core/src/main/java/org/apache/fury/serializer/ObjectSerializer.java
b/java/fury-core/src/main/java/org/apache/fury/serializer/ObjectSerializer.java
index 9edd5fb8..2c72fb2e 100644
---
a/java/fury-core/src/main/java/org/apache/fury/serializer/ObjectSerializer.java
+++
b/java/fury-core/src/main/java/org/apache/fury/serializer/ObjectSerializer.java
@@ -20,7 +20,6 @@
package org.apache.fury.serializer;
import static org.apache.fury.type.DescriptorGrouper.createDescriptorGrouper;
-import static org.apache.fury.type.TypeUtils.getRawType;
import java.util.ArrayList;
import java.util.Arrays;
@@ -36,15 +35,11 @@ import org.apache.fury.memory.MemoryBuffer;
import org.apache.fury.memory.Platform;
import org.apache.fury.meta.ClassDef;
import org.apache.fury.reflect.FieldAccessor;
-import org.apache.fury.reflect.TypeRef;
import org.apache.fury.resolver.ClassInfo;
-import org.apache.fury.resolver.ClassInfoHolder;
import org.apache.fury.resolver.ClassResolver;
import org.apache.fury.resolver.RefResolver;
import org.apache.fury.type.Descriptor;
import org.apache.fury.type.DescriptorGrouper;
-import org.apache.fury.type.FinalObjectTypeStub;
-import org.apache.fury.type.GenericType;
import org.apache.fury.type.Generics;
import org.apache.fury.util.record.RecordInfo;
import org.apache.fury.util.record.RecordUtils;
@@ -127,75 +122,6 @@ public final class ObjectSerializer<T> extends
AbstractObjectSerializer<T> {
containerFields = infos.f2;
}
- static Tuple3<Tuple2<FinalTypeField[], boolean[]>, GenericTypeField[],
GenericTypeField[]>
- buildFieldInfos(Fury fury, DescriptorGrouper grouper) {
- // When a type is both Collection/Map and final, add it to collection/map
fields to keep
- // consistent with jit.
- Collection<Descriptor> primitives = grouper.getPrimitiveDescriptors();
- Collection<Descriptor> boxed = grouper.getBoxedDescriptors();
- Collection<Descriptor> finals = grouper.getFinalDescriptors();
- FinalTypeField[] finalFields =
- new FinalTypeField[primitives.size() + boxed.size() + finals.size()];
- int cnt = 0;
- for (Descriptor d : primitives) {
- finalFields[cnt++] = buildFinalTypeField(fury, d);
- }
- for (Descriptor d : boxed) {
- finalFields[cnt++] = buildFinalTypeField(fury, d);
- }
- // TODO(chaokunyang) Support Pojo<T> generics besides Map/Collection
subclass
- // when it's supported in BaseObjectCodecBuilder.
- for (Descriptor d : finals) {
- finalFields[cnt++] = buildFinalTypeField(fury, d);
- }
- boolean[] isFinal = new boolean[finalFields.length];
- for (int i = 0; i < isFinal.length; i++) {
- ClassInfo classInfo = finalFields[i].classInfo;
- isFinal[i] = classInfo != null &&
fury.getClassResolver().isMonomorphic(classInfo.getCls());
- }
- cnt = 0;
- GenericTypeField[] otherFields = new
GenericTypeField[grouper.getOtherDescriptors().size()];
- for (Descriptor descriptor : grouper.getOtherDescriptors()) {
- GenericTypeField genericTypeField =
- new GenericTypeField(
- descriptor.getRawType(),
- descriptor.getDeclaringClass() + "." + descriptor.getName(),
- descriptor.getField() != null
- ? FieldAccessor.createAccessor(descriptor.getField())
- : null,
- fury);
- otherFields[cnt++] = genericTypeField;
- }
- cnt = 0;
- Collection<Descriptor> collections = grouper.getCollectionDescriptors();
- Collection<Descriptor> maps = grouper.getMapDescriptors();
- GenericTypeField[] containerFields = new
GenericTypeField[collections.size() + maps.size()];
- for (Descriptor d : collections) {
- containerFields[cnt++] = buildContainerField(fury, d);
- }
- for (Descriptor d : maps) {
- containerFields[cnt++] = buildContainerField(fury, d);
- }
- return Tuple3.of(Tuple2.of(finalFields, isFinal), otherFields,
containerFields);
- }
-
- private static FinalTypeField buildFinalTypeField(Fury fury, Descriptor d) {
- return new FinalTypeField(
- d.getRawType(),
- d.getDeclaringClass() + "." + d.getName(),
- // `d.getField()` will be null when peer class doesn't have this field.
- d.getField() != null ? FieldAccessor.createAccessor(d.getField()) :
null,
- fury);
- }
-
- private static GenericTypeField buildContainerField(Fury fury, Descriptor d)
{
- return new GenericTypeField(
- d.getTypeRef(),
- d.getDeclaringClass() + "." + d.getName(),
- d.getField() != null ? FieldAccessor.createAccessor(d.getField()) :
null,
- fury);
- }
-
@Override
public void write(MemoryBuffer buffer, T value) {
Fury fury = this.fury;
@@ -856,90 +782,6 @@ public final class ObjectSerializer<T> extends
AbstractObjectSerializer<T> {
}
}
- static class InternalFieldInfo {
- protected final short classId;
- protected final String qualifiedFieldName;
- protected final FieldAccessor fieldAccessor;
-
- private InternalFieldInfo(
- short classId, String qualifiedFieldName, FieldAccessor fieldAccessor)
{
- this.classId = classId;
- this.qualifiedFieldName = qualifiedFieldName;
- this.fieldAccessor = fieldAccessor;
- }
-
- @Override
- public String toString() {
- return "InternalFieldInfo{"
- + "classId="
- + classId
- + ", fieldName="
- + qualifiedFieldName
- + ", field="
- + (fieldAccessor != null ? fieldAccessor.getField() : null)
- + '}';
- }
- }
-
- static final class FinalTypeField extends InternalFieldInfo {
- final ClassInfo classInfo;
-
- private FinalTypeField(Class<?> type, String fieldName, FieldAccessor
accessor, Fury fury) {
- super(getRegisteredClassId(fury, type), fieldName, accessor);
- // invoke `copy` to avoid ObjectSerializer construct clear serializer by
`clearSerializer`.
- if (type == FinalObjectTypeStub.class) {
- // `FinalObjectTypeStub` has no fields, using its `classInfo`
- // will make deserialization failed.
- classInfo = null;
- } else {
- classInfo = fury.getClassResolver().getClassInfo(type);
- }
- }
- }
-
- static final class GenericTypeField extends InternalFieldInfo {
- private final GenericType genericType;
- final ClassInfoHolder classInfoHolder;
- final boolean trackingRef;
-
- private GenericTypeField(
- Class<?> cls, String qualifiedFieldName, FieldAccessor accessor, Fury
fury) {
- super(getRegisteredClassId(fury, cls), qualifiedFieldName, accessor);
- // TODO support generics <T> in Pojo<T>, see
ComplexObjectSerializer.getGenericTypes
- genericType = fury.getClassResolver().buildGenericType(cls);
- classInfoHolder = fury.getClassResolver().nilClassInfoHolder();
- trackingRef = fury.getClassResolver().needToWriteRef(cls);
- }
-
- private GenericTypeField(
- TypeRef<?> typeRef, String qualifiedFieldName, FieldAccessor accessor,
Fury fury) {
- super(getRegisteredClassId(fury, getRawType(typeRef)),
qualifiedFieldName, accessor);
- // TODO support generics <T> in Pojo<T>, see
ComplexObjectSerializer.getGenericTypes
- genericType = fury.getClassResolver().buildGenericType(typeRef);
- classInfoHolder = fury.getClassResolver().nilClassInfoHolder();
- trackingRef =
fury.getClassResolver().needToWriteRef(getRawType(typeRef));
- }
-
- @Override
- public String toString() {
- return "GenericTypeField{"
- + "genericType="
- + genericType
- + ", classId="
- + classId
- + ", qualifiedFieldName="
- + qualifiedFieldName
- + ", field="
- + (fieldAccessor != null ? fieldAccessor.getField() : null)
- + '}';
- }
- }
-
- private static short getRegisteredClassId(Fury fury, Class<?> cls) {
- Short classId = fury.getClassResolver().getRegisteredClassId(cls);
- return classId == null ? ClassResolver.NO_CLASS_ID : classId;
- }
-
public static int computeVersionHash(Collection<Descriptor> descriptors) {
// TODO(chaokunyang) use murmurhash
List<Integer> list = new ArrayList<>();
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]