Skip to content

Commit c5bb33b

Browse files
committed
[Mono.Android] Define JavaCollection before ICollection (#741)
Fixes: https://bugzilla.xamarin.com/show_bug.cgi?id=58303 Background: It is possible for a Java type to have "aliasing bindings": two or more managed types which claim to bind the same Java type: // C# namespace Android.Runtime { [Register ("java/util/HashMap", DoNotRegisterAcw=true)] partial class JavaDictionary { } } namespace Java.Util { [Register ("java/util/HashMap", DoNotRegisterAcw=true)] partial class HashMap { } } These can't be realistically forbidden. Enter a new-to-bind Java type: // Java public class Bxc58383 extends java.util.HashMap implements java.util.Map { } In order to bind the above `Bxc58383` type, `generator` needs to determine the appropriate binding type to use for `java.util.HashMap`. `generator`'s approach to supporting aliasing types is (largely) to ignore the problem (almost) entirely: There Can Be Only One™ mapping from a Java type to a managed type, so `generator` needs to pick one. It does so by using the *last* definition encountered in the assembly. Consequently, for the above set of C# declarations, when `generator` needs to find the managed type which binds `java.util.HashMap`, `Java.Util.HashMap` will be chosen, as it is the last declared type. Unfortunately, "real life" is a bit more complicated: `Mono.Android.dll` is made up of *thousands* of files, and the order of types within an assembly is a compiler implementation detail. As such...the current `Mono.Android.dll` has `JavaDictionary` defined *after* `HashMap`: # output truncated for relevance $ monodis --typedef bin/Debug/lib/xamarin.android/xbuild-frameworks/MonoAndroid/v7.1/Mono.Android.dll | grep 'Dictionary\|HashMap' 1270: Java.Util.Dictionary (flist=12611, mlist=29569, flags=0x100081, extends=0x20b8) 1287: Java.Util.HashMap (flist=12662, mlist=29806, flags=0x100001, extends=0x1388) 3992: Android.Runtime.JavaDictionary (flist=32135, mlist=85344, flags=0x100001, extends=0x20b8) Because `JavaDictionary` is defined *after* `HashMap`, and both of those types have `[Register]` attributes which declare that they bind the *same* Java type, the result is that the binding of `Bxc58383` is horrifically broken: // C# partial class Bxc58383 : global::Android.Runtime.JavaDictionary, global::Java.Util.IMap { } Unfortunately, `JavaDictionary` doesn't itself implement `IMap`, so: error CS0535: 'Bxc58383' does not implement interface member 'IMap.ContainsKey(Object)' along with 10 other related errors. Update the `src/Mono.Android` build process so that `JavaDictionary` and related types will be defined within `Mono.Android.dll` *before* all the generated types. This allows `HashMap` to be defined last, allowing `Bxc58383` to be bound without error: # output truncated $ monodis --typedef bin/Debug/lib/xamarin.android/xbuild-frameworks/MonoAndroid/v7.1/Mono.Android.dll | grep 'Dictionary\|HashMap' 3703: Android.Runtime.JavaDictionary (flist=34089, mlist=78134, flags=0x100001, extends=0x4e08) 4170: Java.Util.Dictionary (flist=39685, mlist=91737, flags=0x100081, extends=0x4e08) 4187: Java.Util.HashMap (flist=39736, mlist=91974, flags=0x100001, extends=0x40d8)
1 parent 1861a89 commit c5bb33b

File tree

3 files changed

+22
-14
lines changed

3 files changed

+22
-14
lines changed

src/Mono.Android/Mono.Android.csproj

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,20 @@
7575
<Private>False</Private>
7676
</Reference>
7777
</ItemGroup>
78+
<Import Project="$(JavaInteropFullPath)\src\Java.Interop.Tools.TypeNameMappings\Java.Interop.Tools.TypeNameMappings.projitems" Label="Shared" Condition="Exists('$(JavaInteropFullPath)\src\Java.Interop.Tools.TypeNameMappings\Java.Interop.Tools.TypeNameMappings.projitems')" />
79+
<Import Project="..\Xamarin.Android.NamingCustomAttributes\Xamarin.Android.NamingCustomAttributes.projitems" Label="Shared" Condition="Exists('..\Xamarin.Android.NamingCustomAttributes\Xamarin.Android.NamingCustomAttributes.projitems')" />
80+
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
81+
<PropertyGroup>
82+
<ImplicitlyExpandDesignTimeFacades>False</ImplicitlyExpandDesignTimeFacades>
83+
<IntermediateOutputPath>$(IntermediateOutputPath)android-$(AndroidApiLevel)\</IntermediateOutputPath>
84+
</PropertyGroup>
85+
<Import Project="Mono.Android.targets" />
86+
<PropertyGroup>
87+
<JavaCallableWrapperAbsAssembly>$([System.IO.Path]::GetFullPath ('$(OutputPath)$(AssemblyName).dll'))</JavaCallableWrapperAbsAssembly>
88+
<JavaCallableWrapperAfterTargets>CoreBuild</JavaCallableWrapperAfterTargets>
89+
</PropertyGroup>
90+
<Import Project="..\..\build-tools\scripts\JavaCallableWrappers.targets" />
91+
<Import Project="$(IntermediateOutputPath)mcw\Mono.Android.projitems" Condition="Exists('$(IntermediateOutputPath)mcw\Mono.Android.projitems')" />
7892
<ItemGroup>
7993
<Compile Include="Android\IncludeAndroidResourcesFromAttribute.cs" />
8094
<Compile Include="Android\LinkerSafeAttribute.cs" />
@@ -311,20 +325,6 @@
311325
<Compile Include="Xamarin.Android.Net\AuthModuleDigest.cs" />
312326
<Compile Include="Xamarin.Android.Net\IAndroidAuthenticationModule.cs" />
313327
</ItemGroup>
314-
<Import Project="$(JavaInteropFullPath)\src\Java.Interop.Tools.TypeNameMappings\Java.Interop.Tools.TypeNameMappings.projitems" Label="Shared" Condition="Exists('$(JavaInteropFullPath)\src\Java.Interop.Tools.TypeNameMappings\Java.Interop.Tools.TypeNameMappings.projitems')" />
315-
<Import Project="..\Xamarin.Android.NamingCustomAttributes\Xamarin.Android.NamingCustomAttributes.projitems" Label="Shared" Condition="Exists('..\Xamarin.Android.NamingCustomAttributes\Xamarin.Android.NamingCustomAttributes.projitems')" />
316-
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
317-
<PropertyGroup>
318-
<ImplicitlyExpandDesignTimeFacades>False</ImplicitlyExpandDesignTimeFacades>
319-
<IntermediateOutputPath>$(IntermediateOutputPath)android-$(AndroidApiLevel)\</IntermediateOutputPath>
320-
</PropertyGroup>
321-
<Import Project="Mono.Android.targets" />
322-
<PropertyGroup>
323-
<JavaCallableWrapperAbsAssembly>$([System.IO.Path]::GetFullPath ('$(OutputPath)$(AssemblyName).dll'))</JavaCallableWrapperAbsAssembly>
324-
<JavaCallableWrapperAfterTargets>CoreBuild</JavaCallableWrapperAfterTargets>
325-
</PropertyGroup>
326-
<Import Project="..\..\build-tools\scripts\JavaCallableWrappers.targets" />
327-
<Import Project="$(IntermediateOutputPath)mcw\Mono.Android.projitems" Condition="Exists('$(IntermediateOutputPath)mcw\Mono.Android.projitems')" />
328328
<ItemGroup>
329329
<ProjectReference Include="..\..\build-tools\api-merge\api-merge.csproj">
330330
<Project>{3FC3E78B-F7D4-42EA-BBE8-4535DF42BFF8}</Project>

tests/CodeGen-Binding/Xamarin.Android.McwGen-Tests/Xamarin.Android.McwGen-Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
</ItemGroup>
7777
<ItemGroup>
7878
<XamarinTestJar Include="java\com\xamarin\android\Bxc4288.java" />
79+
<XamarinTestJar Include="java\com\xamarin\android\Bxc58383.java" />
7980
<XamarinTestJar Include="java\com\xamarin\android\CallMethodFromCtor.java" />
8081
<XamarinTestJar Include="java\com\xamarin\android\CallNonvirtualBase.java" />
8182
<XamarinTestJar Include="java\com\xamarin\android\CallNonvirtualDerived.java" />
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.xamarin.android;
2+
3+
public class Bxc58383
4+
extends java.util.HashMap
5+
implements java.util.Map
6+
{
7+
}

0 commit comments

Comments
 (0)