wakilurislam opened a new pull request, #3637:
URL: https://github.com/apache/fory/pull/3637
# PR Description
## Why?
When Fory serializes an unregistered class that has `writeReplace()`
returning a different type (e.g., a Hibernate/ByteBuddy proxy), the outer type
info uses `NAMED_EXT` which writes the **proxy class name** to the byte stream.
On a different JVM where that proxy class doesn't exist, deserialization fails
with `ClassNotFoundException` before `ReplaceResolveSerializer` can handle the
replacement.
This affects any framework using generated proxies with `writeReplace()`:
Hibernate (ByteBuddy lazy-load proxies), Spring AOP, and custom proxy
frameworks relying on serialization transparency.
## What does this PR do?
Changes `ClassResolver.buildUnregisteredTypeId()` to return
`REPLACE_STUB_ID` instead of `Types.NAMED_EXT` for classes detected as
writeReplace candidates. This writes a compact 1-byte internal type ID (no
class name bytes), matching the existing pattern used for lambdas
(`LAMBDA_STUB_ID`) and JDK proxies (`JDK_PROXY_STUB_ID`).
### Changes
**`ClassResolver.java`** (2 changes):
1. `buildUnregisteredTypeId()` — Return `REPLACE_STUB_ID` when the
serializer is a `ReplaceResolveSerializer` or
`useReplaceResolveSerializer(cls)` returns true:
```diff
- if (serializer == null && !cls.isEnum() &&
useReplaceResolveSerializer(cls)) {
- return Types.NAMED_EXT;
+ if (!cls.isEnum()
+ && (serializer instanceof ReplaceResolveSerializer ||
useReplaceResolveSerializer(cls))) {
+ return REPLACE_STUB_ID;
```
2. `addSerializer()` — Guard against overwriting the pre-registered
`typeIdToTypeInfo[REPLACE_STUB_ID]` entry:
```diff
+ if (typeId == REPLACE_STUB_ID) {
+ classInfoMap.put(type, typeInfo);
+ } else {
+ updateTypeInfo(type, typeInfo);
+ }
```
**`WriteReplaceCrossJvmTest.java`** (new file):
- 6 test methods × 4 configurations = 24 tests
- Cross-JVM dynamic proxy, same-JVM regression, same-type replace,
round-trip, nested proxy in DTO
## Related issues
- Fixes #3635
## AI Contribution Checklist
- [x] Substantial AI assistance was used in this PR: `yes`
- [x] If `yes`, I included a completed [AI Contribution
Checklist](https://github.com/apache/fory/blob/main/AI_POLICY.md#9-contributor-checklist-for-ai-assisted-prs)
in this PR description and the required `AI Usage Disclosure`.
- [x] If `yes`, my PR description includes the required `ai_review` summary
and screenshot evidence of the final clean AI review results from both fresh
reviewers on the current PR diff or current HEAD after the latest code changes.
### Full AI Contribution Checklist
- [x] Substantial AI assistance was used in this PR: `yes`
- [x] If `yes`, I included the standardized `AI Usage Disclosure` block
below.
- [x] If `yes`, I can explain and defend all important changes without AI
help.
- [x] If `yes`, I reviewed AI-assisted code changes line by line before
submission.
- [x] If `yes`, I completed line-by-line self-review first and fixed issues
before requesting AI review.
- [x] If `yes`, I ran two fresh AI review agents on the current PR diff or
current HEAD after the latest code changes: one using
`.claude/skills/fory-code-review/SKILL.md` and one without that skill.
- [x] If `yes`, I addressed all AI review comments and repeated the review
loop until both ai reviewers reported no further actionable comments.
- [x] If `yes`, I attached the final clean AI review results from both fresh
reviewers on the current PR diff or current HEAD after the latest code changes
in this PR body.
- [x] If `yes`, I ran adequate human verification and recorded evidence
(checks run locally or in CI, pass/fail summary, and confirmation I reviewed
results).
- [x] If `yes`, I added/updated tests and specs where required.
- [x] If `yes`, I validated protocol/performance impacts with evidence when
applicable.
- [x] If `yes`, I verified licensing and provenance compliance.
```text
AI Usage Disclosure
- substantial_ai_assistance: yes
- scope: code drafting, tests, design analysis
- affected_files_or_subsystems: java/fory-core ClassResolver.java
(serializer type ID resolution), WriteReplaceCrossJvmTest.java (new test)
- ai_review: line-by-line self-review completed; ran two fresh AI reviewers
on current HEAD — Reviewer 1 (with fory-code-review skill) found 0 blocking
issues, 2 minor suggestions (wire-format compat note, test rename). Reviewer 2
(without skill) found 0 actionable issues. Both concluded with "no further
actionable comments".
- ai_review_artifacts: (attach screenshots of review_1_with_skill.md and
review_2_without_skill.md final results)
- human_verification: ran locally with JDK 8 — `mvn clean test -pl fory-core
-Dtest=WriteReplaceCrossJvmTest,ReplaceResolveSerializerTest,FinalFieldReplaceResolveSerializerTest`
— 82 tests run, 0 failures, 0 errors. Verified test fails without fix (4
failures) and passes with fix (24/24).
- performance_verification: N/A — no hot-path changes; only affects the
one-time type-ID resolution for unregistered writeReplace classes, not
per-element serialization
- provenance_license_confirmation: Apache-2.0-compatible provenance
confirmed; no incompatible third-party code introduced. All code is original
work addressing the identified bug.
```
## Does this PR introduce any user-facing change?
- [ ] Does this PR introduce any public API change?
- [ ] Does this PR introduce any binary protocol compatibility change?
No public API changes. The wire format changes only for unregistered
writeReplace classes: the outer type ID byte changes from `NAMED_EXT` (+ class
name bytes) to `REPLACE_STUB_ID` (1 byte, no class name). This is a **bug fix**
— the previous format was broken for cross-JVM scenarios. Bytes serialized
before this fix with same-JVM writeReplace classes will still work (the read
path handles both formats).
## Benchmark
N/A — This change only affects the one-time `buildUnregisteredTypeId()` call
during first serialization of a writeReplace class. No per-element hot-path
impact.
[review_1_with_skill.md](https://github.com/user-attachments/files/27200400/review_1_with_skill.md)
[review_2_without_skill.md](https://github.com/user-attachments/files/27200402/review_2_without_skill.md)
--
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]