Skip to content

Commit

Permalink
[Java.Base] Bind package java.util.concurrent (#1274)
Browse files Browse the repository at this point in the history
Context: 0aec86a

Commit 0aec86a mentioned:

>  * Use of `JNIEnv.GetJniName()`
>
>        string __id = "(L" + global::Android.Runtime.JNIEnv.GetJniName (GetType ().DeclaringType) + ";)V";
>
>    Impacts: NestedTypes.cs

This issue also impacts
[`java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject`][0].

Update `Java.Base` to bind the `java.util.concurrent` package, which
will cause `AbstractQueuedSynchronizer` to be bound, which in turn
forces us to update `generator` to not emit `JNIEnv.GetJniName()`.
Instead of using `JNIEnv.GetJniName(GetType().DeclaringType)`, use:

	JniEnvironment.Runtime.TypeManager.GetTypeSignature (GetType ().DeclaringType).SimpleReference

Update NestedTypes.cs to enable `TryJavaInterop1 => true`.

Update `Java.Base.csproj` to ignore C# warning [CS0109][1], as
[`CompletableFuture.handle()`][2] is emitted with a `new` which is
not required:

	Java.Util.Concurrent.CompletableFuture.cs(629,76): warning CS0109: The member
	'CompletableFuture.Handle(IBiFunction?)' does not hide an accessible member.
	The new keyword is not required.

Add a test to `tests/Java.Base-Tests` which tests nested type support.

Update `JavaNativeTypeManager.cs` so that `IsNonStaticInnerClass()`
supports JavaInterop1-style attributes, not just XAJavaInterop1.

Aside: I updated my local JDK to JDK-17 (from JDK-11), which caused
many changes to `src/Java.Base-ref.cs`, particularly parameter names.

TODO? Update `Java.Interop.Tools.JavaCallableWrappers` so that
non-static inner classes don't have a prefix of their declaring type.
This would result in `example/MyQueuedSynchronizer$MyConditionObject`
instead of
`example/MyQueuedSynchronizer$MyQueuedSynchronizer_MyConditionObject`.

[0]: https://developer.android.com/reference/java/util/concurrent/locks/AbstractQueuedSynchronizer.ConditionObject
[1]: https://learn.microsoft.com/dotnet/csharp/misc/cs0109
[2]: https://developer.android.com/reference/java/util/concurrent/CompletableFuture#handle(java.util.function.BiFunction%3C?%20super%20T,java.lang.Throwable,?%20extends%20U%3E)
  • Loading branch information
jonpryor authored Oct 28, 2024
1 parent 87fdb8e commit 2bdf2bc
Show file tree
Hide file tree
Showing 10 changed files with 3,072 additions and 35 deletions.
2,964 changes: 2,934 additions & 30 deletions src/Java.Base-ref.cs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/Java.Base/Java.Base.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<TargetFramework>$(DotNetTargetFramework)</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Nullable>enable</Nullable>
<NoWarn>$(NoWarn);8764;0114</NoWarn>
<NoWarn>$(NoWarn);8764;0109;0114</NoWarn>
</PropertyGroup>

<Import Project="..\..\TargetFrameworkDependentValues.props" />
Expand Down
33 changes: 33 additions & 0 deletions src/Java.Base/Transforms/Metadata.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
not(
starts-with(@name, 'java.lang')
or starts-with(@name, 'java.io')
or starts-with(@name, 'java.util.concurrent')
or starts-with(@name, 'java.util.function')
)]" />

Expand Down Expand Up @@ -87,4 +88,36 @@
name="managedOverride">reabstract</attr>
<attr path="/api/package[@name='java.lang.reflect']/interface[@name='AnnotatedType']/method[@name='getDeclaredAnnotations' and count(parameter)=0]"
name="explicitInterface">IAnnotatedElement</attr>

