From bc4cf1cb93c90a7ed572530962bbf3b6d932722b Mon Sep 17 00:00:00 2001
From: Ryan Pavlik <ryan.pavlik@collabora.com>
Date: Fri, 30 Apr 2021 17:55:34 -0500
Subject: [PATCH] external/jnipp: Move away from explicit instantiation of
 function templates.

Makes it too hard to track down errors: they showed up as linker errors, instead of compiler errors.
---
 src/external/jnipp/jnipp.cpp | 46 ++++++++++++++++++------------------
 src/external/jnipp/jnipp.h   | 43 +++++++++++++++++++++++++++++----
 2 files changed, 62 insertions(+), 27 deletions(-)

diff --git a/src/external/jnipp/jnipp.cpp b/src/external/jnipp/jnipp.cpp
index 2c558bda6..a250b76cd 100644
--- a/src/external/jnipp/jnipp.cpp
+++ b/src/external/jnipp/jnipp.cpp
@@ -353,20 +353,20 @@ namespace jni
         return _handle == nullptr || env()->IsSameObject(_handle, nullptr);
     }
 
-    template <> void Object::callMethod(method_t method, internal::value_t* args) const
+    void Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<void> const&) const
     {
         env()->CallVoidMethodA(_handle, method, (jvalue*) args);
         handleJavaExceptions();
     }
 
-    template <> bool Object::callMethod(method_t method, internal::value_t* args) const
+    bool Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<bool> const&) const
     {
         auto result = env()->CallBooleanMethodA(_handle, method, (jvalue*) args);
         handleJavaExceptions();
         return result != 0;
     }
 
-    template <> bool Object::get(field_t field) const
+    bool Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<bool> const&) const
     {
         return env()->GetBooleanField(_handle, field) != 0;
     }
@@ -376,122 +376,122 @@ namespace jni
         env()->SetBooleanField(_handle, field, value);
     }
 
-    template <> byte_t Object::callMethod(method_t method, internal::value_t* args) const
+    byte_t Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<byte_t> const&) const
     {
         auto result = env()->CallByteMethodA(_handle, method, (jvalue*) args);
         handleJavaExceptions();
         return result;
     }
 
-    template <> wchar_t Object::callMethod(method_t method, internal::value_t* args) const
+    wchar_t Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<wchar_t> const&) const
     {
         auto result = env()->CallCharMethodA(_handle, method, (jvalue*) args);
         handleJavaExceptions();
         return result;
     }
 
-    template <> short Object::callMethod(method_t method, internal::value_t* args) const
+    short Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<short> const&) const
     {
         auto result = env()->CallShortMethodA(_handle, method, (jvalue*) args);
         handleJavaExceptions();
         return result;
     }
 
-    template <> int Object::callMethod(method_t method, internal::value_t* args) const
+    int Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<int> const&) const
     {
         auto result = env()->CallIntMethodA(_handle, method, (jvalue*) args);
         handleJavaExceptions();
         return result;
     }
 
-    template <> long long Object::callMethod(method_t method, internal::value_t* args) const
+    long long Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<long long> const&) const
     {
         auto result = env()->CallLongMethodA(_handle, method, (jvalue*) args);
         handleJavaExceptions();
         return result;
     }
 
-    template <> float Object::callMethod(method_t method, internal::value_t* args) const
+    float Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<float> const&) const
     {
         auto result = env()->CallFloatMethodA(_handle, method, (jvalue*) args);
         handleJavaExceptions();
         return result;
     }
 
-    template <> double Object::callMethod(method_t method, internal::value_t* args) const
+    double Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<double> const&) const
     {
         auto result = env()->CallDoubleMethodA(_handle, method, (jvalue*) args);
         handleJavaExceptions();
         return result;
     }
 
-    template <> std::string Object::callMethod(method_t method, internal::value_t* args) const
+    std::string Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<std::string> const&) const
     {
         auto result = env()->CallObjectMethodA(_handle, method, (jvalue*) args);
         handleJavaExceptions();
         return toString(result);
     }
 
-    template <> std::wstring Object::callMethod(method_t method, internal::value_t* args) const
+    std::wstring Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<std::wstring> const&) const
     {
         auto result = env()->CallObjectMethodA(_handle, method, (jvalue*) args);
         handleJavaExceptions();
         return toWString(result);
     }
 
-    template <> jni::Object Object::callMethod(method_t method, internal::value_t* args) const
+    jni::Object Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<jni::Object> const&) const
     {
         auto result = env()->CallObjectMethodA(_handle, method, (jvalue*) args);
         handleJavaExceptions();
         return Object(result, DeleteLocalInput);
     }
 
-    template <> byte_t Object::get(field_t field) const
+    byte_t Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<byte_t> const&) const
     {
         return env()->GetByteField(_handle, field);
     }
 
-    template <> wchar_t Object::get(field_t field) const
+    wchar_t Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<wchar_t> const&) const
     {
         return env()->GetCharField(_handle, field);
     }
 
-    template <> short Object::get(field_t field) const
+    short Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<short> const&) const
     {
         return env()->GetShortField(_handle, field);
     }
 
