Skip to content

Commit

Permalink
[Java.Interop.{Dynamic,Export}] Nullable Reference Type support (#980)
Browse files Browse the repository at this point in the history
Annotate `Java.Interop.Dynamic.dll` and `Java.Interop.Export.dll` to
support C#8 [Nullable Reference Types][0].

[0]: https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references
  • Loading branch information
jonpryor authored May 10, 2022
1 parent 843f3c7 commit 3fcce74
Show file tree
Hide file tree
Showing 13 changed files with 160 additions and 130 deletions.
2 changes: 2 additions & 0 deletions src/Java.Interop.Dynamic/Java.Interop.Dynamic.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>8.0</LangVersion>
<ProjectGuid>{AD4468F8-8883-434B-9D4C-E1801BB3B52A}</ProjectGuid>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\..\product.snk</AssemblyOriginatorKeyFile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ protected virtual void Dispose (bool disposing)
return;

info.Dispose ();
info = null;
info = null!;
disposed = true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ public DynamicJavaInstance (IJavaPeerable value)

Value = value;

var type = JniEnvironment.Types.GetJniTypeNameFromInstance (value.PeerReference);
var type = JniEnvironment.Types.GetJniTypeNameFromInstance (value.PeerReference) ??
throw new InvalidOperationException ($"Could not get JniType from value `{value}`.");
klass = JavaClassInfo.GetClassInfo (type);
}

Expand Down Expand Up @@ -53,8 +54,8 @@ protected virtual void Dispose (bool disposing)
}

disposed = true;
Value = null;
klass = null;
Value = null!;
klass = null!;
}

DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject (Expression parameter)
Expand Down
62 changes: 33 additions & 29 deletions src/Java.Interop.Dynamic/Java.Interop.Dynamic/JavaClassInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ static JavaClassInfo ()
public static JavaClassInfo GetClassInfo (string jniClassName)
{
lock (Classes) {
JavaClassInfo info = _GetClassInfo (jniClassName);
JavaClassInfo? info = _GetClassInfo (jniClassName);
if (info != null) {
Interlocked.Increment (ref info.RefCount);
return info;
Expand All @@ -80,7 +80,7 @@ public static JavaClassInfo GetClassInfo (string jniClassName)
}
}

static JavaClassInfo _GetClassInfo (string jniClassName)
static JavaClassInfo? _GetClassInfo (string jniClassName)
{
lock (Classes) {
WeakReference value;
Expand Down Expand Up @@ -114,19 +114,19 @@ public static int GetClassInfoCount (string jniClassName)

int RefCount = 1;

List<JavaConstructorInfo> constructors;
Dictionary<string, List<JavaFieldInfo>> fields;
Dictionary<string, List<JavaMethodInfo>> methods;
List<JavaConstructorInfo>? constructors;
Dictionary<string, List<JavaFieldInfo>>? fields;
Dictionary<string, List<JavaMethodInfo>>? methods;

public List<JavaConstructorInfo> Constructors {
public List<JavaConstructorInfo>? Constructors {
get {return LookupConstructors ();}
}

public Dictionary<string, List<JavaFieldInfo>> Fields {
public Dictionary<string, List<JavaFieldInfo>>? Fields {
get {return LookupFields ();}
}

public Dictionary<string, List<JavaMethodInfo>> Methods {
public Dictionary<string, List<JavaMethodInfo>>? Methods {
get {return LookupMethods ();}
}

Expand All @@ -152,7 +152,7 @@ public void Dispose ()
foreach (var name in methods.Keys.ToList ()) {
foreach (var info in methods [name])
info.Dispose ();
methods [name] = null;
methods.Remove (name);
}
}

Expand All @@ -171,7 +171,7 @@ internal static JniObjectReference GetConstructorParameters (JniObjectReference
return JniEnvironment.InstanceMethods.CallObjectMethod (method, Constructor_getParameterTypes);
}

List<JavaConstructorInfo> LookupConstructors ()
List<JavaConstructorInfo>? LookupConstructors ()
{
if (Members == null)
return null;
Expand Down Expand Up @@ -199,7 +199,7 @@ List<JavaConstructorInfo> LookupConstructors ()
}
}

Dictionary<string, List<JavaFieldInfo>> LookupFields ()
Dictionary<string, List<JavaFieldInfo>>? LookupFields ()
{
if (Members == null)
return null;
Expand All @@ -216,17 +216,18 @@ Dictionary<string, List<JavaFieldInfo>> LookupFields ()
for (int i = 0; i < len; ++i) {
var field = JniEnvironment.Arrays.GetObjectArrayElement (fields, i);
var n_name = JniEnvironment.InstanceMethods.CallObjectMethod (field, Field_getName);
var name = JniEnvironment.Strings.ToString (ref n_name, JniObjectReferenceOptions.CopyAndDispose);
var isStatic = IsStatic (field);
var name = JniEnvironment.Strings.ToString (ref n_name, JniObjectReferenceOptions.CopyAndDispose) ??
throw new InvalidOperationException ($"Could not determine field name at index {i}!");

List<JavaFieldInfo> overloads;
if (!Fields.TryGetValue (name, out overloads))
Fields.Add (name, overloads = new List<JavaFieldInfo> ());
List<JavaFieldInfo>? overloads = null;
if (!Fields?.TryGetValue (name, out overloads) ?? false)
Fields!.Add (name, overloads = new List<JavaFieldInfo> ());

var n_type = JniEnvironment.InstanceMethods.CallObjectMethod (field, Field_getType);
using (var type = new JniType (ref n_type, JniObjectReferenceOptions.CopyAndDispose)) {
var sig = JniTypeSignature.Parse (type.Name);
overloads.Add (new JavaFieldInfo (Members, name + "." + sig.QualifiedReference, isStatic));
overloads?.Add (new JavaFieldInfo (Members, name + "." + sig.QualifiedReference, isStatic));
}

JniObjectReference.Dispose (ref field);
Expand All @@ -239,7 +240,7 @@ Dictionary<string, List<JavaFieldInfo>> LookupFields ()
}
}

Dictionary<string, List<JavaMethodInfo>> LookupMethods ()
Dictionary<string, List<JavaMethodInfo>>? LookupMethods ()
{
if (Members == null)
return null;
Expand All @@ -256,19 +257,20 @@ Dictionary<string, List<JavaMethodInfo>> LookupMethods ()
for (int i = 0; i < len; ++i) {
var method = JniEnvironment.Arrays.GetObjectArrayElement (methods, i);
var n_name = JniEnvironment.InstanceMethods.CallObjectMethod (method, Method_getName);
var name = JniEnvironment.Strings.ToString (ref n_name, JniObjectReferenceOptions.CopyAndDispose);
var isStatic = IsStatic (method);
var name = JniEnvironment.Strings.ToString (ref n_name, JniObjectReferenceOptions.CopyAndDispose) ??
throw new InvalidOperationException ($"Could not determine method name at index {i}!");

List<JavaMethodInfo> overloads;
if (!Methods.TryGetValue (name, out overloads))
Methods.Add (name, overloads = new List<JavaMethodInfo> ());
List<JavaMethodInfo>? overloads = null;
if (!Methods?.TryGetValue (name, out overloads) ?? false)
Methods!.Add (name, overloads = new List<JavaMethodInfo> ());

var nrt = JniEnvironment.InstanceMethods.CallObjectMethod (method, Method_getReturnType);
var rt = new JniType (ref nrt, JniObjectReferenceOptions.CopyAndDispose);
var m = new JavaMethodInfo (Members, method, name, isStatic) {
ReturnType = rt,
};
overloads.Add (m);
overloads?.Add (m);
JniObjectReference.Dispose (ref method);
}
} finally {
Expand All @@ -286,11 +288,11 @@ static bool IsStatic (JniObjectReference member)
return (s & JavaModifiers.Static) == JavaModifiers.Static;
}

internal unsafe bool TryInvokeMember (IJavaPeerable self, JavaMethodBase[] overloads, DynamicMetaObject[] args, out object value)
internal unsafe bool TryInvokeMember (IJavaPeerable self, JavaMethodBase[] overloads, DynamicMetaObject[] args, out object? value)
{
value = null;
var vms = (List<JniValueMarshaler>) null;
var states = (JniValueMarshalerState[]) null;
var vms = (List<JniValueMarshaler>?) null;
var states = (JniValueMarshalerState[]?) null;

var jtypes = GetJniTypes (args);
try {
Expand All @@ -313,18 +315,20 @@ internal unsafe bool TryInvokeMember (IJavaPeerable self, JavaMethodBase[] overl
}
finally {
for (int i = 0; vms != null && i < vms.Count; ++i) {
if (states == null) {
continue;
}
vms [i].DestroyArgumentState (args [i].Value, ref states [i]);
}
for (int i = 0; i < jtypes.Count; ++i) {
if (jtypes [i] != null)
jtypes [i].Dispose ();
jtypes [i]?.Dispose ();
}
}
}

static List<JniType> GetJniTypes (DynamicMetaObject[] args)
static List<JniType?> GetJniTypes (DynamicMetaObject[] args)
{
var r = new List<JniType> (args.Length);
var r = new List<JniType?> (args.Length);
var vm = JniEnvironment.Runtime;
foreach (var a in args) {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,17 @@ protected override string JniReturnType {
get {return "V";}
}

public override unsafe object Invoke (IJavaPeerable self, JniArgumentValue* arguments)
public override unsafe object? Invoke (IJavaPeerable? self, JniArgumentValue* arguments)
{
var signature = JniSignature ?? throw new InvalidOperationException ("No JniSignature!");
if (self == null) {
var h = members.InstanceMethods.StartCreateInstance (JniSignature, typeof (JavaInstanceProxy), arguments);
var h = members.InstanceMethods.StartCreateInstance (signature, typeof (JavaInstanceProxy), arguments);
self = JniEnvironment.Runtime.ValueManager.GetValue<JavaInstanceProxy> (ref h, JniObjectReferenceOptions.CopyAndDispose);
if (self == null) {
throw new InvalidOperationException ($"Could not create instance of {members.ManagedPeerType}!");
}
}
members.InstanceMethods.FinishCreateInstance (JniSignature, self, arguments);
members.InstanceMethods.FinishCreateInstance (signature, self, arguments);
return new DynamicJavaInstance (self);
}
}
Expand Down
44 changes: 22 additions & 22 deletions src/Java.Interop.Dynamic/Java.Interop.Dynamic/JavaFieldInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public override string Name {
}
}

public object GetValue (IJavaPeerable self)
public object? GetValue (IJavaPeerable self)
{
AssertSelf (self);

Expand All @@ -59,7 +59,7 @@ void AssertSelf (IJavaPeerable self)
"self");
}

object GetStaticValue ()
object? GetStaticValue ()
{
var n = GetSignatureStartIndex ();
switch (JniSignature [n + 1]) {
Expand All @@ -80,7 +80,7 @@ object GetStaticValue ()
}
}

object GetInstanceValue (IJavaPeerable self)
object? GetInstanceValue (IJavaPeerable self)
{
var n = GetSignatureStartIndex ();
switch (JniSignature [n + 1]) {
Expand Down Expand Up @@ -110,7 +110,7 @@ int GetSignatureStartIndex ()
return n;
}

public void SetValue (IJavaPeerable self, object value)
public void SetValue (IJavaPeerable self, object? value)
{
AssertSelf (self);

Expand All @@ -121,18 +121,18 @@ public void SetValue (IJavaPeerable self, object value)
}
}

void SetStaticValue (object value)
void SetStaticValue (object? value)
{
var n = GetSignatureStartIndex ();
switch (JniSignature [n + 1]) {
case 'Z': members.StaticFields.SetValue (JniSignature, (bool) value); break;
case 'B': members.StaticFields.SetValue (JniSignature, (byte) value); break;
case 'C': members.StaticFields.SetValue (JniSignature, (char) value); break;
case 'S': members.StaticFields.SetValue (JniSignature, (short) value); break;
case 'I': members.StaticFields.SetValue (JniSignature, (int) value); break;
case 'J': members.StaticFields.SetValue (JniSignature, (long) value); break;
case 'F': members.StaticFields.SetValue (JniSignature, (float) value); break;
case 'D': members.StaticFields.SetValue (JniSignature, (double) value); break;
case 'Z': members.StaticFields.SetValue (JniSignature, (bool) value!); break;
case 'B': members.StaticFields.SetValue (JniSignature, (byte) value!); break;
case 'C': members.StaticFields.SetValue (JniSignature, (char) value!); break;
case 'S': members.StaticFields.SetValue (JniSignature, (short) value!); break;
case 'I': members.StaticFields.SetValue (JniSignature, (int) value!); break;
case 'J': members.StaticFields.SetValue (JniSignature, (long) value!); break;
case 'F': members.StaticFields.SetValue (JniSignature, (float) value!); break;
case 'D': members.StaticFields.SetValue (JniSignature, (double) value!); break;
case 'L':
case '[':
if (value == null) {
Expand All @@ -152,18 +152,18 @@ void SetStaticValue (object value)
}
}

void SetInstanceValue (IJavaPeerable self, object value)
void SetInstanceValue (IJavaPeerable self, object? value)
{
var n = GetSignatureStartIndex ();
switch (JniSignature [n + 1]) {
case 'Z': members.InstanceFields.SetValue (JniSignature, self, (bool) value); break;
case 'B': members.InstanceFields.SetValue (JniSignature, self, (byte) value); break;
case 'C': members.InstanceFields.SetValue (JniSignature, self, (char) value); break;
case 'S': members.InstanceFields.SetValue (JniSignature, self, (short) value); break;
case 'I': members.InstanceFields.SetValue (JniSignature, self, (int) value); break;
case 'J': members.InstanceFields.SetValue (JniSignature, self, (long) value); break;
case 'F': members.InstanceFields.SetValue (JniSignature, self, (float) value); break;
case 'D': members.InstanceFields.SetValue (JniSignature, self, (double) value); break;
case 'Z': members.InstanceFields.SetValue (JniSignature, self, (bool) value!); break;
case 'B': members.InstanceFields.SetValue (JniSignature, self, (byte) value!); break;
case 'C': members.InstanceFields.SetValue (JniSignature, self, (char) value!); break;
case 'S': members.InstanceFields.SetValue (JniSignature, self, (short) value!); break;
case 'I': members.InstanceFields.SetValue (JniSignature, self, (int) value!); break;
case 'J': members.InstanceFields.SetValue (JniSignature, self, (long) value!); break;
case 'F': members.InstanceFields.SetValue (JniSignature, self, (float) value!); break;
case 'D': members.InstanceFields.SetValue (JniSignature, self, (double) value!); break;
case 'L':
case '[':
if (value == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@ protected virtual void Dispose (bool disposing)
{
}

protected static object ToReturnValue (ref JniObjectReference handle, string signature, int n)
protected static object? ToReturnValue (ref JniObjectReference handle, string signature, int n)
{
var instance = JniEnvironment.Runtime.ValueManager.GetValue<IJavaPeerable> (ref handle, JniObjectReferenceOptions.CopyAndDispose);
if (instance == null) {
return null;
}
switch (signature [n]) {
case 'L':
return new DynamicJavaInstance (instance);
Expand Down
Loading

0 comments on commit 3fcce74

Please sign in to comment.