Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get JNIEnv pointer #812

Closed
wants to merge 4 commits into from
Closed
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
Binary file modified lib/native/android-aarch64.jar
Binary file not shown.
Binary file modified lib/native/android-arm.jar
Binary file not shown.
Binary file modified lib/native/android-armv7.jar
Binary file not shown.
Binary file modified lib/native/android-mips.jar
Binary file not shown.
Binary file modified lib/native/android-mips64.jar
Binary file not shown.
Binary file modified lib/native/android-x86-64.jar
Binary file not shown.
Binary file modified lib/native/android-x86.jar
Binary file not shown.
Binary file modified lib/native/linux-x86-64.jar
Binary file not shown.
13 changes: 13 additions & 0 deletions native/dispatch.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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]);
Expand Down Expand Up @@ -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");
Expand Down
2 changes: 2 additions & 0 deletions native/dispatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ enum {
CVT_TYPE_MAPPER = com_sun_jna_Native_CVT_TYPE_MAPPER,
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 */
Expand Down
5 changes: 5 additions & 0 deletions native/testlib.c
Original file line number Diff line number Diff line change
Expand Up @@ -1026,6 +1026,11 @@ Java_com_sun_jna_PerformanceTest_00024JNILibrary_getpid(JNIEnv *UNUSED(env), jcl
#endif
}

EXPORT jclass
returnClass(JNIEnv *env, jobject arg) {
return (*env)->GetObjectClass(env, arg);
}

#ifdef __cplusplus
}
#endif
34 changes: 34 additions & 0 deletions src/com/sun/jna/JNIEnv.java
Original file line number Diff line number Diff line change
@@ -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.
* Pass {@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() {}
}
15 changes: 11 additions & 4 deletions src/com/sun/jna/Native.java
Original file line number Diff line number Diff line change
Expand Up @@ -1534,8 +1534,10 @@ static String replace(String s1, String s2, String str) {
private static final int CVT_TYPE_MAPPER = 23;
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) {
private static int getConversion(Class<?> type, TypeMapper mapper, boolean allowObjects) {
if (type == Boolean.class) type = boolean.class;
else if (type == Byte.class) type = byte.class;
else if (type == Short.class) type = short.class;
Expand Down Expand Up @@ -1624,7 +1626,10 @@ private static int getConversion(Class<?> type, TypeMapper mapper) {
}
return CVT_NATIVE_MAPPED;
}
return CVT_UNSUPPORTED;
if (JNIEnv.class == type) {
return CVT_JNIENV;
}
return allowObjects ? CVT_OBJECT : CVT_UNSUPPORTED;
}

/**
Expand Down Expand Up @@ -1657,6 +1662,7 @@ public static void register(Class<?> cls, NativeLibrary lib) {
List<Method> mlist = new ArrayList<Method>();
Map<String, ?> options = lib.getOptions();
TypeMapper mapper = (TypeMapper) options.get(Library.OPTION_TYPE_MAPPER);
boolean allowObjects = Boolean.TRUE.equals(options.get(Library.OPTION_ALLOW_OBJECTS));
options = cacheOptions(cls, options, null);

for (Method m : methods) {
Expand All @@ -1677,7 +1683,7 @@ public static void register(Class<?> cls, NativeLibrary lib) {
int[] cvt = new int[ptypes.length];
ToNativeConverter[] toNative = new ToNativeConverter[ptypes.length];
FromNativeConverter fromNative = null;
int rcvt = getConversion(rclass, mapper);
int rcvt = getConversion(rclass, mapper, allowObjects);
boolean throwLastError = false;
switch (rcvt) {
case CVT_UNSUPPORTED:
Expand All @@ -1701,6 +1707,7 @@ public static void register(Class<?> cls, NativeLibrary lib) {
rtype = FFIType.get(NativeMappedConverter.getInstance(rclass).nativeType()).peer;
break;
case CVT_STRUCTURE:
case CVT_OBJECT:
closure_rtype = rtype = FFIType.get(Pointer.class).peer;
break;
case CVT_STRUCTURE_BYVAL:
Expand All @@ -1714,7 +1721,7 @@ public static void register(Class<?> cls, NativeLibrary lib) {
for (int t=0;t < ptypes.length;t++) {
Class<?> type = ptypes[t];
sig += getSignature(type);
int conversionType = getConversion(type, mapper);
int conversionType = getConversion(type, mapper, allowObjects);
cvt[t] = conversionType;
if (conversionType == CVT_UNSUPPORTED) {
throw new IllegalArgumentException(type + " is not a supported argument type (in method " + method.getName() + " in " + cls + ")");
Expand Down
33 changes: 21 additions & 12 deletions test/com/sun/jna/DirectReturnTypesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
*/
package com.sun.jna;

