Get int value from java - java-native-interface

im trying to get the value of an int which is non static
java code
public int valuex = 500;
public native int intfromjni();
native code
JNIEXPORT jint JNICALL Java_com_samplejni_cls_intfromjni(JNIEnv* env, jobject thiz)
{
jclass x = env->GetObjectClass(thiz);
jfieldID f = env->GetFieldID(x, "valuex", "I");
int i = env->GetIntField(x, f);
return i;
}
but it throws crash with log
JNI DETECTED ERROR IN APPLICATION: jfieldID int com.samplejni.cls.valuex not valid for an object of class java.lang.Class<com.samplejni.cls>

here
int i = env->GetIntField(x, f);
you trying to use jclass to get a particular object's value. It would work for static fields.
For non-static firelds you should use jobject:
int i = env->GetIntField(thiz, f);

Related

Convert jobject to Integer in JNI C++ and parse the intValue

I have following code which accepts int value at JAVA level
dataObj.property(20);
This is the definition of property function
void property(Object value){
// JNI called
}
JNI function definition
Java_com_XXX_XXXX_JNIProperty(JNIEnv *a_pEnv, jclass, **jobject a_oPropertyValue**) {
// how to convert jobject to Integer object and then get the intValue
jclass cls = a_pEnv->FindClass("java/lang/Integer");
jmethodID getVal = a_pEnv->GetMethodID(cls, "intValue", "()I");
int i = a_pEnv->CallIntMethod(value, getVal);
}
How to convert jobject which was of type Object in Java to Integer object in JNI and parse int value ?
For a class in Java
public class PassObject {
public static native void displayInt(Object obj);
public static void property(int value) {
PassObject.displayInt(value);
}
public static void main(String[] args) {
PassObject.property(44);
// make sure to be careful in your case,
// as you make assumption that "Object" will be of type "Int"
// It's really easy to be very nasty.
PassObject.displayInt("44");
}
}
you can use following JNI code
JNIEXPORT void JNICALL Java_recipeNo055_PassObject_displayInt
(JNIEnv * env, jclass obj, jobject objarg) {
jclass cls = (*env)->GetObjectClass (env, objarg);
jmethodID integerToInt = (*env)->GetMethodID(env, cls, "intValue", "()I");
jint result = (*env)->CallIntMethod(env, objarg, integerToInt);
printf("Passed value: %d\n", result);
}
if you want to be extra careful, you can always do
jclass cls = (*env)->GetObjectClass (env, objarg);
if( (*env)->IsInstanceOf(env, objarg, (*env)->FindClass(env, "java/lang/Integer")) ) {
jmethodID intValue = (*env)->GetMethodID(env, cls, "intValue", "()I");
jint result = (*env)->CallIntMethod(env, objarg, intValue);
printf("%-22s: %d\n", "Passed value (int)", result);
} else {
// error
}

JNI : When should I release resources?

JNIEXPORT jstring JNICALL Java_com_xxx_xpdf_PdfToText_getTextOnly(JNIEnv *env, jclass obj,
jstring pdf_path) {
const char *pdf = env->GetStringUTFChars(pdf_path, 0);
std::string content;
unsigned int i = getTextFromPDF(pdf, &content);
env->ReleaseStringUTFChars(pdf_path, pdf);
const char *result = content.c_str();
jstring str = env->NewStringUTF(result);
return str;
}
Do I need to relase str and content here ? And why ?
No. str refers to a Java object which continues to exist beyond this JNI method, as it is the return value. content is a C++ local object which is auto-destroyed when its declaring scope exits.

SQLite Virtual table for querying lists of custom datatypes

