From 4f8f5c363cd72f0358a2a0bfb51358915429387b Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Mon, 16 Mar 2020 13:42:46 +1100 Subject: [PATCH 1/7] Fix return type --- natj-win/mingw.mutex.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/natj-win/mingw.mutex.h b/natj-win/mingw.mutex.h index 191ed98..095b7fe 100755 --- a/natj-win/mingw.mutex.h +++ b/natj-win/mingw.mutex.h @@ -191,7 +191,7 @@ class timed_mutex: public _NonRecursiveMutex public: using base::base; template - void try_lock_for(const std::chrono::duration& dur) + bool try_lock_for(const std::chrono::duration& dur) { bool ret = base::try_lock_for(dur); #ifdef STDTHREAD_STRICT_NONRECURSIVE_LOCKS From 102d782381efb8bb6dda13f8683ee3553c3ee27c Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Mon, 16 Mar 2020 13:13:17 +1100 Subject: [PATCH 2/7] Bumped version to 1.1.4 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index e3952ef..88a4c30 100644 --- a/build.gradle +++ b/build.gradle @@ -30,7 +30,7 @@ for (target in ['ios', 'macos', 'windows', 'ndk']) { allprojects { group 'org.moe' - version '1.1.3' + version '1.1.4' } /**************************** From a111ed2a970bf8559c68aa4799fba90cd1e2456d Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Thu, 25 Jun 2020 23:59:18 +1000 Subject: [PATCH 3/7] Fix crash on iOS 14 --- src/main/native/natj/ObjCRuntime.mm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/native/natj/ObjCRuntime.mm b/src/main/native/natj/ObjCRuntime.mm index 17b53ee..e73d86b 100644 --- a/src/main/native/natj/ObjCRuntime.mm +++ b/src/main/native/natj/ObjCRuntime.mm @@ -85,6 +85,7 @@ static Class gBlockClass = NSClassFromString(@"NSBlock"); static Class gStackBlockClass = NSClassFromString(@"__NSStackBlock"); +static Class gStackBlockClass2 = NSClassFromString(@"__NSStackBlock__"); static int8_t gDefaultUnboxPolicy; @@ -985,7 +986,8 @@ jboolean Java_org_moe_natj_objc_ObjCRuntime_isObjectBlock(JNIEnv* env, jboolean Java_org_moe_natj_objc_ObjCRuntime_isStackBlock(JNIEnv* env, jclass clazz, jlong object) { - return [reinterpret_cast(object) isKindOfClass:gStackBlockClass]; + return [reinterpret_cast(object) isKindOfClass:gStackBlockClass] + || (gStackBlockClass2 != nil && [reinterpret_cast(object) isKindOfClass:gStackBlockClass2]); } jlong Java_org_moe_natj_objc_ObjCRuntime_copyBlock(JNIEnv* env, From 4cc91708e239ac0582a8450a15e2e310ba023d41 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Fri, 26 Jun 2020 00:33:50 +1000 Subject: [PATCH 4/7] Fix crash when debugging objc blocks (due to the call to `.toString()`) --- .../moe/natj/objc/map/ObjCCallbackMapper.java | 118 ++++++++++++------ 1 file changed, 83 insertions(+), 35 deletions(-) diff --git a/src/main/java/org/moe/natj/objc/map/ObjCCallbackMapper.java b/src/main/java/org/moe/natj/objc/map/ObjCCallbackMapper.java index 537c7d4..32f54f7 100644 --- a/src/main/java/org/moe/natj/objc/map/ObjCCallbackMapper.java +++ b/src/main/java/org/moe/natj/objc/map/ObjCCallbackMapper.java @@ -20,7 +20,6 @@ import org.moe.natj.general.NatJ; import org.moe.natj.general.Pointer; import org.moe.natj.general.ann.Runtime; -import org.moe.natj.objc.ObjCObject; import org.moe.natj.objc.ObjCRuntime; import org.moe.natj.objc.WeakReference; import org.moe.natj.objc.ann.ObjCBlock; @@ -126,30 +125,79 @@ public static Pointer createStrongBlockBindingPointer(long peer, boolean owned) /** * Base for invocation handlers. + * + * Handling of hashCode(), equals() and toString() use the sample code from + * https://docs.oracle.com/javase/8/docs/technotes/guides/reflection/proxy.html */ private abstract static class BlockInvocationHandler implements InvocationHandler { + // preloaded Method objects for the methods in java.lang.Object + private static Method hashCodeMethod; + private static Method equalsMethod; + private static Method toStringMethod; + static { + try { + hashCodeMethod = Object.class.getMethod("hashCode", null); + equalsMethod = Object.class.getMethod("equals", new Class[] { Object.class }); + toStringMethod = Object.class.getMethod("toString", null); + } catch (NoSuchMethodException e) { + throw new NoSuchMethodError(e.getMessage()); + } + } + + private final String name; public Pointer peer; public long data; - protected BlockInvocationHandler(Pointer peer, long data) { + protected BlockInvocationHandler(String name, Pointer peer, long data) { + this.name = name; this.peer = peer; this.data = data; } @Override - public abstract Object invoke(Object proxy, Method method, Object[] args); + public Object invoke(Object proxy, Method method, Object[] args) { + Class declaringClass = method.getDeclaringClass(); + + if (declaringClass == Object.class) { + if (method.equals(hashCodeMethod)) { + return proxyHashCode(proxy); + } else if (method.equals(equalsMethod)) { + return proxyEquals(proxy, args[0]); + } else if (method.equals(toStringMethod)) { + return proxyToString(proxy); + } else { + throw new InternalError("unexpected Object method dispatched: " + method); + } + } else { + return invoke0(proxy, method, args); + } + } + + protected Integer proxyHashCode(Object proxy) { + return new Integer(System.identityHashCode(proxy)); + } + + protected Boolean proxyEquals(Object proxy, Object other) { + return (proxy == other ? Boolean.TRUE : Boolean.FALSE); + } + + protected String proxyToString(Object proxy) { + return name + '@' + Integer.toHexString(proxy.hashCode()); + } + + protected abstract Object invoke0(Object proxy, Method method, Object[] args); } /** * Invocation handler for native blocks with boolean return value. */ private static class BooleanInvocationHandler extends BlockInvocationHandler { - public BooleanInvocationHandler(Pointer peer, long data) { - super(peer, data); + public BooleanInvocationHandler(String name, Pointer peer, long data) { + super(name, peer, data); } @Override - public Object invoke(Object proxy, Method method, Object[] args) { + public Object invoke0(Object proxy, Method method, Object[] args) { return new Boolean(ObjCRuntime.forwardBooleanBlockCall(peer.getPeer(), data, args)); } } @@ -158,12 +206,12 @@ public Object invoke(Object proxy, Method method, Object[] args) { * Invocation handler for native blocks with byte return value. */ private static class ByteInvocationHandler extends BlockInvocationHandler { - public ByteInvocationHandler(Pointer peer, long data) { - super(peer, data); + public ByteInvocationHandler(String name, Pointer peer, long data) { + super(name, peer, data); } @Override - public Object invoke(Object proxy, Method method, Object[] args) { + public Object invoke0(Object proxy, Method method, Object[] args) { return new Byte(ObjCRuntime.forwardByteBlockCall(peer.getPeer(), data, args)); } } @@ -172,12 +220,12 @@ public Object invoke(Object proxy, Method method, Object[] args) { * Invocation handler for native blocks with char return value. */ private static class CharacterInvocationHandler extends BlockInvocationHandler { - public CharacterInvocationHandler(Pointer peer, long data) { - super(peer, data); + public CharacterInvocationHandler(String name, Pointer peer, long data) { + super(name, peer, data); } @Override - public Object invoke(Object proxy, Method method, Object[] args) { + public Object invoke0(Object proxy, Method method, Object[] args) { return new Character(ObjCRuntime.forwardCharBlockCall(peer.getPeer(), data, args)); } } @@ -186,12 +234,12 @@ public Object invoke(Object proxy, Method method, Object[] args) { * Invocation handler for native blocks with short return value. */ private static class ShortInvocationHandler extends BlockInvocationHandler { - public ShortInvocationHandler(Pointer peer, long data) { - super(peer, data); + public ShortInvocationHandler(String name, Pointer peer, long data) { + super(name, peer, data); } @Override - public Object invoke(Object proxy, Method method, Object[] args) { + public Object invoke0(Object proxy, Method method, Object[] args) { return new Short(ObjCRuntime.forwardShortBlockCall(peer.getPeer(), data, args)); } } @@ -200,12 +248,12 @@ public Object invoke(Object proxy, Method method, Object[] args) { * Invocation handler for native blocks with int return value. */ private static class IntegerInvocationHandler extends BlockInvocationHandler { - public IntegerInvocationHandler(Pointer peer, long data) { - super(peer, data); + public IntegerInvocationHandler(String name, Pointer peer, long data) { + super(name, peer, data); } @Override - public Object invoke(Object proxy, Method method, Object[] args) { + public Object invoke0(Object proxy, Method method, Object[] args) { return new Integer(ObjCRuntime.forwardIntBlockCall(peer.getPeer(), data, args)); } } @@ -214,12 +262,12 @@ public Object invoke(Object proxy, Method method, Object[] args) { * Invocation handler for native blocks with long return value. */ private static class LongInvocationHandler extends BlockInvocationHandler { - public LongInvocationHandler(Pointer peer, long data) { - super(peer, data); + public LongInvocationHandler(String name, Pointer peer, long data) { + super(name, peer, data); } @Override - public Object invoke(Object proxy, Method method, Object[] args) { + public Object invoke0(Object proxy, Method method, Object[] args) { return new Long(ObjCRuntime.forwardLongBlockCall(peer.getPeer(), data, args)); } } @@ -228,12 +276,12 @@ public Object invoke(Object proxy, Method method, Object[] args) { * Invocation handler for native blocks with float return value. */ private static class FloatInvocationHandler extends BlockInvocationHandler { - public FloatInvocationHandler(Pointer peer, long data) { - super(peer, data); + public FloatInvocationHandler(String name, Pointer peer, long data) { + super(name, peer, data); } @Override - public Object invoke(Object proxy, Method method, Object[] args) { + public Object invoke0(Object proxy, Method method, Object[] args) { return new Float(ObjCRuntime.forwardFloatBlockCall(peer.getPeer(), data, args)); } } @@ -242,12 +290,12 @@ public Object invoke(Object proxy, Method method, Object[] args) { * Invocation handler for native blocks with double return value. */ private static class DoubleInvocationHandler extends BlockInvocationHandler { - public DoubleInvocationHandler(Pointer peer, long data) { - super(peer, data); + public DoubleInvocationHandler(String name, Pointer peer, long data) { + super(name, peer, data); } @Override - public Object invoke(Object proxy, Method method, Object[] args) { + public Object invoke0(Object proxy, Method method, Object[] args) { return new Double(ObjCRuntime.forwardDoubleBlockCall(peer.getPeer(), data, args)); } } @@ -256,12 +304,12 @@ public Object invoke(Object proxy, Method method, Object[] args) { * Invocation handler for native blocks with boolean return value. */ private static class VoidInvocationHandler extends BlockInvocationHandler { - public VoidInvocationHandler(Pointer peer, long data) { - super(peer, data); + public VoidInvocationHandler(String name, Pointer peer, long data) { + super(name, peer, data); } @Override - public Object invoke(Object proxy, Method method, Object[] args) { + public Object invoke0(Object proxy, Method method, Object[] args) { ObjCRuntime.forwardVoidBlockCall(peer.getPeer(), data, args); return null; } @@ -271,12 +319,12 @@ public Object invoke(Object proxy, Method method, Object[] args) { * Invocation handler for native blocks with boolean return value. */ private static class ObjectInvocationHandler extends BlockInvocationHandler { - public ObjectInvocationHandler(Pointer peer, long data) { - super(peer, data); + public ObjectInvocationHandler(String name, Pointer peer, long data) { + super(name, peer, data); } @Override - public Object invoke(Object proxy, Method method, Object[] args) { + public Object invoke0(Object proxy, Method method, Object[] args) { return ObjCRuntime.forwardObjectBlockCall(peer.getPeer(), data, args); } } @@ -571,7 +619,7 @@ private Object objectToJava(long peer, NatJ.JavaObjectConstructionInfo info) { } try { blockInfo.handlerConstructor = handler.getConstructor( - Pointer.class, Long.TYPE); + String.class, Pointer.class, Long.TYPE); blockInfo.proxyConstructor = Proxy.getProxyClass( info.type.getClassLoader(), new Class[] { info.type @@ -592,7 +640,7 @@ private Object objectToJava(long peer, NatJ.JavaObjectConstructionInfo info) { } try { instance = blockInfo.proxyConstructor.newInstance(blockInfo.handlerConstructor - .newInstance(pointer, blockInfo.data)); + .newInstance(info.type.getName(), pointer, blockInfo.data)); } catch (Exception e) { throw new RuntimeException("Java object construction error!", e); } From db8db74d2a9546afd0071ce98399da5238863584 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 21 Jul 2020 19:46:56 +1000 Subject: [PATCH 5/7] Find parameter annotations from direct super class and interfaces as well --- src/main/java/org/moe/natj/general/NatJ.java | 68 ++++++++++++++++++++ src/main/native/natj/NatJ.cpp | 8 ++- src/main/native/natj/NatJ.h | 1 + 3 files changed, 75 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/moe/natj/general/NatJ.java b/src/main/java/org/moe/natj/general/NatJ.java index 071f4d7..50ae699 100644 --- a/src/main/java/org/moe/natj/general/NatJ.java +++ b/src/main/java/org/moe/natj/general/NatJ.java @@ -30,9 +30,12 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; @@ -919,6 +922,71 @@ public static class NativeObjectConstructionInfo { public Mapper mapper; } + public static Annotation[][] getParameterAnnotationsInherited(Method method) { + Class[] parameterTypes = method.getParameterTypes(); + if (parameterTypes.length == 0) { + return new Annotation[0][]; + } + + List> results = new ArrayList<>(parameterTypes.length); + for (int i = 0; i < parameterTypes.length; i++) { + results.add(new ArrayList()); + } + + ArrayList> supers = new ArrayList<>(); + // First get annotations from interfaces + Class methodDeclaredKlass = method.getDeclaringClass(); + Class[] interfaces = methodDeclaredKlass.getInterfaces(); + supers.addAll(Arrays.asList(interfaces)); + // Then super class + Class superClass = methodDeclaredKlass.getSuperclass(); + if (superClass != null) { + supers.add(superClass); + } + + for (Class c : supers) { + // Find method + try { + for (Method sm : c.getDeclaredMethods()) { + int modifiers = sm.getModifiers(); + if (Modifier.isStatic(modifiers) + || Modifier.isPrivate(modifiers) + || Modifier.isFinal(modifiers)) { + continue; + } + + if (method.getName().equals(sm.getName()) && Arrays.equals(parameterTypes, sm.getParameterTypes())) { + int idx = 0; + for (Annotation[] annotations : sm.getParameterAnnotations()) { + results.get(idx).addAll(Arrays.asList(annotations)); + idx++; + } + break; + } + } + } catch (Throwable e) { + // Do nothing + } + } + + // Finally add annotations from current method + int idx = 0; + for (Annotation[] annotations : method.getParameterAnnotations()) { + results.get(idx).addAll(Arrays.asList(annotations)); + idx++; + } + + // Convert list to array + Annotation[][] resultArray = new Annotation[parameterTypes.length][]; + for (int i = 0; i < parameterTypes.length; i++) { + List al = results.get(i); + Annotation[] aa = new Annotation[al.size()]; + aa = al.toArray(aa); + resultArray[i] = aa; + } + return resultArray; + } + /** * Constructs a {@link JavaObjectConstructionInfo} instance. * diff --git a/src/main/native/natj/NatJ.cpp b/src/main/native/natj/NatJ.cpp index 3d78603..62f43b4 100644 --- a/src/main/native/natj/NatJ.cpp +++ b/src/main/native/natj/NatJ.cpp @@ -133,6 +133,7 @@ jmethodID gBuildNativeObjectInfoStaticMethod = NULL; jmethodID gGetMappedMethod = NULL; jmethodID gGetMappedReturnMethod = NULL; jmethodID gGetParameterAnnotationsMethod = NULL; +jmethodID gGetParameterAnnotationsInheritedStaticMethod = NULL; jmethodID gGetRuntimeStaticMethod = NULL; jmethodID gGetNativeExceptionMethod = NULL; jmethodID gGetMessageMethod = NULL; @@ -403,6 +404,9 @@ void JNICALL Java_org_moe_natj_general_NatJ_initialize(JNIEnv* env, jclass clazz gGetParameterAnnotationsMethod = env->GetMethodID(gMethodClass, "getParameterAnnotations", "()[[Ljava/lang/annotation/Annotation;"); + gGetParameterAnnotationsInheritedStaticMethod = + env->GetStaticMethodID(gNatJClass, "getParameterAnnotationsInherited", + "(Ljava/lang/reflect/Method;)[[Ljava/lang/annotation/Annotation;"); gGetRuntimeStaticMethod = env->GetStaticMethodID( gNatJClass, "getRuntime", "(Ljava/lang/Class;Z)Lorg/moe/natj/general/NativeRuntime;"); @@ -866,8 +870,8 @@ void buildInfos(JNIEnv* env, jobject method, bool toJava, jobject** paramInfos, #endif jobjectArray parameterTypes = (jobjectArray)env->CallObjectMethod(method, gGetParameterTypesMethod); - jobjectArray parameterAnns = (jobjectArray)env->CallObjectMethod( - method, gGetParameterAnnotationsMethod); + jobjectArray parameterAnns = (jobjectArray)env->CallStaticObjectMethod( + gNatJClass, gGetParameterAnnotationsInheritedStaticMethod, method); jsize parameterCount = env->GetArrayLength(parameterTypes); if (isVariadic) { parameterCount--; diff --git a/src/main/native/natj/NatJ.h b/src/main/native/natj/NatJ.h index 89a73c3..0adb508 100644 --- a/src/main/native/natj/NatJ.h +++ b/src/main/native/natj/NatJ.h @@ -507,6 +507,7 @@ extern jmethodID gBuildNativeObjectInfoStaticMethod; extern jmethodID gGetMappedMethod; extern jmethodID gGetMappedReturnMethod; extern jmethodID gGetParameterAnnotationsMethod; +extern jmethodID gGetParameterAnnotationsInheritedStaticMethod; extern jmethodID gGetRuntimeStaticMethod; extern jmethodID gGetNativeExceptionMethod; extern jmethodID gGetMessageMethod; From ae3fcd8921918e93228faf2fb30017c866bcaf8d Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sat, 8 Aug 2020 16:44:30 +1000 Subject: [PATCH 6/7] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 7fca799..f001b90 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ local.properties .project .classpath .settings +bin/ \ No newline at end of file From 7e9065bc738a809b9191a8852429667b0ab2a3b0 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sat, 8 Aug 2020 16:45:07 +1000 Subject: [PATCH 7/7] Bumped version to 1.1.5 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 88a4c30..d81cebe 100644 --- a/build.gradle +++ b/build.gradle @@ -30,7 +30,7 @@ for (target in ['ios', 'macos', 'windows', 'ndk']) { allprojects { group 'org.moe' - version '1.1.4' + version '1.1.5' } /****************************