From 9b9a799e26d30cb1f11d9823636afbc503dd4063 Mon Sep 17 00:00:00 2001
From: Sylvain Berfini <sylvain.berfini@belledonne-communications.com>
Date: Wed, 19 Jan 2022 11:43:16 +0100
Subject: [PATCH] Added support for enum lists in java wrapper

---
 tools/abstractapi.py              |  2 +-
 wrappers/java/genwrapper.py       | 25 +++++++++++++++++++++----
 wrappers/java/java_class.mustache |  2 +-
 wrappers/java/java_enum.mustache  | 18 ++++++++++++++++++
 wrappers/java/jni.mustache        | 22 +++++++++++++++++++---
 5 files changed, 60 insertions(+), 9 deletions(-)

diff --git a/tools/abstractapi.py b/tools/abstractapi.py
index f872404123..80c7e9526a 100644
--- a/tools/abstractapi.py
+++ b/tools/abstractapi.py
@@ -1281,7 +1281,7 @@ class JavaLangTranslator(CLikeLangTranslator):
 					return 'jobjectArray'
 				return _type.containedTypeDesc.translate(self, jni=True) + 'Array'
 			elif type(_type.containedTypeDesc) is EnumType:
-				ptrtype = _type.containedTypeDesc.translate(self, native=native)
+				return 'jintArray'
 		ptrtype = ''
 		if type(_type.containedTypeDesc) is ClassType:
 			ptrtype = _type.containedTypeDesc.translate(self, native=native, namespace=namespace)
diff --git a/wrappers/java/genwrapper.py b/wrappers/java/genwrapper.py
index ce1570e746..22e0d5563a 100755
--- a/wrappers/java/genwrapper.py
+++ b/wrappers/java/genwrapper.py
@@ -245,13 +245,22 @@ class JavaTranslator:
     def generate_set_listener(self, _class):
         return self.generate_listener('setListener', _class)
 
+    def translate_method_native_arg(self, arg, namespace):
+        if type(arg.type) is AbsApi.EnumType:
+            return arg.name.translate(self.nameTranslator) + '.toInt()'
+        elif type(arg.type) is AbsApi.ListType and isinstance(arg.type.containedTypeDesc, AbsApi.EnumType):
+            typename = arg.type.translate(self.langTranslator, isReturn=True, namespace=namespace)
+            return typename[:-2] + '.toIntArray(' + arg.name.translate(self.nameTranslator) + ')'
+        return arg.name.translate(self.nameTranslator)
+
     def translate_method(self, _method, _hasCoreAccessor=False, _forceMethodName=""):
         methodDict = {}
 
         namespace = _method.find_first_ancestor_by_type(AbsApi.Namespace)
 
         methodDict['return'] = _method.returnType.translate(self.langTranslator, isReturn=True, namespace=namespace, exceptionEnabled=self.exceptions)
-        isArray = _method.returnType.translate(self.langTranslator, jni=True, isReturn=True, namespace=namespace) == 'jobjectArray'
+        native_type = _method.returnType.translate(self.langTranslator, jni=True, isReturn=True, namespace=namespace)
+        isArray = native_type == 'jobjectArray' or native_type == 'jintArray'
         # Wrapper takes care or never returning a null array even if the doc says it can return a null list
         methodDict['return_maybenil'] = _method.maybenil and not isArray
         methodDict['return_notnil'] = _method.notnil or isArray
@@ -276,13 +285,17 @@ class JavaTranslator:
         methodDict['exception'] = self.throws_exception(_method.returnType)
 
         methodDict['enumCast'] = type(_method.returnType) is AbsApi.EnumType