Consider the class listed below:
typedef enum{
TYPE_ERROR = 0,
TYPE_WARNING = 1,
TYPE_INFO = 2,
TYPE_MAX
}TYPE_E;
typedef enum{
STATE_INITIALIZED = 0,
STATE_RUNNING = 1,
STATE_EXPIRED = 2,
STATE_UNKNOWN
}STATE_E;
class CustDataType
{
public :
~CustDataType(void);
CustDataType(int p_ID, TYPE_E p_Type, STATE_E stateIn);
int GetID(void) const;
string GetName(void) const;
TYPE_E GetType(void) const;
STATE_E GetState(void) const;
void DisplayDetails(void);
static void CreatesList(vector<CustDataType*> &p_vecsIn);
static void DestroysList(vector<CustDataType*> &p_vecsIn);
static void DisplaysList(vector<CustDataType*> &p_vecsIn);
private :
int m_nID;
string m_strName;
TYPE_E m_nType;
STATE_E m_nState;
};
The usecase is to implement a search filter using SQL like sysntax. SQLite virtual tables came in handy and was implemented. The issue I face now is how I can extend the implementation to other types of classes in my project which are similar to the class listed above but have different properties.
SQLite VTable module requires CSTyle static function pointers. Hence I cannot pass my class's methods. So I need a mechanism to redirect calls to my objects based on the type that has been created from the module callbacks. I noticed 2 things:
SQlite VTable documentation at https://www.sqlite.org/vtab.html suggests that the sqlite3_vtab structure needs to be subclassed in custom VTable implementations.
All callbacks receive the sqlite3_vtab either directly or via sqlite3_vtab_cursor.
Accordingly I derived a class from sqlite3_vtab
class CustDataFilter : public sqlite3_vtab
{
public:
int iVersion;
int CreateVirtualTable(sqlite3*, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char**);
int ConnectVirtualTable(sqlite3*, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char**);
int BestIndexVirtualTable(sqlite3_vtab *pVTab, sqlite3_index_info*);
int DisconnectVirtualTable(sqlite3_vtab *pVTab);
int DestroyVirtualTable(sqlite3_vtab *pVTab);
int OpenCursor(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor);
int CloseCursor(sqlite3_vtab_cursor*);
int FilterVirtualTable(sqlite3_vtab_cursor*, int idxNum, const char *idxStr, int argc, sqlite3_value **argv);
int NextRow(sqlite3_vtab_cursor*);
int Eof(sqlite3_vtab_cursor*);
int GetCurrentColumnValue(sqlite3_vtab_cursor*, sqlite3_context*, int);
int GetRow(sqlite3_vtab_cursor*, sqlite3_int64 *pRowid);
int FindFunctionVirtualTable(sqlite3_vtab *pVtab, int nArg, const char *zName,
void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
void **ppArg);
void MatchFunction(sqlite3_context* ctx, int argc, sqlite3_value** argv);
int DestructorVirtualTable(sqlite3_vtab *pVtab);
int CallbackResultSet(void *data, int argc, char **argv, char **azColName);
private:
vector<CustDataType> m_DataList;
}
Created the object and passed it as a void * to the sqlite3_create_module call.
int main()
{
// Register Alarm Module
if(registerModule(m_pDatabase) != SQLITE_OK)
{
fprintf(stderr, "Failed to register alarm module\n");
//return SQLITE_ERROR;
}
// Create it.
rc = sqlite3_exec(m_pDatabase, "CREATE VIRTUAL TABLE FOR CustDataType", NULL, NULL, &msg);
if(rc != SQLITE_OK)
{
printf("ERROR: %s\n", msg);
}
}
int registerModule(sqlite3 *db, CustDataFilter *filterIn)
{
return sqlite3_create_module(db, "ALARM_MODULE", &alarm_module, (void *)filterIn);
}
Finally in the xcreate callback I receive my object which I passed to sqlite as below:
int MyModule::CreateVirtualTable( sqlite3 *db,
void *p_aux,
int argc, const char *const*argv,
sqlite3_vtab **pp_vt,
char **pzErr )
{
*pp_vt = (sqlit3_vtab *) (p_aux);
}
In the other call backs I want to recast the sqlite3_vtab object received to my CustDataFilter type and call its relevant methods.
I see that I receive an object with the same address that was created. However when I cast this using C-style cast or dynamic_cast or reinterpret_cast I get an access violation exception when trying to call the object's methods.
So my question is
Is the approach correct? I am using this approach so I can extend a single module implementation to multiple data types.
If correct what am I doing wrong to get the access violation exception?
If the approach is wrong please suggest an alternate one.
Well we did some more digging and found the solution. The basic approach is fine but needed some fine tuning.
Instead of deriving our class hierarchy directly from sqlite3_vtab we created an intermediate structure derived from sqlite3_vtab. This new structure had only 1 member which was a void * pointer to our object. The only work then left was to cast this void * pointer to our object type and redirect calls to our objects to handle. The new implementation now looks like something below:
struct CustVTab : public sqlite3_vtab
{
void *myVtabImpl;
}
int main()
{
// Register Alarm Module
CustDataFilter *pCustFilter = new CustDataFilter();
if(registerModule(db, pCustFilter) != SQLITE_OK)
{
fprintf(stderr, "Failed to register alarm module\n");
//return SQLITE_ERROR;
}
// Create it.
rc = sqlite3_exec(m_pDatabase, "CREATE VIRTUAL TABLE FOR CustDataType", NULL, NULL, &msg);
if(rc != SQLITE_OK)
{
printf("ERROR: %s\n", msg);
}
}
int registerModule(sqlite3 *db, CustDataFilter *filterIn)
{
CustVTab *theVtab = new CustVTab();
theVTab.myVTabImpl = (void *) filterIn;
return sqlite3_create_module(db, "ALARM_MODULE", &alarm_module, (void *)theVtab);
}
int MyModule::CreateVirtualTable( sqlite3 *db,
void *p_aux,
int argc, const char *const*argv,
sqlite3_vtab **pp_vt,
char **pzErr )
{
*pp_vt = (sqlit3_vtab *) (p_aux);
}
And then in the callbacks get the custom filter implementation as below:
int CAlarm_module::GetRow(sqlite3_vtab_cursor *cur, sqlite_int64 *p_rowid)
{
CustVTab *theVTab = (CustVTab *) cur->pVtab;
CustDataFilter *pFilter = (CustDataFilter *) (theVTab->myVtabImpl);
pFilter->NextRow(cur);
return SQLITE_OK;
}
I have done a lot of work with sqlite3 virtual tables and modules.
As it relates to what you're doing here, have you considered using the callback of sqlite3_exec to process your results?
By way of example (of just the callback logic), I implemented a sqlite3 virtual table module that interfaced with libpng
The query results from SELECT statements contained the data from the image file.
Stripping out a lot of the extra stuff.. the call back looks something like this:
extern "C" {
/*!
* SqlCore's callback function for sqlite3_exec(...)
*
*/
static int sqlite3_exec_cb(void* pUserData, int numColumns,
char** pColumns,
char** pColumnNames) {
QUrl* image_url = (QUrl*)(pUserData);
return SQLITE_OK;
}
};
And is hooked into the process with something like this:
rc = sqlite3_exec(_db,
qPrintable(query_str),
&sqlite3_exec_cb, &image_url, &err);
if ( rc != SQLITE_OK ) {
sqlite3_free(err);
throw std::runtime_error("");
}
** I apologize for the incompleteness and reference to functions not defined. Sqlite3 questions always interest me -- but some times I am unclear as to the question being asked.