<attr path="/api/package[@name='java.util.concurrent']/interface[@name='RunnableFuture']/method[@name='run' and count(parameter)=0]"
name="managedOverride">reabstract</attr>
<attr path="/api/package[@name='java.util.concurrent']/interface[@name='RunnableFuture']/method[@name='run' and count(parameter)=0]"
name="explicitInterface">global::Java.Lang.IRunnable</attr>
<attr path="/api/package[@name='java.util.concurrent']/class[@name='CompletableFuture']/method[@name='applyToEither'
or @name='applyToEitherAsync'
or @name='acceptEither'
or @name='acceptEitherAsync'
or @name='exceptionally'
or @name='handle'
or @name='handleAsync'
or @name='runAfterBoth'
or @name='runAfterBothAsync'
or @name='runAfterEither'
or @name='runAfterEitherAsync'
or @name='thenAccept'
or @name='thenAcceptAsync'
or @name='thenAcceptBoth'
or @name='thenAcceptBothAsync'
or @name='thenApply'
or @name='thenApplyAsync'
or @name='thenCombine'
or @name='thenCombineAsync'
or @name='thenCompose'
or @name='thenComposeAsync'
or @name='thenRun'
or @name='thenRunAsync'
or @name='whenComplete'
or @name='whenCompleteAsync'
]"
name="managedReturn">Java.Util.Concurrent.ICompletionStage</attr>
</metadata>
Original file line number Diff line number Diff line change
Expand Up @@ -737,7 +737,7 @@ internal static bool IsNonStaticInnerClass (TypeDefinition? type, IMetadataResol
foreach (var baseType in type.GetBaseTypes (cache)) {
if (baseType == null)
continue;
if (!baseType.AnyCustomAttributes (typeof (RegisterAttribute)))
if (!HasTypeRegistrationAttribute (baseType))
continue;

foreach (var method in baseType.Methods) {
Expand All @@ -753,6 +753,14 @@ internal static bool IsNonStaticInnerClass (TypeDefinition? type, IMetadataResol

return false;
}

static bool HasTypeRegistrationAttribute (TypeDefinition type)
{
if (!type.HasCustomAttributes)
return false;
return type.AnyCustomAttributes (typeof (RegisterAttribute)) ||
type.AnyCustomAttributes ("Java.Interop.JniTypeSignatureAttribute");
}
#endif // HAVE_CECIL

static string ToCrc64 (string value)
Expand Down
2 changes: 2 additions & 0 deletions tests/Java.Base-Tests/Java.Base/JavaVMFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ static partial void CreateJavaVM ()
["example/MyIntConsumer"] = typeof (MyIntConsumer),
["example/MyRunnable"] = typeof (MyRunnable),
[JavaInvoker.JniTypeName] = typeof (JavaInvoker),
[MyQueuedSynchronizer.JniTypeName] = typeof (MyQueuedSynchronizer),
["example/MyQueuedSynchronizer$MyQueuedSynchronizer_MyConditionObject"] = typeof (MyQueuedSynchronizer.MyConditionObject),
}
);
JniRuntime.SetCurrent (c);
Expand Down
36 changes: 36 additions & 0 deletions tests/Java.Base-Tests/Java.Base/NestedTypeTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System;

using Java.Interop;

using NUnit.Framework;

namespace Java.BaseTests {

[TestFixture]
public class NestedTypeTests : JavaVMFixture {

[Test]
public void Create_AbstractQueuedSynchronizer_ConditionObject ()
{
using var outer = new MyQueuedSynchronizer ();
using var inner = new MyQueuedSynchronizer.MyConditionObject (outer);
}
}

[JniTypeSignature (JniTypeName)]
class MyQueuedSynchronizer : Java.Util.Concurrent.Locks.AbstractQueuedSynchronizer {
internal const string JniTypeName = "example/MyQueuedSynchronizer";

public MyQueuedSynchronizer ()
{
}

public class MyConditionObject : Java.Util.Concurrent.Locks.AbstractQueuedSynchronizer.ConditionObject {

public MyConditionObject (MyQueuedSynchronizer outer)
: base (outer)
{
}
}
}
}
2 changes: 1 addition & 1 deletion tests/generator-Tests/Integration-Tests/NestedTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace generatortests
[TestFixture]
public class NestedTypes : BaseGeneratorTest
{
protected override bool TryJavaInterop1 => false;
protected override bool TryJavaInterop1 => true;

[Test]
public void GeneratedOK ()
Expand Down
10 changes: 10 additions & 0 deletions tests/generator-Tests/expected.ji/NestedTypes/Java.Lang.Object.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

#nullable restore
using System;
using System.Collections.Generic;
using Java.Interop;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

#nullable restore
using System;
using System.Collections.Generic;
using Java.Interop;
Expand All @@ -14,10 +24,39 @@ public abstract partial class Action : global::Java.Lang.Object {
[global::Java.Interop.JniTypeSignature ("xamarin/test/NotificationCompatBase$Action$Factory", GenerateJavaPeer=false)]
public partial interface IFactory : IJavaPeerable {
// Metadata.xml XPath method reference: path="/api/package[@name='xamarin.test']/interface[@name='NotificationCompatBase.Action.Factory']/method[@name='build' and count(parameter)=1 and parameter[1][@type='int']]"
[global::Java.Interop.JniMethodSignature ("build", "(I)Lxamarin/test/NotificationCompatBase$Action;")]
global::Xamarin.Test.NotificationCompatBase.Action Build (int p0);

}

[global::Java.Interop.JniTypeSignature ("xamarin/test/NotificationCompatBase$Action$Factory", GenerateJavaPeer=false)]
internal partial class IFactoryInvoker : global::Java.Lang.Object, IFactory {
[global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)]
[global::System.ComponentModel.EditorBrowsable (global::System.ComponentModel.EditorBrowsableState.Never)]
public override global::Java.Interop.JniPeerMembers JniPeerMembers {
get { return _members_xamarin_test_NotificationCompatBase_Action_Factory; }
}

static readonly JniPeerMembers _members_xamarin_test_NotificationCompatBase_Action_Factory = new JniPeerMembers ("xamarin/test/NotificationCompatBase$Action$Factory", typeof (IFactoryInvoker));

public IFactoryInvoker (ref JniObjectReference reference, JniObjectReferenceOptions options) : base (ref reference, options)
{
}

public unsafe global::Xamarin.Test.NotificationCompatBase.Action Build (int p0)
{
const string __id = "build.(I)Lxamarin/test/NotificationCompatBase$Action;";
try {
JniArgumentValue* __args = stackalloc JniArgumentValue [1];
__args [0] = new JniArgumentValue (p0);
var __rm = _members_xamarin_test_NotificationCompatBase_Action_Factory.InstanceMethods.InvokeAbstractObjectMethod (__id, this, __args);
return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue<global::Xamarin.Test.NotificationCompatBase.Action> (ref __rm, JniObjectReferenceOptions.CopyAndDispose);
} finally {
}
}

}

static readonly JniPeerMembers _members = new JniPeerMembers ("xamarin/test/NotificationCompatBase$Action", typeof (Action));

[global::System.Diagnostics.DebuggerBrowsable (global::System.Diagnostics.DebuggerBrowsableState.Never)]
Expand Down Expand Up @@ -64,9 +103,10 @@ protected InstanceInner (ref JniObjectReference reference, JniObjectReferenceOpt
}

// Metadata.xml XPath constructor reference: path="/api/package[@name='xamarin.test']/class[@name='NotificationCompatBase.InstanceInner']/constructor[@name='NotificationCompatBase.InstanceInner' and count(parameter)=1 and parameter[1][@type='xamarin.test.NotificationCompatBase']]"
[global::Java.Interop.JniConstructorSignature ("(Lxamarin/test/NotificationCompatBase;)V")]
public unsafe InstanceInner (global::Xamarin.Test.NotificationCompatBase __self) : base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None)
{
string __id = "(L" + global::Android.Runtime.JNIEnv.GetJniName (GetType ().DeclaringType) + ";)V";
string __id = "(L" + global::Java.Interop.JniEnvironment.Runtime.TypeManager.GetTypeSignature (GetType ().DeclaringType).SimpleReference + ";)V";

if (PeerReference.IsValid)
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,11 @@ public string GetJniNestedDerivedSignature (CodeGenerationOptions opt)
StringBuilder sb = new StringBuilder ();
foreach (Parameter p in items) {
if (p.Name == "__self") {
sb.AppendFormat ("L\" + global::Android.Runtime.JNIEnv.GetJniName (GetType ().DeclaringType{0}) + \";", opt.NullForgivingOperator);
if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) {
sb.AppendFormat ("L\" + global::Java.Interop.JniEnvironment.Runtime.TypeManager.GetTypeSignature (GetType ().DeclaringType{0}).SimpleReference + \";", opt.NullForgivingOperator);
} else {
sb.AppendFormat ("L\" + global::Android.Runtime.JNIEnv.GetJniName (GetType ().DeclaringType{0}) + \";", opt.NullForgivingOperator);
}
continue;
}
sb.Append (p.JniType);
Expand Down

0 comments on commit 2bdf2bc

Please sign in to comment.