Skip to content

Commit e3481bc

Browse files
committed
[Java.Interop] JniPeerMembers shouldn't require that Java types exist.
Java.Interop is intended to be used with Xamarin.Android, which binds the Android Java APIs. An artifact of this is that Android has "API levels", in which new types and members will be added to successive versions of Android. It is desirable (required) to be able to use a binding for API Y on a device running API X, X < Y. (For example, use a binding for API-23 on a device running API-10.) This in turn requires the ability to instantiate JniPeerMembers instances for types that may not exist: var members = new JniPeerMembers ("android/app/Fragment", typeof (Fragment)); android.app.Fragment was added in API-11, so if the above statement is executed on an API-10 device, IT MUST NOT THROW [0]. (Why? Because JniPeerMembers will be invoked from a static constructor, and there have been instances where new base classes were introduced, e.g. in API-8 android.view.MotionEvent inherited from java.lang.Object, while in API-9 MotionEvent inherited from the new android.view.InputEvent type. Thus, when using an API-10+ binding on an API-8 device, the InputEvent static constructor *will* execute, even though the InputEvent type *doesn't exist*.) Fix JniPeerMembers so that it doesn't instantiate the JniType unless it actually needs to. If no other JniPeerMembers members are used, then the JniType won't be created, and no runtime error will occur. [0] 1) Test Error : Java.InteropTests.JniPeerMembersTests.Ctor_CanReferenceNonexistentType Java.Interop.JavaException : __this__/__type__/__had__/__better__/__not__/__Exist__ ----> Java.Interop.JavaException : __this__.__type__.__had__.__better__.__not__.__Exist__ at Java.Interop.JniEnvironment+Types.FindClass (System.String classname) [0x00049] in .../Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.g.cs:3231 at Java.Interop.JniType..ctor (System.String classname) [0x00008] in .../Java.Interop/src/Java.Interop/Java.Interop/JniType.cs:31 at Java.Interop.JniType.GetCachedJniType (Java.Interop.JniType& cachedType, System.String classname) [0x0002f] in .../Java.Interop/src/Java.Interop/Java.Interop/JniType.cs:92 at Java.Interop.JniPeerMembers.get_JniPeerType () [0x0000d] in .../Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.cs:75 at Java.Interop.JniPeerMembers+JniInstanceMethods..ctor (Java.Interop.JniPeerMembers members) [0x0002b] in .../Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs:12 at Java.Interop.JniPeerMembers..ctor (System.String jniPeerType, System.Type managedPeerType, Boolean checkManagedPeerType) [0x000c1] in .../Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.cs:53 at Java.Interop.JniPeerMembers..ctor (System.String jniPeerType, System.Type managedPeerType) [0x00000] in .../Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.cs:10 at Java.InteropTests.JniPeerMembersTests.Ctor_CanReferenceNonexistentType () [0x00010] in .../Java.Interop/src/Java.Interop/Tests/Java.Interop/JniPeerMembersTests.cs:15 at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&) at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00054] in /private/tmp/source-mono-mac-4.0.0-branch-c5sr5/bockbuild-mono-4.0.0-branch/profiles/mono-mac-xamarin/build-root/mono-4.0.5/mcs/class/corlib/System.Reflection/MonoMethod.cs:230 --- End of managed Java.Interop.JavaException stack trace --- java.lang.NoClassDefFoundError: __this__/__type__/__had__/__better__/__not__/__Exist__ Caused by: java.lang.ClassNotFoundException: __this__.__type__.__had__.__better__.__not__.__Exist__ at java.net.URLClassLoader$1.run(URLClassLoader.java:202) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:190) at java.lang.ClassLoader.loadClass(ClassLoader.java:306) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301) at java.lang.ClassLoader.loadClass(ClassLoader.java:247) --JavaException --- End of managed Java.Interop.JavaException stack trace --- java.lang.ClassNotFoundException: __this__.__type__.__had__.__better__.__not__.__Exist__ at java.net.URLClassLoader$1.run(URLClassLoader.java:202) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:190) at java.lang.ClassLoader.loadClass(ClassLoader.java:306) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301) at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
1 parent e6468d2 commit e3481bc

File tree

4 files changed

+36
-7
lines changed

4 files changed

+36
-7
lines changed

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

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ public sealed partial class JniInstanceMethods
99
internal JniInstanceMethods (JniPeerMembers members)
1010
{
1111
DeclaringType = members.ManagedPeerType;
12-
JniPeerType = members.JniPeerType;
12+
Members = members;
1313
}
1414

1515
JniInstanceMethods (Type declaringType)
@@ -22,11 +22,16 @@ internal JniInstanceMethods (JniPeerMembers members)
2222
declaringType.FullName));
2323

