From 3bd19e0d44c309b9c0347b3482ee528d6efbbf99 Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Thu, 29 Oct 2020 13:52:36 -0400 Subject: [PATCH] [Mono.Android] Generate Mono.Android.xml; @(JavaSourceJar) on JDK11 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://github.com/xamarin/xamarin-android/issues/4789 Context: https://github.com/xamarin/java.interop/pull/687 Context: https://github.com/xamarin/xamarin-android/issues/5200 What do we want? Updated documentation! How do we get that? Uh… Historically, [Xamarin.Android API docs][0] were produced by parsing Android's HTML documentation from `docs-24_r01.zip` and converting it into [**mdoc**(5) documentation][1] via [`tools/javadoc2mdoc`]. The problem is that Google hasn't released an updated `docs*.zip` package since API-24 (~6 years ago), and thus our documentation is woefully out of date. We could have scraped developer.android.com/reference within that time frame, but web scraping is annoying, and we'd still have to deal with the pain of parsing HTML. There is an alternative, though: with API-30, there is a new `sources` package which contains the Java source code used for the API level, which in turn contains Javadoc source code comments. Previous API levels similarly contained an `android-stubs-src.jar` file which likewise contained Java source code containing Javadoc comments. The new approach is to: 1. Update `build-tools/xaprepare` to install the `sources` package. 2. Use [`java-source-tool.jar`][2] to parse the Java source code, creating an `android-javadoc.xml` file. 3. [Update `generator`][3] to consume `android-javadoc.xml` and convert the Javadocs into [C# XML documentation comments][4]. 4. Update `src/Mono.Android` so that `generator` will emit C# XML doc comments, and then produce a `Mono.Android.xml` file. The result is a `Mono.Android.xml` file which contains imported Android Javadoc documentation, e.g. Mono.Android Class Object is the root of the class hierarchy. Class Object is the root of the class hierarchy. … "Later", `Mono.Android.xml` can then be used alongside [`mdoc update --import=Mono.Android.xml`][5] to update our published API documentation. Finally, commit 380e95e3, which added support for JDK 11, *broke* support for `@(JavaSourceJar)` when running under JDK 11, as JDK 11's Javadoc HTML output differs from what we expect. With the new `java-source-utils.jar` and `generator --with-javadoc-xml=FILE` infrastructure in place, we can reasonably address this breakage under JDK 11, fixing Issue #4789: Update `Xamarin.Android.Bindings.Core.targets` so that before invoking `generator`, we first run `java-source-utils.jar` on the `@(JavaSourceJar)` files, producing Javadoc XML files. The `` task in turn is updated to accept a new `BindingsGenerator.JavadocXml` property, which is converted into a `generator --with-javadoc-xml=FILE` option. The `@(JavaSourceJar)` item group is "extended" to support the following item metadata: * `%(CopyrightFile)`: A path to a file that contains copyright information for the Javadoc contents, which will be appended to all imported documentation. * `%(UrlPrefix)`: A URL prefix to support linking to online documentation within imported documentation. * `%(UrlStyle)`: The "style" of URLs to generate when linking to online documentation. Only one style is currently supported: `developer.android.com/reference@2020-Nov`. For .NET 6 ("One .NET") integration purposes, provide a default item group of `@(JavaSourceJar)` which includes `**\*-source?.jar` and `**\*-src.jar`. This will allow `dotnet build` of an "Android Java Library Binding" project (`dotnet new android-bindinglib`) to automatically process `.java` source code for documentation translation purposes. Add `Java.Interop.Tools.Generator.dll` to the `Microsoft.Android.Sdk*.nupkg` file, as it is an assembly dependency of `generator.dll`. (Not sure why this didn't previously fail…) Finally, add a new `$(_UseLegacyJavadocImport)` MSBuild property which *disables* use of `java-source-utils.jar` for Javadoc importing, and instead use the previous, legacy, doesn't work on JDK 11, approach of using `javadoc` and HTML parsing. This shouldn't be needed, but just in case it *is* needed… [0]: https://github.com/xamarin/android-api-docs [1]: http://docs.go-mono.com/?link=man%3amdoc(5) [2]: https://github.com/xamarin/java.interop/commit/69e1b80afd81ac502494e4bc2a2de75f5171c73f [3]: https://github.com/xamarin/java.interop/pull/687 [4]: https://docs.microsoft.com/dotnet/csharp/codedoc [5]: http://docs.go-mono.com/?link=man%3amdoc-update(1) --- .gitmodules | 4 +- Xamarin.Android.sln | 9 +- .../create-packs/Microsoft.Android.Sdk.proj | 1 + .../installers/create-installers.targets | 3 + .../Dependencies/AndroidToolchain.cs | 2 + .../ThirdPartyNotices/Java.Interop.cs | 13 ++ external/Java.Interop | 2 +- src/Mono.Android/Mono.Android.csproj | 11 ++ src/Mono.Android/Mono.Android.targets | 48 ++++- src/Mono.Android/javadoc-copyright.xml | 5 + .../Xamarin.Android.Bindings.Core.targets | 23 +++ ...rin.Android.Bindings.Documentation.targets | 10 +- .../Sdk/AutoImport.props | 3 +- .../Tasks/Generator.cs | 8 + .../Tasks/JavaSourceUtils.cs | 181 ++++++++++++++++++ .../BindingBuildTest.cs | 31 +-- .../Xamarin.Android.Build.Tests/XASdkTests.cs | 6 +- .../Xamarin.Android.McwGen-Tests.csproj | 4 + .../Xamarin.Android.McwGen-Tests.targets | 11 ++ .../android/DefaultMethodsInterface.java | 1 + 20 files changed, 333 insertions(+), 43 deletions(-) create mode 100644 src/Mono.Android/javadoc-copyright.xml create mode 100644 src/Xamarin.Android.Build.Tasks/Tasks/JavaSourceUtils.cs diff --git a/.gitmodules b/.gitmodules index 02c34fcbc01..f7ad716dd35 100644 --- a/.gitmodules +++ b/.gitmodules @@ -12,8 +12,8 @@ branch = master [submodule "external/Java.Interop"] path = external/Java.Interop - url = https://github.com/xamarin/java.interop.git - branch = master + url = https://github.com/jonpryor/java.interop.git + branch = jonp-generator-javadoc-xml [submodule "external/lz4"] path = external/lz4 url = https://github.com/lz4/lz4.git diff --git a/Xamarin.Android.sln b/Xamarin.Android.sln index 5f4525a319d..f672d86ece7 100644 --- a/Xamarin.Android.sln +++ b/Xamarin.Android.sln @@ -142,6 +142,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xamarin.SourceWriter", "ext EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "apksigner", "src\apksigner\apksigner.csproj", "{9A9EF774-6EA6-414F-9D2F-DCD66C56B92A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "java-source-utils", "external\Java.Interop\tools\java-source-utils\java-source-utils.csproj", "{37FCD325-1077-4603-98E7-4509CAD648D6}" +EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution src\Xamarin.Android.NamingCustomAttributes\Xamarin.Android.NamingCustomAttributes.projitems*{3f1f2f50-af1a-4a5a-bedb-193372f068d7}*SharedItemsImports = 4 @@ -376,7 +378,7 @@ Global {071D9096-65BB-4359-822E-09788439F210}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU {071D9096-65BB-4359-822E-09788439F210}.Debug|AnyCPU.Build.0 = Debug|Any CPU {071D9096-65BB-4359-822E-09788439F210}.Release|AnyCPU.ActiveCfg = Release|Any CPU - {071D9096-65BB-4359-822E-09788439F210}.Release|AnyCPU.Build.0 = Release|Any CPU EndGlobalSection + {071D9096-65BB-4359-822E-09788439F210}.Release|AnyCPU.Build.0 = Release|Any CPU {2CE4CD4B-B7B7-4EAE-A9BE-2699824D6096}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU {2CE4CD4B-B7B7-4EAE-A9BE-2699824D6096}.Debug|AnyCPU.Build.0 = Debug|Any CPU {2CE4CD4B-B7B7-4EAE-A9BE-2699824D6096}.Release|AnyCPU.ActiveCfg = Release|Any CPU @@ -389,6 +391,10 @@ Global {9A9EF774-6EA6-414F-9D2F-DCD66C56B92A}.Debug|AnyCPU.Build.0 = Debug|Any CPU {9A9EF774-6EA6-414F-9D2F-DCD66C56B92A}.Release|AnyCPU.ActiveCfg = Release|Any CPU {9A9EF774-6EA6-414F-9D2F-DCD66C56B92A}.Release|AnyCPU.Build.0 = Release|Any CPU + {37FCD325-1077-4603-98E7-4509CAD648D6}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU + {37FCD325-1077-4603-98E7-4509CAD648D6}.Debug|AnyCPU.Build.0 = Debug|Any CPU + {37FCD325-1077-4603-98E7-4509CAD648D6}.Release|AnyCPU.ActiveCfg = Release|Any CPU + {37FCD325-1077-4603-98E7-4509CAD648D6}.Release|AnyCPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -454,6 +460,7 @@ Global {2CE4CD4B-B7B7-4EAE-A9BE-2699824D6096} = {04E3E11E-B47D-4599-8AFC-50515A95E715} {86A8DEFE-7ABB-4097-9389-C249581E243D} = {04E3E11E-B47D-4599-8AFC-50515A95E715} {9A9EF774-6EA6-414F-9D2F-DCD66C56B92A} = {04E3E11E-B47D-4599-8AFC-50515A95E715} + {37FCD325-1077-4603-98E7-4509CAD648D6} = {864062D3-A415-4A6F-9324-5820237BA058} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {53A1F287-EFB2-4D97-A4BB-4A5E145613F6} diff --git a/build-tools/create-packs/Microsoft.Android.Sdk.proj b/build-tools/create-packs/Microsoft.Android.Sdk.proj index 9240ef79571..84034a5f427 100644 --- a/build-tools/create-packs/Microsoft.Android.Sdk.proj +++ b/build-tools/create-packs/Microsoft.Android.Sdk.proj @@ -76,6 +76,7 @@ core workload sdk packs imported by Microsoft.NET.Workload.Android. <_PackageFiles Include="$(ToolsSourceDir)**" PackagePath="tools" /> <_PackageFiles Include="$(NetCoreAppToolsSourceDir)generator.dll" PackagePath="tools" /> <_PackageFiles Include="$(NetCoreAppToolsSourceDir)generator.runtimeconfig.json" PackagePath="tools" /> + <_PackageFiles Include="$(NetCoreAppToolsSourceDir)Java.Interop.Tools.Generator.dll" PackagePath="tools" /> <_PackageFiles Include="$(NetCoreAppToolsSourceDir)javadoc-to-mdoc.dll" PackagePath="tools" /> <_PackageFiles Include="$(NetCoreAppToolsSourceDir)javadoc-to-mdoc.runtimeconfig.json" PackagePath="tools" /> <_PackageFiles Include="$(XAInstallPrefix)xbuild-frameworks\Microsoft.Android\Version*" PackagePath="tools" /> diff --git a/build-tools/installers/create-installers.targets b/build-tools/installers/create-installers.targets index dcc7c1e4ffa..90404e54e4f 100644 --- a/build-tools/installers/create-installers.targets +++ b/build-tools/installers/create-installers.targets @@ -132,6 +132,7 @@ <_MSBuildFiles Include="$(MSBuildSrcDir)\illinkanalyzer.pdb" ExcludeFromAndroidNETSdk="true" /> <_MSBuildFiles Include="$(MSBuildSrcDir)\Irony.dll" /> <_MSBuildFiles Include="$(MSBuildSrcDir)\java-interop.jar" /> + <_MSBuildFiles Include="$(MSBuildSrcDir)\java-source-utils.jar" /> <_MSBuildFiles Include="$(MSBuildSrcDir)\javadoc-to-mdoc.exe" ExcludeFromAndroidNETSdk="true" /> <_MSBuildFiles Include="$(MSBuildSrcDir)\javadoc-to-mdoc.pdb" ExcludeFromAndroidNETSdk="true" /> <_MSBuildFiles Include="$(MSBuildSrcDir)\Java.Interop.dll" /> @@ -149,6 +150,8 @@ <_MSBuildFiles Include="$(MSBuildSrcDir)\Java.Interop.Tools.Generator.pdb" ExcludeFromAndroidNETSdk="true" /> <_MSBuildFiles Include="$(MSBuildSrcDir)\Java.Interop.Tools.JavaCallableWrappers.dll" /> <_MSBuildFiles Include="$(MSBuildSrcDir)\Java.Interop.Tools.JavaCallableWrappers.pdb" /> + <_MSBuildFiles Include="$(MSBuildSrcDir)\Java.Interop.Tools.JavaSource.dll" /> + <_MSBuildFiles Include="$(MSBuildSrcDir)\Java.Interop.Tools.JavaSource.pdb" /> <_MSBuildFiles Include="$(MSBuildSrcDir)\Java.Runtime.Environment.dll" /> <_MSBuildFiles Include="$(MSBuildSrcDir)\Java.Runtime.Environment.pdb" /> <_MSBuildFiles Include="$(MSBuildSrcDir)\Java.Runtime.Environment.dll.config" Condition=" '$(HostOS)' != 'Windows' " /> diff --git a/build-tools/xaprepare/xaprepare/ConfigAndData/Dependencies/AndroidToolchain.cs b/build-tools/xaprepare/xaprepare/ConfigAndData/Dependencies/AndroidToolchain.cs index b2286001e72..6266f200528 100644 --- a/build-tools/xaprepare/xaprepare/ConfigAndData/Dependencies/AndroidToolchain.cs +++ b/build-tools/xaprepare/xaprepare/ConfigAndData/Dependencies/AndroidToolchain.cs @@ -62,6 +62,8 @@ public AndroidToolchain () new AndroidPlatformComponent ("platform-29_r01", apiLevel: "29", pkgRevision: "1"), new AndroidPlatformComponent ("platform-30_r01", apiLevel: "30", pkgRevision: "1"), + new AndroidToolchainComponent ("sources-30_r01", destDir: Path.Combine ("platforms", $"android-30", "src"), pkgRevision: "1", dependencyType: AndroidToolchainComponentType.BuildDependency), + new AndroidToolchainComponent ("docs-24_r01", destDir: "docs", pkgRevision: "1", dependencyType: AndroidToolchainComponentType.BuildDependency), new AndroidToolchainComponent ("android_m2repository_r47", destDir: Path.Combine ("extras", "android", "m2repository"), pkgRevision: "47.0.0", dependencyType: AndroidToolchainComponentType.BuildDependency), new AndroidToolchainComponent ($"x86_64-29_r07-{osTag}", destDir: Path.Combine ("system-images", "android-29", "default", "x86_64"), relativeUrl: new Uri ("sys-img/android/", UriKind.Relative), pkgRevision: "7", dependencyType: AndroidToolchainComponentType.EmulatorDependency), diff --git a/build-tools/xaprepare/xaprepare/ThirdPartyNotices/Java.Interop.cs b/build-tools/xaprepare/xaprepare/ThirdPartyNotices/Java.Interop.cs index c76d89ff01f..7128b63c9ca 100644 --- a/build-tools/xaprepare/xaprepare/ThirdPartyNotices/Java.Interop.cs +++ b/build-tools/xaprepare/xaprepare/ThirdPartyNotices/Java.Interop.cs @@ -12,6 +12,7 @@ class JavaInterop_External_Dependencies_Group : ThirdPartyNoticeGroup public override List Notices => new List { new JavaInterop_xamarin_Java_Interop_TPN (), new JavaInterop_gityf_crc_TPN (), + new JavaInterop_javaparser_javaparser_TPN (), new JavaInterop_jbevain_mono_linq_expressions_TPN (), new JavaInterop_mono_csharp_TPN (), new JavaInterop_mono_LineEditor_TPN (), @@ -69,6 +70,18 @@ POSSIBILITY OF SUCH DAMAGE. "; } + // via: https://github.com/xamarin/java.interop/blob/b588ef502d8d3b4c32e0ad731115e1b71fd56b5c/tools/java-source-utils/build.gradle#L33-L34 + class JavaInterop_javaparser_javaparser_TPN : ThirdPartyNotice + { + static readonly Uri url = new Uri ("https://github.com/javaparser/javaparser/"); + static readonly string licenseFile = Path.Combine (Configurables.Paths.ExternalJavaInteropDir, "LICENSE"); + + public override string LicenseFile => CommonLicenses.Apache20Path; + public override string Name => "javaparser/javaparser"; + public override Uri SourceUrl => url; + public override string LicenseText => String.Empty; + } + // git submodules of Java.Interop class JavaInterop_jbevain_mono_linq_expressions_TPN : ThirdPartyNotice { diff --git a/external/Java.Interop b/external/Java.Interop index 99897b24ead..ab032271e4b 160000 --- a/external/Java.Interop +++ b/external/Java.Interop @@ -1 +1 @@ -Subproject commit 99897b24eada3b68fa1eedae41efd15fbf128ae1 +Subproject commit ab032271e4b794976e170e5473e7f575202b0f58 diff --git a/src/Mono.Android/Mono.Android.csproj b/src/Mono.Android/Mono.Android.csproj index 0eb1e062cd0..8b8c905f285 100644 --- a/src/Mono.Android/Mono.Android.csproj +++ b/src/Mono.Android/Mono.Android.csproj @@ -24,6 +24,16 @@ true + + + True + + + + $(OutputPath)Mono.Android.xml + CS1573;CS1591 + + MonoAndroid v1.0 @@ -347,6 +357,7 @@ + diff --git a/src/Mono.Android/Mono.Android.targets b/src/Mono.Android/Mono.Android.targets index 76f9388fb5f..13343a093f3 100644 --- a/src/Mono.Android/Mono.Android.targets +++ b/src/Mono.Android/Mono.Android.targets @@ -53,6 +53,50 @@ Replacements="@PACKAGE_VERSION@=$(_PackageVersion);@PACKAGE_VERSION_BUILD@=$(_PackageVersionBuild);@PACKAGE_HEAD_REV@=$(XAVersionHash);@PACKAGE_HEAD_BRANCH@=$(XAVersionBranch)"> + + <_JavaSourceUtilsJar>$(XAInstallPrefix)xbuild\Xamarin\Android\java-source-utils.jar + <_AndroidStableSrcDir>$(AndroidSdkDirectory)\platforms\android-$(AndroidLatestStableApiLevel)\src + <_AndroidJavadocXml>..\..\bin\Build$(Configuration)\android-javadoc.xml + + + + <_Doclink Include="--doc-copyright" /> + <_Doclink Include="$(MSBuildThisFileDirectory)javadoc-copyright.xml" /> + <_Doclink Include="--doc-url-prefix" /> + <_Doclink Include="https://developer.android.com/reference" /> + <_Doclink Include="--doc-url-style" /> + <_Doclink Include="developer.android.com/reference@2020-Nov" /> + + + <_AndroidSources Include="$(_AndroidStableSrcDir)\android\**\*.java" /> + <_AndroidSources Include="$(_AndroidStableSrcDir)\java\**\*.java" /> + <_AndroidSources Include="$(_AndroidStableSrcDir)\javax\**\*.java" /> + <_AndroidSources Include="$(_AndroidStableSrcDir)\org\**\*.java" /> + <_AndroidSources Remove="$(_AndroidStableSrcDir)\**\*.annotated.java" /> + + + <_Filenames>$(IntermediateOutputPath)\java-sources.txt + + + + <_JSIArg Include="-v" /> + <_JSIArg Include="--source "$(_AndroidStableSrcDir)"" /> + <_JSIArg Include="--output-javadoc "$(_AndroidJavadocXml)"" /> + <_JSIArg Include="@$(_Filenames)" /> + + + + --type-map-report=$(IntermediateOutputPath)mcw\type-mapping.txt <_Api>$(IntermediateOutputPath)mcw\api.xml <_Dirs>--enumdir=$(IntermediateOutputPath)mcw + <_WithJavadocXml Condition=" '$(IncludeAndroidJavadoc)' == 'True' ">"--with-javadoc-xml=$(_AndroidJavadocXml)" <_FullIntermediateOutputPath>$([System.IO.Path]::GetFullPath('$(IntermediateOutputPath)')) <_LangFeatures>--lang-features=nullable-reference-types <_LangFeatures Condition="$(AndroidApiLevel) >= 30">$(_LangFeatures),default-interface-methods,nested-interface-types,interface-constants diff --git a/src/Mono.Android/javadoc-copyright.xml b/src/Mono.Android/javadoc-copyright.xml new file mode 100644 index 00000000000..7bca1d75e90 --- /dev/null +++ b/src/Mono.Android/javadoc-copyright.xml @@ -0,0 +1,5 @@ +Portions of this page are modifications based on work created and shared by the +Android Open Source Project + and used according to terms described in the +Creative Commons 2.5 Attribution License. + diff --git a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.Core.targets b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.Core.targets index 39e0400c9b3..acb671c4b8a 100644 --- a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.Core.targets +++ b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.Core.targets @@ -12,6 +12,7 @@ It is shared between "legacy" binding projects and .NET 5 projects. + @@ -21,6 +22,11 @@ It is shared between "legacy" binding projects and .NET 5 projects. <_GeneratorStampFile>$(IntermediateOutputPath)generator.stamp + + $(OutputPath)\$(AssemblyName).xml + $(NoWarn);CS1573;CS1591 + + @@ -42,6 +48,22 @@ It is shared between "legacy" binding projects and .NET 5 projects. + + + + - - <_JavadocSupported Condition=" $(_JdkVersion.StartsWith ('1.8')) ">True - - - + + diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/Generator.cs b/src/Xamarin.Android.Build.Tasks/Tasks/Generator.cs index f055c95b478..213205f14c2 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/Generator.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/Generator.cs @@ -52,6 +52,8 @@ public class BindingsGenerator : AndroidDotnetToolTask public ITaskItem[] ReferencedManagedLibraries { get; set; } public ITaskItem[] AnnotationsZipFiles { get; set; } + public ITaskItem[] JavadocXml { get; set; } + private List> transform_files = new List> (); public override bool RunTask () @@ -166,6 +168,12 @@ protected override string GenerateCommandLineCommands () if (EnableInterfaceMembersPreview && SupportsCSharp8) WriteLine (sw, "--lang-features=interface-constants,default-interface-methods"); + + if (JavadocXml != null) { + foreach (var xml in JavadocXml) { + WriteLine (sw, $"--with-javadoc-xml=\"{Path.GetFullPath (xml.ItemSpec)}\""); + } + } } cmd.AppendSwitch (ApiXmlInput); diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/JavaSourceUtils.cs b/src/Xamarin.Android.Build.Tasks/Tasks/JavaSourceUtils.cs new file mode 100644 index 00000000000..c8fb877e606 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Tasks/JavaSourceUtils.cs @@ -0,0 +1,181 @@ +// Copyright (C) 2012 Xamarin, Inc. All rights reserved. + +using System; +using System.Linq; +using System.IO; +using System.Reflection; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using Xamarin.Android.Tools; + +namespace Xamarin.Android.Tasks +{ + public class JavaSourceUtils : AndroidToolTask + { + public override string TaskPrefix => "JSU"; + + [Required] + public string MonoAndroidToolsDirectory { get; set; } + + [Required] + public string JavaSdkDirectory { get; set; } + + [Required] + public ITaskItem OutputDirectory { get; set; } + + [Required] + public ITaskItem[] InputFiles { get; set; } + + public ITaskItem[] References { get; set; } + + public ITaskItem[] BootClassPath { get; set; } + + public ITaskItem JavadocCopyrightFile { get; set; } + public string JavadocUrlPrefix { get; set; } + public string JavadocUrlStyle { get; set; } + + public string JavaOptions { get; set; } + + public string JavaMaximumHeapSize { get; set; } + + [Output] + public ITaskItem OutputJavadocXml { get; set; } + + string responseFilePath; + + public override bool RunTask () + { + if (InputFiles == null || InputFiles.Count () == 0) { + Log.LogCodedError ("XA1020", Properties.Resources.XA1020); + return false; + } + + if (References != null) + foreach (var path in References) + if (!Directory.Exists (path.ItemSpec) && !File.Exists (path.ItemSpec)) + Log.LogCodedError ("XA1022", Properties.Resources.XA1022, path.ItemSpec); + + if (Log.HasLoggedErrors) + return false; + + OutputJavadocXml = new TaskItem (Path.Combine (OutputDirectory.ItemSpec, GetOutputFileName (InputFiles)) + ".xml"); + + try { + return base.RunTask (); + } + finally { + File.Delete (responseFilePath); + } + } + + static string GetOutputFileName (ITaskItem[] items) => + Files.HashString ( + string.Join ("\n", items.Select (item => Path.GetFullPath (item.ItemSpec).Replace ('\\', '/')))); + + + protected override string GenerateCommandLineCommands () + { + responseFilePath = CreateResponseFile (); + + var cmd = new CommandLineBuilder (); + + // Add the JavaOptions if they are not null + // These could be any of the additional options + if (!string.IsNullOrEmpty (JavaOptions)) { + cmd.AppendSwitch (JavaOptions); + } + + if (!string.IsNullOrEmpty (JavaMaximumHeapSize)) { + cmd.AppendSwitchIfNotNull("-Xmx", JavaMaximumHeapSize); + } + + // Arguments sent to java.exe + cmd.AppendSwitchIfNotNull ("-jar ", Path.Combine (MonoAndroidToolsDirectory, "java-source-utils.jar")); + + cmd.AppendSwitch ($"@{responseFilePath}"); + + + return cmd.ToString (); + } + + string CreateResponseFile () + { + var responseFile = Path.GetTempFileName (); + + using var response = new StreamWriter (responseFile, append: false, encoding: MonoAndroidHelper.UTF8withoutBOM); + Log.LogDebugMessage ("[java-source-utils] response file contents: {0}", responseFile); + + if (BootClassPath != null && BootClassPath.Any ()) { + var classpath = string.Join (Path.PathSeparator.ToString (), BootClassPath.Select (p => Path.GetFullPath (p.ItemSpec))); + AppendArg (response, "--bootclasspath"); + AppendArg (response, classpath); + } + + if (References != null && References.Any ()) { + foreach (var r in References) { + if (Directory.Exists (r.ItemSpec)) { + AppendArg (response, "--source"); + AppendArg (response, Path.GetFullPath (r.ItemSpec)); + continue; + } + if (!File.Exists (r.ItemSpec)) { + Log.LogCodedError ("XA1022", Properties.Resources.XA1022, r.ItemSpec); + continue; + } + if (r.ItemSpec.EndsWith (".jar", StringComparison.OrdinalIgnoreCase)) { + AppendArg (response, "--jar"); + AppendArg (response, Path.GetFullPath (r.ItemSpec)); + continue; + } + if (r.ItemSpec.EndsWith (".aar", StringComparison.OrdinalIgnoreCase)) { + AppendArg (response, "--aar"); + AppendArg (response, Path.GetFullPath (r.ItemSpec)); + continue; + } + Log.LogError ($"Unsupported @(Reference) item: {r.ItemSpec}"); + } + } + AppendArg (response, "--output-javadoc"); + AppendArg (response, OutputJavadocXml.ItemSpec); + + if (!string.IsNullOrEmpty (JavadocCopyrightFile?.ItemSpec)) { + AppendArg (response, "--doc-copyright"); + AppendArg (response, Path.GetFullPath (JavadocCopyrightFile.ItemSpec)); + } + if (!string.IsNullOrEmpty (JavadocUrlPrefix)) { + AppendArg (response, "--doc-url-prefix"); + AppendArg (response, Path.GetFullPath (JavadocUrlPrefix)); + } + if (!string.IsNullOrEmpty (JavadocUrlStyle)) { + AppendArg (response, "--doc-link-style"); + AppendArg (response, Path.GetFullPath (JavadocUrlStyle)); + } + + foreach (var path in InputFiles) { + AppendArg (response, Path.GetFullPath (path.ItemSpec)); + } + + return responseFile; + + void AppendArg (TextWriter writer, string line) + { + writer.WriteLine (line); + Log.LogDebugMessage (line); + } + } + + protected override string ToolName { + get => "java-source-utils"; + } + + public override string ToolExe { + get { return OS.IsWindows ? "java.exe" : "java"; } + set { base.ToolExe = value; } + } + + protected override string GenerateFullPathToTool () + { + return Path.Combine (JavaSdkDirectory, "bin", ToolExe); + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BindingBuildTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BindingBuildTest.cs index fb638b52ef2..1accb8bda3d 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BindingBuildTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BindingBuildTest.cs @@ -452,36 +452,11 @@ public void JavaSourceJar () BinaryContent = () => Convert.FromBase64String (InlineData.JavaSourcesJarBase64) }); Assert.IsTrue (bindingBuilder.Build (binding), "binding build should have succeeded"); - var jdkVersion = GetJdkVersion (); - if (jdkVersion > new Version (9, 0)) { - Assert.Ignore ("JDK 11 and @(JavaSourceJar) don't currently mix."); - return; - } - string xml = bindingBuilder.Output.GetIntermediaryAsText ("docs/Com.Xamarin.Android.Test.Msbuildtest/JavaSourceJarTest.xml"); - Assert.IsTrue (xml.Contains (" - name to display."), "missing doc"); - } - } - static Version GetJdkVersion () - { - var jdkPath = AndroidSdkResolver.GetJavaSdkPath (); - var releasePath = Path.Combine (jdkPath, "release"); - if (!File.Exists (releasePath)) - return null; - foreach (var line in File.ReadLines (releasePath)) { - const string JavaVersionStart = "JAVA_VERSION=\""; - if (!line.StartsWith (JavaVersionStart, StringComparison.OrdinalIgnoreCase)) - continue; - var value = line.Substring (JavaVersionStart.Length, line.Length - JavaVersionStart.Length - 1); - int last = 0; - for (last = 0; last < value.Length; ++last) { - if (char.IsDigit (value, last) || value [last] == '.') - continue; - break; - } - return Version.Parse (last == value.Length ? value : value.Substring (0, last)); + var path = Path.Combine (Root, bindingBuilder.ProjectDirectory, binding.OutputPath, "UnnamedProject.xml"); + var xml = File.ReadAllText (path); + Assert.IsTrue (xml.Contains ("name to display."), "param `name` documentation not imported!"); } - return null; } [Test] diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs index c69821c5e00..ab69d178fc5 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs @@ -369,12 +369,14 @@ public void DotNetBuild (string runtimeIdentifiers, bool isRelease) .Select (Path.GetFileName) .OrderBy (f => f) .ToArray (); - CollectionAssert.AreEqual (new [] { + var expectedFiles = new[]{ $"{proj.ProjectName}.dll", $"{proj.ProjectName}.pdb", + $"{proj.ProjectName}.xml", $"{proj.PackageName}.apk", $"{proj.PackageName}-Signed.apk", - }, files); + }; + CollectionAssert.AreEqual (expectedFiles, files, $"Expected: {string.Join (";", expectedFiles)}\n Found: {string.Join (";", files)}"); var assemblyPath = Path.Combine (outputPath, $"{proj.ProjectName}.dll"); FileAssert.Exists (assemblyPath); diff --git a/tests/CodeGen-Binding/Xamarin.Android.McwGen-Tests/Xamarin.Android.McwGen-Tests.csproj b/tests/CodeGen-Binding/Xamarin.Android.McwGen-Tests/Xamarin.Android.McwGen-Tests.csproj index 0e59e81a532..d7e1255318f 100644 --- a/tests/CodeGen-Binding/Xamarin.Android.McwGen-Tests/Xamarin.Android.McwGen-Tests.csproj +++ b/tests/CodeGen-Binding/Xamarin.Android.McwGen-Tests/Xamarin.Android.McwGen-Tests.csproj @@ -142,6 +142,9 @@ + + + @@ -149,6 +152,7 @@ BuildTestJarFile; _CopyTestJarFiles; + _CreateJavaSourceJar; $(BuildDependsOn) diff --git a/tests/CodeGen-Binding/Xamarin.Android.McwGen-Tests/Xamarin.Android.McwGen-Tests.targets b/tests/CodeGen-Binding/Xamarin.Android.McwGen-Tests/Xamarin.Android.McwGen-Tests.targets index 72f6f5c59bf..45a38d3fd96 100644 --- a/tests/CodeGen-Binding/Xamarin.Android.McwGen-Tests/Xamarin.Android.McwGen-Tests.targets +++ b/tests/CodeGen-Binding/Xamarin.Android.McwGen-Tests/Xamarin.Android.McwGen-Tests.targets @@ -6,7 +6,18 @@ DestinationFolder="$(OutputPath)" /> + + + + + diff --git a/tests/CodeGen-Binding/Xamarin.Android.McwGen-Tests/java/com/xamarin/android/DefaultMethodsInterface.java b/tests/CodeGen-Binding/Xamarin.Android.McwGen-Tests/java/com/xamarin/android/DefaultMethodsInterface.java index 1323f0c5c4b..04f2af75255 100644 --- a/tests/CodeGen-Binding/Xamarin.Android.McwGen-Tests/java/com/xamarin/android/DefaultMethodsInterface.java +++ b/tests/CodeGen-Binding/Xamarin.Android.McwGen-Tests/java/com/xamarin/android/DefaultMethodsInterface.java @@ -1,5 +1,6 @@ package com.xamarin.android; +/** An interface which contains interface default methods. */ public interface DefaultMethodsInterface { default int foo () { return 0; }