import java.util.Map;
import java.util.Collections;

/** Exercise a range of native methods.
*
Expand All @@ -42,6 +42,10 @@ public TestObject returnObjectArgument(TestObject s) {
throw new IllegalArgumentException(s.getClass().getName());
}
@Override
public Class returnClass(JNIEnv env, Object arg) {
throw new IllegalArgumentException(arg.getClass().getName());
}
@Override
public native boolean returnFalse();
@Override
public native boolean returnTrue();
Expand Down Expand Up @@ -90,14 +94,17 @@ public TestObject returnObjectArgument(TestObject s) {
}
}

@Override
protected void setUp() {
lib = new DirectTestLibrary();
}

public static class DirectObjectTestLibrary extends DirectTestLibrary {
public DirectObjectTestLibrary(Map<String, ?> options) {
Native.register(getClass(), NativeLibrary.getInstance("testlib", options));
@Override
public native Object returnObjectArgument(Object s);
@Override
public native TestObject returnObjectArgument(TestObject s);
@Override
public native Class returnClass(JNIEnv env, Object arg);

static {
Native.register(NativeLibrary.getInstance("testlib",
Collections.singletonMap(Library.OPTION_ALLOW_OBJECTS, Boolean.TRUE)));
}
}

Expand All @@ -108,19 +115,21 @@ public static class DirectNativeMappedLibrary implements NativeMappedLibrary {
public native size_t returnInt32Magic();
@Override
public native size_t returnInt64Magic();

static {
Native.register("testlib");
}
}

@Override
protected NativeMappedLibrary loadNativeMappedLibrary() {
return new DirectNativeMappedLibrary();
protected void setUp() {
lib = new DirectTestLibrary();
libSupportingObject = new DirectObjectTestLibrary();
libNativeMapped = new DirectNativeMappedLibrary();
}

// Override not-yet-supported tests
@Override
public void testReturnObject() { }
@Override
public void testReturnPointerArray() { }
@Override
public void testReturnStringArray() { }
Expand Down
66 changes: 35 additions & 31 deletions test/com/sun/jna/ReturnTypesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,11 @@
public class ReturnTypesTest extends TestCase {

private static final String UNICODE = "[\u0444]";
private static final int INT_MAGIC = 0x12345678;
private static final long LONG_MAGIC = 0x123456789ABCDEF0L;
private static final double DOUBLE_MAGIC = -118.625d;
private static final float FLOAT_MAGIC = -118.625f;
private static final String STRING_MAGIC = "magic";

public static interface TestLibrary extends Library {

Expand Down Expand Up @@ -104,6 +107,7 @@ protected List<String> getFieldOrder() {
class TestObject { }
Object returnObjectArgument(Object s);
TestObject returnObjectArgument(TestObject s);
Class returnClass(JNIEnv env, Object arg);
boolean returnFalse();
boolean returnTrue();
int returnInt32Zero();
Expand All @@ -129,26 +133,33 @@ class TestObject { }
}

TestLibrary lib;
TestLibrary libSupportingObject;
NativeMappedLibrary libNativeMapped;

@Override
protected void setUp() {
lib = Native.loadLibrary("testlib", TestLibrary.class);
libSupportingObject = Native.loadLibrary("testlib", TestLibrary.class,
Collections.singletonMap(Library.OPTION_ALLOW_OBJECTS, Boolean.TRUE));
libNativeMapped = Native.loadLibrary("testlib", NativeMappedLibrary.class);
}

@Override
protected void tearDown() {
lib = null;
libSupportingObject = null;
libNativeMapped = null;
}

public void testReturnObject() throws Exception {
lib = Native.loadLibrary("testlib", TestLibrary.class, Collections.singletonMap(Library.OPTION_ALLOW_OBJECTS, Boolean.TRUE));
assertNull("null value not returned", lib.returnObjectArgument(null));
assertNull("null value not returned", libSupportingObject.returnObjectArgument(null));
final Object VALUE = new Object() {
@Override
public String toString() {
return getName();
}
};
assertEquals("Wrong object returned", VALUE, lib.returnObjectArgument(VALUE));
assertEquals("Wrong object returned", VALUE, libSupportingObject.returnObjectArgument(VALUE));
}

public void testReturnObjectUnsupported() throws Exception {
Expand All @@ -165,38 +176,37 @@ public void testReturnObjectUnsupported() throws Exception {
}
}

public void testReturnClass() throws Exception {
assertEquals("Wrong class returned", Class.class,
libSupportingObject.returnClass(JNIEnv.CURRENT, TestLibrary.class));
assertEquals("Wrong class returned", StringBuilder.class,
libSupportingObject.returnClass(JNIEnv.CURRENT, new StringBuilder()));
}

public void testInvokeBoolean() {
assertFalse("Expect false", lib.returnFalse());
assertTrue("Expect true", lib.returnTrue());
}

public void testInvokeInt() {
assertEquals("Expect 32-bit zero", 0, lib.returnInt32Zero());
assertEquals("Expect 32-bit magic",
"12345678",
Integer.toHexString(lib.returnInt32Magic()));
assertEquals("Expect 32-bit magic", INT_MAGIC, lib.returnInt32Magic());
}

public void testInvokeLong() {
assertEquals("Expect 64-bit zero", 0L, lib.returnInt64Zero());
assertEquals("Expect 64-bit magic",
"123456789abcdef0",
Long.toHexString(lib.returnInt64Magic()));
assertEquals("Expect 64-bit magic", LONG_MAGIC, lib.returnInt64Magic());
}

public void testInvokeNativeLong() {
if (NativeLong.SIZE == 4) {
assertEquals("Expect 32-bit zero", new NativeLong(0), lib.returnLongZero());
assertEquals("Expect 32-bit magic",
"12345678",
Integer.toHexString(lib.returnLongMagic().intValue()));

new NativeLong(INT_MAGIC), lib.returnLongMagic());
} else {
assertEquals("Expect 64-bit zero", new NativeLong(0L),
lib.returnLongZero());
assertEquals("Expect 64-bit zero", new NativeLong(0L), lib.returnLongZero());
assertEquals("Expect 64-bit magic",
"123456789abcdef0",
Long.toHexString(lib.returnLongMagic().longValue()));
new NativeLong(LONG_MAGIC), lib.returnLongMagic());
}
}

Expand Down Expand Up @@ -238,22 +248,17 @@ public boolean equals(Object o) {
return o instanceof Custom && ((Custom)o).value == value;
}
}
protected NativeMappedLibrary loadNativeMappedLibrary() {
return Native.loadLibrary("testlib", NativeMappedLibrary.class);
}

public void testInvokeNativeMapped() {
NativeMappedLibrary lib = loadNativeMappedLibrary();
final int MAGIC = 0x12345678;
final long MAGIC64 = 0x123456789ABCDEF0L;
final Custom EXPECTED = new Custom(MAGIC);
assertEquals("NativeMapped 'Custom' result not mapped", EXPECTED, lib.returnInt32Argument(MAGIC));
final Custom EXPECTED = new Custom(INT_MAGIC);
assertEquals("NativeMapped 'Custom' result not mapped",
EXPECTED, libNativeMapped.returnInt32Argument(INT_MAGIC));

assertEquals("NativeMapped IntegerType result not mapped (32)",
new size_t(MAGIC), lib.returnInt32Magic());
new size_t(INT_MAGIC), libNativeMapped.returnInt32Magic());
if (Native.SIZE_T_SIZE == 8) {
assertEquals("NativeMapped IntegerType result not mapped (64)",
new size_t(MAGIC64), lib.returnInt64Magic());
new size_t(LONG_MAGIC), libNativeMapped.returnInt64Magic());
}
}

Expand All @@ -269,15 +274,14 @@ public void testInvokeDouble() {
DOUBLE_MAGIC, lib.returnDoubleMagic(), 0d);
}

static final String MAGIC = "magic";
public void testInvokeString() {
assertEquals("Expect String magic", MAGIC, lib.returnStringMagic());
assertEquals("Expect String magic", STRING_MAGIC, lib.returnStringMagic());
}

public void testInvokeWString() {
WString s = lib.returnWStringMagic();
assertEquals("Wrong length", MAGIC.length(), s.toString().length());
assertEquals("Expect WString magic", new WString(MAGIC), s);
assertEquals("Wrong length", STRING_MAGIC.length(), s.length());
assertEquals("Expect WString magic", new WString(STRING_MAGIC), s);
}

public void testInvokeStructure() {
Expand Down Expand Up @@ -354,4 +358,4 @@ public static void main(java.lang.String[] argList) {
junit.textui.TestRunner.run(ReturnTypesTest.class);
}

}
}