Skip to content

Commit 0075112

Browse files
committed
Improve support for Arrays of Strings in JNI Generator
A number of places in the GTK4 API there is the possibility of passing in arrays of Strings, i.e. Java String[] -> char ** as input argument to C side. This change adds better support to the JNI generator for this use case by converting the jobjectArray (String[]) to char ** on the C side. Part of #2126 Split out of #2538
1 parent 43f54cc commit 0075112

File tree

6 files changed

+123
-5
lines changed

6 files changed

+123
-5
lines changed

bundles/org.eclipse.swt.tools/JNI Generation/org/eclipse/swt/tools/internal/ASTType.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,10 @@ public String getTypeSignature2() {
148148
if (name.equals("Ljava/lang/String;")) return "jstring";
149149
if (name.equals("Ljava/lang/Class;")) return "jclass";
150150
if (isArray()) {
151-
return getComponentType().getTypeSignature2() + "Array";
151+
if (getComponentType().isPrimitive()) {
152+
return getComponentType().getTypeSignature2() + "Array";
153+
}
154+
return "jobjectArray";
152155
}
153156
return "jobject";
154157
}

bundles/org.eclipse.swt.tools/JNI Generation/org/eclipse/swt/tools/internal/NativesGenerator.java

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,57 @@ public void generate(JNIClass clazz) {
7777
sort(methods);
7878
generateNativeMacro(clazz);
7979
generateWarningSettings();
80+
generateStaticMethods();
8081
generateExcludes(methods);
8182
generate(methods);
8283
}
84+
private void generateStaticMethods() {
85+
if (!getOutputName().equals("gtk4")) {
86+
return;
87+
}
88+
89+
outputln("""
90+
static char **
91+
getArrayOfStringsUTF(JNIEnv *env, jobjectArray javaArray) {
92+
jsize length = (*env)->GetArrayLength(env, javaArray);
93+
94+
char **cStrings = (char **)malloc((length + 1) * sizeof(char*));
95+
if (!cStrings) {
96+
return NULL;
97+
}
98+
99+
for (jsize i = 0; i < length; i++) {
100+
jstring jstr = (jstring)(*env)->GetObjectArrayElement(env, javaArray, i);
101+
if (jstr) {
102+
const char *utfStr = (*env)->GetStringUTFChars(env, jstr, 0);
103+
104+
cStrings[i] = strdup(utfStr);
105+
106+
(*env)->ReleaseStringUTFChars(env, jstr, utfStr);
107+
(*env)->DeleteLocalRef(env, jstr);
108+
} else {
109+
cStrings[i] = NULL;
110+
}
111+
}
112+
113+
cStrings[length] = NULL;
114+
return cStrings;
115+
}
116+
117+
static void
118+
releaseArrayOfStringsUTF(JNIEnv *env, jobjectArray javaArray, char **cStrings) {
119+
jsize length = (*env)->GetArrayLength(env, javaArray);
120+
121+
for (jsize i = 0; i < length; i++) {
122+
if (cStrings[i]) {
123+
free(cStrings[i]);
124+
}
125+
}
126+
free(cStrings);
127+
}
128+
129+
""");
130+
}
83131

84132
public void generate(JNIMethod[] methods) {
85133
sort(methods);
@@ -299,6 +347,14 @@ boolean generateGetParameter(JNIParameter param, boolean critical, int indent) {
299347
output(iStr);
300348
output(", NULL)");
301349
}
350+
} else if (componentType.isType("java.lang.String")) {
351+
if (param.getFlag(FLAG_UNICODE)) {
352+
throw new Error("not done");
353+
}
354+
355+
output("getArrayOfStringsUTF(env, arg");
356+
output(iStr);
357+
output(")");
302358
} else {
303359
throw new Error("not done");
304360
}
@@ -381,6 +437,16 @@ void generateSetParameter(JNIParameter param, boolean critical) {
381437
output("0");
382438
}
383439
output(");");
440+
} else if (componentType.isType("java.lang.String")) {
441+
if (param.getFlag(FLAG_UNICODE)) {
442+
throw new Error("not done");
443+
}
444+
445+
output("releaseArrayOfStringsUTF(env, arg");
446+
output(iStr);
447+
output(", lparg");
448+
output(iStr);
449+
output(");");
384450
} else {
385451
throw new Error("not done");
386452
}
@@ -452,6 +518,12 @@ boolean generateLocalVars(JNIParameter[] params, JNIType returnType) {
452518
output(componentType.getTypeSignature2());
453519
output(" *lparg" + i);
454520
output("=NULL;");
521+
} else if (componentType.isType("java.lang.String")) {
522+
if (param.getFlag(FLAG_UNICODE)) {
523+
output("jchar **lparg" + i + "=NULL");
524+
} else {
525+
output("char **lparg" + i+ "=NULL");
526+
}
455527
} else {
456528
throw new Error("not done");
457529
}

