mirror of https://github.com/adamdruppe/arsd.git
lots of cool stuff
This commit is contained in:
parent
643527c897
commit
35d58a4c0d
411
jni.d
411
jni.d
|
@ -120,15 +120,85 @@
|
|||
+/
|
||||
module arsd.jni;
|
||||
|
||||
// FIXME: java.lang.CharSequence is the interface for String. We should support that just as well.
|
||||
// FIXME: if user defines an interface with the appropriate RAII return values,
|
||||
// it should let them do that for more efficiency
|
||||
// e.g. @Import Manual!(int[]) getJavaArray();
|
||||
|
||||
/+
|
||||
final class CharSequence : JavaClass!("java.lang", CharSequence) {
|
||||
@Import string toString(); // this triggers a dmd segfault! whoa. FIXME dmd
|
||||
}
|
||||
+/
|
||||
|
||||
/++
|
||||
This is an interface in Java that the built in String class
|
||||
implements. In D, our string is not an object at all, and
|
||||
overloading an auto-generated method with a user-defined one
|
||||
is a bit awkward and not automatic, so I'm instead cheating
|
||||
here and pretending it is a class we can construct in a D
|
||||
overload.
|
||||
|
||||
This is not a great solution. I'm also considering a UDA
|
||||
on the param to indicate Java actually expects the interface,
|
||||
or even a runtime lookup to disambiguate, but meh for now
|
||||
I'm just sticking with this slightly wasteful overload/construct.
|
||||
+/
|
||||
final class CharSequence : JavaClass!("java.lang", CharSequence) {
|
||||
this(string data) {
|
||||
auto env = activeEnv;
|
||||
assert(env !is null);
|
||||
|
||||
wchar[1024] buffer;
|
||||
const(wchar)[] translated;
|
||||
if(data.length < 1024) {
|
||||
size_t len;
|
||||
foreach(wchar ch; data)
|
||||
buffer[len++] = ch;
|
||||
translated = buffer[0 .. len];
|
||||
} else {
|
||||
import std.conv;
|
||||
translated = to!wstring(data);
|
||||
}
|
||||
// Java copies the buffer so it is perfectly fine to return here now
|
||||
internalJavaHandle_ = (*env).NewString(env, translated.ptr, cast(jsize) translated.length);
|
||||
}
|
||||
this(wstring data) {
|
||||
auto env = activeEnv;
|
||||
assert(env !is null);
|
||||
internalJavaHandle_ = (*env).NewString(env, data.ptr, cast(jsize) data.length);
|
||||
}
|
||||
}
|
||||
|
||||
/++
|
||||
Can be used as a UDA for methods or classes where the D name
|
||||
and the Java name don't match (for example, if it happens to be
|
||||
a D keyword).
|
||||
|
||||
---
|
||||
@JavaName("version")
|
||||
@Import int version_();
|
||||
---
|
||||
+/
|
||||
struct JavaName {
|
||||
string name;
|
||||
}
|
||||
|
||||
private string getJavaName(alias a)() {
|
||||
string name = __traits(identifier, a);
|
||||
static foreach(attr; __traits(getAttributes, a))
|
||||
static if(is(typeof(attr) == JavaName))
|
||||
name = attr.name;
|
||||
return name;
|
||||
}
|
||||
|
||||
// semi-FIXME: java.lang.CharSequence is the interface for String. We should support that just as well.
|
||||
// possibly other boxed types too, like Integer.
|
||||
// FIXME: in general, handle substituting subclasses for interfaces nicely
|
||||
|
||||
// FIXME: solve the globalref/pin issue with the type system
|
||||
|
||||
//
|
||||
|
||||
// FIXME: in general i didn't handle overloads at all. Using RegisterNatives should make that doable... and I might be able to remove some of the pragma(mangle) that way too. And get more error checking done up-front.
|
||||
|
||||
// FIXME: what about the parent class of the java object? Best we can probably do is an interface but perhaps it could be auto-generated by the JavaClass magic. It could take the list and just copy the @Import items.
|
||||
|
||||
/+
|
||||
|
@ -153,30 +223,8 @@ module arsd.jni;
|
|||
//pragma(crt_constructor) // fyi
|
||||
//pragma(crt_destructor)
|
||||
|
||||
// FIXME: put this in a mixin instead of assuming it is needed/wanted?
|
||||
|
||||
extern(C)
|
||||
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||
/+
|
||||
|
||||
JNIEnv* env;
|
||||
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
// Find your class. JNI_OnLoad is called from the correct class loader context for this to work.
|
||||
jclass c = env->FindClass("com/example/app/package/MyClass");
|
||||
if (c == nullptr) return JNI_ERR;
|
||||
|
||||
// Register your class' native methods.
|
||||
static const JNINativeMethod methods[] = {
|
||||
{"nativeFoo", "()V", reinterpret_cast(nativeFoo)},
|
||||
{"nativeBar", "(Ljava/lang/String;I)Z", reinterpret_cast(nativeBar)},
|
||||
};
|
||||
int rc = env->RegisterNatives(c, methods, sizeof(methods)/sizeof(JNINativeMethod));
|
||||
if (rc != JNI_OK) return rc;
|
||||
|
||||
+/
|
||||
extern(System)
|
||||
export jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||
try {
|
||||
import core.runtime;
|
||||
// note this is OK if it is already initialized
|
||||
|
@ -187,10 +235,20 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
|||
}
|
||||
|
||||
activeJvm = vm;
|
||||
|
||||
JNIEnv* env;
|
||||
if ((*vm).GetEnv(vm, cast(void**) &env, JNI_VERSION_1_6) != JNI_OK) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
foreach(init; classInitializers_)
|
||||
if(init(env) != 0)
|
||||
return JNI_ERR;
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
extern(C)
|
||||
void JNI_OnUnload(JavaVM* vm, void* reserved) {
|
||||
extern(System)
|
||||
export void JNI_OnUnload(JavaVM* vm, void* reserved) {
|
||||
activeJvm = null;
|
||||
import core.runtime;
|
||||
try {
|
||||
|
@ -224,17 +282,44 @@ struct ActivateJniEnv {
|
|||
|
||||
/++
|
||||
Creates a JVM for use when `main` is in D. Keep the returned
|
||||
struct around until you are done with it.
|
||||
struct around until you are done with it. While this struct
|
||||
is live, you can use imported Java classes and methods almost
|
||||
as if they were written in D.
|
||||
|
||||
If `main` is in Java, this is not necessary and should not be
|
||||
used.
|
||||
|
||||
If you use this, you will need to link in a jni shared lib.
|
||||
|
||||
This function will try to load the jvm with dynamic runtime
|
||||
linking. For this to succeed:
|
||||
|
||||
On Windows, make sure the path to `jvm.dll` is in your `PATH`
|
||||
environment variable, or installed system wide. For example:
|
||||
|
||||
$(CONSOLE
|
||||
set PATH=%PATH%;c:\users\me\program\jdk-13.0.1\bin\server
|
||||
)
|
||||
|
||||
On Linux (and I think Mac), set `LD_LIBRARY_PATH` environment
|
||||
variable to include the path to `libjvm.so`.
|
||||
|
||||
$(CONSOLE
|
||||
export LD_LIBRARY_PATH=/home/me/jdk-13.0.1/bin/server
|
||||
)
|
||||
|
||||
Failure to do this will throw an exception along the lines of
|
||||
"no jvm dll" in the message.
|
||||
+/
|
||||
auto createJvm()() {
|
||||
struct JVM {
|
||||
version(Windows)
|
||||
import core.sys.windows.windows;
|
||||
else
|
||||
import core.sys.posix.dlfcn;
|
||||
|
||||
static struct JVM {
|
||||
ActivateJniEnv e;
|
||||
JavaVM* pvm;
|
||||
void* jvmdll;
|
||||
|
||||
@disable this(this);
|
||||
|
||||
|
@ -242,22 +327,77 @@ auto createJvm()() {
|
|||
if(pvm)
|
||||
(*pvm).DestroyJavaVM(pvm);
|
||||
activeJvm = null;
|
||||
|
||||
version(Windows) {
|
||||
if(jvmdll) FreeLibrary(jvmdll);
|
||||
} else {
|
||||
if(jvmdll) dlclose(jvmdll);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JavaVM* pvm;
|
||||
JNIEnv* env;
|
||||
auto res = JNI_CreateJavaVM(&pvm, cast(void**) &env, null);
|
||||
|
||||
JavaVMInitArgs vm_args;
|
||||
JavaVMOption[0] options;
|
||||
|
||||
//options[0].optionString = "-Djava.compiler=NONE"; /* disable JIT */
|
||||
//options[1].optionString = "-verbose:jni"; /* print JNI-related messages */
|
||||
//options[1].optionString = `-Djava.class.path=c:\Users\me\program\jni\`; /* user classes */
|
||||
//options[2].optionString = `-Djava.library.path=c:\Users\me\program\jdk-13.0.1\lib\`; /* set native library path */
|
||||
|
||||
vm_args.version_ = JNI_VERSION_1_6;
|
||||
vm_args.options = options.ptr;
|
||||
vm_args.nOptions = cast(int) options.length;
|
||||
vm_args.ignoreUnrecognized = true;
|
||||
|
||||
//import std.process;
|
||||
//environment["PATH"] = environment["PATH"] ~ `;c:\users\me\program\jdk-13.0.1\bin\server`;
|
||||
|
||||
version(Windows)
|
||||
auto jvmdll = LoadLibraryW("jvm.dll"w.ptr);
|
||||
else
|
||||
auto jvmdll = dlopen("libjvm.so");
|
||||
|
||||
if(jvmdll is null)
|
||||
throw new Exception("no jvm dll");
|
||||
|
||||
version(Windows)
|
||||
auto fn = cast(typeof(&JNI_CreateJavaVM)) GetProcAddress(jvmdll, "JNI_CreateJavaVM");
|
||||
else
|
||||
auto fn = cast(typeof(&JNI_CreateJavaVM)) dlsym(jvmdll, "JNI_CreateJavaVM");
|
||||
|
||||
if(fn is null)
|
||||
throw new Exception("no fun");
|
||||
|
||||
auto res = fn(&pvm, cast(void**) &env, &vm_args);//, args);
|
||||
if(res != JNI_OK)
|
||||
throw new Exception("create jvm failed"); // FIXME: throw res);
|
||||
|
||||
activeJvm = pvm;
|
||||
|
||||
return JVM(ActivateJniEnv(env), pvm);
|
||||
return JVM(ActivateJniEnv(env), pvm, jvmdll);
|
||||
}
|
||||
|
||||
version(Windows)
|
||||
private extern(Windows) bool SetDllDirectoryW(wstring);
|
||||
|
||||
|
||||
@JavaName("Throwable")
|
||||
final class JavaThrowable : JavaClass!("java.lang", JavaThrowable) {
|
||||
@Import string getMessage();
|
||||
@Import StackTraceElement[] getStackTrace();
|
||||
}
|
||||
|
||||
final class StackTraceElement : JavaClass!("java.lang", StackTraceElement) {
|
||||
@Import this(string declaringClass, string methodName, string fileName, int lineNumber);
|
||||
@Import string getClassName();
|
||||
@Import string getFileName();
|
||||
@Import int getLineNumber();
|
||||
@Import string getMethodName();
|
||||
@Import bool isNativeMethod();
|
||||
}
|
||||
|
||||
private void exceptionCheck(JNIEnv* env) {
|
||||
if((*env).ExceptionCheck(env)) {
|
||||
|
@ -266,6 +406,7 @@ private void exceptionCheck(JNIEnv* env) {
|
|||
// do I need to free thrown?
|
||||
(*env).ExceptionClear(env);
|
||||
|
||||
// FIXME
|
||||
throw new Exception("Java threw");
|
||||
}
|
||||
}
|
||||
|
@ -274,6 +415,31 @@ private enum ImportImplementationString = q{
|
|||
static if(is(typeof(return) == void)) {
|
||||
(*env).CallSTATICVoidMethod(env, jobj, _jmethodID, DDataToJni(env, args).args);
|
||||
exceptionCheck(env);
|
||||
} else static if(is(typeof(return) == string) || is(typeof(return) == wstring)) {
|
||||
// I can't just use JavaParamsToD here btw because of lifetime worries.
|
||||
// maybe i should fix it down there though because there is a lot of duplication
|
||||
|
||||
auto jret = (*env).CallSTATICObjectMethod(env, jobj, _jmethodID, DDataToJni(env, args).args);
|
||||
exceptionCheck(env);
|
||||
|
||||
typeof(return) ret;
|
||||
|
||||
auto len = (*env).GetStringLength(env, jret);
|
||||
auto ptr = (*env).GetStringChars(env, jret, null);
|
||||
static if(is(T == wstring)) {
|
||||
if(ptr !is null) {
|
||||
ret = ptr[0 .. len].idup;
|
||||
(*env).ReleaseStringChars(env, jret, ptr);
|
||||
}
|
||||
} else {
|
||||
import std.conv;
|
||||
if(ptr !is null) {
|
||||
ret = to!string(ptr[0 .. len]);
|
||||
(*env).ReleaseStringChars(env, jret, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
} else static if(is(typeof(return) == int)) {
|
||||
auto ret = (*env).CallSTATICIntMethod(env, jobj, _jmethodID, DDataToJni(env, args).args);
|
||||
exceptionCheck(env);
|
||||
|
@ -302,13 +468,57 @@ private enum ImportImplementationString = q{
|
|||
auto ret = (*env).CallSTATICCharMethod(env, jobj, _jmethodID, DDataToJni(env, args).args);
|
||||
exceptionCheck(env);
|
||||
return ret;
|
||||
} else static if(is(typeof(return) == E[], E)) {
|
||||
// Java arrays are represented as objects
|
||||
auto jarr = (*env).CallSTATICObjectMethod(env, jobj, _jmethodID, DDataToJni(env, args).args);
|
||||
exceptionCheck(env);
|
||||
|
||||
auto len = (*env).GetArrayLength(env, jarr);
|
||||
static if(is(E == int)) {
|
||||
auto eles = (*env).GetIntArrayElements(env, jarr, null);
|
||||
auto res = eles[0 .. len];
|
||||
(*env).ReleaseIntArrayElements(env, jarr, eles, 0);
|
||||
} else static if(is(E == bool)) {
|
||||
auto eles = (*env).GetBooleanArrayElements(env, jarr, null);
|
||||
auto res = eles[0 .. len];
|
||||
(*env).ReleaseBooleanArrayElements(env, jarr, eles, 0);
|
||||
} else static if(is(E == long)) {
|
||||
auto eles = (*env).GetLongArrayElements(env, jarr, null);
|
||||
auto res = eles[0 .. len];
|
||||
(*env).ReleaseLongArrayElements(env, jarr, eles, 0);
|
||||
} else static if(is(E == short)) {
|
||||
auto eles = (*env).GetShortArrayElements(env, jarr, null);
|
||||
auto res = eles[0 .. len];
|
||||
(*env).ReleaseShortArrayElements(env, jarr, eles, 0);
|
||||
} else static if(is(E == wchar)) {
|
||||
auto eles = (*env).GetCharArrayElements(env, jarr, null);
|
||||
auto res = eles[0 .. len];
|
||||
(*env).ReleaseCharArrayElements(env, jarr, eles, 0);
|
||||
} else static if(is(E == float)) {
|
||||
auto eles = (*env).GetFloatArrayElements(env, jarr, null);
|
||||
auto res = eles[0 .. len];
|
||||
(*env).ReleaseFloatArrayElements(env, jarr, eles, 0);
|
||||
} else static if(is(E == double)) {
|
||||
auto eles = (*env).GetDoubleArrayElements(env, jarr, null);
|
||||
auto res = eles[0 .. len];
|
||||
(*env).ReleaseDoubleArrayElements(env, jarr, eles, 0);
|
||||
} else static if(is(E == byte)) {
|
||||
auto eles = (*env).GetByteArrayElements(env, jarr, null);
|
||||
auto res = eles[0 .. len];
|
||||
(*env).ReleaseByteArrayElements(env, jarr, eles, 0);
|
||||
} else static if(is(E : IJavaObject)) {
|
||||
// FIXME: implement this
|
||||
typeof(return) res = null;
|
||||
} else static assert(0, E.stringof ~ " not supported array element type yet"); // FIXME handle object arrays too. which would also prolly include arrays of arrays.
|
||||
|
||||
return res;
|
||||
} else {
|
||||
static assert(0, "Unsupported return type for JNI " ~ typeof(return).stringof);
|
||||
//return DDataToJni(env, __traits(getMember, dobj, __traits(identifier, method))(JavaParamsToD!(Parameters!method)(env, args).args));
|
||||
}
|
||||
};
|
||||
|
||||
private mixin template JavaImportImpl(T, alias method) {
|
||||
private mixin template JavaImportImpl(T, alias method, size_t overloadIndex) {
|
||||
import std.traits;
|
||||
|
||||
private static jmethodID _jmethodID;
|
||||
|
@ -362,7 +572,7 @@ private mixin template JavaImportImpl(T, alias method) {
|
|||
jc = internalJavaClassHandle_;
|
||||
}
|
||||
_jmethodID = (*env).GetStaticMethodID(env, jc,
|
||||
__traits(identifier, method).ptr,
|
||||
getJavaName!method.ptr,
|
||||
// java method string is (args)ret
|
||||
("(" ~ DTypesToJniString!(typeof(args)) ~ ")" ~ DTypesToJniString!(typeof(return)) ~ "\0").ptr
|
||||
);
|
||||
|
@ -387,7 +597,7 @@ private mixin template JavaImportImpl(T, alias method) {
|
|||
if(!_jmethodID) {
|
||||
auto jc = (*env).GetObjectClass(env, jobj);
|
||||
_jmethodID = (*env).GetMethodID(env, jc,
|
||||
__traits(identifier, method).ptr,
|
||||
getJavaName!method.ptr,
|
||||
// java method string is (args)ret
|
||||
("(" ~ DTypesToJniString!(typeof(args)) ~ ")" ~ DTypesToJniString!(typeof(return)) ~ "\0").ptr
|
||||
);
|
||||
|
@ -403,62 +613,49 @@ private mixin template JavaImportImpl(T, alias method) {
|
|||
|
||||
private template DTypesToJniString(Types...) {
|
||||
static if(Types.length == 0)
|
||||
string DTypesToJniString = "";
|
||||
enum string DTypesToJniString = "";
|
||||
else static if(Types.length == 1) {
|
||||
alias T = Types[0];
|
||||
|
||||
static if(is(T == void))
|
||||
string DTypesToJniString = "V";
|
||||
else static if(is(T == string))
|
||||
string DTypesToJniString = "Ljava/lang/String;";
|
||||
else static if(is(T == wstring))
|
||||
string DTypesToJniString = "Ljava/lang/String;";
|
||||
enum string DTypesToJniString = "V";
|
||||
else static if(is(T == string)) {
|
||||
enum string DTypesToJniString = "Ljava/lang/String;";
|
||||
} else static if(is(T == wstring))
|
||||
enum string DTypesToJniString = "Ljava/lang/String;";
|
||||
else static if(is(T == int))
|
||||
string DTypesToJniString = "I";
|
||||
enum string DTypesToJniString = "I";
|
||||
else static if(is(T == bool))
|
||||
string DTypesToJniString = "Z";
|
||||
enum string DTypesToJniString = "Z";
|
||||
else static if(is(T == byte))
|
||||
string DTypesToJniString = "B";
|
||||
enum string DTypesToJniString = "B";
|
||||
else static if(is(T == wchar))
|
||||
string DTypesToJniString = "C";
|
||||
enum string DTypesToJniString = "C";
|
||||
else static if(is(T == short))
|
||||
string DTypesToJniString = "S";
|
||||
enum string DTypesToJniString = "S";
|
||||
else static if(is(T == long))
|
||||
string DTypesToJniString = "J";
|
||||
enum string DTypesToJniString = "J";
|
||||
else static if(is(T == float))
|
||||
string DTypesToJniString = "F";
|
||||
enum string DTypesToJniString = "F";
|
||||
else static if(is(T == double))
|
||||
string DTypesToJniString = "D";
|
||||
enum string DTypesToJniString = "D";
|
||||
else static if(is(T == size_t))
|
||||
string DTypesToJniString = "I"; // possible FIXME...
|
||||
enum string DTypesToJniString = "I"; // possible FIXME...
|
||||
else static if(is(T == IJavaObject))
|
||||
string DTypesToJniString = "LObject;"; // FIXME?
|
||||
enum string DTypesToJniString = "LObject;"; // FIXME?
|
||||
else static if(is(T : IJavaObject)) // child of this but a concrete type
|
||||
string DTypesToJniString = T._javaParameterString;
|
||||
/+ // FIXME they are just "[" ~ element type string
|
||||
else static if(is(T == IJavaObject[]))
|
||||
string DTypesToJniString = jobjectArray;
|
||||
else static if(is(T == bool[]))
|
||||
string DTypesToJniString = jbooleanArray;
|
||||
else static if(is(T == byte[]))
|
||||
string DTypesToJniString = jbyteArray;
|
||||
else static if(is(T == wchar[]))
|
||||
string DTypesToJniString = jcharArray;
|
||||
else static if(is(T == short[]))
|
||||
string DTypesToJniString = jshortArray;
|
||||
else static if(is(T == int[]))
|
||||
string DTypesToJniString = jintArray;
|
||||
else static if(is(T == long[]))
|
||||
string DTypesToJniString = jlongArray;
|
||||
else static if(is(T == float[]))
|
||||
string DTypesToJniString = jfloatArray;
|
||||
else static if(is(T == double[]))
|
||||
string DTypesToJniString = jdoubleArray;
|
||||
+/
|
||||
enum string DTypesToJniString = T._javaParameterString;
|
||||
else static if(is(T == E[], E))
|
||||
enum string DTypesToJniString = "[" ~ DTypesToJniString!E;
|
||||
else static assert(0, "Unsupported type for JNI call " ~ T.stringof);
|
||||
} else {
|
||||
import std.typecons;
|
||||
string DTypesToJni = DTypesToJni!(Types[0]) ~ DTypesToJni(Types[1 .. $]);
|
||||
private string helper() {
|
||||
string s;
|
||||
foreach(Type; Types)
|
||||
s ~= DTypesToJniString!Type;
|
||||
return s;
|
||||
}
|
||||
enum string DTypesToJniString = helper;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -515,8 +712,10 @@ private template DTypesToJni(Types...) {
|
|||
alias DTypesToJni = jdoubleArray;
|
||||
else static assert(0, "Unsupported type for JNI " ~ T.stringof);
|
||||
} else {
|
||||
import std.typecons;
|
||||
alias DTypesToJni = AliasSeq!(DTypesToJni!(Types[0]), DTypesToJni(Types[1 .. $]));
|
||||
import std.meta;
|
||||
// FIXME: write about this later if you forget the ! on the final DTypesToJni, dmd
|
||||
// says "error: recursive template expansion". woof.
|
||||
alias DTypesToJni = AliasSeq!(DTypesToJni!(Types[0]), DTypesToJni!(Types[1 .. $]));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -562,7 +761,7 @@ auto DDatumToJni(T)(JNIEnv* env, T data) {
|
|||
else static if(is(T == float)) return data;
|
||||
else static if(is(T == double)) return data;
|
||||
else static if(is(T == size_t)) return cast(int) data;
|
||||
else static if(is(T : IJavaObject)) return data.getJavaHandle();
|
||||
else static if(is(T : IJavaObject)) return data is null ? null : data.getJavaHandle();
|
||||
else static assert(0, "Unsupported type " ~ T.stringof);
|
||||
/* // FIXME: finish these.
|
||||
else static if(is(T == IJavaObject[]))
|
||||
|
@ -675,22 +874,24 @@ void jniRethrow(JNIEnv* env, Throwable t) {
|
|||
);
|
||||
}
|
||||
|
||||
private mixin template JavaExportImpl(T, alias method) {
|
||||
private mixin template JavaExportImpl(T, alias method, size_t overloadIndex) {
|
||||
import std.traits;
|
||||
import std.string;
|
||||
|
||||
static if(__traits(identifier, method) == "__ctor")
|
||||
static assert(0, "Cannot export D constructors");
|
||||
|
||||
/+
|
||||
static private string JniMangle() {
|
||||
// this actually breaks with -betterC though so does a lot more so meh.
|
||||
static if(is(T : JavaClass!(JP, P), string JP, P))
|
||||
return "Java_" ~replace(JP, ".", "_") ~ (JP.length ? "_" : "") ~ P.stringof ~ "_" ~ __traits(identifier, method);
|
||||
else static assert(0);
|
||||
}
|
||||
+/
|
||||
|
||||
extern(C)
|
||||
pragma(mangle, JniMangle())
|
||||
extern(System)
|
||||
//pragma(mangle, JniMangle())
|
||||
// I need it in the DLL, but want it to be not accessible from outside... alas.
|
||||
export /*private*/ static DTypesToJni!(ReturnType!method) privateJniImplementation(JNIEnv* env, jobject obj, DTypesToJni!(Parameters!method) args) {
|
||||
// set it up in the thread for future calls
|
||||
|
@ -716,19 +917,28 @@ private mixin template JavaExportImpl(T, alias method) {
|
|||
|
||||
static if(is(typeof(return) == void)) {
|
||||
try {
|
||||
__traits(getMember, dobj, __traits(identifier, method))(JavaParamsToD!(Parameters!method)(env, args).args);
|
||||
__traits(getOverloads, dobj, __traits(identifier, method))[overloadIndex](JavaParamsToD!(Parameters!method)(env, args).args);
|
||||
} catch(Throwable t) {
|
||||
jniRethrow(env, t);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
return DDatumToJni(env, __traits(getMember, dobj, __traits(identifier, method))(JavaParamsToD!(Parameters!method)(env, args).args));
|
||||
return DDatumToJni(env, __traits(getOverloads, dobj, __traits(identifier, method))[overloadIndex](JavaParamsToD!(Parameters!method)(env, args).args));
|
||||
} catch(Throwable t) {
|
||||
jniRethrow(env, t);
|
||||
return typeof(return).init; // still required to return...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
shared static this() {
|
||||
nativeMethodsData_ ~= JNINativeMethod(
|
||||
getJavaName!method.ptr,
|
||||
("(" ~ DTypesToJniString!(Parameters!method) ~ ")" ~ DTypesToJniString!(ReturnType!method) ~ "\0").ptr,
|
||||
&privateJniImplementation
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/++
|
||||
|
@ -776,27 +986,48 @@ class JavaClass(string javaPackage, CRTP) : IJavaObject {
|
|||
static assert("JavaClasses can only be constructed by Java. Try making a constructor in Java, then make an @Import this(args); here.");
|
||||
|
||||
// implementations
|
||||
static foreach(attr; __traits(getAttributes, __traits(getMember, CRTP, memberName))) {
|
||||
static foreach(oi, overload; __traits(getOverloads, CRTP, memberName))
|
||||
static foreach(attr; __traits(getAttributes, overload)) {
|
||||
static if(is(attr == Import))
|
||||
mixin JavaImportImpl!(CRTP, __traits(getMember, CRTP, memberName));
|
||||
mixin JavaImportImpl!(CRTP, overload, oi);
|
||||
else static if(is(attr == Export))
|
||||
mixin JavaExportImpl!(CRTP, __traits(getMember, CRTP, memberName));
|
||||
mixin JavaExportImpl!(CRTP, overload, oi);
|
||||
}
|
||||
}
|
||||
|
||||
protected jobject internalJavaHandle_;
|
||||
protected jobject getJavaHandle() { return internalJavaHandle_; }
|
||||
|
||||
__gshared static protected /*immutable*/ JNINativeMethod[] nativeMethodsData_;
|
||||
protected static jclass internalJavaClassHandle_;
|
||||
protected static int initializeInJvm_(JNIEnv* env) {
|
||||
|
||||
import core.stdc.stdio;
|
||||
auto internalJavaClassHandle_ = (*env).FindClass(env, (_javaParameterString[1 .. $-1] ~ "\0").ptr);
|
||||
if(!internalJavaClassHandle_) {
|
||||
fprintf(stderr, ("Cannot find Java class for " ~ CRTP.stringof));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if((*env).RegisterNatives(env, internalJavaClassHandle_, nativeMethodsData_.ptr, cast(int) nativeMethodsData_.length)) {
|
||||
fprintf(stderr, ("RegisterNatives failed for " ~ CRTP.stringof));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
shared static this() {
|
||||
classInitializers_ ~= &initializeInJvm_;
|
||||
}
|
||||
|
||||
static import std.string;
|
||||
static if(javaPackage.length)
|
||||
public static immutable string _javaParameterString = "L" ~ std.string.replace(javaPackage, ".", "/") ~ "/" ~ CRTP.stringof ~ ";";
|
||||
public static immutable string _javaParameterString = "L" ~ std.string.replace(javaPackage, ".", "/") ~ "/" ~ getJavaName!CRTP ~ ";";
|
||||
else
|
||||
public static immutable string _javaParameterString = "L" ~ CRTP.stringof ~ ";";
|
||||
public static immutable string _javaParameterString = "L" ~ getJavaName!CRTP ~ ";";
|
||||
}
|
||||
|
||||
|
||||
__gshared /* immutable */ int function(JNIEnv* env)[] classInitializers_;
|
||||
|
||||
|
||||
|
||||
|
@ -820,7 +1051,7 @@ class JavaClass(string javaPackage, CRTP) : IJavaObject {
|
|||
import core.stdc.stdarg;
|
||||
|
||||
//version (Android):
|
||||
extern (C):
|
||||
extern (System):
|
||||
@system:
|
||||
nothrow:
|
||||
@nogc:
|
||||
|
|
Loading…
Reference in New Issue