Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions src/documentation/articles/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,10 @@ Most of the time the code works fine, but the failure is non-deterministic and h

### `using` or `try-finally` with `Dispose`

All JNet classes implement `IDisposable`. Wrapping the object in a `using` block keeps it alive and releases the JVM reference deterministically:
From 2.6.7+ version only JNet classes extending `AutoCloseable` implement `IDisposable`.
Naturally the `using` block replaces the equivalent `try-with-resources` of Java and reference is not collected till the end of the object usage.
For all other classes without `IDisposable` (i.e. does not represent an `AutoCloseable` class), JCOBridge 2.6.8 introduces the `JVMBridgeCoreDisposable` which wraps the input object, make the reference alive and exposes an `IDisposable` interface.
Wrapping the object in a `using` block keeps it alive and releases the JVM reference deterministically:

```csharp
using Java.Util;
Expand All @@ -226,7 +229,8 @@ namespace MASES.JNetExample
MyJNetCore.CreateGlobalInstance();
try
{
using (Java.Util.Set<string> set = Collections.Singleton("test"))
Java.Util.Set<string> set = Collections.Singleton("test");
using (var disposeable = JVMBridgeCoreDisposable.Create(set)) // or using (var disposeable = set.ToDisposeable())
{
ArrayList<string> arrayList = new();
arrayList.AddAll(0, set);
Expand Down Expand Up @@ -257,21 +261,23 @@ namespace MASES.JNetExample
MyJNetCore.CreateGlobalInstance();
try
{
Java.Util.Set<string> set = null;
Java.Util.Set<string> set = Collections.Singleton("test");
var disposeable = JVMBridgeCoreDisposable.Create(set); // or var disposeable = set.ToDisposeable();
try
{
set = Collections.Singleton("test");
ArrayList<string> arrayList = new();
arrayList.AddAll(0, set);
}
finally { set?.Dispose(); }
finally { disposeable?.Dispose(); }
}
catch (System.Exception ex) { System.Console.WriteLine(ex.Message); }
}
}
}
```



### `SuppressFinalize`/`ReRegisterForFinalize` pattern

When restructuring to `using` is not practical, you can suppress finalization for the duration of the cross-boundary call:
Expand Down
14 changes: 13 additions & 1 deletion src/net/JNet/Specific/Extensions/JNetCoreExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@ namespace MASES.JNet.Specific.Extensions
/// </summary>
public static class JNetCoreExtensions
{
/// <summary>
/// Converts any instance of <see cref="JVMBridgeCore"/> in <paramref name="bridge"/> to an <see cref="IDisposable"/>
/// </summary>
/// <param name="bridge">The <see cref="JVMBridgeCore"/> instance to convert</param>
/// <returns>The <see cref="IDisposable"/> instance</returns>
/// <remarks>The method check if <paramref name="bridge"/> implements <see cref="IDisposable"/> and returns that instance, otherwise wraps <paramref name="bridge"/> into an <see cref="JVMBridgeCoreDisposable"/></remarks>
public static IDisposable ToDisposable(this JVMBridgeCore bridge)
{
if (bridge is IDisposable disposable) return disposable;
return JVMBridgeCoreDisposable.Create(bridge);
}

/// <summary>
/// Builds a new var-arg result starting from fixed parameters stored in <paramref name="fixedParameters"/> and the <see langword="params"/> argument available in <paramref name="varArg"/>
/// </summary>
Expand Down Expand Up @@ -75,7 +87,7 @@ public static Java.Lang.Class<TClass> Class<TClass>(this TClass _) where TClass
public static TWrap DirectBufferWithWrap<TData, TWrap>(this TData[] data, bool useMemoryControlBlock = true, bool arrangeCapacity = true, int timeToLive = System.Threading.Timeout.Infinite, Func<ByteBuffer, TWrap> converter = null) where TWrap : IJVMBridgeBase
{
var buf = JCOBridge.C2JBridge.JCOBridge.Global.JVM.NewDirectBuffer(data, useMemoryControlBlock, arrangeCapacity, timeToLive);
if (data is byte[]) return JVMBridgeBase.WrapsDirect<TWrap>(buf.DisableCleanupAndReturn());
if (data is byte[]) return JVMBridgeCore.WrapsDirect<TWrap>(buf.DisableCleanupAndReturn());
else
{
IJVMBridgeBase ibb;
Expand Down
Loading