hlleb-lizunkou opened a new issue, #3826: URL: https://github.com/apache/fory/issues/3826
### Search before asking - [x] I had searched in the [issues](https://github.com/apache/fory/issues) and found no similar issues describing this exact failure (related: #3621, but that covers a different symptom and its fix doesn't cover this case — see below). ### Version 1.2.0, 1.3.0 (not reproducible on 1.1.0) ### Component(s) Java ### Minimal reproduce step ```java import org.apache.fory.Fory; import org.apache.fory.ThreadSafeFory; import org.apache.fory.config.Language; import org.hibernate.collection.spi.PersistentSet; import java.util.HashSet; import java.util.Set; public class Repro { public static class Holder { Set<String> tags; } public static void main(String[] args) { ThreadSafeFory fory = Fory.builder() .withLanguage(Language.JAVA) .withRefTracking(true) .requireClassRegistration(false) .buildThreadSafeFory(); HashSet<String> backing = new HashSet<>(); backing.add("a"); backing.add("b"); Holder holder = new Holder(); // any Set/Collection impl that is (a) unregistered, (b) not a java.util builtin, and // (c) has instance fields beyond its elements should reproduce this holder.tags = new PersistentSet<>(null, backing); byte[] bytes = fory.serialize(holder); fory.deserialize(bytes); // throws } } ``` `org.hibernate.collection.spi.PersistentSet` is from `org.hibernate.orm:hibernate-core` (used here as a real-world example of a `Set` implementation carrying extra instance state alongside its elements — session, role, key, dirty flags, etc.). ### What did you expect to see? Either: 1. The unregistered `Set` implementation round-trips (as it does on fory-core 1.1.0), or 2. A clear, actionable error at serialize or deserialize time, rather than an internal `ClassCastException` surfacing from generated code. ### What did you see instead? ``` org.apache.fory.exception.DeserializationException: Deserialize failed, read objects are: [Holder, null] Caused by: java.lang.ClassCastException: class org.hibernate.collection.spi.PersistentSetForyRefCodecCompatible1_0 cannot be cast to class org.apache.fory.serializer.collection.CollectionLikeSerializer (org.hibernate.collection.spi.PersistentSetForyRefCodecCompatible1_0 is in unnamed module of loader org.apache.fory.util.ClassLoaderUtils$ByteArrayClassLoader; org.apache.fory.serializer.collection.CollectionLikeSerializer is in unnamed module of loader 'app') at org.hibernate.collection.spi.PersistentSetForyRefCodecCompatible1_0.readCollection$(PersistentSetForyRefCodecCompatible1_0.java) at org.hibernate.collection.spi.PersistentSetForyRefCodecCompatible1_0.readFields3$(PersistentSetForyRefCodecCompatible1_0.java) at org.hibernate.collection.spi.PersistentSetForyRefCodecCompatible1_0.read(PersistentSetForyRefCodecCompatible1_0.java) at org.apache.fory.context.ReadContext.readDataInternal(ReadContext.java) at org.apache.fory.context.ReadContext.readNonRef(ReadContext.java) at org.apache.fory.context.ReadContext.readRef(ReadContext.java) at org.apache.fory.Fory.deserialize(Fory.java) ``` The same generated-code pattern appears at the enclosing bean's own field-read site, not just inside `PersistentSet`'s codec: ```java // generated for Holder.tags (declared java.util.Set<String>) private Object readCollection(ReadContext readContext, MemoryBuffer memoryBuffer) { CollectionLikeSerializer collectionSerializer = (CollectionLikeSerializer) _f_typeResolver.readTypeInfo(readContext, setTypeInfoHolder).getSerializer(); ... } ``` ### Root cause (as far as I could determine) The generated field-read code for a `Set`/`Collection`-typed field unconditionally casts whatever serializer resolves for the field's concrete runtime type to `CollectionLikeSerializer`. Because `PersistentSet` is unregistered and has instance fields beyond its Set elements, its own serializer is built via `CompatibleCodecBuilder` and extends `GeneratedCompatibleSerializer` — a plain bean codec that does **not** implement `CollectionLikeSerializer`. The cast above then fails. Bisected by pinning only the `fory-core` dependency version against the same reproduction: - `1.1.0` — passes (a single non-"Compatible" codec is generated and shared between read and write for the concrete class, so no such cast happens against a bean codec) - `1.2.0` — fails with the exact exception above - `1.3.0` — fails with the exact exception above This lines up with the 1.2.0 release note "default compatible mode for native serialization" as the likely point where read-time codec selection changed for fields like this. ### Anything else? This looks like the same underlying gap as #3621 (COMPATIBLE mode mishandling unregistered, non-`java.util` Collection/Map implementations), surfacing with a different symptom — a hard `ClassCastException` here instead of silent data loss there. The fix that closed #3621 (#3628) only special-cased containers implementing `Externalizable`; `PersistentSet` (and presumably other custom collection wrappers carrying their own extra state) is not `Externalizable`, so it still falls into the same general gap. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
