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

+2-1
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

+1-1
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>
+20
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

+9
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+
}
+8
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+
}
+8
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

+17-11
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

-2
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

+1-1
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

+4-4
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 {

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ internal sealed partial class AnimatorListenerImplementor : global::Java.Lang.Ob
5757
}
5858

5959
#pragma warning disable 0649
60-
public EventHandler<AnimationEndEventArgs> OnAnimationEndHandler;
60+
public EventHandler<AnimationEndEventArgs>? OnAnimationEndHandler;
6161
#pragma warning restore 0649
6262

6363
public bool OnAnimationEnd (int param1)
@@ -71,7 +71,7 @@ internal sealed partial class AnimatorListenerImplementor : global::Java.Lang.Ob
7171
}
7272

7373
#pragma warning disable 0649
74-
public EventHandler<AnimationEndEventArgs> OnAnimationEndHandler;
74+
public EventHandler<AnimationEndEventArgs>? OnAnimationEndHandler;
7575
#pragma warning restore 0649
7676

7777
public bool OnAnimationEnd (int param1, int param2)
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,8 @@
1-
[Register ("java/code/IMyInterface", DoNotGenerateAcw=true)]
2-
public abstract class MyInterface : Java.Lang.Object {
3-
internal MyInterface ()
4-
{
5-
}
6-
7-
// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='StaticMethod' and count(parameter)=0]"
8-
public static unsafe void StaticMethod ()
9-
{
10-
const string __id = "StaticMethod.()V";
11-
try {
12-
_members.StaticMethods.InvokeVoidMethod (__id, null);
13-
} finally {
14-
}
15-
}
16-
17-
static readonly JniPeerMembers _members = new JniPeerMembers ("java/code/IMyInterface", typeof (MyInterface));
18-
19-
}
20-
21-
[Register ("java/code/IMyInterface", DoNotGenerateAcw=true)]
22-
[global::System.Obsolete ("Use the 'MyInterface' type. This type will be removed in a future release.", error: true)]
23-
public abstract class MyInterfaceConsts : MyInterface {
24-
private MyInterfaceConsts ()
25-
{
26-
}
27-
28-
}
29-
301
// Metadata.xml XPath interface reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']"
312
[global::Java.Interop.JniTypeSignature ("java/code/IMyInterface", GenerateJavaPeer=false)]
323
public partial interface IMyInterface : IJavaPeerable {
4+
private static readonly JniPeerMembers _members = new JniPeerMembers ("java/code/IMyInterface", typeof (IMyInterface), isInterface: true);
5+
336
int Count {
347
// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='get_Count' and count(parameter)=0]"
358
get;
@@ -38,7 +11,7 @@ public partial interface IMyInterface : IJavaPeerable {
3811
set;
3912
}
4013

41-
string Key {
14+
string? Key {
4215
// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='get_Key' and count(parameter)=0]"
4316
get;
4417

@@ -54,13 +27,45 @@ public partial interface IMyInterface : IJavaPeerable {
5427
set;
5528
}
5629

30+
static unsafe int StaticCount {
31+
// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='get_StaticCount' and count(parameter)=0]"
32+
get {
33+
const string __id = "get_StaticCount.()I";
34+
try {
35+
var __rm = _members.StaticMethods.InvokeInt32Method (__id, null);
36+
return __rm;
37+
} finally {
38+
}
39+
}
40+
// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='set_StaticCount' and count(parameter)=1 and parameter[1][@type='int']]"
41+
set {
42+
const string __id = "set_StaticCount.(I)V";
43+
try {
44+
JniArgumentValue* __args = stackalloc JniArgumentValue [1];
45+
__args [0] = new JniArgumentValue (value);
46+
_members.StaticMethods.InvokeVoidMethod (__id, __args);
47+
} finally {
48+
}
49+
}
50+
}
51+
5752
// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='GetCountForKey' and count(parameter)=1 and parameter[1][@type='java.lang.String']]"
58-
int GetCountForKey (string key);
53+
int GetCountForKey (string? key);
5954

6055
// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='Key' and count(parameter)=0]"
61-
string Key ();
56+
string? Key ();
6257

6358
// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='AbstractMethod' and count(parameter)=0]"
6459
void AbstractMethod ();
6560

61+
// Metadata.xml XPath method reference: path="/api/package[@name='java.code']/interface[@name='IMyInterface']/method[@name='StaticMethod' and count(parameter)=0]"
62+
public static unsafe void StaticMethod ()
63+
{
64+
const string __id = "StaticMethod.()V";
65+
try {
66+
_members.StaticMethods.InvokeVoidMethod (__id, null);
67+
} finally {
68+
}
69+
}
70+
6671
}
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
public delegate int MyIGetCountForKeyHandler (string key);
1+
public delegate int MyIGetCountForKeyHandler (string? key);
22

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
// event args for com.xamarin.android.MyListener.onDoSomething
22
public partial class MyEventArgs : global::System.EventArgs {
33

4-
public MyEventArgs (params Java.Lang.Object[] args)
4+
public MyEventArgs (params Java.Lang.Object[]? args)
55
{
66
this.args = args;
77
}
88

9-
Java.Lang.Object[] args;
10-
public Java.Lang.Object[] Args {
9+
Java.Lang.Object[]? args;
10+
public Java.Lang.Object[]? Args {
1111
get { return args; }
1212
}
1313
}
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,59 @@
11
[global::Android.Runtime.Register ("mono/java/code/IMyInterfaceImplementor")]
22
internal sealed partial class IMyInterfaceImplementor : global::Java.Lang.Object, IMyInterface {
33

4-
object sender;
4+
object sender;
55

6-
public IMyInterfaceImplementor (object sender)
7-
: base (
8-
global::Android.Runtime.JNIEnv.StartCreateInstance ("mono/java/code/IMyInterfaceImplementor", "()V"),
9-
JniHandleOwnership.TransferLocalRef)
10-
{
11-
global::Android.Runtime.JNIEnv.FinishCreateInstance (this.PeerReference, "()V");
12-
this.sender = sender;
13-
}
6+
public IMyInterfaceImplementor (object sender)
7+
: base (
8+
global::Android.Runtime.JNIEnv.StartCreateInstance ("mono/java/code/IMyInterfaceImplementor", "()V"),
9+
JniHandleOwnership.TransferLocalRef)
10+
{
11+
global::Android.Runtime.JNIEnv.FinishCreateInstance (this.PeerReference, "()V");
12+
this.sender = sender;
13+
}
1414

1515
#pragma warning disable 0649
16-
public MyIGetCountForKeyHandler GetCountForKeyHandler;
16+
public MyIGetCountForKeyHandler? GetCountForKeyHandler;
1717
#pragma warning restore 0649
1818

19-
public int GetCountForKey (string key)
20-
{
21-
var __h = GetCountForKeyHandler;
22-
return __h != null ? __h (key) : default (int);
23-
}
19+
public int GetCountForKey (string? key)
20+
{
21+
var __h = GetCountForKeyHandler;
22+
return __h != null ? __h (key) : default (int);
23+
}
2424
#pragma warning disable 0649
25-
public MyIKeyHandler KeyHandler;
25+
public MyIKeyHandler? KeyHandler;
2626
#pragma warning restore 0649
2727

28-
public string Key ()
29-
{
30-
var __h = KeyHandler;
31-
return __h != null ? __h () : default (string);
32-
}
28+
public string? Key ()
29+
{
30+
var __h = KeyHandler;
31+
return __h != null ? __h () : default (string?);
32+
}
3333
#pragma warning disable 0649
34-
public EventHandler StaticMethodHandler;
34+
public EventHandler? StaticMethodHandler;
3535
#pragma warning restore 0649
3636

37-
public void StaticMethod ()
38-
{
39-
var __h = StaticMethodHandler;
40-
if (__h != null)
41-
__h (sender, new EventArgs ());
42-
}
37+
public void StaticMethod ()
38+
{
39+
var __h = StaticMethodHandler;
40+
if (__h != null)
41+
__h (sender, new EventArgs ());
42+
}
4343
#pragma warning disable 0649
44-
public EventHandler AbstractMethodHandler;
44+
public EventHandler? AbstractMethodHandler;
4545
#pragma warning restore 0649
4646

47-
public void AbstractMethod ()
48-
{
49-
var __h = AbstractMethodHandler;
50-
if (__h != null)
51-
__h (sender, new EventArgs ());
52-
}
53-
54-
internal static bool __IsEmpty (IMyInterfaceImplementor value)
55-
{
56-
return value.GetCountForKeyHandler == null && value.KeyHandler == null && value.StaticMethodHandler == null && value.AbstractMethodHandler == null;
57-
}
47+
public void AbstractMethod ()
48+
{
49+
var __h = AbstractMethodHandler;
50+
if (__h != null)
51+
__h (sender, new EventArgs ());
52+
}
53+
54+
internal static bool __IsEmpty (IMyInterfaceImplementor value)
55+
{
56+
return value.GetCountForKeyHandler == null && value.KeyHandler == null && value.StaticMethodHandler == null && value.AbstractMethodHandler == null;
57+
}
5858
}
59+

0 commit comments

Comments
 (0)