Jelajahi Sumber

Add JNI method call functionality integer support

This method call now supports "getter" type method calls with
return type of integer.
Patrick-Christopher Mattulat 1 tahun lalu
induk
melakukan
a1c1a775a5

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

@@ -24,6 +24,7 @@ namespace ls::std::core::interface_type
       virtual ~IJniApi();
 
       virtual jbyte callByteMethod(jobject _javaObject, jmethodID _methodId) = 0;
+      virtual jint callIntMethod(jobject _javaObject, jmethodID _methodId) = 0;
       virtual jclass findClass(const ::std::string &_classPath) = 0;
       virtual jmethodID getMethodId(jclass _javaClass, const char *_methodIdentifier, const char *_methodSignature) = 0;
   };

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

@@ -23,6 +23,7 @@ namespace ls::std::core
       ~JniApi() noexcept override;
 
       jbyte callByteMethod(jobject _javaObject, jmethodID _methodId) override;
+      jint callIntMethod(jobject _javaObject, jmethodID _methodId) override;
       jclass findClass(const ::std::string &_classPath) override;
       jmethodID getMethodId(jclass _javaClass, const char *_methodIdentifier, const char *_methodSignature) override;
 

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

@@ -42,6 +42,7 @@ namespace ls::std::core
       ::std::string path{};
 
       void _callByteMethod(const ::std::string &_methodIdentifier, ls::std::core::JniReturnValue &_returnValue);
+      void _callIntMethod(const ::std::string &_methodIdentifier, ls::std::core::JniReturnValue &_returnValue);
       void _createJniApi();
       [[nodiscard]] bool _hasMethod(const ::std::string &_methodIdentifier);
   };

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

@@ -23,11 +23,14 @@ namespace ls::std::core
       ~JniReturnValue();
 
       [[nodiscard]] jbyte getByteValue() const;
+      [[nodiscard]] jint getIntegerValue() const;
       void setByteValue(jbyte _byteValue);
+      void setIntegerValue(jint _integerValue);
 
     private:
 
       jbyte byteValue{};
+      jint integerValue{};
   };
 }
 

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

@@ -27,6 +27,11 @@ jbyte JniApi::callByteMethod(jobject _javaObject, jmethodID _methodId)
   return this->environment->CallByteMethod(_javaObject, _methodId);
 }
 
+jint JniApi::callIntMethod(jobject _javaObject, jmethodID _methodId)
+{
+  return this->environment->CallIntMethod(_javaObject, _methodId);
+}
+
 jclass JniApi::findClass(const string &_classPath)
 {
   return this->environment->FindClass(_classPath.c_str());

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

@@ -49,6 +49,7 @@ JniReturnValue JniClass::callMethod(const string &_methodIdentifier)
   if (this->_hasMethod(_methodIdentifier))
   {
     this->_callByteMethod(_methodIdentifier, returnValue);
+    this->_callIntMethod(_methodIdentifier, returnValue);
   }
 
   return returnValue;
@@ -86,14 +87,27 @@ void JniClass::_callByteMethod(const string &_methodIdentifier, JniReturnValue &
   JniMethod method = this->methods.at(_methodIdentifier);
   string searchString = ")B";
   string methodSignature = method.getMethodSignature();
-  bool hasBooleanReturnType = methodSignature.rfind(searchString) == (methodSignature.size() - searchString.size());
+  bool hasByteReturnType = methodSignature.rfind(searchString) == (methodSignature.size() - searchString.size());
 
-  if (hasBooleanReturnType)
+  if (hasByteReturnType)
   {
     _returnValue.setByteValue(this->parameter->getJniApi()->callByteMethod(this->parameter->getJavaObject(), method.getMethodId()));
   }
 }
 
+void JniClass::_callIntMethod(const string &_methodIdentifier, JniReturnValue &_returnValue)
+{
+  JniMethod method = this->methods.at(_methodIdentifier);
+  string searchString = ")I";
+  string methodSignature = method.getMethodSignature();
+  bool hasIntegerReturnType = methodSignature.rfind(searchString) == (methodSignature.size() - searchString.size());
+
+  if (hasIntegerReturnType)
+  {
+    _returnValue.setIntegerValue(this->parameter->getJniApi()->callIntMethod(this->parameter->getJavaObject(), method.getMethodId()));
+  }
+}
+
 void JniClass::_createJniApi()
 {
   this->parameter->setJniApi(make_shared<JniApi>(this->parameter->getJavaEnvironment()));

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

@@ -20,7 +20,17 @@ jbyte JniReturnValue::getByteValue() const
   return this->byteValue;
 }
 
+jint JniReturnValue::getIntegerValue() const
+{
+  return this->integerValue;
+}
+
 void JniReturnValue::setByteValue(jbyte _byteValue)
 {
   this->byteValue = _byteValue;
 }
+
+void JniReturnValue::setIntegerValue(jint _integerValue)
+{
+  this->integerValue = _integerValue;
+}

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

@@ -104,11 +104,13 @@ namespace
 
     EXPECT_CALL(*this->jniApi, findClass(classPath)).Times(AtLeast(1));
     ON_CALL(*this->jniApi, findClass(classPath)).WillByDefault(Return(make_shared<_jclass>().get()));
+
     string methodIdentifier = "getDay";
     string methodSignature = "()B";
     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, callByteMethod(testing::_, methodId)).Times(AtLeast(1));
     ON_CALL(*this->jniApi, callByteMethod(testing::_, methodId)).WillByDefault(Return(22));
 