2424
DeclaringType = declaringType;
25-
JniPeerType = new JniType (info.Name);
26-
JniPeerType.RegisterWithRuntime ();
25+
jniPeerType = new JniType (info.Name);
26+
jniPeerType.RegisterWithRuntime ();
2727
}
2828

29-
internal JniType JniPeerType;
29+
JniPeerMembers Members;
30+
JniType jniPeerType;
31+
32+
internal JniType JniPeerType {
33+
get {return jniPeerType ?? Members.JniPeerType;}
34+
}
3035

3136
readonly Type DeclaringType;
3237

@@ -35,7 +40,7 @@ internal JniInstanceMethods (JniPeerMembers members)
3540

3641
internal void Dispose ()
3742
{
38-
if (JniPeerType == null)
43+
if (InstanceMethods == null)
3944
return;
4045

4146
// Don't dispose JniPeerType; it's shared with others.
@@ -45,7 +50,9 @@ internal void Dispose ()
4550
p.Dispose ();
4651
SubclassConstructors = null;
4752

48-
JniPeerType = null;
53+
if (jniPeerType != null)
54+
jniPeerType.Dispose ();
55+
jniPeerType = null;
4956
}
5057

5158
public JniInstanceMethodInfo GetConstructor (string signature)

src/Java.Interop/Tests/Interop-Tests.projitems

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
<Compile Include="$(MSBuildThisFileDirectory)Java.Interop\JniInstanceMethodIDTest.cs" />
3939
<Compile Include="$(MSBuildThisFileDirectory)Java.Interop\JniMarshalMethodTests.cs" />
4040
<Compile Include="$(MSBuildThisFileDirectory)Java.Interop\JniMarshalTests.cs" />
41+
<Compile Include="$(MSBuildThisFileDirectory)Java.Interop\JniPeerMembersTests.cs" />
4142
<Compile Include="$(MSBuildThisFileDirectory)Java.Interop\JniTransitionTest.cs" />
4243
<Compile Include="$(MSBuildThisFileDirectory)Java.Interop\JniTypeSignatureTest.cs" />
4344
<Compile Include="$(MSBuildThisFileDirectory)Java.Interop\JniTypeTest.cs" />

src/Java.Interop/Tests/Java.Interop/JavaObjectTest.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,9 @@ public void CrossThreadSharingRequresRegistration ()
186186
class JavaObjectWithNoJavaPeer : JavaObject {
187187
}
188188

189-
[JniTypeSignature ("__this__/__type__/__had__/__better__/__not__/__Exist__")]
189+
[JniTypeSignature (JniTypeName)]
190190
class JavaObjectWithMissingJavaPeer : JavaObject {
191+
internal const string JniTypeName = "__this__/__type__/__had__/__better__/__not__/__Exist__";
191192
}
192193

193194
[JniTypeSignature ("java/lang/Object")]
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System;
2+
3+
using Java.Interop;
4+
5+
using NUnit.Framework;
6+
7+
namespace Java.InteropTests
8+
{
9+
[TestFixture]
10+
public class JniPeerMembersTests : JavaVMFixture
11+
{
12+
[Test]
13+
public void Ctor_CanReferenceNonexistentType ()
14+
{
15+
var members = new JniPeerMembers (JavaObjectWithMissingJavaPeer.JniTypeName, typeof(JavaObjectWithMissingJavaPeer));
16+
JniPeerMembers.Dispose (members);
17+
}
18+
}
19+
}
20+

0 commit comments

Comments
 (0)