Skip to content

Commit a65d6fb

Browse files
authored
[Java.Base, generator] Bind all of package java.lang (#966)
Context: bc5bcf4 Bind all classes and interfaces in the `java.lang` package. Alter Java array binding, so that instead of `IList<T>`, we get "direct" Java arrays, e.g. namespace Java.Lang { partial class Character { // Previous/Xamarin.Android-like public static int CodePointAt (IList<char>? a, int index); // New/Desktop public static int CodePointAt (JavaCharArray? a, int index); } } Rationale: it *allows* for more efficient JVM :: .NET array copying, by making copies explicit (to the dev), not implicit. We can add an implicit conversion from e.g. `IEnumerable<char>` to `JavaCharArray` in the future, if deemed useful. This also impacts method return types, properties, and fields. Bind the `java.lang.module` package in the namespace `Java.Lang.Modules`. This is to avoid a type/namespace conflict with `java.lang.Module`, bound as `Java.Lang.Module`. Continue updating `generator` to remove "Android-isms". Update `Java.Base.csproj` to ignore [warning CS0108][0]: Java.Lang.Reflect.IAnnotatedArrayType.cs(15,45): warning CS0108: 'IAnnotatedArrayType.AnnotatedOwnerType' hides inherited member 'IAnnotatedType.AnnotatedOwnerType'. Use the new keyword if hiding was intended. The problem here is that we have: public partial interface IAnnotatedType { // Contains default interface method virtual unsafe IAnnotatedType? AnnotatedOwnerType => …; } public partial interface IAnnotatedArrayType : IAnnotatedType { // Contains *no* method body; re-abstracted IAnnotatedType? AnnotatedOwnerType {get;} } TODO: figure out how to properly fix this. `managedOverride` metadata (5a0e37e) doesn't seem useful to "re-abstract" a default interface member. Update `Java.Base.targets` to use `generator --global`. This is so that `java.lang.System` can be bound as `Java.Lang.System` without causing various C# compilation errors due to type lookup. (Compare to Xamarin.Android's `Java.Lang.JavaSystem`, which got a `Java*` prefix to avoid these compilation errors.) Update `JavaInteropCodeGeneratorTests.CreateOptions()` so that C# features such as default interface methods and nested interface types are enabled within the unit tests. TODO: * When `generator --codegen-target=JavaInterop1` is used, all the language features should also be enabled by default. * Certain Java Annotation-related types aren't bound in JavaInterop1, vs. XAJavaInterop1. Revisit this. * "Revisit" use of `JNIEnv.ToLocalJniHandle()` in Xamarin.Android bindings, and it's outright removal in JavaInterop1 bindings. @jonpryor *thinks* the `JNIENv.ToLocalJniHandle(v)` was introduced "in case" `v` would be collected by the GC "during" a JNI call. Use of `GC.KeepAlive()` (1f21f38, da73d6a), would be a better solution, but also requires auditing `generator` output. * Bind the rest of `java.base.jmod` (bc5bcf4). [0]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-messages/cs0108
1 parent ed9c2ab commit a65d6fb

File tree

70 files changed

+954
-316
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+954
-316
lines changed

src/Java.Base/Java.Base.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
<TargetFrameworks>net6.0</TargetFrameworks>
55
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
66
<Nullable>enable</Nullable>
7-
<NoWarn>$(NoWarn);8764</NoWarn>
7+
<!-- TODO: CS0108 is due to e.g. interfaces re-abstracting default interface methods -->
8+
<NoWarn>$(NoWarn);8764;CS0108</NoWarn>
89
<Version>$(JICoreLibVersion)</Version>
910
</PropertyGroup>
1011

src/Java.Base/Java.Base.targets

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
<MakeDir Directories="$(IntermediateOutputPath)mcw" />
4545
<PropertyGroup>
4646
<Generator>"$(GeneratorPath)"</Generator>
47-
<_GenFlags>--public</_GenFlags>
47+
<_GenFlags>--public --global</_GenFlags>
4848
<_Out>-o "$(IntermediateOutputPath)mcw"</_Out>
4949
<_Codegen>--codegen-target=JavaInterop1</_Codegen>
5050
<_Fixup>--fixup=Transforms/Metadata.xml</_Fixup>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
namespace Java.Lang {
2+
3+
public static partial class ICharSequenceExtensions {
4+
5+
public static ICharSequence[]? ToCharSequenceArray (this string?[]? values)
6+
{
7+
if (values == null) {
8+
return null;
9+
}
10+
var array = new ICharSequence [values.Length];
11+
for (int i = 0; i < values.Length; ++i) {
12+
if (values [i] == null) {
13+
continue;
14+
}
15+
array [i] = new Java.Lang.String (values [i]);
16+
}
17+
return array;
18+
}
19+
}
20+
}

src/Java.Base/Java.Lang/String.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using Java.Interop;
5+
6+
namespace Java.Lang {
7+
public partial class String : IEnumerable, IEnumerable<char> {
8+
}
9+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
5+
namespace Java.Lang {
6+
partial class StringBuffer : IEnumerable, IEnumerable<char> {
7+
}
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
5+
namespace Java.Lang {
6+
partial class StringBuilder : IEnumerable, IEnumerable<char> {
7+
}
8+
}

src/Java.Base/Transforms/Metadata.xml

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,22 @@
22
<!-- For now, just bind java.lang.* -->
33
<remove-node path="//api/package[not(starts-with(@name, 'java.lang'))]" />
44

5-
<!-- For now, just bind Class, Object, Throwable -->
6-
<remove-node path="//api/package/interface" />
7-
<remove-node path="//api/package/class[not(@name = 'Object'
8-
or @name = 'BootstrapMethodError'
9-
or @name = 'Class'
10-
or @name = 'Math'
11-
or @name = 'Number'
12-
or @name = 'Throwable'
13-
)]"
14-
/>
5+
<!-- Type / Namespace conflicts -->
6+
<ns-replace source="java.lang.module" replacement="Java.Lang.Modules" />
157

16-
<attr path="/api/package[@name='java.lang']/class[@name='Object']/method[@name='finalize']" name="managedName">JavaFinalize</attr>
8+
<!-- Bind `Object.finalize()` as `Object.JavaFinalize()` -->
9+
<attr path="/api/package[@name='java.lang']//method[@name='finalize' and count(parameter)=0]" name="managedName">JavaFinalize</attr>
10+
<!-- warning CS0672: Member 'Enum.JavaFinalize()' overrides obsolete member 'Object.JavaFinalize()'. Add the Obsolete attribute to 'Enum.JavaFinalize()'. -->
11+
<attr path="/api/package[@name='java.lang']/class[@name='Enum']/method[@name='finalize' and count(parameter)=0]" name="deprecated">deprecated</attr>
12+
13+
<!-- AbstractStringBuilder is package-private; fixity fix -->
14+
<remove-node path="//api/package[@name='java.lang']/class[@name='AbstractStringBuilder']" />
15+
16+
<attr path="/api/package[@name='java.lang']/class[@name='StringBuilder']" name="extends">java.lang.Object</attr>
17+
<remove-node path="//api/package[@name='java.lang']/class[@name='StringBuilder']/method[@jni-return='Ljava/lang/AbstractStringBuilder;']" />
18+
<remove-node path="//api/package[@name='java.lang']/class[@name='StringBuilder']/method[@jni-return='Ljava/lang/Appendable;']" />
19+
20+
<attr path="/api/package[@name='java.lang']/class[@name='StringBuffer']" name="extends">java.lang.Object</attr>
21+
<remove-node path="//api/package[@name='java.lang']/class[@name='StringBuffer']/method[@jni-return='Ljava/lang/AbstractStringBuilder;']" />
22+
<remove-node path="//api/package[@name='java.lang']/class[@name='StringBuffer']/method[@jni-return='Ljava/lang/Appendable;']" />
1723
</metadata>

tests/generator-Tests/Integration-Tests/Arrays.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ namespace generatortests
66
[TestFixture]
77
public class Arrays : BaseGeneratorTest
88
{
9-
protected override bool TryJavaInterop1 => false;
10-
119
[Test]
1210
public void GeneratedOK ()
1311
{

tests/generator-Tests/Integration-Tests/Compiler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public static Assembly Compile (Xamarin.Android.Binder.CodeGeneratorOptions opti
7171
var references = referencePaths.Select (p => MetadataReference.CreateFromFile (p)).ToArray ();
7272

7373
string testCommandLine =
74-
$"csc \"-out:{Path.GetFileName (assemblyFileName)}\" " +
74+
$"csc -noconfig -nostdlib \"-out:{Path.GetFileName (assemblyFileName)}\" " +
7575
$"-unsafe -t:library " +
7676
string.Join (" ", preprocessorSymbols.Select (p => $"\"-define:{p}\"")) + " " +
7777
string.Join (" ", referencePaths.Select (p => $"\"-r:{p}\"")) + " " +

tests/generator-Tests/Unit-Tests/CodeGeneratorExpectedResults/JavaInterop1/WriteClass.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public partial class MyClass {
2424
}
2525

2626
// Metadata.xml XPath constructor reference: path="/api/package[@name='java.code']/class[@name='MyClass']/constructor[@name='MyClass' and count(parameter)=1 and parameter[1][@type='java.lang.String']]"
27-
unsafe MyClass (string p0) : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None)
27+
unsafe MyClass (string? p0) : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None)
2828
{
2929
const string __id = "(Ljava/lang/String;)V";
3030

@@ -65,7 +65,7 @@ public partial class MyClass {
6565
}
6666
}
6767

68-
public virtual unsafe string Key {
68+
public virtual unsafe string? Key {
6969
// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='get_Key' and count(parameter)=0]"
7070
get {
7171
const string __id = "get_Key.()Ljava/lang/String;";
@@ -120,7 +120,7 @@ public partial class MyClass {
120120
}
121121

122122
// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='GetCountForKey' and count(parameter)=1 and parameter[1][@type='java.lang.String']]"
123-
public virtual unsafe int GetCountForKey (string key)
123+
public virtual unsafe int GetCountForKey (string? key)
124124
{
125125
const string __id = "GetCountForKey.(Ljava/lang/String;)I";
126126
var native_key = global::Java.Interop.JniEnvironment.Strings.NewString (key);
@@ -135,7 +135,7 @@ public partial class MyClass {
135135
}
136136

137137
// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/class[@name='MyClass']/method[@name='Key' and count(parameter)=0]"
138-
public virtual unsafe string Key ()
138+
public virtual unsafe string? Key ()
139139
{
140140
const string __id = "Key.()Ljava/lang/String;";
141141
try {

0 commit comments

Comments
 (0)