bundles/org.eclipse.swt.tools/JNI Generation/org/eclipse/swt/tools/internal/ReflectType.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,10 @@ public String getTypeSignature2() {
9191
if (clazz == String.class) return "jstring";
9292
if (clazz == Class.class) return "jclass";
9393
if (clazz.isArray()) {
94-
return getComponentType().getTypeSignature2() + "Array";
94+
if (getComponentType().isPrimitive()) {
95+
return getComponentType().getTypeSignature2() + "Array";
96+
}
97+
return "jobjectArray";
9598
}
9699
return "jobject";
97100
}

bundles/org.eclipse.swt.tools/META-INF/MANIFEST.MF

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ Manifest-Version: 1.0
22
Bundle-Name: %pluginName
33
Bundle-Vendor: %providerName
44
Bundle-SymbolicName: org.eclipse.swt.tools; singleton:=true
5-
Bundle-Version: 3.110.800.qualifier
5+
Bundle-Version: 3.110.900.qualifier
66
Bundle-ManifestVersion: 2
77
Export-Package: org.eclipse.swt.tools.internal; x-internal:=true
88
Bundle-ActivationPolicy: lazy
99
Bundle-Localization: plugin
10-
Bundle-RequiredExecutionEnvironment: JavaSE-17
10+
Bundle-RequiredExecutionEnvironment: JavaSE-21
1111
Require-Bundle: org.eclipse.core.runtime;bundle-version="3.29.0",
1212
org.eclipse.core.resources;bundle-version="3.4.0",
1313
org.eclipse.jdt.core;bundle-version="3.4.0",

bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,46 @@
2626
#pragma warning (disable: 4100)
2727
#endif
2828

29+
static char **
30+
getArrayOfStringsUTF(JNIEnv *env, jobjectArray javaArray) {
31+
jsize length = (*env)->GetArrayLength(env, javaArray);
32+
33+
char **cStrings = (char **)malloc((length + 1) * sizeof(char*));
34+
if (!cStrings) {
35+
return NULL;
36+
}
37+
38+
for (jsize i = 0; i < length; i++) {
39+
jstring jstr = (jstring)(*env)->GetObjectArrayElement(env, javaArray, i);
40+
if (jstr) {
41+
const char *utfStr = (*env)->GetStringUTFChars(env, jstr, 0);
42+
43+
cStrings[i] = strdup(utfStr);
44+
45+
(*env)->ReleaseStringUTFChars(env, jstr, utfStr);
46+
(*env)->DeleteLocalRef(env, jstr);
47+
} else {
48+
cStrings[i] = NULL;
49+
}
50+
}
51+
52+
cStrings[length] = NULL;
53+
return cStrings;
54+
}
55+
56+
static void
57+
releaseArrayOfStringsUTF(JNIEnv *env, jobjectArray javaArray, char **cStrings) {
58+
jsize length = (*env)->GetArrayLength(env, javaArray);
59+
60+
for (jsize i = 0; i < length; i++) {
61+
if (cStrings[i]) {
62+
free(cStrings[i]);
63+
}
64+
}
65+
free(cStrings);
66+
}
67+
68+
2969
#ifndef NO_gdk_1clipboard_1get_1content
3070
JNIEXPORT jlong JNICALL GTK4_NATIVE(gdk_1clipboard_1get_1content)
3171
(JNIEnv *env, jclass that, jlong arg0)

features/org.eclipse.swt.tools.feature/feature.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<feature
33
id="org.eclipse.swt.tools.feature"
44
label="%featureName"
5-
version="3.109.800.qualifier"
5+
version="3.109.900.qualifier"
66
provider-name="%providerName"
77
license-feature="org.eclipse.license"
88
license-feature-version="0.0.0">

0 commit comments

Comments
 (0)