+        methodDict['enumArrayCast'] = type(_method.returnType) is AbsApi.ListType and isinstance(_method.returnType.containedTypeDesc, AbsApi.EnumType)
+        methodDict['enumName'] = ""
+        if methodDict['enumArrayCast']:
+            methodDict['enumName'] = methodDict['return'][:-2]
         methodDict['classCast'] = type(_method.returnType) is AbsApi.ClassType
 
         methodDict['params'] = ', '.join(['{0}{1}'.format('@Nullable ' if arg.maybenil else '@NonNull ' if arg.notnil else '', arg.translate(self.langTranslator, namespace=namespace)) for arg in _method.args])
         methodDict['native_params'] = ', '.join(['long nativePtr'] + [arg.translate(self.langTranslator, native=True, namespace=namespace) for arg in _method.args])
         methodDict['static_native_params'] = ', '.join([arg.translate(self.langTranslator, native=True, namespace=namespace) for arg in _method.args])
         methodDict['native_params_impl'] = ', '.join(
-            ['nativePtr'] + [arg.name.translate(self.nameTranslator) + ('.toInt()' if type(arg.type) is AbsApi.EnumType else '') for arg in _method.args])
+            ['nativePtr'] + [self.translate_method_native_arg(arg, namespace) for arg in _method.args])
 
         methodDict['deprecated'] = _method.deprecated
         methodDict['briefDoc'] = _method.briefDescription.translate(self.docTranslator, tagAsBrief=True) if _method.briefDescription is not None else None
@@ -314,7 +327,7 @@ class JavaTranslator:
         methodDict['needLjb'] = False
 
         methodDict['return'] = _method.returnType.translate(self.langTranslator, jni=True, isReturn=True, namespace=namespace)
-        methodDict['hasListReturn'] = methodDict['return'] == 'jobjectArray'
+        methodDict['hasListReturn'] = methodDict['return'] == 'jobjectArray' or methodDict['return'] == 'jintArray'
         methodDict['hasByteArrayReturn'] = methodDict['return'] == 'jbyteArray'
         methodDict['hasReturn'] = not methodDict['return'] == 'void' and not methodDict['hasListReturn'] and not methodDict['hasByteArrayReturn']
         methodDict['hasStringReturn'] = methodDict['return'] == 'jstring'
@@ -345,6 +358,7 @@ class JavaTranslator:
         methodDict['returnClassName'] = _method.returnType.translate(self.langTranslator, namespace=namespace)
         methodDict['isRealObjectArray'] = False
         methodDict['isStringObjectArray'] = False
+        methodDict['isEnumObjectArray'] = False
         methodDict['c_type_return'] = _method.returnType.translate(self.clangTranslator)
 
         if methodDict['c_name'] in jni_blacklist:
@@ -355,6 +369,8 @@ class JavaTranslator:
                 methodDict['isStringObjectArray'] = True
             elif isinstance(_method.returnType.containedTypeDesc, AbsApi.BaseType):
                 methodDict['isStringObjectArray'] = True
+            elif isinstance(_method.returnType.containedTypeDesc, AbsApi.EnumType):
+                methodDict['isEnumObjectArray'] = True
             elif isinstance(_method.returnType.containedTypeDesc, AbsApi.ClassType):
                 methodDict['isRealObjectArray'] = True
                 methodDict['needLjb'] = True
@@ -393,7 +409,8 @@ class JavaTranslator:
             elif isinstance(arg.type, AbsApi.ListType):
                 isStringList = type(arg.type.containedTypeDesc) is AbsApi.BaseType and arg.type.containedTypeDesc.name == 'string'
                 isObjList = type(arg.type.containedTypeDesc) is AbsApi.ClassType
-                methodDict['lists'].append({'list': argname, 'isStringList': isStringList, 'isObjList': isObjList, 'objectClassCName': arg.type.containedTypeDesc.name})
+                isEnumList = type(arg.type.containedTypeDesc) is AbsApi.EnumType
+                methodDict['lists'].append({'list': argname, 'isStringList': isStringList, 'isEnumList': isEnumList, 'isObjList': isObjList, 'objectClassCName': arg.type.containedTypeDesc.name})
                 methodDict['params_impl'] += 'bctbx_list_' + argname
 
             elif isinstance(arg.type, AbsApi.EnumType):
