Parcourir la source

Add JNI boolean getter method support

Patrick-Christopher Mattulat il y a 1 an
Parent
commit
acf3426b53

+ 1 - 0
include/ls-std/core/interface/IJniApi.hpp

@@ -23,6 +23,7 @@ namespace ls::std::core::experimental::interface_type
       IJniApi();
       virtual ~IJniApi();
 
+      virtual jboolean callBooleanMethod(jobject _javaObject, jmethodID _methodId) = 0;
       virtual jbyte callByteMethod(jobject _javaObject, jmethodID _methodId) = 0;
       virtual jint callIntMethod(jobject _javaObject, jmethodID _methodId) = 0;
       virtual jclass findClass(const ::std::string &_classPath) = 0;

+ 1 - 0
include/ls-std/core/jni/JniApi.hpp

@@ -22,6 +22,7 @@ namespace ls::std::core::experimental
       explicit JniApi(JNIEnv *_environment);
       ~JniApi() noexcept override;
 
+      jboolean callBooleanMethod(jobject _javaObject, jmethodID _methodId) override;
       jbyte callByteMethod(jobject _javaObject, jmethodID _methodId) override;
       jint callIntMethod(jobject _javaObject, jmethodID _methodId) override;
       jclass findClass(const ::std::string &_classPath) override;

+ 1 - 0
include/ls-std/core/jni/JniClass.hpp

@@ -41,6 +41,7 @@ namespace ls::std::core::experimental
       ::std::shared_ptr<ls::std::core::experimental::JniClassParameter> parameter{};
       ::std::string path{};
 
+      void _callBooleanMethod(const ::std::string &_methodIdentifier, ls::std::core::experimental::JniReturnValue &_returnValue);
       void _callByteMethod(const ::std::string &_methodIdentifier, ls::std::core::experimental::JniReturnValue &_returnValue);
       void _callIntMethod(const ::std::string &_methodIdentifier, ls::std::core::experimental::JniReturnValue &_returnValue);
       void _createJniApi();

+ 3 - 0
include/ls-std/core/jni/JniReturnValue.hpp

@@ -22,13 +22,16 @@ namespace ls::std::core::experimental
       JniReturnValue();
       ~JniReturnValue();
 
+      [[nodiscard]] jboolean getBooleanValue() const;
       [[nodiscard]] jbyte getByteValue() const;
       [[nodiscard]] jint getIntegerValue() const;
+      void setBooleanValue(jboolean _booleanValue);
       void setByteValue(jbyte _byteValue);
       void setIntegerValue(jint _integerValue);
 
     private:
 
+      jboolean booleanValue{};
       jbyte byteValue{};
       jint integerValue{};
   };

+ 5 - 0
source/ls-std/core/jni/JniApi.cpp

@@ -22,6 +22,11 @@ JniApi::JniApi(JNIEnv *_environment)
 
 JniApi::~JniApi() noexcept = default;
 
