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 16459abb feat(java): support trackingRef in furyField (#2168)
16459abb is described below
commit 16459abba585850a0399be4d82987da7f2acb2e6
Author: hn <[email protected]>
AuthorDate: Mon May 12 21:20:00 2025 +0800
feat(java): support trackingRef in furyField (#2168)
<!--
**Thanks for contributing to Fury.**
**If this is your first time opening a PR on fury, you can refer to
[CONTRIBUTING.md](https://github.com/apache/fury/blob/main/CONTRIBUTING.md).**
Contribution Checklist
- The **Apache Fury (incubating)** community has restrictions on the
naming of pr titles. You can also find instructions in
[CONTRIBUTING.md](https://github.com/apache/fury/blob/main/CONTRIBUTING.md).
- Fury has a strong focus on performance. If the PR you submit will have
an impact on performance, please benchmark it first and provide the
benchmark result here.
-->
## What does this PR do?
<!-- Describe the purpose of this PR. -->
## Related issues
#2167
<!--
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
<!--
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.
-->
---------
Co-authored-by: hening <[email protected]>
---
.../java/org/apache/fury/annotation/FuryField.java | 3 +++
.../org/apache/fury/resolver/FieldResolver.java | 10 +++++++++-
.../org/apache/fury/resolver/MapRefResolver.java | 6 ++++++
.../org/apache/fury/resolver/NoRefResolver.java | 5 +++++
.../java/org/apache/fury/resolver/RefResolver.java | 2 ++
.../fury/serializer/AbstractObjectSerializer.java | 23 ++++++++++++++--------
.../fury/serializer/SerializationBinding.java | 14 +++++++++++++
.../apache/fury/annotation/FuryAnnotationTest.java | 9 ++-------
8 files changed, 56 insertions(+), 16 deletions(-)
diff --git
a/java/fury-core/src/main/java/org/apache/fury/annotation/FuryField.java
b/java/fury-core/src/main/java/org/apache/fury/annotation/FuryField.java
index c36ed986..00d1d250 100644
--- a/java/fury-core/src/main/java/org/apache/fury/annotation/FuryField.java
+++ b/java/fury-core/src/main/java/org/apache/fury/annotation/FuryField.java
@@ -30,4 +30,7 @@ public @interface FuryField {
/** Whether field is nullable, default false. */
boolean nullable() default false;
+
+ /** Whether field need trackingRef, default false. */
+ boolean trackingRef() default false;
}
diff --git
a/java/fury-core/src/main/java/org/apache/fury/resolver/FieldResolver.java
b/java/fury-core/src/main/java/org/apache/fury/resolver/FieldResolver.java
index 65110875..35337d5f 100644
--- a/java/fury-core/src/main/java/org/apache/fury/resolver/FieldResolver.java
+++ b/java/fury-core/src/main/java/org/apache/fury/resolver/FieldResolver.java
@@ -749,7 +749,8 @@ public class FieldResolver {
protected final ClassResolver classResolver;
private final FieldAccessor fieldAccessor;
private final ClassInfoHolder classInfoHolder;
- private boolean nullable;
+ private final boolean nullable;
+ private boolean trackingRef;
public FieldInfo(
Fury fury,
@@ -776,6 +777,13 @@ public class FieldResolver {
}
FuryField furyField = field == null ? null :
field.getAnnotation(FuryField.class);
this.nullable = furyField == null || furyField.nullable();
+ if (fury.trackingRef()) {
+ trackingRef =
+ furyField != null
+ ? furyField.trackingRef()
+ // todo question TypeRef.of(type)?
+ : classResolver.needToWriteRef(TypeRef.of(type));
+ }
}
public static FieldInfo of(
diff --git
a/java/fury-core/src/main/java/org/apache/fury/resolver/MapRefResolver.java
b/java/fury-core/src/main/java/org/apache/fury/resolver/MapRefResolver.java
index efab1943..fede7977 100644
--- a/java/fury-core/src/main/java/org/apache/fury/resolver/MapRefResolver.java
+++ b/java/fury-core/src/main/java/org/apache/fury/resolver/MapRefResolver.java
@@ -165,6 +165,12 @@ public final class MapRefResolver implements RefResolver {
return nextReadRefId;
}
+ @Override
+ public int preserveRefId(int refId) {
+ readRefIds.add(refId);
+ return refId;
+ }
+
@Override
public int tryPreserveRefId(MemoryBuffer buffer) {
byte headFlag = buffer.readByte();
diff --git
a/java/fury-core/src/main/java/org/apache/fury/resolver/NoRefResolver.java
b/java/fury-core/src/main/java/org/apache/fury/resolver/NoRefResolver.java
index 3937b1cd..998e8f32 100644
--- a/java/fury-core/src/main/java/org/apache/fury/resolver/NoRefResolver.java
+++ b/java/fury-core/src/main/java/org/apache/fury/resolver/NoRefResolver.java
@@ -65,6 +65,11 @@ public final class NoRefResolver implements RefResolver {
return -1;
}
+ @Override
+ public int preserveRefId(int refId) {
+ return -1;
+ }
+
@Override
public int tryPreserveRefId(MemoryBuffer buffer) {
// `NOT_NULL_VALUE_FLAG` can be used as stub reference id because we use
diff --git
a/java/fury-core/src/main/java/org/apache/fury/resolver/RefResolver.java
b/java/fury-core/src/main/java/org/apache/fury/resolver/RefResolver.java
index 46c581bb..f77ba458 100644
--- a/java/fury-core/src/main/java/org/apache/fury/resolver/RefResolver.java
+++ b/java/fury-core/src/main/java/org/apache/fury/resolver/RefResolver.java
@@ -77,6 +77,8 @@ public interface RefResolver {
*/
int preserveRefId();
+ int preserveRefId(int refId);
+
/**
* Preserve and return a `refId` which is `>=` {@link
Fury#NOT_NULL_VALUE_FLAG} if the value is
* not null. If the value is referencable value, the `refId` will be {@link
#preserveRefId}.
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 3af22ebe..cba248e9 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
@@ -30,6 +30,7 @@ import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.fury.Fury;
+import org.apache.fury.annotation.FuryField;
import org.apache.fury.collection.Tuple2;
import org.apache.fury.collection.Tuple3;
import org.apache.fury.memory.MemoryBuffer;
@@ -128,6 +129,7 @@ public abstract class AbstractObjectSerializer<T> extends
Serializer<T> {
if (fieldInfo.trackingRef) {
fieldValue = binding.readRef(buffer, fieldInfo);
} else {
+ binding.preserveRefId(-1);
if (nullable) {
byte headFlag = buffer.readByte();
if (headFlag == Fury.NULL_FLAG) {
@@ -150,6 +152,7 @@ public abstract class AbstractObjectSerializer<T> extends
Serializer<T> {
fieldValue = binding.readContainerFieldValueRef(buffer, fieldInfo);
generics.popGenericType();
} else {
+ binding.preserveRefId(-1);
boolean nullable = fieldInfo.nullable;
if (nullable) {
byte headFlag = buffer.readByte();
@@ -984,14 +987,22 @@ public abstract class AbstractObjectSerializer<T> extends
Serializer<T> {
protected final String qualifiedFieldName;
protected final FieldAccessor fieldAccessor;
protected boolean nullable;
+ protected boolean trackingRef;
- private InternalFieldInfo(Descriptor d, short classId) {
+ private InternalFieldInfo(Fury fury, Descriptor d, short classId) {
this.typeRef = d.getTypeRef();
this.classId = classId;
this.qualifiedFieldName = d.getDeclaringClass() + "." + d.getName();
this.fieldAccessor = d.getField() != null ?
FieldAccessor.createAccessor(d.getField()) : null;
+ FuryField furyField = d.getFuryField();
if (!typeRef.isPrimitive()) {
- nullable = d.getFuryField() == null || d.getFuryField().nullable();
+ nullable = furyField == null || furyField.nullable();
+ }
+ if (fury.trackingRef()) {
+ trackingRef =
+ furyField != null
+ ? furyField.trackingRef()
+ : fury.getClassResolver().needToWriteRef(typeRef);
}
}
@@ -1014,10 +1025,9 @@ public abstract class AbstractObjectSerializer<T>
extends Serializer<T> {
static final class FinalTypeField extends InternalFieldInfo {
final ClassInfo classInfo;
- final boolean trackingRef;
private FinalTypeField(Fury fury, Descriptor d) {
- super(d, getRegisteredClassId(fury, d.getTypeRef().getRawType()));
+ super(fury, d, getRegisteredClassId(fury, d.getTypeRef().getRawType()));
// invoke `copy` to avoid ObjectSerializer construct clear serializer by
`clearSerializer`.
if (typeRef.getRawType() == FinalObjectTypeStub.class) {
// `FinalObjectTypeStub` has no fields, using its `classInfo`
@@ -1026,19 +1036,17 @@ public abstract class AbstractObjectSerializer<T>
extends Serializer<T> {
} else {
classInfo = SerializationUtils.getClassInfo(fury,
typeRef.getRawType());
}
- trackingRef = fury.getClassResolver().needToWriteRef(typeRef);
}
}
static final class GenericTypeField extends InternalFieldInfo {
final GenericType genericType;
final ClassInfoHolder classInfoHolder;
- final boolean trackingRef;
final boolean isArray;
final ClassInfo containerClassInfo;
private GenericTypeField(Fury fury, Descriptor d) {
- super(d, getRegisteredClassId(fury, getRawType(d.getTypeRef())));
+ super(fury, d, getRegisteredClassId(fury, getRawType(d.getTypeRef())));
// TODO support generics <T> in Pojo<T>, see
ComplexObjectSerializer.getGenericTypes
ClassResolver classResolver = fury.getClassResolver();
GenericType t = classResolver.buildGenericType(typeRef);
@@ -1052,7 +1060,6 @@ public abstract class AbstractObjectSerializer<T> extends
Serializer<T> {
}
genericType = t;
classInfoHolder = classResolver.nilClassInfoHolder();
- trackingRef = classResolver.needToWriteRef(typeRef);
isArray = cls.isArray();
if (!fury.isCrossLanguage()) {
containerClassInfo = null;
diff --git
a/java/fury-core/src/main/java/org/apache/fury/serializer/SerializationBinding.java
b/java/fury-core/src/main/java/org/apache/fury/serializer/SerializationBinding.java
index c12845d3..80c0267c 100644
---
a/java/fury-core/src/main/java/org/apache/fury/serializer/SerializationBinding.java
+++
b/java/fury-core/src/main/java/org/apache/fury/serializer/SerializationBinding.java
@@ -88,6 +88,8 @@ interface SerializationBinding {
Object readContainerFieldValueRef(MemoryBuffer buffer, GenericTypeField
fieldInfo);
+ int preserveRefId(int refId);
+
static SerializationBinding createBinding(Fury fury) {
if (fury.isCrossLanguage()) {
return new XlangSerializationBinding(fury);
@@ -99,10 +101,12 @@ interface SerializationBinding {
final class JavaSerializationBinding implements SerializationBinding {
private final Fury fury;
private final ClassResolver classResolver;
+ private final RefResolver refResolver;
JavaSerializationBinding(Fury fury) {
this.fury = fury;
classResolver = fury.getClassResolver();
+ refResolver = fury.getRefResolver();
}
@Override
@@ -279,6 +283,11 @@ interface SerializationBinding {
MemoryBuffer buffer, Object fieldValue, ClassInfo classInfo) {
fury.writeNonRef(buffer, fieldValue, classInfo);
}
+
+ @Override
+ public int preserveRefId(int refId) {
+ return refResolver.preserveRefId(refId);
+ }
}
final class XlangSerializationBinding implements SerializationBinding {
@@ -479,5 +488,10 @@ interface SerializationBinding {
MemoryBuffer buffer, Object fieldValue, ClassInfo classInfo) {
fury.xwriteData(buffer, classInfo, fieldValue);
}
+
+ @Override
+ public int preserveRefId(int refId) {
+ return refResolver.preserveRefId(refId);
+ }
}
}
diff --git
a/java/fury-core/src/test/java/org/apache/fury/annotation/FuryAnnotationTest.java
b/java/fury-core/src/test/java/org/apache/fury/annotation/FuryAnnotationTest.java
index 2d3bdd71..8a481ac6 100644
---
a/java/fury-core/src/test/java/org/apache/fury/annotation/FuryAnnotationTest.java
+++
b/java/fury-core/src/test/java/org/apache/fury/annotation/FuryAnnotationTest.java
@@ -20,7 +20,6 @@
package org.apache.fury.annotation;
import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertThrows;
import com.google.common.collect.Lists;
import java.util.List;
@@ -134,7 +133,7 @@ public class FuryAnnotationTest extends FuryTestBase {
@Data
public static class BeanM1 {
- @FuryField private BeanN beanN;
+ @FuryField private BeanN beanN = new BeanN();
}
@Test(dataProvider = "basicMultiConfigFury")
@@ -168,10 +167,6 @@ public class FuryAnnotationTest extends FuryTestBase {
.withCodegen(false)
.build();
BeanM1 o1 = new BeanM1();
- if (referenceTracking) {
- assertEquals(serDe(fury, o1), o1);
- } else {
- assertThrows(NullPointerException.class, () -> fury.serialize(o1));
- }
+ assertEquals(serDe(fury, o1), o1);
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]