Skip to content
This repository was archived by the owner on Jul 6, 2026. It is now read-only.

Commit 3fcce74

Browse files
authored
[Java.Interop.{Dynamic,Export}] Nullable Reference Type support (#980)
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
1 parent 843f3c7 commit 3fcce74

13 files changed

Lines changed: 160 additions & 130 deletions

‎src/Java.Interop.Dynamic/Java.Interop.Dynamic.csproj‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
<ProjectSdk="Microsoft.NET.Sdk">
33
<PropertyGroup>
44
<TargetFramework>netstandard2.0</TargetFramework>
5+
<LangVersion>8.0</LangVersion>
56
<ProjectGuid>{AD4468F8-8883-434B-9D4C-E1801BB3B52A}</ProjectGuid>
7+
<Nullable>enable</Nullable>
68
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
79
<SignAssembly>true</SignAssembly>
810
<AssemblyOriginatorKeyFile>..\..\product.snk</AssemblyOriginatorKeyFile>

‎src/Java.Interop.Dynamic/Java.Interop.Dynamic/DynamicJavaClass.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ protected virtual void Dispose (bool disposing)
4242
return;
4343

4444
info.Dispose();
45-
info=null;
45+
info=null!;
4646
disposed=true;
4747
}
4848

‎src/Java.Interop.Dynamic/Java.Interop.Dynamic/DynamicJavaInstance.cs‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ public DynamicJavaInstance (IJavaPeerable value)
2323

2424
Value=value;
2525

26-
vartype=JniEnvironment.Types.GetJniTypeNameFromInstance(value.PeerReference);
26+
vartype=JniEnvironment.Types.GetJniTypeNameFromInstance(value.PeerReference)??
27+
thrownewInvalidOperationException($"Could not get JniType from value `{value}`.");
2728
klass=JavaClassInfo.GetClassInfo(type);
2829
}
2930

@@ -53,8 +54,8 @@ protected virtual void Dispose (bool disposing)
5354
}
5455

5556
disposed=true;
56-
Value=null;
57-
klass=null;
57+
Value=null!;
58+
klass=null!;
5859
}
5960

6061
DynamicMetaObjectIDynamicMetaObjectProvider.GetMetaObject(Expressionparameter)

