diff --git a/Directory.Build.props b/Directory.Build.props index 5da999fb1..c132f796b 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -47,7 +47,7 @@ False False - obj\ + $(MSBuildProjectDirectory)\obj\ diff --git a/src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs b/src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs index 1ce3e6543..4102c498e 100644 --- a/src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs +++ b/src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs @@ -307,7 +307,7 @@ static Type GetPeerType ([DynamicallyAccessedMembers (Constructors)] Type type) } targetType = targetType ?? typeof (JavaObject); - targetType = GetPeerType (targetType); + targetType = GetPeerType(targetType); if (!typeof (IJavaPeerable).IsAssignableFrom (targetType)) throw new ArgumentException ($"targetType `{targetType.AssemblyQualifiedName}` must implement IJavaPeerable!", nameof (targetType)); @@ -359,8 +359,8 @@ static Type GetPeerType ([DynamicallyAccessedMembers (Constructors)] Type type) if (!JniTypeSignature.TryParse (jniTypeName, out sig)) return null; - Type? type = GetTypeAssignableTo (sig, targetType); - if (type != null) { + Type? type = GetBestTypeForSignature (sig); + if (type != null && type.IsAssignableTo(targetType)) { var peer = TryCreatePeerInstance (ref reference, transfer, type); if (peer != null) { @@ -379,18 +379,57 @@ static Type GetPeerType ([DynamicallyAccessedMembers (Constructors)] Type type) } JniObjectReference.Dispose (ref klass, JniObjectReferenceOptions.CopyAndDispose); + // If we have nothing in the hierarchy, assume caller knows best and create targetType return TryCreatePeerInstance (ref reference, transfer, targetType); + [UnconditionalSuppressMessage ("Trimming", "IL2073", Justification = "Types returned here should be preserved via other means.")] [return: DynamicallyAccessedMembers (Constructors)] - Type? GetTypeAssignableTo (JniTypeSignature sig, Type targetType) + Type? GetBestTypeForSignature (JniTypeSignature sig) { - foreach (var t in Runtime.TypeManager.GetTypes (sig)) { - if (targetType.IsAssignableFrom (t)) { - return t; + string[] sdkAssemblyNames = ["Mono.Android", "Java.Base", "Java.Interop"]; + // Find single best instance + Type? best = null; + foreach (Type type in Runtime.TypeManager.GetTypes (sig)) { + if (best is null) { + best = type; + continue; + } + if (type == best) + continue; + // Types in sdk assemblies should be first in the list + if ((uint)Array.IndexOf(sdkAssemblyNames, best.Module.Assembly.GetName ().Name) > + (uint)Array.IndexOf(sdkAssemblyNames, type.Module.Assembly.GetName ().Name)) { + best = type; + continue; + } + // We found the `Invoker` type *before* the declared type + // Fix things up so the abstract type is first, and the `Invoker` is considered a duplicate. + if ((type.IsAbstract || type.IsInterface) && + !best.IsAbstract && + !best.IsInterface && + type.IsAssignableFrom (best)) { + best = type; + continue; + } + + // If the type is a derived type of the current best, then it is better + if (type.IsAssignableTo(best)) + { + best = type; + continue; + } + + // we found a generic subclass of a non-generic type + if (type.IsGenericType && + !best.IsGenericType && + type.IsAssignableTo (best)) { + best = type; + continue; } } - return null; + + return best; } } diff --git a/src/java-interop/java-interop.targets b/src/java-interop/java-interop.targets index 9d35aaa47..fad633f88 100644 --- a/src/java-interop/java-interop.targets +++ b/src/java-interop/java-interop.targets @@ -35,13 +35,13 @@ - <_MonoNativePath>$(NuGetPackageRoot)microsoft.netcore.app.runtime.mono.$(NETCoreSdkRuntimeIdentifier)/$(DotNetRuntimePacksVersion)/runtimes/$(NETCoreSdkRuntimeIdentifier)/native/ + <_MonoNativePath>$(NuGetPackageRoot)\microsoft.netcore.app.runtime.mono.$(NETCoreSdkRuntimeIdentifier)/$(DotNetRuntimePacksVersion)/runtimes/$(NETCoreSdkRuntimeIdentifier)/native/ <_MonoIncludePath>$(_MonoNativePath)include/mono-2.0 <_DEnableMono>-DENABLE_MONO_INTEGRATION=ON <_DEnableOsxArchitectures Condition=" $([MSBuild]::IsOSPlatform ('osx')) ">"-DENABLE_OSX_ARCHITECTURES=$(_CmakeOsxArch)" <_DMonoDirs>"-DMONO_INCLUDE_LIST=$(_MonoIncludePath)" <_DJdkDirs>"-DJDK_INCLUDE_LIST=@(JdkIncludePath, ';')" - <_DJni_c>"-DJNI_C_PATH=$(MSBuildThisFileDirectory)$(IntermediateOutputPath)jni.c" + <_DJni_c>"-DJNI_C_PATH=$(IntermediateOutputPath)jni.c" <_MonoLinkFlags Condition=" $([MSBuild]::IsOSPlatform ('windows')) " >$(MSBuildThisFileDirectory)coreclr.lib <_MonoLinkFlags Condition=" !$([MSBuild]::IsOSPlatform ('windows')) ">-L $(_MonoNativePath) -lcoreclr <_DMonoLinkFlags>"-DMONO_LINK_FLAGS=$(_MonoLinkFlags)" @@ -71,7 +71,7 @@ <_Cmake Include="CmakePath=$(CmakePath)" /> <_Cmake Include="CmakeGenerator=$(CmakeGenerator)" /> <_Cmake Include="CmakeSourceDir=$(MSBuildThisFileDirectory)" /> - <_Cmake Include="CmakeBuildDir=$(MSBuildThisFileDirectory)$(IntermediateOutputPath)" /> + <_Cmake Include="CmakeBuildDir=$(IntermediateOutputPath)" /> <_Cmake Include="CmakeExtraArgs=$(_ExtraArgs)" /> - + Inputs="$(MSBuildThisFileDirectory)coreclr.def" + Outputs="$(MSBuildThisFileDirectory)coreclr.lib"> + <_Cmake Include="CmakeGenerator=$(CmakeGenerator)" /> <_Cmake Include="CmakeSourceDir=$(MSBuildThisFileDirectory)" /> - <_Cmake Include="CmakeBuildDir=$(MSBuildThisFileDirectory)$(IntermediateOutputPath)%(_NativeTimingLib.Dir)" /> + <_Cmake Include="CmakeBuildDir=$(IntermediateOutputPath)%(_NativeTimingLib.Dir)" /> <_Cmake Include="CmakeExtraArgs=$(_JdkDirs)" />