Convert jobject to Integer in JNI C++ and parse the intValue - java-native-interface

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
}

Related

Get int value from java

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);

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.

OOP in Lua From C

I would like to implement Object Orientated Programming in my lua interpreter, I understand that I can return a lua table from a C Function. And I would like the table that is returned to be full of C functions.
player = getClosestPlayer();
player.walkTo();
where both getClosestPlayer() and walkTo() are C functions.
From the C function for walkTo(), how do I differentiate between object types?
I would prefer every object to have a gid that I can use to identify it (player.gid) but how do I access that gid from the c function?
In other words, what is the equivalent of self.gid from C code?
int l_playerWalkTo(lua_State* functionState){
int gid = // self.gid?
// do something with gid
}
One way I could do this is to upvalue every single function in the table, but is there a more elegant way to do it?
Many thanks to macroland for his answer, I just though I would clear up what he has said.
This lua wrapper can be used to implement c++ classes into Lua:
https://bitbucket.org/alexames/luawrapper/overview
A great example of the usage of this library can be found here:
https://bitbucket.org/alexames/luawrapperexample/src/
Here is the code (taken straight from the example site)
Lua:
alicesaccount = BankAccount.new("Alice", 100)
alicesaccount:deposit(20);
alicesaccount:deposit(30);
alicesaccount:deposit(40);
c++:
BankAccount* BankAccount_new(lua_State *L)
{
const char* owner = luaL_checkstring(L, 1);
float balance = luaL_checknumber(L, 2);
return new BankAccount(owner, balance);
}
int BankAccount_deposit(lua_State *L)
{
BankAccount* account = luaW_check<BankAccount>(L, 1);
float amount = luaL_checknumber(L, 2);
account->deposit(amount);
return 0;
}
static luaL_Reg BankAccount_table[] =
{
{ NULL, NULL }
};
static luaL_Reg BankAccount_metatable[] =
{
{ "deposit", BankAccount_deposit },
{ NULL, NULL }
};
int luaopen_BankAccount(lua_State* L)
{
luaW_register<BankAccount>(L,
"BankAccount",
BankAccount_table,
BankAccount_metatable,
BankAccount_new // If your class has a default constructor you can omit this argument,
// LuaWrapper will generate a default allocator for you.
);
return 1;
}
As you can see, Using this method the first argument is an instance of the object
I had the similar problem and the way I resolved is:
1) Create an interface class in C++ with abstract methods
class LuaInterfaceOOP
{
public:
LuaInterfaceOOP(){}
virtual CObject* clone(void) const=0;
virtual wxString type(void)=0;
virtual wxString ToString(void)=0;
wxString GetType()return this->type();
wxString GetToString() return this->ToString();
virtual ~CObject(){}
};
2) Any class that you want to expose to Lua should implement this to be consistent.
class MyClass: public LuaInterfaceOOP
{
public:
wxString type() { return "MyClass";}
wxString ToString();
};
3) When you write a wrapper for this class make sure
int MyClass_toString(lua_State* L)
{
MyClass* mc= luaW_check<MyClass>(L, 1);
const char* str=mc->ToString().c_str();
lua_pushstring(L, str);
return 1;
}
int MyClass_type(lua_State* L)
{
lua_pushstring(L,"MyClass");
return 1;
}
4) Overload the type function provided by Lua, for you the important part will be:
case LUA_TUSERDATA:
{
wxString str1;
if(lua_getmetatable(L,idx)) // Stk: Userdata Table
{
lua_getfield(L,-1,"type"); // Stk: Userdata Table function
if(!lua_pcall(L,0,1,0)) // Stk: Userdata Table string
{
str1<<lua_tostring(L,-1);
wxReturnStr<<str1;
lua_pop(L,2);// Stk: Userdata
}
else //stk: Userdata table
{
lua_pop(L,1);
wxReturnStr<<"userdata"; //stk: Userdata
}
}else wxReturnStr<<"userdata";
break;
}
EDIT 1: Adding code to wrap C++ funcs to Lua
static luaL_Reg MyClass_table[] = {
{ NULL, NULL }
};
static luaL_Reg Myclass_metatable[] = {
{"type", Myclass_type},
{"__tostring", Myclass_toString},
{ NULL, NULL }
};
Finally,
static int luaopen_MyClass(lua_State* L)
{
luaW_register<MyClass>(L, "MyClass", MyClass_table, MyClass_metatable, MyClass_new);
return 1;
}
Now in Lua you can use an expression such as if(type(aclass)=="MyClass")
I am not sure if these steps are the best way, but so far it worked.

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
}