From 9d7e3544ac1c9ff0d6e832fdbd5af950df6bd876 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Tue, 8 Jul 2025 14:31:51 +0100 Subject: [PATCH 1/4] experiment with making deserialize check the type --- .../src/main/java/org/apache/fory/Fory.java | 62 +++++++++++++++++-- .../test/java/org/apache/fory/ForyTest.java | 16 +++++ 2 files changed, 73 insertions(+), 5 deletions(-) diff --git a/java/fory-core/src/main/java/org/apache/fory/Fory.java b/java/fory-core/src/main/java/org/apache/fory/Fory.java index a2840ef5d3..621cb1d104 100644 --- a/java/fory-core/src/main/java/org/apache/fory/Fory.java +++ b/java/fory-core/src/main/java/org/apache/fory/Fory.java @@ -798,7 +798,7 @@ public Object deserialize(byte[] bytes) { public T deserialize(byte[] bytes, Class type) { generics.pushGenericType(classResolver.buildGenericType(type)); try { - return (T) deserialize(MemoryUtils.wrap(bytes), null); + return (T) checkedDeserialize(MemoryUtils.wrap(bytes), null, type); } finally { generics.popGenericType(); } @@ -834,6 +834,12 @@ public Object deserialize(MemoryBuffer buffer) { */ @Override public Object deserialize(MemoryBuffer buffer, Iterable outOfBandBuffers) { + return checkedDeserialize(buffer, outOfBandBuffers, null); + } + + private Object checkedDeserialize(MemoryBuffer buffer, + Iterable outOfBandBuffers, + Class expectedType) { try { jitContext.lock(); if (depth != 0) { @@ -843,9 +849,9 @@ public Object deserialize(MemoryBuffer buffer, Iterable outOfBandB short magicNumber = buffer.readInt16(); assert magicNumber == MAGIC_NUMBER : String.format( - "The fory xlang serialization must start with magic number 0x%x. Please " - + "check whether the serialization is based on the xlang protocol and the data didn't corrupt.", - MAGIC_NUMBER); + "The fory xlang serialization must start with magic number 0x%x. Please " + + "check whether the serialization is based on the xlang protocol and the data didn't corrupt.", + MAGIC_NUMBER); } byte bitmap = buffer.readByte(); if ((bitmap & isNilFlag) == isNilFlag) { @@ -878,7 +884,13 @@ public Object deserialize(MemoryBuffer buffer, Iterable outOfBandB } Object obj; if (isTargetXLang) { - obj = xreadRef(buffer); + if (expectedType != null) { + obj = checkedXreadRef(buffer, expectedType); + } else { + obj = xreadRef(buffer); + } + } else if (expectedType != null) { + obj = checkedReadRef(buffer, expectedType); } else { obj = readRef(buffer); } @@ -934,6 +946,26 @@ public Object readRef(MemoryBuffer buffer) { } } + private Object checkedReadRef(MemoryBuffer buffer, Class expectedType) { + RefResolver refResolver = this.refResolver; + int nextReadRefId = refResolver.tryPreserveRefId(buffer); + if (nextReadRefId >= NOT_NULL_VALUE_FLAG) { + // ref value or not-null value + ClassInfo classInfo = classResolver.readClassInfo(buffer); + if (!expectedType.isAssignableFrom(classInfo.getCls())) { + throw new IllegalStateException(String.format( + "Unexpected type %s which is not assignable to %s", + classInfo.getClass().getName(), + expectedType.getName())); + } + Object o = readDataInternal(buffer, classInfo); + refResolver.setReadObject(nextReadRefId, o); + return o; + } else { + return refResolver.getReadObject(); + } + } + public Object readRef(MemoryBuffer buffer, ClassInfoHolder classInfoHolder) { RefResolver refResolver = this.refResolver; int nextReadRefId = refResolver.tryPreserveRefId(buffer); @@ -1070,6 +1102,26 @@ public Object xreadRef(MemoryBuffer buffer) { } } + public Object checkedXreadRef(MemoryBuffer buffer, Class expectedType) { + RefResolver refResolver = this.refResolver; + int nextReadRefId = refResolver.tryPreserveRefId(buffer); + if (nextReadRefId >= NOT_NULL_VALUE_FLAG) { + ClassInfo classInfo = xtypeResolver.readClassInfo(buffer); + if (!expectedType.isAssignableFrom(classInfo.getCls())) { + throw new IllegalStateException(String.format( + "Unexpected type %s which is not assignable to %s", + classInfo.getClass().getName(), + expectedType.getName())); + } + Object o = xreadNonRef(buffer, classInfo); + refResolver.setReadObject(nextReadRefId, o); + return o; + } else { + return refResolver.getReadObject(); + } + } + + public Object xreadRef(MemoryBuffer buffer, Serializer serializer) { if (serializer.needToWriteRef()) { RefResolver refResolver = this.refResolver; diff --git a/java/fory-core/src/test/java/org/apache/fory/ForyTest.java b/java/fory-core/src/test/java/org/apache/fory/ForyTest.java index 4d8a10a75b..b20af8fa9d 100644 --- a/java/fory-core/src/test/java/org/apache/fory/ForyTest.java +++ b/java/fory-core/src/test/java/org/apache/fory/ForyTest.java @@ -673,4 +673,20 @@ public void testStructMapping() { Assert.assertEquals(struct1.f1, struct2.f1); Assert.assertEquals(struct1.f2, struct2.f2); } + + @Test + public void testCheckedDeserialize() { + Fory fory = Fory.builder() + .withLanguage(Language.JAVA) + .withRefTracking(true) + .requireClassRegistration(false) + .build(); + LocalDate now = LocalDate.now(); + byte[] bytes = fory.serialize(now); + LocalDate ld0 = fory.deserialize(bytes, LocalDate.class); + Assert.assertEquals(ld0, LocalDate.now()); + // Deserialize with wrong type and get an IllegalStateException + assertThrows(IllegalStateException.class, + () -> fory.deserialize(bytes, String.class)); + } } From 4cd466bc55a9e6417bfa7c3e3c2e66a79d0aa53d Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Tue, 8 Jul 2025 14:42:48 +0100 Subject: [PATCH 2/4] format --- java/fory-core/src/main/java/org/apache/fory/Fory.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/java/fory-core/src/main/java/org/apache/fory/Fory.java b/java/fory-core/src/main/java/org/apache/fory/Fory.java index 621cb1d104..8a2b764242 100644 --- a/java/fory-core/src/main/java/org/apache/fory/Fory.java +++ b/java/fory-core/src/main/java/org/apache/fory/Fory.java @@ -849,9 +849,9 @@ private Object checkedDeserialize(MemoryBuffer buffer, short magicNumber = buffer.readInt16(); assert magicNumber == MAGIC_NUMBER : String.format( - "The fory xlang serialization must start with magic number 0x%x. Please " - + "check whether the serialization is based on the xlang protocol and the data didn't corrupt.", - MAGIC_NUMBER); + "The fory xlang serialization must start with magic number 0x%x. Please " + + "check whether the serialization is based on the xlang protocol and the data didn't corrupt.", + MAGIC_NUMBER); } byte bitmap = buffer.readByte(); if ((bitmap & isNilFlag) == isNilFlag) { @@ -1102,7 +1102,7 @@ public Object xreadRef(MemoryBuffer buffer) { } } - public Object checkedXreadRef(MemoryBuffer buffer, Class expectedType) { + private Object checkedXreadRef(MemoryBuffer buffer, Class expectedType) { RefResolver refResolver = this.refResolver; int nextReadRefId = refResolver.tryPreserveRefId(buffer); if (nextReadRefId >= NOT_NULL_VALUE_FLAG) { From 7387332d468526a7d508908a5747c18034a3a65d Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Tue, 8 Jul 2025 14:53:01 +0100 Subject: [PATCH 3/4] use DeserializationException --- java/fory-core/src/main/java/org/apache/fory/Fory.java | 5 +++-- java/fory-core/src/test/java/org/apache/fory/ForyTest.java | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/java/fory-core/src/main/java/org/apache/fory/Fory.java b/java/fory-core/src/main/java/org/apache/fory/Fory.java index 8a2b764242..70f59dda51 100644 --- a/java/fory-core/src/main/java/org/apache/fory/Fory.java +++ b/java/fory-core/src/main/java/org/apache/fory/Fory.java @@ -37,6 +37,7 @@ import org.apache.fory.config.ForyBuilder; import org.apache.fory.config.Language; import org.apache.fory.config.LongEncoding; +import org.apache.fory.exception.DeserializationException; import org.apache.fory.io.ForyInputStream; import org.apache.fory.io.ForyReadableChannel; import org.apache.fory.logging.Logger; @@ -953,7 +954,7 @@ private Object checkedReadRef(MemoryBuffer buffer, Class expectedType) { // ref value or not-null value ClassInfo classInfo = classResolver.readClassInfo(buffer); if (!expectedType.isAssignableFrom(classInfo.getCls())) { - throw new IllegalStateException(String.format( + throw new DeserializationException(String.format( "Unexpected type %s which is not assignable to %s", classInfo.getClass().getName(), expectedType.getName())); @@ -1108,7 +1109,7 @@ private Object checkedXreadRef(MemoryBuffer buffer, Class expectedType) { if (nextReadRefId >= NOT_NULL_VALUE_FLAG) { ClassInfo classInfo = xtypeResolver.readClassInfo(buffer); if (!expectedType.isAssignableFrom(classInfo.getCls())) { - throw new IllegalStateException(String.format( + throw new DeserializationException(String.format( "Unexpected type %s which is not assignable to %s", classInfo.getClass().getName(), expectedType.getName())); diff --git a/java/fory-core/src/test/java/org/apache/fory/ForyTest.java b/java/fory-core/src/test/java/org/apache/fory/ForyTest.java index b20af8fa9d..096d489ca7 100644 --- a/java/fory-core/src/test/java/org/apache/fory/ForyTest.java +++ b/java/fory-core/src/test/java/org/apache/fory/ForyTest.java @@ -58,6 +58,7 @@ import org.apache.fory.config.CompatibleMode; import org.apache.fory.config.ForyBuilder; import org.apache.fory.config.Language; +import org.apache.fory.exception.DeserializationException; import org.apache.fory.exception.ForyException; import org.apache.fory.exception.InsecureException; import org.apache.fory.memory.MemoryBuffer; @@ -685,8 +686,8 @@ public void testCheckedDeserialize() { byte[] bytes = fory.serialize(now); LocalDate ld0 = fory.deserialize(bytes, LocalDate.class); Assert.assertEquals(ld0, LocalDate.now()); - // Deserialize with wrong type and get an IllegalStateException - assertThrows(IllegalStateException.class, + // Deserialize with wrong type and get a DeserializationException + assertThrows(DeserializationException.class, () -> fory.deserialize(bytes, String.class)); } } From 4233f3d9f5f08d14bac586d9d6db63301600a62e Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Tue, 8 Jul 2025 15:01:17 +0100 Subject: [PATCH 4/4] Update ForyTest.java --- java/fory-core/src/test/java/org/apache/fory/ForyTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/fory-core/src/test/java/org/apache/fory/ForyTest.java b/java/fory-core/src/test/java/org/apache/fory/ForyTest.java index 096d489ca7..abecf269a6 100644 --- a/java/fory-core/src/test/java/org/apache/fory/ForyTest.java +++ b/java/fory-core/src/test/java/org/apache/fory/ForyTest.java @@ -685,7 +685,7 @@ public void testCheckedDeserialize() { LocalDate now = LocalDate.now(); byte[] bytes = fory.serialize(now); LocalDate ld0 = fory.deserialize(bytes, LocalDate.class); - Assert.assertEquals(ld0, LocalDate.now()); + Assert.assertEquals(ld0, now); // Deserialize with wrong type and get a DeserializationException assertThrows(DeserializationException.class, () -> fory.deserialize(bytes, String.class));