+jboolean JniApi::callBooleanMethod(jobject _javaObject, jmethodID _methodId)
+{
+  return this->environment->CallBooleanMethod(_javaObject, _methodId);
+}
+
 jbyte JniApi::callByteMethod(jobject _javaObject, jmethodID _methodId)
 {
   return this->environment->CallByteMethod(_javaObject, _methodId);

+ 16 - 2
source/ls-std/core/jni/JniClass.cpp

@@ -48,6 +48,7 @@ JniReturnValue JniClass::callMethod(const string &_methodIdentifier)
 
   if (this->_hasMethod(_methodIdentifier))
   {
+    this->_callBooleanMethod(_methodIdentifier, returnValue);
     this->_callByteMethod(_methodIdentifier, returnValue);
     this->_callIntMethod(_methodIdentifier, returnValue);
   }
@@ -68,7 +69,7 @@ bool JniClass::load()
 
 bool JniClass::loadMethod(const string &_methodIdentifier, const string &_methodSignature)
 {
-  NullPointerEvaluator{this->javaClass}.evaluate();
+  NullPointerEvaluator{this->javaClass, "no Java class reference available for loading class method!"}.evaluate();
   jmethodID methodId = this->parameter->getJniApi()->getMethodId(this->javaClass, _methodIdentifier.c_str(), _methodSignature.c_str());
   bool succeeded = methodId != nullptr && !this->_hasMethod(_methodIdentifier);
 
@@ -82,7 +83,20 @@ bool JniClass::loadMethod(const string &_methodIdentifier, const string &_method
   return succeeded;
 }
 
-void JniClass::_callByteMethod(const string &_methodIdentifier, JniReturnValue &_returnValue)
+void JniClass::_callBooleanMethod(const ::std::string &_methodIdentifier, ls::std::core::experimental::JniReturnValue &_returnValue)
+{
+  JniMethod method = this->methods.at(_methodIdentifier);
+  string searchString = ")Z";
+  string methodSignature = method.getMethodSignature();
+  bool hasBooleanReturnType = methodSignature.rfind(searchString) == (methodSignature.size() - searchString.size());
+
+  if (hasBooleanReturnType)
+  {
+    _returnValue.setBooleanValue(this->parameter->getJniApi()->callBooleanMethod(this->parameter->getJavaObject(), method.getMethodId()));
+  }
+}
+
+void JniClass::_callByteMethod(const ::std::string &_methodIdentifier, ls::std::core::experimental::JniReturnValue &_returnValue)
 {
   JniMethod method = this->methods.at(_methodIdentifier);
   string searchString = ")B";

+ 10 - 0
source/ls-std/core/jni/JniReturnValue.cpp

@@ -15,6 +15,11 @@ JniReturnValue::JniReturnValue() = default;
 
 JniReturnValue::~JniReturnValue() = default;
 
+jboolean JniReturnValue::getBooleanValue() const
+{
+  return this->booleanValue;
+}
+
 jbyte JniReturnValue::getByteValue() const
 {
   return this->byteValue;
@@ -25,6 +30,11 @@ jint JniReturnValue::getIntegerValue() const
   return this->integerValue;
 }
 
+void JniReturnValue::setBooleanValue(jboolean _booleanValue)
+{
+  this->booleanValue = _booleanValue;
+}
+
 void JniReturnValue::setByteValue(jbyte _byteValue)
 {
   this->byteValue = _byteValue;

+ 26 - 0
test/cases/core/jni/JniClassTest.cpp

@@ -109,6 +109,28 @@ namespace
         IllegalArgumentException);
   }
 
+  TEST_F(JniClassTest, callMethod_boolean_return_value)
+  {
+    string classPath = "java.utils.String";
+    JniClass javaClass = this->createJniClass(classPath);
+
+    EXPECT_CALL(*this->jniApi, findClass(classPath)).Times(AtLeast(1));
+    ON_CALL(*this->jniApi, findClass(classPath)).WillByDefault(Return(make_shared<_jclass>().get()));
+
+    string methodIdentifier = "isBlue";
+    string methodSignature = "()Z";
+    EXPECT_CALL(*this->jniApi, getMethodId(testing::_, methodIdentifier.c_str(), methodSignature.c_str())).Times(AtLeast(1));
+    jmethodID methodId = (jmethodID) make_shared<int>().get();
+    ON_CALL(*this->jniApi, getMethodId(testing::_, methodIdentifier.c_str(), methodSignature.c_str())).WillByDefault(Return(methodId));
+
+    EXPECT_CALL(*this->jniApi, callBooleanMethod(testing::_, methodId)).Times(AtLeast(1));
+    ON_CALL(*this->jniApi, callBooleanMethod(testing::_, methodId)).WillByDefault(Return(true));
+
+    ASSERT_TRUE(javaClass.load());
+    ASSERT_TRUE(javaClass.loadMethod(methodIdentifier, methodSignature));
+    ASSERT_TRUE(javaClass.callMethod(methodIdentifier).getBooleanValue());
+  }
+
   TEST_F(JniClassTest, callMethod_byte_return_value)
   {
     string classPath = "java.utils.String";
@@ -225,6 +247,10 @@ namespace
           }
           catch (const NullPointerException &_exception)
           {
+            string expected = _exception.getName() + " thrown - no Java class reference available for loading class method!";
+            string actual = _exception.what();
+
+            ASSERT_STREQ(expected.c_str(), actual.c_str());
             throw;
           }
         },

+ 14 - 0
test/cases/core/jni/JniReturnValueTest.cpp

@@ -23,6 +23,12 @@ namespace
       ~JniReturnValueTest() override = default;
   };
 
+  TEST_F(JniReturnValueTest, getBooleanValue)
+  {
+    JniReturnValue returnValue{};
+    ASSERT_FALSE(returnValue.getBooleanValue());
+  }
+
   TEST_F(JniReturnValueTest, getByteValue)
   {
     JniReturnValue returnValue{};
@@ -35,6 +41,14 @@ namespace
     ASSERT_EQ(0, returnValue.getIntegerValue());
   }
 
+  TEST_F(JniReturnValueTest, setBooleanValue)
+  {
+    JniReturnValue returnValue{};
+    returnValue.setBooleanValue(true);
+
+    ASSERT_TRUE(returnValue.getBooleanValue());
+  }
+
   TEST_F(JniReturnValueTest, setByteValue)
   {
     JniReturnValue returnValue{};

+ 1 - 0
test/classes/core/jni/MockJniApi.hpp

@@ -22,6 +22,7 @@ namespace test::core::jni
       MockJniApi();
       ~MockJniApi() noexcept override;
 
+      MOCK_METHOD(jboolean, callBooleanMethod, (jobject _javaObject, jmethodID _methodId), (override));
       MOCK_METHOD(jbyte, callByteMethod, (jobject _javaObject, jmethodID _methodId), (override));
       MOCK_METHOD(jint, callIntMethod, (jobject _javaObject, jmethodID _methodId), (override));
       MOCK_METHOD(jclass, findClass, (const ::std::string &_classPath), (override));