static String jni_signature(Class c) { if (c == int.class) return "I"; if (c == long.class) return "J"; if (c == short.class) return "S"; if (c == byte.class) return "B"; if (c == boolean.class) return "Z"; if (c == double.class) return "D"; if (c == float.class) return "F"; if (c == char.class) return "C"; if (c == void.class) return "V"; if (c.isArray()) return "[" + jni_signature(c.getComponentType()); return "L" + name(c) + ";"; }
static String[] c_signature(Class c, String expr) { if (c.isPrimitive()) return strs("j" + c.toString(), expr, expr); if (c == Pointer.class) return strs( "void*", "createPointerFromIO(env, " + expr + ", NULL)", "getPointerPeer(env, " + expr + ")"); // TODO callIO if (c == CLong.class) return strs("long", "BoxCLong(env, " + expr + ")", "UnBoxCLong(env, " + expr + ")"); if (c == SizeT.class) return strs("size_t", "BoxSizeT(env, " + expr + ")", "UnBoxSizeT(env, " + expr + ")"); if (c == TimeT.class) return strs("time_t", "BoxTimeT(env, " + expr + ")", "UnBoxTimeT(env, " + expr + ")"); throw new UnsupportedOperationException("Cannot compute C signature for " + c.getName()); }
public static String generateProxy(Class interfaceClass) throws Exception { StringBuilder b = new StringBuilder(); b.append("#include <jni.h>\n"); b.append("#ifdef _WIN32\n"); b.append("#define PROXY_EXPORT __declspec(dllexport)\n"); b.append("#else\n"); b.append("#define PROXY_EXPORT\n"); b.append("#endif\n"); b.append( "#define FIND_GLOBAL_CLASS(name) (*env)->NewGlobalRef(env, (*env)->FindClass(env, name))\n"); List<ProxiedMethod> methods = new ArrayList<ProxiedMethod>(); int iClassName = 0, iMethodName = 0; Map<Class, String> classVarNames = new HashMap<Class, String>(); for (Method m : interfaceClass.getDeclaredMethods()) { try { ProxiedMethod pm = getProxiedMethod(m); String classVarName = classVarNames.get(pm.owner); if (classVarName == null) classVarNames.put(pm.owner, classVarName = "gClass" + (++iClassName)); pm.classVarName = classVarName; pm.methodVarName = "gMethod" + (++iMethodName); methods.add(pm); } catch (Throwable th) { // th.printStackTrace(); } } b.append("jboolean inited = JNI_FALSE;\n"); String instanceVarName = "gProxiedInstance"; b.append("JNIEnv* env = NULL;\n"); b.append("JavaVM* jvm = NULL;\n"); b.append("jobject ").append(instanceVarName).append(" = NULL;\n"); for (String n : classVarNames.values()) b.append("jclass ").append(n).append(" = NULL;\n"); for (ProxiedMethod pm : methods) b.append("jmethodID ").append(pm.methodVarName).append(" = NULL;\n"); String jniInit = "jni_init"; b.append("void ").append(jniInit).append("(JNIEnv* env) {\n"); b.append("\tif (inited) return; else inited = JNI_TRUE;\n"); for (Map.Entry<Class, String> e : classVarNames.entrySet()) { String n = e.getValue(); Class c = e.getKey(); b.append("\t") .append(n) .append(" = ") .append("FIND_GLOBAL_CLASS(\"") .append(name(c)) .append("\");\n"); } for (ProxiedMethod pm : methods) { int mods = pm.method.getModifiers(); b.append("\t") .append(pm.methodVarName) .append(" = ") .append("(*env)->") .append(Modifier.isStatic(mods) ? "GetStaticMethodID" : "GetMethodID") .append("(env, ") .append(pm.classVarName) .append(", \"") .append(pm.name) .append("\", \"") .append(pm.jni_signature) .append("\");\n"); } b.append("}\n"); for (ProxiedMethod pm : methods) { b.append("PROXY_EXPORT ").append(pm.c_signature).append(" {\n"); int mods = pm.method.getModifiers(); b.append("\t").append(jniInit).append("();\n"); b.append("\t"); if (pm.method.getReturnType() != null && !pm.method.getReturnType().equals(void.class)) b.append("return "); StringBuilder r = new StringBuilder(); boolean stat = Modifier.isStatic(mods); r.append("(*env)->") .append("Call" + (stat ? "Static" : "") + pm.retCapitalized + "Method") .append("(env, "); if (stat) r.append(pm.classVarName); else r.append(instanceVarName); for (String argValue : pm.argValues) { r.append(", \n\t\t"); r.append(argValue); } // TODO... r.append("\n\t)"); b.append(c_signature(pm.method.getReturnType(), r.toString())[2]); b.append(";\n"); b.append("}\n"); } return b.toString(); }
static String name(Class c) { return c.getName().replace('.', '/'); }