Search before asking
Version
1.x.x
Component(s)
Java
Minimal reproduce step
Payloads written by fory-core 1.3.0 can't be read back by 1.4.0, 1.5.0, or 1.6.0 when the serialized object's class extends an abstract superclass that was never registered. 1.3.0 reads the same bytes fine, and 1.4.0+ round-trips with itself fine — only reading old bytes breaks.
Full reproducer (writer pinned to 1.3.0, reader version switchable, payload file committed so you don't need to build against 1.3.0) attached
tmp-fory-repro.zip
Config, identical on writer and reader (Language.JAVA, not xlang; JDK 21):
Fory.builder()
.withLanguage(Language.JAVA)
.withCodegen(true)
.requireClassRegistration(true)
.withAsyncCompilation(false)
.serializeEnumByName(false)
.deserializeUnknownEnumValueAsNull(true)
.withCompatibleMode(CompatibleMode.COMPATIBLE)
.withDeserializeUnknownClass(false)
.withRefTracking(false)
.withRefCopy(false)
.withStringCompressed(false)
.withNumberCompressed(false)
Model:
public interface Code<T> { T value(); }
public abstract class CodeDecorator<T> implements Code<T> {
@ForyField(id = 0) private final Code<T> delegate;
...
}
public final class BasicCode implements Code<String> { ... } // registered, id 1000
public final class WrappedCode extends CodeDecorator<String> { ... } // registered, id 1001
CodeDecorator itself is not registered (it's abstract, never serialized as a root). 1.3.0 is fine with that on both ends. Serializing a WrappedCode on 1.3.0 and reading it on 1.4.0/1.5.0/1.6.0 gives:
org.apache.fory.exception.InsecureException: Class repro.model.CodeDecorator is not registered.
at org.apache.fory.resolver.TypeResolver.loadClass(TypeResolver.java:1451)
at org.apache.fory.resolver.ClassResolver.loadClassForMeta(ClassResolver.java:2228)
at org.apache.fory.meta.NativeTypeDefDecoder.decodeTypeDef(NativeTypeDefDecoder.java:186)
at org.apache.fory.meta.NativeTypeDefDecoder.decodeTypeDef(NativeTypeDefDecoder.java:106)
at org.apache.fory.meta.TypeDef.readTypeDef(TypeDef.java:351)
at org.apache.fory.resolver.TypeResolver.readSharedTypeDefInfo(TypeResolver.java:964)
at org.apache.fory.resolver.TypeResolver.readSharedClassTypeInfo(TypeResolver.java:950)
at org.apache.fory.resolver.TypeResolver.readTypeInfo(TypeResolver.java:827)
at org.apache.fory.context.ReadContext.readRootRef(ReadContext.java:628)
at org.apache.fory.Fory.deserialize(Fory.java:515)
Registering CodeDecorator on the reader (with an id the writer never had) makes 1.4.0+ read the old bytes correctly, so the registration check is resolving the class by name out of the encoded TypeDef. That works as a stopgap, but it means 1.4.0+ readers reject metadata that 1.3.0 legitimately produced under requireClassRegistration(true).
The break correlates with refTracking(false): the same corpus written with refTracking(true) + refCopy(true) reads fine on 1.4.0+. In a larger production corpus (~300 registered types, same config) we also see NPEs at TypeResolver.getMetaSharedTypeInfo (TypeResolver.java:1237), IllegalStateException: Serializer of class Unknown should be set in ClassResolver#getMetaSharedTypeInfo, and occasional MemoryBuffer bounds errors on 1.3.0 bytes — the reproducer isolates the registration-check variant, which is the dominant one.
Expected: a 1.4+ reader with COMPATIBLE mode and identical config/registrations should read 1.3.0 bytes.
Possibly related: #3794, #3833.
Repro steps:
gradle :writer:run # writes payloads with 1.3.0 (already committed)
gradle :reader:run -PforyVersion=1.3.0 # OK
gradle :reader:run -PforyVersion=1.6.0 # FAIL
gradle :reader:run -PforyVersion=1.6.0 -PregisterDecorator=true # OK (workaround)
Search before asking
Version
1.x.x
Component(s)
Java
Minimal reproduce step
Payloads written by fory-core 1.3.0 can't be read back by 1.4.0, 1.5.0, or 1.6.0 when the serialized object's class extends an abstract superclass that was never registered. 1.3.0 reads the same bytes fine, and 1.4.0+ round-trips with itself fine — only reading old bytes breaks.
Full reproducer (writer pinned to 1.3.0, reader version switchable, payload file committed so you don't need to build against 1.3.0) attached
tmp-fory-repro.zip
Config, identical on writer and reader (Language.JAVA, not xlang; JDK 21):
Model:
CodeDecoratoritself is not registered (it's abstract, never serialized as a root). 1.3.0 is fine with that on both ends. Serializing aWrappedCodeon 1.3.0 and reading it on 1.4.0/1.5.0/1.6.0 gives:Registering
CodeDecoratoron the reader (with an id the writer never had) makes 1.4.0+ read the old bytes correctly, so the registration check is resolving the class by name out of the encoded TypeDef. That works as a stopgap, but it means 1.4.0+ readers reject metadata that 1.3.0 legitimately produced under requireClassRegistration(true).The break correlates with refTracking(false): the same corpus written with refTracking(true) + refCopy(true) reads fine on 1.4.0+. In a larger production corpus (~300 registered types, same config) we also see NPEs at
TypeResolver.getMetaSharedTypeInfo(TypeResolver.java:1237),IllegalStateException: Serializer of class Unknown should be set in ClassResolver#getMetaSharedTypeInfo, and occasional MemoryBuffer bounds errors on 1.3.0 bytes — the reproducer isolates the registration-check variant, which is the dominant one.Expected: a 1.4+ reader with COMPATIBLE mode and identical config/registrations should read 1.3.0 bytes.
Possibly related: #3794, #3833.
Repro steps: