diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 5176a76a9..36818352a 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -34,7 +34,6 @@ ### Core Libraries (`src/`) - **`Java.Interop/`**: Main JNI binding library with core types and runtime -- **`Java.Interop.Dynamic/`**: C# 4.0 `dynamic` provider for runtime method invocation - **`Java.Interop.Export/`**: `[Export]` attribute support for exposing managed methods to Java - **`Java.Runtime.Environment/`**: JVM loading and lifecycle management - **`Java.Base/`**: Bindings for core Java types (`java.lang.*`, etc.) diff --git a/.github/skills/build-and-test/SKILL.md b/.github/skills/build-and-test/SKILL.md index 7b7d5d38b..f3f166c61 100644 --- a/.github/skills/build-and-test/SKILL.md +++ b/.github/skills/build-and-test/SKILL.md @@ -55,7 +55,6 @@ dotnet test tests//.csproj Common test projects: - `Java.Interop-Tests` — core JNI binding tests (largest suite) - `Java.Interop.Export-Tests` — export attribute tests -- `Java.Interop.Dynamic-Tests` — dynamic invocation tests - `Java.Base-Tests` — Java.Base binding tests - `generator-Tests` — C# binding generator tests - `Java.Interop.Tools.JavaCallableWrappers-Tests` — JCW generation tests diff --git a/Documentation/Architecture.md b/Documentation/Architecture.md index ac58dbdfe..3f8035953 100644 --- a/Documentation/Architecture.md +++ b/Documentation/Architecture.md @@ -85,16 +85,10 @@ The problem with Xamarin.Android is a lack of flexibility: JNI glue code elsewhere (the desktop JVM?). * An incomplete binding ABI restricts fully embracing AOT -Relatedly, there has long been a desire to provide a -[C# 4 `dynamic` provider][Java.Interop.Dynamic] to permit invoking Java methods -without requiring a separately generated binding assembly. `dynamic` providers, -in turn, implement the [IDynamicMetaObjectProvider][IDynamicMetaObjectProvider] -interface, which is based ~entirely upon -[System.Linq.Expressions][System.Linq.Expressions], which *also* supports -generating IL for execution at runtime (or saving to disk). - -[Java.Interop.Dynamic]: src/Java.Interop.Dynamic -[IDynamicMetaObjectProvider]: https://msdn.microsoft.com/en-us/library/system.dynamic.idynamicmetaobjectprovider%28v=vs.110%29.aspx +Relatedly, there has long been a desire to embrace +[System.Linq.Expressions][System.Linq.Expressions], which supports generating IL +for execution at runtime (or saving to disk). + [System.Linq.Expressions]: https://msdn.microsoft.com/en-us/library/system.linq.expressions.aspx Thus, the solution to *all our problems*? *Embrace* `System.Linq.Expressions`. diff --git a/Documentation/BuildConfiguration.md b/Documentation/BuildConfiguration.md index 424adfbc2..3cff9e86e 100644 --- a/Documentation/BuildConfiguration.md +++ b/Documentation/BuildConfiguration.md @@ -41,11 +41,10 @@ The following **make**(1) variables may be specified: * `$(TESTS)`: Which unit tests to execute. Useful in conjunction with the `make run-tests` target: - make run-tests TESTS=bin/Debug/Java.Interop.Dynamic-Tests.dll + make run-tests TESTS=bin/Debug/Java.Interop-Tests.dll * `$(V)`: If set to a non-empty string, adds `/v:diag` to `$(MSBUILD_FLAGS)` invocations. * `$(MSBUILD)`: The MSBuild build tool to execute for builds. Default value is `xbuild`. - diff --git a/Java.Interop.sln b/Java.Interop.sln index e25824547..7fb468cc9 100644 --- a/Java.Interop.sln +++ b/Java.Interop.sln @@ -17,8 +17,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop", "src\Java.In EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "java-interop", "src\java-interop\java-interop.csproj", "{BB0AB9F7-0979-41A7-B7A9-877260655F94}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Dynamic", "src\Java.Interop.Dynamic\Java.Interop.Dynamic.csproj", "{AD4468F8-8883-434B-9D4C-E1801BB3B52A}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Tools.JavaSource", "src\Java.Interop.Tools.JavaSource\Java.Interop.Tools.JavaSource.csproj", "{5C0B3562-8DA0-4726-9762-75B9709ED6B7}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Desktop", "Desktop", "{0998E45F-8BCE-4791-A944-962CD54E2D80}" @@ -39,8 +37,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestJVM", "tests\TestJVM\Te EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop-Tests", "tests\Java.Interop-Tests\Java.Interop-Tests.csproj", "{04E28441-36FF-4964-ADD7-EFBB47CCE406}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Dynamic-Tests", "tests\Java.Interop.Dynamic-Tests\Java.Interop.Dynamic-Tests.csproj", "{82B1DD53-69CA-4A61-B6B1-F06F1525EF4D}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "logcat-parse-Tests", "tests\logcat-parse-Tests\logcat-parse-Tests.csproj", "{DB05D566-0BA0-4935-868D-689E2F03688E}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xamarin.Android.Tools.Bytecode-Tests", "tests\Xamarin.Android.Tools.Bytecode-Tests\Xamarin.Android.Tools.Bytecode-Tests.csproj", "{C9FA4492-DEB0-4932-A6B8-E2C4E0581692}" @@ -139,10 +135,6 @@ Global {BB0AB9F7-0979-41A7-B7A9-877260655F94}.Debug|Any CPU.Build.0 = Debug|Any CPU {BB0AB9F7-0979-41A7-B7A9-877260655F94}.Release|Any CPU.ActiveCfg = Release|Any CPU {BB0AB9F7-0979-41A7-B7A9-877260655F94}.Release|Any CPU.Build.0 = Release|Any CPU - {AD4468F8-8883-434B-9D4C-E1801BB3B52A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AD4468F8-8883-434B-9D4C-E1801BB3B52A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AD4468F8-8883-434B-9D4C-E1801BB3B52A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AD4468F8-8883-434B-9D4C-E1801BB3B52A}.Release|Any CPU.Build.0 = Release|Any CPU {5C0B3562-8DA0-4726-9762-75B9709ED6B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5C0B3562-8DA0-4726-9762-75B9709ED6B7}.Debug|Any CPU.Build.0 = Debug|Any CPU {5C0B3562-8DA0-4726-9762-75B9709ED6B7}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -175,10 +167,6 @@ Global {04E28441-36FF-4964-ADD7-EFBB47CCE406}.Debug|Any CPU.Build.0 = Debug|Any CPU {04E28441-36FF-4964-ADD7-EFBB47CCE406}.Release|Any CPU.ActiveCfg = Release|Any CPU {04E28441-36FF-4964-ADD7-EFBB47CCE406}.Release|Any CPU.Build.0 = Release|Any CPU - {82B1DD53-69CA-4A61-B6B1-F06F1525EF4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {82B1DD53-69CA-4A61-B6B1-F06F1525EF4D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {82B1DD53-69CA-4A61-B6B1-F06F1525EF4D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {82B1DD53-69CA-4A61-B6B1-F06F1525EF4D}.Release|Any CPU.Build.0 = Release|Any CPU {DB05D566-0BA0-4935-868D-689E2F03688E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DB05D566-0BA0-4935-868D-689E2F03688E}.Debug|Any CPU.Build.0 = Debug|Any CPU {DB05D566-0BA0-4935-868D-689E2F03688E}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -313,7 +301,6 @@ Global {D14A1B5C-2060-4930-92BE-F7190256C735} = {C8F58966-94BF-407F-914A-8654F8B8AE3B} {94BD81F7-B06F-4295-9636-F8A3B6BDC762} = {4C173212-371D-45D8-BA83-9226194F48DC} {BB0AB9F7-0979-41A7-B7A9-877260655F94} = {4C173212-371D-45D8-BA83-9226194F48DC} - {AD4468F8-8883-434B-9D4C-E1801BB3B52A} = {4C173212-371D-45D8-BA83-9226194F48DC} {5C0B3562-8DA0-4726-9762-75B9709ED6B7} = {0998E45F-8BCE-4791-A944-962CD54E2D80} {5887B410-D448-4257-A46B-EAC03C80BE93} = {0998E45F-8BCE-4791-A944-962CD54E2D80} {B17475BC-45A2-47A3-B8FC-62F3A0959EE0} = {0998E45F-8BCE-4791-A944-962CD54E2D80} @@ -322,7 +309,6 @@ Global {41DFB021-F795-4EB6-8E53-0D069C0BED9F} = {0998E45F-8BCE-4791-A944-962CD54E2D80} {A76309AB-98AC-4AE2-BA30-75481420C52F} = {271C9F30-F679-4793-942B-0D9527CB3E2F} {04E28441-36FF-4964-ADD7-EFBB47CCE406} = {271C9F30-F679-4793-942B-0D9527CB3E2F} - {82B1DD53-69CA-4A61-B6B1-F06F1525EF4D} = {271C9F30-F679-4793-942B-0D9527CB3E2F} {DB05D566-0BA0-4935-868D-689E2F03688E} = {271C9F30-F679-4793-942B-0D9527CB3E2F} {C9FA4492-DEB0-4932-A6B8-E2C4E0581692} = {271C9F30-F679-4793-942B-0D9527CB3E2F} {891F2E04-5614-4A26-A78F-3778025ECF43} = {271C9F30-F679-4793-942B-0D9527CB3E2F} diff --git a/Makefile b/Makefile index 99b00c2c2..ddf68c88f 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,6 @@ NET_SUFFIX = -net7.0 TESTS = \ bin/Test$(CONFIGURATION)/Java.Interop-Tests.dll \ - bin/Test$(CONFIGURATION)/Java.Interop.Dynamic-Tests.dll \ bin/Test$(CONFIGURATION)/Java.Interop.Tools.JavaCallableWrappers-Tests.dll \ bin/Test$(CONFIGURATION)/Java.Interop.Tools.JavaSource-Tests.dll \ bin/Test$(CONFIGURATION)/logcat-parse-Tests.dll \ @@ -95,7 +94,6 @@ bin/Test$$(CONFIGURATION)/$(1)-Tests.dll: $(wildcard src/$(1)/*/*.cs src/$(1)/Te endef # TestAssemblyTemplate $(eval $(call TestAssemblyTemplate,Java.Interop)) -$(eval $(call TestAssemblyTemplate,Java.Interop.Dynamic)) $(eval $(call TestAssemblyTemplate,Java.Interop.Export)) $(eval $(call TestAssemblyTemplate,Java.Interop.Tools.JavaCallableWrappers)) diff --git a/build-tools/automation/templates/core-tests.yaml b/build-tools/automation/templates/core-tests.yaml index 1eba72ec6..d736d80ea 100644 --- a/build-tools/automation/templates/core-tests.yaml +++ b/build-tools/automation/templates/core-tests.yaml @@ -62,13 +62,6 @@ steps: condition: or(eq('${{ parameters.runNativeDotnetTests }}', 'true'), eq('${{ parameters.runNativeTests }}', 'true')) retryCount: 1 -- template: run-dotnet-test.yaml - parameters: - testRunTitle: Java.Interop.Dynamic (${{ parameters.platformName }}) - testAssemblyName: Java.Interop.Dynamic-Tests - condition: eq('${{ parameters.runNativeTests }}', 'true') - retryCount: 1 - - template: run-dotnet-test.yaml parameters: testRunTitle: Java.Base ($(DotNetTargetFramework) - ${{ parameters.platformName }}) diff --git a/src/Java.Interop.Dynamic/Java.Interop.Dynamic.csproj b/src/Java.Interop.Dynamic/Java.Interop.Dynamic.csproj deleted file mode 100644 index 9f3ac37de..000000000 --- a/src/Java.Interop.Dynamic/Java.Interop.Dynamic.csproj +++ /dev/null @@ -1,26 +0,0 @@ - - - - $(DotNetTargetFramework) - annotations - true - true - ..\..\product.snk - - - - - - $(ToolOutputFullPath) - $(JICoreLibVersion) - - - - - - - - - - - \ No newline at end of file diff --git a/src/Java.Interop.Dynamic/Java.Interop.Dynamic/DynamicJavaClass.cs b/src/Java.Interop.Dynamic/Java.Interop.Dynamic/DynamicJavaClass.cs deleted file mode 100644 index 26bc7c27a..000000000 --- a/src/Java.Interop.Dynamic/Java.Interop.Dynamic/DynamicJavaClass.cs +++ /dev/null @@ -1,146 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Dynamic; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Text; - -using Java.Interop; - -namespace Java.Interop.Dynamic { - - public class DynamicJavaClass : IDynamicMetaObjectProvider, IDisposable - { - public string JniClassName {get; private set;} - - JavaClassInfo info; - bool disposed; - - public DynamicJavaClass (string jniClassName) - { - if (jniClassName == null) - throw new ArgumentNullException ("jniClassName"); - - JniClassName = jniClassName; - info = JavaClassInfo.GetClassInfo (jniClassName); - } - - public void Dispose () - { - Dispose (disposing: true); - GC.SuppressFinalize (this); - } - - protected virtual void Dispose (bool disposing) - { - if (!disposing) - return; - - if (disposed) - return; - - info.Dispose (); - info = null!; - disposed = true; - } - - DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject (Expression parameter) - { - return new MetaObject (parameter, this); - } - -#if false - Type CreateManagedPeerType () - { - var className = JniClassName.Replace ('/', '-'); - var aname = new AssemblyName ("Java.Interop.Dynamic-" + className); - - var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly (aname, AssemblyBuilderAccess.ReflectionOnly); - var module = assembly.DefineDynamicModule (className); - var type = module.DefineType (JniClassName, TypeAttributes.Sealed, typeof (JavaObject)); - type.SetCustomAttribute ( - new CustomAttributeBuilder ( - typeof (JniTypeInfoAttribute).GetConstructor (new[]{ typeof(string) }), - new []{JniClassName})); - - return type.CreateType (); - } -#endif - - class MetaObject : JniMetaObject - { - DynamicJavaClass klass; - - public MetaObject (Expression parameter, DynamicJavaClass klass) - : base (parameter, klass, klass.info) - { - this.klass = klass; - } - - protected override bool Disposed { - get {return klass.disposed;} - } - - protected override JniObjectReference ConversionTarget { - get { - return klass.info.Members.JniPeerType.PeerReference; - } - } - - protected override bool HasSelf { - get {return false;} - } - - protected override Expression GetSelf () - { - return Expression.Constant (null, typeof (IJavaPeerable)); - } - - public override DynamicMetaObject BindInvoke (InvokeBinder binder, DynamicMetaObject[] args) - { - if (klass.info == null || klass.info.Disposed) - return binder.FallbackInvoke (this, args); - - var constructors = klass.info.Constructors; - if (constructors == null) - return binder.FallbackInvoke (this, args); - - if (Disposed) { - return new DynamicMetaObject (ThrowObjectDisposedException (typeof (object)), BindingRestrictions.GetInstanceRestriction (Expression, Value)); - } - - var applicable = constructors.Where (o => o.ArgumentTypes.Count == args.Length).ToArray (); - if (applicable.Length == 0) - return binder.FallbackInvoke (this, args); - - TryInvokeMember invoke = klass.info.TryInvokeMember; - var value = Expression.Parameter (typeof (object), "value"); - var fallback = binder.FallbackInvoke (this, args); - var call = Expression.Block ( - new[]{value}, - Expression.Condition ( - test: Expression.Call (Expression.Constant (klass.info), invoke.GetMethodInfo (), - Expression.Constant (null, typeof (IJavaPeerable)), Expression.Constant (applicable), Expression.Constant (args), value), - ifTrue: value, - ifFalse: fallback.Expression) - ); - return new DynamicMetaObject (call, BindingRestrictions.GetInstanceRestriction (Expression, Value)); - } - } - } - - static class JavaModifiers { - public static readonly int Static; - - static JavaModifiers () - { - using (var t = new JniType ("java/lang/reflect/Modifier")) { - var s = t.GetStaticField ("STATIC", "I"); - Static = JniEnvironment.StaticFields.GetStaticIntField (t.PeerReference, s); - } - } - } -} - diff --git a/src/Java.Interop.Dynamic/Java.Interop.Dynamic/DynamicJavaInstance.cs b/src/Java.Interop.Dynamic/Java.Interop.Dynamic/DynamicJavaInstance.cs deleted file mode 100644 index d79be95cb..000000000 --- a/src/Java.Interop.Dynamic/Java.Interop.Dynamic/DynamicJavaInstance.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Dynamic; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Text; - -using Java.Interop; - - -namespace Java.Interop.Dynamic { - - public class DynamicJavaInstance : IDynamicMetaObjectProvider, IDisposable { - - JavaClassInfo klass; - - public DynamicJavaInstance (IJavaPeerable value) - { - if (value == null) - throw new ArgumentNullException ("value"); - - Value = value; - - var type = JniEnvironment.Types.GetJniTypeNameFromInstance (value.PeerReference) ?? - throw new InvalidOperationException ($"Could not get JniType from value `{value}`."); - klass = JavaClassInfo.GetClassInfo (type); - } - - bool disposed; - - public IJavaPeerable Value {get; private set;} - - public void Dispose () - { - Dispose (disposing: true); - GC.SuppressFinalize (this); - } - - protected virtual void Dispose (bool disposing) - { - if (disposed) - return; - - if (disposing) { - var java = Value as IJavaPeerable; - if (java != null) { - java.DisposeUnlessReferenced (); - } - - if (klass != null) - klass.Dispose (); - } - - disposed = true; - Value = null!; - klass = null!; - } - - DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject (Expression parameter) - { - return new MetaObject (parameter, this); - } - - class MetaObject : JniMetaObject { - - DynamicJavaInstance instance; - - public MetaObject (Expression parameter, DynamicJavaInstance instance) - : base (parameter, instance, instance.klass) - { - this.instance = instance; - } - - protected override bool Disposed { - get {return instance.disposed;} - } - - protected override JniObjectReference ConversionTarget { - get { - return instance.Value.PeerReference; - } - } - - protected override bool HasSelf { - get {return (instance.Value as IJavaPeerable) != null;} - } - - protected override Expression GetSelf () - { - return Expression.Constant (instance.Value as IJavaPeerable, typeof (IJavaPeerable)); - } - } - } -} - diff --git a/src/Java.Interop.Dynamic/Java.Interop.Dynamic/JavaClassInfo.cs b/src/Java.Interop.Dynamic/Java.Interop.Dynamic/JavaClassInfo.cs deleted file mode 100644 index 666c2265d..000000000 --- a/src/Java.Interop.Dynamic/Java.Interop.Dynamic/JavaClassInfo.cs +++ /dev/null @@ -1,348 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Dynamic; -using System.Runtime.CompilerServices; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Threading; -using System.Text; - -using Java.Interop; - -namespace Java.Interop.Dynamic { - - class JavaClassInfo : IDisposable { - - static readonly Func CreatePeerMembers; - - static readonly JniMethodInfo Class_getConstructors; - static readonly JniMethodInfo Class_getFields; - static readonly JniMethodInfo Class_getMethods; - - static readonly JniMethodInfo Constructor_getParameterTypes; - - static readonly JniMethodInfo Field_getName; - static readonly JniMethodInfo Field_getType; - - static readonly JniMethodInfo Method_getName; - static readonly JniMethodInfo Method_getReturnType; - static readonly JniMethodInfo Method_getParameterTypes; - - static readonly JniMethodInfo Member_getModifiers; - - static readonly Dictionary Classes = new Dictionary (); - - static JavaClassInfo () - { - CreatePeerMembers = (Func) typeof (JniPeerMembers) - .GetTypeInfo () - .GetDeclaredMethod ("CreatePeerMembers") - .CreateDelegate (typeof (Func)); - if (CreatePeerMembers == null) - throw new NotSupportedException ("Could not find JniPeerMembers.CreatePeerMembers!"); - - using (var t = new JniType ("java/lang/Class")) { - Class_getConstructors = t.GetInstanceMethod ("getConstructors", "()[Ljava/lang/reflect/Constructor;"); - Class_getFields = t.GetInstanceMethod ("getFields", "()[Ljava/lang/reflect/Field;"); - Class_getMethods = t.GetInstanceMethod ("getMethods", "()[Ljava/lang/reflect/Method;"); - } - using (var t = new JniType ("java/lang/reflect/Constructor")) { - Constructor_getParameterTypes = t.GetInstanceMethod ("getParameterTypes", "()[Ljava/lang/Class;"); - } - using (var t = new JniType ("java/lang/reflect/Field")) { - Field_getName = t.GetInstanceMethod ("getName", "()Ljava/lang/String;"); - Field_getType = t.GetInstanceMethod ("getType", "()Ljava/lang/Class;"); - } - using (var t = new JniType ("java/lang/reflect/Method")) { - Method_getName = t.GetInstanceMethod ("getName", "()Ljava/lang/String;"); - Method_getParameterTypes = t.GetInstanceMethod ("getParameterTypes", "()[Ljava/lang/Class;"); - Method_getReturnType = t.GetInstanceMethod ("getReturnType", "()Ljava/lang/Class;"); - } - using (var t = new JniType ("java/lang/reflect/Member")) { - Member_getModifiers = t.GetInstanceMethod ("getModifiers", "()I"); - } - } - - public static JavaClassInfo GetClassInfo (string jniClassName) - { - lock (Classes) { - JavaClassInfo? info = _GetClassInfo (jniClassName); - if (info != null) { - Interlocked.Increment (ref info.RefCount); - return info; - } - - info = new JavaClassInfo (jniClassName); - Classes.Add (jniClassName, new WeakReference (info)); - return info; - } - } - - static JavaClassInfo? _GetClassInfo (string jniClassName) - { - lock (Classes) { - WeakReference value; - if (Classes.TryGetValue (jniClassName, out value)) { - var info = (JavaClassInfo) value.Target; - if (info != null) { - return info; - } - Classes.Remove (jniClassName); - } - - return null; - } - } - - // For testing - public static int GetClassInfoCount (string jniClassName) - { - lock (Classes) { - var info = _GetClassInfo (jniClassName); - if (info != null) - return info.RefCount; - return -1; - } - } - - public string JniClassName {get; private set;} - - internal bool Disposed; - internal JniPeerMembers Members; - - int RefCount = 1; - - List? constructors; - Dictionary>? fields; - Dictionary>? methods; - - public List? Constructors { - get {return LookupConstructors ();} - } - - public Dictionary>? Fields { - get {return LookupFields ();} - } - - public Dictionary>? Methods { - get {return LookupMethods ();} - } - - - JavaClassInfo (string jniClassName) - { - if (jniClassName == null) - throw new ArgumentNullException ("jniClassName"); - - JniClassName = jniClassName; - Members = CreatePeerMembers (jniClassName, typeof (JavaInstanceProxy)); - } - - public void Dispose () - { - lock (Classes) { - if (Interlocked.Decrement (ref RefCount) != 0) - return; - - Disposed = true; - - if (methods != null) { - foreach (var name in methods.Keys.ToList ()) { - foreach (var info in methods [name]) - info.Dispose (); - methods.Remove (name); - } - } - - JniPeerMembers.Dispose (Members); - Classes.Remove (JniClassName); - } - } - - internal static JniObjectReference GetMethodParameters (JniObjectReference method) - { - return JniEnvironment.InstanceMethods.CallObjectMethod (method, Method_getParameterTypes); - } - - internal static JniObjectReference GetConstructorParameters (JniObjectReference method) - { - return JniEnvironment.InstanceMethods.CallObjectMethod (method, Constructor_getParameterTypes); - } - - List? LookupConstructors () - { - if (Members == null) - return null; - - lock (Members) { - if (constructors != null || Disposed) - return constructors; - - constructors = new List (); - - var ctors = JniEnvironment.InstanceMethods.CallObjectMethod (Members.JniPeerType.PeerReference, Class_getConstructors); - try { - int len = JniEnvironment.Arrays.GetArrayLength (ctors); - for (int i = 0; i < len; ++i) { - var ctor = JniEnvironment.Arrays.GetObjectArrayElement (ctors, i); - var m = new JavaConstructorInfo (Members, ctor); - constructors.Add (m); - JniObjectReference.Dispose (ref ctor); - } - } finally { - JniObjectReference.Dispose (ref ctors); - } - - return constructors; - } - } - - Dictionary>? LookupFields () - { - if (Members == null) - return null; - - lock (Members) { - if (this.fields != null || Disposed) - return this.fields; - - this.fields = new Dictionary> (); - - var fields = JniEnvironment.InstanceMethods.CallObjectMethod (Members.JniPeerType.PeerReference, Class_getFields); - try { - int len = JniEnvironment.Arrays.GetArrayLength (fields); - for (int i = 0; i < len; ++i) { - var field = JniEnvironment.Arrays.GetObjectArrayElement (fields, i); - var n_name = JniEnvironment.InstanceMethods.CallObjectMethod (field, Field_getName); - var isStatic = IsStatic (field); - var name = JniEnvironment.Strings.ToString (ref n_name, JniObjectReferenceOptions.CopyAndDispose) ?? - throw new InvalidOperationException ($"Could not determine field name at index {i}!"); - - List? overloads = null; - if (!Fields?.TryGetValue (name, out overloads) ?? false) - Fields!.Add (name, overloads = new List ()); - - var n_type = JniEnvironment.InstanceMethods.CallObjectMethod (field, Field_getType); - using (var type = new JniType (ref n_type, JniObjectReferenceOptions.CopyAndDispose)) { - var sig = JniTypeSignature.Parse (type.Name); - overloads?.Add (new JavaFieldInfo (Members, name + "." + sig.QualifiedReference, isStatic)); - } - - JniObjectReference.Dispose (ref field); - } - } finally { - JniObjectReference.Dispose (ref fields); - } - - return this.fields; - } - } - - Dictionary>? LookupMethods () - { - if (Members == null) - return null; - - lock (Members) { - if (this.methods != null || Disposed) - return this.methods; - - this.methods = new Dictionary> (); - - var methods = JniEnvironment.InstanceMethods.CallObjectMethod (Members.JniPeerType.PeerReference, Class_getMethods); - try { - int len = JniEnvironment.Arrays.GetArrayLength (methods); - for (int i = 0; i < len; ++i) { - var method = JniEnvironment.Arrays.GetObjectArrayElement (methods, i); - var n_name = JniEnvironment.InstanceMethods.CallObjectMethod (method, Method_getName); - var isStatic = IsStatic (method); - var name = JniEnvironment.Strings.ToString (ref n_name, JniObjectReferenceOptions.CopyAndDispose) ?? - throw new InvalidOperationException ($"Could not determine method name at index {i}!"); - - List? overloads = null; - if (!Methods?.TryGetValue (name, out overloads) ?? false) - Methods!.Add (name, overloads = new List ()); - - var nrt = JniEnvironment.InstanceMethods.CallObjectMethod (method, Method_getReturnType); - var rt = new JniType (ref nrt, JniObjectReferenceOptions.CopyAndDispose); - var m = new JavaMethodInfo (Members, method, name, isStatic) { - ReturnType = rt, - }; - overloads?.Add (m); - JniObjectReference.Dispose (ref method); - } - } finally { - JniObjectReference.Dispose (ref methods); - } - - return this.methods; - } - } - - static bool IsStatic (JniObjectReference member) - { - var s = JniEnvironment.InstanceMethods.CallIntMethod (member, Member_getModifiers); - - return (s & JavaModifiers.Static) == JavaModifiers.Static; - } - - internal unsafe bool TryInvokeMember (IJavaPeerable self, JavaMethodBase[] overloads, DynamicMetaObject[] args, out object? value) - { - value = null; - var vms = (List?) null; - var states = (JniValueMarshalerState[]?) null; - - var jtypes = GetJniTypes (args); - try { - var matches = overloads.Where (o => (o.IsConstructor || o.IsStatic == (self == null)) && o.CompatibleWith (jtypes, args)); - var invoke = matches.FirstOrDefault (); - if (invoke == null) - return false; - - var jvm = JniEnvironment.Runtime; - vms = args.Select (arg => jvm.ValueManager.GetValueMarshaler (arg.LimitType)).ToList (); - states = new JniValueMarshalerState [vms.Count]; - for (int i = 0; i < vms.Count; ++i) { - states [i] = vms [i].CreateArgumentState (args [i].Value); - } - var jargs = stackalloc JniArgumentValue [vms.Count]; - for (int i = 0; i < states.Length; ++i) - jargs [i] = states [i].JniArgumentValue; - value = invoke.Invoke (self, jargs); - return true; - } - finally { - for (int i = 0; vms != null && i < vms.Count; ++i) { - if (states == null) { - continue; - } - vms [i].DestroyArgumentState (args [i].Value, ref states [i]); - } - for (int i = 0; i < jtypes.Count; ++i) { - jtypes [i]?.Dispose (); - } - } - } - - static List GetJniTypes (DynamicMetaObject[] args) - { - var r = new List (args.Length); - var vm = JniEnvironment.Runtime; - foreach (var a in args) { - try { - var at = new JniType (vm.TypeManager.GetTypeSignature (a.LimitType).Name); - r.Add (at); - } catch (JavaException e) { - e.Dispose (); - r.Add (null); - } catch { - r.Add (null); - } - } - return r; - } - } -} - diff --git a/src/Java.Interop.Dynamic/Java.Interop.Dynamic/JavaConstructorInfo.cs b/src/Java.Interop.Dynamic/Java.Interop.Dynamic/JavaConstructorInfo.cs deleted file mode 100644 index 07424fff9..000000000 --- a/src/Java.Interop.Dynamic/Java.Interop.Dynamic/JavaConstructorInfo.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Dynamic; -using System.Runtime.CompilerServices; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Threading; -using System.Text; - -using Java.Interop; - -namespace Java.Interop.Dynamic { - - class JavaConstructorInfo : JavaMethodBase { - - public JavaConstructorInfo (JniPeerMembers members, JniObjectReference method) - : base (members, method) - { - } - - public override string Name { - get {return "";} - } - - public override bool IsStatic { - get {return false;} - } - - public override bool IsConstructor { - get {return true;} - } - - protected override string JniReturnType { - get {return "V";} - } - - public override unsafe object? Invoke (IJavaPeerable? self, JniArgumentValue* arguments) - { - var signature = JniSignature ?? throw new InvalidOperationException ("No JniSignature!"); - if (self == null) { - var h = members.InstanceMethods.StartCreateInstance (signature, typeof (JavaInstanceProxy), arguments); - self = JniEnvironment.Runtime.ValueManager.GetValue (ref h, JniObjectReferenceOptions.CopyAndDispose); - if (self == null) { - throw new InvalidOperationException ($"Could not create instance of {members.ManagedPeerType}!"); - } - } - members.InstanceMethods.FinishCreateInstance (signature, self, arguments); - return new DynamicJavaInstance (self); - } - } -} diff --git a/src/Java.Interop.Dynamic/Java.Interop.Dynamic/JavaFieldInfo.cs b/src/Java.Interop.Dynamic/Java.Interop.Dynamic/JavaFieldInfo.cs deleted file mode 100644 index 33e7a5c0e..000000000 --- a/src/Java.Interop.Dynamic/Java.Interop.Dynamic/JavaFieldInfo.cs +++ /dev/null @@ -1,186 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Dynamic; -using System.Runtime.CompilerServices; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Threading; -using System.Text; - -using Java.Interop; - -namespace Java.Interop.Dynamic { - - class JavaFieldInfo : JavaMemberInfo { - - public string JniSignature; - - JniPeerMembers members; - bool isStatic; - - public JavaFieldInfo (JniPeerMembers members, string jniSignature, bool isStatic) - { - this.members = members; - this.isStatic = isStatic; - JniSignature = jniSignature; - } - - public override bool IsStatic { - get {return isStatic;} - } - - public override string Name { - get { - var i = JniSignature.IndexOf ('.'); - return JniSignature.Substring (0, i); - } - } - - public object? GetValue (IJavaPeerable self) - { - AssertSelf (self); - - if (IsStatic) - return GetStaticValue (); - return GetInstanceValue (self); - } - - void AssertSelf (IJavaPeerable self) - { - if (IsStatic && self != null) - throw new ArgumentException ( - string.Format ("Field '{0}' is static but an instance was provided.", JniSignature), - "self"); - if (!IsStatic && self == null) - throw new ArgumentException ( - string.Format ("Field '{0}' is an instance field but no instance was provided.", JniSignature), - "self"); - } - - object? GetStaticValue () - { - var n = GetSignatureStartIndex (); - switch (JniSignature [n + 1]) { - case 'Z': return members.StaticFields.GetBooleanValue (JniSignature); - case 'B': return members.StaticFields.GetSByteValue (JniSignature); - case 'C': return members.StaticFields.GetCharValue (JniSignature); - case 'S': return members.StaticFields.GetInt16Value (JniSignature); - case 'I': return members.StaticFields.GetInt32Value (JniSignature); - case 'J': return members.StaticFields.GetInt64Value (JniSignature); - case 'F': return members.StaticFields.GetSingleValue (JniSignature); - case 'D': return members.StaticFields.GetDoubleValue (JniSignature); - case 'L': - case '[': - var lref = members.StaticFields.GetObjectValue (JniSignature); - return ToReturnValue (ref lref, JniSignature, n + 1); - default: - throw new NotSupportedException ("Unsupported argument type: " + JniSignature.Substring (n + 1)); - } - } - - object? GetInstanceValue (IJavaPeerable self) - { - var n = GetSignatureStartIndex (); - switch (JniSignature [n + 1]) { - case 'Z': return members.InstanceFields.GetBooleanValue (JniSignature, self); - case 'B': return members.InstanceFields.GetSByteValue (JniSignature, self); - case 'C': return members.InstanceFields.GetCharValue (JniSignature, self); - case 'S': return members.InstanceFields.GetInt16Value (JniSignature, self); - case 'I': return members.InstanceFields.GetInt32Value (JniSignature, self); - case 'J': return members.InstanceFields.GetInt64Value (JniSignature, self); - case 'F': return members.InstanceFields.GetSingleValue (JniSignature, self); - case 'D': return members.InstanceFields.GetDoubleValue (JniSignature, self); - case 'L': - case '[': - var lref = members.InstanceFields.GetObjectValue (JniSignature, self); - return ToReturnValue (ref lref, JniSignature, n + 1); - default: - throw new NotSupportedException ("Unsupported argument type: " + JniSignature.Substring (n + 1)); - } - } - - int GetSignatureStartIndex () - { - int n = JniSignature.IndexOf ('.'); - if (n == JniSignature.Length - 1) - throw new NotSupportedException ( - string.Format ("Could not determine field type from signature '{0}'.", JniSignature)); - return n; - } - - public void SetValue (IJavaPeerable self, object? value) - { - AssertSelf (self); - - if (IsStatic) { - SetStaticValue (value); - } else { - SetInstanceValue (self, value); - } - } - - void SetStaticValue (object? value) - { - var n = GetSignatureStartIndex (); - switch (JniSignature [n + 1]) { - case 'Z': members.StaticFields.SetValue (JniSignature, (bool) value!); break; - case 'B': members.StaticFields.SetValue (JniSignature, (byte) value!); break; - case 'C': members.StaticFields.SetValue (JniSignature, (char) value!); break; - case 'S': members.StaticFields.SetValue (JniSignature, (short) value!); break; - case 'I': members.StaticFields.SetValue (JniSignature, (int) value!); break; - case 'J': members.StaticFields.SetValue (JniSignature, (long) value!); break; - case 'F': members.StaticFields.SetValue (JniSignature, (float) value!); break; - case 'D': members.StaticFields.SetValue (JniSignature, (double) value!); break; - case 'L': - case '[': - if (value == null) { - members.StaticFields.SetValue (JniSignature, new JniObjectReference ()); - return; - } - var vm = JniEnvironment.Runtime.ValueManager.GetValueMarshaler (value.GetType ()); - var s = vm.CreateArgumentState (value); - try { - members.StaticFields.SetValue (JniSignature, s.ReferenceValue); - } finally { - vm.DestroyArgumentState (value, ref s, 0); - } - return; - default: - throw new NotSupportedException ("Unsupported argument type: " + JniSignature.Substring (n + 1)); - } - } - - void SetInstanceValue (IJavaPeerable self, object? value) - { - var n = GetSignatureStartIndex (); - switch (JniSignature [n + 1]) { - case 'Z': members.InstanceFields.SetValue (JniSignature, self, (bool) value!); break; - case 'B': members.InstanceFields.SetValue (JniSignature, self, (byte) value!); break; - case 'C': members.InstanceFields.SetValue (JniSignature, self, (char) value!); break; - case 'S': members.InstanceFields.SetValue (JniSignature, self, (short) value!); break; - case 'I': members.InstanceFields.SetValue (JniSignature, self, (int) value!); break; - case 'J': members.InstanceFields.SetValue (JniSignature, self, (long) value!); break; - case 'F': members.InstanceFields.SetValue (JniSignature, self, (float) value!); break; - case 'D': members.InstanceFields.SetValue (JniSignature, self, (double) value!); break; - case 'L': - case '[': - if (value == null) { - members.InstanceFields.SetValue (JniSignature, self, new JniObjectReference ()); - return; - } - var vm = JniEnvironment.Runtime.ValueManager.GetValueMarshaler (value.GetType ()); - var s = vm.CreateArgumentState (value); - try { - members.InstanceFields.SetValue (JniSignature, self, s.ReferenceValue); - } finally { - vm.DestroyArgumentState (value, ref s, 0); - } - return; - default: - throw new NotSupportedException ("Unsupported argument type: " + JniSignature.Substring (n + 1)); - } - } - } -} diff --git a/src/Java.Interop.Dynamic/Java.Interop.Dynamic/JavaInstanceProxy.cs b/src/Java.Interop.Dynamic/Java.Interop.Dynamic/JavaInstanceProxy.cs deleted file mode 100644 index d4079746f..000000000 --- a/src/Java.Interop.Dynamic/Java.Interop.Dynamic/JavaInstanceProxy.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Dynamic; -using System.Runtime.CompilerServices; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Threading; -using System.Text; - -using Java.Interop; - -namespace Java.Interop.Dynamic { - - [JniTypeSignature ("java/lang/Object", GenerateJavaPeer=false)] - class JavaInstanceProxy : JavaObject { - - public JavaInstanceProxy (ref JniObjectReference reference, JniObjectReferenceOptions transfer) - : base (ref reference, transfer) - { - } - } - -} diff --git a/src/Java.Interop.Dynamic/Java.Interop.Dynamic/JavaMemberInfo.cs b/src/Java.Interop.Dynamic/Java.Interop.Dynamic/JavaMemberInfo.cs deleted file mode 100644 index c3508e16d..000000000 --- a/src/Java.Interop.Dynamic/Java.Interop.Dynamic/JavaMemberInfo.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; - -namespace Java.Interop.Dynamic { - - abstract class JavaMemberInfo : IDisposable { - - public abstract string Name {get;} - public abstract bool IsStatic {get;} - - protected JavaMemberInfo () - { - } - - public void Dispose () - { - Dispose (disposing: true); - } - - protected virtual void Dispose (bool disposing) - { - } - - protected static object? ToReturnValue (ref JniObjectReference handle, string signature, int n) - { - var instance = JniEnvironment.Runtime.ValueManager.GetValue (ref handle, JniObjectReferenceOptions.CopyAndDispose); - if (instance == null) { - return null; - } - switch (signature [n]) { - case 'L': - return new DynamicJavaInstance (instance); - case '[': - default: - return instance; - } - } - } -} - diff --git a/src/Java.Interop.Dynamic/Java.Interop.Dynamic/JavaMethodBase.cs b/src/Java.Interop.Dynamic/Java.Interop.Dynamic/JavaMethodBase.cs deleted file mode 100644 index c556d8a2b..000000000 --- a/src/Java.Interop.Dynamic/Java.Interop.Dynamic/JavaMethodBase.cs +++ /dev/null @@ -1,140 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Dynamic; -using System.Runtime.CompilerServices; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Threading; -using System.Text; - -using Java.Interop; - -namespace Java.Interop.Dynamic { - - abstract class JavaMethodBase : JavaMemberInfo { - - public abstract bool IsConstructor {get;} - - public abstract unsafe object? Invoke (IJavaPeerable? self, JniArgumentValue* arguments); - - protected abstract string JniReturnType {get;} - - public JniObjectReference PeerReference {get; private set;} - public string? JniSignature {get; private set;} - - protected JniPeerMembers members; - - List? arguments; - public List ArgumentTypes { - get { - LookupArguments (); - return arguments!; - } - } - - public string JniDeclaringClassName { - get { return members == null ? "" : members.JniPeerTypeName; } - } - - public JavaMethodBase (JniPeerMembers members, JniObjectReference method) - { - this.members = members; - PeerReference = method.NewGlobalRef (); - } - - protected override void Dispose (bool disposing) - { - if (!disposing || !PeerReference.IsValid) - return; - - var pr = PeerReference; - JniObjectReference.Dispose (ref pr); - PeerReference = pr; - - members = null!; - - if (arguments == null) - return; - - for (int i = 0; i < arguments.Count; ++i) { - var a = arguments [i]; - JniObjectReference.Dispose (ref a); - arguments [i] = a; - } - arguments = null; - } - - public void LookupArguments () - { - if (arguments != null) - return; - - var vm = JniEnvironment.Runtime; - var sb = new StringBuilder (); - var mgr = vm.TypeManager; - - if (!IsConstructor) { - sb.Append (Name).Append ("."); - } - - sb.Append ("("); - - var parameters = IsConstructor - ? JavaClassInfo.GetConstructorParameters (PeerReference) - : JavaClassInfo.GetMethodParameters (PeerReference); - try { - int len = JniEnvironment.Arrays.GetArrayLength (parameters); - arguments = new List (len); - for (int i = 0; i < len; ++i) { - var p = JniEnvironment.Arrays.GetObjectArrayElement (parameters, i); - try { - var typeName = JniEnvironment.Types.GetJniTypeNameFromClass (p) ?? - throw new NotSupportedException ($"Could not determine class for {p}."); - var sig = JniTypeSignature.Parse (typeName); - sb.Append (sig.QualifiedReference); - arguments.Add (p.NewGlobalRef ()); - } finally { - JniObjectReference.Dispose (ref p); - } - } - } finally { - JniObjectReference.Dispose (ref parameters); - } - sb.Append (")").Append (JniReturnType); - JniSignature = sb.ToString (); - } - - public bool CompatibleWith (List argumentTypes, DynamicMetaObject[] argumentValues) - { - LookupArguments (); - - if (argumentTypes.Count != arguments?.Count) - return false; - - var vm = JniEnvironment.Runtime; - - for (int i = 0; i < arguments.Count; ++i) { - if (argumentTypes [i] == null) { - // Builtin type -- JNIEnv.FindClass("I") throws! - if (JniEnvironment.Types.GetJniTypeNameFromClass (arguments [i]) != vm.TypeManager.GetTypeSignature (argumentValues [i].LimitType).Name) - return false; - } - else if (!JniEnvironment.Types.IsAssignableFrom (arguments [i], argumentTypes [i]?.PeerReference ?? default)) - return false; - } - return true; - } - - public override string ToString () - { - return string.Format ("{0}{1}({2}) -> {3}", - IsStatic ? "static " : "", - Name, - string.Join (", ", ArgumentTypes.Select (a => JniEnvironment.Types.GetJniTypeNameFromClass (a))), - JniReturnType); - } - } - -} diff --git a/src/Java.Interop.Dynamic/Java.Interop.Dynamic/JavaMethodInfo.cs b/src/Java.Interop.Dynamic/Java.Interop.Dynamic/JavaMethodInfo.cs deleted file mode 100644 index abb2d9cac..000000000 --- a/src/Java.Interop.Dynamic/Java.Interop.Dynamic/JavaMethodInfo.cs +++ /dev/null @@ -1,138 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Dynamic; -using System.Runtime.CompilerServices; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Threading; -using System.Text; - -using Java.Interop; - -namespace Java.Interop.Dynamic { - - class JavaMethodInfo : JavaMethodBase { - - public JniType? ReturnType; - - string name; - bool isStatic; - - public JavaMethodInfo (JniPeerMembers members, JniObjectReference method, string name, bool isStatic) - : base (members, method) - { - this.name = name; - this.isStatic = isStatic; - } - - public override string Name { - get {return name;} - } - - public override bool IsStatic { - get {return isStatic;} - } - - public override bool IsConstructor { - get {return false;} - } - - protected override void Dispose (bool disposing) - { - if (!disposing || ReturnType == null) - return; - - ReturnType.Dispose (); - ReturnType = null; - } - - protected override string JniReturnType { - get { - if (ReturnType == null) - return "V"; - return JniTypeSignature.Parse (ReturnType.Name).QualifiedReference; - } - } - - public override unsafe object? Invoke (IJavaPeerable? self, JniArgumentValue* arguments) - { - AssertSelf (self); - - if (IsStatic) - return InvokeStaticMethod (arguments); - return InvokeInstanceMethod (self!, arguments); - } - - void AssertSelf (IJavaPeerable? self) - { - if (IsStatic && self != null) - throw new ArgumentException ( - string.Format ("Field '{0}' is static but an instance was provided.", JniSignature), - "self"); - if (!IsStatic && self == null) - throw new ArgumentException ( - string.Format ("Field '{0}' is an instance field but no instance was provided.", JniSignature), - "self"); - } - - unsafe object? InvokeInstanceMethod (IJavaPeerable self, JniArgumentValue* arguments) - { - var e = GetSignatureReturnTypeStartIndex (); - switch (JniSignature?[e + 1]) { - case 'Z': return members.InstanceMethods.InvokeVirtualBooleanMethod (JniSignature, self, arguments); - case 'B': return members.InstanceMethods.InvokeVirtualSByteMethod (JniSignature, self, arguments); - case 'C': return members.InstanceMethods.InvokeVirtualCharMethod (JniSignature, self, arguments); - case 'S': return members.InstanceMethods.InvokeVirtualInt16Method (JniSignature, self, arguments); - case 'I': return members.InstanceMethods.InvokeVirtualInt32Method (JniSignature, self, arguments); - case 'J': return members.InstanceMethods.InvokeVirtualInt64Method (JniSignature, self, arguments); - case 'F': return members.InstanceMethods.InvokeVirtualSingleMethod (JniSignature, self, arguments); - case 'D': return members.InstanceMethods.InvokeVirtualDoubleMethod (JniSignature, self, arguments); - case 'L': - case '[': - var lref = members.InstanceMethods.InvokeVirtualObjectMethod (JniSignature, self, arguments); - return ToReturnValue (ref lref, JniSignature, e + 1); - case 'V': - members.InstanceMethods.InvokeVirtualVoidMethod (JniSignature, self, arguments); - return null; - default: - throw new NotSupportedException ("Unsupported argument type: " + JniSignature?.Substring (e + 1)); - } - } - - unsafe object? InvokeStaticMethod (JniArgumentValue* arguments) - { - var e = GetSignatureReturnTypeStartIndex (); - switch (JniSignature?[e + 1]) { - case 'Z': return members.StaticMethods.InvokeBooleanMethod (JniSignature, arguments); - case 'B': return members.StaticMethods.InvokeSByteMethod (JniSignature, arguments); - case 'C': return members.StaticMethods.InvokeCharMethod (JniSignature, arguments); - case 'S': return members.StaticMethods.InvokeInt16Method (JniSignature, arguments); - case 'I': return members.StaticMethods.InvokeInt32Method (JniSignature, arguments); - case 'J': return members.StaticMethods.InvokeInt64Method (JniSignature, arguments); - case 'F': return members.StaticMethods.InvokeSingleMethod (JniSignature, arguments); - case 'D': return members.StaticMethods.InvokeDoubleMethod (JniSignature, arguments); - case 'L': - case '[': - var lref = members.StaticMethods.InvokeObjectMethod (JniSignature, arguments); - return ToReturnValue (ref lref, JniSignature, e + 1); - case 'V': - members.StaticMethods.InvokeVoidMethod (JniSignature, arguments); - return null; - default: - throw new NotSupportedException ("Unsupported argument type: " + JniSignature?.Substring (e + 1)); - } - } - - protected int GetSignatureReturnTypeStartIndex () - { - int n = JniSignature?.IndexOf (')') ?? -1; - if (n == JniSignature?.Length - 1 || n < 0) - throw new NotSupportedException ( - string.Format ("Could not determine method return type from signature '{0}'.", JniSignature)); - return n; - } - } - -} diff --git a/src/Java.Interop.Dynamic/Java.Interop.Dynamic/JniMetaObject.cs b/src/Java.Interop.Dynamic/Java.Interop.Dynamic/JniMetaObject.cs deleted file mode 100644 index f2f354c32..000000000 --- a/src/Java.Interop.Dynamic/Java.Interop.Dynamic/JniMetaObject.cs +++ /dev/null @@ -1,165 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Dynamic; -using System.Runtime.CompilerServices; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Threading; -using System.Text; - -using Java.Interop; - -namespace Java.Interop.Dynamic { - - abstract class JniMetaObject : DynamicMetaObject - { - protected delegate bool TryInvokeMember (IJavaPeerable self, JavaMethodBase[] overloads, DynamicMetaObject[] args, out object? value); - - JavaClassInfo? info; - - public JniMetaObject (Expression parameter, object? value, JavaClassInfo info) - : base (parameter, BindingRestrictions.GetInstanceRestriction (parameter, value), value) - { - this.info = info; - } - - protected abstract bool Disposed {get;} - protected abstract JniObjectReference ConversionTarget {get;} - protected abstract bool HasSelf {get;} - - protected abstract Expression GetSelf (); - - public override IEnumerable GetDynamicMemberNames () - { - if (info == null || info.Disposed) - return new string[0]; - return (((IEnumerable?) info.Fields?.Keys) ?? Array.Empty ()).Concat ( - ((IEnumerable?) info.Methods?.Keys) ?? Array.Empty () - ); - } - - public override DynamicMetaObject BindConvert (ConvertBinder binder) - { - if (info == null || info.Disposed) - throw new ObjectDisposedException (GetType ().FullName); - - var vm = JniEnvironment.Runtime; - if (binder.Type == typeof (Type)) { - var sig = JniTypeSignature.Parse (info.JniClassName); - var type = vm.TypeManager.GetType (sig); - var typeE = Expression.Convert (Expression.Constant (type), binder.Type); - return new DynamicMetaObject (typeE, BindingRestrictions.GetTypeRestriction (typeE, binder.Type), type); - } - - object? value; - try { - var r = ConversionTarget; - value = vm.ValueManager.GetValue (ref r, JniObjectReferenceOptions.Copy, binder.Type); - } catch { - return binder.FallbackConvert (this); - } - - var valueE = Expression.Convert (Expression.Constant (value), binder.Type); - return new DynamicMetaObject (valueE, BindingRestrictions.GetTypeRestriction (valueE, binder.Type), value); - } - - public override DynamicMetaObject BindGetMember (GetMemberBinder binder) - { - if (info == null || info.Disposed) - throw new ObjectDisposedException (GetType ().FullName); - - List? overloads = GetFields (binder.Name); - if (overloads == null) - return binder.FallbackGetMember (this); - - if (Disposed) { - return new DynamicMetaObject (ThrowObjectDisposedException (typeof (object)), BindingRestrictions.GetInstanceRestriction (Expression, Value)); - } - - var field = overloads.FirstOrDefault (f => f.IsStatic == true); - - Func getValue = field.GetValue; - - var e = Expression.Call (Expression.Constant (field), getValue.GetMethodInfo (), GetSelf ()); - return new DynamicMetaObject (e, BindingRestrictions.GetInstanceRestriction (Expression, Value)); - } - - protected static Expression ThrowObjectDisposedException (Type? type = null) - { - return Expression.Throw (Expression.Constant (new ObjectDisposedException (nameof (DynamicJavaClass))), type); - } - - List? GetFields (string name) - { - if (info == null || info.Fields == null) - return null; - - List overloads; - if (info.Fields.TryGetValue (name, out overloads)) - return overloads; - - return null; - } - - public override DynamicMetaObject BindInvokeMember (InvokeMemberBinder binder, DynamicMetaObject[] args) - { - var overloads = GetMethods (binder.Name); - if (overloads == null) - return binder.FallbackInvokeMember (this, args); - - if (Disposed) { - return new DynamicMetaObject (ThrowObjectDisposedException (typeof (object)), BindingRestrictions.GetInstanceRestriction (Expression, Value)); - } - - var applicable = overloads.Where (o => (o.IsStatic == !HasSelf) && o.ArgumentTypes.Count == args.Length).ToArray (); - if (applicable.Length == 0) - return binder.FallbackInvokeMember (this, args); - - TryInvokeMember invoke = info!.TryInvokeMember; - var value = Expression.Parameter (typeof (object), "value"); - var fallback = binder.FallbackInvokeMember (this, args); - var call = Expression.Block ( - new[]{value}, - Expression.Condition ( - test: Expression.Call (Expression.Constant (info), invoke.GetMethodInfo (), GetSelf (), Expression.Constant (applicable), Expression.Constant (args), value), - ifTrue: value, - ifFalse: fallback.Expression) - ); - return new DynamicMetaObject (call, BindingRestrictions.GetInstanceRestriction (Expression, Value)); - } - - protected List? GetMethods (string name) - { - if (info == null || info.Methods == null) - return null; - - List overloads; - if (info.Methods.TryGetValue (name, out overloads)) - return overloads; - - return null; - } - - public override DynamicMetaObject BindSetMember (SetMemberBinder binder, DynamicMetaObject value) - { - List? overloads = GetFields (binder.Name); - if (overloads == null) - return binder.FallbackSetMember (this, value); - - if (Disposed) { - return new DynamicMetaObject (ThrowObjectDisposedException (), BindingRestrictions.GetInstanceRestriction (Expression, Value)); - } - - var field = overloads.FirstOrDefault (f => f.IsStatic == true); - - Action setValue = field.SetValue; - var e = Expression.Block ( - Expression.Call (Expression.Constant (field), setValue.GetMethodInfo (), - GetSelf (), Expression.Convert (value.Expression, typeof (object))), - Expression); - return new DynamicMetaObject (e, BindingRestrictions.GetInstanceRestriction (Expression, Value)); - } - } -} diff --git a/tests/Java.Interop.Dynamic-Tests/Java.Interop.Dynamic-Tests.csproj b/tests/Java.Interop.Dynamic-Tests/Java.Interop.Dynamic-Tests.csproj deleted file mode 100644 index 6ba3b3128..000000000 --- a/tests/Java.Interop.Dynamic-Tests/Java.Interop.Dynamic-Tests.csproj +++ /dev/null @@ -1,29 +0,0 @@ - - - - $(DotNetTargetFramework) - false - true - - - - - - $(TestOutputFullPath) - - - - - - - - - - - - - - - - - diff --git a/tests/Java.Interop.Dynamic-Tests/Java.Interop/DynamicJavaClassTests.cs b/tests/Java.Interop.Dynamic-Tests/Java.Interop/DynamicJavaClassTests.cs deleted file mode 100644 index b3ed85508..000000000 --- a/tests/Java.Interop.Dynamic-Tests/Java.Interop/DynamicJavaClassTests.cs +++ /dev/null @@ -1,156 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Threading; - -using Java.Interop; -using Java.Interop.Dynamic; - -using NUnit.Framework; - -namespace Java.Interop.DynamicTests { - - class MyDynamicObject : DynamicJavaClass { - - public MyDynamicObject () - : base ("java/lang/Object") - { - } - - public int MyProperty {get; set;} - - public int Method (string value) - { - return value.Length; - } - } - - [TestFixture] - class DynamicJavaClassTests : Java.InteropTests.JavaVMFixture - { - const string Arrays_class = "java/util/Arrays"; - const string Integer_class = "java/lang/Integer"; - - [Test] - public void Constructor () - { - Assert.Throws (() => new DynamicJavaClass (null)); - } - - [Test] - public void DisposedInstanceThrowsObjectDisposedException () - { - dynamic Integer = new DynamicJavaClass (Integer_class); - Assert.AreEqual (1, JavaClassInfo.GetClassInfoCount (Integer_class)); - Integer.Dispose (); - Assert.AreEqual (-1, JavaClassInfo.GetClassInfoCount (Integer_class)); - Integer.Dispose (); // Dispose() is idempotent - Assert.Catch (() => Integer.bitCount (2)); - Assert.Catch (() => { - int max = Integer.MAX_INT; - max = max > 0 ? max : max; - }); - Assert.Catch (() => { - Integer.MAX_INT = 42; - }); - } - - [Test] - public void JniClassName () - { - dynamic Arrays = new DynamicJavaClass (Arrays_class); - Assert.AreEqual (1, JavaClassInfo.GetClassInfoCount (Arrays_class)); - Assert.AreEqual (Arrays_class, Arrays.JniClassName); - Arrays.Dispose (); - Assert.AreEqual (-1, JavaClassInfo.GetClassInfoCount (Arrays_class)); - } - - [Test] - public void CallStaticMethod () - { - dynamic Arrays = new DynamicJavaClass (Arrays_class); - var array = new int[]{ 1, 2, 3, 4 }; - int value = 3; - int index = Arrays.binarySearch (array, value); - Assert.AreEqual (2, index); - Arrays.Dispose (); - } - - [Test] - public void ReadStaticMember () - { - dynamic Integer = new DynamicJavaClass (Integer_class); - int max = Integer.MAX_VALUE; - Assert.AreEqual (int.MaxValue, max); - Integer.Dispose (); - } - - [Test] - public void WriteStaticMember () - { - dynamic Integer = new DynamicJavaClass (Integer_class); - int cur = Integer.MAX_VALUE; - Console.WriteLine ("# MAX_VALUE={0}", cur); - Integer.MAX_VALUE = 42; - int max = Integer.MAX_VALUE; - Console.WriteLine ("# set MAX_VALUE=42"); - Assert.AreEqual (42, max); - Integer.MAX_VALUE = cur; - Console.WriteLine ("# done!"); - Integer.Dispose (); - } - - [Test] - public void FallbackPropertySet () - { - dynamic d = new MyDynamicObject (); - - d.MyProperty = 42; - int v = d.MyProperty; - Assert.AreEqual (42, v); - d.Dispose (); - } - - [Test] - public void FallbackInvokeMember () - { - dynamic d = new MyDynamicObject (); - int v = d.Method ("foo"); - Assert.AreEqual (3, v); - d.Dispose (); - } - - [Test] - public void InvokeConstructor () - { - dynamic Integer = new DynamicJavaClass (Integer_class); - Assert.AreEqual (1, JavaClassInfo.GetClassInfoCount (Integer_class)); - dynamic value = Integer (42); - Assert.AreEqual (2, JavaClassInfo.GetClassInfoCount (Integer_class)); - Assert.IsTrue (value is DynamicJavaInstance); - value.Dispose (); - Assert.AreEqual (1, JavaClassInfo.GetClassInfoCount (Integer_class)); - Integer.Dispose (); - Assert.AreEqual (-1, JavaClassInfo.GetClassInfoCount (Integer_class)); - } - } - - static class JavaClassInfo { - - static Func getClassInfoCount; - - static JavaClassInfo () - { - var t = typeof (DynamicJavaClass).Assembly.GetType ("Java.Interop.Dynamic.JavaClassInfo"); - getClassInfoCount = (Func) - Delegate.CreateDelegate (typeof (Func), t.GetMethod ("GetClassInfoCount")); - } - - public static int GetClassInfoCount (string jniClassName) - { - return getClassInfoCount (jniClassName); - } - } -} - diff --git a/tests/Java.Interop.Dynamic-Tests/Java.Interop/DynamicJavaInstanceTests.cs b/tests/Java.Interop.Dynamic-Tests/Java.Interop/DynamicJavaInstanceTests.cs deleted file mode 100644 index 345163e69..000000000 --- a/tests/Java.Interop.Dynamic-Tests/Java.Interop/DynamicJavaInstanceTests.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Threading; - -using Java.Interop; -using Java.Interop.Dynamic; - -using NUnit.Framework; - -namespace Java.Interop.DynamicTests { - - [TestFixture] - class DynamicJavaInstanceTests : Java.InteropTests.JavaVMFixture - { - [Test] - public void Constructor () - { - Assert.Throws (() => new DynamicJavaInstance (null)); - } - - [Test] - public void DisposeWithJavaObjectDisposesObject ([Values (true, false)] bool register) - { - var native = new JavaObject (); - if (!register) { - native.UnregisterFromRuntime (); - } - - var instance = new DynamicJavaInstance (native); - - Assert.AreEqual (1, JavaClassInfo.GetClassInfoCount ("java/lang/Object")); - - Assert.AreSame (native, instance.Value); - instance.Dispose (); - Assert.AreEqual (null, instance.Value); - Assert.AreEqual (-1, JavaClassInfo.GetClassInfoCount ("java/lang/Object")); - - if (register) { - Assert.IsTrue (native.PeerReference.IsValid); - } else { - Assert.IsFalse (native.PeerReference.IsValid); - } - } - - [Test] - public void Demo () - { - dynamic Integer = new DynamicJavaClass ("java/lang/Integer"); - dynamic value = Integer (42); - Integer.Dispose (); - - sbyte byteV = value.byteValue (); - Assert.AreEqual ((sbyte) 42, byteV); - dynamic str = value.toString (); - var s = (string) str; - Assert.AreEqual ("42", s); - str.Dispose (); - value.Dispose (); - } - - [Test] - public void Boxing () - { - dynamic Integer = new DynamicJavaClass ("java/lang/Integer"); - dynamic value = Integer (42); - int c = value.compareTo ((int?) 42); - Assert.AreEqual (0, c); - } - } -} - diff --git a/tests/Java.Interop.Dynamic-Tests/Java.Interop/JavaVMFixture.cs b/tests/Java.Interop.Dynamic-Tests/Java.Interop/JavaVMFixture.cs deleted file mode 100644 index 4f93c4b1a..000000000 --- a/tests/Java.Interop.Dynamic-Tests/Java.Interop/JavaVMFixture.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.IO; -using System.Diagnostics; -using System.Linq; - -using Java.Interop; - -namespace Java.InteropTests { - - public abstract partial class JavaVMFixture { - - static JavaVMFixture () - { - var c = new TestJVM ( - ); - JniRuntime.SetCurrent (c); - } - - protected JavaVMFixture () - { - } - } -} -