Cannot convert 'const bool' to 'jobject

I need to add a bool to an object map, my bool is defined as a primitive, and I need to convert it to an object.
How do I do that ?
You can convert your bool to a jboolean then box the jboolean into a Boolean jobject with JNI calls like this:
jboolean value = true;
jclass booleanClass = env->FindClass("java/lang/Boolean");
jmethodID methodID = env->GetMethodID(booleanClass, "<init>", "(Z)V", false);
jobject booleanObject = env->NewObject(booleanClass, methodID, value);

JNI C++ templates to acquire/release resources

What is recommended template set or library to acquire/release JNI resources from C++ code?
"Bad" example:
//C++ code
extern "C"
JNIEXPORT void JNICALL Java_ClassName_MethodName
(JNIEnv *env, jobject obj, jstring javaString)
{
//Get the native string from javaString
const char *nativeString = env->GetStringUTFChars(javaString, 0);
//Do something with the nativeString
//DON'T FORGET THIS LINE!!!
env->ReleaseStringUTFChars(javaString, nativeString);
}
Obviously, everybody uses a template set, not the code above.
For jstring it calls GetStringUTFChars to acquire resource and ReleaseStringUTFChars to release, when object goes "out of scope".
Gotta be something similar to auto_ptr template, but tailored to JNI to call GetStringUTFChars/ReleaseStringUTFChars for jstring, for example.
You can use std::unique_ptr in C++11, which allows you to set the deleter yourself:
#include <memory>
#include <functional>
typedef std::unique_ptr<char const[], std::function<void(char const*)>> jni_string_ptr;
// the "std::function" is needed to store any callable†
extern "C"
JNIEXPORT void JNICALL Java_ClassName_MethodName
(JNIEnv *env, jobject obj, jstring javaString)
{
//Get the native string from javaString
jni_string_ptr nativeString(env->GetStringUTFChars(javaString, 0),
[=](char const* p) mutable{ env->ReleaseStringUTFChars(javaString, p); });
// lambda as the deleter
// mutable needed if "ReleaseStringUTFChars" is a non-const method
//Do something with the nativeString
// nativeString automatically calls the passed deleter
}
If you're stuck in C++03 and don't have access to std::unique_ptr, boost::shared_array provides a.. viable alternative.
#include <boost/shared_ptr.hpp>
typedef boost::shared_array<char const*> jni_string_ptr;
struct jni_string_deleter{
jni_string_deleter(JNIEnv* e, jstring js)
: _env(e), _java_string(js) {}
void operator()(char const* p) const{
_env->ReleaseStringUTFChars(_java_string, p);
}
private:
JNIEnv* _env;
jstring _java_string;
};
extern "C"
JNIEXPORT void JNICALL Java_ClassName_MethodName
(JNIEnv *env, jobject obj, jstring javaString)
{
//Get the native string from javaString
jni_string_ptr nativeString(env->GetStringUTFChars(javaString, 0),
jni_string_deleter(env, javaString));
//Do something with the nativeString
// nativeString automatically calls the passed deleter
}
† You can also use a specific delter type here, as with the shared_array example, to avoid the type-erasure overhead of std::function:
struct jni_string_deleter{
jni_string_deleter(JNIEnv* e, jstring js)
: _env(e), _java_string(js) {}
void operator()(char const* p) const{
_env->ReleaseStringUTFChars(_java_string, p);
}
private:
JNIEnv* _env;
jstring _java_string;
};
typedef std::unique_ptr<char const[], jni_string_deleter> jni_string_ptr;
// create
jni_string_ptr(env->get_the_chars(), jni_string_deleter(env, javaString));
The keyword here is RAII:
class jni_string {
public:
jni_string(JNIEnv *env, jstring javaString)
: env_(env), javaString_(javaString)
{ nativeString_ = env_->GetStringUTFChars(javaString_, 0); }
~jni_string() { env_->ReleaseStringUTFChars(javaString_, nativeString_); }
operator const char *() const { return nativeString_; }
private:
jni_string(const jni_string &x);
jni_string &operator=(const jni_string &x);
JNIEnv *env_;
jstring javaString_;
const char *nativeString_;
};
Usage would be:
//C++ code
extern "C"
JNIEXPORT void JNICALL Java_ClassName_MethodName
(JNIEnv *env, jobject obj, jstring javaString)
{
//Get the native string from javaString
jni_string nativeString(env, javaString);
//Do something with the nativeString
}