user3422841
user3422841

Reputation: 105

Holding reference to native class object in JNI

I am trying to create a c++ class and hold its objects into an array, and reference those c++ objects from java using JNI, since JNI does not provide any mechanism to hold any non primitive type of objects into java.

I have implemented the code as mentioned below but the output is showing me as if multiple objects have got created and i am also receiving a heap error on the second call to create a new native object.

Can anyone look into this?

thanks

Codes:

Java class(The function for loading library dll has been defined in LibObj):

package org.jnp.pkg004;

import org.jnp.libloader.LibObj;

public class PureCppObjFactory extends LibObj {

    private long cppobjlstsz;

    public PureCppObjFactory() {
        super();
        cppobjlstsz=0;
    }

    public native void newCppObj();

    public native void PrintCppObjDetails(long cppobjlstindex);

}

C++ library code:

#include "stdafx.h"
#include "stdlib.h"
#include <iostream>
#include <iomanip>
#include <stdio.h>

using namespace std;

#include "org_jnp_pkg004_PureCppObjFactory.h"

class NativeObjClass
{
    private:
        int num_ran;
        int obj_num;
    public:
        static int obj_cnt;
        NativeObjClass()
        {
            obj_cnt++;
            obj_num=obj_cnt;
            num_ran=rand();
            cout<<"Native Object number "<<setfill('0')<<setw(5)<<obj_cnt<<" Random number:"<<num_ran<<endl;    
        }

        int get_obj_num()
        {
            return obj_num;
        }

        int get_num_ran()
        {
            return num_ran;
        }
};

int NativeObjClass::obj_cnt=0;

NativeObjClass *nobj_lst;
long nobj_lst_size=0;

JNIEXPORT void JNICALL Java_org_jnp_pkg004_PureCppObjFactory_newCppObj
  (JNIEnv *env, jobject obj)
{

    jclass thisCls = env->GetObjectClass(obj);
    jfieldID fid=env->GetFieldID(thisCls,"cppobjlstsz","J");    
    NativeObjClass nobj;

    jlong java_lst_sz=env->GetLongField(obj,fid);   

    NativeObjClass *temp_nobj_lst;
    temp_nobj_lst=new NativeObjClass[nobj_lst_size];
    if(nobj_lst_size>0)
    {
        memmove(temp_nobj_lst,nobj_lst,nobj_lst_size);
        delete nobj_lst;
    }   
    nobj_lst_size++;
    nobj_lst=new NativeObjClass[nobj_lst_size];
    if(nobj_lst_size>1)
    {
        memmove(nobj_lst,temp_nobj_lst,nobj_lst_size);
        delete temp_nobj_lst;
    }
    nobj_lst[nobj_lst_size]=nobj;
    java_lst_sz++;

    env->SetLongField(obj,fid,java_lst_sz);

}


JNIEXPORT void JNICALL Java_org_jnp_pkg004_PureCppObjFactory_PrintCppObjDetails
  (JNIEnv *env, jobject obj, jlong indx)
{
    NativeObjClass nobj=nobj_lst[indx];
    cout<<"Retrieved Native Object number "<<setfill('0')<<setw(5)<<nobj.get_obj_num()<<" Random number:"<<nobj.get_num_ran()<<endl;
}

Class containing main:

package test.jnp.pkg004;

import org.jnp.pkg004.PureCppObjFactory;

public class PureCppObjFactoryTest {

    public static void main(String[] args) {

        PureCppObjFactory pcf=new PureCppObjFactory();
        pcf.newCppObj();
        pcf.PrintCppObjDetails(0);
        pcf.newCppObj();
        //pcf.newCppObj();

    }

}

Output:

Native Object number 00001 Random number:41
Native Object number 00002 Random number:18467
Retrieved Native Object number 00002 Random number:18467
Native Object number 00003 Random number:6334
Native Object number 00004 Random number:26500

Also getting a heap error popup after this code executes

Upvotes: 5

Views: 2517

Answers (2)

Erik
Erik

Reputation: 91270

