diff --git a/integration_tests/latest_jdk_tests/src/test/java/org/apache/fury/integration_tests/RecordSerializersTest.java b/integration_tests/latest_jdk_tests/src/test/java/org/apache/fury/integration_tests/RecordSerializersTest.java index 8922ced02e..c582f8b994 100644 --- a/integration_tests/latest_jdk_tests/src/test/java/org/apache/fury/integration_tests/RecordSerializersTest.java +++ b/integration_tests/latest_jdk_tests/src/test/java/org/apache/fury/integration_tests/RecordSerializersTest.java @@ -235,4 +235,14 @@ public void testPrivateRecord(boolean codegen) { } private record PrivateRecord(String foo) {} + + @Test(dataProvider = "codegen") + public void testCopy(boolean codegen) { + Fury fury = Fury.builder().withCodegen(codegen).build(); + fury.register(Foo.class); + fury.register(PrivateRecord.class); + Assert.assertEquals(fury.copy(new PrivateRecord("foo")), new PrivateRecord("foo")); + Foo foo = new Foo(10, "abc", new ArrayList<>(Arrays.asList("a", "b")), 'x'); + Assert.assertEquals(fury.copy(foo), foo); + } } 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 8591c6c8f0..7a53478c93 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 @@ -26,8 +26,10 @@ import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.stream.Collectors; import org.apache.fury.Fury; import org.apache.fury.collection.Tuple2; import org.apache.fury.collection.Tuple3; @@ -44,6 +46,7 @@ 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.RecordInfo; import org.apache.fury.util.record.RecordUtils; public abstract class AbstractObjectSerializer extends Serializer { @@ -52,6 +55,7 @@ public abstract class AbstractObjectSerializer extends Serializer { protected final boolean isRecord; protected final MethodHandle constructor; private InternalFieldInfo[] fieldInfos; + private RecordInfo copyRecordInfo; public AbstractObjectSerializer(Fury fury, Class type) { this( @@ -78,7 +82,9 @@ public T copy(T originObj) { if (isRecord) { Object[] fieldValues = copyFields(originObj); try { - return (T) constructor.invokeWithArguments(fieldValues); + T t = (T) constructor.invokeWithArguments(fieldValues); + Arrays.fill(copyRecordInfo.getRecordComponents(), null); + return t; } catch (Throwable e) { Platform.throwException(e); } @@ -117,7 +123,7 @@ private Object[] copyFields(T originObj) { fieldValues[i] = fury.copyObject(fieldValue, fieldInfo.classId); } } - return fieldValues; + return RecordUtils.remapping(copyRecordInfo, fieldValues); } private void copyFields(T originObj, T newObj) { @@ -242,6 +248,13 @@ private InternalFieldInfo[] buildFieldsInfo() { 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); + if (isRecord) { + List fieldNames = + Arrays.stream(fieldInfos) + .map(f -> f.fieldAccessor.getField().getName()) + .collect(Collectors.toList()); + copyRecordInfo = new RecordInfo(type, fieldNames); + } return fieldInfos; } diff --git a/java/fury-core/src/main/java/org/apache/fury/serializer/CompatibleSerializer.java b/java/fury-core/src/main/java/org/apache/fury/serializer/CompatibleSerializer.java index d018e5dd55..433093d88a 100644 --- a/java/fury-core/src/main/java/org/apache/fury/serializer/CompatibleSerializer.java +++ b/java/fury-core/src/main/java/org/apache/fury/serializer/CompatibleSerializer.java @@ -301,10 +301,10 @@ public T read(MemoryBuffer buffer) { if (isRecord) { Object[] fieldValues = new Object[fieldResolver.getNumFields()]; readFields(buffer, fieldValues); - RecordUtils.remapping(recordInfo, fieldValues); + fieldValues = RecordUtils.remapping(recordInfo, fieldValues); assert constructor != null; try { - T t = (T) constructor.invokeWithArguments(recordInfo.getRecordComponents()); + T t = (T) constructor.invokeWithArguments(fieldValues); Arrays.fill(recordInfo.getRecordComponents(), null); return t; } catch (Throwable e) { 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 1292fcbdb6..ee9628728a 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 @@ -128,9 +128,9 @@ public T read(MemoryBuffer buffer) { Object[] fieldValues = new Object[finalFields.length + otherFields.length + containerFields.length]; readFields(buffer, fieldValues); - RecordUtils.remapping(recordInfo, fieldValues); + fieldValues = RecordUtils.remapping(recordInfo, fieldValues); try { - T t = (T) constructor.invokeWithArguments(recordInfo.getRecordComponents()); + T t = (T) constructor.invokeWithArguments(fieldValues); Arrays.fill(recordInfo.getRecordComponents(), null); return t; } catch (Throwable e) { 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 2c72fb2e9b..374b5be9d0 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 @@ -230,9 +230,9 @@ static void writeContainerFieldValue( public T read(MemoryBuffer buffer) { if (isRecord) { Object[] fields = readFields(buffer); - RecordUtils.remapping(recordInfo, fields); + fields = RecordUtils.remapping(recordInfo, fields); try { - T obj = (T) constructor.invokeWithArguments(recordInfo.getRecordComponents()); + T obj = (T) constructor.invokeWithArguments(fields); Arrays.fill(recordInfo.getRecordComponents(), null); return obj; } catch (Throwable e) { diff --git a/java/fury-core/src/main/java/org/apache/fury/util/record/RecordUtils.java b/java/fury-core/src/main/java/org/apache/fury/util/record/RecordUtils.java index 65652e0546..6b2de31cbe 100644 --- a/java/fury-core/src/main/java/org/apache/fury/util/record/RecordUtils.java +++ b/java/fury-core/src/main/java/org/apache/fury/util/record/RecordUtils.java @@ -278,7 +278,7 @@ public static Map buildFieldToComponentMapping(Class cls) { return recordComponentsIndex; } - public static void remapping(RecordInfo recordInfo, Object[] fields) { + public static Object[] remapping(RecordInfo recordInfo, Object[] fields) { int[] recordComponentsIndex = recordInfo.getRecordComponentsIndex(); Object[] recordComponents = recordInfo.getRecordComponents(); Object[] recordComponentsDefaultValues = recordInfo.getRecordComponentsDefaultValues(); @@ -291,5 +291,6 @@ public static void remapping(RecordInfo recordInfo, Object[] fields) { recordComponents[i] = recordComponentsDefaultValues[i]; } } + return recordComponents; } }