Skip to content

Commit 4ab7633

Browse files
committed
[Java.Interop] Type & Member Remapping Support
Context: #867 Type fallback: done. InTune support: not done.
1 parent d3f0c5c commit 4ab7633

File tree

12 files changed

+421
-72
lines changed

12 files changed

+421
-72
lines changed

src/Java.Interop/Java.Interop.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
<OutputPath>$(ToolOutputFullPath)</OutputPath>
2727
<DocumentationFile>$(ToolOutputFullPath)Java.Interop.xml</DocumentationFile>
2828
<JNIEnvGenPath>$(BuildToolOutputFullPath)</JNIEnvGenPath>
29-
<LangVersion>8.0</LangVersion>
29+
<LangVersion Condition=" '$(JIBuildingForNetCoreApp)' == 'True' ">9.0</LangVersion>
30+
<LangVersion Condition=" '$(LangVersion)' == '' ">8.0</LangVersion>
3031
<Nullable>enable</Nullable>
3132
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
3233
<MSBuildWarningsAsMessages>NU1702</MSBuildWarningsAsMessages>

src/Java.Interop/Java.Interop/JavaArray.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,9 +231,9 @@ bool IList.IsFixedSize {
231231

232232
object? IList.this [int index] {
233233
get {return this [index];}
234-
#pragma warning disable 8601
234+
#pragma warning disable 8600,8601
235235
set {this [index] = (T) value;}
236-
#pragma warning restore 8601
236+
#pragma warning restore 8600,8601
237237
}
238238

239239
void ICollection.CopyTo (Array array, int index)

src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,59 @@ internal JniInstanceMethods GetConstructorsForType (Type declaringType)
8484
public JniMethodInfo GetMethodInfo (string encodedMember)
8585
{
8686
lock (InstanceMethods) {
87-
if (!InstanceMethods.TryGetValue (encodedMember, out var m)) {
88-
string method, signature;
89-
JniPeerMembers.GetNameAndSignature (encodedMember, out method, out signature);
90-
m = JniPeerType.GetInstanceMethod (method, signature);
91-
InstanceMethods.Add (encodedMember, m);
87+
if (InstanceMethods.TryGetValue (encodedMember, out var m)) {
88+
return m;
9289
}
90+
}
91+
string method, signature;
92+
JniPeerMembers.GetNameAndSignature (encodedMember, out method, out signature);
93+
var info = GetMethodInfo (method, signature);
94+
lock (InstanceMethods) {
95+
if (InstanceMethods.TryGetValue (encodedMember, out var m)) {
96+
return m;
97+
}
98+
InstanceMethods.Add (encodedMember, info);
99+
}
100+
return info;
101+
}
102+
103+
JniMethodInfo GetMethodInfo (string method, string signature)
104+
{
105+
#if NET
106+
if (JniPeerType.TryGetInstanceMethod (method, signature, out var m)) {
93107
return m;
94108
}
109+
var fallbackTypes = JniEnvironment.Runtime.TypeManager.GetFallbackTypes (Members.JniPeerTypeName);
110+
if (fallbackTypes != null) {
111+
foreach (var ft in fallbackTypes) {
112+
using var t = new JniType (ft);
113+
if (t.TryGetInstanceMethod (method, signature, out m)) {
114+
return m;
115+
}
116+
}
117+
}
118+
#endif // NET
119+
return JniPeerType.GetInstanceMethod (method, signature);
120+
}
121+
122+
123+
JniMethodInfo GetMethodInfoLocked (string method, string signature)
124+
{
125+
#if NET
126+
if (Members.JniPeerType.TryGetStaticMethod (method, signature, out var m)) {
127+
return m;
128+
}
129+
var fallbackTypes = JniEnvironment.Runtime.TypeManager.GetFallbackTypes (Members.JniPeerTypeName);
130+
if (fallbackTypes != null) {
131+
foreach (var ft in fallbackTypes) {
132+
using var t = new JniType (ft);
133+
if (t.TryGetStaticMethod (method, signature, out m)) {
134+
return m;
135+
}
136+
}
137+
}
138+
#endif // NET
139+
return Members.JniPeerType.GetStaticMethod (method, signature);
95140
}
96141

97142
public unsafe JniObjectReference StartCreateInstance (string constructorSignature, Type declaringType, JniArgumentValue* parameters)

src/Java.Interop/Java.Interop/JniPeerMembers.JniStaticMethods.cs

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,39 @@ internal void Dispose ()
2525
public JniMethodInfo GetMethodInfo (string encodedMember)
2626
{
2727
lock (StaticMethods) {
28-
if (!StaticMethods.TryGetValue (encodedMember, out var m)) {
29-
string method, signature;
30-
JniPeerMembers.GetNameAndSignature (encodedMember, out method, out signature);
31-
m = Members.JniPeerType.GetStaticMethod (method, signature);
32-
StaticMethods.Add (encodedMember, m);
28+
if (StaticMethods.TryGetValue (encodedMember, out var m)) {
29+
return m;
3330
}
31+
}
32+
string method, signature;
33+
JniPeerMembers.GetNameAndSignature (encodedMember, out method, out signature);
34+
var info = GetMethodInfo (method, signature);
35+
lock (StaticMethods) {
36+
if (StaticMethods.TryGetValue (encodedMember, out var m)) {
37+
return m;
38+
}
39+
StaticMethods.Add (encodedMember, info);
40+
}
41+
return info;
42+
}
43+
44+
JniMethodInfo GetMethodInfo (string method, string signature)
45+
{
46+
#if NET
47+
if (Members.JniPeerType.TryGetStaticMethod (method, signature, out var m)) {
3448
return m;
3549
}
50+
var fallbackTypes = JniEnvironment.Runtime.TypeManager.GetFallbackTypes (Members.JniPeerTypeName);
51+
if (fallbackTypes != null) {
52+
foreach (var ft in fallbackTypes) {
53+
using var t = new JniType (ft);
54+
if (t.TryGetStaticMethod (method, signature, out m)) {
55+
return m;
56+
}
57+
}
58+
}
59+
#endif // NET
60+
return Members.JniPeerType.GetStaticMethod (method, signature);
3661
}
3762

3863
public unsafe void InvokeVoidMethod (string encodedMember, JniArgumentValue* parameters)

src/Java.Interop/Java.Interop/JniRuntime.JniTypeManager.cs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,75 @@
66
using System.Linq;
77
using System.Reflection;
88
using System.Runtime.CompilerServices;
9+
using System.Runtime.Versioning;
910
using System.Threading;
1011

1112
namespace Java.Interop {
1213

14+
#if NET
15+
[RequiresPreviewFeatures]
16+
public struct ReplacementMethodInfo : IEquatable<ReplacementMethodInfo>
17+
{
18+
public string? JniSourceType {get; set;}
19+
public string? SourceJniMethodName {get; set;}
20+
public string? SourceJniMethodSignature {get; set;}
21+
public string? JniTargetType {get; set;}
22+
public string? TargetJniMethodName {get; set;}
23+
public string? TargetJniMethodSignature {get; set;}
24+
public int? TargetJniMethodParameterCount {get; set;}
25+
public bool TargetJniMethodIsStatic {get; set;}
26+
27+
public override bool Equals (object? obj)
28+
{
29+
if (obj is ReplacementMethodInfo o) {
30+
return Equals (o);
31+
}
32+
return false;
33+
}
34+
35+
public bool Equals (ReplacementMethodInfo other)
36+
{
37+
return string.Equals (JniSourceType, other.JniSourceType) &&
38+
string.Equals (SourceJniMethodName, other.SourceJniMethodName) &&
39+
string.Equals (SourceJniMethodSignature, other.SourceJniMethodSignature) &&
40+
string.Equals (JniTargetType, other.JniTargetType) &&
41+
string.Equals (TargetJniMethodName, other.TargetJniMethodName) &&
42+
string.Equals (TargetJniMethodSignature, other.TargetJniMethodSignature) &&
43+
TargetJniMethodParameterCount == other.TargetJniMethodParameterCount &&
44+
TargetJniMethodIsStatic == other.TargetJniMethodIsStatic;
45+
}
46+
47+
public override int GetHashCode ()
48+
{
49+
return (JniSourceType?.GetHashCode () ?? 0) ^
50+
(SourceJniMethodName?.GetHashCode () ?? 0) ^
51+
(SourceJniMethodSignature?.GetHashCode () ?? 0) ^
52+
(JniTargetType?.GetHashCode () ?? 0) ^
53+
(TargetJniMethodName?.GetHashCode () ?? 0) ^
54+
(TargetJniMethodSignature?.GetHashCode () ?? 0) ^
55+
(TargetJniMethodParameterCount?.GetHashCode () ?? 0) ^
56+
TargetJniMethodIsStatic.GetHashCode ();
57+
}
58+
59+
public override string ToString ()
60+
{
61+
return $"{nameof (ReplacementMethodInfo)} {{ " +
62+
$"JniSourceType = \"{JniSourceType}\"" +
63+
$", SourceJniMethodName = \"{SourceJniMethodName}\"" +
64+
$", SourceJniMethodSignature = \"{SourceJniMethodSignature}\"" +
65+
$", JniTargetType = \"{JniTargetType}\"" +
66+
$", TargetJniMethodName = \"{TargetJniMethodName}\"" +
67+
$", TargetJniMethodSignature = \"{TargetJniMethodSignature}\"" +
68+
$", TargetJniMethodParameterCount = {TargetJniMethodParameterCount?.ToString () ?? "null"}" +
69+
$", TargetJniMethodIsStatic = {TargetJniMethodIsStatic}" +
70+
$"}}";
71+
}
72+
73+
public static bool operator==(ReplacementMethodInfo a, ReplacementMethodInfo b) => a.Equals (b);
74+
public static bool operator!=(ReplacementMethodInfo a, ReplacementMethodInfo b) => !a.Equals (b);
75+
}
76+
#endif // NET
77+
1378
public partial class JniRuntime {
1479

1580
public class JniTypeManager : IDisposable, ISetRuntime {
@@ -251,6 +316,14 @@ IEnumerable<Type> CreateGetTypesForSimpleReferenceEnumerator (string jniSimpleRe
251316
yield break;
252317
}
253318

319+
#if NET
320+
[RequiresPreviewFeatures]
321+
internal protected virtual string[]? GetFallbackTypes (string jniSimpleReference) => null;
322+
// public virtual string? GetReplacementType (string jniTypeSimpleReference) => null;
323+
[RequiresPreviewFeatures]
324+
internal protected virtual ReplacementMethodInfo? GetReplacementMethodInfo (string jniSourceType, string jniMethodName, string jniMethodSignature) => null;
325+
#endif // NET
326+
254327
public virtual void RegisterNativeMembers (JniType nativeClass, Type type, string? methods)
255328
{
256329
TryRegisterNativeMembers (nativeClass, type, methods);

src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -402,9 +402,9 @@ public T CreateValue<T> (ref JniObjectReference reference, JniObjectReferenceOpt
402402
targetType = targetType ?? typeof (T);
403403

404404
if (typeof (IJavaPeerable).IsAssignableFrom (targetType)) {
405-
#pragma warning disable CS8601 // Possible null reference assignment.
405+
#pragma warning disable CS8600,CS8601 // Possible null reference assignment.
406406
return (T) JavaPeerableValueMarshaler.Instance.CreateGenericValue (ref reference, options, targetType);
407-
#pragma warning restore CS8601 // Possible null reference assignment.
407+
#pragma warning restore CS8600,CS8601 // Possible null reference assignment.
408408
}
409409

410410
var marshaler = GetValueMarshaler<T> ();
@@ -481,9 +481,9 @@ public T GetValue<T> (ref JniObjectReference reference, JniObjectReferenceOption
481481
}
482482

483483
if (typeof (IJavaPeerable).IsAssignableFrom (targetType)) {
484-
#pragma warning disable CS8601 // Possible null reference assignment.
484+
#pragma warning disable CS8600,CS8601 // Possible null reference assignment.
485485
return (T) JavaPeerableValueMarshaler.Instance.CreateGenericValue (ref reference, options, targetType);
486-
#pragma warning restore CS8601 // Possible null reference assignment.
486+
#pragma warning restore CS8600,CS8601 // Possible null reference assignment.
487487
}
488488

489489
var marshaler = GetValueMarshaler<T> ();

src/Java.Interop/Java.Interop/JniType.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,28 @@ public JniMethodInfo GetInstanceMethod (string name, string signature)
236236
return JniEnvironment.InstanceMethods.GetMethodID (PeerReference, name, signature);
237237
}
238238

239+
#if NET
240+
internal bool TryGetInstanceMethod (string name, string signature, [NotNullWhen(true)] out JniMethodInfo? method)
241+
{
242+
AssertValid ();
243+
244+
IntPtr thrown;
245+
method = null;
246+
var id = NativeMethods.java_interop_jnienv_get_method_id (JniEnvironment.EnvironmentPointer, out thrown, PeerReference.Handle, name, signature);
247+
if (thrown != IntPtr.Zero) {
248+
JniEnvironment.Exceptions.ExceptionClear ();
249+
NativeMethods.java_interop_jnienv_delete_local_ref (JniEnvironment.EnvironmentPointer, thrown);
250+
return false;
251+
}
252+
if (id == IntPtr.Zero) {
253+
// …huh? Should only happen if `thrown != IntPtr.Zero`, handled above.
254+
return false;
255+
}
256+
method = new JniMethodInfo (name, signature, id, isStatic: false);
257+
return true;
258+
}
259+
#endif // NET
260+
239261
public JniMethodInfo GetCachedInstanceMethod ([NotNull] ref JniMethodInfo? cachedMethod, string name, string signature)
240262
{
241263
AssertValid ();
@@ -256,6 +278,28 @@ public JniMethodInfo GetStaticMethod (string name, string signature)
256278
return JniEnvironment.StaticMethods.GetStaticMethodID (PeerReference, name, signature);
257279
}
258280

281+
#if NET
282+
internal bool TryGetStaticMethod (string name, string signature, [NotNullWhen(true)] out JniMethodInfo? method)
283+
{
284+
AssertValid ();
285+
286+
IntPtr thrown;
287+
method = null;
288+
var id = NativeMethods.java_interop_jnienv_get_static_method_id (JniEnvironment.EnvironmentPointer, out thrown, PeerReference.Handle, name, signature);
289+
if (thrown != IntPtr.Zero) {
290+
JniEnvironment.Exceptions.ExceptionClear ();
291+
NativeMethods.java_interop_jnienv_delete_local_ref (JniEnvironment.EnvironmentPointer, thrown);
292+
return false;
293+
}
294+
if (id == IntPtr.Zero) {
295+
// …huh? Should only happen if `thrown != IntPtr.Zero`, handled above.
296+
return false;
297+
}
298+
method = new JniMethodInfo (name, signature, id, isStatic: true);
299+
return true;
300+
}
301+
#endif // NET
302+
259303
public JniMethodInfo GetCachedStaticMethod ([NotNull] ref JniMethodInfo? cachedMethod, string name, string signature)
260304
{
261305
AssertValid ();

tests/Java.Interop-Tests/Java.Interop-Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<TargetFrameworks>net472;net6.0</TargetFrameworks>
55
<IsPackable>false</IsPackable>
66
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
7+
<LangVersion>8.0</LangVersion>
78
</PropertyGroup>
89

910
<PropertyGroup>
Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#nullable enable
12
using System;
23
using System.Collections.Generic;
34
using System.IO;
@@ -10,20 +11,50 @@ namespace Java.InteropTests {
1011

1112
partial class JavaVMFixture {
1213

14+
internal static TestJVM? VM;
15+
internal static JavaVMFixtureTypeManager? TypeManager;
16+
1317
static partial void CreateJavaVM ()
1418
{
15-
var c = new TestJVM (
16-
jars: new[]{ "interop-test.jar" },
17-
typeMappings: new Dictionary<string, Type> () {
19+
var o = new TestJVMOptions {
20+
JarFilePaths = {
21+
"interop-test.jar",
22+
},
23+
TypeManager = new JavaVMFixtureTypeManager (),
24+
};
25+
VM = new TestJVM (o);
26+
TypeManager = (JavaVMFixtureTypeManager) VM.TypeManager;
27+
JniRuntime.SetCurrent (VM);
28+
}
29+
}
30+
31+
class JavaVMFixtureTypeManager : TestJvmTypeManager {
32+
public JavaVMFixtureTypeManager ()
33+
: base (CreateDefaultTypeMappings ())
34+
{
35+
}
36+
37+
static Dictionary<string, Type> CreateDefaultTypeMappings ()
38+
{
39+
return new Dictionary<string, Type> () {
1840
#if !NO_MARSHAL_MEMBER_BUILDER_SUPPORT
19-
{ TestType.JniTypeName, typeof (TestType) },
41+
[TestType.JniTypeName] = typeof (TestType),
2042
#endif // !NO_MARSHAL_MEMBER_BUILDER_SUPPORT
21-
{ GenericHolder<int>.JniTypeName, typeof (GenericHolder<>) },
22-
}
23-
);
24-
JniRuntime.SetCurrent (c);
43+
[GenericHolder<int>.JniTypeName] = typeof (GenericHolder<>),
44+
};
2545
}
2646

47+
#if NET
48+
public string? RequestedFallbackTypesForSimpleReference;
49+
protected override string[]? GetFallbackTypes (string jniSimpleReference)
50+
{
51+
RequestedFallbackTypesForSimpleReference = jniSimpleReference;
52+
Debug.WriteLine ($"# GetFallbackTypes (jniSimpleReference={jniSimpleReference})");
53+
return null;
54+
}
55+
// public virtual string? GetReplacementType (string jniTypeSimpleReference) => null;
56+
// internal protected virtual ReplacementMethodInfo? GetReplacementMethodInfo (string jniSourceType, string jniMethodName, string jniMethodSignature) => null;
57+
#endif // NET
2758
}
2859
}
2960

0 commit comments

Comments
 (0)