-    template <> int Object::get(field_t field) const
+    int Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<int> const&) const
     {
         return env()->GetIntField(_handle, field);
     }
 
-    template <> long long Object::get(field_t field) const
+    long long Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<long long> const&) const
     {
         return env()->GetLongField(_handle, field);
     }
 
-    template <> float Object::get(field_t field) const
+    float Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<float> const&) const
     {
         return env()->GetFloatField(_handle, field);
     }
 
-    template <> double Object::get(field_t field) const
+    double Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<double> const&) const
     {
         return env()->GetDoubleField(_handle, field);
     }
 
-    template <> std::string Object::get(field_t field) const
+    std::string Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<std::string> const&) const
     {
         return toString(env()->GetObjectField(_handle, field));
     }
 
-    template <> std::wstring Object::get(field_t field) const
+    std::wstring Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<std::wstring> const&) const
     {
         return toWString(env()->GetObjectField(_handle, field));
     }
 
-    template <> Object Object::get(field_t field) const
+    Object Object::getFieldValue(field_t field, internal::ReturnTypeWrapper<Object> const&) const
     {
         return Object(env()->GetObjectField(_handle, field), DeleteLocalInput);
     }
diff --git a/src/external/jnipp/jnipp.h b/src/external/jnipp/jnipp.h
index aa20c217d..70515c979 100644
--- a/src/external/jnipp/jnipp.h
+++ b/src/external/jnipp/jnipp.h
@@ -176,6 +176,11 @@ namespace jni
         };
 
         long getArrayLength(jarray array);
+
+        template<typename T>
+        struct ReturnTypeWrapper{
+            using type = T;
+        };
     }
 
     /**
@@ -282,7 +287,7 @@ namespace jni
             \return The method's return value.
          */
         template <class TReturn>
-        TReturn call(method_t method) const { return callMethod<TReturn>(method, nullptr); }
+        TReturn call(method_t method) const { return callMethod(method, nullptr, internal::ReturnTypeWrapper<TReturn>{}); }
 
         /**
             Calls the method on this Object with the given name, and no arguments.
@@ -312,7 +317,7 @@ namespace jni
         template <class TReturn, class... TArgs>
         TReturn call(method_t method, const TArgs&... args) const {
             internal::ArgArray<TArgs...> transform(args...);
-            return callMethod<TReturn>(method, transform.values);
+            return callMethod(method, transform.values, internal::ReturnTypeWrapper<TReturn>{});
         }
 
         /**
@@ -342,7 +347,11 @@ namespace jni
             \return The field's value.
          */
         template <class TType>
-        TType get(field_t field) const;
+        TType get(field_t field) const {
+            // If you get a compile error here, then you've asked for a type
+            // we don't know how to get from JNI directly.
+            return getFieldValue(field, internal::ReturnTypeWrapper<TType>{});
+        }
 
         /**
             Gets a field value from this Object. The field must belong to the
@@ -410,7 +419,33 @@ namespace jni
         method_t getMethod(const char* name, const char* signature) const;
         method_t getMethod(const char* nameAndSignature) const;
         field_t getField(const char* name, const char* signature) const;
-        template <class TType> TType callMethod(method_t method, internal::value_t* values) const;
+
+        void callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<void> const&) const;
+        bool callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<bool> const&) const;
+        byte_t callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<byte_t> const&) const;
+        wchar_t callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<wchar_t> const&) const;
+        short callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<short> const&) const;
+        int callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<int> const&) const;
+        long long callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<long long> const&) const;
+        float callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<float> const&) const;
+        double callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<double> const&) const;
+        std::string callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<std::string> const&) const;
+        std::wstring callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<std::wstring> const&) const;
+        jni::Object callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper<jni::Object> const&) const;
+
+
+        void getFieldValue(field_t field, internal::ReturnTypeWrapper<void> const&) const;
+        bool getFieldValue(field_t field, internal::ReturnTypeWrapper<bool> const&) const;
+        byte_t getFieldValue(field_t field, internal::ReturnTypeWrapper<byte_t> const&) const;
+        wchar_t getFieldValue(field_t field, internal::ReturnTypeWrapper<wchar_t> const&) const;
+        short getFieldValue(field_t field, internal::ReturnTypeWrapper<short> const&) const;
+        int getFieldValue(field_t field, internal::ReturnTypeWrapper<int> const&) const;
+        long long getFieldValue(field_t field, internal::ReturnTypeWrapper<long long> const&) const;
+        float getFieldValue(field_t field, internal::ReturnTypeWrapper<float> const&) const;
+        double getFieldValue(field_t field, internal::ReturnTypeWrapper<double> const&) const;
+        std::string getFieldValue(field_t field, internal::ReturnTypeWrapper<std::string> const&) const;
+        std::wstring getFieldValue(field_t field, internal::ReturnTypeWrapper<std::wstring> const&) const;
+        jni::Object getFieldValue(field_t field, internal::ReturnTypeWrapper<jni::Object> const&) const;
 
         // Instance Variables
         jobject _handle;