Skip to content

Commit

Permalink
add FieldInfo annotation
Browse files Browse the repository at this point in the history
  • Loading branch information
hening committed Feb 5, 2025
1 parent 8889203 commit d27d8b6
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 30 deletions.
28 changes: 19 additions & 9 deletions java/fury-core/src/main/java/org/apache/fury/Fury.java
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,25 @@ public void writeJavaStringRef(MemoryBuffer buffer, String str) {
}
}

public void writeJavaStringRef(MemoryBuffer buffer, String str, boolean refTracking, boolean nullable) {
if (refTracking) {
if (!refResolver.writeRefOrNull(buffer, str)) {
stringSerializer.writeJavaString(buffer, str);
}
} else {
if (nullable) {
if (str == null) {
buffer.writeByte(Fury.NULL_FLAG);
} else {
buffer.writeByte(Fury.NOT_NULL_VALUE_FLAG);
stringSerializer.write(buffer, str);
}
} else {
stringSerializer.write(buffer, str);
}
}
}

public String readJavaStringRef(MemoryBuffer buffer) {
RefResolver refResolver = this.refResolver;
if (stringSerializer.needToWriteRef()) {
Expand Down Expand Up @@ -935,15 +954,6 @@ public Object readNullable(MemoryBuffer buffer) {
}
}

public Object readNullable(MemoryBuffer buffer, ClassInfoHolder classInfoHolder) {
byte headFlag = buffer.readByte();
if (headFlag == Fury.NULL_FLAG) {
return null;
} else {
return readNonRef(buffer, classInfoHolder);
}
}

/** Class should be read already. */
public Object readData(MemoryBuffer buffer, ClassInfo classInfo) {
depth++;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.apache.fury.annotation;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FieldInfo {

/**
* Whether to track reference.
*/
boolean trackingRef() default false;
/**
* Whether field is nullable.
*/
boolean nullable() default true;
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import static org.apache.fury.type.DescriptorGrouper.createDescriptorGrouper;
import static org.apache.fury.type.TypeUtils.getRawType;

import java.lang.annotation.Annotation;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
Expand All @@ -31,6 +32,7 @@
import java.util.List;
import java.util.stream.Collectors;
import org.apache.fury.Fury;
import org.apache.fury.annotation.FieldInfo;
import org.apache.fury.collection.Tuple2;
import org.apache.fury.collection.Tuple3;
import org.apache.fury.memory.Platform;
Expand Down Expand Up @@ -413,6 +415,7 @@ public static class InternalFieldInfo {
protected final short classId;
protected final String qualifiedFieldName;
protected final FieldAccessor fieldAccessor;
protected FieldInfo fieldInfo;

private InternalFieldInfo(
short classId, String qualifiedFieldName, FieldAccessor fieldAccessor) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ private void readAndWriteFieldValue(
fury, buffer, targetObject, fieldAccessor, classId)) {
Object fieldValue;
fieldValue = fieldAccessor.getObject(targetObject);
if (ObjectSerializer.writeBasicObjectFieldValueFailed(fury, buffer, fieldValue, classId)) {
if (ObjectSerializer.writeBasicObjectFieldValueFailed(fury, buffer, fieldValue, classId, false, true)) {
if (classId == ClassResolver.NO_CLASS_ID) { // SEPARATE_TYPES_HASH
writeSeparateFieldValue(fieldInfo, buffer, fieldValue);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@

import static org.apache.fury.type.DescriptorGrouper.createDescriptorGrouper;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.apache.fury.Fury;
import org.apache.fury.annotation.FieldInfo;
import org.apache.fury.collection.Tuple2;
import org.apache.fury.collection.Tuple3;
import org.apache.fury.exception.FuryException;
Expand Down Expand Up @@ -136,11 +138,16 @@ public void write(MemoryBuffer buffer, T value) {
writeFinalFields(buffer, value, fury, refResolver, classResolver);
for (GenericTypeField fieldInfo : otherFields) {
FieldAccessor fieldAccessor = fieldInfo.fieldAccessor;
Object fieldValue = fieldAccessor.getObject(value);
FieldInfo fieldInfoAnnotation = fieldInfo.fieldInfo;
Object fieldValue = fieldAccessor.getObject(value);
if (fieldInfo.trackingRef) {
fury.writeRef(buffer, fieldValue, fieldInfo.classInfoHolder);
} else {
fury.writeNullable(buffer, fieldValue, fieldInfo.classInfoHolder);
if (fieldInfoAnnotation != null && !fieldInfoAnnotation.nullable()) {
fury.writeNonRef(buffer, fieldValue, classResolver.getClassInfo(fieldValue.getClass(), fieldInfo.classInfoHolder));
} else {
fury.writeNullable(buffer, fieldValue, fieldInfo.classInfoHolder);
}
}
}
writeContainerFields(buffer, value, fury, refResolver, classResolver);
Expand All @@ -160,7 +167,14 @@ private void writeFinalFields(
short classId = fieldInfo.classId;
if (writePrimitiveFieldValueFailed(fury, buffer, value, fieldAccessor, classId)) {
Object fieldValue = fieldAccessor.getObject(value);
if (writeBasicObjectFieldValueFailed(fury, buffer, fieldValue, classId)) {
final FieldInfo fieldInfoAnnotation = fieldInfo.fieldInfo;
boolean nullable = true;
boolean trackingRef = false;
if (fieldInfoAnnotation != null) {
nullable = fieldInfoAnnotation.nullable();
trackingRef = fieldInfoAnnotation.trackingRef();
}
if (writeBasicObjectFieldValueFailed(fury, buffer, fieldValue, classId, trackingRef, nullable)) {
Serializer<Object> serializer = fieldInfo.classInfo.getSerializer();
if (!metaShareEnabled || isFinal[i]) {
// whether tracking ref is recorded in `fieldInfo.serializer`, so it's still
Expand All @@ -174,7 +188,11 @@ private void writeFinalFields(
serializer.write(buffer, fieldValue);
}
} else {
fury.writeNullable(buffer, fieldValue, fieldInfo.classInfo);
if (nullable) {
fury.writeNullable(buffer, fieldValue, fieldInfo.classInfo);
} else {
fury.writeNonRef(buffer, fieldValue, fieldInfo.classInfo);
}
}
}
}
Expand Down Expand Up @@ -205,6 +223,13 @@ static void writeContainerFieldValue(
GenericTypeField fieldInfo,
MemoryBuffer buffer,
Object fieldValue) {
final FieldInfo fieldInfoAnnotation = fieldInfo.fieldInfo;
boolean trackingRef = false;
boolean nullable = true;
if (fieldInfoAnnotation != null) {
nullable = fieldInfoAnnotation.nullable();
trackingRef = fieldInfoAnnotation.trackingRef();
}
if (fieldInfo.trackingRef) {
if (!refResolver.writeRefOrNull(buffer, fieldValue)) {
ClassInfo classInfo =
Expand All @@ -214,20 +239,33 @@ static void writeContainerFieldValue(
generics.popGenericType();
}
} else {
if (fieldValue == null) {
buffer.writeByte(Fury.NULL_FLAG);
} else {
buffer.writeByte(Fury.NOT_NULL_VALUE_FLAG);
generics.pushGenericType(fieldInfo.genericType);
fury.writeNonRef(
buffer,
fieldValue,
classResolver.getClassInfo(fieldValue.getClass(), fieldInfo.classInfoHolder));
generics.popGenericType();
}
if (nullable) {
writeContainerFieldValueNullable(buffer, fury, fieldInfo, generics, classResolver, fieldValue);
} else {
generics.pushGenericType(fieldInfo.genericType);
fury.writeNonRef(
buffer,
fieldValue,
classResolver.getClassInfo(fieldValue.getClass(), fieldInfo.classInfoHolder));
generics.popGenericType();
}
}
}

private static void writeContainerFieldValueNullable(MemoryBuffer buffer, Fury fury, GenericTypeField fieldInfo, Generics generics, ClassResolver classResolver, Object fieldValue) {
if (fieldValue == null) {
buffer.writeByte(Fury.NULL_FLAG);
} else {
buffer.writeByte(Fury.NOT_NULL_VALUE_FLAG);
generics.pushGenericType(fieldInfo.genericType);
fury.writeNonRef(
buffer,
fieldValue,
classResolver.getClassInfo(fieldValue.getClass(), fieldInfo.classInfoHolder));
generics.popGenericType();
}
}

@Override
public T read(MemoryBuffer buffer) {
if (isRecord) {
Expand Down Expand Up @@ -495,16 +533,20 @@ static boolean writePrimitiveFieldValueFailed(
* @return true if field value isn't written by this function.
*/
static boolean writeBasicObjectFieldValueFailed(
Fury fury, MemoryBuffer buffer, Object fieldValue, short classId) {
Fury fury, MemoryBuffer buffer, Object fieldValue, short classId, boolean trackingRef, boolean nullable) {
if (!fury.isBasicTypesRefIgnored()) {
return true; // let common path handle this.
}
// add time types serialization here.
// add time types serialization here.
switch (classId) {
case ClassResolver.STRING_CLASS_ID: // fastpath for string.
fury.writeJavaStringRef(buffer, (String) (fieldValue));
fury.writeJavaStringRef(buffer, (String) (fieldValue), trackingRef, nullable);
return false;
case ClassResolver.BOOLEAN_CLASS_ID:
if (!nullable) {
buffer.writeBoolean((Boolean) (fieldValue));
return false;
}
{
if (fieldValue == null) {
buffer.writeByte(Fury.NULL_FLAG);
Expand All @@ -515,6 +557,10 @@ static boolean writeBasicObjectFieldValueFailed(
return false;
}
case ClassResolver.BYTE_CLASS_ID:
if (!nullable) {
buffer.writeByte((Byte) (fieldValue));
return false;
}
{
if (fieldValue == null) {
buffer.writeByte(Fury.NULL_FLAG);
Expand All @@ -525,6 +571,10 @@ static boolean writeBasicObjectFieldValueFailed(
return false;
}
case ClassResolver.CHAR_CLASS_ID:
if (!nullable) {
buffer.writeChar((Character) (fieldValue));
return false;
}
{
if (fieldValue == null) {
buffer.writeByte(Fury.NULL_FLAG);
Expand All @@ -535,6 +585,10 @@ static boolean writeBasicObjectFieldValueFailed(
return false;
}
case ClassResolver.SHORT_CLASS_ID:
if (!nullable) {
buffer.writeInt16((Short) (fieldValue));
return false;
}
{
if (fieldValue == null) {
buffer.writeByte(Fury.NULL_FLAG);
Expand All @@ -545,6 +599,14 @@ static boolean writeBasicObjectFieldValueFailed(
return false;
}
case ClassResolver.INTEGER_CLASS_ID:
if (!nullable) {
if (fury.compressInt()) {
buffer.writeVarInt32((Integer) (fieldValue));
} else {
buffer.writeInt32((Integer) (fieldValue));
}
return false;
}
{
if (fieldValue == null) {
buffer.writeByte(Fury.NULL_FLAG);
Expand All @@ -559,6 +621,10 @@ static boolean writeBasicObjectFieldValueFailed(
return false;
}
case ClassResolver.FLOAT_CLASS_ID:
if (!nullable) {
buffer.writeFloat32((Float) (fieldValue));
return false;
}
{
if (fieldValue == null) {
buffer.writeByte(Fury.NULL_FLAG);
Expand All @@ -569,6 +635,10 @@ static boolean writeBasicObjectFieldValueFailed(
return false;
}
case ClassResolver.LONG_CLASS_ID:
if (!nullable) {
fury.writeInt64(buffer, (Long) (fieldValue));
return false;
}
{
if (fieldValue == null) {
buffer.writeByte(Fury.NULL_FLAG);
Expand All @@ -579,6 +649,10 @@ static boolean writeBasicObjectFieldValueFailed(
return false;
}
case ClassResolver.DOUBLE_CLASS_ID:
if (!nullable) {
buffer.writeFloat64((Double) (fieldValue));
return false;
}
{
if (fieldValue == null) {
buffer.writeByte(Fury.NULL_FLAG);
Expand Down
7 changes: 5 additions & 2 deletions java/fury-core/src/test/java/org/apache/fury/FuryTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -436,8 +436,11 @@ private static class IgnoreFields {

@Test
public void testIgnoreFields() {
Fury fury = Fury.builder().requireClassRegistration(false).build();
IgnoreFields o = serDe(fury, new IgnoreFields(1, 2, 3));
Fury fury = Fury.builder().requireClassRegistration(false).withCodegen(false).build();
ImmutableMap<String, Integer> map1 = ImmutableMap.of("1", 1);
ImmutableMap<String, Integer> map2 = ImmutableMap.of("2", 2);
ExposeFields o = serDe(fury, new ExposeFields(1, 2, 3, map1, map2));
IgnoreFields o1 = serDe(fury, new IgnoreFields(1, 2, 3));
assertEquals(0, o.f1);
assertEquals(0, o.f2);
assertEquals(3, o.f3);
Expand Down

0 comments on commit d27d8b6

Please sign in to comment.