diff --git a/wrappers/java/java_class.mustache b/wrappers/java/java_class.mustache
index f37c171de8..00afc705eb 100644
--- a/wrappers/java/java_class.mustache
+++ b/wrappers/java/java_class.mustache
@@ -273,7 +273,7 @@ class {{classImplName}} {{#isLinphoneFactory}}extends{{/isLinphoneFactory}}{{#is
 				}
 			}
 		}{{/cantBeCalledIfObjectIsConst}}
-        {{#exception}}int exceptionResult = {{/exception}}{{return_keyword}}{{#enumCast}}{{return}}.fromInt({{/enumCast}}{{#classCast}}({{return}}){{/classCast}}{{name_native}}({{native_params_impl}}){{#enumCast}}){{/enumCast}};{{#exception}}
+        {{#exception}}int exceptionResult = {{/exception}}{{return_keyword}}{{#enumCast}}{{return}}.fromInt({{/enumCast}}{{#enumArrayCast}}{{enumName}}.fromIntArray({{/enumArrayCast}}{{#classCast}}({{return}}){{/classCast}}{{name_native}}({{native_params_impl}}){{#enumCast}}){{/enumCast}}{{#enumArrayCast}}){{/enumArrayCast}};{{#exception}}
         if (exceptionResult != 0) throw new CoreException("{{name}} returned value " + exceptionResult);{{/exception}}{{#hasCoreAccessor}}{{#isNotGetCore}}
         }{{/isNotGetCore}}{{/hasCoreAccessor}}
     }
diff --git a/wrappers/java/java_enum.mustache b/wrappers/java/java_enum.mustache
index a64299797e..2d1ee504e4 100644
--- a/wrappers/java/java_enum.mustache
+++ b/wrappers/java/java_enum.mustache
@@ -71,6 +71,24 @@ public enum {{{className}}} {
             throw new RuntimeException("Unhandled enum value " + value + " for {{className}}");
         }
     }
+    
+    static protected {{className}}[] fromIntArray(int[] values) throws RuntimeException {
+        int arraySize = values.length;
+        {{className}}[] enumArray = new {{className}}[arraySize];
+        for (int i = 0; i < arraySize; i++) {
+            enumArray[i] = {{className}}.fromInt(values[i]);
+        }
+        return enumArray;
+    }
+    
+    static protected int[] toIntArray({{className}}[] values) throws RuntimeException {
+        int arraySize = values.length;
+        int[] intArray = new int[arraySize];
+        for (int i = 0; i < arraySize; i++) {
+            intArray[i] = values[i].toInt();
+        }
+        return intArray;
+    }
 
     public int toInt() {
         return mValue;
diff --git a/wrappers/java/jni.mustache b/wrappers/java/jni.mustache
index afba1d0ec2..0084fab244 100644
--- a/wrappers/java/jni.mustache
+++ b/wrappers/java/jni.mustache
@@ -555,6 +555,7 @@ JNIEXPORT {{return}} JNICALL {{name}}({{params}}) {
 		LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_factory_get_user_data(linphone_factory_get());
 		jobjectArray jni_list_result = env->NewObjectArray(0, ljb->{{objectCPrefix}}_class, NULL);{{/isRealObjectArray}}
 		{{#isStringObjectArray}}jobjectArray jni_list_result = env->NewObjectArray(0, env->FindClass("java/lang/String"), env->NewStringUTF(""));{{/isStringObjectArray}}
+		{{#isEnumObjectArray}}jintArray jni_list_result = env->NewIntArray(0);{{/isEnumObjectArray}}
 		{{/hasListReturn}}
 		return {{#hasReturn}}0{{/hasReturn}}{{#hasListReturn}}jni_list_result{{/hasListReturn}}{{#hasByteArrayReturn}}0{{/hasByteArrayReturn}};
 	}
@@ -568,6 +569,7 @@ JNIEXPORT {{return}} JNICALL {{name}}({{params}}) {
 	{{/objects}}{{#lists}}
 	bctbx_list_t *bctbx_list_{{list}} = nullptr;
 	int {{list}}_count = env->GetArrayLength({{list}});
+	{{#isEnumList}}jint *int_elems_{{list}} = env->GetIntArrayElements({{list}}, 0);{{/isEnumList}}
 	for (int i=0; i < {{list}}_count; i++) {
 		{{#isStringList}}
 		jstring obj = (jstring) env->GetObjectArrayElement({{list}}, i);
@@ -581,6 +583,9 @@ JNIEXPORT {{return}} JNICALL {{name}}({{params}}) {
 		jobject obj = env->GetObjectArrayElement({{list}}, i);
 		bctbx_list_{{list}} = bctbx_list_append(bctbx_list_{{list}}, ({{objectClassCName}} *)GetObjectNativePtr(env, obj));
 		{{/isObjList}}
+		{{#isEnumList}}
+		bctbx_list_{{list}} = bctbx_list_append(bctbx_list_{{list}}, (void*)(intptr_t)int_elems_{{list}}[i]);
+		{{/isEnumList}}
 	}
 	{{/lists}}{{#hasListReturn}}
 	{{#isConst}}const {{/isConst}}bctbx_list_t *list = {{c_name}}({{#notStatic}}cptr{{/notStatic}}{{params_impl}});
@@ -590,21 +595,32 @@ JNIEXPORT {{return}} JNICALL {{name}}({{params}}) {
 	LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_factory_get_user_data(linphone_factory_get());
 	jobjectArray jni_list_result = env->NewObjectArray((int)count, ljb->{{objectCPrefix}}_class, nullptr);{{/isRealObjectArray}}
 	{{#isStringObjectArray}}jobjectArray jni_list_result = env->NewObjectArray((int)count, env->FindClass("java/lang/String"), env->NewStringUTF(""));{{/isStringObjectArray}}
+	{{#isEnumObjectArray}}jintArray jni_list_result = env->NewIntArray((int)count);
+	int carray[(int)count];{{/isEnumObjectArray}}
 	int i = 0;
 	while (list_it != nullptr) {
 		{{#isRealObjectArray}}
 		{{objectClassCName}}* c_object = ({{objectClassCName}}*)list_it->data;
 		jobject object = get{{objectClassName}}(env, c_object, {{takeRefOnReturnedObject}}, {{isRealObjectConst}});
+		if (object != nullptr) {
+			env->SetObjectArrayElement(jni_list_result, (int)i, object);
+			env->DeleteLocalRef(object);
+		}
 		{{/isRealObjectArray}}
 		{{#isStringObjectArray}}const char *cstring = (const char *)list_it->data;
-		jstring object = cstring ? get_jstring_from_char(env, cstring) : 0;{{/isStringObjectArray}}
+		jstring object = cstring ? get_jstring_from_char(env, cstring) : 0;
 		if (object != nullptr) {
 			env->SetObjectArrayElement(jni_list_result, (int)i, object);
-			{{#isRealObjectArray}}env->DeleteLocalRef(object);{{/isRealObjectArray}}
-		}
+		}{{/isStringObjectArray}}
+		{{#isEnumObjectArray}}
+		carray[i] = (int)(intptr_t)list_it->data;
+		{{/isEnumObjectArray}}
 		list_it = bctbx_list_next(list_it);
 		i += 1;
 	}
+	{{#isEnumObjectArray}}
+	env->SetIntArrayRegion(jni_list_result, 0, (int)count, carray);
+	{{/isEnumObjectArray}}
 	{{#isNotConst}}bctbx_list_free(list);{{/isNotConst}}
 	{{/hasListReturn}}{{#hasByteArrayReturn}}
 	{{c_type_return}} jni_result = {{c_name}}({{#notStatic}}cptr{{/notStatic}}{{params_impl}});
-- 
GitLab