diff --git a/native/dispatch.c b/native/dispatch.c index 50bb49cb32..f8797ada5b 100644 --- a/native/dispatch.c +++ b/native/dispatch.c @@ -169,6 +169,7 @@ static jclass classAttachOptions; static jclass classNativeMapped; static jclass classIntegerType; static jclass classPointerType; +static jclass classJNIEnv; static jclass class_ffi_callback; static jmethodID MID_Class_getComponentType; @@ -540,6 +541,11 @@ dispatch(JNIEnv *env, void* func, jint flags, jobjectArray args, arg_types[i] = &ffi_type_pointer; arg_values[i] = &c_args[i].l; } + else if ((*env)->IsInstanceOf(env, arg, classJNIEnv)) { + c_args[i].l = (void*)env; + arg_types[i] = &ffi_type_pointer; + arg_values[i] = &c_args[i].l; + } else if ((*env)->IsInstanceOf(env, arg, classStructure)) { c_args[i].l = getStructureAddress(env, arg); arg_types[i] = getStructureType(env, arg); @@ -1793,6 +1799,9 @@ dispatch_direct(ffi_cif* cif, void* volatile resp, void** argp, void *cdata) { case CVT_POINTER: *(void **)args[i] = getNativeAddress(env, *(void **)args[i]); break; + case CVT_JNIENV: + *(void **)args[i] = (void*)env; + break; case CVT_STRUCTURE: objects[i] = *(void **)args[i]; writeStructure(env, *(void **)args[i]); @@ -2959,6 +2968,10 @@ Java_com_sun_jna_Native_initIDs(JNIEnv *env, jclass cls) { throwByName(env, EUnsatisfiedLink, "Can't obtain constructor for class com.sun.jna.WString"); } + else if (!LOAD_CREF(env, JNIEnv, "com/sun/jna/JNIEnv")) { + throwByName(env, EUnsatisfiedLink, + "Can't obtain class com.sun.jna.JNIEnv"); + } else if (!LOAD_CREF(env, _ffi_callback, "com/sun/jna/Native$ffi_callback")) { throwByName(env, EUnsatisfiedLink, "Can't obtain class com.sun.jna.Native$ffi_callback"); diff --git a/native/dispatch.h b/native/dispatch.h index 91ddd27fb4..aed8c89c2d 100644 --- a/native/dispatch.h +++ b/native/dispatch.h @@ -116,6 +116,7 @@ enum { CVT_TYPE_MAPPER_STRING = com_sun_jna_Native_CVT_TYPE_MAPPER_STRING, CVT_TYPE_MAPPER_WSTRING = com_sun_jna_Native_CVT_TYPE_MAPPER_WSTRING, CVT_OBJECT = com_sun_jna_Native_CVT_OBJECT, + CVT_JNIENV = com_sun_jna_Native_CVT_JNIENV, }; /* callback behavior flags */ diff --git a/native/testlib.c b/native/testlib.c index 0747e45667..4fcf7037b6 100644 --- a/native/testlib.c +++ b/native/testlib.c @@ -1029,3 +1029,8 @@ Java_com_sun_jna_PerformanceTest_00024JNILibrary_getpid(JNIEnv *UNUSED(env), jcl #ifdef __cplusplus } #endif + +EXPORT jclass +returnClass(JNIEnv *env, jobject arg) { + return (*env)->GetObjectClass(env, arg); +} diff --git a/src/com/sun/jna/JNIEnv.java b/src/com/sun/jna/JNIEnv.java new file mode 100644 index 0000000000..dc9d00b24c --- /dev/null +++ b/src/com/sun/jna/JNIEnv.java @@ -0,0 +1,34 @@ +/* + * The contents of this file is dual-licensed under 2 + * alternative Open Source/Free licenses: LGPL 2.1 or later and + * Apache License 2.0. (starting with JNA version 4.0.0). + * + * You can freely decide which license you want to apply to + * the project. + * + * You may obtain a copy of the LGPL License at: + * + * http://www.gnu.org/licenses/licenses.html + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "LGPL2.1". + * + * You may obtain a copy of the Apache License at: + * + * http://www.apache.org/licenses/ + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "AL2.0". + */ +package com.sun.jna; + +/** Marker type for the JNIEnv pointer. + * Use this to wrap native methods that take a JNIEnv* parameter. + * Use {@link JNIEnv#CURRENT} as the argument. + */ +public final class JNIEnv { + /** Marker object representing the current thread's JNIEnv pointer. */ + public static final JNIEnv CURRENT = new JNIEnv(); + + private JNIEnv() {} +} \ No newline at end of file diff --git a/src/com/sun/jna/Native.java b/src/com/sun/jna/Native.java index cc28856157..7b7a7d4e29 100644 --- a/src/com/sun/jna/Native.java +++ b/src/com/sun/jna/Native.java @@ -1535,6 +1535,7 @@ static String replace(String s1, String s2, String str) { private static final int CVT_TYPE_MAPPER_STRING = 24; private static final int CVT_TYPE_MAPPER_WSTRING = 25; private static final int CVT_OBJECT = 26; + private static final int CVT_JNIENV = 27; private static int getConversion(Class type, TypeMapper mapper, boolean allowObjects) { if (type == Boolean.class) type = boolean.class; @@ -1625,6 +1626,9 @@ private static int getConversion(Class type, TypeMapper mapper, boolean allow } return CVT_NATIVE_MAPPED; } + if (JNIEnv.class == type) { + return CVT_JNIENV; + } return allowObjects ? CVT_OBJECT : CVT_UNSUPPORTED; } diff --git a/test/com/sun/jna/DirectReturnTypesTest.java b/test/com/sun/jna/DirectReturnTypesTest.java index afe0778018..49cf106276 100644 --- a/test/com/sun/jna/DirectReturnTypesTest.java +++ b/test/com/sun/jna/DirectReturnTypesTest.java @@ -86,6 +86,9 @@ public TestObject returnObjectArgument(TestObject s) { @Override public WString[] returnPointerArgument(WString[] arg) {throw new UnsupportedOperationException();} + @Override + public Class returnClass(JNIEnv env, Object arg) {throw new UnsupportedOperationException();} + static { Native.register("testlib"); } @@ -101,6 +104,9 @@ public static class DirectObjectTestLibrary extends DirectTestLibrary { public native Object returnObjectArgument(Object s); @Override public native TestObject returnObjectArgument(TestObject s); + @Override + public native Class returnClass(JNIEnv env, Object arg); + public DirectObjectTestLibrary() { Native.register(getClass(), NativeLibrary.getInstance("testlib", Collections.singletonMap(Library.OPTION_ALLOW_OBJECTS, Boolean.TRUE))); @@ -123,12 +129,16 @@ protected NativeMappedLibrary loadNativeMappedLibrary() { return new DirectNativeMappedLibrary(); } - @Override public void testReturnObject() { lib = new DirectObjectTestLibrary(); } + @Override + public void testReturnClass() { + lib = new DirectObjectTestLibrary(); + } + // Override not-yet-supported tests @Override public void testReturnPointerArray() { } diff --git a/test/com/sun/jna/ReturnTypesTest.java b/test/com/sun/jna/ReturnTypesTest.java index 4a60ed8909..fab2e88904 100644 --- a/test/com/sun/jna/ReturnTypesTest.java +++ b/test/com/sun/jna/ReturnTypesTest.java @@ -126,6 +126,8 @@ class TestObject { } Pointer[] returnPointerArgument(Pointer[] arg); String[] returnPointerArgument(String[] arg); WString[] returnPointerArgument(WString[] arg); + + Class returnClass(JNIEnv env, Object arg); } TestLibrary lib; @@ -165,6 +167,12 @@ public void testReturnObjectUnsupported() throws Exception { } } + public void testReturnClass() throws Exception { + lib = Native.loadLibrary("testlib", TestLibrary.class, Collections.singletonMap(Library.OPTION_ALLOW_OBJECTS, Boolean.TRUE)); + assertEquals("Wrong class returned", Class.class, lib.returnClass(JNIEnv.CURRENT, TestLibrary.class)); + assertEquals("Wrong class returned", StringBuilder.class, lib.returnClass(JNIEnv.CURRENT, new StringBuilder())); + } + public void testInvokeBoolean() { assertFalse("Expect false", lib.returnFalse()); assertTrue("Expect true", lib.returnTrue());