Split reflection-based JniTypeManager and JniValueManager behavior#1441
Split reflection-based JniTypeManager and JniValueManager behavior#1441simonrozsival wants to merge 23 commits into
Conversation
5ff4c17 to
6d72140
Compare
6d72140 to
58f0dbd
Compare
|
/azp run |
|
No pipelines are associated with this pull request. |
There was a problem hiding this comment.
Pull request overview
This draft PR refactors JniRuntime.JniTypeManager into an abstract base and moves the default reflection-based behavior into a new JniRuntime.DynamicJniTypeManager, with corresponding updates across tests, JRE runtime helpers, samples, and public API baselines.
Changes:
- Introduces
JniRuntime.DynamicJniTypeManagerand makesJniRuntime.JniTypeManagerabstract, shifting default/reflection-backed logic into the new derived type. - Updates test and JRE type managers to inherit from
DynamicJniTypeManager, and adjusts tests for new behaviors (e.g., generic invoker handling,GetTypearray behavior). - Updates trimmer/AOT annotations and PublicAPI baselines to reflect the split and new abstract members.
Show a summary per file
| File | Description |
|---|---|
| tests/Java.Interop-Tests/Java.Interop/JniTypeManagerTests.cs | Updates expectations around GetType behavior (notably array signatures and generic holder mapping). |
| tests/Java.Interop-Tests/Java.Interop/JniRuntimeTest.cs | Switches proxy manager to DynamicJniTypeManager and adds trim suppression for test-only reflection use. |
| tests/Java.Interop-Tests/Java.Interop/JniRuntime.JniTypeManagerTests.cs | Adds a generic invoker negative test and updates test manager base type. |
| tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.cs | Updates fixture type manager to DynamicJniTypeManager and refines type lookup with trimming annotations. |
| src/Java.Runtime.Environment/Java.Interop/JreTypeManager.cs | Moves to DynamicJniTypeManager and adds a DAM-annotated GetTypeForSimpleReference override. |
| src/Java.Interop/PublicAPI.Unshipped.txt | Records newly introduced/reshaped APIs (new type, newly-abstract members, overrides). |
| src/Java.Interop/PublicAPI.Shipped.txt | Updates shipped API surface to reflect newly-abstract members and removed methods from JniTypeManager. |
| src/Java.Interop/Java.Interop/JniValueMarshaler.cs | Simplifies expression-based marshaler instantiation and adjusts trimming annotations. |
| src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs | Switches peer-type selection to GetReflectionConstructibleTypes() and refactors uninitialized peer creation. |
| src/Java.Interop/Java.Interop/JniRuntime.JniTypeManager.cs | Makes JniTypeManager abstract and factors previously-inlined logic into abstract core methods. |
| src/Java.Interop/Java.Interop/JniRuntime.DynamicJniTypeManager.cs | Adds the new reflection-backed type manager implementation and related registration behavior. |
| src/Java.Interop/Java.Interop/JniRuntime.cs | Removes the default new JniTypeManager() fallback; requires an explicit type manager in creation options. |
| src/Java.Interop/Java.Interop/JavaPrimitiveArrays.tt | Retargets primitive array helper generation to DynamicJniTypeManager. |
| src/Java.Interop/Java.Interop/JavaPrimitiveArrays.cs | Updates the generated primitive array helper container type to DynamicJniTypeManager. |
| src/Java.Interop/GlobalSuppressions.cs | Adds CA1034 suppression for the new nested DynamicJniTypeManager type. |
| samples/Hello-NativeAOTFromJNI/NativeAotTypeManager.cs | Updates sample type manager implementation to new hierarchy and adds explicit native member registration. |
| samples/Hello-NativeAOTFromJNI/ManagedType.cs | Changes the native registration hook to internal for sample-driven registration. |
| samples/Hello-NativeAOTFromAndroid/NativeAotTypeManager.cs | Updates sample type manager implementation to new hierarchy and implements abstract members. |
Copilot's findings
- Files reviewed: 18/18 changed files
- Comments generated: 3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Map Java.Interop's internal proxy peer types in the base type manager so custom AOT-safe managers do not need reflection-based DynamicJniTypeManager behavior for JavaProxyThrowable/JavaProxyObject. Register built-in proxy native members by JNI type name before asking custom managers for a managed Type, avoiding DAM-annotated lookups of internal Exception/Delegate-derived types. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Let the base JniTypeManager resolve primitive JNI keyword signatures without requiring custom AOT-safe managers to duplicate the dynamic type manager's primitive mappings. Use that base lookup as a fallback when matching Java-to-managed constructor signatures so signatures such as (I)V resolve to System.Int32. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Rename DynamicJniTypeManager to ReflectionJniTypeManager so the type name describes the reflection-based behavior that is incompatible with Native AOT. Update the matching source file name, API baseline, JRE type manager inheritance, generated primitive-array partial, and tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
@copilot resolve the merge conflicts in this pull request |
…-aot-warnings-jni-type-manager # Conflicts: # src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>
|
/review |
|
✅ Java.Interop PR Reviewer completed successfully! |
There was a problem hiding this comment.
⚠️ Needs Changes
The architectural split of JniTypeManager → JniTypeManager (abstract) + ReflectionJniTypeManager and JniValueManager → JniValueManager (abstract) + ReflectionJniValueManager is well-structured. The approach of pushing reflection-based behavior into opt-in subclasses while keeping the abstract bases AOT-safe is sound. The built-in type signature/lookup helpers in the base class, the ReflectionConstructibleType wrapper for DAM annotation flow, and the KnownArrayTypes lookup table to avoid MakeArrayType/MakeGenericType calls are all good improvements.
Issues by severity
| Severity | Count | Summary |
|---|---|---|
| ❌ Error | 2 | Runtime crash in GetObjectArrayMarshaler; placeholder "TODO" in user-facing attributes |
| 1 | Indentation mismatch in CreateValueCore |
|
| 💡 Suggestion | 1 | Unused EmptyStringArray field |
Critical: GetObjectArrayMarshaler runtime crash
The lambda refactor at ReflectionJniValueManager.cs:481-486 replaced a named generic helper method with a non-generic lambda. Calling GetGenericMethodDefinition() on the resulting compiler-generated method will throw InvalidOperationException at runtime whenever a non-primitive IList<T> value is marshaled.
CI Status
Only license/cla and .github/dependabot.yml checks are present — no build/test CI checks appear to have run on this PR. The build issues mentioned in the PR description may explain this, but the GetObjectArrayMarshaler bug above would cause a runtime failure if tested.
Positive callouts
- Clean separation of concerns between AOT-safe base and reflection-based derived classes
- Good use of
[RequiresDynamicCode]/[RequiresUnreferencedCode]onReflectionJniTypeManager - The
KnownArrayTypesdictionary approach for avoidingMakeArrayType/MakeGenericTypein the type manager is a solid AOT-safe alternative - NativeAOT sample updates are thorough and demonstrate the intended usage pattern
- Public API baseline updates are comprehensive
Generated by Java.Interop PR Reviewer for issue #1441 · ● 9.5M
|
@copilot address code review |
…TypeManager Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>
Addressed all code review issues in commit
|
|
/review |
|
✅ Java.Interop PR Reviewer completed successfully! |
There was a problem hiding this comment.
🤖 Review Summary — ⚠️ Needs Minor Changes
Overview: This PR cleanly splits the reflection-backed behavior from JniTypeManager and JniValueManager into dedicated subclasses (ReflectionJniTypeManager, ReflectionJniValueManager), making the abstract bases NativeAOT-safe. The architecture is sound and the code movement is faithful to the original.
Issues by severity
| Severity | Count |
|---|---|
| 2 | |
| 💡 Suggestion | 2 |
Positive callouts
- Clean separation of concerns: abstract bases carry no reflection,
[RequiresDynamicCode]/[RequiresUnreferencedCode]correctly annotate reflection subclasses - NativeAOT sample managers properly implement the abstract methods without reflection
ReflectionConstructibleTypewrapper preserves[DynamicallyAccessedMembers]flow annotations correctly through the type hierarchyJreTypeManagercomposition pattern (inheritingReflectionJniTypeManagerand overriding specific methods) is well-designed- Public API baseline updates look complete and consistent
CI Note
Only the license/cla check is visible — no build/test results were found at review time. Please confirm CI is green before merging.
Generated by Java.Interop PR Reviewer for issue #1441 · ● 10.5M
|
@copilot address review comments |
…l-forgiving operator Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>
Addressed all review comments in commit
|
|
/review |
|
🚀 Java.Interop PR Reviewer has started processing this issue comment |
Draft PR to let CI validate the JniTypeManager/JniValueManager split and AOT warning work.
Summary:
Local validation:
Notes: