sjahedhussini opened a new pull request, #3797:
URL: https://github.com/apache/fory/pull/3797

   <!--
   **Thanks for contributing to Apache Fory™.**
   
   **If this is your first time opening a PR on fory, you can refer to 
[CONTRIBUTING.md](https://github.com/apache/fory/blob/main/CONTRIBUTING.md).**
   
   Contribution Checklist
   
       - The **Apache Fory™** community has requirements on the naming of pr 
titles. You can also find instructions in 
[CONTRIBUTING.md](https://github.com/apache/fory/blob/main/CONTRIBUTING.md).
   
       - Apache Fory™ has a strong focus on performance. If the PR you submit 
will have an impact on performance, please benchmark it first and provide the 
benchmark result here.
   -->
   
   ## Why?
   
   `Fory.copy(obj)` throws `UnsupportedOperationException: Class 
java.lang.Package
   doesn't support serialization` (wrapped in `CopyException`) when the object 
graph
   contains a non-`Serializable` JDK class, even though the same object 
round-trips
   fine through `serialize` + `deserialize`. This makes deep-copying common
   real-world object graphs (e.g. Hibernate objects) fail.
   
   ## What does this PR do?
   
   Root cause: `ClassResolver.getSerializerClass` rejects non-`Serializable` JDK
   classes via the `checkJdkClassSerializable` guard. The check is correct for
   serialization, but because copy and serialize share the same per-class 
serializer
   created in `createSerializer`, the guard fired at serializer-creation time 
and
   broke `copy()` as collateral damage.
   
   Fix: route these classes to a new `NonSerializableSerializer`. Its 
`write`/`read`
   still throw `UnsupportedOperationException` (binary serialization behavior is
   unchanged — the failure is simply deferred to write time), but it inherits 
the
   field-copy implementation from `AbstractObjectSerializer`, so `Fory.copy()` 
now
   works. Transient fields are still copied (e.g. `HashMap`'s `size`/`table`), 
since
   the inherited copy path copies all non-static fields.
   
   `NonSerializableSerializer` is kept deliberately distinct from
   `CopyOnlyObjectSerializer`: the latter blocks serialization for
   registration-security reasons (remediable by registering the class), whereas 
a
   non-`Serializable` JDK class is intrinsically non-serializable and not 
remediable
   by registration, so the failure semantics differ. The new serializer is also
   registered in `GraalvmSupport`'s default serializer set, consistent with 
every
   other class returned by `getSerializerClass`.
   
   Files changed:
   - `resolver/ClassResolver.java` — route non-`Serializable` JDK classes to 
the new serializer instead of throwing.
   - `serializer/NonSerializableSerializer.java` — new serializer (copy 
supported, serialize unsupported).
   - `platform/GraalvmSupport.java` — register the new serializer for 
native-image builds.
   - `test/ForyCopyTest.java` — tests.
   
   Behavior note: serialization of these classes now surfaces as
   `SerializationException` wrapping `UnsupportedOperationException`, rather 
than the
   raw `UnsupportedOperationException` thrown eagerly at serializer creation.
   
   
   ## Related issues
   
   Fixes issue #2941.
   
   ## AI Contribution Checklist
   
   - [x] Substantial AI assistance was used in this PR: `yes`
   - [x] If `yes`, I included a completed AI Contribution Checklist in this PR 
description and the required `AI Usage Disclosure`.
   - [x] If `yes`, my PR description includes the `ai_review` summary and 
screenshot evidence/links from both fresh reviewers on the current diff.
   
   - [x] Substantial AI assistance was used: `yes`
   - [x] I can explain and defend all important changes without AI help.
   - [x] I reviewed AI-assisted code changes line by line before submission.
   - [x] I completed line-by-line self-review first and fixed issues before 
requesting AI review.
   - [x] I ran two fresh AI review agents on the current diff: one using 
`.claude/skills/fory-code-review/SKILL.md` and one without.
   - [x] I addressed all AI review comments and repeated the loop until both 
reviewers reported no further actionable comments.
   - [x] I attached evidence of the final clean AI review from both reviewers 
below.
   - [x] I ran human verification and recorded evidence below.
   - [x] I added/updated tests where required.
   - [x] N/A — no protocol/wire-format change; no separate performance evidence 
required (see below).
   - [x] I verified licensing and provenance compliance.
   
   
   \```
   AI Usage Disclosure
   - substantial_ai_assistance: yes
   - scope: design drafting, code drafting, tests, PR rationale
   - affected_files_or_subsystems: java/fory-core — 
resolver/ClassResolver.java, serializer/NonSerializableSerializer.java (new), 
platform/GraalvmSupport.java, test/ForyCopyTest.java
   - ai_review: Completed line-by-line self-review and fixed issues first. Ran 
two fresh reviewers on the final diff — one using 
.claude/skills/fory-code-review/SKILL.md, one without. Addressed all actionable 
comments (duplicate-serializer justification, removal of issue/history 
references in comments, GraalVM registration, test assertion strength, typos) 
and reran both until neither reported further actionable comments.
   - ai_review_artifacts:  Attached are the result of AI Agents. The claude 
command for independent agent is: 
   Do a thorough, independent code review of the changes on my current branch
   versus main: `git diff main...fix-issue-2941`. Review every changed line for
   correctness, edge cases, performance, maintainability, test quality, and 
style.
   Do NOT use any project-specific review skill — I want a fresh general review.
   List concrete actionable issues.
   The claude command for SKILL based agent is: 
   Review the changes on my current branch versus main using the guidance in
   .claude/skills/fory-code-review/SKILL.md. Diff: `git diff 
main...fix-issue-2941`.
   Go line by line and list any actionable issues.
   
   <img width="1859" height="304" alt="Screenshot from 2026-06-28 02-06-37" 
src="https://github.com/user-attachments/assets/65d5b72d-ccce-4690-98fa-16da2173e08c";
 />
   <img width="1877" height="148" alt="Screenshot from 2026-06-28 01-58-47" 
src="https://github.com/user-attachments/assets/b5703716-eb0b-4ed1-856e-d1cab00f1d87";
 />
   
   - human_verification: cd java && mvn -pl fory-core test 
-Dtest=org.apache.fory.ForyCopyTest — pass. cd java && mvn -pl fory-core test — 
pass. Local spotless:check could not run due to a google-java-format/JDK 
incompatibility (JCAnyPattern NoClassDefFoundError) affecting files unrelated 
to this change; relying on project CI for the format gate. Reviewed all results.
   - performance_verification: N/A — change only redirects serializer 
resolution for non-Serializable JDK classes that previously threw; existing hot 
paths unchanged.
   - provenance_license_confirmation: Apache-2.0-compatible provenance 
confirmed; no incompatible third-party code introduced. New file carries the 
standard ASF license header.
   \```
   
   ## Does this PR introduce any user-facing change?
   
   <!--
   If any user-facing interface changes, please [open an 
issue](https://github.com/apache/fory/issues/new/choose) describing the need to 
do so and update the document if necessary.
   
   Delete section if not applicable.
   -->
   
   - [x] No public API change. `Fory.copy()` now succeeds where it previously 
threw; no signature or contract change.
   - [x] No binary protocol compatibility change. Serialization of these 
classes is still refused (now at write time).
   
   
   ## Benchmark
   
   N/A — see performance_verification above.
   


-- 
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