Ok, here's a list of issues seen at first glance:

  • using namespace std; is bad form
  • static int obj_cnt; isn't threadsafe
  • NativeObjClass *nobj_lst; should be a static member
  • NativeObjClass *nobj_lst; should be a std::vector
  • long nobj_lst_size=0; should be a static member
  • long nobj_lst_size=0; should be of type size_t
  • NativeObjClass nobj; creates an object - it's not just a reference
  • nobj_lst=(NativeObjClass*)calloc(nobj_lst_size,sizeof(NativeObjClass)); is just plain wrong. Use new[] if you have to use your manually managed array, but a std::vector would still be better
  • nobj_lst[nobj_lst_size-1]=nobj copies the object you created
  • NativeObjClass nobj=nobj_lst[indx]; makes a pointless copy of your array object

Consider this approach instead. Note that the below code has not been tested or even compiled, it's just to display the idea.

public class CppObject {

    private long handle;

    public CppObject() {
        handle = createNativeObject();
    }

    public void cleanup() {
        deleteNativeObject(handle);
        handle = 0;
    }

    private static native long createNativeObject();
    private static native void deleteNativeObject(long handle);
    private static native void printObjectDetails(long handle);


    public void PrintObjDetails() {
        printObjectDetails(handle);
    }

}




JNIEXPORT jlong JNICALL whatever_createNativeObject(JNIEnv *env, jobject obj) {
    return reinterpret_cast<jlong>(new CppObject());
}

JNIEXPORT void JNICALL whatever_deleteNativeObject(JNIEnv *env, jobject obj, jlong handle) {
    delete reinterpret_cast<CppObject *>(handle);
}

JNIEXPORT void JNICALL printObjectDetails(JNIEnv *env, jobject obj, jlong handle) {
    reinterpret_cast<CppObject *>(handle)->printDetails();
}

A java long is 64 bits, so the above code should work fine on both 32 and 64-bit platforms.

Upvotes: 5

user3422841
user3422841

Reputation: 105

#include "stdafx.h"
#include "stdlib.h"
#include <iostream>
#include <iomanip>
#include <stdio.h>

using namespace std;

#include "org_jnp_pkg004_PureCppObjFactory.h"

class NativeObjClass
{
    private:
        int num_ran;
        int obj_num;
    public:
        static int obj_cnt;
        NativeObjClass()
        {
            obj_cnt++;
            obj_num=obj_cnt;
            num_ran=rand();
            cout<<"Native Object number "<<setfill('0')<<setw(5)<<obj_cnt<<" Random number:"<<num_ran<<endl;    
        }

        int get_obj_num()
        {
            return obj_num;
        }

        int get_num_ran()
        {
            return num_ran;
        }
};

int NativeObjClass::obj_cnt=0;

NativeObjClass *nobj_lst;
long nobj_lst_size=0;

JNIEXPORT void JNICALL Java_org_jnp_pkg004_PureCppObjFactory_newCppObj
  (JNIEnv *env, jobject obj)
{

    jclass thisCls = env->GetObjectClass(obj);
    jfieldID fid=env->GetFieldID(thisCls,"cppobjlstsz","J");    
    NativeObjClass nobj;    

    jlong java_lst_sz=env->GetLongField(obj,fid);       

    if(nobj_lst_size==0)
    {           
        nobj_lst_size++;
        nobj_lst=(NativeObjClass*)calloc(nobj_lst_size,sizeof(NativeObjClass));     
        nobj_lst[nobj_lst_size-1]=nobj;
    }   
    else
    {
        nobj_lst_size++;
        nobj_lst=(NativeObjClass*)realloc(nobj_lst,nobj_lst_size*sizeof(NativeObjClass));   
        nobj_lst[nobj_lst_size-1]=nobj;
    }   

    java_lst_sz++;
    env->SetLongField(obj,fid,java_lst_sz);

}


JNIEXPORT void JNICALL Java_org_jnp_pkg004_PureCppObjFactory_printCppObjDetails
  (JNIEnv *env, jobject obj, jlong indx)
{
    NativeObjClass nobj=nobj_lst[indx];
    cout<<"Retrieved Native Object number "<<setfill('0')<<setw(5)<<nobj.get_obj_num()<<" Random number:"<<nobj.get_num_ran()<<endl;
}

Upvotes: 0

Related Questions