From 22fc1e4efba8a219d140e353e7d5b861e651a792 Mon Sep 17 00:00:00 2001 From: FITOR Date: Wed, 6 Nov 2024 11:17:37 +0100 Subject: [PATCH 01/28] implemented support for nested exceptions --- .../org/bytedeco/javacpp/tools/Generator.java | 443 ++++++++---------- src/main/resources/META-INF/MANIFEST.MF | 3 + .../jniTemplates/JNIExceptionHandler.h | 36 ++ 3 files changed, 241 insertions(+), 241 deletions(-) create mode 100644 src/main/resources/META-INF/MANIFEST.MF create mode 100644 src/main/resources/org/bytedeco/javacpp/jniTemplates/JNIExceptionHandler.h diff --git a/src/main/java/org/bytedeco/javacpp/tools/Generator.java b/src/main/java/org/bytedeco/javacpp/tools/Generator.java index cb41b19a2..63bbe6ec9 100644 --- a/src/main/java/org/bytedeco/javacpp/tools/Generator.java +++ b/src/main/java/org/bytedeco/javacpp/tools/Generator.java @@ -22,76 +22,18 @@ package org.bytedeco.javacpp.tools; -import java.io.File; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.Writer; +import org.bytedeco.javacpp.*; +import org.bytedeco.javacpp.annotation.*; + +import java.io.*; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.nio.Buffer; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.DoubleBuffer; -import java.nio.FloatBuffer; -import java.nio.IntBuffer; -import java.nio.LongBuffer; -import java.nio.ShortBuffer; +import java.nio.*; import java.nio.charset.Charset; -import java.util.Arrays; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; import java.util.Properties; -import java.util.Set; -import org.bytedeco.javacpp.BoolPointer; -import org.bytedeco.javacpp.BooleanPointer; -import org.bytedeco.javacpp.BytePointer; -import org.bytedeco.javacpp.CLongPointer; -import org.bytedeco.javacpp.CharPointer; -import org.bytedeco.javacpp.ClassProperties; -import org.bytedeco.javacpp.DoublePointer; -import org.bytedeco.javacpp.FloatPointer; -import org.bytedeco.javacpp.FunctionPointer; -import org.bytedeco.javacpp.IntPointer; -import org.bytedeco.javacpp.LoadEnabled; -import org.bytedeco.javacpp.Loader; -import org.bytedeco.javacpp.LongPointer; -import org.bytedeco.javacpp.Pointer; -import org.bytedeco.javacpp.PointerPointer; -import org.bytedeco.javacpp.ShortPointer; -import org.bytedeco.javacpp.SizeTPointer; -import org.bytedeco.javacpp.annotation.Adapter; -import org.bytedeco.javacpp.annotation.Allocator; -import org.bytedeco.javacpp.annotation.ArrayAllocator; -import org.bytedeco.javacpp.annotation.ByPtr; -import org.bytedeco.javacpp.annotation.ByPtrPtr; -import org.bytedeco.javacpp.annotation.ByPtrRef; -import org.bytedeco.javacpp.annotation.ByRef; -import org.bytedeco.javacpp.annotation.ByVal; -import org.bytedeco.javacpp.annotation.Cast; -import org.bytedeco.javacpp.annotation.Const; -import org.bytedeco.javacpp.annotation.Convention; -import org.bytedeco.javacpp.annotation.CriticalRegion; -import org.bytedeco.javacpp.annotation.Function; -import org.bytedeco.javacpp.annotation.Index; -import org.bytedeco.javacpp.annotation.MemberGetter; -import org.bytedeco.javacpp.annotation.MemberSetter; -import org.bytedeco.javacpp.annotation.Name; -import org.bytedeco.javacpp.annotation.Namespace; -import org.bytedeco.javacpp.annotation.AsUtf16; -import org.bytedeco.javacpp.annotation.NoDeallocator; -import org.bytedeco.javacpp.annotation.NoException; -import org.bytedeco.javacpp.annotation.NoOffset; -import org.bytedeco.javacpp.annotation.Opaque; -import org.bytedeco.javacpp.annotation.Platform; -import org.bytedeco.javacpp.annotation.Raw; -import org.bytedeco.javacpp.annotation.ValueGetter; -import org.bytedeco.javacpp.annotation.ValueSetter; -import org.bytedeco.javacpp.annotation.Virtual; +import java.util.*; /** * The Generator is where all the C++ source code that we need gets generated. @@ -107,6 +49,7 @@ * meant to have with them as part of the documentation of the annotations, so * we can refer to them to understand more about how Generator should work: * + * @author Samuel Audet * @see Adapter * @see Allocator * @see ArrayAllocator @@ -133,27 +76,46 @@ * @see Raw * @see ValueGetter * @see ValueSetter - * - * @author Samuel Audet */ public class Generator { public Generator(Logger logger, Properties properties) { this(logger, properties, null); } + public Generator(Logger logger, Properties properties, String encoding) { this.logger = logger; this.properties = properties; this.encoding = encoding; } - static enum BooleanEnum { BOOLEAN; boolean value; } - static enum ByteEnum { BYTE; byte value; } - static enum ShortEnum { SHORT; short value; } - static enum IntEnum { INT; int value; } - static enum LongEnum { LONG; long value; } + static enum BooleanEnum { + BOOLEAN; + boolean value; + } + + static enum ByteEnum { + BYTE; + byte value; + } + + static enum ShortEnum { + SHORT; + short value; + } + + static enum IntEnum { + INT; + int value; + } + + static enum LongEnum { + LONG; + long value; + } + static final String JNI_VERSION = "JNI_VERSION_1_6"; - static final List baseClasses = Arrays.asList(new Class[] { + static final List baseClasses = Arrays.asList(new Class[]{ Loader.class, Loader.Helper.class, Pointer.class, @@ -169,40 +131,45 @@ static enum LongEnum { LONG; long value; } PointerPointer.class, BoolPointer.class, CLongPointer.class, - SizeTPointer.class }); + SizeTPointer.class}); final Logger logger; final Properties properties; final String encoding; PrintWriter out, out2, jniConfigOut, reflectConfigOut; - Map callbacks; + Map callbacks; IndexedSet functions, deallocators, arrayDeallocators, jclasses; - Map> members, virtualFunctions, virtualMembers; - Map annotationCache; + Map> members, virtualFunctions, virtualMembers; + Map annotationCache; boolean mayThrowExceptions, usesAdapters, passesStrings, accessesEnums; public boolean generate(String sourceFilename, String jniConfigFilename, String reflectConfigFilename, String headerFilename, - String loadSuffix, String baseLoadSuffix, String classPath, Class ... classes) throws IOException { + String loadSuffix, String baseLoadSuffix, String classPath, Class... classes) throws IOException { try { // first pass using a null writer to fill up the IndexedSet objects out = new PrintWriter(new Writer() { - @Override public void write(char[] cbuf, int off, int len) { } - @Override public void flush() { } - @Override public void close() { } + @Override + public void write(char[] cbuf, int off, int len) { } + + @Override + public void flush() { } + + @Override + public void close() { } }); - out2 = jniConfigOut = reflectConfigOut= null; - callbacks = new LinkedHashMap(); - functions = new IndexedSet(); - deallocators = new IndexedSet(); - arrayDeallocators = new IndexedSet(); - jclasses = new IndexedSet(); - members = new LinkedHashMap>(); - virtualFunctions = new LinkedHashMap>(); - virtualMembers = new LinkedHashMap>(); - annotationCache = new LinkedHashMap(); - mayThrowExceptions = false; - usesAdapters = false; - passesStrings = false; + out2 = jniConfigOut = reflectConfigOut = null; + callbacks = new LinkedHashMap(); + functions = new IndexedSet(); + deallocators = new IndexedSet(); + arrayDeallocators = new IndexedSet(); + jclasses = new IndexedSet(); + members = new LinkedHashMap>(); + virtualFunctions = new LinkedHashMap>(); + virtualMembers = new LinkedHashMap>(); + annotationCache = new LinkedHashMap(); + mayThrowExceptions = false; + usesAdapters = false; + passesStrings = false; if (baseLoadSuffix == null || baseLoadSuffix.isEmpty()) { for (Class cls : baseClasses) { jclasses.index(cls); @@ -264,7 +231,7 @@ public boolean generate(String sourceFilename, String jniConfigFilename, String } boolean classes(boolean handleExceptions, boolean defineAdapters, boolean convertStrings, boolean declareEnums, - String loadSuffix, String baseLoadSuffix, String classPath, Class ... classes) { + String loadSuffix, String baseLoadSuffix, String classPath, Class... classes) { String version = Generator.class.getPackage().getImplementationVersion(); if (version == null) { version = "unknown"; @@ -420,8 +387,8 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver if (classes != null) { List exclude = clsProperties.get("platform.exclude"); - List[] include = { clsProperties.get("platform.cinclude"), - clsProperties.get("platform.include") }; + List[] include = {clsProperties.get("platform.cinclude"), + clsProperties.get("platform.include")}; for (int i = 0; i < include.length; i++) { if (include[i] != null && include[i].size() > 0) { if (i == 0) { @@ -432,7 +399,7 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver out2.println("#endif"); } } - for (String s : (List)include[i]) { + for (String s : (List) include[i]) { if (exclude.contains(s)) { continue; } @@ -469,7 +436,7 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver int maxMemberSize = 0; while (classIterator.hasNext()) { Class c = classIterator.next(); - out.print(" \"" + c.getName().replace('.','/') + "\""); + out.print(" \"" + c.getName().replace('.', '/') + "\""); if (classIterator.hasNext()) { out.println(","); } @@ -992,7 +959,7 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver out.println(" args[3].j = ptr_to_jlong(deallocator);"); out.println(" if (JavaCPP_haveNonvirtual) {"); out.println(" env->CallNonvirtualVoidMethodA(obj, JavaCPP_getClass(env, " - + jclasses.index(Pointer.class) + "), JavaCPP_initMID, args);"); + + jclasses.index(Pointer.class) + "), JavaCPP_initMID, args);"); out.println(" } else {"); out.println(" env->CallVoidMethodA(obj, JavaCPP_initMID, args);"); out.println(" }"); @@ -1115,30 +1082,20 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver out.println(" char msg[1024];"); out.println("};"); out.println(); + if (handleExceptions) { - out.println("#ifndef GENERIC_EXCEPTION_CLASS"); - out.println("#define GENERIC_EXCEPTION_CLASS std::exception"); - out.println("#endif"); - out.println("#ifndef GENERIC_EXCEPTION_TOSTRING"); - out.println("#define GENERIC_EXCEPTION_TOSTRING what()"); - out.println("#endif"); - out.println("static JavaCPP_noinline jthrowable JavaCPP_handleException(JNIEnv* env, int i) {"); - out.println(" jstring str = NULL;"); - out.println(" try {"); - out.println(" throw;"); - out.println(" } catch (GENERIC_EXCEPTION_CLASS& e) {"); - out.println(" str = JavaCPP_createStringFromBytes(env, e.GENERIC_EXCEPTION_TOSTRING);"); - out.println(" } catch (...) {"); - out.println(" str = JavaCPP_createStringFromBytes(env, \"Unknown exception.\");"); - out.println(" }"); - out.println(" jmethodID mid = JavaCPP_getMethodID(env, i, \"\", \"(Ljava/lang/String;)V\");"); - out.println(" if (mid == NULL) {"); - out.println(" return NULL;"); - out.println(" }"); - out.println(" return (jthrowable)env->NewObject(JavaCPP_getClass(env, i), mid, str);"); - out.println("}"); - out.println(); + try (InputStream inputStream = Generator.class.getResourceAsStream("/org/bytedeco/javacpp/jniTemplates/JNIExceptionHandler.h"); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { + + String line; + while ((line = reader.readLine()) != null) { + out.println(line); + } + } catch (IOException e) { + throw new RuntimeException("Unable to find template 'JNIExceptionHandler'", e); + } } + Class deallocator, nativeDeallocator; try { deallocator = Class.forName(Pointer.class.getName() + "$Deallocator", false, Pointer.class.getClassLoader()); @@ -1151,7 +1108,7 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver out.println(" if (obj != NULL) {"); out.println(" jobject deallocator = env->GetObjectField(obj, JavaCPP_deallocatorFID);"); out.println(" if (deallocator != NULL && env->IsInstanceOf(deallocator, JavaCPP_getClass(env, " - + jclasses.index(nativeDeallocator) + "))) {"); + + jclasses.index(nativeDeallocator) + "))) {"); out.println(" return jlong_to_ptr(env->GetLongField(deallocator, JavaCPP_ownerAddressFID));"); out.println(" }"); out.println(" }"); @@ -1575,7 +1532,7 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver String[] typeName = cppTypeName(c); String[] returnConvention = typeName[0].split("\\("); String[] returnType = {returnConvention[0] + (returnConvention.length > 2 ? "(*" : ""), - returnConvention.length > 2 ? ")(" + returnConvention[2] : ""}; + returnConvention.length > 2 ? ")(" + returnConvention[2] : ""}; if (returnConvention.length > 2) { returnConvention = Arrays.copyOfRange(returnConvention, 2, returnConvention.length); } @@ -1633,7 +1590,7 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver + typeName + "*)p)->obj) " + typeName + "_instances[i].obj = NULL; }"); } out.println("\n JNIEnv *e; bool a = JavaCPP_getEnv(&e); if (e != NULL) e->DeleteWeakGlobalRef((jweak)((" - + typeName + "*)p)->obj); delete (" + typeName + "*)p; JavaCPP_detach(a); }"); + + typeName + "*)p)->obj); delete (" + typeName + "*)p; JavaCPP_detach(a); }"); } else if (virtualFunctions.containsKey(c)) { String[] typeName = cppTypeName(c); String valueTypeName = valueTypeName(typeName); @@ -1690,7 +1647,7 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver } out.print("sizeof(" + valueTypeName + ")"); } else { - out.print("offsetof(" + valueTypeName + ", " + memberName + ")"); + out.print("offsetof(" + valueTypeName + ", " + memberName + ")"); } if (memberIterator.hasNext()) { out.print(", "); @@ -2022,7 +1979,7 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver allClasses.add(LongEnum.class); } - for (PrintWriter o : new PrintWriter[] {jniConfigOut, reflectConfigOut}) { + for (PrintWriter o : new PrintWriter[]{jniConfigOut, reflectConfigOut}) { if (o == null) { continue; } @@ -2238,14 +2195,14 @@ boolean methods(Class cls) { } void parametersBefore(MethodInformation methodInfo) { - String adapterLine = ""; + String adapterLine = ""; AdapterInformation prevAdapterInfo = null; int skipParameters = methodInfo.parameterTypes.length > 0 && methodInfo.parameterTypes[0] == Class.class ? 1 : 0; for (int j = skipParameters; j < methodInfo.parameterTypes.length; j++) { if (!methodInfo.parameterTypes[j].isPrimitive()) { Annotation passBy = by(methodInfo, j); String cast = cast(methodInfo, j); - String[] typeName = methodInfo.parameterRaw[j] ? new String[] { "" } + String[] typeName = methodInfo.parameterRaw[j] ? new String[]{""} : cppTypeName(methodInfo, j); AdapterInformation adapterInfo = methodInfo.parameterRaw[j] ? null : adapterInformation(false, methodInfo, j); @@ -2292,8 +2249,8 @@ void parametersBefore(MethodInformation methodInfo) { ")jlong_to_ptr(env->GetLongField(arg" + j + ", JavaCPP_addressFID));"); if ((j == 0 && FunctionPointer.class.isAssignableFrom(methodInfo.cls) && methodInfo.cls.isAnnotationPresent(Namespace.class)) - || (passBy instanceof ByVal && ((ByVal)passBy).nullValue().length() == 0) - || (passBy instanceof ByRef && ((ByRef)passBy).nullValue().length() == 0)) { + || (passBy instanceof ByVal && ((ByVal) passBy).nullValue().length() == 0) + || (passBy instanceof ByRef && ((ByRef) passBy).nullValue().length() == 0)) { // in the case of member ptr, ptr0 is our object pointer, which cannot be NULL out.println(" if (ptr" + j + " == NULL) {"); out.println(" env->ThrowNew(JavaCPP_getClass(env, " + @@ -2309,7 +2266,7 @@ void parametersBefore(MethodInformation methodInfo) { if (!methodInfo.parameterTypes[j].isAnnotationPresent(Opaque.class)) { out.println(" jlong position" + j + " = arg" + j + " == NULL ? 0 : env->GetLongField(arg" + j + ", JavaCPP_positionFID);"); - out.println(" ptr" + j + " += position" + j + ";"); + out.println(" ptr" + j + " += position" + j + ";"); if (adapterInfo != null || prevAdapterInfo != null) { out.println(" size" + j + " -= position" + j + ";"); } @@ -2369,7 +2326,7 @@ void parametersBefore(MethodInformation methodInfo) { } out.println(" jlong position" + j + " = arg" + j + " == NULL ? 0 : env->GetIntField(arg" + j + ", JavaCPP_bufferPositionFID);"); - out.println(" ptr" + j + " += position" + j + ";"); + out.println(" ptr" + j + " += position" + j + ";"); if (adapterInfo != null || prevAdapterInfo != null) { out.println(" size" + j + " -= position" + j + ";"); } @@ -2423,7 +2380,7 @@ String returnBefore(MethodInformation methodInfo) { } } else { String cast = cast(methodInfo.returnType, methodInfo.annotations); - String[] typeName = methodInfo.returnRaw ? new String[] { "" } + String[] typeName = methodInfo.returnRaw ? new String[]{""} : cppCastTypeName(methodInfo.returnType, methodInfo.annotations); Annotation returnBy = by(methodInfo.annotations); if (FunctionPointer.class.isAssignableFrom(methodInfo.cls) @@ -2458,7 +2415,7 @@ String returnBefore(MethodInformation methodInfo) { } else if (Pointer.class.isAssignableFrom(methodInfo.returnType) || Buffer.class.isAssignableFrom(methodInfo.returnType) || (methodInfo.returnType.isArray() && - methodInfo.returnType.getComponentType().isPrimitive())) { + methodInfo.returnType.getComponentType().isPrimitive())) { if (FunctionPointer.class.isAssignableFrom(methodInfo.returnType)) { functions.index(methodInfo.returnType); returnPrefix = "if (rptr != NULL) rptr->ptr = "; @@ -2470,14 +2427,14 @@ String returnBefore(MethodInformation methodInfo) { typeName[1] = ""; valueTypeName = valueTypeName(typeName); } - if (returnBy instanceof ByVal || (returnBy instanceof ByRef && ((ByRef)returnBy).value())) { + if (returnBy instanceof ByVal || (returnBy instanceof ByRef && ((ByRef) returnBy).value())) { returnPrefix += (noException(methodInfo.returnType, methodInfo.method) ? - "new (std::nothrow) " : "new ") + valueTypeName + typeName[1] + "("; + "new (std::nothrow) " : "new ") + valueTypeName + typeName[1] + "("; } else if (returnBy instanceof ByRef) { returnPrefix += "&"; } else if (returnBy instanceof ByPtrPtr) { if (cast.length() > 0) { - typeName[0] = typeName[0].substring(0, typeName[0].length()-1); + typeName[0] = typeName[0].substring(0, typeName[0].length() - 1); } returnPrefix = "rptr = NULL; " + typeName[0] + "* rptrptr" + typeName[1] + " = " + cast; } // else ByPtr || ByPtrRef @@ -2558,10 +2515,10 @@ void call(MethodInformation methodInfo, String returnPrefix, boolean secondCall) out.println(indent + "}"); return; // nothing else should be appended here for deallocator } else if (!FunctionPointer.class.isAssignableFrom(methodInfo.cls) && - (methodInfo.valueGetter || methodInfo.valueSetter || - methodInfo.memberGetter || methodInfo.memberSetter)) { + (methodInfo.valueGetter || methodInfo.valueSetter || + methodInfo.memberGetter || methodInfo.memberSetter)) { boolean wantsPointer = false; - int k = methodInfo.parameterTypes.length-1; + int k = methodInfo.parameterTypes.length - 1; if ((methodInfo.valueSetter || methodInfo.memberSetter) && !(by(methodInfo, k) instanceof ByRef) && adapterInformation(false, methodInfo, k) == null && @@ -2578,7 +2535,7 @@ void call(MethodInformation methodInfo, String returnPrefix, boolean secondCall) } else if (k >= 1 && methodInfo.parameterTypes[0].isArray() && methodInfo.parameterTypes[0].getComponentType().isPrimitive() && (methodInfo.parameterTypes[1] == int.class || - methodInfo.parameterTypes[1] == long.class)) { + methodInfo.parameterTypes[1] == long.class)) { // special considerations for primitive arrays out.print(indent + "memcpy("); wantsPointer = true; @@ -2653,7 +2610,7 @@ void call(MethodInformation methodInfo, String returnPrefix, boolean secondCall) // If method is an array allocator, the function must return a pointer to an array } else { out.print((noException(methodInfo.cls, methodInfo.method) ? - "new (std::nothrow) " : "new ") + valueTypeName + typeName[1]); + "new (std::nothrow) " : "new ") + valueTypeName + typeName[1]); if (methodInfo.arrayAllocator) { prefix = "["; suffix = "]"; @@ -2771,9 +2728,9 @@ void call(MethodInformation methodInfo, String returnPrefix, boolean secondCall) } } else if (passBy instanceof ByVal || (passBy instanceof ByRef && methodInfo.parameterTypes[j] != String.class)) { - boolean rvalue = passBy instanceof ByRef ? ((ByRef)passBy).value() : false; - String nullValue = passBy instanceof ByVal ? ((ByVal)passBy).nullValue() - : passBy instanceof ByRef ? ((ByRef)passBy).nullValue() : ""; + boolean rvalue = passBy instanceof ByRef ? ((ByRef) passBy).value() : false; + String nullValue = passBy instanceof ByVal ? ((ByVal) passBy).nullValue() + : passBy instanceof ByRef ? ((ByRef) passBy).nullValue() : ""; if (rvalue) { out.print("std::move("); } @@ -2810,7 +2767,7 @@ void call(MethodInformation methodInfo, String returnPrefix, boolean secondCall) void returnAfter(MethodInformation methodInfo) { String indent = methodInfo.throwsException != null ? " " : " "; String[] typeName = methodInfo.allocator || methodInfo.arrayAllocator - ? cppTypeName(methodInfo.cls) : methodInfo.returnRaw ? new String[] { "" } + ? cppTypeName(methodInfo.cls) : methodInfo.returnRaw ? new String[]{""} : cppCastTypeName(methodInfo.returnType, methodInfo.annotations); Annotation returnBy = by(methodInfo.annotations); String valueTypeName = valueTypeName(typeName); @@ -2827,10 +2784,10 @@ void returnAfter(MethodInformation methodInfo) { } if ((Pointer.class.isAssignableFrom(methodInfo.returnType) || (methodInfo.returnType.isArray() && - methodInfo.returnType.getComponentType().isPrimitive()) || + methodInfo.returnType.getComponentType().isPrimitive()) || Buffer.class.isAssignableFrom(methodInfo.returnType)) || methodInfo.returnType == String.class) { - if ((returnBy instanceof ByVal || (returnBy instanceof ByRef && ((ByRef)returnBy).value())) && adapterInfo == null) { + if ((returnBy instanceof ByVal || (returnBy instanceof ByRef && ((ByRef) returnBy).value())) && adapterInfo == null) { suffix = ")" + suffix; } else if (returnBy instanceof ByPtrPtr) { out.println(suffix); @@ -2942,18 +2899,18 @@ void returnAfter(MethodInformation methodInfo) { if (Arrays.equals(methodInfo.parameterAnnotations[i], methodInfo.annotations) && methodInfo.parameterTypes[i] == methodInfo.returnType && !(returnBy instanceof ByPtrPtr) && !(returnBy instanceof ByPtrRef)) { - out.println( "if (rptr == " + cast + "ptr" + i + ") {"); + out.println("if (rptr == " + cast + "ptr" + i + ") {"); out.println(indent + " rarg = arg" + i + ";"); out.print(indent + "} else "); } } } else if (!Modifier.isStatic(methodInfo.modifiers) && methodInfo.cls == methodInfo.returnType) { - out.println( "if (rptr == ptr) {"); + out.println("if (rptr == ptr) {"); out.println(indent + " rarg = obj;"); out.print(indent + "} else "); } } - out.println( "if (rptr != NULL) {"); + out.println("if (rptr != NULL) {"); out.println(indent + " rarg = JavaCPP_createPointer(env, " + jclasses.index(methodInfo.returnType) + (methodInfo.parameterTypes.length > 0 && methodInfo.parameterTypes[0] == Class.class ? ", arg0);" : ");")); out.println(indent + " if (rarg != NULL) {"); @@ -3011,8 +2968,8 @@ void returnAfter(MethodInformation methodInfo) { void parametersAfter(MethodInformation methodInfo) { if (methodInfo.throwsException != null) { mayThrowExceptions = true; - out.println(" } catch (...) {"); - out.println(" exc = JavaCPP_handleException(env, " + jclasses.index(methodInfo.throwsException) + ");"); + out.println(" } catch (std::exception& e) {"); + out.println(" exc = JavaCPP_handleException(env, e);"); out.println(" }"); out.println(); } @@ -3028,7 +2985,7 @@ void parametersAfter(MethodInformation methodInfo) { if ("void*".equals(typeName[0]) && !methodInfo.parameterTypes[j].isAnnotationPresent(Opaque.class)) { typeName[0] = "char*"; } - + // If const array, then use JNI_ABORT to avoid copying unmodified data back to JVM final String releaseArrayFlag; if (cast.contains(" const *") || cast.startsWith("(const ")) { @@ -3040,14 +2997,14 @@ void parametersAfter(MethodInformation methodInfo) { if (Pointer.class.isAssignableFrom(methodInfo.parameterTypes[j])) { if (adapterInfo != null) { for (int k = 0; k < adapterInfo.argc; k++) { - out.println(" " + typeName[0] + " rptr" + (j+k) + typeName[1] + " = " + cast + "adapter" + j + ";"); - out.println(" jlong rsize" + (j+k) + " = (jlong)adapter" + j + ".size" + (k > 0 ? (k+1) + ";" : ";")); - out.println(" void* rowner" + (j+k) + " = adapter" + j + ".owner" + (k > 0 ? (k+1) + ";" : ";")); - out.println(" if (rptr" + (j+k) + " != " + cast + "ptr" + (j+k) + ") {"); - out.println(" JavaCPP_initPointer(env, arg" + j + ", rptr" + (j+k) + ", rsize" + (j+k) + ", rowner" + (j+k) + ", &" + adapterInfo.name + "::deallocate);"); + out.println(" " + typeName[0] + " rptr" + (j + k) + typeName[1] + " = " + cast + "adapter" + j + ";"); + out.println(" jlong rsize" + (j + k) + " = (jlong)adapter" + j + ".size" + (k > 0 ? (k + 1) + ";" : ";")); + out.println(" void* rowner" + (j + k) + " = adapter" + j + ".owner" + (k > 0 ? (k + 1) + ";" : ";")); + out.println(" if (rptr" + (j + k) + " != " + cast + "ptr" + (j + k) + ") {"); + out.println(" JavaCPP_initPointer(env, arg" + j + ", rptr" + (j + k) + ", rsize" + (j + k) + ", rowner" + (j + k) + ", &" + adapterInfo.name + "::deallocate);"); out.println(" } else {"); - out.println(" env->SetLongField(arg" + j + ", JavaCPP_limitFID, rsize" + (j+k) - + (!methodInfo.parameterTypes[j].isAnnotationPresent(Opaque.class) ? " + position" + (j+k) : "") + ");"); + out.println(" env->SetLongField(arg" + j + ", JavaCPP_limitFID, rsize" + (j + k) + + (!methodInfo.parameterTypes[j].isAnnotationPresent(Opaque.class) ? " + position" + (j + k) : "") + ");"); out.println(" }"); } } else if ((passBy instanceof ByPtrPtr || passBy instanceof ByPtrRef) && @@ -3063,10 +3020,10 @@ void parametersAfter(MethodInformation methodInfo) { } else if (methodInfo.parameterTypes[j].isArray() && methodInfo.parameterTypes[j].getComponentType().isPrimitive()) { for (int k = 0; adapterInfo != null && k < adapterInfo.argc; k++) { - out.println(" " + typeName[0] + " rptr" + (j+k) + typeName[1] + " = " + cast + "adapter" + j + ";"); - out.println(" void* rowner" + (j+k) + " = adapter" + j + ".owner" + (k > 0 ? (k+1) + ";" : ";")); - out.println(" if (rptr" + (j+k) + " != " + cast + "ptr" + (j+k) + ") {"); - out.println(" " + adapterInfo.name + "::deallocate(rowner" + (j+k) + ");"); + out.println(" " + typeName[0] + " rptr" + (j + k) + typeName[1] + " = " + cast + "adapter" + j + ";"); + out.println(" void* rowner" + (j + k) + " = adapter" + j + ".owner" + (k > 0 ? (k + 1) + ";" : ";")); + out.println(" if (rptr" + (j + k) + " != " + cast + "ptr" + (j + k) + ") {"); + out.println(" " + adapterInfo.name + "::deallocate(rowner" + (j + k) + ");"); out.println(" }"); } out.print(" if (arg" + j + " != NULL) "); @@ -3081,10 +3038,10 @@ void parametersAfter(MethodInformation methodInfo) { } else if (Buffer.class.isAssignableFrom(methodInfo.parameterTypes[j]) && methodInfo.parameterTypes[j] != Buffer.class) { for (int k = 0; adapterInfo != null && k < adapterInfo.argc; k++) { - out.println(" " + typeName[0] + " rptr" + (j+k) + typeName[1] + " = " + cast + "adapter" + j + ";"); - out.println(" void* rowner" + (j+k) + " = adapter" + j + ".owner" + (k > 0 ? (k+1) + ";" : ";")); - out.println(" if (rptr" + (j+k) + " != " + cast + "ptr" + (j+k) + ") {"); - out.println(" " + adapterInfo.name + "::deallocate(rowner" + (j+k) + ");"); + out.println(" " + typeName[0] + " rptr" + (j + k) + typeName[1] + " = " + cast + "adapter" + j + ";"); + out.println(" void* rowner" + (j + k) + " = adapter" + j + ".owner" + (k > 0 ? (k + 1) + ";" : ";")); + out.println(" if (rptr" + (j + k) + " != " + cast + "ptr" + (j + k) + ") {"); + out.println(" " + adapterInfo.name + "::deallocate(rowner" + (j + k) + ");"); out.println(" }"); } out.print(" if (arr" + j + " != NULL) "); @@ -3092,11 +3049,11 @@ void parametersAfter(MethodInformation methodInfo) { parameterSimpleName = parameterSimpleName.substring(0, parameterSimpleName.length() - 6); String parameterSimpleNameLowerCase = Character.toLowerCase(parameterSimpleName.charAt(0)) + parameterSimpleName.substring(1); if (methodInfo.criticalRegion) { - out.println("env->ReleasePrimitiveArrayCritical(arr" + j + ", ptr" + j + " - position" + j +", " + releaseArrayFlag + ");"); + out.println("env->ReleasePrimitiveArrayCritical(arr" + j + ", ptr" + j + " - position" + j + ", " + releaseArrayFlag + ");"); } else { out.println("env->Release" + parameterSimpleName + "ArrayElements(arr" + j + ", " + - "(j" + parameterSimpleNameLowerCase + "*)(ptr" + j + " - position" + j +"), " + - releaseArrayFlag + ");"); + "(j" + parameterSimpleNameLowerCase + "*)(ptr" + j + " - position" + j + "), " + + releaseArrayFlag + ");"); } } } @@ -3112,7 +3069,7 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo String[] callbackTypeName = cppFunctionTypeName(callbackMethod); String[] returnConvention = callbackTypeName[0].split("\\("); String[] returnType = {returnConvention[0] + (returnConvention.length > 2 ? "(*" : ""), - returnConvention.length > 2 ? ")(" + returnConvention[2] : ""}; + returnConvention.length > 2 ? ")(" + returnConvention[2] : ""}; if (returnConvention.length > 2) { returnConvention = Arrays.copyOfRange(returnConvention, 2, returnConvention.length); } @@ -3144,7 +3101,7 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo String nonconstParamDeclaration = parameterDeclaration.endsWith(" const") ? parameterDeclaration.substring(0, parameterDeclaration.length() - 6) : parameterDeclaration; - String[] typeName = methodInfo.returnRaw ? new String[] { "" } + String[] typeName = methodInfo.returnRaw ? new String[]{""} : cppTypeName(methodInfo.cls); String valueTypeName = valueTypeName(typeName); String subType = "JavaCPP_" + mangle(valueTypeName); @@ -3175,8 +3132,8 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo member += usingLine + "\n "; } member += "virtual " + returnType[0] + (returnConvention.length > 1 ? returnConvention[1] : "") - + methodInfo.memberName[0] + parameterDeclaration + returnType[1] + " JavaCPP_override;\n " - + returnType[0] + "super_" + methodInfo.name + nonconstParamDeclaration + returnType[1] + " { "; + + methodInfo.memberName[0] + parameterDeclaration + returnType[1] + " JavaCPP_override;\n " + + returnType[0] + "super_" + methodInfo.name + nonconstParamDeclaration + returnType[1] + " { "; if (methodInfo.method.getAnnotation(Virtual.class).value()) { member += "throw JavaCPP_exception(\"Cannot call pure virtual function " + valueTypeName + "::" + methodInfo.memberName[0] + "().\"); }"; } else { @@ -3293,7 +3250,7 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo if (Pointer.class.isAssignableFrom(callbackParameterTypes[j]) || Buffer.class.isAssignableFrom(callbackParameterTypes[j]) || (callbackParameterTypes[j].isArray() && - callbackParameterTypes[j].getComponentType().isPrimitive())) { + callbackParameterTypes[j].getComponentType().isPrimitive())) { String cast = "(" + typeName[0] + typeName[1] + ")"; if (FunctionPointer.class.isAssignableFrom(callbackParameterTypes[j])) { functions.index(callbackParameterTypes[j]); @@ -3315,8 +3272,8 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo out.println(" ptr" + j + " = adapter" + j + ";"); } else if (passBy instanceof ByVal && callbackParameterTypes[j] != Pointer.class) { out.println(" ptr" + j + (noException(callbackParameterTypes[j], callbackMethod) ? - " = new (std::nothrow) " : " = new ") + valueTypeName + typeName[1] + - "(*" + cast + "&arg" + j + ");"); + " = new (std::nothrow) " : " = new ") + valueTypeName + typeName[1] + + "(*" + cast + "&arg" + j + ");"); } else if (passBy instanceof ByVal || passBy instanceof ByRef) { out.println(" ptr" + j + " = " + cast + "&arg" + j + ";"); } else if (passBy instanceof ByPtrPtr) { @@ -3491,7 +3448,7 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo out.println(" *arg" + j + " = *" + cast + "&rptr" + j + ";"); out.println(" }"); } else if (passBy instanceof ByPtrRef) { - out.println(" arg" + j + " = " + cast + "rptr" + j + ";"); + out.println(" arg" + j + " = " + cast + "rptr" + j + ";"); } } } @@ -3652,7 +3609,7 @@ static Method[] functionMethods(Class cls, Method[] methods, boolean[] callba if (callbackAllocators != null && methodName.startsWith("allocate") && Modifier.isNative(modifiers) && returnType == void.class && (parameterTypes.length == 0 || (parameterTypes.length == 1 && - (parameterTypes[0] == int.class || parameterTypes[0] == long.class)))) { + (parameterTypes[0] == int.class || parameterTypes[0] == long.class)))) { // found a callback allocator method callbackAllocators[i] = true; } else if (methodName.startsWith("call") || methodName.startsWith("apply")) { @@ -3670,18 +3627,18 @@ static Method[] functionMethods(Class cls, Method[] methods, boolean[] callba MethodInformation methodInformation(Method method) { MethodInformation info = new MethodInformation(); - info.cls = method.getDeclaringClass(); - info.method = method; + info.cls = method.getDeclaringClass(); + info.method = method; info.annotations = method.getAnnotations(); - info.modifiers = method.getModifiers(); - info.returnType = method.getReturnType(); + info.modifiers = method.getModifiers(); + info.returnType = method.getReturnType(); info.name = method.getName(); Name name = method.getAnnotation(Name.class); - info.memberName = name != null ? name.value() : new String[] { info.name }; + info.memberName = name != null ? name.value() : new String[]{info.name}; Index index = method.getAnnotation(Index.class); info.allocatorMax = allocatorMax(info.cls, info.method); - info.dim = index != null ? index.value() : 0; - info.parameterTypes = method.getParameterTypes(); + info.dim = index != null ? index.value() : 0; + info.parameterTypes = method.getParameterTypes(); info.parameterAnnotations = method.getParameterAnnotations(); info.criticalRegion = criticalRegion(info.cls, info.method); info.returnRaw = method.isAnnotationPresent(Raw.class); @@ -3691,12 +3648,12 @@ MethodInformation methodInformation(Method method) { for (int j = 0; j < info.parameterAnnotations[i].length; j++) { if (info.parameterAnnotations[i][j] instanceof Raw) { info.parameterRaw[i] = true; - info.withEnv |= ((Raw)info.parameterAnnotations[i][j]).withEnv(); + info.withEnv |= ((Raw) info.parameterAnnotations[i][j]).withEnv(); } } } - boolean canBeGetter = info.returnType != void.class || (info.parameterTypes.length > 0 && + boolean canBeGetter = info.returnType != void.class || (info.parameterTypes.length > 0 && info.parameterTypes[0].isArray() && info.parameterTypes[0].getComponentType().isPrimitive()); boolean canBeSetter = (info.returnType == void.class || info.returnType == info.cls) && info.parameterTypes.length > 0; @@ -3714,11 +3671,11 @@ MethodInformation methodInformation(Method method) { MethodInformation info2 = annotationCache.get(method2); if (info2 == null) { annotationCache.put(method2, info2 = new MethodInformation()); - info2.modifiers = method2.getModifiers(); - info2.returnType = method2.getReturnType(); - info2.name = method2.getName(); - info2.parameterTypes = method2.getParameterTypes(); - info2.annotations = method2.getAnnotations(); + info2.modifiers = method2.getModifiers(); + info2.returnType = method2.getReturnType(); + info2.name = method2.getName(); + info2.parameterTypes = method2.getParameterTypes(); + info2.annotations = method2.getAnnotations(); info2.parameterAnnotations = method2.getParameterAnnotations(); } int skipParameters = info.parameterTypes.length > 0 && info.parameterTypes[0] == Class.class ? 1 : 0; @@ -3761,20 +3718,20 @@ MethodInformation methodInformation(Method method) { if (canBeGetter && info2.parameterTypes.length - (parameterAsReturn ? 0 : 1) == info.parameterTypes.length - skipParameters && (parameterAsReturn ? info.parameterTypes[info.parameterTypes.length - 1] : info.returnType) == - info2.parameterTypes[info2.parameterTypes.length - 1] && (info2.returnType == void.class || info2.returnType == info.cls) + info2.parameterTypes[info2.parameterTypes.length - 1] && (info2.returnType == void.class || info2.returnType == info.cls) && (info2.parameterAnnotations[info2.parameterAnnotations.length - 1].length == 0 - || (Arrays.equals(info2.parameterAnnotations[info2.parameterAnnotations.length - 1], info.annotations)))) { + || (Arrays.equals(info2.parameterAnnotations[info2.parameterAnnotations.length - 1], info.annotations)))) { pairedMethod = method2; - valueGetter = canBeValueGetter; + valueGetter = canBeValueGetter; memberGetter = canBeMemberGetter; noReturnGetter = parameterAsReturn; } else if (canBeSetter && info.parameterTypes.length - (parameterAsReturn2 ? 0 : 1) == info2.parameterTypes.length - skipParameters2 && (parameterAsReturn2 ? info2.parameterTypes[info2.parameterTypes.length - 1] : info2.returnType) == - info.parameterTypes[info.parameterTypes.length - 1] && (info.returnType == void.class || info.returnType == info.cls) + info.parameterTypes[info.parameterTypes.length - 1] && (info.returnType == void.class || info.returnType == info.cls) && (info.parameterAnnotations[info.parameterAnnotations.length - 1].length == 0 - || (Arrays.equals(info.parameterAnnotations[info.parameterAnnotations.length - 1], info2.annotations)))) { + || (Arrays.equals(info.parameterAnnotations[info.parameterAnnotations.length - 1], info2.annotations)))) { pairedMethod = method2; - valueSetter = canBeValueSetter; + valueSetter = canBeValueSetter; memberSetter = canBeMemberSetter; } @@ -3848,18 +3805,18 @@ MethodInformation methodInformation(Method method) { } info.noOffset = info.cls.isAnnotationPresent(NoOffset.class) || - method.isAnnotationPresent(NoOffset.class) || - method.isAnnotationPresent(Index.class); + method.isAnnotationPresent(NoOffset.class) || + method.isAnnotationPresent(Index.class); if (!info.noOffset && info.pairedMethod != null) { info.noOffset = info.pairedMethod.isAnnotationPresent(NoOffset.class) || - info.pairedMethod.isAnnotationPresent(Index.class); + info.pairedMethod.isAnnotationPresent(Index.class); } if (info.parameterTypes.length == 0 || !info.parameterTypes[0].isArray()) { if (info.valueGetter || info.memberGetter) { info.dim = info.parameterTypes.length; } else if (info.memberSetter || info.valueSetter) { - info.dim = info.parameterTypes.length-1; + info.dim = info.parameterTypes.length - 1; } if ((info.valueGetter || info.valueSetter) && FunctionPointer.class.isAssignableFrom(info.cls) @@ -3876,7 +3833,7 @@ MethodInformation methodInformation(Method method) { (index != null && index.function().length() > 0) || (index2 != null && index2.function().length() > 0) || !info.deallocator && !info.valueGetter && !info.valueSetter && - !info.memberGetter && !info.memberSetter && !info.bufferGetter) { + !info.memberGetter && !info.memberSetter && !info.bufferGetter) { Class[] exceptions = method.getExceptionTypes(); info.throwsException = exceptions.length > 0 ? exceptions[0] : RuntimeException.class; } @@ -3887,7 +3844,7 @@ MethodInformation methodInformation(Method method) { static int allocatorMax(Class cls, Method method) { try { Allocator a = allocator(cls, method); - return a != null ? a.max() : (int)Allocator.class.getDeclaredMethod("max").getDefaultValue(); + return a != null ? a.max() : (int) Allocator.class.getDeclaredMethod("max").getDefaultValue(); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } @@ -3973,7 +3930,7 @@ AdapterInformation adapterInformation(boolean out, MethodInformation methodInfo, } String typeName = cast(methodInfo, j); if (typeName != null && typeName.startsWith("(") && typeName.endsWith(")")) { - typeName = typeName.substring(1, typeName.length()-1); + typeName = typeName.substring(1, typeName.length() - 1); } if (typeName == null || typeName.length() == 0) { typeName = cppCastTypeName(methodInfo.parameterTypes[j], methodInfo.parameterAnnotations[j])[0]; @@ -3987,21 +3944,21 @@ AdapterInformation adapterInformation(boolean out, MethodInformation methodInfo, return adapter; } - AdapterInformation adapterInformation(boolean out, String valueTypeName, Annotation ... annotations) { + AdapterInformation adapterInformation(boolean out, String valueTypeName, Annotation... annotations) { AdapterInformation adapterInfo = null; boolean constant = false; String cast = "", cast2 = ""; for (Annotation a : annotations) { // allow overriding template type for const, etc if (a instanceof Cast) { - Cast c = ((Cast)a); + Cast c = ((Cast) a); if (c.value().length > 0 && c.value()[0].length() > 0) { valueTypeName = constValueTypeName(c.value()[0]); } } } for (Annotation a : annotations) { - Adapter adapter = a instanceof Adapter ? (Adapter)a : a.annotationType().getAnnotation(Adapter.class); + Adapter adapter = a instanceof Adapter ? (Adapter) a : a.annotationType().getAnnotation(Adapter.class); if (adapter != null) { adapterInfo = new AdapterInformation(); adapterInfo.name = adapter.value(); @@ -4022,7 +3979,7 @@ AdapterInformation adapterInformation(boolean out, String valueTypeName, Annotat // this adapter does not support a template type valueTypeName = null; } - Cast c = (Cast)cls.getAnnotation(Cast.class); + Cast c = (Cast) cls.getAnnotation(Cast.class); if (c != null && cast.length() == 0) { cast = c.value()[0]; if (valueTypeName != null) { @@ -4035,7 +3992,7 @@ AdapterInformation adapterInformation(boolean out, String valueTypeName, Annotat cast2 = c.value()[2]; } } - } catch (Exception ex) { + } catch (Exception ex) { logger.warn("Could not invoke the value() method on annotation \"" + a + "\": " + ex); } if (valueTypeName != null && valueTypeName.length() > 0) { @@ -4045,7 +4002,7 @@ AdapterInformation adapterInformation(boolean out, String valueTypeName, Annotat } else if (a instanceof Const) { constant = true; } else if (a instanceof Cast) { - Cast c = ((Cast)a); + Cast c = ((Cast) a); if (c.value().length > 1) { cast = c.value()[1]; } @@ -4064,17 +4021,17 @@ AdapterInformation adapterInformation(boolean out, String valueTypeName, Annotat String cast(MethodInformation methodInfo, int j) { String cast = cast(methodInfo.parameterTypes[j], methodInfo.parameterAnnotations[j]); - if ((cast == null || cast.length() == 0) && j == methodInfo.parameterTypes.length-1 && + if ((cast == null || cast.length() == 0) && j == methodInfo.parameterTypes.length - 1 && (methodInfo.valueSetter || methodInfo.memberSetter) && methodInfo.pairedMethod != null) { cast = cast(methodInfo.pairedMethod.getReturnType(), methodInfo.pairedMethod.getAnnotations()); } return cast; } - String cast(Class type, Annotation ... annotations) { + String cast(Class type, Annotation... annotations) { String[] typeName = null; for (Annotation a : annotations) { - if ((a instanceof Cast && ((Cast)a).value()[0].length() > 0) || a instanceof Const) { + if ((a instanceof Cast && ((Cast) a).value()[0].length() > 0) || a instanceof Const) { typeName = cppCastTypeName(type, annotations); break; } @@ -4092,7 +4049,7 @@ Annotation by(MethodInformation methodInfo, int j) { return passBy; } - Annotation by(Annotation ... annotations) { + Annotation by(Annotation... annotations) { Annotation byAnnotation = null; for (Annotation a : annotations) { if (a instanceof ByPtr || a instanceof ByPtrPtr || a instanceof ByPtrRef || @@ -4108,7 +4065,7 @@ Annotation by(Annotation ... annotations) { return byAnnotation; } - Annotation behavior(Annotation ... annotations) { + Annotation behavior(Annotation... annotations) { Annotation behaviorAnnotation = null; for (Annotation a : annotations) { if (a instanceof Function || a instanceof Allocator || a instanceof ArrayAllocator || @@ -4162,29 +4119,29 @@ static boolean asUtf16(Annotation[] annotations) { static String createString(String ptr, String adapter, boolean asUtf16) { return (asUtf16 ? "JavaCPP_createStringFromUTF16(env, " - : "JavaCPP_createStringFromBytes(env, ") + : "JavaCPP_createStringFromBytes(env, ") + ptr + (adapter != null ? ", " + adapter + ".size);" : ");"); } static String getStringData(String str, boolean asUtf16) { return (asUtf16 ? "JavaCPP_getStringUTF16(env, " - : "JavaCPP_getStringBytes(env, ") + str + ");"; + : "JavaCPP_getStringBytes(env, ") + str + ");"; } static String releaseStringData(String str, String ptr, boolean asUtf16) { return (asUtf16 ? "JavaCPP_releaseStringUTF16(env, " - : "JavaCPP_releaseStringBytes(env, " + str + ", ") + ptr + ");"; + : "JavaCPP_releaseStringBytes(env, " + str + ", ") + ptr + ");"; } - static String constValueTypeName(String ... typeName) { + static String constValueTypeName(String... typeName) { String type = typeName[0]; if (type.endsWith("*") || type.endsWith("&")) { - type = type.substring(0, type.length()-1); + type = type.substring(0, type.length() - 1); } return type; } - static String valueTypeName(String ... typeName) { + static String valueTypeName(String... typeName) { String type = typeName[0]; if (type.startsWith("const ")) { type = type.substring(6); @@ -4239,14 +4196,14 @@ static boolean noexceptFunction(Class classType, Method functionMethod) { return false; } - String[] cppAnnotationTypeName(Class type, Annotation ... annotations) { + String[] cppAnnotationTypeName(Class type, Annotation... annotations) { String[] typeName = cppCastTypeName(type, annotations); String prefix = typeName[0]; String suffix = typeName[1]; boolean casted = false; for (Annotation a : annotations) { - if ((a instanceof Cast && ((Cast)a).value()[0].length() > 0) || a instanceof Const) { + if ((a instanceof Cast && ((Cast) a).value()[0].length() > 0) || a instanceof Const) { casted = true; break; } @@ -4270,13 +4227,13 @@ String[] cppAnnotationTypeName(Class type, Annotation ... annotations) { return typeName; } - String[] cppCastTypeName(Class type, Annotation ... annotations) { + String[] cppCastTypeName(Class type, Annotation... annotations) { String[] typeName = null; boolean warning = false, adapter = false; for (Annotation a : annotations) { if (a instanceof Cast) { warning = typeName != null; - String prefix = ((Cast)a).value()[0], suffix = ""; + String prefix = ((Cast) a).value()[0], suffix = ""; int templateCount = 0; for (int i = 0; i < prefix.length(); i++) { int c = prefix.charAt(i); @@ -4290,9 +4247,9 @@ String[] cppCastTypeName(Class type, Annotation ... annotations) { break; } } - typeName = prefix.length() > 0 ? new String[] { prefix, suffix } : null; + typeName = prefix.length() > 0 ? new String[]{prefix, suffix} : null; } else if (a instanceof Const) { - boolean[] b = ((Const)a).value(); + boolean[] b = ((Const) a).value(); if ((b.length == 1 && !b[0]) || (b.length > 1 && !b[0] && !b[1])) { // not interested in const members continue; @@ -4399,7 +4356,7 @@ String[] cppTypeName(Class type, Annotation[] annotations) { " does not map to any C++ type. Compilation will most likely fail."); } } - return new String[] { prefix, suffix }; + return new String[]{prefix, suffix}; } String[] cppFunctionTypeName(Method... functionMethods) { @@ -4473,7 +4430,7 @@ String[] cppFunctionTypeName(Method... functionMethods) { if (noexceptFunction(type, functionMethod)) { suffix += " noexcept"; } - return new String[] { prefix, suffix }; + return new String[]{prefix, suffix}; } static String cppScopeName(MethodInformation methodInfo) { @@ -4515,7 +4472,7 @@ static String cppScopeName(Class type) { if (i < 0) { i = s.lastIndexOf("."); } - s = s.substring(i+1); + s = s.substring(i + 1); } else { s = name.value()[0]; } @@ -4584,8 +4541,8 @@ static String jniTypeName(Class type) { } } - static String signature(Class ... types) { - StringBuilder signature = new StringBuilder(2*types.length); + static String signature(Class... types) { + StringBuilder signature = new StringBuilder(2 * types.length); for (Class type : types) { if (type == byte.class) { signature.append("B"); @@ -4615,7 +4572,7 @@ static String signature(Class ... types) { } static String mangle(String name) { - StringBuilder mangledName = new StringBuilder(2*name.length()); + StringBuilder mangledName = new StringBuilder(2 * name.length()); for (int i = 0; i < name.length(); i++) { char c = name.charAt(i); if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) { @@ -4632,10 +4589,14 @@ static String mangle(String name) { String code = Integer.toHexString(c); mangledName.append("_0"); switch (code.length()) { - case 1: mangledName.append("0"); - case 2: mangledName.append("0"); - case 3: mangledName.append("0"); - default: mangledName.append(code); + case 1: + mangledName.append("0"); + case 2: + mangledName.append("0"); + case 3: + mangledName.append("0"); + default: + mangledName.append(code); } } } diff --git a/src/main/resources/META-INF/MANIFEST.MF b/src/main/resources/META-INF/MANIFEST.MF new file mode 100644 index 000000000..a7b55ef5b --- /dev/null +++ b/src/main/resources/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: org.bytedeco.javacpp.tools.Builder + diff --git a/src/main/resources/org/bytedeco/javacpp/jniTemplates/JNIExceptionHandler.h b/src/main/resources/org/bytedeco/javacpp/jniTemplates/JNIExceptionHandler.h new file mode 100644 index 000000000..c9ea490eb --- /dev/null +++ b/src/main/resources/org/bytedeco/javacpp/jniTemplates/JNIExceptionHandler.h @@ -0,0 +1,36 @@ +static JavaCPP_noinline jclass JavaCPP_mapJavaExceptions(JNIEnv *env, const std::exception& e){ + if (dynamic_cast(&e)) { + return env->FindClass("java/lang/IllegalArgumentException"); + } + else if (dynamic_cast(&e)) { + return env->FindClass("java/lang/IndexOutOfBoundsException"); + } + else if (dynamic_cast(&e)) { + return env->FindClass("java/lang/RuntimeException"); + } + return env->FindClass("java/lang/Exception"); +} + +static JavaCPP_noinline jthrowable JavaCPP_createJavaException(JNIEnv *env, const std::exception& e, jthrowable cause = nullptr) { + jclass exClass = JavaCPP_mapJavaExceptions(env, e); + jstring message = env->NewStringUTF(e.what()); + jmethodID constructor = env->GetMethodID(exClass, "", "(Ljava/lang/String;)V"); + + if(cause) { + jmethodID initCause = env->GetMethodID(exClass, "initCause", "(Ljava/lang/Throwable;)Ljava/lang/Throwable;"); + jobject exWithCause = static_cast(env->NewObject(exClass, constructor, message)); + env->CallVoidMethod(exWithCause, initCause, cause); + return static_cast(exWithCause); + } + return static_cast(env->NewObject(exClass, constructor, message)); +} + +static JavaCPP_noinline jthrowable JavaCPP_handleException(JNIEnv *env, const std::exception& e) { + try { + std::rethrow_if_nested(e); + } catch (std::exception &nested) { + jthrowable cause = static_cast(JavaCPP_handleException(env, nested)); + return JavaCPP_createJavaException(env, e, cause); + } + return JavaCPP_createJavaException(env, e); +} From 0d068e4728d446b11625dd8a410128de32b5fe35 Mon Sep 17 00:00:00 2001 From: FITOR Date: Wed, 6 Nov 2024 13:58:36 +0100 Subject: [PATCH 02/28] [UNFINISHED] prepared dynamic exceptionMapping --- .../org/bytedeco/javacpp/ClassProperties.java | 93 ++++---- .../bytedeco/javacpp/annotation/Platform.java | 213 ++++++++++++------ .../org/bytedeco/javacpp/tools/Generator.java | 6 + 3 files changed, 192 insertions(+), 120 deletions(-) diff --git a/src/main/java/org/bytedeco/javacpp/ClassProperties.java b/src/main/java/org/bytedeco/javacpp/ClassProperties.java index e886f5432..72a46bdf2 100644 --- a/src/main/java/org/bytedeco/javacpp/ClassProperties.java +++ b/src/main/java/org/bytedeco/javacpp/ClassProperties.java @@ -22,17 +22,12 @@ package org.bytedeco.javacpp; -import java.io.File; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; import org.bytedeco.javacpp.annotation.Platform; import org.bytedeco.javacpp.tools.Logger; +import java.io.File; +import java.util.*; + /** * Does the heavy lifting of collecting values off Properties annotations found * on enclosing classes. Operates for the desired "platform" value specified @@ -41,14 +36,15 @@ * * @see Loader#loadProperties(Class, java.util.Properties, boolean) */ -public class ClassProperties extends HashMap> { +public class ClassProperties extends HashMap> { private static final Logger logger = Logger.create(ClassProperties.class); public ClassProperties() { } + public ClassProperties(Properties properties) { - platform = properties.getProperty("platform"); + platform = properties.getProperty("platform"); platformExtension = properties.getProperty("platform.extension"); - platformRoot = properties.getProperty("platform.root"); + platformRoot = properties.getProperty("platform.root"); pathSeparator = properties.getProperty("platform.path.separator"); if (platformRoot == null || platformRoot.length() == 0) { platformRoot = "."; @@ -57,17 +53,11 @@ public ClassProperties(Properties properties) { platformRoot += File.separator; } for (Map.Entry e : properties.entrySet()) { - String k = (String)e.getKey(), v = (String)e.getValue(); + String k = (String) e.getKey(), v = (String) e.getValue(); if (v == null || v.length() == 0) { continue; } - if (k.equals("platform.includepath") || k.equals("platform.includeresource") || k.equals("platform.include") - || k.equals("platform.linkpath") || k.equals("platform.linkresource") || k.equals("platform.link") - || k.equals("platform.preloadpath") || k.equals("platform.preloadresource") || k.equals("platform.preload") - || k.equals("platform.resourcepath") || k.equals("platform.resource") - || k.equals("platform.frameworkpath") || k.equals("platform.framework") - || k.equals("platform.executablepath") || k.equals("platform.executable") - || k.equals("platform.compiler.*") || k.equals("platform.library.suffix") || k.equals("platform.extension")) { + if (k.equals("platform.includepath") || k.equals("platform.includeresource") || k.equals("platform.include") || k.equals("platform.linkpath") || k.equals("platform.linkresource") || k.equals("platform.link") || k.equals("platform.preloadpath") || k.equals("platform.preloadresource") || k.equals("platform.preload") || k.equals("platform.resourcepath") || k.equals("platform.resource") || k.equals("platform.frameworkpath") || k.equals("platform.framework") || k.equals("platform.executablepath") || k.equals("platform.executable") || k.equals("platform.compiler.*") || k.equals("platform.library.suffix") || k.equals("platform.extension")) { addAll(k, v.split(pathSeparator)); } else { setProperty(k, v); @@ -84,21 +74,21 @@ public ClassProperties(Properties properties) { public List get(String key) { List list = super.get(key); if (list == null) { - put((String)key, list = new ArrayList()); + put((String) key, list = new ArrayList()); } return list; } - public void addAll(String key, String ... values) { + public void addAll(String key, String... values) { if (values != null) { addAll(key, Arrays.asList(values)); } } + public void addAll(String key, Collection values) { if (values != null) { String root = null; - if (key.equals("platform.compiler") || key.equals("platform.sysroot") || key.equals("platform.toolchain") || - key.equals("platform.includepath") || key.equals("platform.linkpath")) { + if (key.equals("platform.compiler") || key.equals("platform.sysroot") || key.equals("platform.toolchain") || key.equals("platform.includepath") || key.equals("platform.linkpath")) { root = platformRoot; } @@ -107,8 +97,7 @@ public void addAll(String key, Collection values) { if (value == null) { continue; } - if (root != null && !new File(value).isAbsolute() && - new File(root + value).exists()) { + if (root != null && !new File(value).isAbsolute() && new File(root + value).exists()) { value = root + value; } if (!values2.contains(value)) { @@ -121,10 +110,12 @@ public void addAll(String key, Collection values) { public String getProperty(String key) { return getProperty(key, null); } + public String getProperty(String key, String defaultValue) { List values = get(key); return values.isEmpty() ? defaultValue : values.get(0); } + public String setProperty(String key, String value) { List values = get(key); String oldValue = values.isEmpty() ? null : values.get(0); @@ -137,17 +128,14 @@ public void load(Class cls, boolean inherit) { Class c = Loader.getEnclosingClass(cls); List classList = new ArrayList(); classList.add(0, c); - while (!c.isAnnotationPresent(org.bytedeco.javacpp.annotation.Properties.class) - && !c.isAnnotationPresent(Platform.class) && c.getSuperclass() != null - && c.getSuperclass() != Object.class && c.getSuperclass() != Pointer.class) { + while (!c.isAnnotationPresent(org.bytedeco.javacpp.annotation.Properties.class) && !c.isAnnotationPresent(Platform.class) && c.getSuperclass() != null && c.getSuperclass() != Object.class && c.getSuperclass() != Pointer.class) { // accumulate superclasses to process native methods from those as well classList.add(0, c = c.getSuperclass()); } if (effectiveClasses == null) { effectiveClasses = classList; } - org.bytedeco.javacpp.annotation.Properties classProperties = - c.getAnnotation(org.bytedeco.javacpp.annotation.Properties.class); + org.bytedeco.javacpp.annotation.Properties classProperties = c.getAnnotation(org.bytedeco.javacpp.annotation.Properties.class); Platform classPlatform = c.getAnnotation(Platform.class); Platform[] platforms = null; String ourTarget = null; @@ -195,7 +183,7 @@ public void load(Class cls, boolean inherit) { } if (classPlatform != null) { if (platforms == null) { - platforms = new Platform[] { classPlatform }; + platforms = new Platform[]{classPlatform}; } else { platforms = Arrays.copyOf(platforms, platforms.length + 1); platforms[platforms.length - 1] = classPlatform; @@ -203,9 +191,7 @@ public void load(Class cls, boolean inherit) { } boolean hasPlatformProperties = platforms != null && platforms.length > (classProperties != null && classPlatform != null ? 1 : 0); - String[] pragma = {}, define = {}, exclude = {}, include = {}, cinclude = {}, includepath = {}, includeresource = {}, compiler = {}, - linkpath = {}, linkresource = {}, link = {}, frameworkpath = {}, framework = {}, preloadpath = {}, preloadresource = {}, preload = {}, - resourcepath = {}, resource = {}, extension = {}, executablepath = {}, executable = {}; + String[] exceptionMappings = {}, pragma = {}, define = {}, exclude = {}, include = {}, cinclude = {}, includepath = {}, includeresource = {}, compiler = {}, linkpath = {}, linkresource = {}, link = {}, frameworkpath = {}, framework = {}, preloadpath = {}, preloadresource = {}, preload = {}, resourcepath = {}, resource = {}, extension = {}, executablepath = {}, executable = {}; String library = "jni" + c.getSimpleName(); if (hasPlatformProperties) { if (ourTarget != null && ourTarget.length() > 0) { @@ -219,8 +205,8 @@ public void load(Class cls, boolean inherit) { } } for (Platform p : platforms != null ? platforms : new Platform[0]) { - String[][] names = { p.value().length > 0 ? p.value() : defaultNames, p.not(), p.pattern() }; - boolean[] matches = { false, false, false }; + String[][] names = {p.value().length > 0 ? p.value() : defaultNames, p.not(), p.pattern()}; + boolean[] matches = {false, false, false}; for (int i = 0; i < names.length; i++) { for (String s : names[i]) { if ((i < 2 && platform.startsWith(s)) || (s.length() > 0 && platform.matches(s))) { @@ -241,28 +227,29 @@ public void load(Class cls, boolean inherit) { if (!match) { continue; } - if (p.pragma() .length > 0) { pragma = p.pragma(); } - if (p.define() .length > 0) { define = p.define(); } - if (p.exclude() .length > 0) { exclude = p.exclude(); } - if (p.include() .length > 0) { include = p.include(); } - if (p.cinclude() .length > 0) { cinclude = p.cinclude(); } + if (p.exceptionMappings().length > 0) { exceptionMappings = p.exceptionMappings(); } + if (p.pragma().length > 0) { pragma = p.pragma(); } + if (p.define().length > 0) { define = p.define(); } + if (p.exclude().length > 0) { exclude = p.exclude(); } + if (p.include().length > 0) { include = p.include(); } + if (p.cinclude().length > 0) { cinclude = p.cinclude(); } if (p.includepath().length > 0) { includepath = p.includepath(); } if (p.includeresource().length > 0) { includeresource = p.includeresource(); } - if (p.compiler() .length > 0) { compiler = p.compiler(); } - if (p.linkpath() .length > 0) { linkpath = p.linkpath(); } - if (p.linkresource() .length > 0) { linkresource = p.linkresource(); } - if (p.link() .length > 0) { link = p.link(); } + if (p.compiler().length > 0) { compiler = p.compiler(); } + if (p.linkpath().length > 0) { linkpath = p.linkpath(); } + if (p.linkresource().length > 0) { linkresource = p.linkresource(); } + if (p.link().length > 0) { link = p.link(); } if (p.frameworkpath().length > 0) { frameworkpath = p.frameworkpath(); } - if (p.framework() .length > 0) { framework = p.framework(); } + if (p.framework().length > 0) { framework = p.framework(); } if (p.preloadresource().length > 0) { preloadresource = p.preloadresource(); } if (p.preloadpath().length > 0) { preloadpath = p.preloadpath(); } - if (p.preload() .length > 0) { preload = p.preload(); } + if (p.preload().length > 0) { preload = p.preload(); } if (p.resourcepath().length > 0) { resourcepath = p.resourcepath(); } - if (p.resource() .length > 0) { resource = p.resource(); } - if (p.extension() .length > 0) { extension = p.extension(); } + if (p.resource().length > 0) { resource = p.resource(); } + if (p.extension().length > 0) { extension = p.extension(); } if (p.executablepath().length > 0) { executablepath = p.executablepath(); } - if (p.executable() .length > 0) { executable = p.executable(); } - if (p.library().length() > 0) { library = p.library(); } + if (p.executable().length > 0) { executable = p.executable(); } + if (p.library().length() > 0) { library = p.library(); } } } for (int i = 0; i < includeresource.length; i++) { @@ -289,6 +276,8 @@ public void load(Class cls, boolean inherit) { linkresource[i] = "/" + name; } } + + addAll("platform.exceptionMappings", exceptionMappings); addAll("platform.pragma", pragma); addAll("platform.define", define); addAll("platform.exclude", exclude); @@ -319,7 +308,7 @@ public void load(Class cls, boolean inherit) { if (LoadEnabled.class.isAssignableFrom(c)) { try { - ((LoadEnabled)c.newInstance()).init(this); + ((LoadEnabled) c.newInstance()).init(this); } catch (ClassCastException | InstantiationException | IllegalAccessException e) { logger.warn("Could not create an instance of " + c + ": " + e); } diff --git a/src/main/java/org/bytedeco/javacpp/annotation/Platform.java b/src/main/java/org/bytedeco/javacpp/annotation/Platform.java index 65014dfe6..13f30138b 100644 --- a/src/main/java/org/bytedeco/javacpp/annotation/Platform.java +++ b/src/main/java/org/bytedeco/javacpp/annotation/Platform.java @@ -1,14 +1,11 @@ package org.bytedeco.javacpp.annotation; -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; import org.bytedeco.javacpp.Loader; import org.bytedeco.javacpp.tools.Builder; import org.bytedeco.javacpp.tools.Generator; +import java.lang.annotation.*; + /** * Defines native properties for a top-level enclosing class as well as indicates * classes and methods that should be generated or not, for specified platforms. @@ -30,81 +27,161 @@ * Further, with the {@link Properties} annotation, properties can be inherited * from other classes, and different properties can be defined for each platform. * + * @author Samuel Audet * @see Builder * @see Generator * @see Loader - * - * @author Samuel Audet */ -@Documented @Retention(RetentionPolicy.RUNTIME) +@Documented +@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) public @interface Platform { - /** The properties, class, or method apply only to the named platforms. - * The strings are matched with {@link String#startsWith(String)} */ - String[] value() default {}; - /** The properties, class, or method do NOT apply to the named platforms. - * The strings are matched with {@link String#startsWith(String)} */ - String[] not() default {}; - /** The properties, class, or method apply only to the named platforms. - * The strings are matched as regular expressions with {@link String#matches(String)}. */ - String[] pattern() default {}; - /** A list of {@code pragma} directives to list at the top of the generated - * code, before {@link #define()} macros and any included header files. */ - String[] pragma() default {}; - /** A list of macros to {@code #define} at the top of the generated code, - * before {@link #include()} and {@link #cinclude()} header files. */ - String[] define() default {}; - /** A list of C/C++ header files that should not be included in the generated code, - * even when they are inherited from an include list. */ - String[] exclude() default {}; - /** A list of C++ header files to include at the top of the generated code. */ - String[] include() default {}; - /** A list of C header files to include at the top of the generated code. The - * {@code #include} directives will be generated in a {@code extern "C" { } } block.*/ - String[] cinclude() default {}; - /** A list of include paths passed to the native compiler. */ + /** + * The properties, class, or method apply only to the named platforms. + * The strings are matched with {@link String#startsWith(String)} + */ + String[] value() default {}; + + /** + * The properties, class, or method do NOT apply to the named platforms. + * The strings are matched with {@link String#startsWith(String)} + */ + String[] not() default {}; + + /** + * The properties, class, or method apply only to the named platforms. + * The strings are matched as regular expressions with {@link String#matches(String)}. + */ + String[] pattern() default {}; + + /** + * A list of {@code pragma} directives to list at the top of the generated + * code, before {@link #define()} macros and any included header files. + */ + String[] pragma() default {}; + + /** + * A list of macros to {@code #define} at the top of the generated code, + * before {@link #include()} and {@link #cinclude()} header files. + */ + String[] define() default {}; + + /** + * A list of C/C++ header files that should not be included in the generated code, + * even when they are inherited from an include list. + */ + String[] exclude() default {}; + + /** + * A list of C++ header files to include at the top of the generated code. + */ + String[] include() default {}; + + /** + * A list of C header files to include at the top of the generated code. The + * {@code #include} directives will be generated in a {@code extern "C" { } } block. + */ + String[] cinclude() default {}; + + /** + * A list of include paths passed to the native compiler. + */ String[] includepath() default {}; - /** A list of include resources passed to the native compiler. */ + + /** + * A list of include resources passed to the native compiler. + */ String[] includeresource() default {}; - /** A list of options applied for the native compiler. The options here refer to - * property names. The actual command line options of the native compiler are the - * values of these properties, which need to be defined elsewhere. On an empty - * array, the {@link Builder} uses the "platform.compiler.default" property. */ - String[] compiler() default {}; - /** A list of library paths passed to the native compiler for use at link time. */ - String[] linkpath() default {}; - /** A list of library resources passed to the native compiler for use at link time. */ + + /** + * A list of options applied for the native compiler. The options here refer to + * property names. The actual command line options of the native compiler are the + * values of these properties, which need to be defined elsewhere. On an empty + * array, the {@link Builder} uses the "platform.compiler.default" property. + */ + String[] compiler() default {}; + + /** + * A list of library paths passed to the native compiler for use at link time. + */ + String[] linkpath() default {}; + + /** + * A list of library resources passed to the native compiler for use at link time. + */ String[] linkresource() default {}; - /** A list of libraries the native compiler should link with. - * Accepts "@" + optional version tag and "#" + a second optional name used at extraction (or empty to prevent it). */ - String[] link() default {}; - /** A list of framework paths passed to the native compiler for use at link time. */ + + /** + * A list of libraries the native compiler should link with. + * Accepts "@" + optional version tag and "#" + a second optional name used at extraction (or empty to prevent it). + */ + String[] link() default {}; + + /** + * A list of framework paths passed to the native compiler for use at link time. + */ String[] frameworkpath() default {}; - /** A list of frameworks the native compiler should build against. */ - String[] framework() default {}; - /** A list of paths from which to attempt preloading libraries from the - * {@link #link()} and {@link #preload()} lists. */ + + /** + * A list of frameworks the native compiler should build against. + */ + String[] framework() default {}; + + /** + * A list of paths from which to attempt preloading libraries from the + * {@link #link()} and {@link #preload()} lists. + */ String[] preloadpath() default {}; - /** A list of resources from which to attempt preloading libraries from the - * {@link #link()} and {@link #preload()} lists. */ + + /** + * A list of resources from which to attempt preloading libraries from the + * {@link #link()} and {@link #preload()} lists. + */ String[] preloadresource() default {}; - /** A list of libraries, in addition to {@link #link()}, that should be extracted and preloaded, if possible. - * Accepts "@" + optional version tag and "#" + a second optional name used at extraction (or empty to prevent it). */ - String[] preload() default {}; - /** A list of paths from which to copy resources from the {@link #resource()} list. */ + + /** + * A list of libraries, in addition to {@link #link()}, that should be extracted and preloaded, if possible. + * Accepts "@" + optional version tag and "#" + a second optional name used at extraction (or empty to prevent it). + */ + String[] preload() default {}; + + /** + * A list of paths from which to copy resources from the {@link #resource()} list. + */ String[] resourcepath() default {}; - /** A list of resources, either files or directories, that can be copied and extracted. */ - String[] resource() default {}; - /** The platform extensions to attempt to load for this library. The names here are - * appended to the platform name and looked up in the class path. */ - String[] extension() default {}; - /** A list of paths from which to copy executables from the {@link #executable()} value. */ + + /** + * A list of resources, either files or directories, that can be copied and extracted. + */ + String[] resource() default {}; + + /** + * The platform extensions to attempt to load for this library. The names here are + * appended to the platform name and looked up in the class path. + */ + String[] extension() default {}; + + /** + * A list of paths from which to copy executables from the {@link #executable()} value. + */ String[] executablepath() default {}; - /** Executables to bundle at build time and extract at runtime on load, instead of a library. */ - String[] executable() default {}; - /** The native JNI library associated with this class that {@link Builder} should - * try to build and {@link Loader} should try to load. If left empty, this value - * defaults to "jni" + the name that {@link Class#getSimpleName()} returns for - * {@link Properties#target} or {@link Properties#global} class, or this class, if not given. */ - String library() default ""; + + /** + * Executables to bundle at build time and extract at runtime on load, instead of a library. + */ + String[] executable() default {}; + + /** + * The native JNI library associated with this class that {@link Builder} should + * try to build and {@link Loader} should try to load. If left empty, this value + * defaults to "jni" + the name that {@link Class#getSimpleName()} returns for + * {@link Properties#target} or {@link Properties#global} class, or this class, if not given. + */ + String library() default ""; + + /** + * Mappings for custom exceptions. + * // TODO(Fitor) finish doc, also see whether you can replace String[] with a more fitting datatype (needs to be turned into String[] in {@link org.bytedeco.javacpp.ClassProperties eventually} + */ + String[] exceptionMappings() default ""; } diff --git a/src/main/java/org/bytedeco/javacpp/tools/Generator.java b/src/main/java/org/bytedeco/javacpp/tools/Generator.java index 63bbe6ec9..0925f3a71 100644 --- a/src/main/java/org/bytedeco/javacpp/tools/Generator.java +++ b/src/main/java/org/bytedeco/javacpp/tools/Generator.java @@ -250,6 +250,12 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver for (String s : clsProperties.get("platform.define")) { out.println("#define " + s); } + + out.println("FITORR"); + for(String s : clsProperties.get("platform.exceptionMappings")) { + out.println(s); + } + out.println(); out.println("#ifdef _WIN32"); out.println(" #define _JAVASOFT_JNI_MD_H_"); From c72d55a74dbcf9311746e2a807c29e584bc85113 Mon Sep 17 00:00:00 2001 From: FITOR Date: Thu, 7 Nov 2024 14:22:24 +0100 Subject: [PATCH 03/28] implemented dynamic exception mapping through the @Platform-annotation --- .../org/bytedeco/javacpp/ClassProperties.java | 15 +++++++++- .../javacpp/annotation/ExceptionMapper.java | 29 ++++++++++++++++++ .../bytedeco/javacpp/annotation/Platform.java | 4 +-- .../org/bytedeco/javacpp/tools/Generator.java | 30 +++++++++++++++---- .../jniTemplates/JNIExceptionHandler.h | 9 ++++-- 5 files changed, 76 insertions(+), 11 deletions(-) create mode 100644 src/main/java/org/bytedeco/javacpp/annotation/ExceptionMapper.java diff --git a/src/main/java/org/bytedeco/javacpp/ClassProperties.java b/src/main/java/org/bytedeco/javacpp/ClassProperties.java index 72a46bdf2..1740c032c 100644 --- a/src/main/java/org/bytedeco/javacpp/ClassProperties.java +++ b/src/main/java/org/bytedeco/javacpp/ClassProperties.java @@ -22,6 +22,7 @@ package org.bytedeco.javacpp; +import org.bytedeco.javacpp.annotation.ExceptionMapper; import org.bytedeco.javacpp.annotation.Platform; import org.bytedeco.javacpp.tools.Logger; @@ -227,7 +228,19 @@ public void load(Class cls, boolean inherit) { if (!match) { continue; } - if (p.exceptionMappings().length > 0) { exceptionMappings = p.exceptionMappings(); } + + if (p.exceptionMappings().length > 0) { + List exceptionMappingsList = new LinkedList<>(); + for (ExceptionMapper mapper : p.exceptionMappings()) { + final String cppException = mapper.cppException(); + final String javaException = mapper.javaExceptionClass().getName().replace('.', '/'); + + exceptionMappingsList.add(cppException); + exceptionMappingsList.add(javaException); + } + exceptionMappings = exceptionMappingsList.toArray(new String[0]); + } + if (p.pragma().length > 0) { pragma = p.pragma(); } if (p.define().length > 0) { define = p.define(); } if (p.exclude().length > 0) { exclude = p.exclude(); } diff --git a/src/main/java/org/bytedeco/javacpp/annotation/ExceptionMapper.java b/src/main/java/org/bytedeco/javacpp/annotation/ExceptionMapper.java new file mode 100644 index 000000000..d25ed1b47 --- /dev/null +++ b/src/main/java/org/bytedeco/javacpp/annotation/ExceptionMapper.java @@ -0,0 +1,29 @@ +package org.bytedeco.javacpp.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Exception Mapper maps a C/C++ exception to the given java exception. + * Will overwrite any existing exception-mappings. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({}) +public @interface ExceptionMapper { + + /** + * The C/C++ exception to be mapped (e.g.: std::runtime_error). + * + * @return A String representation of the C/C++ exception to be mapped. + */ + String cppException(); + + /** + * The corresponding java-exception. + * + * @return The corresponding java-exception. + */ + Class javaExceptionClass(); +} + diff --git a/src/main/java/org/bytedeco/javacpp/annotation/Platform.java b/src/main/java/org/bytedeco/javacpp/annotation/Platform.java index 13f30138b..275873f46 100644 --- a/src/main/java/org/bytedeco/javacpp/annotation/Platform.java +++ b/src/main/java/org/bytedeco/javacpp/annotation/Platform.java @@ -181,7 +181,7 @@ /** * Mappings for custom exceptions. - * // TODO(Fitor) finish doc, also see whether you can replace String[] with a more fitting datatype (needs to be turned into String[] in {@link org.bytedeco.javacpp.ClassProperties eventually} + * @return An array of {@link ExceptionMapper}, which determines the mapping of custom native exceptions to any javaException. */ - String[] exceptionMappings() default ""; + ExceptionMapper[] exceptionMappings() default {}; } diff --git a/src/main/java/org/bytedeco/javacpp/tools/Generator.java b/src/main/java/org/bytedeco/javacpp/tools/Generator.java index 0925f3a71..2e9721fd9 100644 --- a/src/main/java/org/bytedeco/javacpp/tools/Generator.java +++ b/src/main/java/org/bytedeco/javacpp/tools/Generator.java @@ -251,11 +251,6 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver out.println("#define " + s); } - out.println("FITORR"); - for(String s : clsProperties.get("platform.exceptionMappings")) { - out.println(s); - } - out.println(); out.println("#ifdef _WIN32"); out.println(" #define _JAVASOFT_JNI_MD_H_"); @@ -1089,7 +1084,31 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver out.println("};"); out.println(); + //////////////////// EXCEPTION HANDLER //////////////////// if (handleExceptions) { + // Build a function which maps custom java Exceptions to corresponding native exceptions. + out.println("static JavaCPP_noinline jclass JavaCPP_mapCustomExceptions(JNIEnv *env, const std::exception& e) {"); + + final String ifCondition = " if(dynamic_cast(&e)){"; + final String elifCondition = " else if(dynamic_cast(&e)){"; + final String returnVal = " return env->FindClass(\"%s\");"; + + List exceptionMappings = clsProperties.get("platform.exceptionMappings"); + for (int i = 0; i < exceptionMappings.size(); i += 2) { + final String cppException = exceptionMappings.get(i); + final String javaException = exceptionMappings.get(i + 1); + + out.println(i == 0 ? + String.format(ifCondition, cppException) : + String.format(elifCondition, cppException)); + + out.println(String.format(returnVal, javaException)); + out.println(" }"); + } + out.println(" return nullptr;"); + out.println("}"); + + // "Import" the remaining exception-specific functions. try (InputStream inputStream = Generator.class.getResourceAsStream("/org/bytedeco/javacpp/jniTemplates/JNIExceptionHandler.h"); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { @@ -1101,6 +1120,7 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver throw new RuntimeException("Unable to find template 'JNIExceptionHandler'", e); } } + //////////////////// EXCEPTION HANDLER //////////////////// Class deallocator, nativeDeallocator; try { diff --git a/src/main/resources/org/bytedeco/javacpp/jniTemplates/JNIExceptionHandler.h b/src/main/resources/org/bytedeco/javacpp/jniTemplates/JNIExceptionHandler.h index c9ea490eb..2abad8eb3 100644 --- a/src/main/resources/org/bytedeco/javacpp/jniTemplates/JNIExceptionHandler.h +++ b/src/main/resources/org/bytedeco/javacpp/jniTemplates/JNIExceptionHandler.h @@ -1,3 +1,4 @@ +// Function finds the right java-exception to the most common native std::exceptions static JavaCPP_noinline jclass JavaCPP_mapJavaExceptions(JNIEnv *env, const std::exception& e){ if (dynamic_cast(&e)) { return env->FindClass("java/lang/IllegalArgumentException"); @@ -10,9 +11,11 @@ static JavaCPP_noinline jclass JavaCPP_mapJavaExceptions(JNIEnv *env, const std: } return env->FindClass("java/lang/Exception"); } - +// Function creates a jobject (extends Throwable) from the passed std::exception static JavaCPP_noinline jthrowable JavaCPP_createJavaException(JNIEnv *env, const std::exception& e, jthrowable cause = nullptr) { - jclass exClass = JavaCPP_mapJavaExceptions(env, e); + jclass exClass = JavaCPP_mapCustomExceptions(env, e); + exClass = exClass ? exClass : JavaCPP_mapJavaExceptions(env, e); + jstring message = env->NewStringUTF(e.what()); jmethodID constructor = env->GetMethodID(exClass, "", "(Ljava/lang/String;)V"); @@ -24,7 +27,7 @@ static JavaCPP_noinline jthrowable JavaCPP_createJavaException(JNIEnv *env, cons } return static_cast(env->NewObject(exClass, constructor, message)); } - +// Function unrolls native exceptions and builds the corresponding java exception static JavaCPP_noinline jthrowable JavaCPP_handleException(JNIEnv *env, const std::exception& e) { try { std::rethrow_if_nested(e); From 8689d4a05d16e4044a118a204c48b56a68344c6b Mon Sep 17 00:00:00 2001 From: FITOR Date: Thu, 28 Nov 2024 09:24:37 +0100 Subject: [PATCH 04/28] test commit --- .../org/bytedeco/javacpp/jniTemplates/JNIExceptionHandler.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/resources/org/bytedeco/javacpp/jniTemplates/JNIExceptionHandler.h b/src/main/resources/org/bytedeco/javacpp/jniTemplates/JNIExceptionHandler.h index 2abad8eb3..ad04868dc 100644 --- a/src/main/resources/org/bytedeco/javacpp/jniTemplates/JNIExceptionHandler.h +++ b/src/main/resources/org/bytedeco/javacpp/jniTemplates/JNIExceptionHandler.h @@ -11,7 +11,8 @@ static JavaCPP_noinline jclass JavaCPP_mapJavaExceptions(JNIEnv *env, const std: } return env->FindClass("java/lang/Exception"); } -// Function creates a jobject (extends Throwable) from the passed std::exception + +// Function creates a jobject (extends Throwable) from the passed std::exception (with causes) static JavaCPP_noinline jthrowable JavaCPP_createJavaException(JNIEnv *env, const std::exception& e, jthrowable cause = nullptr) { jclass exClass = JavaCPP_mapCustomExceptions(env, e); exClass = exClass ? exClass : JavaCPP_mapJavaExceptions(env, e); From deee6ce1a6e9de4799b5b1387ee18318cd1e81ee Mon Sep 17 00:00:00 2001 From: FITOR Date: Fri, 29 Nov 2024 13:19:45 +0100 Subject: [PATCH 05/28] added missing include --- .gitignore | 1 + .../org/bytedeco/javacpp/jniTemplates/JNIExceptionHandler.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index b61aa4c26..c497c029a 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ # IntelliJ *.iml .idea +**/out/** diff --git a/src/main/resources/org/bytedeco/javacpp/jniTemplates/JNIExceptionHandler.h b/src/main/resources/org/bytedeco/javacpp/jniTemplates/JNIExceptionHandler.h index ad04868dc..7806f995c 100644 --- a/src/main/resources/org/bytedeco/javacpp/jniTemplates/JNIExceptionHandler.h +++ b/src/main/resources/org/bytedeco/javacpp/jniTemplates/JNIExceptionHandler.h @@ -1,3 +1,5 @@ +#include + // Function finds the right java-exception to the most common native std::exceptions static JavaCPP_noinline jclass JavaCPP_mapJavaExceptions(JNIEnv *env, const std::exception& e){ if (dynamic_cast(&e)) { From 8d0f08ec1516e3e2061633b1b4c85656cdd36400 Mon Sep 17 00:00:00 2001 From: FITOR Date: Fri, 29 Nov 2024 13:24:10 +0100 Subject: [PATCH 06/28] edited .gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index c497c029a..b61aa4c26 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,3 @@ # IntelliJ *.iml .idea -**/out/** From ac453a9042cffbd4958b46b69efe2a3ee7242946 Mon Sep 17 00:00:00 2001 From: FITOR Date: Fri, 29 Nov 2024 13:45:56 +0100 Subject: [PATCH 07/28] added include --- src/main/java/org/bytedeco/javacpp/tools/Generator.java | 1 + .../org/bytedeco/javacpp/jniTemplates/JNIExceptionHandler.h | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/org/bytedeco/javacpp/tools/Generator.java b/src/main/java/org/bytedeco/javacpp/tools/Generator.java index 2e9721fd9..6a1f69954 100644 --- a/src/main/java/org/bytedeco/javacpp/tools/Generator.java +++ b/src/main/java/org/bytedeco/javacpp/tools/Generator.java @@ -1086,6 +1086,7 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver //////////////////// EXCEPTION HANDLER //////////////////// if (handleExceptions) { + out.println("#include "); // Build a function which maps custom java Exceptions to corresponding native exceptions. out.println("static JavaCPP_noinline jclass JavaCPP_mapCustomExceptions(JNIEnv *env, const std::exception& e) {"); diff --git a/src/main/resources/org/bytedeco/javacpp/jniTemplates/JNIExceptionHandler.h b/src/main/resources/org/bytedeco/javacpp/jniTemplates/JNIExceptionHandler.h index 7806f995c..ad04868dc 100644 --- a/src/main/resources/org/bytedeco/javacpp/jniTemplates/JNIExceptionHandler.h +++ b/src/main/resources/org/bytedeco/javacpp/jniTemplates/JNIExceptionHandler.h @@ -1,5 +1,3 @@ -#include - // Function finds the right java-exception to the most common native std::exceptions static JavaCPP_noinline jclass JavaCPP_mapJavaExceptions(JNIEnv *env, const std::exception& e){ if (dynamic_cast(&e)) { From c6bef28ff58fc447a14896a1bf8074fd35e33845 Mon Sep 17 00:00:00 2001 From: FITOR Date: Tue, 3 Dec 2024 15:01:35 +0100 Subject: [PATCH 08/28] enabled custom mapping for single methods --- .../javacpp/annotation/CustomMapper.java | 28 + .../org/bytedeco/javacpp/tools/Generator.java | 555 +++++++----------- 2 files changed, 228 insertions(+), 355 deletions(-) create mode 100644 src/main/java/org/bytedeco/javacpp/annotation/CustomMapper.java diff --git a/src/main/java/org/bytedeco/javacpp/annotation/CustomMapper.java b/src/main/java/org/bytedeco/javacpp/annotation/CustomMapper.java new file mode 100644 index 000000000..49d4cd2bd --- /dev/null +++ b/src/main/java/org/bytedeco/javacpp/annotation/CustomMapper.java @@ -0,0 +1,28 @@ +package org.bytedeco.javacpp.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation allows to implement custom jni-mappings for specific methods. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface CustomMapper { + + /** + * Custom mapping logic, used only when filePath is not set. + * + * @return A String which will be directly used for the mapping. + */ + String customMapping() default "// do Nothing"; + + /** + * FilePath of the file, which contains the mapping. + * + * @return The filePath of the file, which contains the mapping. + */ + String filePath() default ""; +} \ No newline at end of file diff --git a/src/main/java/org/bytedeco/javacpp/tools/Generator.java b/src/main/java/org/bytedeco/javacpp/tools/Generator.java index 6a1f69954..b5fd8eecb 100644 --- a/src/main/java/org/bytedeco/javacpp/tools/Generator.java +++ b/src/main/java/org/bytedeco/javacpp/tools/Generator.java @@ -1099,9 +1099,7 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver final String cppException = exceptionMappings.get(i); final String javaException = exceptionMappings.get(i + 1); - out.println(i == 0 ? - String.format(ifCondition, cppException) : - String.format(elifCondition, cppException)); + out.println(i == 0 ? String.format(ifCondition, cppException) : String.format(elifCondition, cppException)); out.println(String.format(returnVal, javaException)); out.println(" }"); @@ -1110,16 +1108,8 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver out.println("}"); // "Import" the remaining exception-specific functions. - try (InputStream inputStream = Generator.class.getResourceAsStream("/org/bytedeco/javacpp/jniTemplates/JNIExceptionHandler.h"); - BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { - - String line; - while ((line = reader.readLine()) != null) { - out.println(line); - } - } catch (IOException e) { - throw new RuntimeException("Unable to find template 'JNIExceptionHandler'", e); - } + String fileContent = getFileContentFromLocal("/org/bytedeco/javacpp/jniTemplates/JNIExceptionHandler.h"); + out.println(fileContent); } //////////////////// EXCEPTION HANDLER //////////////////// @@ -1801,80 +1791,65 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver out.println(" if (JavaCPP_deallocatorFID == NULL) {"); out.println(" return JNI_ERR;"); out.println(" }"); - out.println(" JavaCPP_ownerAddressFID = JavaCPP_getFieldID(env, " + - jclasses.index(nativeDeallocator) + ", \"ownerAddress\", \"J\");"); + out.println(" JavaCPP_ownerAddressFID = JavaCPP_getFieldID(env, " + jclasses.index(nativeDeallocator) + ", \"ownerAddress\", \"J\");"); out.println(" if (JavaCPP_ownerAddressFID == NULL) {"); out.println(" return JNI_ERR;"); out.println(" }"); if (declareEnums) { - out.println(" JavaCPP_booleanValueFID = JavaCPP_getFieldID(env, \"" + - BooleanEnum.class.getName().replace('.', '/') + "\", \"value\", \"Z\");"); + out.println(" JavaCPP_booleanValueFID = JavaCPP_getFieldID(env, \"" + BooleanEnum.class.getName().replace('.', '/') + "\", \"value\", \"Z\");"); out.println(" if (JavaCPP_booleanValueFID == NULL) {"); out.println(" return JNI_ERR;"); out.println(" }"); - out.println(" JavaCPP_byteValueFID = JavaCPP_getFieldID(env, \"" + - ByteEnum.class.getName().replace('.', '/') + "\", \"value\", \"B\");"); + out.println(" JavaCPP_byteValueFID = JavaCPP_getFieldID(env, \"" + ByteEnum.class.getName().replace('.', '/') + "\", \"value\", \"B\");"); out.println(" if (JavaCPP_byteValueFID == NULL) {"); out.println(" return JNI_ERR;"); out.println(" }"); - out.println(" JavaCPP_shortValueFID = JavaCPP_getFieldID(env, \"" + - ShortEnum.class.getName().replace('.', '/') + "\", \"value\", \"S\");"); + out.println(" JavaCPP_shortValueFID = JavaCPP_getFieldID(env, \"" + ShortEnum.class.getName().replace('.', '/') + "\", \"value\", \"S\");"); out.println(" if (JavaCPP_shortValueFID == NULL) {"); out.println(" return JNI_ERR;"); out.println(" }"); - out.println(" JavaCPP_intValueFID = JavaCPP_getFieldID(env, \"" + - IntEnum.class.getName().replace('.', '/') + "\", \"value\", \"I\");"); + out.println(" JavaCPP_intValueFID = JavaCPP_getFieldID(env, \"" + IntEnum.class.getName().replace('.', '/') + "\", \"value\", \"I\");"); out.println(" if (JavaCPP_intValueFID == NULL) {"); out.println(" return JNI_ERR;"); out.println(" }"); - out.println(" JavaCPP_longValueFID = JavaCPP_getFieldID(env, \"" + - LongEnum.class.getName().replace('.', '/') + "\", \"value\", \"J\");"); + out.println(" JavaCPP_longValueFID = JavaCPP_getFieldID(env, \"" + LongEnum.class.getName().replace('.', '/') + "\", \"value\", \"J\");"); out.println(" if (JavaCPP_longValueFID == NULL) {"); out.println(" return JNI_ERR;"); out.println(" }"); } - out.println(" JavaCPP_initMID = JavaCPP_getMethodID(env, " + - jclasses.index(Pointer.class) + ", \"init\", \"(JJJJ)V\");"); + out.println(" JavaCPP_initMID = JavaCPP_getMethodID(env, " + jclasses.index(Pointer.class) + ", \"init\", \"(JJJJ)V\");"); out.println(" if (JavaCPP_initMID == NULL) {"); out.println(" return JNI_ERR;"); out.println(" }"); - out.println(" JavaCPP_arrayMID = JavaCPP_getMethodID(env, " + - jclasses.index(Buffer.class) + ", \"array\", \"()Ljava/lang/Object;\");"); + out.println(" JavaCPP_arrayMID = JavaCPP_getMethodID(env, " + jclasses.index(Buffer.class) + ", \"array\", \"()Ljava/lang/Object;\");"); out.println(" if (JavaCPP_arrayMID == NULL) {"); out.println(" return JNI_ERR;"); out.println(" }"); - out.println(" JavaCPP_arrayOffsetMID = JavaCPP_getMethodID(env, " + - jclasses.index(Buffer.class) + ", \"arrayOffset\", \"()I\");"); + out.println(" JavaCPP_arrayOffsetMID = JavaCPP_getMethodID(env, " + jclasses.index(Buffer.class) + ", \"arrayOffset\", \"()I\");"); out.println(" if (JavaCPP_arrayOffsetMID == NULL) {"); out.println(" return JNI_ERR;"); out.println(" }"); - out.println(" JavaCPP_bufferPositionFID = JavaCPP_getFieldID(env, " + - jclasses.index(Buffer.class) + ", \"position\", \"I\");"); + out.println(" JavaCPP_bufferPositionFID = JavaCPP_getFieldID(env, " + jclasses.index(Buffer.class) + ", \"position\", \"I\");"); out.println(" if (JavaCPP_bufferPositionFID == NULL) {"); out.println(" return JNI_ERR;"); out.println(" }"); - out.println(" JavaCPP_bufferLimitFID = JavaCPP_getFieldID(env, " + - jclasses.index(Buffer.class) + ", \"limit\", \"I\");"); + out.println(" JavaCPP_bufferLimitFID = JavaCPP_getFieldID(env, " + jclasses.index(Buffer.class) + ", \"limit\", \"I\");"); out.println(" if (JavaCPP_bufferLimitFID == NULL) {"); out.println(" return JNI_ERR;"); out.println(" }"); - out.println(" JavaCPP_bufferCapacityFID = JavaCPP_getFieldID(env, " + - jclasses.index(Buffer.class) + ", \"capacity\", \"I\");"); + out.println(" JavaCPP_bufferCapacityFID = JavaCPP_getFieldID(env, " + jclasses.index(Buffer.class) + ", \"capacity\", \"I\");"); out.println(" if (JavaCPP_bufferCapacityFID == NULL) {"); out.println(" return JNI_ERR;"); out.println(" }"); - out.println(" JavaCPP_stringMID = JavaCPP_getMethodID(env, " + - jclasses.index(String.class) + ", \"\", \"([B)V\");"); + out.println(" JavaCPP_stringMID = JavaCPP_getMethodID(env, " + jclasses.index(String.class) + ", \"\", \"([B)V\");"); out.println(" if (JavaCPP_stringMID == NULL) {"); out.println(" return JNI_ERR;"); out.println(" }"); - out.println(" JavaCPP_getBytesMID = JavaCPP_getMethodID(env, " + - jclasses.index(String.class) + ", \"getBytes\", \"()[B\");"); + out.println(" JavaCPP_getBytesMID = JavaCPP_getMethodID(env, " + jclasses.index(String.class) + ", \"getBytes\", \"()[B\");"); out.println(" if (JavaCPP_getBytesMID == NULL) {"); out.println(" return JNI_ERR;"); out.println(" }"); - out.println(" JavaCPP_toStringMID = JavaCPP_getMethodID(env, " + - jclasses.index(Object.class) + ", \"toString\", \"()Ljava/lang/String;\");"); + out.println(" JavaCPP_toStringMID = JavaCPP_getMethodID(env, " + jclasses.index(Object.class) + ", \"toString\", \"()Ljava/lang/String;\");"); out.println(" if (JavaCPP_toStringMID == NULL) {"); out.println(" return JNI_ERR;"); out.println(" }"); @@ -1898,13 +1873,11 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver out.println(" JavaCPP_log(\"Error creating global reference for java.nio.charset.Charset instance\");"); out.println(" return JNI_ERR;"); out.println(" }"); - out.println(" JavaCPP_stringWithCharsetMID = JavaCPP_getMethodID(env, " + - jclasses.index(String.class) + ", \"\", \"([BLjava/nio/charset/Charset;)V\");"); + out.println(" JavaCPP_stringWithCharsetMID = JavaCPP_getMethodID(env, " + jclasses.index(String.class) + ", \"\", \"([BLjava/nio/charset/Charset;)V\");"); out.println(" if (JavaCPP_stringWithCharsetMID == NULL) {"); out.println(" return JNI_ERR;"); out.println(" }"); - out.println(" JavaCPP_getBytesWithCharsetMID = JavaCPP_getMethodID(env, " + - jclasses.index(String.class) + ", \"getBytes\", \"(Ljava/nio/charset/Charset;)[B\");"); + out.println(" JavaCPP_getBytesWithCharsetMID = JavaCPP_getMethodID(env, " + jclasses.index(String.class) + ", \"getBytes\", \"(Ljava/nio/charset/Charset;)[B\");"); out.println(" if (JavaCPP_getBytesWithCharsetMID == NULL) {"); out.println(" return JNI_ERR;"); out.println(" }"); @@ -2015,8 +1988,7 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver for (Class cls : allClasses) { o.println(separator + " {"); o.print(" \"name\" : \"" + cls.getName() + "\""); - if (reflectClasses.contains(cls) || reflectClasses.contains(cls.getEnclosingClass()) - || virtualFunctions.get(cls) != null || FunctionPointer.class.isAssignableFrom(cls)) { + if (reflectClasses.contains(cls) || reflectClasses.contains(cls.getEnclosingClass()) || virtualFunctions.get(cls) != null || FunctionPointer.class.isAssignableFrom(cls)) { o.println(","); o.println(" \"allDeclaredConstructors\" : true,"); o.println(" \"allPublicConstructors\" : true,"); @@ -2049,10 +2021,7 @@ boolean methods(Class cls) { } Set memberList = members.get(cls); - if (!cls.isAnnotationPresent(Opaque.class) && cls != Loader.class - && !FunctionPointer.class.isAssignableFrom(cls) - && cls.getEnclosingClass() != Loader.class - && cls.getEnclosingClass() != Pointer.class) { + if (!cls.isAnnotationPresent(Opaque.class) && cls != Loader.class && !FunctionPointer.class.isAssignableFrom(cls) && cls.getEnclosingClass() != Loader.class && cls.getEnclosingClass() != Pointer.class) { if (memberList == null) { members.put(cls, memberList = new LinkedHashSet()); } @@ -2063,8 +2032,7 @@ boolean methods(Class cls) { boolean didSomething = false; for (Class c : cls.getDeclaredClasses()) { - if (Pointer.class.isAssignableFrom(c) || - Pointer.class.equals(c.getEnclosingClass())) { + if (Pointer.class.isAssignableFrom(c) || Pointer.class.equals(c.getEnclosingClass())) { didSomething |= methods(c); } } @@ -2108,16 +2076,13 @@ boolean methods(Class cls) { } MethodInformation methodInfo = methodInfos[i]; String nativeName = mangle(cls.getName()) + "_" + mangle(methods[i].getName()); - String callbackName = callbackAllocators[i] && methodInfo.parameterTypes.length > 0 - ? null : "JavaCPP_" + nativeName + "_callback"; + String callbackName = callbackAllocators[i] && methodInfo.parameterTypes.length > 0 ? null : "JavaCPP_" + nativeName + "_callback"; if (callbackAllocators[i] && functionMethods == null) { - logger.warn("No callback method call() or apply() has been not declared in \"" + - cls.getCanonicalName() + "\". No code will be generated for callback allocator."); + logger.warn("No callback method call() or apply() has been not declared in \"" + cls.getCanonicalName() + "\". No code will be generated for callback allocator."); continue; } else if (functionMethods != null) { for (Method functionMethod : functionMethods) { - if (functionMethod != null && (callbackAllocators[i]) - || (methods[i].equals(functionMethod) && !Modifier.isNative(methods[i].getModifiers()))) { + if (functionMethod != null && (callbackAllocators[i]) || (methods[i].equals(functionMethod) && !Modifier.isNative(methods[i].getModifiers()))) { functions.index(cls); Name name = methods[i].getAnnotation(Name.class); if (name != null && name.value().length > 0 && name.value()[0].length() > 0) { @@ -2130,9 +2095,7 @@ boolean methods(Class cls) { } } - if ((Modifier.isNative(methods[i].getModifiers()) || Modifier.isAbstract(methods[i].getModifiers())) - && !methodInfo.valueGetter && !methodInfo.valueSetter && !methodInfo.memberGetter && !methodInfo.memberSetter - && !cls.isInterface() && (methods[i].isAnnotationPresent(Virtual.class) || methodInfo.allocator)) { + if ((Modifier.isNative(methods[i].getModifiers()) || Modifier.isAbstract(methods[i].getModifiers())) && !methodInfo.valueGetter && !methodInfo.valueSetter && !methodInfo.memberGetter && !methodInfo.memberSetter && !cls.isInterface() && (methods[i].isAnnotationPresent(Virtual.class) || methodInfo.allocator)) { // also process virtual methods and their allocators as callbacks callback(cls, methods[i], methodInfo.memberName[0], methodInfo.allocatorMax, !methodInfo.allocator, methodInfo); } @@ -2141,8 +2104,7 @@ boolean methods(Class cls) { continue; } - if ((methodInfo.memberGetter || methodInfo.memberSetter) && !methodInfo.noOffset && - memberList != null && !Modifier.isStatic(methodInfo.modifiers)) { + if ((methodInfo.memberGetter || methodInfo.memberSetter) && !methodInfo.noOffset && memberList != null && !Modifier.isStatic(methodInfo.modifiers)) { if (!memberList.contains(methodInfo.memberName[0])) { memberList.add(methodInfo.memberName[0]); } @@ -2166,8 +2128,7 @@ boolean methods(Class cls) { if (callbackAllocators[i]) { callbackAllocator(cls, callbackName, methodInfo.allocatorMax); continue; - } else if (!Modifier.isStatic(methodInfo.modifiers) && Pointer.class.isAssignableFrom(cls) - && !methodInfo.allocator && !methodInfo.arrayAllocator && !methodInfo.deallocator) { + } else if (!Modifier.isStatic(methodInfo.modifiers) && Pointer.class.isAssignableFrom(cls) && !methodInfo.allocator && !methodInfo.arrayAllocator && !methodInfo.deallocator) { // get our "this" pointer String[] typeName = cppTypeName(cls); if ("void*".equals(typeName[0]) && !cls.isAnnotationPresent(Opaque.class)) { @@ -2177,17 +2138,14 @@ boolean methods(Class cls) { typeName[0] = functionClassName(cls) + "*"; typeName[1] = ""; } - out.println(" " + typeName[0] + " ptr" + typeName[1] + " = (" + typeName[0] + - typeName[1] + ")jlong_to_ptr(env->GetLongField(obj, JavaCPP_addressFID));"); + out.println(" " + typeName[0] + " ptr" + typeName[1] + " = (" + typeName[0] + typeName[1] + ")jlong_to_ptr(env->GetLongField(obj, JavaCPP_addressFID));"); out.println(" if (ptr == NULL) {"); - out.println(" env->ThrowNew(JavaCPP_getClass(env, " + - jclasses.index(NullPointerException.class) + "), \"This pointer address is NULL.\");"); + out.println(" env->ThrowNew(JavaCPP_getClass(env, " + jclasses.index(NullPointerException.class) + "), \"This pointer address is NULL.\");"); out.println(" return" + (methodInfo.returnType == void.class ? ";" : " 0;")); out.println(" }"); if (FunctionPointer.class.isAssignableFrom(cls) && !methodInfo.valueGetter && !methodInfo.valueSetter) { out.println(" if (ptr->ptr == NULL) {"); - out.println(" env->ThrowNew(JavaCPP_getClass(env, " + - jclasses.index(NullPointerException.class) + "), \"This function pointer address is NULL.\");"); + out.println(" env->ThrowNew(JavaCPP_getClass(env, " + jclasses.index(NullPointerException.class) + "), \"This function pointer address is NULL.\");"); out.println(" return" + (methodInfo.returnType == void.class ? ";" : " 0;")); out.println(" }"); } @@ -2204,8 +2162,32 @@ boolean methods(Class cls) { parametersBefore(methodInfo); String returnPrefix = returnBefore(methodInfo); - call(methodInfo, returnPrefix, false); - returnAfter(methodInfo); + + boolean containsCustomMapping = false; + for (Annotation annotation : methodInfo.annotations) { + if (annotation.annotationType().equals(CustomMapper.class)) { + containsCustomMapping = true; + + CustomMapper mapper = (CustomMapper) annotation; + final String mappingFilePath = mapper.filePath(); + + if (!mappingFilePath.isEmpty()) { + String fileContent = getFileContentFromOther(mappingFilePath); + out.println(fileContent); + } else { + out.println(mapper.customMapping()); + } + + break; + } + } + + // ignore the default mapping if the customMapping has been enabled + if (!containsCustomMapping) { + call(methodInfo, returnPrefix, false); + returnAfter(methodInfo); + } + parametersAfter(methodInfo); if (methodInfo.throwsException != null) { out.println(" if (exc != NULL) {"); @@ -2229,10 +2211,8 @@ void parametersBefore(MethodInformation methodInfo) { if (!methodInfo.parameterTypes[j].isPrimitive()) { Annotation passBy = by(methodInfo, j); String cast = cast(methodInfo, j); - String[] typeName = methodInfo.parameterRaw[j] ? new String[]{""} - : cppTypeName(methodInfo, j); - AdapterInformation adapterInfo = methodInfo.parameterRaw[j] ? null - : adapterInformation(false, methodInfo, j); + String[] typeName = methodInfo.parameterRaw[j] ? new String[]{""} : cppTypeName(methodInfo, j); + AdapterInformation adapterInfo = methodInfo.parameterRaw[j] ? null : adapterInformation(false, methodInfo, j); if (Enum.class.isAssignableFrom(methodInfo.parameterTypes[j])) { accessesEnums = true; @@ -2240,12 +2220,10 @@ void parametersBefore(MethodInformation methodInfo) { if (s != null) { String S = Character.toUpperCase(s.charAt(0)) + s.substring(1); out.println(" if (arg" + j + " == NULL) {"); - out.println(" env->ThrowNew(JavaCPP_getClass(env, " + - jclasses.index(NullPointerException.class) + "), \"Enum for argument " + j + " is NULL.\");"); + out.println(" env->ThrowNew(JavaCPP_getClass(env, " + jclasses.index(NullPointerException.class) + "), \"Enum for argument " + j + " is NULL.\");"); out.println(" return" + (methodInfo.returnType == void.class ? ";" : " 0;")); out.println(" }"); - out.println(" " + typeName[0] + " val" + j + typeName[1] + " = (" + typeName[0] + typeName[1] + - ")env->Get" + S + "Field(arg" + j + ", JavaCPP_" + s + "ValueFID);"); + out.println(" " + typeName[0] + " val" + j + typeName[1] + " = (" + typeName[0] + typeName[1] + ")env->Get" + S + "Field(arg" + j + ", JavaCPP_" + s + "ValueFID);"); } continue; } @@ -2253,8 +2231,7 @@ void parametersBefore(MethodInformation methodInfo) { if (FunctionPointer.class.isAssignableFrom(methodInfo.parameterTypes[j])) { functions.index(methodInfo.parameterTypes[j]); if (methodInfo.parameterTypes[j] == FunctionPointer.class) { - logger.warn("Method \"" + methodInfo.method + "\" has an abstract FunctionPointer parameter, " + - "but a concrete subclass is required. Compilation will most likely fail."); + logger.warn("Method \"" + methodInfo.method + "\" has an abstract FunctionPointer parameter, " + "but a concrete subclass is required. Compilation will most likely fail."); } typeName[0] = functionClassName(methodInfo.parameterTypes[j]) + "*"; typeName[1] = ""; @@ -2272,27 +2249,20 @@ void parametersBefore(MethodInformation methodInfo) { } out.print(" " + typeName[0] + " ptr" + j + typeName[1] + " = "); if (Pointer.class.isAssignableFrom(methodInfo.parameterTypes[j])) { - out.println("arg" + j + " == NULL ? NULL : (" + typeName[0] + typeName[1] + - ")jlong_to_ptr(env->GetLongField(arg" + j + ", JavaCPP_addressFID));"); - if ((j == 0 && FunctionPointer.class.isAssignableFrom(methodInfo.cls) - && methodInfo.cls.isAnnotationPresent(Namespace.class)) - || (passBy instanceof ByVal && ((ByVal) passBy).nullValue().length() == 0) - || (passBy instanceof ByRef && ((ByRef) passBy).nullValue().length() == 0)) { + out.println("arg" + j + " == NULL ? NULL : (" + typeName[0] + typeName[1] + ")jlong_to_ptr(env->GetLongField(arg" + j + ", JavaCPP_addressFID));"); + if ((j == 0 && FunctionPointer.class.isAssignableFrom(methodInfo.cls) && methodInfo.cls.isAnnotationPresent(Namespace.class)) || (passBy instanceof ByVal && ((ByVal) passBy).nullValue().length() == 0) || (passBy instanceof ByRef && ((ByRef) passBy).nullValue().length() == 0)) { // in the case of member ptr, ptr0 is our object pointer, which cannot be NULL out.println(" if (ptr" + j + " == NULL) {"); - out.println(" env->ThrowNew(JavaCPP_getClass(env, " + - jclasses.index(NullPointerException.class) + "), \"Pointer address of argument " + j + " is NULL.\");"); + out.println(" env->ThrowNew(JavaCPP_getClass(env, " + jclasses.index(NullPointerException.class) + "), \"Pointer address of argument " + j + " is NULL.\");"); out.println(" return" + (methodInfo.returnType == void.class ? ";" : " 0;")); out.println(" }"); } if (adapterInfo != null || prevAdapterInfo != null) { - out.println(" jlong size" + j + " = arg" + j + " == NULL ? 0 : env->GetLongField(arg" + j + - ", JavaCPP_limitFID);"); + out.println(" jlong size" + j + " = arg" + j + " == NULL ? 0 : env->GetLongField(arg" + j + ", JavaCPP_limitFID);"); out.println(" void* owner" + j + " = JavaCPP_getPointerOwner(env, arg" + j + ");"); } if (!methodInfo.parameterTypes[j].isAnnotationPresent(Opaque.class)) { - out.println(" jlong position" + j + " = arg" + j + " == NULL ? 0 : env->GetLongField(arg" + j + - ", JavaCPP_positionFID);"); + out.println(" jlong position" + j + " = arg" + j + " == NULL ? 0 : env->GetLongField(arg" + j + ", JavaCPP_positionFID);"); out.println(" ptr" + j + " += position" + j + ";"); if (adapterInfo != null || prevAdapterInfo != null) { out.println(" size" + j + " -= position" + j + ";"); @@ -2305,27 +2275,23 @@ void parametersBefore(MethodInformation methodInfo) { out.println(" jlong size" + j + " = 0;"); out.println(" void* owner" + j + " = (void*)ptr" + j + ";"); } - } else if (methodInfo.parameterTypes[j].isArray() && - methodInfo.parameterTypes[j].getComponentType().isPrimitive()) { + } else if (methodInfo.parameterTypes[j].isArray() && methodInfo.parameterTypes[j].getComponentType().isPrimitive()) { out.print("arg" + j + " == NULL ? NULL : "); String s = methodInfo.parameterTypes[j].getComponentType().getName(); - if (methodInfo.criticalRegion || methodInfo.valueGetter || methodInfo.valueSetter || - methodInfo.memberGetter || methodInfo.memberSetter) { + if (methodInfo.criticalRegion || methodInfo.valueGetter || methodInfo.valueSetter || methodInfo.memberGetter || methodInfo.memberSetter) { out.println("(j" + s + "*)env->GetPrimitiveArrayCritical(arg" + j + ", NULL);"); } else { s = Character.toUpperCase(s.charAt(0)) + s.substring(1); out.println("env->Get" + s + "ArrayElements(arg" + j + ", NULL);"); } if (adapterInfo != null || prevAdapterInfo != null) { - out.println(" jlong size" + j + - " = arg" + j + " == NULL ? 0 : env->GetArrayLength(arg" + j + ");"); + out.println(" jlong size" + j + " = arg" + j + " == NULL ? 0 : env->GetArrayLength(arg" + j + ");"); out.println(" void* owner" + j + " = (void*)ptr" + j + ";"); } } else if (Buffer.class.isAssignableFrom(methodInfo.parameterTypes[j])) { out.println("arg" + j + " == NULL ? NULL : (" + typeName[0] + typeName[1] + ")env->GetDirectBufferAddress(arg" + j + ");"); if (adapterInfo != null || prevAdapterInfo != null) { - out.println(" jlong size" + j + " = arg" + j + " == NULL ? 0 : env->GetIntField(arg" + j + - ", JavaCPP_bufferLimitFID);"); + out.println(" jlong size" + j + " = arg" + j + " == NULL ? 0 : env->GetIntField(arg" + j + ", JavaCPP_bufferLimitFID);"); out.println(" void* owner" + j + " = (void*)ptr" + j + ";"); } if (methodInfo.parameterTypes[j] != Buffer.class) { @@ -2342,25 +2308,21 @@ void parametersBefore(MethodInformation methodInfo) { out.println(" return" + (methodInfo.returnType == void.class ? ";" : " 0;")); out.println(" } else {"); if (methodInfo.criticalRegion) { - out.println(" ptr" + j + " = arr" + j + " == NULL ? NULL : (" + typeName[0] + typeName[1] - + ")env->GetPrimitiveArrayCritical(arr" + j + ", NULL) + offset" + j + ";"); + out.println(" ptr" + j + " = arr" + j + " == NULL ? NULL : (" + typeName[0] + typeName[1] + ")env->GetPrimitiveArrayCritical(arr" + j + ", NULL) + offset" + j + ";"); } else { - out.println(" ptr" + j + " = arr" + j + " == NULL ? NULL : env->Get" - + paramName + "ArrayElements(arr" + j + ", NULL) + offset" + j + ";"); + out.println(" ptr" + j + " = arr" + j + " == NULL ? NULL : env->Get" + paramName + "ArrayElements(arr" + j + ", NULL) + offset" + j + ";"); } out.println(" }"); out.println(" }"); } - out.println(" jlong position" + j + " = arg" + j + " == NULL ? 0 : env->GetIntField(arg" + j + - ", JavaCPP_bufferPositionFID);"); + out.println(" jlong position" + j + " = arg" + j + " == NULL ? 0 : env->GetIntField(arg" + j + ", JavaCPP_bufferPositionFID);"); out.println(" ptr" + j + " += position" + j + ";"); if (adapterInfo != null || prevAdapterInfo != null) { out.println(" size" + j + " -= position" + j + ";"); } } else { out.println("arg" + j + ";"); - logger.warn("Method \"" + methodInfo.method + "\" has an unsupported parameter of type \"" + - methodInfo.parameterTypes[j].getCanonicalName() + "\". Compilation will most likely fail."); + logger.warn("Method \"" + methodInfo.method + "\" has an unsupported parameter of type \"" + methodInfo.parameterTypes[j].getCanonicalName() + "\". Compilation will most likely fail."); } if (adapterInfo != null) { @@ -2407,12 +2369,9 @@ String returnBefore(MethodInformation methodInfo) { } } else { String cast = cast(methodInfo.returnType, methodInfo.annotations); - String[] typeName = methodInfo.returnRaw ? new String[]{""} - : cppCastTypeName(methodInfo.returnType, methodInfo.annotations); + String[] typeName = methodInfo.returnRaw ? new String[]{""} : cppCastTypeName(methodInfo.returnType, methodInfo.annotations); Annotation returnBy = by(methodInfo.annotations); - if (FunctionPointer.class.isAssignableFrom(methodInfo.cls) - && !methodInfo.cls.isAnnotationPresent(Namespace.class) - && methodInfo.valueGetter) { + if (FunctionPointer.class.isAssignableFrom(methodInfo.cls) && !methodInfo.cls.isAnnotationPresent(Namespace.class) && methodInfo.valueGetter) { typeName = cppTypeName(methodInfo.cls); } if (methodInfo.valueSetter || methodInfo.memberSetter || methodInfo.noReturnGetter) { @@ -2439,10 +2398,7 @@ String returnBefore(MethodInformation methodInfo) { typeName[0] = jniTypeName(methodInfo.returnType); out.println(" " + typeName[0] + " rarg = NULL;"); out.println(" " + typeName[0] + " rptr;"); - } else if (Pointer.class.isAssignableFrom(methodInfo.returnType) || - Buffer.class.isAssignableFrom(methodInfo.returnType) || - (methodInfo.returnType.isArray() && - methodInfo.returnType.getComponentType().isPrimitive())) { + } else if (Pointer.class.isAssignableFrom(methodInfo.returnType) || Buffer.class.isAssignableFrom(methodInfo.returnType) || (methodInfo.returnType.isArray() && methodInfo.returnType.getComponentType().isPrimitive())) { if (FunctionPointer.class.isAssignableFrom(methodInfo.returnType)) { functions.index(methodInfo.returnType); returnPrefix = "if (rptr != NULL) rptr->ptr = "; @@ -2455,8 +2411,7 @@ String returnBefore(MethodInformation methodInfo) { valueTypeName = valueTypeName(typeName); } if (returnBy instanceof ByVal || (returnBy instanceof ByRef && ((ByRef) returnBy).value())) { - returnPrefix += (noException(methodInfo.returnType, methodInfo.method) ? - "new (std::nothrow) " : "new ") + valueTypeName + typeName[1] + "("; + returnPrefix += (noException(methodInfo.returnType, methodInfo.method) ? "new (std::nothrow) " : "new ") + valueTypeName + typeName[1] + "("; } else if (returnBy instanceof ByRef) { returnPrefix += "&"; } else if (returnBy instanceof ByPtrPtr) { @@ -2465,8 +2420,7 @@ String returnBefore(MethodInformation methodInfo) { } returnPrefix = "rptr = NULL; " + typeName[0] + "* rptrptr" + typeName[1] + " = " + cast; } // else ByPtr || ByPtrRef - if (adapterInfo != null && methodInfo.returnType.isArray() && - methodInfo.returnType.getComponentType().isPrimitive()) { + if (adapterInfo != null && methodInfo.returnType.isArray() && methodInfo.returnType.getComponentType().isPrimitive()) { // data will get copied out anyway if (!typeName[0].startsWith("const ")) { typeName[0] = "const " + typeName[0]; @@ -2503,8 +2457,7 @@ String returnBefore(MethodInformation methodInfo) { returnPrefix += "(" + typeName[0] + ")"; } } else { - logger.warn("Method \"" + methodInfo.method + "\" has unsupported return type \"" + - methodInfo.returnType.getCanonicalName() + "\". Compilation will most likely fail."); + logger.warn("Method \"" + methodInfo.method + "\" has unsupported return type \"" + methodInfo.returnType.getCanonicalName() + "\". Compilation will most likely fail."); } if (adapterInfo != null) { @@ -2541,15 +2494,10 @@ void call(MethodInformation methodInfo, String returnPrefix, boolean secondCall) out.println(indent + " (*deallocatorAddress)(allocatedAddress);"); out.println(indent + "}"); return; // nothing else should be appended here for deallocator - } else if (!FunctionPointer.class.isAssignableFrom(methodInfo.cls) && - (methodInfo.valueGetter || methodInfo.valueSetter || - methodInfo.memberGetter || methodInfo.memberSetter)) { + } else if (!FunctionPointer.class.isAssignableFrom(methodInfo.cls) && (methodInfo.valueGetter || methodInfo.valueSetter || methodInfo.memberGetter || methodInfo.memberSetter)) { boolean wantsPointer = false; int k = methodInfo.parameterTypes.length - 1; - if ((methodInfo.valueSetter || methodInfo.memberSetter) && - !(by(methodInfo, k) instanceof ByRef) && - adapterInformation(false, methodInfo, k) == null && - methodInfo.parameterTypes[k] == String.class) { + if ((methodInfo.valueSetter || methodInfo.memberSetter) && !(by(methodInfo, k) instanceof ByRef) && adapterInformation(false, methodInfo, k) == null && methodInfo.parameterTypes[k] == String.class) { // special considerations for char arrays as strings if (asUtf16(methodInfo, k)) { out.print(indent + "memcpy("); @@ -2559,10 +2507,7 @@ void call(MethodInformation methodInfo, String returnPrefix, boolean secondCall) } wantsPointer = true; prefix = ", "; - } else if (k >= 1 && methodInfo.parameterTypes[0].isArray() && - methodInfo.parameterTypes[0].getComponentType().isPrimitive() && - (methodInfo.parameterTypes[1] == int.class || - methodInfo.parameterTypes[1] == long.class)) { + } else if (k >= 1 && methodInfo.parameterTypes[0].isArray() && methodInfo.parameterTypes[0].getComponentType().isPrimitive() && (methodInfo.parameterTypes[1] == int.class || methodInfo.parameterTypes[1] == long.class)) { // special considerations for primitive arrays out.print(indent + "memcpy("); wantsPointer = true; @@ -2636,8 +2581,7 @@ void call(MethodInformation methodInfo, String returnPrefix, boolean secondCall) out.print(methodInfo.memberName[0]); // If method is an array allocator, the function must return a pointer to an array } else { - out.print((noException(methodInfo.cls, methodInfo.method) ? - "new (std::nothrow) " : "new ") + valueTypeName + typeName[1]); + out.print((noException(methodInfo.cls, methodInfo.method) ? "new (std::nothrow) " : "new ") + valueTypeName + typeName[1]); if (methodInfo.arrayAllocator) { prefix = "["; suffix = "]"; @@ -2670,9 +2614,7 @@ void call(MethodInformation methodInfo, String returnPrefix, boolean secondCall) prefix = "." + name + prefix; } else { String op = name.startsWith("operator") ? name.substring(8).trim() : ""; - if (methodInfo.parameterTypes.length > 0 - && (op.equals("=") || op.equals("+") || op.equals("-") || op.equals("*") || op.equals("/") || op.equals("%") - || op.equals("==") || op.equals("!=") || op.equals("<") || op.equals(">") || op.equals("<=") || op.equals(">="))) { + if (methodInfo.parameterTypes.length > 0 && (op.equals("=") || op.equals("+") || op.equals("-") || op.equals("*") || op.equals("/") || op.equals("%") || op.equals("==") || op.equals("!=") || op.equals("<") || op.equals(">") || op.equals("<=") || op.equals(">="))) { out.print("((*ptr)"); prefix = op + prefix; suffix += ")"; @@ -2710,20 +2652,16 @@ void call(MethodInformation methodInfo, String returnPrefix, boolean secondCall) } Annotation passBy = by(methodInfo, j); String cast = cast(methodInfo, j); - AdapterInformation adapterInfo = methodInfo.parameterRaw[j] ? null - : adapterInformation(false, methodInfo, j); + AdapterInformation adapterInfo = methodInfo.parameterRaw[j] ? null : adapterInformation(false, methodInfo, j); - if (FunctionPointer.class.isAssignableFrom(methodInfo.cls) - && !methodInfo.cls.isAnnotationPresent(Namespace.class) - && methodInfo.valueSetter) { + if (FunctionPointer.class.isAssignableFrom(methodInfo.cls) && !methodInfo.cls.isAnnotationPresent(Namespace.class) && methodInfo.valueSetter) { String[] typeName = cppTypeName(methodInfo.cls); cast = "(" + typeName[0] + typeName[1] + ")"; } if (Enum.class.isAssignableFrom(methodInfo.parameterTypes[j])) { accessesEnums = true; out.print(cast + "val" + j); - } else if (("(void*)".equals(cast) || "(void *)".equals(cast)) && - methodInfo.parameterTypes[j] == long.class) { + } else if (("(void*)".equals(cast) || "(void *)".equals(cast)) && methodInfo.parameterTypes[j] == long.class) { out.print("jlong_to_ptr(arg" + j + ")"); } else if (methodInfo.parameterTypes[j].isPrimitive()) { if (passBy instanceof ByPtr || passBy instanceof ByPtrRef) { @@ -2743,8 +2681,7 @@ void call(MethodInformation methodInfo, String returnPrefix, boolean secondCall) } out.print(cast + cast2 + "adapter" + j); j += adapterInfo.argc - 1; - } else if (FunctionPointer.class.isAssignableFrom(methodInfo.parameterTypes[j]) - && (!(passBy instanceof ByVal || passBy instanceof ByRef) || cast.length() > 0)) { + } else if (FunctionPointer.class.isAssignableFrom(methodInfo.parameterTypes[j]) && (!(passBy instanceof ByVal || passBy instanceof ByRef) || cast.length() > 0)) { if (passBy instanceof ByPtrRef) { out.print(cast + "(ptr" + j + "->ptr)"); } else { @@ -2753,11 +2690,9 @@ void call(MethodInformation methodInfo, String returnPrefix, boolean secondCall) } out.print(cast + "(ptr" + j + " == NULL ? NULL : " + (passBy instanceof ByPtrPtr ? "&ptr" : "ptr") + j + "->ptr)"); } - } else if (passBy instanceof ByVal || (passBy instanceof ByRef && - methodInfo.parameterTypes[j] != String.class)) { + } else if (passBy instanceof ByVal || (passBy instanceof ByRef && methodInfo.parameterTypes[j] != String.class)) { boolean rvalue = passBy instanceof ByRef ? ((ByRef) passBy).value() : false; - String nullValue = passBy instanceof ByVal ? ((ByVal) passBy).nullValue() - : passBy instanceof ByRef ? ((ByRef) passBy).nullValue() : ""; + String nullValue = passBy instanceof ByVal ? ((ByVal) passBy).nullValue() : passBy instanceof ByRef ? ((ByRef) passBy).nullValue() : ""; if (rvalue) { out.print("std::move("); } @@ -2793,35 +2728,26 @@ void call(MethodInformation methodInfo, String returnPrefix, boolean secondCall) void returnAfter(MethodInformation methodInfo) { String indent = methodInfo.throwsException != null ? " " : " "; - String[] typeName = methodInfo.allocator || methodInfo.arrayAllocator - ? cppTypeName(methodInfo.cls) : methodInfo.returnRaw ? new String[]{""} - : cppCastTypeName(methodInfo.returnType, methodInfo.annotations); + String[] typeName = methodInfo.allocator || methodInfo.arrayAllocator ? cppTypeName(methodInfo.cls) : methodInfo.returnRaw ? new String[]{""} : cppCastTypeName(methodInfo.returnType, methodInfo.annotations); Annotation returnBy = by(methodInfo.annotations); String valueTypeName = valueTypeName(typeName); AdapterInformation adapterInfo = adapterInformation(false, valueTypeName, methodInfo.annotations); String suffix = methodInfo.deallocator ? "" : ";"; - if (by(methodInfo.annotations) instanceof ByRef - && methodInfo.returnType == String.class - && adapterInfo == null) { + if (by(methodInfo.annotations) instanceof ByRef && methodInfo.returnType == String.class && adapterInfo == null) { // special considerations for std::string without adapter out.print(");\n" + indent + "rptr = rstr.c_str()"); } if ((methodInfo.allocator || methodInfo.arrayAllocator || !methodInfo.returnType.isPrimitive()) && adapterInfo != null) { suffix = ")" + suffix; } - if ((Pointer.class.isAssignableFrom(methodInfo.returnType) || - (methodInfo.returnType.isArray() && - methodInfo.returnType.getComponentType().isPrimitive()) || - Buffer.class.isAssignableFrom(methodInfo.returnType)) || - methodInfo.returnType == String.class) { + if ((Pointer.class.isAssignableFrom(methodInfo.returnType) || (methodInfo.returnType.isArray() && methodInfo.returnType.getComponentType().isPrimitive()) || Buffer.class.isAssignableFrom(methodInfo.returnType)) || methodInfo.returnType == String.class) { if ((returnBy instanceof ByVal || (returnBy instanceof ByRef && ((ByRef) returnBy).value())) && adapterInfo == null) { suffix = ")" + suffix; } else if (returnBy instanceof ByPtrPtr) { out.println(suffix); suffix = ""; out.println(indent + "if (rptrptr == NULL) {"); - out.println(indent + " env->ThrowNew(JavaCPP_getClass(env, " + - jclasses.index(NullPointerException.class) + "), \"Return pointer address is NULL.\");"); + out.println(indent + " env->ThrowNew(JavaCPP_getClass(env, " + jclasses.index(NullPointerException.class) + "), \"Return pointer address is NULL.\");"); out.println(indent + "} else {"); if (FunctionPointer.class.isAssignableFrom(methodInfo.returnType)) { out.println(indent + " rptr->ptr = *rptrptr;"); @@ -2830,8 +2756,7 @@ void returnAfter(MethodInformation methodInfo) { } out.println(indent + "}"); } - if (adapterInfo != null && methodInfo.returnType.isArray() && - methodInfo.returnType.getComponentType().isPrimitive()) { + if (adapterInfo != null && methodInfo.returnType.isArray() && methodInfo.returnType.getComponentType().isPrimitive()) { // data will get copied out anyway if (!typeName[0].startsWith("const ")) { typeName[0] = "const " + typeName[0]; @@ -2840,17 +2765,15 @@ void returnAfter(MethodInformation methodInfo) { } out.println(suffix); + if (methodInfo.returnType == void.class) { if (methodInfo.allocator || methodInfo.arrayAllocator) { - boolean noDeallocator = methodInfo.cls == Pointer.class || - methodInfo.cls.isAnnotationPresent(NoDeallocator.class) || - methodInfo.method.isAnnotationPresent(NoDeallocator.class); + boolean noDeallocator = methodInfo.cls == Pointer.class || methodInfo.cls.isAnnotationPresent(NoDeallocator.class) || methodInfo.method.isAnnotationPresent(NoDeallocator.class); if (adapterInfo != null) { out.println(indent + typeName[0] + " rptr" + typeName[1] + " = radapter;"); out.println(indent + "jlong rcapacity = (jlong)radapter.size;"); out.println(indent + "void* rowner = radapter.owner;"); - if (noDeallocator) - out.println(indent + "void (*deallocator)(void*) = 0;"); + if (noDeallocator) out.println(indent + "void (*deallocator)(void*) = 0;"); else out.println(indent + "void (*deallocator)(void*) = rowner != NULL ? &" + adapterInfo.name + "::deallocate : 0;"); out.println(indent + "JavaCPP_initPointer(env, obj, rptr, rcapacity, rowner, deallocator);"); @@ -2906,12 +2829,10 @@ void returnAfter(MethodInformation methodInfo) { } } needInit = true; - } else if (returnBy instanceof ByVal || - FunctionPointer.class.isAssignableFrom(methodInfo.returnType)) { + } else if (returnBy instanceof ByVal || FunctionPointer.class.isAssignableFrom(methodInfo.returnType)) { out.println(indent + "jlong rcapacity = 1;"); out.println(indent + "void* rowner = (void*)rptr;"); - out.println(indent + "void (*deallocator)(void*) = &JavaCPP_" + - mangle(methodInfo.returnType.getName()) + "_deallocate;"); + out.println(indent + "void (*deallocator)(void*) = &JavaCPP_" + mangle(methodInfo.returnType.getName()) + "_deallocate;"); deallocators.index(methodInfo.returnType); needInit = true; } @@ -2923,9 +2844,7 @@ void returnAfter(MethodInformation methodInfo) { if (Modifier.isStatic(methodInfo.modifiers) && methodInfo.parameterTypes.length > 0) { for (int i = 0; i < methodInfo.parameterTypes.length; i++) { String cast = cast(methodInfo, i); - if (Arrays.equals(methodInfo.parameterAnnotations[i], methodInfo.annotations) - && methodInfo.parameterTypes[i] == methodInfo.returnType - && !(returnBy instanceof ByPtrPtr) && !(returnBy instanceof ByPtrRef)) { + if (Arrays.equals(methodInfo.parameterAnnotations[i], methodInfo.annotations) && methodInfo.parameterTypes[i] == methodInfo.returnType && !(returnBy instanceof ByPtrPtr) && !(returnBy instanceof ByPtrRef)) { out.println("if (rptr == " + cast + "ptr" + i + ") {"); out.println(indent + " rarg = arg" + i + ";"); out.print(indent + "} else "); @@ -2938,8 +2857,7 @@ void returnAfter(MethodInformation methodInfo) { } } out.println("if (rptr != NULL) {"); - out.println(indent + " rarg = JavaCPP_createPointer(env, " + jclasses.index(methodInfo.returnType) + - (methodInfo.parameterTypes.length > 0 && methodInfo.parameterTypes[0] == Class.class ? ", arg0);" : ");")); + out.println(indent + " rarg = JavaCPP_createPointer(env, " + jclasses.index(methodInfo.returnType) + (methodInfo.parameterTypes.length > 0 && methodInfo.parameterTypes[0] == Class.class ? ", arg0);" : ");")); out.println(indent + " if (rarg != NULL) {"); if (needInit) { out.println(indent + " JavaCPP_initPointer(env, rarg, rptr, rcapacity, rowner, deallocator);"); @@ -2953,8 +2871,7 @@ void returnAfter(MethodInformation methodInfo) { out.println(indent + "if (rptr != NULL) {"); out.println(indent + " rarg = " + createString("rptr", (adapterInfo != null ? "radapter" : null), asUtf16(methodInfo.annotations))); out.println(indent + "}"); - } else if (methodInfo.returnType.isArray() && - methodInfo.returnType.getComponentType().isPrimitive()) { + } else if (methodInfo.returnType.isArray() && methodInfo.returnType.getComponentType().isPrimitive()) { if (adapterInfo == null && !(returnBy instanceof ByVal)) { out.println(indent + "jlong rcapacity = rptr != NULL ? 1 : 0;"); } @@ -3030,22 +2947,18 @@ void parametersAfter(MethodInformation methodInfo) { out.println(" if (rptr" + (j + k) + " != " + cast + "ptr" + (j + k) + ") {"); out.println(" JavaCPP_initPointer(env, arg" + j + ", rptr" + (j + k) + ", rsize" + (j + k) + ", rowner" + (j + k) + ", &" + adapterInfo.name + "::deallocate);"); out.println(" } else {"); - out.println(" env->SetLongField(arg" + j + ", JavaCPP_limitFID, rsize" + (j + k) - + (!methodInfo.parameterTypes[j].isAnnotationPresent(Opaque.class) ? " + position" + (j + k) : "") + ");"); + out.println(" env->SetLongField(arg" + j + ", JavaCPP_limitFID, rsize" + (j + k) + (!methodInfo.parameterTypes[j].isAnnotationPresent(Opaque.class) ? " + position" + (j + k) : "") + ");"); out.println(" }"); } - } else if ((passBy instanceof ByPtrPtr || passBy instanceof ByPtrRef) && - !methodInfo.valueSetter && !methodInfo.memberSetter) { + } else if ((passBy instanceof ByPtrPtr || passBy instanceof ByPtrRef) && !methodInfo.valueSetter && !methodInfo.memberSetter) { if (!methodInfo.parameterTypes[j].isAnnotationPresent(Opaque.class)) { out.println(" ptr" + j + " -= position" + j + ";"); } - out.println(" if (arg" + j + " != NULL) env->SetLongField(arg" + j + - ", JavaCPP_addressFID, ptr_to_jlong(ptr" + j + "));"); + out.println(" if (arg" + j + " != NULL) env->SetLongField(arg" + j + ", JavaCPP_addressFID, ptr_to_jlong(ptr" + j + "));"); } } else if (methodInfo.parameterTypes[j] == String.class) { out.println(" " + releaseStringData("arg" + j, "ptr" + j, asUtf16(methodInfo, j))); - } else if (methodInfo.parameterTypes[j].isArray() && - methodInfo.parameterTypes[j].getComponentType().isPrimitive()) { + } else if (methodInfo.parameterTypes[j].isArray() && methodInfo.parameterTypes[j].getComponentType().isPrimitive()) { for (int k = 0; adapterInfo != null && k < adapterInfo.argc; k++) { out.println(" " + typeName[0] + " rptr" + (j + k) + typeName[1] + " = " + cast + "adapter" + j + ";"); out.println(" void* rowner" + (j + k) + " = adapter" + j + ".owner" + (k > 0 ? (k + 1) + ";" : ";")); @@ -3054,16 +2967,14 @@ void parametersAfter(MethodInformation methodInfo) { out.println(" }"); } out.print(" if (arg" + j + " != NULL) "); - if (methodInfo.criticalRegion || methodInfo.valueGetter || methodInfo.valueSetter || - methodInfo.memberGetter || methodInfo.memberSetter) { + if (methodInfo.criticalRegion || methodInfo.valueGetter || methodInfo.valueSetter || methodInfo.memberGetter || methodInfo.memberSetter) { out.println("env->ReleasePrimitiveArrayCritical(arg" + j + ", ptr" + j + ", " + releaseArrayFlag + ");"); } else { String componentType = methodInfo.parameterTypes[j].getComponentType().getName(); String componentTypeUpperCase = Character.toUpperCase(componentType.charAt(0)) + componentType.substring(1); out.println("env->Release" + componentTypeUpperCase + "ArrayElements(arg" + j + ", (j" + componentType + "*)ptr" + j + ", " + releaseArrayFlag + ");"); } - } else if (Buffer.class.isAssignableFrom(methodInfo.parameterTypes[j]) - && methodInfo.parameterTypes[j] != Buffer.class) { + } else if (Buffer.class.isAssignableFrom(methodInfo.parameterTypes[j]) && methodInfo.parameterTypes[j] != Buffer.class) { for (int k = 0; adapterInfo != null && k < adapterInfo.argc; k++) { out.println(" " + typeName[0] + " rptr" + (j + k) + typeName[1] + " = " + cast + "adapter" + j + ";"); out.println(" void* rowner" + (j + k) + " = adapter" + j + ".owner" + (k > 0 ? (k + 1) + ";" : ";")); @@ -3078,9 +2989,7 @@ void parametersAfter(MethodInformation methodInfo) { if (methodInfo.criticalRegion) { out.println("env->ReleasePrimitiveArrayCritical(arr" + j + ", ptr" + j + " - position" + j + ", " + releaseArrayFlag + ");"); } else { - out.println("env->Release" + parameterSimpleName + "ArrayElements(arr" + j + ", " + - "(j" + parameterSimpleNameLowerCase + "*)(ptr" + j + " - position" + j + "), " + - releaseArrayFlag + ");"); + out.println("env->Release" + parameterSimpleName + "ArrayElements(arr" + j + ", " + "(j" + parameterSimpleNameLowerCase + "*)(ptr" + j + " - position" + j + "), " + releaseArrayFlag + ");"); } } } @@ -3095,8 +3004,7 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo String instanceTypeName = functionClassName(cls); String[] callbackTypeName = cppFunctionTypeName(callbackMethod); String[] returnConvention = callbackTypeName[0].split("\\("); - String[] returnType = {returnConvention[0] + (returnConvention.length > 2 ? "(*" : ""), - returnConvention.length > 2 ? ")(" + returnConvention[2] : ""}; + String[] returnType = {returnConvention[0] + (returnConvention.length > 2 ? "(*" : ""), returnConvention.length > 2 ? ")(" + returnConvention[2] : ""}; if (returnConvention.length > 2) { returnConvention = Arrays.copyOfRange(returnConvention, 2, returnConvention.length); } @@ -3125,11 +3033,8 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo String firstLine = ""; if (methodInfo != null) { // stuff from a virtualized class - String nonconstParamDeclaration = parameterDeclaration.endsWith(" const") - ? parameterDeclaration.substring(0, parameterDeclaration.length() - 6) - : parameterDeclaration; - String[] typeName = methodInfo.returnRaw ? new String[]{""} - : cppTypeName(methodInfo.cls); + String nonconstParamDeclaration = parameterDeclaration.endsWith(" const") ? parameterDeclaration.substring(0, parameterDeclaration.length() - 6) : parameterDeclaration; + String[] typeName = methodInfo.returnRaw ? new String[]{""} : cppTypeName(methodInfo.cls); String valueTypeName = valueTypeName(typeName); String subType = "JavaCPP_" + mangle(valueTypeName); Set memberList = virtualMembers.get(cls); @@ -3158,17 +3063,14 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo if (needUsing) { member += usingLine + "\n "; } - member += "virtual " + returnType[0] + (returnConvention.length > 1 ? returnConvention[1] : "") - + methodInfo.memberName[0] + parameterDeclaration + returnType[1] + " JavaCPP_override;\n " - + returnType[0] + "super_" + methodInfo.name + nonconstParamDeclaration + returnType[1] + " { "; + member += "virtual " + returnType[0] + (returnConvention.length > 1 ? returnConvention[1] : "") + methodInfo.memberName[0] + parameterDeclaration + returnType[1] + " JavaCPP_override;\n " + returnType[0] + "super_" + methodInfo.name + nonconstParamDeclaration + returnType[1] + " { "; if (methodInfo.method.getAnnotation(Virtual.class).value()) { member += "throw JavaCPP_exception(\"Cannot call pure virtual function " + valueTypeName + "::" + methodInfo.memberName[0] + "().\"); }"; } else { member += (callbackReturnType != void.class ? "return " : "") + valueTypeName + "::" + methodInfo.memberName[0] + "("; member += callbackArguments + "); }"; } - firstLine = returnType[0] + (returnConvention.length > 1 ? returnConvention[1] : "") - + subType + "::" + methodInfo.memberName[0] + parameterDeclaration + returnType[1] + " {"; + firstLine = returnType[0] + (returnConvention.length > 1 ? returnConvention[1] : "") + subType + "::" + methodInfo.memberName[0] + parameterDeclaration + returnType[1] + " {"; functionList.add(fieldName); } memberList.add(member); @@ -3183,11 +3085,9 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo } for (int i = 0; i < allocatorMax; i++) { if (out2 != null) { - out2.println("JNIIMPORT " + returnType[0] + (returnConvention.length > 1 ? - returnConvention[1] : "") + callbackName + (i > 0 ? i : "") + parameterDeclaration + returnType[1] + ";"); + out2.println("JNIIMPORT " + returnType[0] + (returnConvention.length > 1 ? returnConvention[1] : "") + callbackName + (i > 0 ? i : "") + parameterDeclaration + returnType[1] + ";"); } - out.println("JNIEXPORT " + returnType[0] + (returnConvention.length > 1 ? - returnConvention[1] : "") + callbackName + (i > 0 ? i : "") + parameterDeclaration + returnType[1] + " {"); + out.println("JNIEXPORT " + returnType[0] + (returnConvention.length > 1 ? returnConvention[1] : "") + callbackName + (i > 0 ? i : "") + parameterDeclaration + returnType[1] + " {"); out.print((callbackReturnType != void.class ? " return " : " ") + instanceTypeName + "_instances[" + i + "]("); out.println(callbackArguments + ");"); out.println("}"); @@ -3198,8 +3098,7 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo out2.println("}"); } } - out.println("static " + returnType[0] + "(" + (returnConvention.length > 1 ? - returnConvention[1] : "") + "*" + callbackName + "s[" + allocatorMax + "])" + parameterDeclaration + returnType[1] + " = {"); + out.println("static " + returnType[0] + "(" + (returnConvention.length > 1 ? returnConvention[1] : "") + "*" + callbackName + "s[" + allocatorMax + "])" + parameterDeclaration + returnType[1] + " = {"); for (int i = 0; i < allocatorMax; i++) { out.print(" " + callbackName + (i > 0 ? i : "")); if (i + 1 < allocatorMax) { @@ -3245,10 +3144,7 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo for (int j = 0; j < callbackParameterTypes.length; j++) { Annotation passBy = by(callbackParameterAnnotations[j]); if (callbackParameterTypes[j].isPrimitive()) { - out.println(" args[" + j + "]." + - signature(callbackParameterTypes[j]).toLowerCase() + " = (" + - jniTypeName(callbackParameterTypes[j]) + ")" + - (passBy instanceof ByPtr || passBy instanceof ByPtrRef ? "*arg" : "arg") + j + ";"); + out.println(" args[" + j + "]." + signature(callbackParameterTypes[j]).toLowerCase() + " = (" + jniTypeName(callbackParameterTypes[j]) + ")" + (passBy instanceof ByPtr || passBy instanceof ByPtrRef ? "*arg" : "arg") + j + ";"); } else if (Enum.class.isAssignableFrom(callbackParameterTypes[j])) { accessesEnums = true; String s = enumValueType(callbackParameterTypes[j]); @@ -3274,10 +3170,7 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo out.println(" " + adapterInfo.name + " adapter" + j + "(" + cast2 + "arg" + j + ");"); } - if (Pointer.class.isAssignableFrom(callbackParameterTypes[j]) || - Buffer.class.isAssignableFrom(callbackParameterTypes[j]) || - (callbackParameterTypes[j].isArray() && - callbackParameterTypes[j].getComponentType().isPrimitive())) { + if (Pointer.class.isAssignableFrom(callbackParameterTypes[j]) || Buffer.class.isAssignableFrom(callbackParameterTypes[j]) || (callbackParameterTypes[j].isArray() && callbackParameterTypes[j].getComponentType().isPrimitive())) { String cast = "(" + typeName[0] + typeName[1] + ")"; if (FunctionPointer.class.isAssignableFrom(callbackParameterTypes[j])) { functions.index(callbackParameterTypes[j]); @@ -3298,9 +3191,7 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo } else if (adapterInfo != null) { out.println(" ptr" + j + " = adapter" + j + ";"); } else if (passBy instanceof ByVal && callbackParameterTypes[j] != Pointer.class) { - out.println(" ptr" + j + (noException(callbackParameterTypes[j], callbackMethod) ? - " = new (std::nothrow) " : " = new ") + valueTypeName + typeName[1] + - "(*" + cast + "&arg" + j + ");"); + out.println(" ptr" + j + (noException(callbackParameterTypes[j], callbackMethod) ? " = new (std::nothrow) " : " = new ") + valueTypeName + typeName[1] + "(*" + cast + "&arg" + j + ");"); } else if (passBy instanceof ByVal || passBy instanceof ByRef) { out.println(" ptr" + j + " = " + cast + "&arg" + j + ";"); } else if (passBy instanceof ByPtrPtr) { @@ -3322,12 +3213,10 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo out.println(" void (*deallocator" + j + ")(void*) = &" + adapterInfo.name + "::deallocate;"); } needInit = true; - } else if ((passBy instanceof ByVal && callbackParameterTypes[j] != Pointer.class) || - FunctionPointer.class.isAssignableFrom(callbackParameterTypes[j])) { + } else if ((passBy instanceof ByVal && callbackParameterTypes[j] != Pointer.class) || FunctionPointer.class.isAssignableFrom(callbackParameterTypes[j])) { out.println(" jlong size" + j + " = 1;"); out.println(" void* owner" + j + " = ptr" + j + ";"); - out.println(" void (*deallocator" + j + ")(void*) = &JavaCPP_" + - mangle(callbackParameterTypes[j].getName()) + "_deallocate;"); + out.println(" void (*deallocator" + j + ")(void*) = &JavaCPP_" + mangle(callbackParameterTypes[j].getName()) + "_deallocate;"); deallocators.index(callbackParameterTypes[j]); needInit = true; } @@ -3362,8 +3251,7 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo out.println(" " + typeName[0] + " ptr" + j + typeName[1] + " = (" + typeName[0] + typeName[1] + ")" + (adapterInfo != null ? "adapter" : "arg") + j + ";"); out.println(" jstring obj" + j + " = " + createString("ptr" + j, (adapterInfo != null ? "adapter" + j : null), asUtf16(callbackParameterAnnotations[j]))); out.println(" args[" + j + "].l = obj" + j + ";"); - } else if (callbackParameterTypes[j].isArray() && - callbackParameterTypes[j].getComponentType().isPrimitive()) { + } else if (callbackParameterTypes[j].isArray() && callbackParameterTypes[j].getComponentType().isPrimitive()) { if (adapterInfo == null) { out.println(" jlong size" + j + " = ptr" + j + " != NULL ? 1 : 0;"); } @@ -3389,8 +3277,7 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo out.println(" }"); out.println(" args[" + j + "].l = obj" + j + ";"); } else { - logger.warn("Callback \"" + callbackMethod + "\" has unsupported parameter type \"" + - callbackParameterTypes[j].getCanonicalName() + "\". Compilation will most likely fail."); + logger.warn("Callback \"" + callbackMethod + "\" has unsupported parameter type \"" + callbackParameterTypes[j].getCanonicalName() + "\". Compilation will most likely fail."); } } } @@ -3400,8 +3287,7 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo Virtual virtual = callbackMethod.getAnnotation(Virtual.class); String methodName = (virtual != null && virtual.method().length() > 0) ? virtual.method() : methodInfo.method.getName(); out.println(" if (" + fieldName + " == NULL) {"); - out.println(" " + fieldName + " = JavaCPP_getMethodID(env, " + jclasses.index(cls) + ", \"" + methodName + "\", \"(" + - signature(methodInfo.method.getParameterTypes()) + ")" + signature(methodInfo.method.getReturnType()) + "\");"); + out.println(" " + fieldName + " = JavaCPP_getMethodID(env, " + jclasses.index(cls) + ", \"" + methodName + "\", \"(" + signature(methodInfo.method.getParameterTypes()) + ")" + signature(methodInfo.method.getReturnType()) + "\");"); out.println(" }"); out.println(" jmethodID mid = " + fieldName + ";"); } else if (callbackName != null) { @@ -3421,8 +3307,7 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo out.println(" }"); out.println(" }"); out.println(" if (mid == NULL) {"); - out.println(" mid = JavaCPP_getMethodID(env, " + jclasses.index(cls) + ", \"" + callbackMethod.getName() + "\", \"(" + - signature(callbackMethod.getParameterTypes()) + ")" + signature(callbackMethod.getReturnType()) + "\");"); + out.println(" mid = JavaCPP_getMethodID(env, " + jclasses.index(cls) + ", \"" + callbackMethod.getName() + "\", \"(" + signature(callbackMethod.getParameterTypes()) + ")" + signature(callbackMethod.getReturnType()) + "\");"); out.println(" }"); } out.println(" if (obj == NULL) {"); @@ -3455,8 +3340,7 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo typeName[0] = "char*"; } if (adapterInfo != null || passBy instanceof ByPtrPtr || passBy instanceof ByPtrRef) { - out.println(" " + typeName[0] + " rptr" + j + typeName[1] + " = (" + - typeName[0] + typeName[1] + ")jlong_to_ptr(env->GetLongField(obj" + j + ", JavaCPP_addressFID));"); + out.println(" " + typeName[0] + " rptr" + j + typeName[1] + " = (" + typeName[0] + typeName[1] + ")jlong_to_ptr(env->GetLongField(obj" + j + ", JavaCPP_addressFID));"); if (adapterInfo != null) { out.println(" jlong rsize" + j + " = env->GetLongField(obj" + j + ", JavaCPP_limitFID);"); out.println(" void* rowner" + j + " = JavaCPP_getPointerOwner(env, obj" + j + ");"); @@ -3498,8 +3382,7 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo out.println(" if (rarg == NULL) {"); out.println(" JavaCPP_log(\"Enum for return is NULL in callback for " + cls.getCanonicalName() + ".\");"); out.println(" }"); - out.println(" " + returnTypeName[0] + " rval" + returnTypeName[1] + " = (" + returnTypeName[0] + returnTypeName[1] + - ")(rarg == NULL ? 0 : env->Get" + S + "Field(rarg, JavaCPP_" + s + "ValueFID));"); + out.println(" " + returnTypeName[0] + " rval" + returnTypeName[1] + " = (" + returnTypeName[0] + returnTypeName[1] + ")(rarg == NULL ? 0 : env->Get" + S + "Field(rarg, JavaCPP_" + s + "ValueFID));"); } } else if (Pointer.class.isAssignableFrom(callbackReturnType)) { if (FunctionPointer.class.isAssignableFrom(callbackReturnType)) { @@ -3507,8 +3390,7 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo returnTypeName[0] = functionClassName(callbackReturnType) + "*"; returnTypeName[1] = ""; } - out.println(" " + returnTypeName[0] + " rptr" + returnTypeName[1] + " = rarg == NULL ? NULL : (" + - returnTypeName[0] + returnTypeName[1] + ")jlong_to_ptr(env->GetLongField(rarg, JavaCPP_addressFID));"); + out.println(" " + returnTypeName[0] + " rptr" + returnTypeName[1] + " = rarg == NULL ? NULL : (" + returnTypeName[0] + returnTypeName[1] + ")jlong_to_ptr(env->GetLongField(rarg, JavaCPP_addressFID));"); if (returnAdapterInfo != null) { out.println(" jlong rsize = rarg == NULL ? 0 : env->GetLongField(rarg, JavaCPP_limitFID);"); out.println(" void* rowner = JavaCPP_getPointerOwner(env, rarg);"); @@ -3528,8 +3410,7 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo out.println(" void* rowner = (void*)rptr;"); } } else if (Buffer.class.isAssignableFrom(callbackReturnType)) { - out.println(" " + returnTypeName[0] + " rptr" + returnTypeName[1] + " = rarg == NULL ? NULL : (" - + returnTypeName[0] + returnTypeName[1] + ")env->GetDirectBufferAddress(rarg);"); + out.println(" " + returnTypeName[0] + " rptr" + returnTypeName[1] + " = rarg == NULL ? NULL : (" + returnTypeName[0] + returnTypeName[1] + ")env->GetDirectBufferAddress(rarg);"); if (returnAdapterInfo != null) { out.println(" jlong rsize = rarg == NULL ? 0 : env->GetIntField(rarg, JavaCPP_bufferLimitFID);"); out.println(" void* rowner = (void*)rptr;"); @@ -3538,8 +3419,7 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo out.println(" rsize -= rposition;"); } } else if (!callbackReturnType.isPrimitive()) { - logger.warn("Callback \"" + callbackMethod + "\" has unsupported return type \"" + - callbackReturnType.getCanonicalName() + "\". Compilation will most likely fail."); + logger.warn("Callback \"" + callbackMethod + "\" has unsupported return type \"" + callbackReturnType.getCanonicalName() + "\". Compilation will most likely fail."); } } @@ -3633,10 +3513,7 @@ static Method[] functionMethods(Class cls, Method[] methods, boolean[] callba if (Modifier.isStatic(modifiers)) { continue; } - if (callbackAllocators != null && methodName.startsWith("allocate") && - Modifier.isNative(modifiers) && returnType == void.class && - (parameterTypes.length == 0 || (parameterTypes.length == 1 && - (parameterTypes[0] == int.class || parameterTypes[0] == long.class)))) { + if (callbackAllocators != null && methodName.startsWith("allocate") && Modifier.isNative(modifiers) && returnType == void.class && (parameterTypes.length == 0 || (parameterTypes.length == 1 && (parameterTypes[0] == int.class || parameterTypes[0] == long.class)))) { // found a callback allocator method callbackAllocators[i] = true; } else if (methodName.startsWith("call") || methodName.startsWith("apply")) { @@ -3648,8 +3525,7 @@ static Method[] functionMethods(Class cls, Method[] methods, boolean[] callba functionMethods[2] = methods[i]; } } - return (functionMethods[0] != null || functionMethods[1] != null || functionMethods[2] != null) ? - functionMethods : null; + return (functionMethods[0] != null || functionMethods[1] != null || functionMethods[2] != null) ? functionMethods : null; } MethodInformation methodInformation(Method method) { @@ -3680,13 +3556,10 @@ MethodInformation methodInformation(Method method) { } } - boolean canBeGetter = info.returnType != void.class || (info.parameterTypes.length > 0 && - info.parameterTypes[0].isArray() && info.parameterTypes[0].getComponentType().isPrimitive()); - boolean canBeSetter = (info.returnType == void.class || - info.returnType == info.cls) && info.parameterTypes.length > 0; + boolean canBeGetter = info.returnType != void.class || (info.parameterTypes.length > 0 && info.parameterTypes[0].isArray() && info.parameterTypes[0].getComponentType().isPrimitive()); + boolean canBeSetter = (info.returnType == void.class || info.returnType == info.cls) && info.parameterTypes.length > 0; boolean canBeAllocator = !Modifier.isStatic(info.modifiers) && info.returnType == void.class; - boolean canBeArrayAllocator = canBeAllocator && info.parameterTypes.length == 1 && - (info.parameterTypes[0] == int.class || info.parameterTypes[0] == long.class); + boolean canBeArrayAllocator = canBeAllocator && info.parameterTypes.length == 1 && (info.parameterTypes[0] == int.class || info.parameterTypes[0] == long.class); boolean valueGetter = false; boolean valueSetter = false; @@ -3738,25 +3611,15 @@ MethodInformation methodInformation(Method method) { continue; } - boolean parameterAsReturn = canBeValueGetter && info.parameterTypes.length > 0 && - info.parameterTypes[0].isArray() && info.parameterTypes[0].getComponentType().isPrimitive(); - boolean parameterAsReturn2 = canBeValueSetter && info2.parameterTypes.length > 0 && - info2.parameterTypes[0].isArray() && info2.parameterTypes[0].getComponentType().isPrimitive(); + boolean parameterAsReturn = canBeValueGetter && info.parameterTypes.length > 0 && info.parameterTypes[0].isArray() && info.parameterTypes[0].getComponentType().isPrimitive(); + boolean parameterAsReturn2 = canBeValueSetter && info2.parameterTypes.length > 0 && info2.parameterTypes[0].isArray() && info2.parameterTypes[0].getComponentType().isPrimitive(); - if (canBeGetter && info2.parameterTypes.length - (parameterAsReturn ? 0 : 1) == info.parameterTypes.length - skipParameters - && (parameterAsReturn ? info.parameterTypes[info.parameterTypes.length - 1] : info.returnType) == - info2.parameterTypes[info2.parameterTypes.length - 1] && (info2.returnType == void.class || info2.returnType == info.cls) - && (info2.parameterAnnotations[info2.parameterAnnotations.length - 1].length == 0 - || (Arrays.equals(info2.parameterAnnotations[info2.parameterAnnotations.length - 1], info.annotations)))) { + if (canBeGetter && info2.parameterTypes.length - (parameterAsReturn ? 0 : 1) == info.parameterTypes.length - skipParameters && (parameterAsReturn ? info.parameterTypes[info.parameterTypes.length - 1] : info.returnType) == info2.parameterTypes[info2.parameterTypes.length - 1] && (info2.returnType == void.class || info2.returnType == info.cls) && (info2.parameterAnnotations[info2.parameterAnnotations.length - 1].length == 0 || (Arrays.equals(info2.parameterAnnotations[info2.parameterAnnotations.length - 1], info.annotations)))) { pairedMethod = method2; valueGetter = canBeValueGetter; memberGetter = canBeMemberGetter; noReturnGetter = parameterAsReturn; - } else if (canBeSetter && info.parameterTypes.length - (parameterAsReturn2 ? 0 : 1) == info2.parameterTypes.length - skipParameters2 - && (parameterAsReturn2 ? info2.parameterTypes[info2.parameterTypes.length - 1] : info2.returnType) == - info.parameterTypes[info.parameterTypes.length - 1] && (info.returnType == void.class || info.returnType == info.cls) - && (info.parameterAnnotations[info.parameterAnnotations.length - 1].length == 0 - || (Arrays.equals(info.parameterAnnotations[info.parameterAnnotations.length - 1], info2.annotations)))) { + } else if (canBeSetter && info.parameterTypes.length - (parameterAsReturn2 ? 0 : 1) == info2.parameterTypes.length - skipParameters2 && (parameterAsReturn2 ? info2.parameterTypes[info2.parameterTypes.length - 1] : info2.returnType) == info.parameterTypes[info.parameterTypes.length - 1] && (info.returnType == void.class || info.returnType == info.cls) && (info.parameterAnnotations[info.parameterAnnotations.length - 1].length == 0 || (Arrays.equals(info.parameterAnnotations[info.parameterAnnotations.length - 1], info2.annotations)))) { pairedMethod = method2; valueSetter = canBeValueSetter; memberSetter = canBeMemberSetter; @@ -3764,8 +3627,7 @@ MethodInformation methodInformation(Method method) { if (memberGetter || memberSetter) { for (int j = skipParameters; j < info.parameterTypes.length; j++) { - if (!method.isAnnotationPresent(Index.class) && (pairedMethod == null || !pairedMethod.isAnnotationPresent(Index.class)) - && info.parameterTypes[j] != int.class && info.parameterTypes[j] != long.class) { + if (!method.isAnnotationPresent(Index.class) && (pairedMethod == null || !pairedMethod.isAnnotationPresent(Index.class)) && info.parameterTypes[j] != int.class && info.parameterTypes[j] != long.class) { memberGetter = false; if (j < info.parameterTypes.length - 1) { memberSetter = false; @@ -3792,16 +3654,13 @@ MethodInformation methodInformation(Method method) { info.allocator = info.arrayAllocator = true; } else if (behavior == null) { // try to guess the behavior of the method - if (info.returnType == void.class && "deallocate".equals(info.name) && - !Modifier.isStatic(info.modifiers) && info.parameterTypes.length == 2 && - info.parameterTypes[0] == long.class && info.parameterTypes[1] == long.class) { + if (info.returnType == void.class && "deallocate".equals(info.name) && !Modifier.isStatic(info.modifiers) && info.parameterTypes.length == 2 && info.parameterTypes[0] == long.class && info.parameterTypes[1] == long.class) { info.deallocator = true; } else if (canBeAllocator && "allocate".equals(info.name)) { info.allocator = true; } else if (canBeArrayAllocator && "allocateArray".equals(info.name)) { info.allocator = info.arrayAllocator = true; - } else if (info.returnType.isAssignableFrom(ByteBuffer.class) && "asDirectBuffer".equals(info.name) && - !Modifier.isStatic(info.modifiers) && info.parameterTypes.length == 0) { + } else if (info.returnType.isAssignableFrom(ByteBuffer.class) && "asDirectBuffer".equals(info.name) && !Modifier.isStatic(info.modifiers) && info.parameterTypes.length == 0) { info.bufferGetter = true; } else if (valueGetter || (!memberGetter && canBeGetter && "get".equals(info.name) && index != null)) { info.valueGetter = true; @@ -3819,8 +3678,7 @@ MethodInformation methodInformation(Method method) { info.pairedMethod = pairedMethod; } } else if (!(behavior instanceof Function)) { - logger.warn("Method \"" + method + "\" cannot behave like a \"" + - behavior.annotationType().getSimpleName() + "\". No code will be generated."); + logger.warn("Method \"" + method + "\" cannot behave like a \"" + behavior.annotationType().getSimpleName() + "\". No code will be generated."); return null; } @@ -3831,12 +3689,9 @@ MethodInformation methodInformation(Method method) { } } - info.noOffset = info.cls.isAnnotationPresent(NoOffset.class) || - method.isAnnotationPresent(NoOffset.class) || - method.isAnnotationPresent(Index.class); + info.noOffset = info.cls.isAnnotationPresent(NoOffset.class) || method.isAnnotationPresent(NoOffset.class) || method.isAnnotationPresent(Index.class); if (!info.noOffset && info.pairedMethod != null) { - info.noOffset = info.pairedMethod.isAnnotationPresent(NoOffset.class) || - info.pairedMethod.isAnnotationPresent(Index.class); + info.noOffset = info.pairedMethod.isAnnotationPresent(NoOffset.class) || info.pairedMethod.isAnnotationPresent(Index.class); } if (info.parameterTypes.length == 0 || !info.parameterTypes[0].isArray()) { @@ -3845,9 +3700,7 @@ MethodInformation methodInformation(Method method) { } else if (info.memberSetter || info.valueSetter) { info.dim = info.parameterTypes.length - 1; } - if ((info.valueGetter || info.valueSetter) - && FunctionPointer.class.isAssignableFrom(info.cls) - && info.cls.isAnnotationPresent(Namespace.class)) { + if ((info.valueGetter || info.valueSetter) && FunctionPointer.class.isAssignableFrom(info.cls) && info.cls.isAnnotationPresent(Namespace.class)) { // a member pointer where the first argument is the object info.dim--; } @@ -3856,11 +3709,7 @@ MethodInformation methodInformation(Method method) { Index index2 = pairedMethod != null ? pairedMethod.getAnnotation(Index.class) : null; info.throwsException = null; if (!noException(info.cls, method)) { - if ((by(info.annotations) instanceof ByVal && !noException(info.returnType, method)) || - (index != null && index.function().length() > 0) || - (index2 != null && index2.function().length() > 0) || - !info.deallocator && !info.valueGetter && !info.valueSetter && - !info.memberGetter && !info.memberSetter && !info.bufferGetter) { + if ((by(info.annotations) instanceof ByVal && !noException(info.returnType, method)) || (index != null && index.function().length() > 0) || (index2 != null && index2.function().length() > 0) || !info.deallocator && !info.valueGetter && !info.valueSetter && !info.memberGetter && !info.memberSetter && !info.bufferGetter) { Class[] exceptions = method.getExceptionTypes(); info.throwsException = exceptions.length > 0 ? exceptions[0] : RuntimeException.class; } @@ -3883,8 +3732,7 @@ static Allocator allocator(Class cls, Method method) { if ((a = cls.getAnnotation(Allocator.class)) != null) { break; } - org.bytedeco.javacpp.annotation.Properties classProperties = - cls.getAnnotation(org.bytedeco.javacpp.annotation.Properties.class); + org.bytedeco.javacpp.annotation.Properties classProperties = cls.getAnnotation(org.bytedeco.javacpp.annotation.Properties.class); if (Pointer.class.isAssignableFrom(cls) && classProperties != null) { for (Class c : classProperties.inherit()) { if ((a = allocator(c, method)) != null) { @@ -3902,14 +3750,12 @@ static Allocator allocator(Class cls, Method method) { } static boolean criticalRegion(Class cls, Method method) { - boolean criticalRegion = baseClasses.contains(cls) || - method.isAnnotationPresent(CriticalRegion.class); + boolean criticalRegion = baseClasses.contains(cls) || method.isAnnotationPresent(CriticalRegion.class); while (!criticalRegion && cls != null) { if (criticalRegion = cls.isAnnotationPresent(CriticalRegion.class)) { break; } - org.bytedeco.javacpp.annotation.Properties classProperties = - cls.getAnnotation(org.bytedeco.javacpp.annotation.Properties.class); + org.bytedeco.javacpp.annotation.Properties classProperties = cls.getAnnotation(org.bytedeco.javacpp.annotation.Properties.class); if (Pointer.class.isAssignableFrom(cls) && classProperties != null) { for (Class c : classProperties.inherit()) { if (criticalRegion = criticalRegion(c, method)) { @@ -3927,14 +3773,12 @@ static boolean criticalRegion(Class cls, Method method) { } static boolean noException(Class cls, Method method) { - boolean noException = baseClasses.contains(cls) || - method.isAnnotationPresent(NoException.class); + boolean noException = baseClasses.contains(cls) || method.isAnnotationPresent(NoException.class); while (!noException && cls != null) { if (noException = cls.isAnnotationPresent(NoException.class)) { break; } - org.bytedeco.javacpp.annotation.Properties classProperties = - cls.getAnnotation(org.bytedeco.javacpp.annotation.Properties.class); + org.bytedeco.javacpp.annotation.Properties classProperties = cls.getAnnotation(org.bytedeco.javacpp.annotation.Properties.class); if (Pointer.class.isAssignableFrom(cls) && classProperties != null) { for (Class c : classProperties.inherit()) { if (noException = noException(c, method)) { @@ -3964,8 +3808,7 @@ AdapterInformation adapterInformation(boolean out, MethodInformation methodInfo, } String valueTypeName = valueTypeName(typeName); AdapterInformation adapter = adapterInformation(out, valueTypeName, methodInfo.parameterAnnotations[j]); - if (adapter == null && methodInfo.pairedMethod != null && j == methodInfo.parameterTypes.length - 1 && - (methodInfo.valueSetter || methodInfo.memberSetter)) { + if (adapter == null && methodInfo.pairedMethod != null && j == methodInfo.parameterTypes.length - 1 && (methodInfo.valueSetter || methodInfo.memberSetter)) { adapter = adapterInformation(out, valueTypeName, methodInfo.pairedMethod.getAnnotations()); } return adapter; @@ -4048,8 +3891,7 @@ AdapterInformation adapterInformation(boolean out, String valueTypeName, Annotat String cast(MethodInformation methodInfo, int j) { String cast = cast(methodInfo.parameterTypes[j], methodInfo.parameterAnnotations[j]); - if ((cast == null || cast.length() == 0) && j == methodInfo.parameterTypes.length - 1 && - (methodInfo.valueSetter || methodInfo.memberSetter) && methodInfo.pairedMethod != null) { + if ((cast == null || cast.length() == 0) && j == methodInfo.parameterTypes.length - 1 && (methodInfo.valueSetter || methodInfo.memberSetter) && methodInfo.pairedMethod != null) { cast = cast(methodInfo.pairedMethod.getReturnType(), methodInfo.pairedMethod.getAnnotations()); } return cast; @@ -4068,9 +3910,7 @@ String cast(Class type, Annotation... annotations) { Annotation by(MethodInformation methodInfo, int j) { Annotation passBy = by(methodInfo.parameterAnnotations[j]); - if (passBy == null && methodInfo.pairedMethod != null - && (methodInfo.valueSetter || methodInfo.memberSetter) - && j == methodInfo.parameterAnnotations.length - 1) { + if (passBy == null && methodInfo.pairedMethod != null && (methodInfo.valueSetter || methodInfo.memberSetter) && j == methodInfo.parameterAnnotations.length - 1) { passBy = by(methodInfo.pairedMethod.getAnnotations()); } return passBy; @@ -4079,11 +3919,9 @@ Annotation by(MethodInformation methodInfo, int j) { Annotation by(Annotation... annotations) { Annotation byAnnotation = null; for (Annotation a : annotations) { - if (a instanceof ByPtr || a instanceof ByPtrPtr || a instanceof ByPtrRef || - a instanceof ByRef || a instanceof ByVal) { + if (a instanceof ByPtr || a instanceof ByPtrPtr || a instanceof ByPtrRef || a instanceof ByRef || a instanceof ByVal) { if (byAnnotation != null) { - logger.warn("\"By\" annotation \"" + byAnnotation + - "\" already found. Ignoring superfluous annotation \"" + a + "\"."); + logger.warn("\"By\" annotation \"" + byAnnotation + "\" already found. Ignoring superfluous annotation \"" + a + "\"."); } else { byAnnotation = a; } @@ -4095,12 +3933,9 @@ Annotation by(Annotation... annotations) { Annotation behavior(Annotation... annotations) { Annotation behaviorAnnotation = null; for (Annotation a : annotations) { - if (a instanceof Function || a instanceof Allocator || a instanceof ArrayAllocator || - a instanceof ValueSetter || a instanceof ValueGetter || - a instanceof MemberGetter || a instanceof MemberSetter) { + if (a instanceof Function || a instanceof Allocator || a instanceof ArrayAllocator || a instanceof ValueSetter || a instanceof ValueGetter || a instanceof MemberGetter || a instanceof MemberSetter) { if (behaviorAnnotation != null) { - logger.warn("Behavior annotation \"" + behaviorAnnotation + - "\" already found. Ignoring superfluous annotation \"" + a + "\"."); + logger.warn("Behavior annotation \"" + behaviorAnnotation + "\" already found. Ignoring superfluous annotation \"" + a + "\"."); } else { behaviorAnnotation = a; } @@ -4113,20 +3948,17 @@ String enumValueType(Class type) { try { Field f = type.getField("value"); if (!f.getType().isPrimitive()) { - logger.warn("Field \"value\" of enum type \"" + type.getCanonicalName() - + "\" is not of a primitive type. Compilation will most likely fail."); + logger.warn("Field \"value\" of enum type \"" + type.getCanonicalName() + "\" is not of a primitive type. Compilation will most likely fail."); } return f.getType().getName(); } catch (NoSuchFieldException ex) { - logger.warn("Field \"value\" missing from enum type \"" + type.getCanonicalName() - + ". Compilation will most likely fail."); + logger.warn("Field \"value\" missing from enum type \"" + type.getCanonicalName() + ". Compilation will most likely fail."); return null; } } static boolean asUtf16(MethodInformation methodInfo, int j) { - if (methodInfo.parameterAnnotations[j].length == 0 && methodInfo.pairedMethod != null && - j == methodInfo.parameterTypes.length - 1 && (methodInfo.valueSetter || methodInfo.memberSetter)) { + if (methodInfo.parameterAnnotations[j].length == 0 && methodInfo.pairedMethod != null && j == methodInfo.parameterTypes.length - 1 && (methodInfo.valueSetter || methodInfo.memberSetter)) { return asUtf16(methodInfo.pairedMethod.getAnnotations()); } return asUtf16(methodInfo.parameterAnnotations[j]); @@ -4145,19 +3977,15 @@ static boolean asUtf16(Annotation[] annotations) { } static String createString(String ptr, String adapter, boolean asUtf16) { - return (asUtf16 ? "JavaCPP_createStringFromUTF16(env, " - : "JavaCPP_createStringFromBytes(env, ") - + ptr + (adapter != null ? ", " + adapter + ".size);" : ");"); + return (asUtf16 ? "JavaCPP_createStringFromUTF16(env, " : "JavaCPP_createStringFromBytes(env, ") + ptr + (adapter != null ? ", " + adapter + ".size);" : ");"); } static String getStringData(String str, boolean asUtf16) { - return (asUtf16 ? "JavaCPP_getStringUTF16(env, " - : "JavaCPP_getStringBytes(env, ") + str + ");"; + return (asUtf16 ? "JavaCPP_getStringUTF16(env, " : "JavaCPP_getStringBytes(env, ") + str + ");"; } static String releaseStringData(String str, String ptr, boolean asUtf16) { - return (asUtf16 ? "JavaCPP_releaseStringUTF16(env, " - : "JavaCPP_releaseStringBytes(env, " + str + ", ") + ptr + ");"; + return (asUtf16 ? "JavaCPP_releaseStringUTF16(env, " : "JavaCPP_releaseStringBytes(env, " + str + ", ") + ptr + ");"; } static String constValueTypeName(String... typeName) { @@ -4319,8 +4147,7 @@ String[] cppCastTypeName(Class type, Annotation... annotations) { } String[] cppTypeName(MethodInformation methodInfo, int j) { - if (methodInfo.parameterAnnotations[j].length == 0 && methodInfo.pairedMethod != null && - j == methodInfo.parameterTypes.length - 1 && (methodInfo.valueSetter || methodInfo.memberSetter)) { + if (methodInfo.parameterAnnotations[j].length == 0 && methodInfo.pairedMethod != null && j == methodInfo.parameterTypes.length - 1 && (methodInfo.valueSetter || methodInfo.memberSetter)) { return cppTypeName(methodInfo.pairedMethod.getReturnType(), methodInfo.pairedMethod.getAnnotations()); } return cppTypeName(methodInfo.parameterTypes[j], methodInfo.parameterAnnotations[j]); @@ -4379,8 +4206,7 @@ String[] cppTypeName(Class type, Annotation[] annotations) { if (scopedType.length() > 0) { prefix = scopedType + (Enum.class.isAssignableFrom(type) ? "" : "*"); } else { - logger.warn("The class " + type.getCanonicalName() + - " does not map to any C++ type. Compilation will most likely fail."); + logger.warn("The class " + type.getCanonicalName() + " does not map to any C++ type. Compilation will most likely fail."); } } return new String[]{prefix, suffix}; @@ -4429,10 +4255,8 @@ String[] cppFunctionTypeName(Method... functionMethods) { if (functionMethod == functionMethods[0]) { // this is a real function, not get/put for a field pointer suffix += "("; - if (FunctionPointer.class.isAssignableFrom(type) && namespace != null - && (parameterTypes.length == 0 || !Pointer.class.isAssignableFrom(parameterTypes[0]))) { - logger.warn("First parameter of caller method call() or apply() for member function pointer " + - type.getCanonicalName() + " is not a Pointer. Compilation will most likely fail."); + if (FunctionPointer.class.isAssignableFrom(type) && namespace != null && (parameterTypes.length == 0 || !Pointer.class.isAssignableFrom(parameterTypes[0]))) { + logger.warn("First parameter of caller method call() or apply() for member function pointer " + type.getCanonicalName() + " is not a Pointer. Compilation will most likely fail."); } for (int j = namespace == null ? 0 : 1; j < parameterTypes.length; j++) { String[] paramTypeName = cppAnnotationTypeName(parameterTypes[j], parameterAnnotations[j]); @@ -4489,8 +4313,7 @@ static String cppScopeName(Class type) { while (type != null) { Namespace namespace = type.getAnnotation(Namespace.class); String spaceName = namespace == null ? "" : namespace.value(); - if ((Enum.class.isAssignableFrom(type) || Pointer.class.isAssignableFrom(type)) - && (!baseClasses.contains(type) || type.isAnnotationPresent(Name.class))) { + if ((Enum.class.isAssignableFrom(type) || Pointer.class.isAssignableFrom(type)) && (!baseClasses.contains(type) || type.isAnnotationPresent(Name.class))) { Name name = type.getAnnotation(Name.class); String s; if (name == null) { @@ -4508,8 +4331,7 @@ static String cppScopeName(Class type) { } spaceName += s; } - if (scopeName.length() > 0 && !scopeName.startsWith("class ") && !scopeName.startsWith("struct ") - && !scopeName.startsWith("union ") && !spaceName.endsWith("::")) { + if (scopeName.length() > 0 && !scopeName.startsWith("class ") && !scopeName.startsWith("struct ") && !scopeName.startsWith("union ") && !spaceName.endsWith("::")) { spaceName += "::"; } scopeName = spaceName + scopeName; @@ -4629,4 +4451,27 @@ static String mangle(String name) { } return mangledName.toString(); } -} + + private String getFileContentFromLocal(final String filePath) { + return readFileContent(filePath, true); + } + + private String getFileContentFromOther(final String filePath) { + return readFileContent(filePath, false); + } + + private String readFileContent(final String filePath, boolean isLocal) { + StringBuilder result = new StringBuilder(); + + try (InputStream inputStream = isLocal ? Generator.class.getResourceAsStream(filePath) : Generator.class.getClassLoader().getResourceAsStream(filePath); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { + String line; + while ((line = reader.readLine()) != null) { + result.append(line).append("\n"); + } + } catch (IOException e) { + throw new RuntimeException("Unable to load file: " + filePath, e); + } + + return result.toString(); + } +} \ No newline at end of file From eee05443cbceae20dac3d234c46b720198b2dce6 Mon Sep 17 00:00:00 2001 From: FITOR Date: Thu, 5 Dec 2024 09:52:52 +0100 Subject: [PATCH 09/28] changed default compiler options to use /MT instead of /MD --- .../bytedeco/javacpp/properties/windows-x86-cuda.properties | 4 ++-- .../org/bytedeco/javacpp/properties/windows-x86.properties | 4 ++-- .../javacpp/properties/windows-x86_64-cuda.properties | 4 ++-- .../org/bytedeco/javacpp/properties/windows-x86_64.properties | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/resources/org/bytedeco/javacpp/properties/windows-x86-cuda.properties b/src/main/resources/org/bytedeco/javacpp/properties/windows-x86-cuda.properties index 49e65ec88..5116a049b 100644 --- a/src/main/resources/org/bytedeco/javacpp/properties/windows-x86-cuda.properties +++ b/src/main/resources/org/bytedeco/javacpp/properties/windows-x86-cuda.properties @@ -9,8 +9,8 @@ platform.compiler.cpp03=-std=c++03 platform.compiler.cpp11=-std=c++11 platform.compiler.cpp14=-std=c++14 platform.compiler.cpp17=-std=c++17 -platform.compiler.debug=-Xcompiler=/Od,/EHsc,/MDd,/LDd -platform.compiler.default=-Xcompiler=/Oi,/O2,/EHsc,/Gy,/GL,/MD,/LD +platform.compiler.debug=-Xcompiler=/Od,/EHsc,/MTd,/LDd +platform.compiler.default=-Xcompiler=/Oi,/O2,/EHsc,/Gy,/GL,/MT,/LD platform.compiler.fastfpu=-Xcompiler=/arch:SSE2,/fp:fast platform.compiler.nodeprecated=-Xcompiler=/wd4996 platform.compiler.noexceptions=-Xcompiler=/EHs-c-,/GR- diff --git a/src/main/resources/org/bytedeco/javacpp/properties/windows-x86.properties b/src/main/resources/org/bytedeco/javacpp/properties/windows-x86.properties index 1dcc84b45..a1fa58165 100644 --- a/src/main/resources/org/bytedeco/javacpp/properties/windows-x86.properties +++ b/src/main/resources/org/bytedeco/javacpp/properties/windows-x86.properties @@ -9,8 +9,8 @@ platform.compiler.cpp03= platform.compiler.cpp11= platform.compiler.cpp14=/std:c++14 /Zc:__cplusplus platform.compiler.cpp17=/std:c++17 /Zc:__cplusplus -platform.compiler.debug=/Od /EHsc /MDd /LDd -platform.compiler.default=/Oi /O2 /EHsc /Gy /GL /MD /LD +platform.compiler.debug=/Od /EHsc /MTd /LDd +platform.compiler.default=/Oi /O2 /EHsc /Gy /GL /MT /LD platform.compiler.fastfpu=/arch:SSE2 /fp:fast platform.compiler.nodeprecated=/wd4996 platform.compiler.noexceptions=/EHs-c- /GR- diff --git a/src/main/resources/org/bytedeco/javacpp/properties/windows-x86_64-cuda.properties b/src/main/resources/org/bytedeco/javacpp/properties/windows-x86_64-cuda.properties index e1e001987..f9d40fa06 100644 --- a/src/main/resources/org/bytedeco/javacpp/properties/windows-x86_64-cuda.properties +++ b/src/main/resources/org/bytedeco/javacpp/properties/windows-x86_64-cuda.properties @@ -9,8 +9,8 @@ platform.compiler.cpp03=-std=c++03 platform.compiler.cpp11=-std=c++11 platform.compiler.cpp14=-std=c++14 platform.compiler.cpp17=-std=c++17 -platform.compiler.debug=-Xcompiler=/Od,/EHsc,/MDd,/LDd -platform.compiler.default=-Xcompiler=/Oi,/O2,/EHsc,/Gy,/GL,/MD,/LD +platform.compiler.debug=-Xcompiler=/Od,/EHsc,/MTd,/LDd +platform.compiler.default=-Xcompiler=/Oi,/O2,/EHsc,/Gy,/GL,/MT,/LD platform.compiler.fastfpu=-Xcompiler=/fp:fast platform.compiler.nodeprecated=-Xcompiler=/wd4996 platform.compiler.noexceptions=-Xcompiler=/EHs-c-,/GR- diff --git a/src/main/resources/org/bytedeco/javacpp/properties/windows-x86_64.properties b/src/main/resources/org/bytedeco/javacpp/properties/windows-x86_64.properties index e3cc89226..e3f9c8e25 100644 --- a/src/main/resources/org/bytedeco/javacpp/properties/windows-x86_64.properties +++ b/src/main/resources/org/bytedeco/javacpp/properties/windows-x86_64.properties @@ -9,8 +9,8 @@ platform.compiler.cpp03= platform.compiler.cpp11= platform.compiler.cpp14=/std:c++14 /Zc:__cplusplus platform.compiler.cpp17=/std:c++17 /Zc:__cplusplus -platform.compiler.debug=/Od /EHsc /MDd /LDd -platform.compiler.default=/Oi /O2 /EHsc /Gy /GL /MD /LD +platform.compiler.debug=/Od /EHsc /MTd /LDd +platform.compiler.default=/Oi /O2 /EHsc /Gy /GL /MT /LD platform.compiler.fastfpu=/fp:fast platform.compiler.nodeprecated=/wd4996 platform.compiler.noexceptions=/EHs-c- /GR- From 6c8a089c94d6f88cf4e661551b4ca3d3e6c158aa Mon Sep 17 00:00:00 2001 From: "DESKTOP-JQRNS69\\Seclous" Date: Mon, 9 Dec 2024 09:31:50 +0100 Subject: [PATCH 10/28] enabled dynamicly inserting function name on customMappings --- src/main/java/org/bytedeco/javacpp/tools/Generator.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/bytedeco/javacpp/tools/Generator.java b/src/main/java/org/bytedeco/javacpp/tools/Generator.java index b5fd8eecb..51b0fc757 100644 --- a/src/main/java/org/bytedeco/javacpp/tools/Generator.java +++ b/src/main/java/org/bytedeco/javacpp/tools/Generator.java @@ -2173,11 +2173,12 @@ boolean methods(Class cls) { if (!mappingFilePath.isEmpty()) { String fileContent = getFileContentFromOther(mappingFilePath); + fileContent = fileContent.replace("$funcName", "ptr->" + methodInfo.name); out.println(fileContent); } else { - out.println(mapper.customMapping()); + String content = mapper.customMapping().replace("$funcName", "ptr->" + methodInfo.name); + out.println(content); } - break; } } From 4a18a9f16b96d67a587b059c8cc48bcd636cac1c Mon Sep 17 00:00:00 2001 From: "DESKTOP-JQRNS69\\Seclous" Date: Mon, 9 Dec 2024 09:48:05 +0100 Subject: [PATCH 11/28] added parameternames --- .../org/bytedeco/javacpp/tools/Generator.java | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/bytedeco/javacpp/tools/Generator.java b/src/main/java/org/bytedeco/javacpp/tools/Generator.java index 51b0fc757..74e77fcf6 100644 --- a/src/main/java/org/bytedeco/javacpp/tools/Generator.java +++ b/src/main/java/org/bytedeco/javacpp/tools/Generator.java @@ -149,13 +149,16 @@ public boolean generate(String sourceFilename, String jniConfigFilename, String // first pass using a null writer to fill up the IndexedSet objects out = new PrintWriter(new Writer() { @Override - public void write(char[] cbuf, int off, int len) { } + public void write(char[] cbuf, int off, int len) { + } @Override - public void flush() { } + public void flush() { + } @Override - public void close() { } + public void close() { + } }); out2 = jniConfigOut = reflectConfigOut = null; callbacks = new LinkedHashMap(); @@ -2171,12 +2174,22 @@ boolean methods(Class cls) { CustomMapper mapper = (CustomMapper) annotation; final String mappingFilePath = mapper.filePath(); + int paramCount = methodInfo.parameterTypes.length; + StringBuilder argsString = new StringBuilder(); + for (int currentParamCount = 0; currentParamCount < paramCount; currentParamCount++) { + if (currentParamCount > 0) { + argsString.append(", "); // Add comma separator for all but the first argument + } + argsString.append("arg").append(currentParamCount); // Append arg0, arg1, etc. + } + String functionName = String.format("ptr->%s(%s)", methodInfo.name, argsString); + if (!mappingFilePath.isEmpty()) { String fileContent = getFileContentFromOther(mappingFilePath); - fileContent = fileContent.replace("$funcName", "ptr->" + methodInfo.name); + fileContent = fileContent.replace("$funcName", functionName); out.println(fileContent); } else { - String content = mapper.customMapping().replace("$funcName", "ptr->" + methodInfo.name); + String content = mapper.customMapping().replace("$funcName", functionName); out.println(content); } break; From caf19f80f2d136f0a2e15b40e12e3bbe1d595955 Mon Sep 17 00:00:00 2001 From: Fitor Date: Tue, 10 Dec 2024 13:24:52 +0100 Subject: [PATCH 12/28] added constMember annotation --- .../bytedeco/javacpp/annotation/ConstMember.java | 12 ++++++++++++ .../org/bytedeco/javacpp/tools/Generator.java | 15 ++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 src/main/java/org/bytedeco/javacpp/annotation/ConstMember.java diff --git a/src/main/java/org/bytedeco/javacpp/annotation/ConstMember.java b/src/main/java/org/bytedeco/javacpp/annotation/ConstMember.java new file mode 100644 index 000000000..9c0771658 --- /dev/null +++ b/src/main/java/org/bytedeco/javacpp/annotation/ConstMember.java @@ -0,0 +1,12 @@ +package org.bytedeco.javacpp.annotation; + +import java.lang.annotation.*; + +/** + * Annotation allows to map (mainly virtual) functions, which are const members (e.g.: void func() const) + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +public @interface ConstMember { +} diff --git a/src/main/java/org/bytedeco/javacpp/tools/Generator.java b/src/main/java/org/bytedeco/javacpp/tools/Generator.java index 74e77fcf6..d3eb5099a 100644 --- a/src/main/java/org/bytedeco/javacpp/tools/Generator.java +++ b/src/main/java/org/bytedeco/javacpp/tools/Generator.java @@ -3077,14 +3077,23 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo if (needUsing) { member += usingLine + "\n "; } - member += "virtual " + returnType[0] + (returnConvention.length > 1 ? returnConvention[1] : "") + methodInfo.memberName[0] + parameterDeclaration + returnType[1] + " JavaCPP_override;\n " + returnType[0] + "super_" + methodInfo.name + nonconstParamDeclaration + returnType[1] + " { "; + + + boolean isConstMember = false; + for (Annotation annotation : methodInfo.annotations) { + if (annotation.annotationType().equals(ConstMember.class)) { + isConstMember = true; + } + } + + member += "virtual " + returnType[0] + (returnConvention.length > 1 ? returnConvention[1] : "") + methodInfo.memberName[0] + parameterDeclaration + returnType[1] + (isConstMember ? " const" : "") + " JavaCPP_override;\n " + returnType[0] + "super_" + methodInfo.name + nonconstParamDeclaration + returnType[1] + " { "; if (methodInfo.method.getAnnotation(Virtual.class).value()) { member += "throw JavaCPP_exception(\"Cannot call pure virtual function " + valueTypeName + "::" + methodInfo.memberName[0] + "().\"); }"; } else { member += (callbackReturnType != void.class ? "return " : "") + valueTypeName + "::" + methodInfo.memberName[0] + "("; member += callbackArguments + "); }"; } - firstLine = returnType[0] + (returnConvention.length > 1 ? returnConvention[1] : "") + subType + "::" + methodInfo.memberName[0] + parameterDeclaration + returnType[1] + " {"; + firstLine = returnType[0] + (returnConvention.length > 1 ? returnConvention[1] : "") + subType + "::" + methodInfo.memberName[0] + parameterDeclaration + returnType[1] + (isConstMember ? " const" : "") +" {"; functionList.add(fieldName); } memberList.add(member); @@ -3119,7 +3128,6 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo out.println(","); } } - out.println(" };"); firstLine = returnType[0] + instanceTypeName + "::operator()" + parameterDeclaration + returnType[1] + " {"; } @@ -3127,6 +3135,7 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo if (!needDefinition) { return; } + out.println(firstLine); String returnPrefix = ""; From 217b080652152250fd6c72f3e3faf17c463c427a Mon Sep 17 00:00:00 2001 From: Fitor Date: Thu, 12 Dec 2024 10:58:25 +0100 Subject: [PATCH 13/28] added CustomMapper flexibility --- .../org/bytedeco/javacpp/annotation/CustomMapper.java | 11 +++++++++++ .../java/org/bytedeco/javacpp/tools/Generator.java | 4 +++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/bytedeco/javacpp/annotation/CustomMapper.java b/src/main/java/org/bytedeco/javacpp/annotation/CustomMapper.java index 49d4cd2bd..14bf6fa4d 100644 --- a/src/main/java/org/bytedeco/javacpp/annotation/CustomMapper.java +++ b/src/main/java/org/bytedeco/javacpp/annotation/CustomMapper.java @@ -25,4 +25,15 @@ * @return The filePath of the file, which contains the mapping. */ String filePath() default ""; + + /** + * @return True if the CType of the parameters shall be used instead of the jType, to feed the calling function. + */ + boolean passCTypeParams() default false; + + /** + * + * @return True if the parameter of the function shall be dereferenced. + */ + boolean dereferenceParams() default false; } \ No newline at end of file diff --git a/src/main/java/org/bytedeco/javacpp/tools/Generator.java b/src/main/java/org/bytedeco/javacpp/tools/Generator.java index d3eb5099a..ac32f51d0 100644 --- a/src/main/java/org/bytedeco/javacpp/tools/Generator.java +++ b/src/main/java/org/bytedeco/javacpp/tools/Generator.java @@ -2166,6 +2166,8 @@ boolean methods(Class cls) { parametersBefore(methodInfo); String returnPrefix = returnBefore(methodInfo); + // ByPtr || ByPtrRef || (ByRef && std::string) + boolean containsCustomMapping = false; for (Annotation annotation : methodInfo.annotations) { if (annotation.annotationType().equals(CustomMapper.class)) { @@ -2180,7 +2182,7 @@ boolean methods(Class cls) { if (currentParamCount > 0) { argsString.append(", "); // Add comma separator for all but the first argument } - argsString.append("arg").append(currentParamCount); // Append arg0, arg1, etc. + argsString.append(mapper.dereferenceParams() ? "*" : "").append(mapper.passCTypeParams() ? "ptr" : "arg").append(currentParamCount); // Append arg0, arg1, etc. } String functionName = String.format("ptr->%s(%s)", methodInfo.name, argsString); From f75f244bb630ab84449ec14867d8ff0a7eae8614 Mon Sep 17 00:00:00 2001 From: FITOR Date: Fri, 13 Dec 2024 09:18:35 +0100 Subject: [PATCH 14/28] implemented adding of custom JNI code --- .../java/org/bytedeco/javacpp/ClassProperties.java | 5 +++-- .../java/org/bytedeco/javacpp/annotation/Platform.java | 7 +++++++ .../java/org/bytedeco/javacpp/tools/Generator.java | 10 +++++++++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/bytedeco/javacpp/ClassProperties.java b/src/main/java/org/bytedeco/javacpp/ClassProperties.java index 1740c032c..23424b25b 100644 --- a/src/main/java/org/bytedeco/javacpp/ClassProperties.java +++ b/src/main/java/org/bytedeco/javacpp/ClassProperties.java @@ -192,7 +192,7 @@ public void load(Class cls, boolean inherit) { } boolean hasPlatformProperties = platforms != null && platforms.length > (classProperties != null && classPlatform != null ? 1 : 0); - String[] exceptionMappings = {}, pragma = {}, define = {}, exclude = {}, include = {}, cinclude = {}, includepath = {}, includeresource = {}, compiler = {}, linkpath = {}, linkresource = {}, link = {}, frameworkpath = {}, framework = {}, preloadpath = {}, preloadresource = {}, preload = {}, resourcepath = {}, resource = {}, extension = {}, executablepath = {}, executable = {}; + String[] addCustomJNIFrom = {}, exceptionMappings = {}, pragma = {}, define = {}, exclude = {}, include = {}, cinclude = {}, includepath = {}, includeresource = {}, compiler = {}, linkpath = {}, linkresource = {}, link = {}, frameworkpath = {}, framework = {}, preloadpath = {}, preloadresource = {}, preload = {}, resourcepath = {}, resource = {}, extension = {}, executablepath = {}, executable = {}; String library = "jni" + c.getSimpleName(); if (hasPlatformProperties) { if (ourTarget != null && ourTarget.length() > 0) { @@ -240,7 +240,7 @@ public void load(Class cls, boolean inherit) { } exceptionMappings = exceptionMappingsList.toArray(new String[0]); } - + if (p.addCustomJNIFrom().length > 0) { addCustomJNIFrom = p.addCustomJNIFrom(); } if (p.pragma().length > 0) { pragma = p.pragma(); } if (p.define().length > 0) { define = p.define(); } if (p.exclude().length > 0) { exclude = p.exclude(); } @@ -291,6 +291,7 @@ public void load(Class cls, boolean inherit) { } addAll("platform.exceptionMappings", exceptionMappings); + addAll("platform.addCustomJNIFrom", addCustomJNIFrom); addAll("platform.pragma", pragma); addAll("platform.define", define); addAll("platform.exclude", exclude); diff --git a/src/main/java/org/bytedeco/javacpp/annotation/Platform.java b/src/main/java/org/bytedeco/javacpp/annotation/Platform.java index 275873f46..b126825ac 100644 --- a/src/main/java/org/bytedeco/javacpp/annotation/Platform.java +++ b/src/main/java/org/bytedeco/javacpp/annotation/Platform.java @@ -179,6 +179,13 @@ */ String library() default ""; + /** + * Allows the user to add custom JNI Code from resources. + * + * @return An Array of all the files (from resources) which contain custom JNI code. + */ + String[] addCustomJNIFrom() default {}; + /** * Mappings for custom exceptions. * @return An array of {@link ExceptionMapper}, which determines the mapping of custom native exceptions to any javaException. diff --git a/src/main/java/org/bytedeco/javacpp/tools/Generator.java b/src/main/java/org/bytedeco/javacpp/tools/Generator.java index ac32f51d0..3873029bb 100644 --- a/src/main/java/org/bytedeco/javacpp/tools/Generator.java +++ b/src/main/java/org/bytedeco/javacpp/tools/Generator.java @@ -1087,6 +1087,15 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver out.println("};"); out.println(); + //////////////////// CUSTOM JNI CODE //////////////////// + List customJNIFilePaths = clsProperties.get("platform.addCustomJNIFrom"); + for(String customJNIFilePath : customJNIFilePaths) { + String fileContent = getFileContentFromOther(customJNIFilePath); + out.println(fileContent); + } + //////////////////// CUSTOM JNI CODE //////////////////// + + //////////////////// EXCEPTION HANDLER //////////////////// if (handleExceptions) { out.println("#include "); @@ -2194,7 +2203,6 @@ boolean methods(Class cls) { String content = mapper.customMapping().replace("$funcName", functionName); out.println(content); } - break; } } From 9675848afba171be51494ac9691339e57c551e15 Mon Sep 17 00:00:00 2001 From: FITOR Date: Thu, 19 Dec 2024 14:04:18 +0100 Subject: [PATCH 15/28] adjusted CustomMapping annoptation --- .../org/bytedeco/javacpp/tools/Generator.java | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/bytedeco/javacpp/tools/Generator.java b/src/main/java/org/bytedeco/javacpp/tools/Generator.java index 3873029bb..b916eb854 100644 --- a/src/main/java/org/bytedeco/javacpp/tools/Generator.java +++ b/src/main/java/org/bytedeco/javacpp/tools/Generator.java @@ -2175,9 +2175,12 @@ boolean methods(Class cls) { parametersBefore(methodInfo); String returnPrefix = returnBefore(methodInfo); - // ByPtr || ByPtrRef || (ByRef && std::string) - boolean containsCustomMapping = false; + StringBuilder argsString = new StringBuilder(); + String functionName = ""; + String nativeFunction; + String fileContent = ""; + for (Annotation annotation : methodInfo.annotations) { if (annotation.annotationType().equals(CustomMapper.class)) { containsCustomMapping = true; @@ -2186,28 +2189,32 @@ boolean methods(Class cls) { final String mappingFilePath = mapper.filePath(); int paramCount = methodInfo.parameterTypes.length; - StringBuilder argsString = new StringBuilder(); + argsString = new StringBuilder(); for (int currentParamCount = 0; currentParamCount < paramCount; currentParamCount++) { if (currentParamCount > 0) { argsString.append(", "); // Add comma separator for all but the first argument } argsString.append(mapper.dereferenceParams() ? "*" : "").append(mapper.passCTypeParams() ? "ptr" : "arg").append(currentParamCount); // Append arg0, arg1, etc. } - String functionName = String.format("ptr->%s(%s)", methodInfo.name, argsString); - if (!mappingFilePath.isEmpty()) { - String fileContent = getFileContentFromOther(mappingFilePath); - fileContent = fileContent.replace("$funcName", functionName); - out.println(fileContent); + fileContent = getFileContentFromOther(mappingFilePath); } else { - String content = mapper.customMapping().replace("$funcName", functionName); - out.println(content); + fileContent = mapper.customMapping(); } + } else if(annotation.annotationType().equals(Name.class)) { + functionName = ((Name) annotation).value()[0]; } } // ignore the default mapping if the customMapping has been enabled - if (!containsCustomMapping) { + if (containsCustomMapping) { + if(functionName.isEmpty()) { + functionName = methodInfo.name; + } + nativeFunction = String.format("ptr->%s(%s)", functionName, argsString); + fileContent = fileContent.replace("$funcName", nativeFunction); + out.println(fileContent); + } else { call(methodInfo, returnPrefix, false); returnAfter(methodInfo); } From ea9e40d1de7b2588157021e0fff23a11f23c8c47 Mon Sep 17 00:00:00 2001 From: FITOR Date: Thu, 19 Dec 2024 15:51:17 +0100 Subject: [PATCH 16/28] added dynamic pointer initialization --- .../javacpp/annotation/CustomMapper.java | 2 ++ .../org/bytedeco/javacpp/tools/Generator.java | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/main/java/org/bytedeco/javacpp/annotation/CustomMapper.java b/src/main/java/org/bytedeco/javacpp/annotation/CustomMapper.java index 14bf6fa4d..3993e816a 100644 --- a/src/main/java/org/bytedeco/javacpp/annotation/CustomMapper.java +++ b/src/main/java/org/bytedeco/javacpp/annotation/CustomMapper.java @@ -26,6 +26,8 @@ */ String filePath() default ""; + String deallocatorName() default ""; + /** * @return True if the CType of the parameters shall be used instead of the jType, to feed the calling function. */ diff --git a/src/main/java/org/bytedeco/javacpp/tools/Generator.java b/src/main/java/org/bytedeco/javacpp/tools/Generator.java index b916eb854..e69f818fe 100644 --- a/src/main/java/org/bytedeco/javacpp/tools/Generator.java +++ b/src/main/java/org/bytedeco/javacpp/tools/Generator.java @@ -2180,6 +2180,7 @@ boolean methods(Class cls) { String functionName = ""; String nativeFunction; String fileContent = ""; + String deallocator = ""; for (Annotation annotation : methodInfo.annotations) { if (annotation.annotationType().equals(CustomMapper.class)) { @@ -2187,6 +2188,7 @@ boolean methods(Class cls) { CustomMapper mapper = (CustomMapper) annotation; final String mappingFilePath = mapper.filePath(); + deallocator = mapper.deallocatorName(); int paramCount = methodInfo.parameterTypes.length; argsString = new StringBuilder(); @@ -2208,12 +2210,32 @@ boolean methods(Class cls) { // ignore the default mapping if the customMapping has been enabled if (containsCustomMapping) { + if (fileContent.contains("$initPointer") && deallocator.isEmpty()) { + throw new IllegalStateException("You must specify the deallocator name, when using the $initPointer placeholder"); + } + + + StringBuilder initPointer = new StringBuilder(); + initPointer.append(" if (rptr != NULL) {\n"); + initPointer.append(" if (JavaCPP_haveAllocObject) {\n"); + initPointer.append(" rarg = env->AllocObject(env->FindClass(\"" + methodInfo.returnType.getName().replace('.', '/') + "\"));\n"); + initPointer.append(" }\n\n"); + initPointer.append(" if (rarg != NULL) {\n"); + initPointer.append(" jlong rcapacity = 1;\n"); + initPointer.append(" JavaCPP_initPointer(env, rarg, rptr, rcapacity, rptr, &" + deallocator + ");\n"); + initPointer.append(" }\n"); + initPointer.append(" }\n"); + + if(functionName.isEmpty()) { functionName = methodInfo.name; } nativeFunction = String.format("ptr->%s(%s)", functionName, argsString); fileContent = fileContent.replace("$funcName", nativeFunction); + fileContent = fileContent.replace("$initPointer", initPointer.toString()); out.println(fileContent); + + } else { call(methodInfo, returnPrefix, false); returnAfter(methodInfo); From ac289ba127d4934260f0615cd5e193a9ef5d9f17 Mon Sep 17 00:00:00 2001 From: FITOR Date: Thu, 9 Jan 2025 14:16:35 +0100 Subject: [PATCH 17/28] adjusted CustomMapper --- .../javacpp/annotation/CustomMapper.java | 9 ++-- .../org/bytedeco/javacpp/tools/Generator.java | 52 +++++-------------- 2 files changed, 18 insertions(+), 43 deletions(-) diff --git a/src/main/java/org/bytedeco/javacpp/annotation/CustomMapper.java b/src/main/java/org/bytedeco/javacpp/annotation/CustomMapper.java index 3993e816a..d0d14381b 100644 --- a/src/main/java/org/bytedeco/javacpp/annotation/CustomMapper.java +++ b/src/main/java/org/bytedeco/javacpp/annotation/CustomMapper.java @@ -17,16 +17,19 @@ * * @return A String which will be directly used for the mapping. */ - String customMapping() default "// do Nothing"; + String customMapping() default ""; /** * FilePath of the file, which contains the mapping. * * @return The filePath of the file, which contains the mapping. */ - String filePath() default ""; + String[] filePaths() default {}; - String deallocatorName() default ""; + /** + * Set the name of the function to be called + */ + String functionCall() default ""; /** * @return True if the CType of the parameters shall be used instead of the jType, to feed the calling function. diff --git a/src/main/java/org/bytedeco/javacpp/tools/Generator.java b/src/main/java/org/bytedeco/javacpp/tools/Generator.java index e69f818fe..59e07efb3 100644 --- a/src/main/java/org/bytedeco/javacpp/tools/Generator.java +++ b/src/main/java/org/bytedeco/javacpp/tools/Generator.java @@ -2176,66 +2176,38 @@ boolean methods(Class cls) { String returnPrefix = returnBefore(methodInfo); boolean containsCustomMapping = false; - StringBuilder argsString = new StringBuilder(); - String functionName = ""; - String nativeFunction; - String fileContent = ""; - String deallocator = ""; + String functionCall = ""; + StringBuilder fileContent = new StringBuilder(); for (Annotation annotation : methodInfo.annotations) { if (annotation.annotationType().equals(CustomMapper.class)) { containsCustomMapping = true; - CustomMapper mapper = (CustomMapper) annotation; - final String mappingFilePath = mapper.filePath(); - deallocator = mapper.deallocatorName(); + + final String[] mappingFilePaths = mapper.filePaths(); int paramCount = methodInfo.parameterTypes.length; - argsString = new StringBuilder(); + StringBuilder argsString = new StringBuilder(); for (int currentParamCount = 0; currentParamCount < paramCount; currentParamCount++) { if (currentParamCount > 0) { argsString.append(", "); // Add comma separator for all but the first argument } argsString.append(mapper.dereferenceParams() ? "*" : "").append(mapper.passCTypeParams() ? "ptr" : "arg").append(currentParamCount); // Append arg0, arg1, etc. } - if (!mappingFilePath.isEmpty()) { - fileContent = getFileContentFromOther(mappingFilePath); - } else { - fileContent = mapper.customMapping(); + + functionCall = mapper.functionCall().isEmpty() ? String.format("ptr->%s(%s)", methodInfo.name, argsString) : mapper.functionCall(); + fileContent = new StringBuilder(mapper.customMapping()); + + for (String path : mappingFilePaths) { + fileContent.append(getFileContentFromOther(path)); } - } else if(annotation.annotationType().equals(Name.class)) { - functionName = ((Name) annotation).value()[0]; } } // ignore the default mapping if the customMapping has been enabled if (containsCustomMapping) { - if (fileContent.contains("$initPointer") && deallocator.isEmpty()) { - throw new IllegalStateException("You must specify the deallocator name, when using the $initPointer placeholder"); - } - - - StringBuilder initPointer = new StringBuilder(); - initPointer.append(" if (rptr != NULL) {\n"); - initPointer.append(" if (JavaCPP_haveAllocObject) {\n"); - initPointer.append(" rarg = env->AllocObject(env->FindClass(\"" + methodInfo.returnType.getName().replace('.', '/') + "\"));\n"); - initPointer.append(" }\n\n"); - initPointer.append(" if (rarg != NULL) {\n"); - initPointer.append(" jlong rcapacity = 1;\n"); - initPointer.append(" JavaCPP_initPointer(env, rarg, rptr, rcapacity, rptr, &" + deallocator + ");\n"); - initPointer.append(" }\n"); - initPointer.append(" }\n"); - - - if(functionName.isEmpty()) { - functionName = methodInfo.name; - } - nativeFunction = String.format("ptr->%s(%s)", functionName, argsString); - fileContent = fileContent.replace("$funcName", nativeFunction); - fileContent = fileContent.replace("$initPointer", initPointer.toString()); + fileContent = new StringBuilder(fileContent.toString().replace("$funcName", functionCall)); out.println(fileContent); - - } else { call(methodInfo, returnPrefix, false); returnAfter(methodInfo); From 41c975cc443c8b6ebb5d30cc3692bb39e1878099 Mon Sep 17 00:00:00 2001 From: FITOR Date: Fri, 17 Jan 2025 09:41:30 +0100 Subject: [PATCH 18/28] added feature, whichc allows the user to compile the generated source files into a single linked library instead of multiple different ones --- .../org/bytedeco/javacpp/tools/Builder.java | 115 +++-- .../org/bytedeco/javacpp/tools/Generator.java | 430 +++++++++--------- .../javacpp/properties/windows-x86.properties | 2 +- .../properties/windows-x86_64.properties | 2 +- 4 files changed, 292 insertions(+), 257 deletions(-) diff --git a/src/main/java/org/bytedeco/javacpp/tools/Builder.java b/src/main/java/org/bytedeco/javacpp/tools/Builder.java index 84ac2bfc8..fa2d06081 100644 --- a/src/main/java/org/bytedeco/javacpp/tools/Builder.java +++ b/src/main/java/org/bytedeco/javacpp/tools/Builder.java @@ -22,44 +22,20 @@ package org.bytedeco.javacpp.tools; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.FilenameFilter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.PrintWriter; +import org.bytedeco.javacpp.ClassProperties; +import org.bytedeco.javacpp.Loader; +import org.slf4j.LoggerFactory; + +import java.io.*; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; -import java.nio.file.DirectoryNotEmptyException; -import java.nio.file.FileAlreadyExistsException; -import java.nio.file.FileVisitOption; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.StandardCopyOption; -import java.nio.file.StandardOpenOption; +import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Properties; +import java.util.*; import java.util.jar.JarOutputStream; import java.util.zip.ZipEntry; -import org.bytedeco.javacpp.ClassProperties; -import org.bytedeco.javacpp.Loader; - /** * The Builder is responsible for coordinating efforts between the Parser, the * Generator, and the native compiler. It contains the main() method, and basically @@ -70,6 +46,8 @@ */ public class Builder { + private static final org.slf4j.Logger log = LoggerFactory.getLogger(Builder.class); + /** * Deletes {@link #outputDirectory} if {@link #clean} is true. * @throws IOException @@ -192,17 +170,7 @@ void includeJavaPaths(ClassProperties properties, boolean header) { } } - /** - * Launches and waits for the native compiler to produce a native shared library. - * - * @param sourceFilenames the C++ source filenames - * @param outputFilename the output filename of the shared library - * @param properties the Properties detailing the compiler options to use - * @return the result of {@link Process#waitFor()} - * @throws IOException - * @throws InterruptedException - */ - int compile(String[] sourceFilenames, String outputFilename, ClassProperties properties, File workingDirectory) + List getActualCommand(String[] sourceFilenames, String outputFilename, ClassProperties properties) throws IOException, InterruptedException { ArrayList command = new ArrayList(); @@ -268,9 +236,11 @@ int compile(String[] sourceFilenames, String outputFilename, ClassProperties pro } } + Set sourceFilenamesSet = new HashSet<>(); for (int i = sourceFilenames.length - 1; i >= 0; i--) { - command.add(sourceFilenames[i]); + sourceFilenamesSet.add(sourceFilenames[i]); } + command.addAll(sourceFilenamesSet); List allOptions = properties.get("platform.compiler.*"); if (!allOptions.contains("!default") && !allOptions.contains("default")) { @@ -441,11 +411,33 @@ int compile(String[] sourceFilenames, String outputFilename, ClassProperties pro command.set(i, arg); } + return command; + } + + + int compile(List command, File workingDirectory) throws IOException, InterruptedException { // Use the library output path as the working directory so that all // build files, including intermediate ones from MSVC, are dumped there return commandExecutor.executeCommand(command, workingDirectory, environmentVariables); } + /** + * Launches and waits for the native compiler to produce a native shared library. + * + * @param sourceFilenames the C++ source filenames + * @param outputFilename the output filename of the shared library + * @param properties the Properties detailing the compiler options to use + * @return the result of {@link Process#waitFor()} + * @throws IOException + * @throws InterruptedException + */ + int compile(String[] sourceFilenames, String outputFilename, ClassProperties properties, File workingDirectory) throws IOException, InterruptedException { + List actualCommand = getActualCommand(sourceFilenames, outputFilename, properties); + // Use the library output path as the working directory so that all + // build files, including intermediate ones from MSVC, are dumped there + return commandExecutor.executeCommand(actualCommand, workingDirectory, environmentVariables); + } + /** * Creates and returns the directory where output files should be placed. * Uses {@link #outputDirectory} as is when available, but falls back @@ -585,7 +577,7 @@ File[] generateAndCompile(Class[] classes, String outputName, boolean first, boo } } if (generated) { - if (compile) { + if (compile && !compileSingleDll) { int exitValue = 0; String s = properties.getProperty("platform.library.static", "false").toLowerCase(); if (s.equals("true") || s.equals("t") || s.equals("")) { @@ -722,6 +714,8 @@ public Builder(Logger logger) { /** Logger where to send debug, info, warning, and error messages. */ final Logger logger; + /** Flag allows the user to compile the generated files into a single .dll/.so instead of multiple different ones */ + boolean compileSingleDll = false; /** The name of the character encoding used for input files as well as output files. */ String encoding = null; /** The directory where the generated files and compiled shared libraries get written to. @@ -803,6 +797,15 @@ public Builder compile(boolean compile) { this.compile = compile; return this; } + + /** + * Sets the {@link #compileSingleDll} field to the argument. + */ + public Builder compileSingleDll(boolean compileSingleDll) { + this.compileSingleDll = compileSingleDll; + return this; + } + /** Sets the {@link #deleteJniFiles} field to the argument. */ public Builder deleteJniFiles(boolean deleteJniFiles) { this.deleteJniFiles = deleteJniFiles; @@ -1326,6 +1329,7 @@ public static void printHelp() { System.out.println(" -clean Delete the output directory before generating anything in it"); System.out.println(" -nogenerate Do not try to generate C++ source files, only try to parse header files"); System.out.println(" -nocompile Do not compile or delete the generated C++ source files"); + System.out.println(" -compile-single-dll Compile the generated C++ source files, to a single linked library"); System.out.println(" -nodelete Do not delete generated C++ JNI files after compilation"); System.out.println(" -header Generate header file with declarations of callbacks functions"); System.out.println(" -copylibs Copy to output directory dependent libraries (link and preload)"); @@ -1407,6 +1411,10 @@ public static void main(String[] args) throws Exception { i = args.length; } else if ("-print".equals(args[i])) { printPath = args[++i]; + + } else if ("-compile-single-dll".equals(args[i])) { + builder.compileSingleDll(true); + } else if (args[i].startsWith("-")) { builder.logger.error("Invalid option \"" + args[i] + "\""); printHelp(); @@ -1462,6 +1470,8 @@ public static void main(String[] args) throws Exception { } Files.write(f, s.getBytes(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); } + + if (outputFiles != null && outputFiles.length > 0 && !classes.isEmpty() && execArgs != null) { Class c = classes.iterator().next(); ArrayList command = new ArrayList(Arrays.asList("java", "-cp")); @@ -1472,7 +1482,24 @@ public static void main(String[] args) throws Exception { command.add(paths); command.add(c.getCanonicalName()); command.addAll(Arrays.asList(execArgs)); + + log.info("RUNNING COMMAND: " + Arrays.toString(command.toArray(new String[0]))); System.exit(builder.commandExecutor.executeCommand(command, builder.workingDirectory, builder.environmentVariables)); + + } else if (builder.compileSingleDll) { + List outputFilesList = new ArrayList<>(); + for (File file : outputFiles) { + outputFilesList.add(file.getAbsolutePath()); + } + + final String filenamePrefix = builder.properties.getProperty("platform.library.prefix"); + final String filenameSuffix = builder.properties.getProperty("platform.library.suffix"); + String outputFilename = "javaCpp_single"; + + ClassProperties classProperties = Loader.loadProperties(classes.toArray(new Class[0]), builder.properties, true); + List actualCommand = builder.getActualCommand(outputFilesList.toArray(new String[0]), filenamePrefix + outputFilename + filenameSuffix, classProperties); + log.info("RUNNING COMMAND TO BUILD SINGLE DLL: " + Arrays.toString(actualCommand.toArray(new String[0]))); + System.exit(builder.commandExecutor.executeCommand(actualCommand, new File("build"), builder.environmentVariables)); } } } diff --git a/src/main/java/org/bytedeco/javacpp/tools/Generator.java b/src/main/java/org/bytedeco/javacpp/tools/Generator.java index 59e07efb3..ce6335aa3 100644 --- a/src/main/java/org/bytedeco/javacpp/tools/Generator.java +++ b/src/main/java/org/bytedeco/javacpp/tools/Generator.java @@ -432,9 +432,6 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver } } } - out.println("static JavaVM* JavaCPP_vm = NULL;"); - out.println("static bool JavaCPP_haveAllocObject = false;"); - out.println("static bool JavaCPP_haveNonvirtual = false;"); out.println("static const char* JavaCPP_classNames[" + jclasses.size() + "] = {"); Iterator classIterator = jclasses.iterator(); int maxMemberSize = 0; @@ -451,28 +448,66 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver } out.println(" };"); out.println("static jclass JavaCPP_classes[" + jclasses.size() + "] = { NULL };"); - out.println("static jfieldID JavaCPP_addressFID = NULL;"); - out.println("static jfieldID JavaCPP_positionFID = NULL;"); - out.println("static jfieldID JavaCPP_limitFID = NULL;"); - out.println("static jfieldID JavaCPP_capacityFID = NULL;"); - out.println("static jfieldID JavaCPP_deallocatorFID = NULL;"); - out.println("static jfieldID JavaCPP_ownerAddressFID = NULL;"); - if (declareEnums) { - out.println("static jfieldID JavaCPP_booleanValueFID = NULL;"); - out.println("static jfieldID JavaCPP_byteValueFID = NULL;"); - out.println("static jfieldID JavaCPP_shortValueFID = NULL;"); - out.println("static jfieldID JavaCPP_intValueFID = NULL;"); - out.println("static jfieldID JavaCPP_longValueFID = NULL;"); - } - out.println("static jmethodID JavaCPP_initMID = NULL;"); - out.println("static jmethodID JavaCPP_arrayMID = NULL;"); - out.println("static jmethodID JavaCPP_arrayOffsetMID = NULL;"); - out.println("static jfieldID JavaCPP_bufferPositionFID = NULL;"); - out.println("static jfieldID JavaCPP_bufferLimitFID = NULL;"); - out.println("static jfieldID JavaCPP_bufferCapacityFID = NULL;"); - out.println("static jmethodID JavaCPP_stringMID = NULL;"); - out.println("static jmethodID JavaCPP_getBytesMID = NULL;"); - out.println("static jmethodID JavaCPP_toStringMID = NULL;"); + if (baseLoadSuffix != null && !baseLoadSuffix.isEmpty()) { + out.println("extern JavaVM* JavaCPP_vm;"); + out.println("extern bool JavaCPP_haveAllocObject;"); + out.println("extern bool JavaCPP_haveNonvirtual;"); + + out.println("extern jfieldID JavaCPP_addressFID;"); + out.println("extern jfieldID JavaCPP_positionFID;"); + out.println("extern jfieldID JavaCPP_limitFID;"); + out.println("extern jfieldID JavaCPP_capacityFID;"); + out.println("extern jfieldID JavaCPP_deallocatorFID;"); + out.println("extern jfieldID JavaCPP_ownerAddressFID;"); + if (declareEnums) { + out.println("extern jfieldID JavaCPP_booleanValueFID;"); + out.println("extern jfieldID JavaCPP_byteValueFID;"); + out.println("extern jfieldID JavaCPP_shortValueFID;"); + out.println("extern jfieldID JavaCPP_intValueFID;"); + out.println("extern jfieldID JavaCPP_longValueFID;"); + } + out.println("extern jmethodID JavaCPP_initMID;"); + out.println("extern jmethodID JavaCPP_arrayMID;"); + out.println("extern jmethodID JavaCPP_arrayOffsetMID;"); + out.println("extern jfieldID JavaCPP_bufferPositionFID;"); + out.println("extern jfieldID JavaCPP_bufferLimitFID;"); + out.println("extern jfieldID JavaCPP_bufferCapacityFID;"); + out.println("extern jmethodID JavaCPP_stringMID;"); + out.println("extern jmethodID JavaCPP_getBytesMID;"); + out.println("extern jmethodID JavaCPP_toStringMID;"); + + // only in javacpp.cpp + } else { + out.println("extern JavaVM* JavaCPP_vm = NULL;"); + out.println("extern bool JavaCPP_haveAllocObject = false;"); + out.println("extern bool JavaCPP_haveNonvirtual = false;"); + + out.println("jfieldID JavaCPP_addressFID = NULL;"); + out.println("jfieldID JavaCPP_positionFID = NULL;"); + out.println("jfieldID JavaCPP_limitFID = NULL;"); + out.println("jfieldID JavaCPP_capacityFID = NULL;"); + out.println("jfieldID JavaCPP_deallocatorFID = NULL;"); + out.println("jfieldID JavaCPP_ownerAddressFID = NULL;"); + if (declareEnums) { + out.println("jfieldID JavaCPP_booleanValueFID = NULL;"); + out.println("jfieldID JavaCPP_byteValueFID = NULL;"); + out.println("jfieldID JavaCPP_shortValueFID = NULL;"); + out.println("jfieldID JavaCPP_intValueFID = NULL;"); + out.println("jfieldID JavaCPP_longValueFID = NULL;"); + } + out.println("jmethodID JavaCPP_initMID = NULL;"); + out.println("jmethodID JavaCPP_arrayMID = NULL;"); + out.println("jmethodID JavaCPP_arrayOffsetMID = NULL;"); + out.println("jfieldID JavaCPP_bufferPositionFID = NULL;"); + out.println("jfieldID JavaCPP_bufferLimitFID = NULL;"); + out.println("jfieldID JavaCPP_bufferCapacityFID = NULL;"); + out.println("jmethodID JavaCPP_stringMID = NULL;"); + out.println("jmethodID JavaCPP_getBytesMID = NULL;"); + out.println("jmethodID JavaCPP_toStringMID = NULL;"); + + + + } out.println("#ifdef STRING_BYTES_CHARSET"); out.println("#ifdef MODIFIED_UTF8_STRING"); out.println("#pragma message (\"warning: STRING_BYTES_CHARSET and MODIFIED_UTF8_STRING are mutually exclusive.\")"); @@ -1730,207 +1765,180 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver } if (baseLoadSuffix != null && !baseLoadSuffix.isEmpty()) { out.println(); - out.println("JNIEXPORT jint JNICALL JNI_OnLoad" + baseLoadSuffix + "(JavaVM* vm, void* reserved);"); - out.println("JNIEXPORT void JNICALL JNI_OnUnload" + baseLoadSuffix + "(JavaVM* vm, void* reserved);"); - } - out.println(); // XXX: JNI_OnLoad() should ideally be protected by some mutex - out.println("JNIEXPORT jint JNICALL JNI_OnLoad" + loadSuffix + "(JavaVM* vm, void* reserved) {"); - if (baseLoadSuffix != null && !baseLoadSuffix.isEmpty()) { - out.println(" if (JNI_OnLoad" + baseLoadSuffix + "(vm, reserved) == JNI_ERR) {"); + out.println("JNIEXPORT jint JNICALL JNI_OnLoad" + "(JavaVM* vm, void* reserved);"); + out.println("JNIEXPORT void JNICALL JNI_OnUnload" + "(JavaVM* vm, void* reserved);"); + } else { + out.println(); // XXX: JNI_OnLoad() should ideally be protected by some mutex + out.println("JNIEXPORT jint JNICALL JNI_OnLoad" + "(JavaVM* vm, void* reserved) {"); + out.println(" JNIEnv* env;"); + out.println(" if (vm->GetEnv((void**)&env, " + JNI_VERSION + ") != JNI_OK) {"); + out.println(" JavaCPP_log(\"Could not get JNIEnv for " + JNI_VERSION + " inside JNI_OnLoad" + loadSuffix + "().\");"); out.println(" return JNI_ERR;"); out.println(" }"); - } - out.println(" JNIEnv* env;"); - out.println(" if (vm->GetEnv((void**)&env, " + JNI_VERSION + ") != JNI_OK) {"); - out.println(" JavaCPP_log(\"Could not get JNIEnv for " + JNI_VERSION + " inside JNI_OnLoad" + loadSuffix + "().\");"); - out.println(" return JNI_ERR;"); - out.println(" }"); - out.println(" if (JavaCPP_vm == vm) {"); - out.println(" return env->GetVersion();"); - out.println(" }"); - out.println(" JavaCPP_vm = vm;"); - out.println(" JavaCPP_haveAllocObject = env->functions->AllocObject != NULL;"); - out.println(" JavaCPP_haveNonvirtual = env->functions->CallNonvirtualVoidMethodA != NULL;"); - out.println(" jmethodID putMemberOffsetMID = JavaCPP_getStaticMethodID(env, " + - jclasses.index(Loader.class) + ", \"putMemberOffset\", \"(Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/Class;\");"); - out.println(" if (putMemberOffsetMID == NULL) {"); - out.println(" return JNI_ERR;"); - out.println(" }"); - out.println(" for (int i = 0; i < " + jclasses.size() + " && !env->ExceptionCheck(); i++) {"); - out.println(" for (int j = 0; j < JavaCPP_memberOffsetSizes[i] && !env->ExceptionCheck(); j++) {"); - out.println(" if (env->PushLocalFrame(3) == 0) {"); - out.println(" jvalue args[3];"); - out.println(" args[0].l = env->NewStringUTF(JavaCPP_classNames[i]);"); - out.println(" args[1].l = JavaCPP_members[i][j] == NULL ? NULL : env->NewStringUTF(JavaCPP_members[i][j]);"); - out.println(" args[2].i = JavaCPP_offsets[i][j];"); - out.println(" jclass cls = (jclass)env->CallStaticObjectMethodA(JavaCPP_getClass(env, " + - jclasses.index(Loader.class) + "), putMemberOffsetMID, args);"); - out.println(" if (env->ExceptionCheck()) {"); - out.println(" JavaCPP_log(\"Error putting member offsets for class %s.\", JavaCPP_classNames[i]);"); - out.println(" return JNI_ERR;"); - out.println(" }"); - out.println(" JavaCPP_classes[i] = cls == NULL ? NULL : (jclass)env->NewWeakGlobalRef(cls);"); // cache here for custom class loaders - out.println(" if (env->ExceptionCheck()) {"); - out.println(" JavaCPP_log(\"Error creating global reference of class %s.\", JavaCPP_classNames[i]);"); - out.println(" return JNI_ERR;"); - out.println(" }"); - out.println(" env->PopLocalFrame(NULL);"); - out.println(" }"); - out.println(" }"); - out.println(" }"); - out.println(" JavaCPP_addressFID = JavaCPP_getFieldID(env, " + - jclasses.index(Pointer.class) + ", \"address\", \"J\");"); - out.println(" if (JavaCPP_addressFID == NULL) {"); - out.println(" return JNI_ERR;"); - out.println(" }"); - out.println(" JavaCPP_positionFID = JavaCPP_getFieldID(env, " + - jclasses.index(Pointer.class) + ", \"position\", \"J\");"); - out.println(" if (JavaCPP_positionFID == NULL) {"); - out.println(" return JNI_ERR;"); - out.println(" }"); - out.println(" JavaCPP_limitFID = JavaCPP_getFieldID(env, " + - jclasses.index(Pointer.class) + ", \"limit\", \"J\");"); - out.println(" if (JavaCPP_limitFID == NULL) {"); - out.println(" return JNI_ERR;"); - out.println(" }"); - out.println(" JavaCPP_capacityFID = JavaCPP_getFieldID(env, " + - jclasses.index(Pointer.class) + ", \"capacity\", \"J\");"); - out.println(" if (JavaCPP_capacityFID == NULL) {"); - out.println(" return JNI_ERR;"); - out.println(" }"); - out.println(" JavaCPP_deallocatorFID = JavaCPP_getFieldID(env, " + - jclasses.index(Pointer.class) + ", \"deallocator\", \"" + signature(deallocator) + "\");"); - out.println(" if (JavaCPP_deallocatorFID == NULL) {"); - out.println(" return JNI_ERR;"); - out.println(" }"); - out.println(" JavaCPP_ownerAddressFID = JavaCPP_getFieldID(env, " + jclasses.index(nativeDeallocator) + ", \"ownerAddress\", \"J\");"); - out.println(" if (JavaCPP_ownerAddressFID == NULL) {"); - out.println(" return JNI_ERR;"); - out.println(" }"); - if (declareEnums) { - out.println(" JavaCPP_booleanValueFID = JavaCPP_getFieldID(env, \"" + BooleanEnum.class.getName().replace('.', '/') + "\", \"value\", \"Z\");"); - out.println(" if (JavaCPP_booleanValueFID == NULL) {"); + out.println(" if (JavaCPP_vm == vm) {"); + out.println(" return env->GetVersion();"); + out.println(" }"); + out.println(" JavaCPP_vm = vm;"); + out.println(" JavaCPP_haveAllocObject = env->functions->AllocObject != NULL;"); + out.println(" JavaCPP_haveNonvirtual = env->functions->CallNonvirtualVoidMethodA != NULL;"); + out.println(" jmethodID putMemberOffsetMID = JavaCPP_getStaticMethodID(env, " + + jclasses.index(Loader.class) + ", \"putMemberOffset\", \"(Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/Class;\");"); + out.println(" if (putMemberOffsetMID == NULL) {"); out.println(" return JNI_ERR;"); out.println(" }"); - out.println(" JavaCPP_byteValueFID = JavaCPP_getFieldID(env, \"" + ByteEnum.class.getName().replace('.', '/') + "\", \"value\", \"B\");"); - out.println(" if (JavaCPP_byteValueFID == NULL) {"); + out.println(" JavaCPP_addressFID = JavaCPP_getFieldID(env, " + + jclasses.index(Pointer.class) + ", \"address\", \"J\");"); + out.println(" if (JavaCPP_addressFID == NULL) {"); out.println(" return JNI_ERR;"); out.println(" }"); - out.println(" JavaCPP_shortValueFID = JavaCPP_getFieldID(env, \"" + ShortEnum.class.getName().replace('.', '/') + "\", \"value\", \"S\");"); - out.println(" if (JavaCPP_shortValueFID == NULL) {"); + out.println(" JavaCPP_positionFID = JavaCPP_getFieldID(env, " + + jclasses.index(Pointer.class) + ", \"position\", \"J\");"); + out.println(" if (JavaCPP_positionFID == NULL) {"); out.println(" return JNI_ERR;"); out.println(" }"); - out.println(" JavaCPP_intValueFID = JavaCPP_getFieldID(env, \"" + IntEnum.class.getName().replace('.', '/') + "\", \"value\", \"I\");"); - out.println(" if (JavaCPP_intValueFID == NULL) {"); + out.println(" JavaCPP_limitFID = JavaCPP_getFieldID(env, " + + jclasses.index(Pointer.class) + ", \"limit\", \"J\");"); + out.println(" if (JavaCPP_limitFID == NULL) {"); out.println(" return JNI_ERR;"); out.println(" }"); - out.println(" JavaCPP_longValueFID = JavaCPP_getFieldID(env, \"" + LongEnum.class.getName().replace('.', '/') + "\", \"value\", \"J\");"); - out.println(" if (JavaCPP_longValueFID == NULL) {"); + out.println(" JavaCPP_capacityFID = JavaCPP_getFieldID(env, " + + jclasses.index(Pointer.class) + ", \"capacity\", \"J\");"); + out.println(" if (JavaCPP_capacityFID == NULL) {"); out.println(" return JNI_ERR;"); out.println(" }"); - } - out.println(" JavaCPP_initMID = JavaCPP_getMethodID(env, " + jclasses.index(Pointer.class) + ", \"init\", \"(JJJJ)V\");"); - out.println(" if (JavaCPP_initMID == NULL) {"); - out.println(" return JNI_ERR;"); - out.println(" }"); - out.println(" JavaCPP_arrayMID = JavaCPP_getMethodID(env, " + jclasses.index(Buffer.class) + ", \"array\", \"()Ljava/lang/Object;\");"); - out.println(" if (JavaCPP_arrayMID == NULL) {"); - out.println(" return JNI_ERR;"); - out.println(" }"); - out.println(" JavaCPP_arrayOffsetMID = JavaCPP_getMethodID(env, " + jclasses.index(Buffer.class) + ", \"arrayOffset\", \"()I\");"); - out.println(" if (JavaCPP_arrayOffsetMID == NULL) {"); - out.println(" return JNI_ERR;"); - out.println(" }"); - out.println(" JavaCPP_bufferPositionFID = JavaCPP_getFieldID(env, " + jclasses.index(Buffer.class) + ", \"position\", \"I\");"); - out.println(" if (JavaCPP_bufferPositionFID == NULL) {"); - out.println(" return JNI_ERR;"); - out.println(" }"); - out.println(" JavaCPP_bufferLimitFID = JavaCPP_getFieldID(env, " + jclasses.index(Buffer.class) + ", \"limit\", \"I\");"); - out.println(" if (JavaCPP_bufferLimitFID == NULL) {"); - out.println(" return JNI_ERR;"); - out.println(" }"); - out.println(" JavaCPP_bufferCapacityFID = JavaCPP_getFieldID(env, " + jclasses.index(Buffer.class) + ", \"capacity\", \"I\");"); - out.println(" if (JavaCPP_bufferCapacityFID == NULL) {"); - out.println(" return JNI_ERR;"); - out.println(" }"); - out.println(" JavaCPP_stringMID = JavaCPP_getMethodID(env, " + jclasses.index(String.class) + ", \"\", \"([B)V\");"); - out.println(" if (JavaCPP_stringMID == NULL) {"); - out.println(" return JNI_ERR;"); - out.println(" }"); - out.println(" JavaCPP_getBytesMID = JavaCPP_getMethodID(env, " + jclasses.index(String.class) + ", \"getBytes\", \"()[B\");"); - out.println(" if (JavaCPP_getBytesMID == NULL) {"); - out.println(" return JNI_ERR;"); - out.println(" }"); - out.println(" JavaCPP_toStringMID = JavaCPP_getMethodID(env, " + jclasses.index(Object.class) + ", \"toString\", \"()Ljava/lang/String;\");"); - out.println(" if (JavaCPP_toStringMID == NULL) {"); - out.println(" return JNI_ERR;"); - out.println(" }"); - out.println("#ifdef STRING_BYTES_CHARSET"); - out.println(" jmethodID charsetForNameMID = JavaCPP_getStaticMethodID(env, " + jclasses.index(Charset.class) + ", \"forName\", \"(Ljava/lang/String;)Ljava/nio/charset/Charset;\");"); - out.println(" if (charsetForNameMID == NULL) {"); - out.println(" return JNI_ERR;"); - out.println(" }"); - out.println(" jstring charsetName = env->NewStringUTF(STRING_BYTES_CHARSET);"); - out.println(" if (charsetName == NULL || env->ExceptionCheck()) {"); - out.println(" JavaCPP_log(\"Error creating java.lang.String from '%s'\", STRING_BYTES_CHARSET);"); - out.println(" return JNI_ERR;"); - out.println(" }"); - out.println(" JavaCPP_stringBytesCharset = env->CallStaticObjectMethod(JavaCPP_getClass(env, " + jclasses.index(Charset.class) + "), charsetForNameMID, charsetName);"); - out.println(" if (JavaCPP_stringBytesCharset == NULL || env->ExceptionCheck()) {"); - out.println(" JavaCPP_log(\"Error when calling Charset.forName() for '%s'\", STRING_BYTES_CHARSET);"); - out.println(" return JNI_ERR;"); - out.println(" }"); - out.println(" JavaCPP_stringBytesCharset = env->NewGlobalRef(JavaCPP_stringBytesCharset);"); - out.println(" if (JavaCPP_stringBytesCharset == NULL) {"); - out.println(" JavaCPP_log(\"Error creating global reference for java.nio.charset.Charset instance\");"); - out.println(" return JNI_ERR;"); - out.println(" }"); - out.println(" JavaCPP_stringWithCharsetMID = JavaCPP_getMethodID(env, " + jclasses.index(String.class) + ", \"\", \"([BLjava/nio/charset/Charset;)V\");"); - out.println(" if (JavaCPP_stringWithCharsetMID == NULL) {"); - out.println(" return JNI_ERR;"); - out.println(" }"); - out.println(" JavaCPP_getBytesWithCharsetMID = JavaCPP_getMethodID(env, " + jclasses.index(String.class) + ", \"getBytes\", \"(Ljava/nio/charset/Charset;)[B\");"); - out.println(" if (JavaCPP_getBytesWithCharsetMID == NULL) {"); - out.println(" return JNI_ERR;"); - out.println(" }"); - out.println("#endif // STRING_BYTES_CHARSET"); - out.println(" return env->GetVersion();"); - out.println("}"); - out.println(); - if (out2 != null) { - out2.println("JNIIMPORT int JavaCPP_uninit" + loadSuffix + "();"); - out2.println(); - out.println("JNIEXPORT int JavaCPP_uninit" + loadSuffix + "() {"); - out.println("#if defined(__ANDROID__) || TARGET_OS_IPHONE"); - out.println(" return JNI_OK;"); - out.println("#else"); - out.println(" JavaVM *vm = JavaCPP_vm;"); - out.println(" JNI_OnUnload" + loadSuffix + "(JavaCPP_vm, NULL);"); - out.println(" return vm->DestroyJavaVM();"); + out.println(" JavaCPP_deallocatorFID = JavaCPP_getFieldID(env, " + + jclasses.index(Pointer.class) + ", \"deallocator\", \"" + signature(deallocator) + "\");"); + out.println(" if (JavaCPP_deallocatorFID == NULL) {"); + out.println(" return JNI_ERR;"); + out.println(" }"); + out.println(" JavaCPP_ownerAddressFID = JavaCPP_getFieldID(env, " + jclasses.index(nativeDeallocator) + ", \"ownerAddress\", \"J\");"); + out.println(" if (JavaCPP_ownerAddressFID == NULL) {"); + out.println(" return JNI_ERR;"); + out.println(" }"); + if (declareEnums) { + out.println(" JavaCPP_booleanValueFID = JavaCPP_getFieldID(env, \"" + BooleanEnum.class.getName().replace('.', '/') + "\", \"value\", \"Z\");"); + out.println(" if (JavaCPP_booleanValueFID == NULL) {"); + out.println(" return JNI_ERR;"); + out.println(" }"); + out.println(" JavaCPP_byteValueFID = JavaCPP_getFieldID(env, \"" + ByteEnum.class.getName().replace('.', '/') + "\", \"value\", \"B\");"); + out.println(" if (JavaCPP_byteValueFID == NULL) {"); + out.println(" return JNI_ERR;"); + out.println(" }"); + out.println(" JavaCPP_shortValueFID = JavaCPP_getFieldID(env, \"" + ShortEnum.class.getName().replace('.', '/') + "\", \"value\", \"S\");"); + out.println(" if (JavaCPP_shortValueFID == NULL) {"); + out.println(" return JNI_ERR;"); + out.println(" }"); + out.println(" JavaCPP_intValueFID = JavaCPP_getFieldID(env, \"" + IntEnum.class.getName().replace('.', '/') + "\", \"value\", \"I\");"); + out.println(" if (JavaCPP_intValueFID == NULL) {"); + out.println(" return JNI_ERR;"); + out.println(" }"); + out.println(" JavaCPP_longValueFID = JavaCPP_getFieldID(env, \"" + LongEnum.class.getName().replace('.', '/') + "\", \"value\", \"J\");"); + out.println(" if (JavaCPP_longValueFID == NULL) {"); + out.println(" return JNI_ERR;"); + out.println(" }"); + } + out.println(" JavaCPP_initMID = JavaCPP_getMethodID(env, " + jclasses.index(Pointer.class) + ", \"init\", \"(JJJJ)V\");"); + out.println(" if (JavaCPP_initMID == NULL) {"); + out.println(" return JNI_ERR;"); + out.println(" }"); + out.println(" JavaCPP_arrayMID = JavaCPP_getMethodID(env, " + jclasses.index(Buffer.class) + ", \"array\", \"()Ljava/lang/Object;\");"); + out.println(" if (JavaCPP_arrayMID == NULL) {"); + out.println(" return JNI_ERR;"); + out.println(" }"); + out.println(" JavaCPP_arrayOffsetMID = JavaCPP_getMethodID(env, " + jclasses.index(Buffer.class) + ", \"arrayOffset\", \"()I\");"); + out.println(" if (JavaCPP_arrayOffsetMID == NULL) {"); + out.println(" return JNI_ERR;"); + out.println(" }"); + out.println(" JavaCPP_bufferPositionFID = JavaCPP_getFieldID(env, " + jclasses.index(Buffer.class) + ", \"position\", \"I\");"); + out.println(" if (JavaCPP_bufferPositionFID == NULL) {"); + out.println(" return JNI_ERR;"); + out.println(" }"); + out.println(" JavaCPP_bufferLimitFID = JavaCPP_getFieldID(env, " + jclasses.index(Buffer.class) + ", \"limit\", \"I\");"); + out.println(" if (JavaCPP_bufferLimitFID == NULL) {"); + out.println(" return JNI_ERR;"); + out.println(" }"); + out.println(" JavaCPP_bufferCapacityFID = JavaCPP_getFieldID(env, " + jclasses.index(Buffer.class) + ", \"capacity\", \"I\");"); + out.println(" if (JavaCPP_bufferCapacityFID == NULL) {"); + out.println(" return JNI_ERR;"); + out.println(" }"); + out.println(" JavaCPP_stringMID = JavaCPP_getMethodID(env, " + jclasses.index(String.class) + ", \"\", \"([B)V\");"); + out.println(" if (JavaCPP_stringMID == NULL) {"); + out.println(" return JNI_ERR;"); + out.println(" }"); + out.println(" JavaCPP_getBytesMID = JavaCPP_getMethodID(env, " + jclasses.index(String.class) + ", \"getBytes\", \"()[B\");"); + out.println(" if (JavaCPP_getBytesMID == NULL) {"); + out.println(" return JNI_ERR;"); + out.println(" }"); + out.println(" JavaCPP_toStringMID = JavaCPP_getMethodID(env, " + jclasses.index(Object.class) + ", \"toString\", \"()Ljava/lang/String;\");"); + out.println(" if (JavaCPP_toStringMID == NULL) {"); + out.println(" return JNI_ERR;"); + out.println(" }"); + out.println("#ifdef STRING_BYTES_CHARSET"); + out.println(" jmethodID charsetForNameMID = JavaCPP_getStaticMethodID(env, " + jclasses.index(Charset.class) + ", \"forName\", \"(Ljava/lang/String;)Ljava/nio/charset/Charset;\");"); + out.println(" if (charsetForNameMID == NULL) {"); + out.println(" return JNI_ERR;"); + out.println(" }"); + out.println(" jstring charsetName = env->NewStringUTF(STRING_BYTES_CHARSET);"); + out.println(" if (charsetName == NULL || env->ExceptionCheck()) {"); + out.println(" JavaCPP_log(\"Error creating java.lang.String from '%s'\", STRING_BYTES_CHARSET);"); + out.println(" return JNI_ERR;"); + out.println(" }"); + out.println(" JavaCPP_stringBytesCharset = env->CallStaticObjectMethod(JavaCPP_getClass(env, " + jclasses.index(Charset.class) + "), charsetForNameMID, charsetName);"); + out.println(" if (JavaCPP_stringBytesCharset == NULL || env->ExceptionCheck()) {"); + out.println(" JavaCPP_log(\"Error when calling Charset.forName() for '%s'\", STRING_BYTES_CHARSET);"); + out.println(" return JNI_ERR;"); + out.println(" }"); + out.println(" JavaCPP_stringBytesCharset = env->NewGlobalRef(JavaCPP_stringBytesCharset);"); + out.println(" if (JavaCPP_stringBytesCharset == NULL) {"); + out.println(" JavaCPP_log(\"Error creating global reference for java.nio.charset.Charset instance\");"); + out.println(" return JNI_ERR;"); + out.println(" }"); + out.println(" JavaCPP_stringWithCharsetMID = JavaCPP_getMethodID(env, " + jclasses.index(String.class) + ", \"\", \"([BLjava/nio/charset/Charset;)V\");"); + out.println(" if (JavaCPP_stringWithCharsetMID == NULL) {"); + out.println(" return JNI_ERR;"); + out.println(" }"); + out.println(" JavaCPP_getBytesWithCharsetMID = JavaCPP_getMethodID(env, " + jclasses.index(String.class) + ", \"getBytes\", \"(Ljava/nio/charset/Charset;)[B\");"); + out.println(" if (JavaCPP_getBytesWithCharsetMID == NULL) {"); + out.println(" return JNI_ERR;"); + out.println(" }"); + out.println("#endif // STRING_BYTES_CHARSET"); + out.println(" return env->GetVersion();"); + out.println("}"); + out.println(); + if (out2 != null) { + out2.println("JNIIMPORT int JavaCPP_uninit" + loadSuffix + "();"); + out2.println(); + out.println("JNIEXPORT int JavaCPP_uninit" + loadSuffix + "() {"); + out.println("#if defined(__ANDROID__) || TARGET_OS_IPHONE"); + out.println(" return JNI_OK;"); + out.println("#else"); + out.println(" JavaVM *vm = JavaCPP_vm;"); + out.println(" JNI_OnUnload" + loadSuffix + "(JavaCPP_vm, NULL);"); + out.println(" return vm->DestroyJavaVM();"); + out.println("#endif"); + out.println("}"); + } + + + out.println(); + out.println("JNIEXPORT void JNICALL JNI_OnUnload" + "(JavaVM* vm, void* reserved) {"); + out.println(" JNIEnv* env;"); + out.println(" if (vm->GetEnv((void**)&env, " + JNI_VERSION + ") != JNI_OK) {"); + out.println(" JavaCPP_log(\"Could not get JNIEnv for " + JNI_VERSION + " inside JNI_OnUnLoad" + loadSuffix + "().\");"); + out.println(" return;"); + out.println(" }"); + out.println(" for (int i = 0; i < " + jclasses.size() + "; i++) {"); + out.println(" env->DeleteWeakGlobalRef((jweak)JavaCPP_classes[i]);"); + out.println(" JavaCPP_classes[i] = NULL;"); + out.println(" }"); + out.println("#ifdef STRING_BYTES_CHARSET"); + out.println(" env->DeleteGlobalRef(JavaCPP_stringBytesCharset);"); + out.println(" JavaCPP_stringBytesCharset = NULL;"); out.println("#endif"); + out.println(" JavaCPP_vm = NULL;"); out.println("}"); + out.println(); } - out.println(); - out.println("JNIEXPORT void JNICALL JNI_OnUnload" + loadSuffix + "(JavaVM* vm, void* reserved) {"); - out.println(" JNIEnv* env;"); - out.println(" if (vm->GetEnv((void**)&env, " + JNI_VERSION + ") != JNI_OK) {"); - out.println(" JavaCPP_log(\"Could not get JNIEnv for " + JNI_VERSION + " inside JNI_OnUnLoad" + loadSuffix + "().\");"); - out.println(" return;"); - out.println(" }"); - out.println(" for (int i = 0; i < " + jclasses.size() + "; i++) {"); - out.println(" env->DeleteWeakGlobalRef((jweak)JavaCPP_classes[i]);"); - out.println(" JavaCPP_classes[i] = NULL;"); - out.println(" }"); - out.println("#ifdef STRING_BYTES_CHARSET"); - out.println(" env->DeleteGlobalRef(JavaCPP_stringBytesCharset);"); - out.println(" JavaCPP_stringBytesCharset = NULL;"); - out.println("#endif"); - if (baseLoadSuffix != null && !baseLoadSuffix.isEmpty()) { - out.println(" JNI_OnUnload" + baseLoadSuffix + "(vm, reserved);"); - } - out.println(" JavaCPP_vm = NULL;"); - out.println("}"); - out.println(); boolean supportedPlatform = false; LinkedHashSet allClasses = new LinkedHashSet(); diff --git a/src/main/resources/org/bytedeco/javacpp/properties/windows-x86.properties b/src/main/resources/org/bytedeco/javacpp/properties/windows-x86.properties index a1fa58165..0f65a5b26 100644 --- a/src/main/resources/org/bytedeco/javacpp/properties/windows-x86.properties +++ b/src/main/resources/org/bytedeco/javacpp/properties/windows-x86.properties @@ -9,7 +9,7 @@ platform.compiler.cpp03= platform.compiler.cpp11= platform.compiler.cpp14=/std:c++14 /Zc:__cplusplus platform.compiler.cpp17=/std:c++17 /Zc:__cplusplus -platform.compiler.debug=/Od /EHsc /MTd /LDd +platform.compiler.debug=/Od /EHsc /MTd /LDd /Zi /DEBUG platform.compiler.default=/Oi /O2 /EHsc /Gy /GL /MT /LD platform.compiler.fastfpu=/arch:SSE2 /fp:fast platform.compiler.nodeprecated=/wd4996 diff --git a/src/main/resources/org/bytedeco/javacpp/properties/windows-x86_64.properties b/src/main/resources/org/bytedeco/javacpp/properties/windows-x86_64.properties index e3f9c8e25..17defc053 100644 --- a/src/main/resources/org/bytedeco/javacpp/properties/windows-x86_64.properties +++ b/src/main/resources/org/bytedeco/javacpp/properties/windows-x86_64.properties @@ -9,7 +9,7 @@ platform.compiler.cpp03= platform.compiler.cpp11= platform.compiler.cpp14=/std:c++14 /Zc:__cplusplus platform.compiler.cpp17=/std:c++17 /Zc:__cplusplus -platform.compiler.debug=/Od /EHsc /MTd /LDd +platform.compiler.debug=/Od /EHsc /MTd /LDd /Zi /DEBUG platform.compiler.default=/Oi /O2 /EHsc /Gy /GL /MT /LD platform.compiler.fastfpu=/fp:fast platform.compiler.nodeprecated=/wd4996 From 73bb54e23aabc088c87671e780736eee11bf1350 Mon Sep 17 00:00:00 2001 From: FITOR Date: Fri, 17 Jan 2025 09:55:44 +0100 Subject: [PATCH 19/28] removed logger --- src/main/java/org/bytedeco/javacpp/tools/Builder.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/main/java/org/bytedeco/javacpp/tools/Builder.java b/src/main/java/org/bytedeco/javacpp/tools/Builder.java index fa2d06081..57c0014a9 100644 --- a/src/main/java/org/bytedeco/javacpp/tools/Builder.java +++ b/src/main/java/org/bytedeco/javacpp/tools/Builder.java @@ -24,7 +24,6 @@ import org.bytedeco.javacpp.ClassProperties; import org.bytedeco.javacpp.Loader; -import org.slf4j.LoggerFactory; import java.io.*; import java.net.URI; @@ -45,9 +44,6 @@ * @author Samuel Audet */ public class Builder { - - private static final org.slf4j.Logger log = LoggerFactory.getLogger(Builder.class); - /** * Deletes {@link #outputDirectory} if {@link #clean} is true. * @throws IOException @@ -1483,7 +1479,6 @@ public static void main(String[] args) throws Exception { command.add(c.getCanonicalName()); command.addAll(Arrays.asList(execArgs)); - log.info("RUNNING COMMAND: " + Arrays.toString(command.toArray(new String[0]))); System.exit(builder.commandExecutor.executeCommand(command, builder.workingDirectory, builder.environmentVariables)); } else if (builder.compileSingleDll) { @@ -1498,7 +1493,7 @@ public static void main(String[] args) throws Exception { ClassProperties classProperties = Loader.loadProperties(classes.toArray(new Class[0]), builder.properties, true); List actualCommand = builder.getActualCommand(outputFilesList.toArray(new String[0]), filenamePrefix + outputFilename + filenameSuffix, classProperties); - log.info("RUNNING COMMAND TO BUILD SINGLE DLL: " + Arrays.toString(actualCommand.toArray(new String[0]))); + System.out.println("RUNNING COMMAND TO BUILD SINGLE DLL: " + Arrays.toString(actualCommand.toArray(new String[0]))); System.exit(builder.commandExecutor.executeCommand(actualCommand, new File("build"), builder.environmentVariables)); } } From c235041c952d6d51ba4c32007d4b2f5b0f7828b7 Mon Sep 17 00:00:00 2001 From: FITOR Date: Thu, 23 Jan 2025 12:10:38 +0100 Subject: [PATCH 20/28] slight adjustment --- src/main/java/org/bytedeco/javacpp/tools/Generator.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/bytedeco/javacpp/tools/Generator.java b/src/main/java/org/bytedeco/javacpp/tools/Generator.java index ce6335aa3..9c1510299 100644 --- a/src/main/java/org/bytedeco/javacpp/tools/Generator.java +++ b/src/main/java/org/bytedeco/javacpp/tools/Generator.java @@ -4512,6 +4512,8 @@ private String readFileContent(final String filePath, boolean isLocal) { } } catch (IOException e) { throw new RuntimeException("Unable to load file: " + filePath, e); + } catch (NullPointerException e) { + throw new RuntimeException("Null pointer exception thrown for file: " + filePath, e); } return result.toString(); From 6e41b01459b08a4d96ab96ea586841973e4efc45 Mon Sep 17 00:00:00 2001 From: FITOR Date: Sat, 25 Jan 2025 16:54:15 +0100 Subject: [PATCH 21/28] enabled more precise cross language polymorphism, by adjusting the Virtual annotation --- .../bytedeco/javacpp/annotation/Virtual.java | 6 ++ .../org/bytedeco/javacpp/tools/Generator.java | 75 ++++++++++++++++--- 2 files changed, 72 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/bytedeco/javacpp/annotation/Virtual.java b/src/main/java/org/bytedeco/javacpp/annotation/Virtual.java index 7b2568816..dcd88c1aa 100644 --- a/src/main/java/org/bytedeco/javacpp/annotation/Virtual.java +++ b/src/main/java/org/bytedeco/javacpp/annotation/Virtual.java @@ -22,4 +22,10 @@ boolean value() default false; boolean subclasses() default true; String method() default ""; + + String returnType() default ""; + String methodName() default ""; + String[] callbackParameterTypes() default {}; + String[] customCallbackFilepath() default {}; + String[] customCallbackEndFilepath() default {}; } diff --git a/src/main/java/org/bytedeco/javacpp/tools/Generator.java b/src/main/java/org/bytedeco/javacpp/tools/Generator.java index 9c1510299..f1f686401 100644 --- a/src/main/java/org/bytedeco/javacpp/tools/Generator.java +++ b/src/main/java/org/bytedeco/javacpp/tools/Generator.java @@ -3036,6 +3036,7 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo String instanceTypeName = functionClassName(cls); String[] callbackTypeName = cppFunctionTypeName(callbackMethod); + String[] returnConvention = callbackTypeName[0].split("\\("); String[] returnType = {returnConvention[0] + (returnConvention.length > 2 ? "(*" : ""), returnConvention.length > 2 ? ")(" + returnConvention[2] : ""}; if (returnConvention.length > 2) { @@ -3063,6 +3064,11 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo } } + Virtual virtualAnnotation = null; + String customReturnType = ""; + String customMethodName = ""; + String[] customParamTypes = {}; + String firstLine = ""; if (methodInfo != null) { // stuff from a virtualized class @@ -3105,14 +3111,33 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo } } - member += "virtual " + returnType[0] + (returnConvention.length > 1 ? returnConvention[1] : "") + methodInfo.memberName[0] + parameterDeclaration + returnType[1] + (isConstMember ? " const" : "") + " JavaCPP_override;\n " + returnType[0] + "super_" + methodInfo.name + nonconstParamDeclaration + returnType[1] + " { "; + virtualAnnotation = methodInfo.method.getAnnotation(Virtual.class); + customReturnType = virtualAnnotation.returnType(); + customMethodName = virtualAnnotation.methodName(); + customParamTypes = virtualAnnotation.callbackParameterTypes(); + + String customParams = "("; + for (int i = 0; i < customParamTypes.length; ++i) { + customParams += customParamTypes[i] + "arg" + i; + if (i < customParamTypes.length - 1) { customParams += ", "; } + } + customParams += ")"; + + StringBuilder memberBuilder = new StringBuilder(); + memberBuilder.append("virtual ").append(customReturnType.isEmpty() ? returnType[0] : customReturnType).append(returnConvention.length > 1 ? returnConvention[1] : "").append(customMethodName.isEmpty() ? methodInfo.memberName[0] : customMethodName).append(customParamTypes.length == 0 ? parameterDeclaration + returnType[1] : customParams).append(isConstMember ? " const" : "").append(" JavaCPP_override;\n ").append(customReturnType.isEmpty() ? returnType[0] : customReturnType).append("super_" + (customMethodName.isEmpty() ? methodInfo.name : customMethodName)).append(customParamTypes.length == 0 ? nonconstParamDeclaration + returnType[1] : customParams).append(" { "); + member += memberBuilder.toString(); + if (methodInfo.method.getAnnotation(Virtual.class).value()) { member += "throw JavaCPP_exception(\"Cannot call pure virtual function " + valueTypeName + "::" + methodInfo.memberName[0] + "().\"); }"; } else { member += (callbackReturnType != void.class ? "return " : "") + valueTypeName + "::" + methodInfo.memberName[0] + "("; member += callbackArguments + "); }"; } - firstLine = returnType[0] + (returnConvention.length > 1 ? returnConvention[1] : "") + subType + "::" + methodInfo.memberName[0] + parameterDeclaration + returnType[1] + (isConstMember ? " const" : "") +" {"; + + StringBuilder firstLineBuilder = new StringBuilder(); + firstLineBuilder.append(customReturnType.isEmpty() ? returnType[0] + (returnConvention.length > 1 ? returnConvention[1] : "") : customReturnType).append(subType + "::").append(customMethodName.isEmpty() ? methodInfo.memberName[0] : customMethodName).append(customParamTypes.length == 0 ? parameterDeclaration + returnType[1] : customParams).append(isConstMember ? " const" : "").append(" {"); + + firstLine = firstLineBuilder.toString(); functionList.add(fieldName); } memberList.add(member); @@ -3182,7 +3207,8 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo out.println(" }"); out.println("{"); if (callbackParameterTypes.length > 0) { - out.println(" jvalue args[" + callbackParameterTypes.length + "];"); + + out.println(" jvalue args[" + (customParamTypes.length == 0 ? callbackParameterTypes.length : customParamTypes.length) + "];"); for (int j = 0; j < callbackParameterTypes.length; j++) { Annotation passBy = by(callbackParameterAnnotations[j]); if (callbackParameterTypes[j].isPrimitive()) { @@ -3224,7 +3250,14 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo valueTypeName = subType; } out.println(" " + jniTypeName(callbackParameterTypes[j]) + " obj" + j + " = NULL;"); - out.println(" " + typeName[0] + " ptr" + j + typeName[1] + " = NULL;"); + + String paramType = typeName[0]; + try { + paramType = customParamTypes[j].replace('&', '*').replace("const", ""); + } catch (IndexOutOfBoundsException e) { + // do nothing + } + out.println(" " + paramType + " ptr" + j + typeName[1] + " = NULL;"); if (FunctionPointer.class.isAssignableFrom(callbackParameterTypes[j])) { out.println(" ptr" + j + " = new (std::nothrow) " + valueTypeName + ";"); out.println(" if (ptr" + j + " != NULL) {"); @@ -3243,6 +3276,13 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo out.println(" ptr" + j + " = " + cast + "*arg" + j + ";"); out.println(" }"); } else { // ByPtr || ByPtrRef + try { + cast = customParamTypes[j]; + if (cast.contains("&")) { cast = "(" + cast.replace("&", "*)&").replace("const", ""); } + } catch (IndexOutOfBoundsException e) { + // do nothing + } + out.println(" ptr" + j + " = " + cast + "arg" + j + ";"); } } @@ -3268,6 +3308,7 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo adapterInfo = adapterInformation(true, valueTypeName, callbackParameterAnnotations[j]); if (adapterInfo != null || passBy instanceof ByPtrPtr || passBy instanceof ByPtrRef) { out.println(s); + } else { out.println(" if (ptr" + j + " != NULL) { "); out.println(" " + s); @@ -3357,16 +3398,26 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo out.println(" } else if (mid == NULL) {"); out.println(" JavaCPP_log(\"Error getting method ID of function caller \\\"" + callbackMethod + "\\\" for callback.\");"); out.println(" } else {"); + + String s = "Object"; if (callbackReturnType.isPrimitive()) { s = callbackReturnType.getName(); s = Character.toUpperCase(s.charAt(0)) + s.substring(1); } - out.println(" " + returnPrefix + "env->Call" + s + "MethodA(obj, mid, " + (callbackParameterTypes.length == 0 ? "NULL);" : "args);")); - if (throwsExceptions) { - out.println(" if ((exc = env->ExceptionOccurred()) != NULL) {"); - out.println(" env->ExceptionClear();"); - out.println(" }"); + + if (virtualAnnotation != null && virtualAnnotation.customCallbackFilepath().length > 0) { + for (String path : virtualAnnotation.customCallbackFilepath()) { + out.println(getFileContentFromOther(path)); + } + } else { + + out.println(" " + returnPrefix + "env->Call" + s + "MethodA(obj, mid, " + (callbackParameterTypes.length == 0 ? "NULL);" : "args);")); + if (throwsExceptions) { + out.println(" if ((exc = env->ExceptionOccurred()) != NULL) {"); + out.println(" env->ExceptionClear();"); + out.println(" }"); + } } out.println(" }"); @@ -3412,6 +3463,12 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo out.println("}"); out.println("end:"); + if (virtualAnnotation != null) { + for (String path : virtualAnnotation.customCallbackEndFilepath()) { + out.println(getFileContentFromOther(path)); + } + } + if (callbackReturnType != void.class) { if ("void*".equals(returnTypeName[0]) && !callbackReturnType.isAnnotationPresent(Opaque.class)) { returnTypeName[0] = "char*"; From 469428bf230dc5314a0ee98f71731eda1d715afc Mon Sep 17 00:00:00 2001 From: FITOR Date: Wed, 29 Jan 2025 14:26:31 +0100 Subject: [PATCH 22/28] adjusted @Virutal annotation and Generator --- .../java/org/bytedeco/javacpp/tools/Generator.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/bytedeco/javacpp/tools/Generator.java b/src/main/java/org/bytedeco/javacpp/tools/Generator.java index f1f686401..c3c2cb35a 100644 --- a/src/main/java/org/bytedeco/javacpp/tools/Generator.java +++ b/src/main/java/org/bytedeco/javacpp/tools/Generator.java @@ -3253,7 +3253,8 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo String paramType = typeName[0]; try { - paramType = customParamTypes[j].replace('&', '*').replace("const", ""); + paramType = customParamTypes[j].replace("&", ""); + paramType = (paramType + "*").replace("const", ""); } catch (IndexOutOfBoundsException e) { // do nothing } @@ -3279,11 +3280,15 @@ void callback(Class cls, Method callbackMethod, String callbackName, int allo try { cast = customParamTypes[j]; if (cast.contains("&")) { cast = "(" + cast.replace("&", "*)&").replace("const", ""); } + else if(cast.contains("*")) { cast = "(" + cast + ")"; } + else { + cast = (" new " + cast + "(*(" + cast + "*)&arg" + j + ");").replace("const", ""); + out.println(cast); + } } catch (IndexOutOfBoundsException e) { - // do nothing + out.println(" ptr" + j + " = " + cast + "arg" + j + ";"); } - out.println(" ptr" + j + " = " + cast + "arg" + j + ";"); } } From dfed92cb60640ff1f42b158a78cd8185e63fe164 Mon Sep 17 00:00:00 2001 From: FITOR Date: Thu, 30 Jan 2025 12:42:48 +0100 Subject: [PATCH 23/28] enabled custom classloading --- .../org/bytedeco/javacpp/tools/Generator.java | 23 ++++- .../javacpp/jniTemplates/JNIClassLoader.h | 85 +++++++++++++++++++ 2 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 src/main/resources/org/bytedeco/javacpp/jniTemplates/JNIClassLoader.h diff --git a/src/main/java/org/bytedeco/javacpp/tools/Generator.java b/src/main/java/org/bytedeco/javacpp/tools/Generator.java index c3c2cb35a..d25852f20 100644 --- a/src/main/java/org/bytedeco/javacpp/tools/Generator.java +++ b/src/main/java/org/bytedeco/javacpp/tools/Generator.java @@ -448,7 +448,12 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver } out.println(" };"); out.println("static jclass JavaCPP_classes[" + jclasses.size() + "] = { NULL };"); + + out.println("#include "); if (baseLoadSuffix != null && !baseLoadSuffix.isEmpty()) { + out.println("extern jobject gClassLoader;"); + out.println("extern std::mutex gClassLoaderMutex;"); + out.println("extern JavaVM* JavaCPP_vm;"); out.println("extern bool JavaCPP_haveAllocObject;"); out.println("extern bool JavaCPP_haveNonvirtual;"); @@ -478,9 +483,12 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver // only in javacpp.cpp } else { - out.println("extern JavaVM* JavaCPP_vm = NULL;"); - out.println("extern bool JavaCPP_haveAllocObject = false;"); - out.println("extern bool JavaCPP_haveNonvirtual = false;"); + out.println("jobject gClassLoader = nullptr;"); + out.println("std::mutex gClassLoaderMutex;"); + + out.println("JavaVM* JavaCPP_vm = NULL;"); + out.println("bool JavaCPP_haveAllocObject = false;"); + out.println("bool JavaCPP_haveNonvirtual = false;"); out.println("jfieldID JavaCPP_addressFID = NULL;"); out.println("jfieldID JavaCPP_positionFID = NULL;"); @@ -1767,7 +1775,16 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver out.println(); out.println("JNIEXPORT jint JNICALL JNI_OnLoad" + "(JavaVM* vm, void* reserved);"); out.println("JNIEXPORT void JNICALL JNI_OnUnload" + "(JavaVM* vm, void* reserved);"); + + out.println("jclass findNVDClass(JNIEnv *env, const char *className);"); + out.println("void ensureContextClassLoader(JNIEnv *env);"); + out.println("void setClassLoader(jobject classLoader);"); + } else { + out.println(); + out.println(getFileContentFromLocal("/org/bytedeco/javacpp/jniTemplates/JNIClassLoader.h")); + out.println(); + out.println(); // XXX: JNI_OnLoad() should ideally be protected by some mutex out.println("JNIEXPORT jint JNICALL JNI_OnLoad" + "(JavaVM* vm, void* reserved) {"); out.println(" JNIEnv* env;"); diff --git a/src/main/resources/org/bytedeco/javacpp/jniTemplates/JNIClassLoader.h b/src/main/resources/org/bytedeco/javacpp/jniTemplates/JNIClassLoader.h new file mode 100644 index 000000000..c3fad5c21 --- /dev/null +++ b/src/main/resources/org/bytedeco/javacpp/jniTemplates/JNIClassLoader.h @@ -0,0 +1,85 @@ +jclass findNVDClass(JNIEnv *env, const char *className) { + if (gClassLoader == nullptr) { return nullptr; } + + // Ensure the gClassLoader is valid + jclass classLoaderClass = env->GetObjectClass(gClassLoader); + if (classLoaderClass == nullptr) { return nullptr; } + + // Find the loadClass method + jmethodID loadClassMethod = env->GetMethodID(classLoaderClass, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); + if (loadClassMethod == nullptr) { return nullptr; } + + // Convert the class name to a Java string + jstring javaClassName = env->NewStringUTF(className); + if (javaClassName == nullptr) { return nullptr; } + + // Use the ClassLoader to load the class + jclass loadedClass = static_cast(env->CallObjectMethod(gClassLoader, loadClassMethod, javaClassName)); + + // Clean up the local reference for the Java string + env->DeleteLocalRef(javaClassName); + + // Check for exceptions or null result + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); // Optional: Print the exception + env->ExceptionClear(); + } + + return loadedClass; +} + + +void ensureContextClassLoader(JNIEnv *env) { + if (gClassLoader == nullptr) { throw std::runtime_error("Class loader not set. Call setClassLoader first."); } + + // Get the current thread + jclass threadClass = env->FindClass("java/lang/Thread"); + if (!threadClass) { throw std::runtime_error("Failed to find Thread class."); } + + jmethodID currentThreadMethod = env->GetStaticMethodID(threadClass, "currentThread", "()Ljava/lang/Thread;"); + if (!currentThreadMethod) { throw std::runtime_error("Failed to find currentThread method."); } + + jobject currentThread = env->CallStaticObjectMethod(threadClass, currentThreadMethod); + if (!currentThread) { throw std::runtime_error("Failed to get current thread."); } + + // Get the getContextClassLoader method + jmethodID getContextClassLoaderMethod = env->GetMethodID(threadClass, "getContextClassLoader", "()Ljava/lang/ClassLoader;"); + if (!getContextClassLoaderMethod) { throw std::runtime_error("Failed to find getContextClassLoader method."); } + + jobject currentClassLoader = env->CallObjectMethod(currentThread, getContextClassLoaderMethod); + + // Check if the context class loader is null + if (currentClassLoader == nullptr) { + // Get the setContextClassLoader method + jmethodID setContextClassLoaderMethod = env->GetMethodID(threadClass, "setContextClassLoader", "(Ljava/lang/ClassLoader;)V"); + if (!setContextClassLoaderMethod) { throw std::runtime_error("Failed to find setContextClassLoader method."); } + + // Set the stored global class loader + env->CallVoidMethod(currentThread, setContextClassLoaderMethod, gClassLoader); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); // Optional: Print the exception + env->ExceptionClear(); + throw std::runtime_error("Failed to set context class loader."); + } + } +} + +void setClassLoader(jobject classLoader) { + JNIEnv* env = nullptr; + JavaVM* jvm = nullptr; + + // Attach the current thread to the JVM if needed + jint res = JavaCPP_vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_2); + if (res != JNI_OK) { + throw std::runtime_error("Failed to get JNIEnv."); + } + + std::lock_guard lock(gClassLoaderMutex); + + if (gClassLoader) { + env->DeleteGlobalRef(gClassLoader); + gClassLoader = nullptr; + } + + gClassLoader = env->NewGlobalRef(classLoader); +} \ No newline at end of file From 353a647044c740e85a6f377e95d75e21fc1ee2d7 Mon Sep 17 00:00:00 2001 From: FITOR Date: Fri, 31 Jan 2025 16:12:06 +0100 Subject: [PATCH 24/28] advanced customMapper --- .../javacpp/annotation/CustomMapper.java | 7 + .../org/bytedeco/javacpp/tools/Generator.java | 334 +++++++++++------- 2 files changed, 206 insertions(+), 135 deletions(-) diff --git a/src/main/java/org/bytedeco/javacpp/annotation/CustomMapper.java b/src/main/java/org/bytedeco/javacpp/annotation/CustomMapper.java index d0d14381b..2ea774dd4 100644 --- a/src/main/java/org/bytedeco/javacpp/annotation/CustomMapper.java +++ b/src/main/java/org/bytedeco/javacpp/annotation/CustomMapper.java @@ -41,4 +41,11 @@ * @return True if the parameter of the function shall be dereferenced. */ boolean dereferenceParams() default false; + + /** + * @return The values which should be replaced with (replaces index 0 with 1, 2 with 3...) + */ + String[] replacements() default {}; + + String typename() default ""; } \ No newline at end of file diff --git a/src/main/java/org/bytedeco/javacpp/tools/Generator.java b/src/main/java/org/bytedeco/javacpp/tools/Generator.java index d25852f20..b96ba996c 100644 --- a/src/main/java/org/bytedeco/javacpp/tools/Generator.java +++ b/src/main/java/org/bytedeco/javacpp/tools/Generator.java @@ -2175,6 +2175,16 @@ boolean methods(Class cls) { typeName[0] = functionClassName(cls) + "*"; typeName[1] = ""; } + + for (Annotation annotation : methodInfo.annotations) { + if (annotation.annotationType().equals(CustomMapper.class)) { + CustomMapper mapper = (CustomMapper) annotation; + if (!mapper.typename().isEmpty()) { + typeName[0] = mapper.typename(); + } + } + } + out.println(" " + typeName[0] + " ptr" + typeName[1] + " = (" + typeName[0] + typeName[1] + ")jlong_to_ptr(env->GetLongField(obj, JavaCPP_addressFID));"); out.println(" if (ptr == NULL) {"); out.println(" env->ThrowNew(JavaCPP_getClass(env, " + jclasses.index(NullPointerException.class) + "), \"This pointer address is NULL.\");"); @@ -2203,10 +2213,11 @@ boolean methods(Class cls) { boolean containsCustomMapping = false; String functionCall = ""; StringBuilder fileContent = new StringBuilder(); + String[] replacements = {}; + String customTypename = ""; for (Annotation annotation : methodInfo.annotations) { if (annotation.annotationType().equals(CustomMapper.class)) { - containsCustomMapping = true; CustomMapper mapper = (CustomMapper) annotation; final String[] mappingFilePaths = mapper.filePaths(); @@ -2226,16 +2237,34 @@ boolean methods(Class cls) { for (String path : mappingFilePaths) { fileContent.append(getFileContentFromOther(path)); } + + replacements = mapper.replacements(); + containsCustomMapping = !fileContent.toString().isEmpty(); } } // ignore the default mapping if the customMapping has been enabled if (containsCustomMapping) { + fileContent = new StringBuilder(fileContent.toString().replace("$funcName", functionCall)); - out.println(fileContent); + String actualContent = fileContent.toString(); + + if (replacements.length >= 2) { + actualContent = replaceStrings(replacements, actualContent); + } + out.println(actualContent); + } else { - call(methodInfo, returnPrefix, false); - returnAfter(methodInfo); + String call = callString(methodInfo, returnPrefix, false); + String returnAfter = returnAfterString(methodInfo); + + if (replacements.length >= 2) { + call = replaceStrings(replacements, call); + returnAfter = replaceStrings(replacements, returnAfter); + } + + out.println(call); + out.println(returnAfter); } parametersAfter(methodInfo); @@ -2527,7 +2556,14 @@ String returnBefore(MethodInformation methodInfo) { return returnPrefix; } - void call(MethodInformation methodInfo, String returnPrefix, boolean secondCall) { + public void call(MethodInformation methodInfo, String returnPrefix, boolean secondCall) { + out.println(callString(methodInfo, returnPrefix, secondCall)); + } + + public String callString(MethodInformation methodInfo, String returnPrefix, boolean secondCall) { + StringWriter localSW = new StringWriter(); + PrintWriter localPW = new PrintWriter(localSW); + boolean needSecondCall = false; String indent = secondCall ? "" : methodInfo.throwsException != null ? " " : " "; String prefix = "("; @@ -2538,68 +2574,70 @@ void call(MethodInformation methodInfo, String returnPrefix, boolean secondCall) index = methodInfo.pairedMethod.getAnnotation(Index.class); } if (methodInfo.deallocator) { - out.println(indent + "void* allocatedAddress = jlong_to_ptr(arg0);"); - out.println(indent + "void (*deallocatorAddress)(void*) = (void(*)(void*))jlong_to_ptr(arg1);"); - out.println(indent + "if (deallocatorAddress != NULL && allocatedAddress != NULL) {"); - out.println(indent + " (*deallocatorAddress)(allocatedAddress);"); - out.println(indent + "}"); - return; // nothing else should be appended here for deallocator + localPW.println(indent + "void* allocatedAddress = jlong_to_ptr(arg0);"); + localPW.println(indent + "void (*deallocatorAddress)(void*) = (void(*)(void*))jlong_to_ptr(arg1);"); + localPW.println(indent + "if (deallocatorAddress != NULL && allocatedAddress != NULL) {"); + localPW.println(indent + " (*deallocatorAddress)(allocatedAddress);"); + localPW.println(indent + "}"); + + localPW.flush(); + return localSW.toString(); } else if (!FunctionPointer.class.isAssignableFrom(methodInfo.cls) && (methodInfo.valueGetter || methodInfo.valueSetter || methodInfo.memberGetter || methodInfo.memberSetter)) { boolean wantsPointer = false; int k = methodInfo.parameterTypes.length - 1; if ((methodInfo.valueSetter || methodInfo.memberSetter) && !(by(methodInfo, k) instanceof ByRef) && adapterInformation(false, methodInfo, k) == null && methodInfo.parameterTypes[k] == String.class) { // special considerations for char arrays as strings if (asUtf16(methodInfo, k)) { - out.print(indent + "memcpy("); + localPW.print(indent + "memcpy("); suffix = ", (std::char_traits::length(ptr" + k + ") + 1) * sizeof(unsigned short))"; } else { - out.print(indent + "strcpy((char*)"); + localPW.print(indent + "strcpy((char*)"); } wantsPointer = true; prefix = ", "; } else if (k >= 1 && methodInfo.parameterTypes[0].isArray() && methodInfo.parameterTypes[0].getComponentType().isPrimitive() && (methodInfo.parameterTypes[1] == int.class || methodInfo.parameterTypes[1] == long.class)) { // special considerations for primitive arrays - out.print(indent + "memcpy("); + localPW.print(indent + "memcpy("); wantsPointer = true; prefix = ", "; if (methodInfo.memberGetter || methodInfo.valueGetter) { - out.print("ptr0 + arg1, "); + localPW.print("ptr0 + arg1, "); } else { // methodInfo.memberSetter || methodInfo.valueSetter prefix += "ptr0 + arg1, "; } skipParameters = 2; suffix = " * sizeof(*ptr0)" + suffix; } else { - out.print(indent + returnPrefix); + localPW.print(indent + returnPrefix); prefix = methodInfo.valueGetter || methodInfo.memberGetter ? "" : " = "; suffix = ""; } if (Modifier.isStatic(methodInfo.modifiers) || !Pointer.class.isAssignableFrom(methodInfo.cls)) { - out.print(cppScopeName(methodInfo)); + localPW.print(cppScopeName(methodInfo)); } else if (methodInfo.memberGetter || methodInfo.memberSetter) { if (index != null) { - out.print("(*ptr)"); + localPW.print("(*ptr)"); prefix = "." + methodInfo.memberName[0] + prefix; } else { - out.print("ptr->" + methodInfo.memberName[0]); + localPW.print("ptr->" + methodInfo.memberName[0]); } } else { // methodInfo.valueGetter || methodInfo.valueSetter String cast = cast(methodInfo.returnType, methodInfo.annotations); if (index == null && cast.length() > 0) { // make sure to cast the returned pointer and not the value - out.print("*(" + cast.substring(1, cast.length() - 1) + "*)&"); + localPW.print("*(" + cast.substring(1, cast.length() - 1) + "*)&"); } - out.print(index != null ? "(*ptr)" : methodInfo.dim > 0 || wantsPointer ? "ptr" : "*ptr"); + localPW.print(index != null ? "(*ptr)" : methodInfo.dim > 0 || wantsPointer ? "ptr" : "*ptr"); } } else if (methodInfo.bufferGetter) { - out.print(indent + returnPrefix + "ptr"); + localPW.print(indent + returnPrefix + "ptr"); prefix = ""; suffix = ""; } else { // function call - out.print(indent + returnPrefix); + localPW.print(indent + returnPrefix); if (FunctionPointer.class.isAssignableFrom(methodInfo.cls)) { if (methodInfo.cls.isAnnotationPresent(Namespace.class)) { - out.print("(ptr0->*(ptr->ptr))"); + localPW.print("(ptr0->*(ptr->ptr))"); skipParameters = 1; if (methodInfo.valueGetter || methodInfo.valueSetter) { // this is get/put for a field pointer, not a real function @@ -2608,11 +2646,11 @@ void call(MethodInformation methodInfo, String returnPrefix, boolean secondCall) } } else { if (methodInfo.valueGetter || methodInfo.valueSetter) { - out.print("ptr->ptr"); + localPW.print("ptr->ptr"); prefix = methodInfo.valueGetter ? "" : " = "; suffix = ""; } else { - out.print("(*ptr->ptr)"); + localPW.print("(*ptr->ptr)"); } } } else if (methodInfo.allocator) { @@ -2628,10 +2666,10 @@ void call(MethodInformation methodInfo, String returnPrefix, boolean secondCall) suffix = ""; } else { if (methodInfo.method.isAnnotationPresent(Name.class)) { - out.print(methodInfo.memberName[0]); + localPW.print(methodInfo.memberName[0]); // If method is an array allocator, the function must return a pointer to an array } else { - out.print((noException(methodInfo.cls, methodInfo.method) ? "new (std::nothrow) " : "new ") + valueTypeName + typeName[1]); + localPW.print((noException(methodInfo.cls, methodInfo.method) ? "new (std::nothrow) " : "new ") + valueTypeName + typeName[1]); if (methodInfo.arrayAllocator) { prefix = "["; suffix = "]"; @@ -2639,7 +2677,7 @@ void call(MethodInformation methodInfo, String returnPrefix, boolean secondCall) } } } else if (Modifier.isStatic(methodInfo.modifiers) || !Pointer.class.isAssignableFrom(methodInfo.cls)) { - out.print(cppScopeName(methodInfo)); + localPW.print(cppScopeName(methodInfo)); } else { String name = methodInfo.memberName[0]; String[] typeName = cppTypeName(methodInfo.cls); @@ -2648,28 +2686,28 @@ void call(MethodInformation methodInfo, String returnPrefix, boolean secondCall) String subType = "JavaCPP_" + mangle(valueTypeName); if (Modifier.isPublic(methodInfo.method.getModifiers())) { // non-protected method that could be from any subclass, so check for ours - out.print("(dynamic_cast<" + subType + "*>(ptr) != NULL ? "); + localPW.print("(dynamic_cast<" + subType + "*>(ptr) != NULL ? "); needSecondCall = true; } if (methodInfo.method.isAnnotationPresent(Virtual.class)) { name = "super_" + methodInfo.name; } - out.print("((" + subType + "*)ptr)->" + name); + localPW.print("((" + subType + "*)ptr)->" + name); } else if (secondCall && methodInfo.method.getDeclaringClass() != methodInfo.cls) { // we may have a protected virtual method that isn't protected in the superclass, so let's cast String[] typeName2 = cppTypeName(methodInfo.method.getDeclaringClass()); - out.print("((" + typeName2[0] + typeName2[1] + ")ptr)->" + name); + localPW.print("((" + typeName2[0] + typeName2[1] + ")ptr)->" + name); } else if (index != null) { - out.print("(*ptr)"); + localPW.print("(*ptr)"); prefix = "." + name + prefix; } else { String op = name.startsWith("operator") ? name.substring(8).trim() : ""; if (methodInfo.parameterTypes.length > 0 && (op.equals("=") || op.equals("+") || op.equals("-") || op.equals("*") || op.equals("/") || op.equals("%") || op.equals("==") || op.equals("!=") || op.equals("<") || op.equals(">") || op.equals("<=") || op.equals(">="))) { - out.print("((*ptr)"); + localPW.print("((*ptr)"); prefix = op + prefix; suffix += ")"; } else { - out.print("ptr->" + name); + localPW.print("ptr->" + name); } } } @@ -2678,13 +2716,13 @@ void call(MethodInformation methodInfo, String returnPrefix, boolean secondCall) for (int j = skipParameters; j <= methodInfo.parameterTypes.length; j++) { if (j == skipParameters + methodInfo.dim) { if (methodInfo.memberName.length > 1) { - out.print(methodInfo.memberName[1]); + localPW.print(methodInfo.memberName[1]); } - out.print(prefix); + localPW.print(prefix); if (methodInfo.withEnv) { - out.print(Modifier.isStatic(methodInfo.modifiers) ? "env, cls" : "env, obj"); + localPW.print(Modifier.isStatic(methodInfo.modifiers) ? "env, cls" : "env, obj"); if (methodInfo.parameterTypes.length - skipParameters - methodInfo.dim > 0) { - out.print(", "); + localPW.print(", "); } } } @@ -2695,9 +2733,9 @@ void call(MethodInformation methodInfo, String returnPrefix, boolean secondCall) // print array indices to access array members, or whatever // the C++ operator does with them when the Index annotation is present if (index == null || index.function().length() == 0) { - out.print("["); + localPW.print("["); } else { - out.print("." + index.function() + "("); + localPW.print("." + index.function() + "("); } } Annotation passBy = by(methodInfo, j); @@ -2710,16 +2748,16 @@ void call(MethodInformation methodInfo, String returnPrefix, boolean secondCall) } if (Enum.class.isAssignableFrom(methodInfo.parameterTypes[j])) { accessesEnums = true; - out.print(cast + "val" + j); + localPW.print(cast + "val" + j); } else if (("(void*)".equals(cast) || "(void *)".equals(cast)) && methodInfo.parameterTypes[j] == long.class) { - out.print("jlong_to_ptr(arg" + j + ")"); + localPW.print("jlong_to_ptr(arg" + j + ")"); } else if (methodInfo.parameterTypes[j].isPrimitive()) { if (passBy instanceof ByPtr || passBy instanceof ByPtrRef) { - out.print("&"); + localPW.print("&"); } else if ((passBy instanceof ByVal || passBy instanceof ByRef) && cast.endsWith("*)")) { - out.print("*"); + localPW.print("*"); } - out.print(cast + "arg" + j); + localPW.print(cast + "arg" + j); } else if (adapterInfo != null) { cast = adapterInfo.cast.trim(); if (cast.length() > 0 && !cast.startsWith("(") && !cast.endsWith(")")) { @@ -2729,54 +2767,60 @@ void call(MethodInformation methodInfo, String returnPrefix, boolean secondCall) if (cast2.length() > 0 && !cast2.startsWith("(") && !cast2.endsWith(")")) { cast2 = "(" + cast2 + ")"; } - out.print(cast + cast2 + "adapter" + j); + localPW.print(cast + cast2 + "adapter" + j); j += adapterInfo.argc - 1; } else if (FunctionPointer.class.isAssignableFrom(methodInfo.parameterTypes[j]) && (!(passBy instanceof ByVal || passBy instanceof ByRef) || cast.length() > 0)) { if (passBy instanceof ByPtrRef) { - out.print(cast + "(ptr" + j + "->ptr)"); + localPW.print(cast + "(ptr" + j + "->ptr)"); } else { if (passBy instanceof ByVal || passBy instanceof ByRef) { - out.print("*"); + localPW.print("*"); } - out.print(cast + "(ptr" + j + " == NULL ? NULL : " + (passBy instanceof ByPtrPtr ? "&ptr" : "ptr") + j + "->ptr)"); + localPW.print(cast + "(ptr" + j + " == NULL ? NULL : " + (passBy instanceof ByPtrPtr ? "&ptr" : "ptr") + j + "->ptr)"); } } else if (passBy instanceof ByVal || (passBy instanceof ByRef && methodInfo.parameterTypes[j] != String.class)) { boolean rvalue = passBy instanceof ByRef ? ((ByRef) passBy).value() : false; String nullValue = passBy instanceof ByVal ? ((ByVal) passBy).nullValue() : passBy instanceof ByRef ? ((ByRef) passBy).nullValue() : ""; if (rvalue) { - out.print("std::move("); + localPW.print("std::move("); } - out.print((nullValue.length() > 0 ? "ptr" + j + " == NULL ? " + nullValue + " : " : "") + "*" + cast + "ptr" + j); + localPW.print((nullValue.length() > 0 ? "ptr" + j + " == NULL ? " + nullValue + " : " : "") + "*" + cast + "ptr" + j); if (rvalue) { - out.print(")"); + localPW.print(")"); } } else if (passBy instanceof ByPtrPtr) { - out.print(cast + "(arg" + j + " == NULL ? NULL : &ptr" + j + ")"); + localPW.print(cast + "(arg" + j + " == NULL ? NULL : &ptr" + j + ")"); } else { // ByPtr || ByPtrRef || (ByRef && std::string) - out.print(cast + "ptr" + j); + localPW.print(cast + "ptr" + j); } if (j < skipParameters + methodInfo.dim) { if (index == null || index.function().length() == 0) { - out.print("]"); + localPW.print("]"); } else { - out.print(")"); + localPW.print(")"); } } else if (j < methodInfo.parameterTypes.length - 1) { - out.print(", "); + localPW.print(", "); } } - out.print(suffix); + localPW.print(suffix); if (methodInfo.memberName.length > 2) { - out.print(methodInfo.memberName[2]); + localPW.print(methodInfo.memberName[2]); } if (needSecondCall) { - call(methodInfo, " : ", true); - out.print(")"); + localPW.print(callString(methodInfo, " : ", true)); + localPW.print(")"); } + + localPW.flush(); + return localSW.toString(); } - void returnAfter(MethodInformation methodInfo) { + public String returnAfterString(MethodInformation methodInfo) { + StringWriter localSW = new StringWriter(); + PrintWriter localPW = new PrintWriter(localSW); + String indent = methodInfo.throwsException != null ? " " : " "; String[] typeName = methodInfo.allocator || methodInfo.arrayAllocator ? cppTypeName(methodInfo.cls) : methodInfo.returnRaw ? new String[]{""} : cppCastTypeName(methodInfo.returnType, methodInfo.annotations); Annotation returnBy = by(methodInfo.annotations); @@ -2785,7 +2829,7 @@ void returnAfter(MethodInformation methodInfo) { String suffix = methodInfo.deallocator ? "" : ";"; if (by(methodInfo.annotations) instanceof ByRef && methodInfo.returnType == String.class && adapterInfo == null) { // special considerations for std::string without adapter - out.print(");\n" + indent + "rptr = rstr.c_str()"); + localPW.print(");\n" + indent + "rptr = rstr.c_str()"); } if ((methodInfo.allocator || methodInfo.arrayAllocator || !methodInfo.returnType.isPrimitive()) && adapterInfo != null) { suffix = ")" + suffix; @@ -2794,17 +2838,17 @@ void returnAfter(MethodInformation methodInfo) { if ((returnBy instanceof ByVal || (returnBy instanceof ByRef && ((ByRef) returnBy).value())) && adapterInfo == null) { suffix = ")" + suffix; } else if (returnBy instanceof ByPtrPtr) { - out.println(suffix); + localPW.println(suffix); suffix = ""; - out.println(indent + "if (rptrptr == NULL) {"); - out.println(indent + " env->ThrowNew(JavaCPP_getClass(env, " + jclasses.index(NullPointerException.class) + "), \"Return pointer address is NULL.\");"); - out.println(indent + "} else {"); + localPW.println(indent + "if (rptrptr == NULL) {"); + localPW.println(indent + " env->ThrowNew(JavaCPP_getClass(env, " + jclasses.index(NullPointerException.class) + "), \"Return pointer address is NULL.\");"); + localPW.println(indent + "} else {"); if (FunctionPointer.class.isAssignableFrom(methodInfo.returnType)) { - out.println(indent + " rptr->ptr = *rptrptr;"); + localPW.println(indent + " rptr->ptr = *rptrptr;"); } else { - out.println(indent + " rptr = *rptrptr;"); + localPW.println(indent + " rptr = *rptrptr;"); } - out.println(indent + "}"); + localPW.println(indent + "}"); } if (adapterInfo != null && methodInfo.returnType.isArray() && methodInfo.returnType.getComponentType().isPrimitive()) { // data will get copied out anyway @@ -2813,150 +2857,156 @@ void returnAfter(MethodInformation methodInfo) { } } } - out.println(suffix); + localPW.println(suffix); if (methodInfo.returnType == void.class) { if (methodInfo.allocator || methodInfo.arrayAllocator) { boolean noDeallocator = methodInfo.cls == Pointer.class || methodInfo.cls.isAnnotationPresent(NoDeallocator.class) || methodInfo.method.isAnnotationPresent(NoDeallocator.class); if (adapterInfo != null) { - out.println(indent + typeName[0] + " rptr" + typeName[1] + " = radapter;"); - out.println(indent + "jlong rcapacity = (jlong)radapter.size;"); - out.println(indent + "void* rowner = radapter.owner;"); - if (noDeallocator) out.println(indent + "void (*deallocator)(void*) = 0;"); + localPW.println(indent + typeName[0] + " rptr" + typeName[1] + " = radapter;"); + localPW.println(indent + "jlong rcapacity = (jlong)radapter.size;"); + localPW.println(indent + "void* rowner = radapter.owner;"); + if (noDeallocator) localPW.println(indent + "void (*deallocator)(void*) = 0;"); else - out.println(indent + "void (*deallocator)(void*) = rowner != NULL ? &" + adapterInfo.name + "::deallocate : 0;"); - out.println(indent + "JavaCPP_initPointer(env, obj, rptr, rcapacity, rowner, deallocator);"); + localPW.println(indent + "void (*deallocator)(void*) = rowner != NULL ? &" + adapterInfo.name + "::deallocate : 0;"); + localPW.println(indent + "JavaCPP_initPointer(env, obj, rptr, rcapacity, rowner, deallocator);"); } else { - out.println(indent + "jlong rcapacity = " + (methodInfo.arrayAllocator ? "arg0;" : "1;")); - out.print(indent + "JavaCPP_initPointer(env, obj, rptr, rcapacity, rptr, "); + localPW.println(indent + "jlong rcapacity = " + (methodInfo.arrayAllocator ? "arg0;" : "1;")); + localPW.print(indent + "JavaCPP_initPointer(env, obj, rptr, rcapacity, rptr, "); if (noDeallocator) { - out.println("NULL);"); + localPW.println("NULL);"); } else if (methodInfo.arrayAllocator) { - out.println("&JavaCPP_" + mangle(methodInfo.cls.getName()) + "_deallocateArray);"); + localPW.println("&JavaCPP_" + mangle(methodInfo.cls.getName()) + "_deallocateArray);"); arrayDeallocators.index(methodInfo.cls); } else if (!methodInfo.method.isAnnotationPresent(Name.class)) { - out.println("&JavaCPP_" + mangle(methodInfo.cls.getName()) + "_deallocate);"); + localPW.println("&JavaCPP_" + mangle(methodInfo.cls.getName()) + "_deallocate);"); deallocators.index(methodInfo.cls); } else { // downcast constructor - out.println("NULL);"); + localPW.println("NULL);"); } } if (virtualFunctions.containsKey(methodInfo.cls)) { valueTypeName = valueTypeName(typeName); String subType = "JavaCPP_" + mangle(valueTypeName); - out.println(indent + "((" + subType + "*)rptr)->obj = env->NewWeakGlobalRef(obj);"); + localPW.println(indent + "((" + subType + "*)rptr)->obj = env->NewWeakGlobalRef(obj);"); } } } else { if (methodInfo.valueSetter || methodInfo.memberSetter || methodInfo.noReturnGetter) { // nothing } else if (methodInfo.returnType.isPrimitive()) { - out.println(indent + "rarg = (" + jniTypeName(methodInfo.returnType) + ")rval;"); + localPW.println(indent + "rarg = (" + jniTypeName(methodInfo.returnType) + ")rval;"); } else if (methodInfo.returnRaw) { - out.println(indent + "rarg = rptr;"); + localPW.println(indent + "rarg = rptr;"); } else if (Enum.class.isAssignableFrom(methodInfo.returnType)) { accessesEnums = true; String s = enumValueType(methodInfo.returnType); if (s != null) { String S = Character.toUpperCase(s.charAt(0)) + s.substring(1); - out.println(indent + "if (rarg != NULL) {"); - out.println(indent + " env->Set" + S + "Field(rarg, JavaCPP_" + s + "ValueFID, (j" + s + ")rval);"); - out.println(indent + "}"); + localPW.println(indent + "if (rarg != NULL) {"); + localPW.println(indent + " env->Set" + S + "Field(rarg, JavaCPP_" + s + "ValueFID, (j" + s + ")rval);"); + localPW.println(indent + "}"); } } else { boolean needInit = false; if (adapterInfo != null) { - out.println(indent + "rptr = radapter;"); + localPW.println(indent + "rptr = radapter;"); if (methodInfo.returnType != String.class) { - out.println(indent + "jlong rcapacity = (jlong)radapter.size;"); + localPW.println(indent + "jlong rcapacity = (jlong)radapter.size;"); if (Pointer.class.isAssignableFrom(methodInfo.returnType)) { - out.println(indent + "void* rowner = radapter.owner;"); - out.println(indent + "void (*deallocator)(void*) = rowner != NULL ? &" + adapterInfo.name + "::deallocate : 0;"); + localPW.println(indent + "void* rowner = radapter.owner;"); + localPW.println(indent + "void (*deallocator)(void*) = rowner != NULL ? &" + adapterInfo.name + "::deallocate : 0;"); } else { - out.println(indent + "void (*deallocator)(void*) = 0;"); + localPW.println(indent + "void (*deallocator)(void*) = 0;"); } } needInit = true; } else if (returnBy instanceof ByVal || FunctionPointer.class.isAssignableFrom(methodInfo.returnType)) { - out.println(indent + "jlong rcapacity = 1;"); - out.println(indent + "void* rowner = (void*)rptr;"); - out.println(indent + "void (*deallocator)(void*) = &JavaCPP_" + mangle(methodInfo.returnType.getName()) + "_deallocate;"); + localPW.println(indent + "jlong rcapacity = 1;"); + localPW.println(indent + "void* rowner = (void*)rptr;"); + localPW.println(indent + "void (*deallocator)(void*) = &JavaCPP_" + mangle(methodInfo.returnType.getName()) + "_deallocate;"); deallocators.index(methodInfo.returnType); needInit = true; } if (Pointer.class.isAssignableFrom(methodInfo.returnType)) { - out.print(indent); + localPW.print(indent); if (!(returnBy instanceof ByVal)) { // check if we can reuse one of the Pointer objects from the arguments if (Modifier.isStatic(methodInfo.modifiers) && methodInfo.parameterTypes.length > 0) { for (int i = 0; i < methodInfo.parameterTypes.length; i++) { String cast = cast(methodInfo, i); if (Arrays.equals(methodInfo.parameterAnnotations[i], methodInfo.annotations) && methodInfo.parameterTypes[i] == methodInfo.returnType && !(returnBy instanceof ByPtrPtr) && !(returnBy instanceof ByPtrRef)) { - out.println("if (rptr == " + cast + "ptr" + i + ") {"); - out.println(indent + " rarg = arg" + i + ";"); - out.print(indent + "} else "); + localPW.println("if (rptr == " + cast + "ptr" + i + ") {"); + localPW.println(indent + " rarg = arg" + i + ";"); + localPW.print(indent + "} else "); } } } else if (!Modifier.isStatic(methodInfo.modifiers) && methodInfo.cls == methodInfo.returnType) { - out.println("if (rptr == ptr) {"); - out.println(indent + " rarg = obj;"); - out.print(indent + "} else "); + localPW.println("if (rptr == ptr) {"); + localPW.println(indent + " rarg = obj;"); + localPW.print(indent + "} else "); } } - out.println("if (rptr != NULL) {"); - out.println(indent + " rarg = JavaCPP_createPointer(env, " + jclasses.index(methodInfo.returnType) + (methodInfo.parameterTypes.length > 0 && methodInfo.parameterTypes[0] == Class.class ? ", arg0);" : ");")); - out.println(indent + " if (rarg != NULL) {"); + localPW.println("if (rptr != NULL) {"); + localPW.println(indent + " rarg = JavaCPP_createPointer(env, " + jclasses.index(methodInfo.returnType) + (methodInfo.parameterTypes.length > 0 && methodInfo.parameterTypes[0] == Class.class ? ", arg0);" : ");")); + localPW.println(indent + " if (rarg != NULL) {"); if (needInit) { - out.println(indent + " JavaCPP_initPointer(env, rarg, rptr, rcapacity, rowner, deallocator);"); + localPW.println(indent + " JavaCPP_initPointer(env, rarg, rptr, rcapacity, rowner, deallocator);"); } else { - out.println(indent + " env->SetLongField(rarg, JavaCPP_addressFID, ptr_to_jlong(rptr));"); + localPW.println(indent + " env->SetLongField(rarg, JavaCPP_addressFID, ptr_to_jlong(rptr));"); } - out.println(indent + " }"); - out.println(indent + "}"); + localPW.println(indent + " }"); + localPW.println(indent + "}"); } else if (methodInfo.returnType == String.class) { passesStrings = true; - out.println(indent + "if (rptr != NULL) {"); - out.println(indent + " rarg = " + createString("rptr", (adapterInfo != null ? "radapter" : null), asUtf16(methodInfo.annotations))); - out.println(indent + "}"); + localPW.println(indent + "if (rptr != NULL) {"); + localPW.println(indent + " rarg = " + createString("rptr", (adapterInfo != null ? "radapter" : null), asUtf16(methodInfo.annotations))); + localPW.println(indent + "}"); } else if (methodInfo.returnType.isArray() && methodInfo.returnType.getComponentType().isPrimitive()) { if (adapterInfo == null && !(returnBy instanceof ByVal)) { - out.println(indent + "jlong rcapacity = rptr != NULL ? 1 : 0;"); + localPW.println(indent + "jlong rcapacity = rptr != NULL ? 1 : 0;"); } String componentName = methodInfo.returnType.getComponentType().getName(); String componentNameUpperCase = Character.toUpperCase(componentName.charAt(0)) + componentName.substring(1); - out.println(indent + "if (rptr != NULL) {"); - out.println(indent + " rarg = env->New" + componentNameUpperCase + "Array(rcapacity < INT_MAX ? rcapacity : INT_MAX);"); - out.println(indent + " env->Set" + componentNameUpperCase + "ArrayRegion(rarg, 0, rcapacity < INT_MAX ? rcapacity : INT_MAX, (j" + componentName + "*)rptr);"); - out.println(indent + "}"); + localPW.println(indent + "if (rptr != NULL) {"); + localPW.println(indent + " rarg = env->New" + componentNameUpperCase + "Array(rcapacity < INT_MAX ? rcapacity : INT_MAX);"); + localPW.println(indent + " env->Set" + componentNameUpperCase + "ArrayRegion(rarg, 0, rcapacity < INT_MAX ? rcapacity : INT_MAX, (j" + componentName + "*)rptr);"); + localPW.println(indent + "}"); if (adapterInfo != null) { - out.println(indent + "if (deallocator != 0 && rptr != NULL) {"); - out.println(indent + " (*(void(*)(void*))jlong_to_ptr(deallocator))((void*)rptr);"); - out.println(indent + "}"); + localPW.println(indent + "if (deallocator != 0 && rptr != NULL) {"); + localPW.println(indent + " (*(void(*)(void*))jlong_to_ptr(deallocator))((void*)rptr);"); + localPW.println(indent + "}"); } } else if (Buffer.class.isAssignableFrom(methodInfo.returnType)) { if (methodInfo.bufferGetter) { - out.println(indent + "jlong rposition = position;"); - out.println(indent + "jlong rlimit = limit;"); - out.println(indent + "jlong rcapacity = capacity;"); + localPW.println(indent + "jlong rposition = position;"); + localPW.println(indent + "jlong rlimit = limit;"); + localPW.println(indent + "jlong rcapacity = capacity;"); } else if (adapterInfo == null && !(returnBy instanceof ByVal)) { - out.println(indent + "jlong rcapacity = rptr != NULL ? 1 : 0;"); + localPW.println(indent + "jlong rcapacity = rptr != NULL ? 1 : 0;"); } - out.println(indent + "if (rptr != NULL) {"); - out.println(indent + " jlong rcapacityptr = rcapacity * sizeof(rptr[0]);"); - out.println(indent + " rarg = env->NewDirectByteBuffer((void*)rptr, rcapacityptr < INT_MAX ? rcapacityptr : INT_MAX);"); + localPW.println(indent + "if (rptr != NULL) {"); + localPW.println(indent + " jlong rcapacityptr = rcapacity * sizeof(rptr[0]);"); + localPW.println(indent + " rarg = env->NewDirectByteBuffer((void*)rptr, rcapacityptr < INT_MAX ? rcapacityptr : INT_MAX);"); if (methodInfo.bufferGetter) { - out.println(indent + " jlong rpositionptr = rposition * sizeof(rptr[0]);"); - out.println(indent + " jlong rlimitptr = rlimit * sizeof(rptr[0]);"); - out.println(indent + " env->SetIntField(rarg, JavaCPP_bufferPositionFID, rpositionptr < INT_MAX ? rpositionptr : INT_MAX);"); - out.println(indent + " env->SetIntField(rarg, JavaCPP_bufferLimitFID, rlimitptr < INT_MAX ? rlimitptr : INT_MAX);"); + localPW.println(indent + " jlong rpositionptr = rposition * sizeof(rptr[0]);"); + localPW.println(indent + " jlong rlimitptr = rlimit * sizeof(rptr[0]);"); + localPW.println(indent + " env->SetIntField(rarg, JavaCPP_bufferPositionFID, rpositionptr < INT_MAX ? rpositionptr : INT_MAX);"); + localPW.println(indent + " env->SetIntField(rarg, JavaCPP_bufferLimitFID, rlimitptr < INT_MAX ? rlimitptr : INT_MAX);"); } - out.println(indent + "}"); + localPW.println(indent + "}"); } } } + localPW.flush(); + return localSW.toString(); + } + + void returnAfter(MethodInformation methodInfo) { + out.println(returnAfterString(methodInfo)); } void parametersAfter(MethodInformation methodInfo) { @@ -4597,4 +4647,18 @@ private String readFileContent(final String filePath, boolean isLocal) { return result.toString(); } + + private String replaceStrings(String[] replacements, String source) { + String replacedString = ""; + + if (replacements.length % 2 != 0 && replacements.length < 2) { + throw new IllegalArgumentException("Invalid replacement Strings."); + } + + for (int i = 0; i < replacements.length; i = i + 2) { + replacedString = source.replace(replacements[i], replacements[i + 1]); + } + + return replacedString; + } } \ No newline at end of file From 215439b2ffbc649dc016424718b18ac1d56580fa Mon Sep 17 00:00:00 2001 From: FITOR Date: Mon, 24 Feb 2025 07:11:36 +0100 Subject: [PATCH 25/28] added include --- .../org/bytedeco/javacpp/jniTemplates/JNIClassLoader.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/resources/org/bytedeco/javacpp/jniTemplates/JNIClassLoader.h b/src/main/resources/org/bytedeco/javacpp/jniTemplates/JNIClassLoader.h index c3fad5c21..91fccebdc 100644 --- a/src/main/resources/org/bytedeco/javacpp/jniTemplates/JNIClassLoader.h +++ b/src/main/resources/org/bytedeco/javacpp/jniTemplates/JNIClassLoader.h @@ -1,3 +1,5 @@ +#include + jclass findNVDClass(JNIEnv *env, const char *className) { if (gClassLoader == nullptr) { return nullptr; } From fc6d0c1c90ea7a8f6c7ddafea510e5b88a6e7d68 Mon Sep 17 00:00:00 2001 From: Fitor Avdiji Date: Sun, 8 Jun 2025 22:42:04 +0200 Subject: [PATCH 26/28] removed malloc_trim --- src/main/java/org/bytedeco/javacpp/tools/Generator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/bytedeco/javacpp/tools/Generator.java b/src/main/java/org/bytedeco/javacpp/tools/Generator.java index b96ba996c..82ef1e879 100644 --- a/src/main/java/org/bytedeco/javacpp/tools/Generator.java +++ b/src/main/java/org/bytedeco/javacpp/tools/Generator.java @@ -569,7 +569,8 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver if (baseLoadSuffix == null || baseLoadSuffix.isEmpty()) { out.println("static inline jboolean JavaCPP_trimMemory() {"); out.println("#if defined(__linux__) && !defined(__ANDROID__)"); - out.println(" return (jboolean)malloc_trim(0);"); +// out.println(" return (jboolean)malloc_trim(0);"); + out.println(" return 0"); out.println("#else"); out.println(" return 0;"); out.println("#endif"); From a4e128d2d3d0dbee420b89a82e939240a76f2538 Mon Sep 17 00:00:00 2001 From: Fitor Avdiji Date: Sun, 8 Jun 2025 22:58:00 +0200 Subject: [PATCH 27/28] added semicolon --- src/main/java/org/bytedeco/javacpp/tools/Generator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/bytedeco/javacpp/tools/Generator.java b/src/main/java/org/bytedeco/javacpp/tools/Generator.java index 82ef1e879..11e49f44e 100644 --- a/src/main/java/org/bytedeco/javacpp/tools/Generator.java +++ b/src/main/java/org/bytedeco/javacpp/tools/Generator.java @@ -570,7 +570,7 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver out.println("static inline jboolean JavaCPP_trimMemory() {"); out.println("#if defined(__linux__) && !defined(__ANDROID__)"); // out.println(" return (jboolean)malloc_trim(0);"); - out.println(" return 0"); + out.println(" return 0;"); out.println("#else"); out.println(" return 0;"); out.println("#endif"); From 1a41a10fa897002c308848540d793abd829c1750 Mon Sep 17 00:00:00 2001 From: Fitor Avdiji Date: Thu, 12 Jun 2025 23:53:27 +0200 Subject: [PATCH 28/28] no message --- src/main/java/org/bytedeco/javacpp/tools/Generator.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/bytedeco/javacpp/tools/Generator.java b/src/main/java/org/bytedeco/javacpp/tools/Generator.java index 11e49f44e..2f732797c 100644 --- a/src/main/java/org/bytedeco/javacpp/tools/Generator.java +++ b/src/main/java/org/bytedeco/javacpp/tools/Generator.java @@ -278,8 +278,10 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver out.println("#endif"); out.println(); out.println("#include "); + out.println("#define MODIFIED_UTF8_STRING"); if (out2 != null) { out2.println("#include "); + out2.println("#define MODIFIED_UTF8_STRING"); } out.println(); out.println("#ifdef __ANDROID__");