‎src/Java.Interop.Dynamic/Java.Interop.Dynamic/JavaClassInfo.cs‎

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ static JavaClassInfo ()
6868
publicstaticJavaClassInfoGetClassInfo(stringjniClassName)
6969
{
7070
lock(Classes){
71-
JavaClassInfoinfo=_GetClassInfo(jniClassName);
71+
JavaClassInfo?info=_GetClassInfo(jniClassName);
7272
if(info!=null){
7373
Interlocked.Increment(refinfo.RefCount);
7474
returninfo;
@@ -80,7 +80,7 @@ public static JavaClassInfo GetClassInfo (string jniClassName)
8080
}
8181
}
8282

83-
staticJavaClassInfo_GetClassInfo(stringjniClassName)
83+
staticJavaClassInfo?_GetClassInfo(stringjniClassName)
8484
{
8585
lock(Classes){
8686
WeakReferencevalue;
@@ -114,19 +114,19 @@ public static int GetClassInfoCount (string jniClassName)
114114

115115
intRefCount=1;
116116

117-
List<JavaConstructorInfo>constructors;
118-
Dictionary<string,List<JavaFieldInfo>>fields;
119-
Dictionary<string,List<JavaMethodInfo>>methods;
117+
List<JavaConstructorInfo>?constructors;
118+
Dictionary<string,List<JavaFieldInfo>>?fields;
119+
Dictionary<string,List<JavaMethodInfo>>?methods;
120120

121-
publicList<JavaConstructorInfo>Constructors{
121+
publicList<JavaConstructorInfo>?Constructors{
122122
get{returnLookupConstructors();}
123123
}
124124

125-
publicDictionary<string,List<JavaFieldInfo>>Fields{
125+
publicDictionary<string,List<JavaFieldInfo>>?Fields{
126126
get{returnLookupFields();}
127127
}
128128

129-
publicDictionary<string,List<JavaMethodInfo>>Methods{
129+
publicDictionary<string,List<JavaMethodInfo>>?Methods{
130130
get{returnLookupMethods();}
131131
}
132132

@@ -152,7 +152,7 @@ public void Dispose ()
152152
foreach(varnameinmethods.Keys.ToList()){
153153
foreach(varinfoinmethods[name])
154154
info.Dispose();
155-
methods[name]=null;
155+
methods.Remove(name);
156156
}
157157
}
158158

@@ -171,7 +171,7 @@ internal static JniObjectReference GetConstructorParameters (JniObjectReference
171171
returnJniEnvironment.InstanceMethods.CallObjectMethod(method,Constructor_getParameterTypes);
172172
}
173173

174-
List<JavaConstructorInfo>LookupConstructors()
174+
List<JavaConstructorInfo>?LookupConstructors()
175175
{
176176
if(Members==null)
177177
returnnull;
@@ -199,7 +199,7 @@ List<JavaConstructorInfo> LookupConstructors ()
199199
}
200200
}
201201

202-
Dictionary<string,List<JavaFieldInfo>>LookupFields()
202+
Dictionary<string,List<JavaFieldInfo>>?LookupFields()
203203
{
204204
if(Members==null)
205205
returnnull;
@@ -216,17 +216,18 @@ Dictionary<string, List<JavaFieldInfo>> LookupFields ()
216216
for(inti=0;i<len;++i){
217217
varfield=JniEnvironment.Arrays.GetObjectArrayElement(fields,i);
218218
varn_name=JniEnvironment.InstanceMethods.CallObjectMethod(field,Field_getName);
219-
varname=JniEnvironment.Strings.ToString(refn_name,JniObjectReferenceOptions.CopyAndDispose);
220219
varisStatic=IsStatic(field);
220+
varname=JniEnvironment.Strings.ToString(refn_name,JniObjectReferenceOptions.CopyAndDispose)??
221+
thrownewInvalidOperationException($"Could not determine field name at index {i}!");
221222

222-
List<JavaFieldInfo>overloads;
223-
if(!Fields.TryGetValue(name,outoverloads))
224-
Fields.Add(name,overloads=newList<JavaFieldInfo>());
223+
List<JavaFieldInfo>?overloads=null;
224+
if(!Fields?.TryGetValue(name,outoverloads)??false)
225+
Fields!.Add(name,overloads=newList<JavaFieldInfo>());
225226

226227
varn_type=JniEnvironment.InstanceMethods.CallObjectMethod(field,Field_getType);
227228
using(vartype=newJniType(refn_type,JniObjectReferenceOptions.CopyAndDispose)){
228229
varsig=JniTypeSignature.Parse(type.Name);
229-
overloads.Add(newJavaFieldInfo(Members,name+"."+sig.QualifiedReference,isStatic));
230+
overloads?.Add(newJavaFieldInfo(Members,name+"."+sig.QualifiedReference,isStatic));
230231
}
231232

232233
JniObjectReference.Dispose(reffield);
@@ -239,7 +240,7 @@ Dictionary<string, List<JavaFieldInfo>> LookupFields ()
239240
}
240241
}
241242

242-
Dictionary<string,List<JavaMethodInfo>>LookupMethods()
243+
Dictionary<string,List<JavaMethodInfo>>?LookupMethods()
243244
{
244245
if(Members==null)
245246
returnnull;
@@ -256,19 +257,20 @@ Dictionary<string, List<JavaMethodInfo>> LookupMethods ()
256257
for(inti=0;i<len;++i){
257258
varmethod=JniEnvironment.Arrays.GetObjectArrayElement(methods,i);
258259
varn_name=JniEnvironment.InstanceMethods.CallObjectMethod(method,Method_getName);
259-
varname=JniEnvironment.Strings.ToString(refn_name,JniObjectReferenceOptions.CopyAndDispose);
260260
varisStatic=IsStatic(method);
261+
varname=JniEnvironment.Strings.ToString(refn_name,JniObjectReferenceOptions.CopyAndDispose)??
262+
thrownewInvalidOperationException($"Could not determine method name at index {i}!");
261263

262-
List<JavaMethodInfo>overloads;
263-
if(!Methods.TryGetValue(name,outoverloads))
264-
Methods.Add(name,overloads=newList<JavaMethodInfo>());
264+
List<JavaMethodInfo>?overloads=null;
265+
if(!Methods?.TryGetValue(name,outoverloads)??false)
266+
Methods!.Add(name,overloads=newList<JavaMethodInfo>());
265267

266268
varnrt=JniEnvironment.InstanceMethods.CallObjectMethod(method,Method_getReturnType);
267269
varrt=newJniType(refnrt,JniObjectReferenceOptions.CopyAndDispose);
268270
varm=newJavaMethodInfo(Members,method,name,isStatic){
269271
ReturnType=rt,
270272
};
271-
overloads.Add(m);
273+
overloads?.Add(m);
272274
JniObjectReference.Dispose(refmethod);
273275
}
274276
}finally{
@@ -286,11 +288,11 @@ static bool IsStatic (JniObjectReference member)
286288
return(s&JavaModifiers.Static)==JavaModifiers.Static;
287289
}
288290

289-
internalunsafeboolTryInvokeMember(IJavaPeerableself,JavaMethodBase[]overloads,DynamicMetaObject[]args,outobjectvalue)
291+
internalunsafeboolTryInvokeMember(IJavaPeerableself,JavaMethodBase[]overloads,DynamicMetaObject[]args,outobject?value)
290292
{
291293
value=null;
292-
varvms=(List<JniValueMarshaler>)null;
293-
varstates=(JniValueMarshalerState[])null;
294+
varvms=(List<JniValueMarshaler>?)null;
295+
varstates=(JniValueMarshalerState[]?)null;
294296

295297
varjtypes=GetJniTypes(args);
296298
try{
@@ -313,18 +315,20 @@ internal unsafe bool TryInvokeMember (IJavaPeerable self, JavaMethodBase[] overl
313315
}
314316
finally{
315317
for(inti=0;vms!=null&&i<vms.Count;++i){
318+
if(states==null){
319+
continue;
320+
}
316321
vms[i].DestroyArgumentState(args[i].Value,refstates[i]);
317322
}
318323
for(inti=0;i<jtypes.Count;++i){
319-
if(jtypes[i]!=null)
320-
jtypes[i].Dispose();
324+
jtypes[i]?.Dispose();
321325
}
322326
}
323327
}
324328

325-
staticList<JniType>GetJniTypes(DynamicMetaObject[]args)
329+
staticList<JniType?>GetJniTypes(DynamicMetaObject[]args)
326330
{
327-
varr=newList<JniType>(args.Length);
331+
varr=newList<JniType?>(args.Length);
328332
varvm=JniEnvironment.Runtime;
329333
foreach(varainargs){
330334
try{

‎src/Java.Interop.Dynamic/Java.Interop.Dynamic/JavaConstructorInfo.cs‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,17 @@ protected override string JniReturnType {
3636
get{return"V";}
3737
}
3838

39-
publicoverrideunsafeobjectInvoke(IJavaPeerableself,JniArgumentValue*arguments)
39+
publicoverrideunsafeobject?Invoke(IJavaPeerable?self,JniArgumentValue*arguments)
4040
{
41+
varsignature=JniSignature??thrownewInvalidOperationException("No JniSignature!");
4142
if(self==null){
42-
varh=members.InstanceMethods.StartCreateInstance(JniSignature,typeof(JavaInstanceProxy),arguments);
43+
varh=members.InstanceMethods.StartCreateInstance(signature,typeof(JavaInstanceProxy),arguments);
4344
self=JniEnvironment.Runtime.ValueManager.GetValue<JavaInstanceProxy>(refh,JniObjectReferenceOptions.CopyAndDispose);
45+
if(self==null){
46+
thrownewInvalidOperationException($"Could not create instance of {members.ManagedPeerType}!");
47+
}
4448
}
45-
members.InstanceMethods.FinishCreateInstance(JniSignature,self,arguments);
49+
members.InstanceMethods.FinishCreateInstance(signature,self,arguments);
4650
returnnewDynamicJavaInstance(self);
4751
}
4852
}

‎src/Java.Interop.Dynamic/Java.Interop.Dynamic/JavaFieldInfo.cs‎

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public override string Name {
3838
}
3939
}
4040

41-
publicobjectGetValue(IJavaPeerableself)
41+
publicobject?GetValue(IJavaPeerableself)
4242
{
4343
AssertSelf(self);
4444

@@ -59,7 +59,7 @@ void AssertSelf (IJavaPeerable self)
5959
"self");
6060
}
6161

62-
objectGetStaticValue()
62+
object?GetStaticValue()
6363
{
6464
varn=GetSignatureStartIndex();
6565
switch(JniSignature[n+1]){
@@ -80,7 +80,7 @@ object GetStaticValue ()
8080
}
8181
}
8282

83-
objectGetInstanceValue(IJavaPeerableself)
83+
object?GetInstanceValue(IJavaPeerableself)
8484
{
8585
varn=GetSignatureStartIndex();
8686
switch(JniSignature[n+1]){
@@ -110,7 +110,7 @@ int GetSignatureStartIndex ()
110110
returnn;
111111
}
112112

113-
publicvoidSetValue(IJavaPeerableself,objectvalue)
113+
publicvoidSetValue(IJavaPeerableself,object?value)
114114
{
115115
AssertSelf(self);
116116

@@ -121,18 +121,18 @@ public void SetValue (IJavaPeerable self, object value)
121121
}
122122
}
123123

124-
voidSetStaticValue(objectvalue)
124+
voidSetStaticValue(object?value)
125125
{
126126
varn=GetSignatureStartIndex();
127127
switch(JniSignature[n+1]){
128-
case'Z':members.StaticFields.SetValue(JniSignature,(bool)value);break;
129-
case'B':members.StaticFields.SetValue(JniSignature,(byte)value);break;
130-
case'C':members.StaticFields.SetValue(JniSignature,(char)value);break;
131-
case'S':members.StaticFields.SetValue(JniSignature,(short)value);break;
132-
case'I':members.StaticFields.SetValue(JniSignature,(int)value);break;
133-
case'J':members.StaticFields.SetValue(JniSignature,(long)value);break;
134-
case'F':members.StaticFields.SetValue(JniSignature,(float)value);break;
135-
case'D':members.StaticFields.SetValue(JniSignature,(double)value);break;
128+
case'Z':members.StaticFields.SetValue(JniSignature,(bool)value!);break;
129+
case'B':members.StaticFields.SetValue(JniSignature,(byte)value!);break;
130+
case'C':members.StaticFields.SetValue(JniSignature,(char)value!);break;
131+
case'S':members.StaticFields.SetValue(JniSignature,(short)value!);break;
132+
case'I':members.StaticFields.SetValue(JniSignature,(int)value!);break;
133+
case'J':members.StaticFields.SetValue(JniSignature,(long)value!);break;
134+
case'F':members.StaticFields.SetValue(JniSignature,(float)value!);break;
135+
case'D':members.StaticFields.SetValue(JniSignature,(double)value!);break;
136136
case'L':
137137
case'[':
138138
if(value==null){
@@ -152,18 +152,18 @@ void SetStaticValue (object value)
152152
}
153153
}
154154

155-
voidSetInstanceValue(IJavaPeerableself,objectvalue)
155+
voidSetInstanceValue(IJavaPeerableself,object?value)
156156
{
157157
varn=GetSignatureStartIndex();
158158
switch(JniSignature[n+1]){
159-
case'Z':members.InstanceFields.SetValue(JniSignature,self,(bool)value);break;
160-
case'B':members.InstanceFields.SetValue(JniSignature,self,(byte)value);break;
161-
case'C':members.InstanceFields.SetValue(JniSignature,self,(char)value);break;
162-
case'S':members.InstanceFields.SetValue(JniSignature,self,(short)value);break;
163-
case'I':members.InstanceFields.SetValue(JniSignature,self,(int)value);break;
164-
case'J':members.InstanceFields.SetValue(JniSignature,self,(long)value);break;
165-
case'F':members.InstanceFields.SetValue(JniSignature,self,(float)value);break;
166-
case'D':members.InstanceFields.SetValue(JniSignature,self,(double)value);break;
159+
case'Z':members.InstanceFields.SetValue(JniSignature,self,(bool)value!);break;
160+
case'B':members.InstanceFields.SetValue(JniSignature,self,(byte)value!);break;
161+
case'C':members.InstanceFields.SetValue(JniSignature,self,(char)value!);break;
162+
case'S':members.InstanceFields.SetValue(JniSignature,self,(short)value!);break;
163+
case'I':members.InstanceFields.SetValue(JniSignature,self,(int)value!);break;
164+
case'J':members.InstanceFields.SetValue(JniSignature,self,(long)value!);break;
165+
case'F':members.InstanceFields.SetValue(JniSignature,self,(float)value!);break;
166+
case'D':members.InstanceFields.SetValue(JniSignature,self,(double)value!);break;
167167
case'L':
168168
case'[':
169169
if(value==null){

‎src/Java.Interop.Dynamic/Java.Interop.Dynamic/JavaMemberInfo.cs‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,12 @@ protected virtual void Dispose (bool disposing)
2020
{
2121
}
2222

23-
protectedstaticobjectToReturnValue(refJniObjectReferencehandle,stringsignature,intn)
23+
protectedstaticobject?ToReturnValue(refJniObjectReferencehandle,stringsignature,intn)
2424
{
2525
varinstance=JniEnvironment.Runtime.ValueManager.GetValue<IJavaPeerable>(refhandle,JniObjectReferenceOptions.CopyAndDispose);
26+
if(instance==null){
27+
returnnull;
28+
}
2629
switch(signature[n]){
2730
case'L':
2831
returnnewDynamicJavaInstance(instance);

0 commit comments

Comments
 (0)