diff --git a/src/Java.Interop/Java.Interop/JniBuiltinMarshalers.cs b/src/Java.Interop/Java.Interop/JniBuiltinMarshalers.cs index 3ab2744cc..4728c8987 100644 --- a/src/Java.Interop/Java.Interop/JniBuiltinMarshalers.cs +++ b/src/Java.Interop/Java.Interop/JniBuiltinMarshalers.cs @@ -49,18 +49,22 @@ static bool GetBuiltInTypeSignature (Type type, ref JniTypeSignature signature) case TypeCode.Boolean: signature = GetCachedTypeSignature (ref __BooleanTypeSignature, "Z", arrayRank: 0, keyword: true); return true; + case TypeCode.Byte: case TypeCode.SByte: signature = GetCachedTypeSignature (ref __SByteTypeSignature, "B", arrayRank: 0, keyword: true); return true; case TypeCode.Char: signature = GetCachedTypeSignature (ref __CharTypeSignature, "C", arrayRank: 0, keyword: true); return true; + case TypeCode.UInt16: case TypeCode.Int16: signature = GetCachedTypeSignature (ref __Int16TypeSignature, "S", arrayRank: 0, keyword: true); return true; + case TypeCode.UInt32: case TypeCode.Int32: signature = GetCachedTypeSignature (ref __Int32TypeSignature, "I", arrayRank: 0, keyword: true); return true; + case TypeCode.UInt64: case TypeCode.Int64: signature = GetCachedTypeSignature (ref __Int64TypeSignature, "J", arrayRank: 0, keyword: true); return true; @@ -74,9 +78,6 @@ static bool GetBuiltInTypeSignature (Type type, ref JniTypeSignature signature) case TypeCode.DBNull: case TypeCode.Decimal: case TypeCode.Empty: - case TypeCode.UInt16: - case TypeCode.UInt32: - case TypeCode.UInt64: return false; } diff --git a/src/Java.Interop/Java.Interop/JniBuiltinMarshalers.tt b/src/Java.Interop/Java.Interop/JniBuiltinMarshalers.tt index e5c911bf5..38b3a18d8 100644 --- a/src/Java.Interop/Java.Interop/JniBuiltinMarshalers.tt +++ b/src/Java.Interop/Java.Interop/JniBuiltinMarshalers.tt @@ -18,14 +18,14 @@ using Java.Interop.Expressions; namespace Java.Interop { <# var types = new[]{ - new { Name = "Boolean", Type = "Boolean", JniCallType = "Boolean", JniType = "Z", GetValue = "booleanValue" }, - new { Name = "Byte", Type = "SByte", JniCallType = "Byte", JniType = "B", GetValue = "byteValue" }, - new { Name = "Character", Type = "Char", JniCallType = "Char", JniType = "C", GetValue = "charValue" }, - new { Name = "Short", Type = "Int16", JniCallType = "Short", JniType = "S", GetValue = "shortValue" }, - new { Name = "Integer", Type = "Int32", JniCallType = "Int", JniType = "I", GetValue = "intValue" }, - new { Name = "Long", Type = "Int64", JniCallType = "Long", JniType = "J", GetValue = "longValue" }, - new { Name = "Float", Type = "Single", JniCallType = "Float", JniType = "F", GetValue = "floatValue" }, - new { Name = "Double", Type = "Double", JniCallType = "Double", JniType = "D", GetValue = "doubleValue" }, + new { Name = "Boolean", Type = "Boolean", UnsignedType = "", JniCallType = "Boolean", JniType = "Z", GetValue = "booleanValue" }, + new { Name = "Byte", Type = "SByte", UnsignedType = "Byte", JniCallType = "Byte", JniType = "B", GetValue = "byteValue" }, + new { Name = "Character", Type = "Char", UnsignedType = "", JniCallType = "Char", JniType = "C", GetValue = "charValue" }, + new { Name = "Short", Type = "Int16", UnsignedType = "UInt16", JniCallType = "Short", JniType = "S", GetValue = "shortValue" }, + new { Name = "Integer", Type = "Int32", UnsignedType = "UInt32", JniCallType = "Int", JniType = "I", GetValue = "intValue" }, + new { Name = "Long", Type = "Int64", UnsignedType = "UInt64", JniCallType = "Long", JniType = "J", GetValue = "longValue" }, + new { Name = "Float", Type = "Single", UnsignedType = "", JniCallType = "Float", JniType = "F", GetValue = "floatValue" }, + new { Name = "Double", Type = "Double", UnsignedType = "", JniCallType = "Double", JniType = "D", GetValue = "doubleValue" }, }; #> @@ -57,6 +57,11 @@ namespace Java.Interop { return true; <# foreach (var type in types) { + if (!string.IsNullOrEmpty (type.UnsignedType)) { +#> + case TypeCode.<#= type.UnsignedType #>: +<# + } #> case TypeCode.<#= type.Type #>: signature = GetCachedTypeSignature (ref __<#= type.Type #>TypeSignature, "<#= type.JniType #>", arrayRank: 0, keyword: true); @@ -68,9 +73,6 @@ namespace Java.Interop { case TypeCode.DBNull: case TypeCode.Decimal: case TypeCode.Empty: - case TypeCode.UInt16: - case TypeCode.UInt32: - case TypeCode.UInt64: return false; } @@ -185,7 +187,7 @@ namespace Java.Interop { public override object? CreateValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (ConstructorsAndInterfaces)] + [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) @@ -196,7 +198,7 @@ namespace Java.Interop { public override <#= type.Type #> CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (ConstructorsAndInterfaces)] + [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) @@ -230,6 +232,7 @@ namespace Java.Interop { state = new JniValueMarshalerState (); } + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] public override Expression CreateParameterToManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize, Type? targetType) { @@ -242,6 +245,7 @@ namespace Java.Interop { return sourceValue; } + [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] public override Expression CreateReturnValueFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue) { @@ -256,7 +260,7 @@ namespace Java.Interop { public override <#= type.Type #>? CreateGenericValue ( ref JniObjectReference reference, JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (ConstructorsAndInterfaces)] + [DynamicallyAccessedMembers (Constructors)] Type? targetType) { if (!reference.IsValid) diff --git a/src/Java.Interop/Java.Interop/JniRuntime.JniTypeManager.cs b/src/Java.Interop/Java.Interop/JniRuntime.JniTypeManager.cs index 9a8e5be9d..17ccbb705 100644 --- a/src/Java.Interop/Java.Interop/JniRuntime.JniTypeManager.cs +++ b/src/Java.Interop/Java.Interop/JniRuntime.JniTypeManager.cs @@ -146,7 +146,7 @@ public JniTypeSignature GetTypeSignature (Type type) if (type == null) throw new ArgumentNullException (nameof (type)); if (type.ContainsGenericParameters) - throw new ArgumentException ($"'{type}' contains a generic type definition. This is not supported.", nameof (type)); + throw new NotSupportedException ($"'{type}' contains a generic type definition. This is not supported."); type = GetUnderlyingType (type, out int rank); @@ -184,7 +184,7 @@ public IEnumerable GetTypeSignatures (Type type) if (type == null) yield break; if (type.ContainsGenericParameters) - throw new ArgumentException ($"'{type}' contains a generic type definition. This is not supported.", nameof (type)); + throw new NotSupportedException ($"'{type}' contains a generic type definition. This is not supported."); type = GetUnderlyingType (type, out int rank); diff --git a/tests/Java.Interop-Tests/Java.Interop/JniTypeManagerTests.cs b/tests/Java.Interop-Tests/Java.Interop/JniTypeManagerTests.cs index 60e64fd59..c49b1f2eb 100644 --- a/tests/Java.Interop-Tests/Java.Interop/JniTypeManagerTests.cs +++ b/tests/Java.Interop-Tests/Java.Interop/JniTypeManagerTests.cs @@ -18,7 +18,7 @@ public void GetTypeSignature_Type () Assert.Throws(() => JniRuntime.CurrentRuntime.TypeManager.GetTypeSignature (typeof (int[,]))); Assert.Throws(() => JniRuntime.CurrentRuntime.TypeManager.GetTypeSignature (typeof (int[,][]))); Assert.Throws(() => JniRuntime.CurrentRuntime.TypeManager.GetTypeSignature (typeof (int[][,]))); - Assert.Throws(() => JniRuntime.CurrentRuntime.TypeManager.GetTypeSignature (typeof (Action<>))); + Assert.Throws(() => JniRuntime.CurrentRuntime.TypeManager.GetTypeSignature (typeof (Action<>))); Assert.AreEqual (null, JniRuntime.CurrentRuntime.TypeManager.GetTypeSignature (typeof (JniRuntimeTest)).SimpleReference); AssertGetJniTypeInfoForType (typeof (string), "java/lang/String", false, 0); @@ -44,6 +44,12 @@ public void GetTypeSignature_Type () AssertGetJniTypeInfoForType (typeof (int[][]), "[[I", true, 2); AssertGetJniTypeInfoForType (typeof (int[][][]), "[[[I", true, 3); + // We map unsigned types to their signed counterparts + AssertGetJniTypeInfoForType (typeof (byte[]), "[B", true, 1); + AssertGetJniTypeInfoForType (typeof (ushort[]), "[S", true, 1); + AssertGetJniTypeInfoForType (typeof (uint[]), "[I", true, 1); + AssertGetJniTypeInfoForType (typeof (ulong[]), "[J", true, 1); + AssertGetJniTypeInfoForType (typeof (JavaSByteArray), "[B", true, 1); AssertGetJniTypeInfoForType (typeof (JavaInt16Array), "[S", true, 1); AssertGetJniTypeInfoForType (typeof (JavaInt32Array), "[I", true, 1); @@ -89,14 +95,16 @@ public void GetTypeSignature_Type () static void AssertGetJniTypeInfoForType (Type type, string jniType, bool isKeyword, int arrayRank) { var info = JniRuntime.CurrentRuntime.TypeManager.GetTypeSignature (type); + Assert.IsTrue (info.IsValid, $"info.IsValid for `{type}`"); // `GetTypeSignature() and `GetTypeSignatures()` should be "in sync"; verify that! var info2 = JniRuntime.CurrentRuntime.TypeManager.GetTypeSignatures (type).FirstOrDefault (); + Assert.IsTrue (info2.IsValid, $"info2.IsValid for `{type}`"); Assert.AreEqual (jniType, info.Name, $"info.Name for `{type}`"); - Assert.AreEqual (jniType, info2.Name, $"info.Name for `{type}`"); + Assert.AreEqual (jniType, info2.Name, $"info2.Name for `{type}`"); Assert.AreEqual (arrayRank, info.ArrayRank, $"info.ArrayRank for `{type}`"); - Assert.AreEqual (arrayRank, info2.ArrayRank, $"info.ArrayRank for `{type}`"); + Assert.AreEqual (arrayRank, info2.ArrayRank, $"info2.ArrayRank for `{type}`"); } [Test]