@@ -117,6 +119,28 @@ namespace
     ASSERT_EQ(22, javaClass.callMethod(methodIdentifier).getByteValue());
   }
 
+  TEST_F(JniClassTest, callMethod_integer_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 = "getYear";
+    string methodSignature = "()I";
+    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, callIntMethod(testing::_, methodId)).Times(AtLeast(1));
+    ON_CALL(*this->jniApi, callIntMethod(testing::_, methodId)).WillByDefault(Return(1989));
+
+    ASSERT_TRUE(javaClass.load());
+    ASSERT_TRUE(javaClass.loadMethod(methodIdentifier, methodSignature));
+    ASSERT_EQ(1989, javaClass.callMethod(methodIdentifier).getIntegerValue());
+  }
+
   TEST_F(JniClassTest, hasMethod)
   {
     string classPath = "java.utils.String";
@@ -143,6 +167,7 @@ namespace
 
     EXPECT_CALL(*this->jniApi, findClass(classPath)).Times(AtLeast(1));
     ON_CALL(*this->jniApi, findClass(classPath)).WillByDefault(Return(make_shared<_jclass>().get()));
+
     string methodIdentifier = "getDay";
     string methodSignature = "()B";
     EXPECT_CALL(*this->jniApi, getMethodId(testing::_, methodIdentifier.c_str(), methodSignature.c_str())).Times(AtLeast(1));
@@ -160,6 +185,7 @@ namespace
 
     EXPECT_CALL(*this->jniApi, findClass(classPath)).Times(AtLeast(1));
     ON_CALL(*this->jniApi, findClass(classPath)).WillByDefault(Return(make_shared<_jclass>().get()));
+
     string methodIdentifier = "getDay";
     string methodSignature = "()B";
     EXPECT_CALL(*this->jniApi, getMethodId(testing::_, methodIdentifier.c_str(), methodSignature.c_str())).Times(AtLeast(1));

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

@@ -29,6 +29,12 @@ namespace
     ASSERT_EQ(0, returnValue.getByteValue());
   }
 
+  TEST_F(JniReturnValueTest, getIntegerValue)
+  {
+    JniReturnValue returnValue{};
+    ASSERT_EQ(0, returnValue.getIntegerValue());
+  }
+
   TEST_F(JniReturnValueTest, setByteValue)
   {
     JniReturnValue returnValue{};
@@ -36,4 +42,12 @@ namespace
 
     ASSERT_EQ(22, returnValue.getByteValue());
   }
+
+  TEST_F(JniReturnValueTest, setIntegerValue)
+  {
+    JniReturnValue returnValue{};
+    returnValue.setIntegerValue(1989);
+
+    ASSERT_EQ(1989, returnValue.getIntegerValue());
+  }
 }

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

@@ -23,6 +23,7 @@ namespace test::core::jni
       ~MockJniApi() noexcept 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));
       MOCK_METHOD(jmethodID, getMethodId, (jclass _javaClass, const char *_methodIdentifier, const char *_methodSignature), (override));
   };