aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--compiler/build.gradle3
-rw-r--r--compiler/src/main/java/io/github/landerlyoung/jenny/HandyHelper.kt6
-rw-r--r--compiler/src/main/java/io/github/landerlyoung/jenny/JteData.kt19
-rw-r--r--compiler/src/main/java/io/github/landerlyoung/jenny/MethodOverloadResolver.kt19
-rw-r--r--compiler/src/main/java/io/github/landerlyoung/jenny/NativeProxyGenerator.kt620
-rw-r--r--sample-android/src/main/cpp/CMakeLists.txt33
-rw-r--r--sample-android/src/main/cpp/jni_onload.cpp23
-rw-r--r--sample-android/templates/constructor_definition.kte6
-rw-r--r--sample-android/templates/constructors_ids_declarations.kte9
-rw-r--r--sample-android/templates/fields_ids_declarations.kte9
-rw-r--r--sample-android/templates/header_initfunctions.kte2
-rw-r--r--sample-android/templates/header_initvars.kte4
-rw-r--r--sample-android/templates/header_postamble.kte4
-rw-r--r--sample-android/templates/header_preamble.kte12
-rw-r--r--sample-android/templates/method_prologue.kte2
-rw-r--r--sample-android/templates/methods_ids_declarations.kte9
-rw-r--r--sample-android/templates/param.kte2
-rw-r--r--templates/constructor_definition.kte12
-rw-r--r--templates/header_initfunctions.kte15
-rw-r--r--templates/header_initvars.kte16
-rw-r--r--templates/header_postamble.kte15
-rw-r--r--templates/header_preamble.kte27
-rw-r--r--templates/method_prologue.kte16
-rw-r--r--templates/param.kte22
24 files changed, 608 insertions, 297 deletions
diff --git a/compiler/build.gradle b/compiler/build.gradle
index 11dbb35..d011274 100644
--- a/compiler/build.gradle
+++ b/compiler/build.gradle
@@ -10,6 +10,7 @@ sourceSets {
main {
resources {
srcDirs += rootProject.file("cpp")
+// srcDirs += rootProject.file("templates")
}
}
}
@@ -33,4 +34,4 @@ compileTestKotlin {
kotlinOptions {
jvmTarget = "1.8"
}
-}
+} \ No newline at end of file
diff --git a/compiler/src/main/java/io/github/landerlyoung/jenny/HandyHelper.kt b/compiler/src/main/java/io/github/landerlyoung/jenny/HandyHelper.kt
index 7559dbb..575a2f9 100644
--- a/compiler/src/main/java/io/github/landerlyoung/jenny/HandyHelper.kt
+++ b/compiler/src/main/java/io/github/landerlyoung/jenny/HandyHelper.kt
@@ -282,9 +282,9 @@ class HandyHelper(private val mEnv: Environment) {
}
- fun getConstructorName(index: Int): String {
- return "sConstruct_$index"
- }
+ fun getConstructorName(index: Int) = "sConstruct_$index"
+ fun getMethodName(e: ExecutableElement, index: Int) = "sMethod_" + e.simpleName + "_" + index
+ fun getFieldName(e: Element, index: Int) = "sField_" + e.simpleName + "_" + index
fun toJNIType(t: TypeMirror?): String {
if (t == null) return ""
diff --git a/compiler/src/main/java/io/github/landerlyoung/jenny/JteData.kt b/compiler/src/main/java/io/github/landerlyoung/jenny/JteData.kt
new file mode 100644
index 0000000..8cf0f5e
--- /dev/null
+++ b/compiler/src/main/java/io/github/landerlyoung/jenny/JteData.kt
@@ -0,0 +1,19 @@
+package io.github.landerlyoung.jenny
+
+import javax.lang.model.element.TypeElement
+
+data class JteData(
+ val className: String,
+ val simpleClassName: String,
+ val namespaceHelper: NamespaceHelper,
+ val slashClassName: String,
+ val environment: Environment,
+ var param: String = "",
+ var returnType: String = "",
+ var methodPrologue: String = "",
+ var isStatic: Boolean = false,
+ var useJniHelper: Boolean = false,
+ var clazz: TypeElement? = null,
+ var method: MethodOverloadResolver.MethodRecord? = null,
+ val handyHelper: HandyHelper
+) \ No newline at end of file
diff --git a/compiler/src/main/java/io/github/landerlyoung/jenny/MethodOverloadResolver.kt b/compiler/src/main/java/io/github/landerlyoung/jenny/MethodOverloadResolver.kt
index 244f00f..c51299f 100644
--- a/compiler/src/main/java/io/github/landerlyoung/jenny/MethodOverloadResolver.kt
+++ b/compiler/src/main/java/io/github/landerlyoung/jenny/MethodOverloadResolver.kt
@@ -11,13 +11,14 @@ import javax.lang.model.element.ExecutableElement
* ```
*/
class MethodOverloadResolver(
- private val helper: HandyHelper,
- private val nativeParamResolver: (ExecutableElement) -> String
+ private val helper: HandyHelper,
+ private val nativeParamResolver: (ExecutableElement) -> String
) {
- class MethodRecord(
- val method: ExecutableElement,
- val resolvedPostFix: String,
- val index: Int)
+ data class MethodRecord(
+ val method: ExecutableElement,
+ val resolvedPostFix: String,
+ val index: Int
+ )
fun resolve(methodList: List<ExecutableElement>): List<MethodRecord> {
val duplicateRecord = mutableMapOf<String, Boolean>()
@@ -30,9 +31,9 @@ class MethodOverloadResolver(
val p = nativeParamResolver(m)
if (duplicateRecord[p]!! || Constants.CPP_RESERVED_WORS.contains(m.simpleName.toString())) {
MethodRecord(
- m,
- helper.getMethodOverloadPostfix(m),
- index
+ m,
+ helper.getMethodOverloadPostfix(m),
+ index
)
} else {
MethodRecord(m, "", index)
diff --git a/compiler/src/main/java/io/github/landerlyoung/jenny/NativeProxyGenerator.kt b/compiler/src/main/java/io/github/landerlyoung/jenny/NativeProxyGenerator.kt
index 59c9e2e..799051b 100644
--- a/compiler/src/main/java/io/github/landerlyoung/jenny/NativeProxyGenerator.kt
+++ b/compiler/src/main/java/io/github/landerlyoung/jenny/NativeProxyGenerator.kt
@@ -38,6 +38,7 @@ import gg.jte.resolve.DirectoryCodeResolver;
import gg.jte.TemplateOutput;
import gg.jte.output.StringOutput;
import gg.jte.html.*;
+import java.io.File
/**
* Author: landerlyoung@gmail.com
@@ -45,13 +46,15 @@ import gg.jte.html.*;
* Time: 00:30
* Life with Passion, Code with Creativity.
*/
-class NativeProxyGenerator(env: Environment, clazz: TypeElement, nativeProxy: NativeProxyConfig) : AbsCodeGenerator(env, clazz) {
+class NativeProxyGenerator(env: Environment, clazz: TypeElement, nativeProxy: NativeProxyConfig) :
+ AbsCodeGenerator(env, clazz) {
data class NativeProxyConfig(
- val allMethods: Boolean,
- val allFields: Boolean,
- val namespace: String,
- val onlyPublic: Boolean) {
+ val allMethods: Boolean,
+ val allFields: Boolean,
+ val namespace: String,
+ val onlyPublic: Boolean
+ ) {
constructor(proxy: NativeProxy)
: this(proxy.allMethods, proxy.allFields, proxy.namespace, false)
}
@@ -86,34 +89,35 @@ class NativeProxyGenerator(env: Environment, clazz: TypeElement, nativeProxy: Na
private lateinit var templateEngine: TemplateEngine
- public class JteData(
- public val mCppClassName: String,
- public val mSimpleClassName: String,
- public val mNamespaceHelper: NamespaceHelper,
- public val mSlashClassName: String,
- public val mEnv: Environment,
- public var param: String,
- public var returnType: String,
- public var methodPrologue: String,
- public var isStatic : Boolean = false,
- public var useJniHelper : Boolean = false,
- public var clazz : TypeElement? = null,
- public var method : MethodOverloadResolver.MethodRecord? = null,
- public val mHelper: HandyHelper
-) {
-
- }
- private val jteData: JteData = JteData(cppClassName, mSimpleClassName,
- mNamespaceHelper,
- mSlashClassName, mEnv,
- "", "", "", false, false, null, null, mHelper)
+ private val jteData = JteData(
+ className = cppClassName,
+ simpleClassName = mSimpleClassName,
+ namespaceHelper = mNamespaceHelper,
+ slashClassName = mSlashClassName,
+ environment = mEnv,
+ handyHelper = mHelper
+ )
+ private var useTemplates = mEnv.configurations.useTemplates
+
init {
mHeaderName = mNamespaceHelper.fileNamePrefix + "${cppClassName}.h"
mSourceName = mNamespaceHelper.fileNamePrefix + "${cppClassName}.cpp"
- if (mEnv.configurations.useTemplates) {
- val codeResolver = DirectoryCodeResolver(Path.of(mEnv.configurations.templateDirectory))
- templateEngine = TemplateEngine.create(codeResolver!!, Path.of(mEnv.configurations.templateDirectory), ContentType.Plain, NativeProxyGenerator::class.java.classLoader)
- templateEngine.precompileAll()
+ if (useTemplates) {
+ val path: String = mEnv.configurations.templateDirectory
+ ?: (System.getProperty("user.dir") + "/templates")
+ if (!File(path).exists()) {
+ error("Templates folder does not exist failed to generate using templates. Attempting without templates")
+ useTemplates = false
+ } else {
+ val codeResolver = DirectoryCodeResolver(Path.of(path))
+ templateEngine = TemplateEngine.create(
+ codeResolver,
+ Path.of(path),
+ ContentType.Plain,
+ NativeProxyGenerator::class.java.classLoader
+ )
+ templateEngine.precompileAll()
+ }
}
}
@@ -141,49 +145,58 @@ class NativeProxyGenerator(env: Environment, clazz: TypeElement, nativeProxy: Na
try {
log("write native proxy file [$mHeaderName]")
buildString {
- if (mEnv.configurations.useTemplates) {
+ if (useTemplates) {
val jteOutput = StringOutput()
templateEngine.render("header_preamble.kte", jteData, jteOutput)
append(jteOutput.toString())
} else {
append(Constants.AUTO_GENERATE_NOTICE)
- append("""
+ append(
+ """
|#pragma once
|
|#include <jni.h>
|#include <assert.h>
- |""".trimMargin())
+ |""".trimMargin()
+ )
if (mEnv.configurations.threadSafe) {
- append("""
+ append(
+ """
|#include <atomic>
|#include <mutex>
|
- |""".trimMargin())
+ |""".trimMargin()
+ )
}
if (mEnv.configurations.useJniHelper) {
- append("""
+ append(
+ """
|#include "jnihelper.h"
|
- |""".trimMargin())
+ |""".trimMargin()
+ )
}
- append("""
+ append(
+ """
|${mNamespaceHelper.beginNamespace()}
|class $cppClassName {
|
|public:
| static constexpr auto FULL_CLASS_NAME = "$mSlashClassName";
|
- |""".trimMargin())
+ |""".trimMargin()
+ )
}
buildConstantsIdDeclare()
- if (mEnv.configurations.useTemplates) {
+ if (useTemplates) {
val jteOutput = StringOutput();
templateEngine.render("header_initfunctions.kte", jteData, jteOutput)
append(jteOutput.toString())
} else {
- append("""
+ append(
+ """
|
|public:
|
@@ -196,7 +209,8 @@ class NativeProxyGenerator(env: Environment, clazz: TypeElement, nativeProxy: Na
| assert(initClazzSuccess);
| }
|
- |""".trimMargin())
+ |""".trimMargin()
+ )
}
buildConstructorDefines(false)
@@ -207,58 +221,13 @@ class NativeProxyGenerator(env: Environment, clazz: TypeElement, nativeProxy: Na
generateForJniHelper()
}
- if (mEnv.configurations.useTemplates) {
- val jteOutput = StringOutput();
- templateEngine.render("header_initvars.kte", jteData, jteOutput)
- append(jteOutput.toString())
- } else {
- append("""
- |
- |private:
- | struct ClassInitState {
- |
- """.trimMargin())
-
- if (mEnv.configurations.threadSafe) {
- append("""
- | // thread safe init
- | std::atomic_bool sInited {};
- | std::mutex sInitLock {};
- |""".trimMargin())
- } else {
- append(" bool sInited = false;\n")
- }
- append("""
- |
- | jclass sClazz = nullptr;
- |
- """.trimMargin())
- }
+ headerInitPreDefinition()
buildConstructorIdDeclare()
buildMethodIdDeclare()
buildFieldIdDeclare()
- if (mEnv.configurations.useTemplates) {
- val jteOutput = StringOutput();
- templateEngine.render("header_postamble.kte", jteData, jteOutput)
- append(jteOutput.toString())
- } else {
- append("""
- | }; // endof struct ClassInitState
- |
- | static inline ClassInitState& getClassInitState() {
- | static ClassInitState classInitState;
- | return classInitState;
- | }
- |
- |
- """.trimMargin())
-
- append("};\n")
- append(mNamespaceHelper.endNamespace())
- append("\n\n")
- }
+ headerInitPostDefinition()
if (mEnv.configurations.headerOnlyProxy) {
append("\n\n")
@@ -276,7 +245,8 @@ class NativeProxyGenerator(env: Environment, clazz: TypeElement, nativeProxy: Na
}
private fun StringBuilder.generateForJniHelper() {
- append("""
+ append(
+ """
| // ====== jni helper ======
|private:
| ::jenny::LocalRef<jobject> _local;
@@ -310,45 +280,111 @@ class NativeProxyGenerator(env: Environment, clazz: TypeElement, nativeProxy: Na
| assertInited(::jenny::Env().get());
| }
|
- |""".trimMargin())
+ |""".trimMargin()
+ )
buildConstructorDefines(true)
buildMethodDefines(true)
buildFieldDefines(true)
}
+ private fun StringBuilder.headerInitPreDefinition() {
+ if (useTemplates) {
+ val jteOutput = StringOutput();
+ templateEngine.render("header_initvars.kte", jteData, jteOutput)
+ append(jteOutput.toString())
+ } else {
+ append(
+ """
+ |
+ |private:
+ | struct ClassInitState {
+ |
+ """.trimMargin()
+ )
+
+ if (mEnv.configurations.threadSafe) {
+ append(
+ """
+ | // thread safe init
+ | std::atomic_bool sInited {};
+ | std::mutex sInitLock {};
+ |""".trimMargin()
+ )
+ } else {
+ append(" bool sInited = false;\n")
+ }
+ append(
+ """
+ |
+ | jclass sClazz = nullptr;
+ |
+ """.trimMargin()
+ )
+ }
+ }
+
+ private fun StringBuilder.headerInitPostDefinition() {
+ if (useTemplates) {
+ val jteOutput = StringOutput();
+ templateEngine.render("header_postamble.kte", jteData, jteOutput)
+ append(jteOutput.toString())
+ } else {
+ append(
+ """
+ | }; // endof struct ClassInitState
+ |
+ | static inline ClassInitState& getClassInitState() {
+ | static ClassInitState classInitState;
+ | return classInitState;
+ | }
+ |
+ |
+ """.trimMargin()
+ )
+
+ append("};\n")
+ append(mNamespaceHelper.endNamespace())
+ append("\n\n")
+ }
+ }
+
private fun generateSource() {
mEnv.createOutputFile(Constants.JENNY_GEN_DIR_PROXY, mSourceName)
- .use { out ->
- try {
- log("write native proxy file [$mSourceName]")
- buildString {
- generateSourceContent(false)
- }.let { content ->
- out.write(content.toByteArray(Charsets.UTF_8))
- }
- } catch (e: IOException) {
- warn("generate header file $mHeaderName failed!")
+ .use { out ->
+ try {
+ log("write native proxy file [$mSourceName]")
+ buildString {
+ generateSourceContent(false)
+ }.let { content ->
+ out.write(content.toByteArray(Charsets.UTF_8))
}
+ } catch (e: IOException) {
+ warn("generate header file $mHeaderName failed!")
}
+ }
}
private fun StringBuilder.generateSourceContent(headerOnly: Boolean) {
if (!headerOnly) {
append(Constants.AUTO_GENERATE_NOTICE)
- append("""
+ append(
+ """
|#include "$mHeaderName"
|
- |""".trimMargin())
+ |""".trimMargin()
+ )
}
if (!mEnv.configurations.errorLoggerFunction.isNullOrBlank()) {
- append("""
+ append(
+ """
|
|// external logger function passed by ${Configurations.ERROR_LOGGER_FUNCTION}
|void ${mEnv.configurations.errorLoggerFunction}(JNIEnv* env, const char* error);
|
- |""".trimMargin())
+ |""".trimMargin()
+ )
}
append(mNamespaceHelper.beginNamespace())
@@ -368,29 +404,63 @@ class NativeProxyGenerator(env: Environment, clazz: TypeElement, nativeProxy: Na
append('\n')
}
+ data class MethodIdDeclaration(
+ val helper: HandyHelper,
+ val listOfMethods: List<MethodOverloadResolver.MethodRecord>
+ )
+
private fun StringBuilder.buildConstructorIdDeclare() {
- mConstructors.forEach { r ->
- append(" jmethodID ${mHelper.getConstructorName(r.index)} = nullptr;\n")
+ if (useTemplates) {
+ val stringOutput = StringOutput()
+ val constructors = MethodIdDeclaration(mHelper, mConstructors)
+ templateEngine.render("constructors_ids_declarations.kte", constructors, stringOutput)
+ append(stringOutput.toString())
+ } else {
+ mConstructors.forEach { r ->
+ append(" jmethodID ${mHelper.getConstructorName(r.index)} = nullptr;\n")
+ }
+ append('\n')
}
- append('\n')
}
private fun StringBuilder.buildMethodIdDeclare() {
- mMethods.forEach { r ->
- append(" jmethodID ${getMethodName(r.method, r.index)} = nullptr;\n")
+ if (useTemplates) {
+ val stringOutput = StringOutput()
+ val methods = MethodIdDeclaration(mHelper, mMethods)
+ templateEngine.render("methods_ids_declarations.kte", methods, stringOutput)
+ append(stringOutput.toString())
+ } else {
+ mMethods.forEach { r ->
+ append(" jmethodID ${mHelper.getMethodName(r.method, r.index)} = nullptr;\n")
+ }
+ append('\n')
}
- append('\n')
}
+ data class FieldIdDeclaration(
+ val helper: HandyHelper,
+ val listOfFields: List<VariableElement>
+ )
+
private fun StringBuilder.buildFieldIdDeclare() {
- mFields.forEachIndexed { index, field ->
- if (field.constantValue != null) {
- warn("you are trying to add getter/setter to a compile-time constant "
- + mClassName + "." + field.simpleName.toString())
+ if (useTemplates) {
+ val stringOutput = StringOutput()
+ val fields = FieldIdDeclaration(mHelper, mFields)
+ templateEngine.render("fields_ids_declarations.kte", fields, stringOutput)
+ append(stringOutput.toString())
+ } else {
+ mFields.forEachIndexed { index, field ->
+ if (field.constantValue != null) {
+ warn(
+ "you are trying to add getter/setter to a compile-time constant "
+ + mClassName + "." + field.simpleName.toString()
+ )
+ }
+ append(" jfieldID ${mHelper.getFieldName(field, index)} = nullptr;\n")
}
- append(" jfieldID ${getFieldName(field, index)} = nullptr;\n")
+ append('\n')
}
- append('\n')
+
}
private fun StringBuilder.buildConstructorDefines(useJniHelper: Boolean) {
@@ -398,24 +468,35 @@ class NativeProxyGenerator(env: Environment, clazz: TypeElement, nativeProxy: Na
val param = makeParam(true, useJniHelper, getJniMethodParam(r.method, useJniHelper))
val returnType = if (useJniHelper) cppClassName else "jobject"
- if (mEnv.configurations.useTemplates) {
- val jteOutput = StringOutput()
- jteData.useJniHelper = useJniHelper
- jteData.clazz = mClazz
- jteData.method = r
- jteData.returnType = returnType
- jteData.methodPrologue = methodPrologue(true, useJniHelper)
- templateEngine.render("constructor_definition.kte", jteData, jteOutput)
- append(jteOutput.toString())
+ if (useTemplates) {
+ val jteOutput = StringOutput()
+ jteData.param = param
+ jteData.useJniHelper = useJniHelper
+ jteData.clazz = mClazz
+ jteData.method = r
+ jteData.returnType = returnType
+ jteData.methodPrologue = methodPrologue(true, useJniHelper)
+ templateEngine.render("constructor_definition.kte", jteData, jteOutput)
+ append(jteOutput.toString())
} else {
- append("""
- | // construct: ${mHelper.getModifiers(r.method)} ${mSimpleClassName}(${mHelper.getJavaMethodParam(r.method)})
+ append(
+ """
+ | // construct: ${mHelper.getModifiers(r.method)} ${mSimpleClassName}(${
+ mHelper.getJavaMethodParam(
+ r.method
+ )
+ })
| static $returnType newInstance${r.resolvedPostFix}(${param}) {
| ${methodPrologue(true, useJniHelper)}
- | return env->NewObject(${mHelper.getClassState(mHelper.getClazz())}, ${mHelper.getClassState(mHelper.getConstructorName(r.index))}${mHelper.getJniMethodParamVal(mClazz, r.method, useJniHelper)});
+ | return env->NewObject(${mHelper.getClassState(mHelper.getClazz())}, ${
+ mHelper.getClassState(
+ mHelper.getConstructorName(r.index)
+ )
+ }${mHelper.getJniMethodParamVal(mClazz, r.method, useJniHelper)});
| }
|
- |""".trimMargin())
+ |""".trimMargin()
+ )
}
}
@@ -437,11 +518,17 @@ class NativeProxyGenerator(env: Environment, clazz: TypeElement, nativeProxy: Na
append(" // for jni helper\n")
}
- append("""
- | // method: ${mHelper.getModifiers(m)} ${m.returnType} ${m.simpleName}(${mHelper.getJavaMethodParam(m)})
+ append(
+ """
+ | // method: ${mHelper.getModifiers(m)} ${m.returnType} ${m.simpleName}(${
+ mHelper.getJavaMethodParam(
+ m
+ )
+ })
| ${staticMod}${functionReturnType} ${m.simpleName}${r.resolvedPostFix}(${jniParam}) ${constMod}{
| ${methodPrologue(isStatic, useJniHelper)}
- |""".trimMargin())
+ |""".trimMargin()
+ )
if (m.returnType.kind !== TypeKind.VOID) {
append(" return ")
@@ -459,7 +546,11 @@ class NativeProxyGenerator(env: Environment, clazz: TypeElement, nativeProxy: Na
val static = if (isStatic) "Static" else ""
val classOrObj = if (isStatic) mHelper.getClassState(mHelper.getClazz()) else "thiz"
- append("env->Call${static}${getTypeForJniCall(m.returnType)}Method(${classOrObj}, ${mHelper.getClassState(getMethodName(m, r.index))}${mHelper.getJniMethodParamVal(mClazz, m, useJniHelper)})")
+ append(
+ "env->Call${static}${getTypeForJniCall(m.returnType)}Method(${classOrObj}, ${
+ mHelper.getClassState(mHelper.getMethodName(m, r.index))
+ }${mHelper.getJniMethodParamVal(mClazz, m, useJniHelper)})"
+ )
if (returnTypeNeedCast(jniReturnType)) {
append(")")
}
@@ -478,7 +569,7 @@ class NativeProxyGenerator(env: Environment, clazz: TypeElement, nativeProxy: Na
val isStatic = f.modifiers.contains(Modifier.STATIC)
val camelCaseName = f.simpleName.toString().capitalize(Locale.ROOT)
val getterSetters = hasGetterSetter(f)
- val fieldId = getFieldName(f, index)
+ val fieldId = mHelper.getFieldName(f, index)
val typeForJniCall = getTypeForJniCall(f.asType())
@@ -498,11 +589,13 @@ class NativeProxyGenerator(env: Environment, clazz: TypeElement, nativeProxy: Na
val jniReturnType = mHelper.toJNIType(f.asType())
val functionReturnType = f.asType().toJniTypeForReturn(useJniHelper)
val param = makeParam(isStatic, useJniHelper, "")
- append("""
+ append(
+ """
| $comment
| ${staticMod}$functionReturnType get${camelCaseName}(${param}) ${constMod}{
| ${methodPrologue(isStatic, useJniHelper)}
- | return """.trimMargin())
+ | return """.trimMargin()
+ )
if (useJniHelper && mHelper.needWrapLocalRef(f.asType())) {
append(functionReturnType).append("(")
@@ -512,7 +605,13 @@ class NativeProxyGenerator(env: Environment, clazz: TypeElement, nativeProxy: Na
append("reinterpret_cast<${jniReturnType}>(")
}
- append("${jniEnv}->Get${static}${typeForJniCall}Field(${classOrObj}, ${mHelper.getClassState(fieldId)})")
+ append(
+ "${jniEnv}->Get${static}${typeForJniCall}Field(${classOrObj}, ${
+ mHelper.getClassState(
+ fieldId
+ )
+ })"
+ )
if (returnTypeNeedCast(jniReturnType)) {
append(")")
@@ -520,68 +619,94 @@ class NativeProxyGenerator(env: Environment, clazz: TypeElement, nativeProxy: Na
if (useJniHelper && mHelper.needWrapLocalRef(f.asType())) {
append(")")
}
- append(""";
+ append(
+ """;
|
| }
|
- |""".trimMargin())
+ |""".trimMargin()
+ )
}
// setter
if (getterSetters.contains(GetterSetter.SETTER)) {
- val param = makeParam(isStatic, useJniHelper, "${f.asType().toJniTypeForParam(useJniHelper)} ${f.simpleName}")
- val passedParam = if (useJniHelper && mHelper.needWrapLocalRef(f.asType())) "${f.simpleName}.get()" else f.simpleName
- append("""
+ val param = makeParam(
+ isStatic,
+ useJniHelper,
+ "${f.asType().toJniTypeForParam(useJniHelper)} ${f.simpleName}"
+ )
+ val passedParam =
+ if (useJniHelper && mHelper.needWrapLocalRef(f.asType())) "${f.simpleName}.get()" else f.simpleName
+ append(
+ """
| $comment
| ${staticMod}void set${camelCaseName}(${param}) ${constMod}{
| ${methodPrologue(isStatic, useJniHelper)}
- | ${jniEnv}->Set${static}${typeForJniCall}Field(${classOrObj}, ${mHelper.getClassState(fieldId)}, ${passedParam});
+ | ${jniEnv}->Set${static}${typeForJniCall}Field(${classOrObj}, ${
+ mHelper.getClassState(
+ fieldId
+ )
+ }, ${passedParam});
| }
|
- |""".trimMargin())
+ |""".trimMargin()
+ )
}
append('\n')
}
}
private fun StringBuilder.buildNativeInitClass(headerOnly: Boolean) {
- val prefix = if(headerOnly) "/*static*/ inline" else "/*static*/"
- append("""
+ val prefix = if (headerOnly) "/*static*/ inline" else "/*static*/"
+ append(
+ """
|${prefix} bool $cppClassName::initClazz(JNIEnv* env) {
|#define JENNY_CHECK_NULL(val) \
| do { \
| if ((val) == nullptr) { \
- |""".trimMargin())
+ |""".trimMargin()
+ )
if (!mEnv.configurations.errorLoggerFunction.isNullOrBlank()) {
- append("""
+ append(
+ """
| ${mEnv.configurations.errorLoggerFunction}(env, "can't init ${cppClassName}::" #val); \
- |""".trimMargin())
+ |""".trimMargin()
+ )
} else {
- append("""
+ append(
+ """
| env->ExceptionDescribe(); \
- |""".trimMargin())
+ |""".trimMargin()
+ )
}
- append("""
+ append(
+ """
| return false; \
| } \
| } while(false)
|
- |""".trimMargin())
+ |""".trimMargin()
+ )
- append("""
- | auto& state = mHelper.getClassInitState();
- |""".trimMargin())
+ append(
+ """
+ | auto& state = getClassInitState();
+ |""".trimMargin()
+ )
if (mEnv.configurations.threadSafe) {
- append("""
+ append(
+ """
| if (!state.sInited) {
| std::lock_guard<std::mutex> lg(state.sInitLock);
- |""".trimMargin())
+ |""".trimMargin()
+ )
}
- append("""
+ append(
+ """
| if (!state.sInited) {
| auto clazz = env->FindClass(FULL_CLASS_NAME);
| JENNY_CHECK_NULL(clazz);
@@ -589,35 +714,41 @@ class NativeProxyGenerator(env: Environment, clazz: TypeElement, nativeProxy: Na
| env->DeleteLocalRef(clazz);
| JENNY_CHECK_NULL(state.sClazz);
|
- |""".trimMargin())
+ |""".trimMargin()
+ )
buildConstructorIdInit()
buildMethodIdInit()
buildFieldIdInit()
- append("""
+ append(
+ """
| state.sInited = true;
| }
- |""".trimMargin())
+ |""".trimMargin()
+ )
if (mEnv.configurations.threadSafe) {
append(" }\n")
}
- append("""
+ append(
+ """
|#undef JENNY_CHECK_NULL
| return true;
|}
|
- |""".trimMargin())
+ |""".trimMargin()
+ )
val lockGuard = if (mEnv.configurations.threadSafe) {
"std::lock_guard<std::mutex> lg(state.sInitLock);"
} else {
""
}
- append("""
+ append(
+ """
|${prefix} void $cppClassName::releaseClazz(JNIEnv* env) {
- | auto& state = mHelper.getClassInitState();
+ | auto& state = getClassInitState();
| if (state.sInited) {
| $lockGuard
| if (state.sInited) {
@@ -628,7 +759,8 @@ class NativeProxyGenerator(env: Environment, clazz: TypeElement, nativeProxy: Na
| }
|}
|
- |""".trimMargin())
+ |""".trimMargin()
+ )
}
private fun StringBuilder.buildConstructorIdInit() {
@@ -637,11 +769,13 @@ class NativeProxyGenerator(env: Environment, clazz: TypeElement, nativeProxy: Na
val name = "state.${mHelper.getConstructorName(r.index)}"
val signature = mHelper.getBinaryMethodSignature(c)
- append("""
+ append(
+ """
| $name = env->GetMethodID(state.sClazz, "<init>", "$signature");
| JENNY_CHECK_NULL(${name});
|
- |""".trimMargin())
+ |""".trimMargin()
+ )
}
append('\n')
}
@@ -649,73 +783,77 @@ class NativeProxyGenerator(env: Environment, clazz: TypeElement, nativeProxy: Na
private fun StringBuilder.buildMethodIdInit() {
mMethods.forEach { r ->
val m = r.method
- val name = "state.${getMethodName(m, r.index)}"
+ val name = "state.${mHelper.getMethodName(m, r.index)}"
val static = if (m.modifiers.contains(Modifier.STATIC)) "Static" else ""
val methodName = m.simpleName
val signature = mHelper.getBinaryMethodSignature(m)
- append("""
+ append(
+ """
| $name = env->Get${static}MethodID(state.sClazz, "$methodName", "$signature");
| JENNY_CHECK_NULL(${name});
|
- |""".trimMargin())
+ |""".trimMargin()
+ )
}
append('\n')
}
private fun StringBuilder.buildFieldIdInit() {
mFields.forEachIndexed { index, f ->
- val name = "state.${getFieldName(f, index)}"
+ val name = "state.${mHelper.getFieldName(f, index)}"
val static = if (f.modifiers.contains(Modifier.STATIC)) "Static" else ""
val fieldName = f.simpleName
val signature = mHelper.getBinaryTypeSignature(f.asType())
- append("""
+ append(
+ """
| $name = env->Get${static}FieldID(state.sClazz, "$fieldName", "$signature");
| JENNY_CHECK_NULL(${name});
|
- |""".trimMargin())
+ |""".trimMargin()
+ )
}
append('\n')
}
private fun makeParam(vararg params: String): String =
- params.filter { it.isNotEmpty() }.joinToString(", ")
+ params.filter { it.isNotEmpty() }.joinToString(", ")
private fun makeParam(isStatic: Boolean, useJniHelper: Boolean, jniParam: String): String =
- if (mEnv.configurations.useTemplates) {
- val jteOutput = StringOutput()
- jteData.param = jniParam
- jteData.isStatic = isStatic
- jteData.useJniHelper = useJniHelper
- templateEngine.render("param.kte", jteData, jteOutput)
- jteOutput.toString().trim()
- } else if (!useJniHelper) {
- if (isStatic) {
- makeParam("JNIEnv* env", jniParam)
- } else {
- makeParam("JNIEnv* env", "jobject thiz", jniParam)
- }
+ if (useTemplates) {
+ val jteOutput = StringOutput()
+ jteData.param = jniParam
+ jteData.isStatic = isStatic
+ jteData.useJniHelper = useJniHelper
+ templateEngine.render("param.kte", jteData, jteOutput)
+ jteOutput.toString().trim()
+ } else if (!useJniHelper) {
+ if (isStatic) {
+ makeParam("JNIEnv* env", jniParam)
} else {
- jniParam
+ makeParam("JNIEnv* env", "jobject thiz", jniParam)
}
+ } else {
+ jniParam
+ }
private fun methodPrologue(isStatic: Boolean, useJniHelper: Boolean): String =
- if (mEnv.configurations.useTemplates) {
- val jteOutput = StringOutput()
- jteData.isStatic = isStatic
- jteData.useJniHelper = useJniHelper
- templateEngine.render("method_prologue.kte", jteData, jteOutput)
- jteOutput.toString().trim()
- } else if (useJniHelper) {
- if (isStatic) {
- "::jenny::Env env; assertInited(env.get());"
- } else {
- "::jenny::Env env; ::jenny::LocalRef<jobject> jennyLocalRef = getThis(false); jobject thiz = jennyLocalRef.get();"
- }
+ if (useTemplates) {
+ val jteOutput = StringOutput()
+ jteData.isStatic = isStatic
+ jteData.useJniHelper = useJniHelper
+ templateEngine.render("method_prologue.kte", jteData, jteOutput)
+ jteOutput.toString().trim()
+ } else if (useJniHelper) {
+ if (isStatic) {
+ "::jenny::Env env; assertInited(env.get());"
} else {
- "assertInited(env);"
+ "::jenny::Env env; ::jenny::LocalRef<jobject> jennyLocalRef = getThis(false); jobject thiz = jennyLocalRef.get();"
}
+ } else {
+ "assertInited(env);"
+ }
private fun shouldGenerateMethod(m: ExecutableElement): Boolean {
val annotation = m.getAnnotation(NativeMethodProxy::class.java)
@@ -779,64 +917,58 @@ class NativeProxyGenerator(env: Environment, clazz: TypeElement, nativeProxy: Na
"jshortArray", "jintArray", "jlongArray",
"jfloatArray", "jdoubleArray",
"jthrowable", "jweak" -> true
+
else ->
// primitive type or jobject or void
false
}
}
- private fun getMethodName(e: ExecutableElement, index: Int): String {
- return "sMethod_" + e.simpleName + "_" + index
- }
-
- private fun getFieldName(e: Element, index: Int): String {
- return "sField_" + e.simpleName + "_" + index
- }
-
private fun findConstructors() {
mClazz.enclosedElements
- .asSequence()
- .filter { it.kind == ElementKind.CONSTRUCTOR }
- .map { it as ExecutableElement }
- .filter { visibilityMatched(it) && shouldGenerateMethod(it) }
- .toList()
- .let {
- MethodOverloadResolver(mHelper, this::getJniMethodParamTypes).resolve(it)
- .let { mConstructors.addAll(it) }
- }
+ .asSequence()
+ .filter { it.kind == ElementKind.CONSTRUCTOR }
+ .map { it as ExecutableElement }
+ .filter { visibilityMatched(it) && shouldGenerateMethod(it) }
+ .toList()
+ .let {
+ MethodOverloadResolver(mHelper, this::getJniMethodParamTypes).resolve(it)
+ .let { mConstructors.addAll(it) }
+ }
}
private fun findMethods() {
mClazz.enclosedElements
- .asSequence()
- .filter { it.kind == ElementKind.METHOD }
- .map { it as ExecutableElement }
- .filter { visibilityMatched(it) && shouldGenerateMethod(it) }
- .groupBy { it.simpleName.toString() }
- .forEach { (simpleName, methodList) ->
- mMethodSimpleName.add(simpleName)
- MethodOverloadResolver(mHelper, this::getJniMethodParamTypes).resolve(methodList).let {
+ .asSequence()
+ .filter { it.kind == ElementKind.METHOD }
+ .map { it as ExecutableElement }
+ .filter { visibilityMatched(it) && shouldGenerateMethod(it) }
+ .groupBy { it.simpleName.toString() }
+ .forEach { (simpleName, methodList) ->
+ mMethodSimpleName.add(simpleName)
+ MethodOverloadResolver(mHelper, this::getJniMethodParamTypes).resolve(methodList)
+ .let {
mMethods.addAll(it)
}
- }
+ }
}
private fun findConstants() {
mClazz.enclosedElements
- .asSequence()
- .filter {
- it.kind.isField && visibilityMatched(it)
- && it.modifiers.containsAll(listOf(Modifier.STATIC, Modifier.FINAL))
- && (it as VariableElement).constantValue != null
- }
- .forEach { mConstants.add(it as VariableElement) }
+ .asSequence()
+ .filter {
+ it.kind.isField && visibilityMatched(it)
+ && it.modifiers.containsAll(listOf(Modifier.STATIC, Modifier.FINAL))
+ && (it as VariableElement).constantValue != null
+ }
+ .forEach { mConstants.add(it as VariableElement) }
}
private fun findFields() {
mClazz.enclosedElements
- .asSequence()
- .filter { it.kind.isField && shouldGenerateField(it) && visibilityMatched(it) }
- .forEach { mFields.add(it as VariableElement) }
+ .asSequence()
+ .filter { it.kind.isField && shouldGenerateField(it) && visibilityMatched(it) }
+ .forEach { mFields.add(it as VariableElement) }
}
private fun visibilityMatched(element: Element): Boolean {
@@ -885,15 +1017,15 @@ class NativeProxyGenerator(env: Environment, clazz: TypeElement, nativeProxy: Na
val enclosingElement = mClazz.enclosingElement
// nested class has an this$0 in its constructor
append(enclosingElement.asType().toJniTypeForParam(useJniHelper))
- .append(" ")
- .append("enclosingClass")
+ .append(" ")
+ .append("enclosingClass")
needComma = true
}
m.parameters.forEach { p ->
if (needComma) append(", ")
append(p.asType().toJniTypeForParam(useJniHelper))
- .append(" ")
- .append(p.simpleName)
+ .append(" ")
+ .append(p.simpleName)
needComma = true
}
}
diff --git a/sample-android/src/main/cpp/CMakeLists.txt b/sample-android/src/main/cpp/CMakeLists.txt
index 2706cbd..bdcaa33 100644
--- a/sample-android/src/main/cpp/CMakeLists.txt
+++ b/sample-android/src/main/cpp/CMakeLists.txt
@@ -1,14 +1,19 @@
-cmake_minimum_required(VERSION 3.4.1)
-
-include_directories(gen)
-
-file(GLOB SRC
- ./*.cpp
- ./*.h
- )
-
-add_library(hello-jenny SHARED
- ${SRC}
- )
-
-target_link_libraries(hello-jenny log) \ No newline at end of file
+#cmake_minimum_required(VERSION 3.4.1)
+#
+#project(HelloJenny VERSION 1.0 LANGUAGES CXX)
+#set(CMAKE_CXX_STANDARD 11)
+#set(CMAKE_CXX_STANDARD_REQUIRED ON)
+#
+#file(GLOB_RECURSE SRC_CPP
+# ${CMAKE_SOURCE_DIR}/gen/jenny/glue/cpp/*.cpp
+# ${CMAKE_SOURCE_DIR}/gen/jenny/proxy/*.cpp
+# ${CMAKE_SOURCE_DIR}/*.cpp
+#)
+#file(GLOB_RECURSE SRC_H
+# ${CMAKE_SOURCE_DIR}/gen/jenny/glue/header/*.h
+# ${CMAKE_SOURCE_DIR}/gen/jenny/proxy/*.h
+#)
+#set(SRC ${SRC_CPP} ${SRC_H})
+#add_library(hello-jenny SHARED ${SRC})
+#target_include_directories(hello-jenny PRIVATE ${CMAKE_SOURCE_DIR}/gen/jenny)
+#target_link_libraries(hello-jenny PRIVATE log) \ No newline at end of file
diff --git a/sample-android/src/main/cpp/jni_onload.cpp b/sample-android/src/main/cpp/jni_onload.cpp
index 15b2b61..60557af 100644
--- a/sample-android/src/main/cpp/jni_onload.cpp
+++ b/sample-android/src/main/cpp/jni_onload.cpp
@@ -13,16 +13,19 @@
#include "ComputeIntensiveClass.h"
#include "NestedNativeClass.h"
#include "NativeDrawable.h"
-#include "gen/GenericProxy.h"
-#include "gen/jnihelper.h"
-#include "gen/jenny_fusion_proxies.h"
-
-#include "gen/java_okhttp_BuilderProxy.h"
-#include "gen/java_okhttp_OkHttpClientProxy.h"
-#include "gen/java_okhttp_RequestProxy.h"
-#include "gen/java_okhttp_CallProxy.h"
-#include "gen/java_okhttp_ResponseProxy.h"
-#include "gen/java_okhttp_ResponseBodyProxy.h"
+#include "proxy/GenericProxy.h"
+#include "proxy/jnihelper.h"
+#include "proxy/jenny_fusion_proxies.h"
+
+#include "proxy/java_okhttp_BuilderProxy.h"
+#include "proxy/java_okhttp_OkHttpClientProxy.h"
+#include "proxy/java_okhttp_RequestProxy.h"
+#include "proxy/java_okhttp_CallProxy.h"
+#include "proxy/java_okhttp_ResponseProxy.h"
+#include "proxy/java_okhttp_ResponseBodyProxy.h"
+#include "glue/header/NativeDrawable.h"
+#include "glue/header/ComputeIntensiveClass.h"
+
JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv* env;
diff --git a/sample-android/templates/constructor_definition.kte b/sample-android/templates/constructor_definition.kte
index fedd89d..91361f2 100644
--- a/sample-android/templates/constructor_definition.kte
+++ b/sample-android/templates/constructor_definition.kte
@@ -1,12 +1,12 @@
-@import io.github.landerlyoung.jenny.NativeProxyGenerator.JteData
+@import io.github.landerlyoung.jenny.JteData
@import io.github.landerlyoung.jenny.Constants
@import io.github.landerlyoung.jenny.HandyHelper
@import io.github.landerlyoung.jenny.MethodOverloadResolver.MethodRecord
@param jteData: JteData
- // construct: ${jteData.mHelper.getModifiers(jteData.method!!.method)} ${jteData.mSimpleClassName}(${jteData.mHelper.getJavaMethodParam(jteData.method!!.method)})
+ // construct: ${jteData.handyHelper.getModifiers(jteData.method!!.method)} ${jteData.simpleClassName}(${jteData.handyHelper.getJavaMethodParam(jteData.method!!.method)})
static ${jteData.returnType} newInstance${jteData.method!!.resolvedPostFix}(${jteData.param}) {
${jteData.methodPrologue}
- return env->NewObject(${jteData.mHelper.getClassState(jteData.mHelper.getClazz())}, ${jteData.mHelper.getClassState(jteData.mHelper.getConstructorName(jteData.method!!.index))}${jteData.mHelper.getJniMethodParamVal(jteData.clazz!!, jteData.method!!.method, jteData.useJniHelper)});
+ return env->NewObject(${jteData.handyHelper.getClassState(jteData.handyHelper.getClazz())}, ${jteData.handyHelper.getClassState(jteData.handyHelper.getConstructorName(jteData.method!!.index))}${jteData.handyHelper.getJniMethodParamVal(jteData.clazz!!, jteData.method!!.method, jteData.useJniHelper)});
}
diff --git a/sample-android/templates/constructors_ids_declarations.kte b/sample-android/templates/constructors_ids_declarations.kte
new file mode 100644
index 0000000..acd0a7d
--- /dev/null
+++ b/sample-android/templates/constructors_ids_declarations.kte
@@ -0,0 +1,9 @@
+@import io.github.landerlyoung.jenny.NativeProxyGenerator.MethodIdDeclaration
+@import io.github.landerlyoung.jenny.HandyHelper
+@import io.github.landerlyoung.jenny.MethodOverloadResolver.MethodRecord
+
+@param methodIdDeclaration:MethodIdDeclaration
+
+@for(method:MethodRecord in methodIdDeclaration.listOfMethods)
+ jmethodID ${methodIdDeclaration.helper.getConstructorName(method.index)} = nullptr;
+@endfor \ No newline at end of file
diff --git a/sample-android/templates/fields_ids_declarations.kte b/sample-android/templates/fields_ids_declarations.kte
new file mode 100644
index 0000000..5e1679b
--- /dev/null
+++ b/sample-android/templates/fields_ids_declarations.kte
@@ -0,0 +1,9 @@
+@import io.github.landerlyoung.jenny.NativeProxyGenerator.FieldIdDeclaration
+@import io.github.landerlyoung.jenny.HandyHelper
+@import javax.lang.model.element.VariableElement
+
+@param fieldIdDeclaration:FieldIdDeclaration
+
+@for((index, fieldElement) in fieldIdDeclaration.listOfFields.withIndex())
+ jfieldID ${fieldIdDeclaration.helper.getFieldName(fieldElement, index)} = nullptr;
+@endfor \ No newline at end of file
diff --git a/sample-android/templates/header_initfunctions.kte b/sample-android/templates/header_initfunctions.kte
index cad0890..4949f36 100644
--- a/sample-android/templates/header_initfunctions.kte
+++ b/sample-android/templates/header_initfunctions.kte
@@ -1,4 +1,4 @@
-@import io.github.landerlyoung.jenny.NativeProxyGenerator.JteData
+@import io.github.landerlyoung.jenny.JteData
@import io.github.landerlyoung.jenny.Constants
@param jteData: JteData
diff --git a/sample-android/templates/header_initvars.kte b/sample-android/templates/header_initvars.kte
index fd93466..b59357d 100644
--- a/sample-android/templates/header_initvars.kte
+++ b/sample-android/templates/header_initvars.kte
@@ -1,4 +1,4 @@
-@import io.github.landerlyoung.jenny.NativeProxyGenerator.JteData
+@import io.github.landerlyoung.jenny.JteData
@import io.github.landerlyoung.jenny.Constants
@param jteData: JteData
@@ -6,7 +6,7 @@
private:
struct ClassInitState {
-@if (jteData.mEnv.configurations.threadSafe)
+@if (jteData.environment.configurations.threadSafe)
// thread safe init
std::atomic_bool sInited {};
std::mutex sInitLock {};
diff --git a/sample-android/templates/header_postamble.kte b/sample-android/templates/header_postamble.kte
index cde05c9..fc6b0e0 100644
--- a/sample-android/templates/header_postamble.kte
+++ b/sample-android/templates/header_postamble.kte
@@ -1,4 +1,4 @@
-@import io.github.landerlyoung.jenny.NativeProxyGenerator.JteData
+@import io.github.landerlyoung.jenny.JteData
@import io.github.landerlyoung.jenny.Constants
@param jteData: JteData
@@ -11,5 +11,5 @@
return classInitState;
}
};
-${jteData.mNamespaceHelper.endNamespace()}
+${jteData.namespaceHelper.endNamespace()}
diff --git a/sample-android/templates/header_preamble.kte b/sample-android/templates/header_preamble.kte
index 4b076a9..6d4a9c2 100644
--- a/sample-android/templates/header_preamble.kte
+++ b/sample-android/templates/header_preamble.kte
@@ -1,4 +1,4 @@
-@import io.github.landerlyoung.jenny.NativeProxyGenerator.JteData
+@import io.github.landerlyoung.jenny.JteData
@import io.github.landerlyoung.jenny.Constants
@param jteData: JteData
@@ -9,19 +9,19 @@ ${Constants.AUTO_GENERATE_NOTICE}
#include <jni.h>
#include <assert.h>
-@if (jteData.mEnv.configurations.threadSafe)
+@if (jteData.environment.configurations.threadSafe)
#include <atomic>
#include <mutex>
@endif
-@if (jteData.mEnv.configurations.useJniHelper)
+@if (jteData.environment.configurations.useJniHelper)
#include "jnihelper.h"
@endif
-${jteData.mNamespaceHelper.beginNamespace()}
-class ${jteData.mCppClassName} {
+${jteData.namespaceHelper.beginNamespace()}
+class ${jteData.className} {
public:
- static constexpr auto FULL_CLASS_NAME = "${jteData.mSlashClassName}";
+ static constexpr auto FULL_CLASS_NAME = "${jteData.slashClassName}";
diff --git a/sample-android/templates/method_prologue.kte b/sample-android/templates/method_prologue.kte
index 82d0bd0..8e28bf8 100644
--- a/sample-android/templates/method_prologue.kte
+++ b/sample-android/templates/method_prologue.kte
@@ -1,4 +1,4 @@
-@import io.github.landerlyoung.jenny.NativeProxyGenerator.JteData
+@import io.github.landerlyoung.jenny.JteData
@import io.github.landerlyoung.jenny.Constants
@import io.github.landerlyoung.jenny.HandyHelper
@import io.github.landerlyoung.jenny.MethodOverloadResolver.MethodRecord
diff --git a/sample-android/templates/methods_ids_declarations.kte b/sample-android/templates/methods_ids_declarations.kte
new file mode 100644
index 0000000..16afca0
--- /dev/null
+++ b/sample-android/templates/methods_ids_declarations.kte
@@ -0,0 +1,9 @@
+@import io.github.landerlyoung.jenny.NativeProxyGenerator.MethodIdDeclaration
+@import io.github.landerlyoung.jenny.HandyHelper
+@import io.github.landerlyoung.jenny.MethodOverloadResolver.MethodRecord
+
+@param methodIdDeclaration:MethodIdDeclaration
+
+@for(method:MethodRecord in methodIdDeclaration.listOfMethods)
+ jmethodID ${methodIdDeclaration.helper.getMethodName(method.method , method.index)} = nullptr;
+@endfor \ No newline at end of file
diff --git a/sample-android/templates/param.kte b/sample-android/templates/param.kte
index f72aeb1..e788593 100644
--- a/sample-android/templates/param.kte
+++ b/sample-android/templates/param.kte
@@ -1,4 +1,4 @@
-@import io.github.landerlyoung.jenny.NativeProxyGenerator.JteData
+@import io.github.landerlyoung.jenny.JteData
@import io.github.landerlyoung.jenny.Constants
@param jteData: JteData
diff --git a/templates/constructor_definition.kte b/templates/constructor_definition.kte
new file mode 100644
index 0000000..32ba70d
--- /dev/null
+++ b/templates/constructor_definition.kte
@@ -0,0 +1,12 @@
+@import io.github.landerlyoung.jenny.JteData
+@import io.github.landerlyoung.jenny.Constants
+@import io.github.landerlyoung.jenny.HandyHelper
+@import io.github.landerlyoung.jenny.MethodOverloadResolver.MethodRecord
+
+@param jteData: JteData
+
+ // construct: ${jteData.mHelper.getModifiers(jteData.method!!.method)} ${jteData.mSimpleClassName}(${jteData.mHelper.getJavaMethodParam(jteData.method!!.method)})
+ static ${jteData.returnType} newInstance${jteData.method!!.resolvedPostFix}(${jteData.param}) {
+ ${jteData.methodPrologue}
+ return env->NewObject(${jteData.mHelper.getClassState(jteData.mHelper.getClazz())}, ${jteData.mHelper.getClassState(jteData.mHelper.getConstructorName(jteData.method!!.index))}${jteData.mHelper.getJniMethodParamVal(jteData.clazz!!, jteData.method!!.method, jteData.useJniHelper)});
+ }
diff --git a/templates/header_initfunctions.kte b/templates/header_initfunctions.kte
new file mode 100644
index 0000000..4949f36
--- /dev/null
+++ b/templates/header_initfunctions.kte
@@ -0,0 +1,15 @@
+@import io.github.landerlyoung.jenny.JteData
+@import io.github.landerlyoung.jenny.Constants
+
+@param jteData: JteData
+
+public:
+
+ static bool initClazz(JNIEnv* env);
+
+ static void releaseClazz(JNIEnv* env);
+
+ static void assertInited(JNIEnv* env) {
+ auto initClazzSuccess = initClazz(env);
+ assert(initClazzSuccess);
+ }
diff --git a/templates/header_initvars.kte b/templates/header_initvars.kte
new file mode 100644
index 0000000..fe6769c
--- /dev/null
+++ b/templates/header_initvars.kte
@@ -0,0 +1,16 @@
+@import io.github.landerlyoung.jenny.JteData
+@import io.github.landerlyoung.jenny.Constants
+
+@param jteData: JteData
+
+private:
+ struct ClassInitState {
+
+@if (jteData.mEnv.configurations.threadSafe)
+ // thread safe init
+ std::atomic_bool sInited {};
+ std::mutex sInitLock {};
+@else
+ bool sInited = false;\n")
+@endif
+ jclass sClazz = nullptr;
diff --git a/templates/header_postamble.kte b/templates/header_postamble.kte
new file mode 100644
index 0000000..d3c5480
--- /dev/null
+++ b/templates/header_postamble.kte
@@ -0,0 +1,15 @@
+@import io.github.landerlyoung.jenny.JteData
+@import io.github.landerlyoung.jenny.Constants
+
+@param jteData: JteData
+
+
+ }; // endof struct ClassInitState
+
+ static inline ClassInitState& getClassInitState() {
+ static ClassInitState classInitState;
+ return classInitState;
+ }
+};
+${jteData.mNamespaceHelper.endNamespace()}
+
diff --git a/templates/header_preamble.kte b/templates/header_preamble.kte
new file mode 100644
index 0000000..c731c3b
--- /dev/null
+++ b/templates/header_preamble.kte
@@ -0,0 +1,27 @@
+@import io.github.landerlyoung.jenny.JteData
+@import io.github.landerlyoung.jenny.Constants
+
+@param jteData: JteData
+
+${Constants.AUTO_GENERATE_NOTICE}
+#pragma once
+
+#include <jni.h>
+#include <assert.h>
+
+@if (jteData.mEnv.configurations.threadSafe)
+#include <atomic>
+#include <mutex>
+@endif
+
+@if (jteData.mEnv.configurations.useJniHelper)
+#include "jnihelper.h"
+@endif
+
+${jteData.mNamespaceHelper.beginNamespace()}
+class ${jteData.mCppClassName} {
+
+public:
+ static constexpr auto FULL_CLASS_NAME = "${jteData.mSlashClassName}";
+
+
diff --git a/templates/method_prologue.kte b/templates/method_prologue.kte
new file mode 100644
index 0000000..8e28bf8
--- /dev/null
+++ b/templates/method_prologue.kte
@@ -0,0 +1,16 @@
+@import io.github.landerlyoung.jenny.JteData
+@import io.github.landerlyoung.jenny.Constants
+@import io.github.landerlyoung.jenny.HandyHelper
+@import io.github.landerlyoung.jenny.MethodOverloadResolver.MethodRecord
+
+@param jteData: JteData
+
+@if (jteData.useJniHelper)
+ @if (jteData.isStatic)
+::jenny::Env env; assertInited(env.get());
+ @else
+::jenny::Env env; ::jenny::LocalRef<jobject> jennyLocalRef = getThis(false); jobject thiz = jennyLocalRef.get();
+ @endif
+@else
+assertInited(env);
+@endif \ No newline at end of file
diff --git a/templates/param.kte b/templates/param.kte
new file mode 100644
index 0000000..e788593
--- /dev/null
+++ b/templates/param.kte
@@ -0,0 +1,22 @@
+@import io.github.landerlyoung.jenny.JteData
+@import io.github.landerlyoung.jenny.Constants
+
+@param jteData: JteData
+
+@if (!jteData.useJniHelper)
+ @if (jteData.isStatic)
+ @if (jteData.param != "")
+JNIEnv* env, ${jteData.param}
+ @else
+JNIEnv* env
+ @endif
+ @else
+ @if (jteData.param != "")
+JNIEnv* env, jobject thiz, ${jteData.param}
+ @else
+JNIEnv* env, jobject thiz
+ @endif
+ @endif
+@else
+${jteData.param}
+@endif \ No newline at end of file