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]

Reply via email to