Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / Win32

Embedding Java VM into C application and using JNI with JSON

4.89/5 (7 votes)
21 Jan 2015CPOL23 min read 33.8K   567  
Exploring how to embed a Java VM into a C application and developing a native library for a Java application using JNI.

Introduction

Some time ago, I put a simple web server functionality into an application written in C and C++. This server did the basics of handling HTTP GET requests and with a bit of client side JavaScript along with a few built-in URIs providing specialized data retrieval services, I was able to explore some of the possible uses of this technology.

However I really had other uses for my time than to build out and maintain an embedded web server so I started looking at alternatives and found Jetty (http://eclipse.org/jetty/). Jetty looked to be a great solution providing a lot of capabilities and services, robust, and best of all, other people would be maintaining it. Jetty could also be embedded into my application. However Jetty is a Java application so I needed to understand how to embed a Java Virtual Machine into a C application and provide a native library to a Java application so as to expose C application data to a Java application.

I also took this opportunity to work with JSON and two JSON packages that are available. The first is the cJSON package by Dave Gamble (http://sourceforge.net/projects/cjson/) which is used in the C application and the other is the JSON simple package (https://code.google.com/p/json-simple/) which is used in the Java application. JSON provides the capability to communicate between components which are not binary compatible similar to what XML provides. However JSON seems to be easier to work with for simple needs.

Background

With this article and its source code, I am attempting to document lessons learned during this exploration of embedding a Java Virtual Machine (VM) into a C/C++ application and providing a native library using JNI to provide additional capabilities. As part of this exploration, I have also looked into using JSON to communicate complex data structures between the Java side and the C side.

You will need to have some experience with C and be comfortable with pointers including function pointers in order to understand the code from this exploration. You will also need to have some experience with Java.

I used Visual Studio 2005 for this work however since this is only a few files and two projects within the Visual Studio solution, this work should be easy to port to newer versions of Visual Studio.

I was pleased to find that working with the Java source file in a step wise refinement fashion was quite straightforward with Visual Studio 2005. I added a custom build step to invoke the javac compiler when doing a build. I have put comments into the Java source file, helloworld.java, documenting the custom build step. The main issue I ran into from a working perspective was identifying the specific line that was generating a javac compiler error.

Since I am using older C Standard Library functions such as strcpy() and sprintf(), the Visual Studio 2005 compiler is issuing warnings suggesting that the secure versions of these functions should be used instead. I have ignored that issue for this example.

Using the Code

The Visual Studio 2005 solution is divided into two projects. The project jvm_test contains the C application, jvm_test.cpp, and the Java application, helloworld.java, source files and builds the main applications. The project jvm_data_if contains the C source for the native functions used by the Java application and builds the dynamic link library jvm_data_if.dll used by the Java application.

The source for the cJSON library was downloaded and put into a folder called cJSONFiles as a sub-folder of the jvm_data_if folder project. I deleted unnecessary files to reduce clutter making no changes to the source.

As a side note, I have wondered whether the cJSON library would provide a way to have variables that would exhibit a chameleon property of exposing different types depending on how the variable is used. It would seem that under some circumstances having the capability to access the contents of a variable as an int or a char string would provide a flexibility that would be worth the additional overhead in terms of memory and CPU. For instance, in the helloworld.java application, I use automatic conversion facilities to build a string out of various pieces.

The execution environment also requires that the JSON simple jar file be available to the Java application. There is a folder, class_jars, which is at the same level as the build output folders and the .sln Visual Studio solution file where the JSON simple jar file is put. For this example, the starting of the Java VM includes specifying the -Djava.class.path using a relative path that specifies the folder class_jars where the jar file containing the JSON simple classes json-simple-1.1.1.jar.

Since as part of the build output is the helloworld.class created by the javac compiler output of the helloworld.java source, we have to include the path to the directory where the helloworld.class class file is located. In this case, we also use a relative path however the path will vary depending on whether this is a Debug build or a Release build so we use the C Preprocessor with #if to determine which version of the -Djava.class.path we need to use.

Finally I am using the Win32 API to start a thread for the Java Virtual Machine. The main thread does not do anything else in this example, it merely waits for the thread running the Java VM to complete and exit. However, there are future thoughts.

Thoughts for the Future

The next phase of this exploration would be to do a more involved example in which the Java application starts up an instance of Jetty. An area that needs to be explored is how to allow the Java application to communicate with the main C application. Currently the native library is a DLL which is separate from the main C application.

However, the goal is to have a Java application that is providing web server facilities and acting as an intermediary between the C application and any web clients wanting to interact with the C application. Some possibilities include using shared memory, the file system, or interprocess communications such as pipes or sockets with TCP or UDP.

One other possibility is to use the DLL as an intermediary since the C application and the Java application and the Dynamic Link Library are all in the same address space. Because all components are in the same address space, the C application could provide to the Java application access to functions and data in the C application by providing to the DLL, a struct containing function and data pointers which would be used by the functions of the DLL to provide access to those functions and data for the Java application.

Comments on Source Update 20th January, 2015

Being curious about how to access the fields of a Java object through the Java VM functions on the native C side, I spent some time working on a native function dumpMe() that would print the various fields of the helloworld class to the standard output device or console window. The dumpMe() function prints out the myInt and the myString fields, an int and a String respectively, and then prints out the fields of the myStruct object which is a RecordStruct class. This would seem to capture the basics of more complicated field processing.

To make things a bit easier, I create some infrastructure on the native C side, two structs to represent the two classes of helloworld and RecordStruct and two functions, fill_helloworld() to fill in a struct Java_helloworld that will take a Java object and create a representation on the native C side that is useful. Notice that the fill_helloworld() function calls a second function, fill_RecordStruct() to handle the transformation for the myStruct field of the helloworld class.

The source for these two native C structs used to represent the Java classes on the native side look like the following:

Java
// represent the RecordStruct class
typedef struct {
    jstring  key;
    jstring  firstName;
    jstring  lastName;
    jint     age;
} Java_RecordStruct;

// represent the helloworld class.
typedef struct {
    jint     myInt;
    jstring  myString;
    Java_RecordStruct  myStruct;
} Java_helloworld;

Generally, the procedure is to use the Java VM function GetObjectClass() to obtain a class description handle, type jclass, to then use the GetFieldID() function to get the field identifier for the field within the class. Once you have the field identifier, you can then get the value of the field from the object.

The following source snip shows the basic process. Notice that a Java int built-in has a direct analogue on the native C side as a jint while a String is treated as an object on the native C side. The result is that in order to access the actual text in the String requires another step requesting that the Java VM provide a character array containing the text. However keeping it as a jstring and only doing the conversion when necessary seems like the best course of action.

Java
jclass helloworld_obj = (*env)->GetObjectClass(env, obj);
jfieldID fid_myInt = (*env)->GetFieldID (env, helloworld_obj, "myInt", "I");
jfieldID fid_myString = (*env)->GetFieldID (env, helloworld_obj, "myString", "Ljava/lang/String;");

myWorld->myInt = (*env)->GetIntField (env, obj, fid_myInt);
myWorld->myString = (*env)->GetObjectField (env, obj, fid_myString);

By the way, in the above example, the pointer myWorld is a pointer to the native C struct, Java_helloworld, we are using to hold native representation of the Java object on the native side. Using a struct to represent the Java object seems fairly intuitive and the use of a helper function to perform the translation nicely encapsulates the source that performs the transformation.

Also notice that some fields have short field types for instance "I" for an int field whereas others have what I would call a fully qualified type such as for a String which uses "Ljava/lang/String;" or in the case of the myStruct object of type RecordStruct which uses "Lhelloworld$RecordStruct;". This last uses a dollar sign to separate the private class RecordStruct encapsulated by the helloworld class from its enclosing class.

One thing to remember is that some of the members of this struct are not the actual entities but rather a kind of handle to the corresponding Java object entity within the Java VM. So in order to actually get the value of the object, you will need to use a Java VM function to do the necessary conversion. An example is with String fields in the Java class. The process for actually accessing the text of a string requires that the jstring handle be used to ask the Java VM to provide a char array containing the text of the String. So to access the actual text of the String you need a series of lines of source such as the following:

Java
const char *strKey;
strKey = (*env)->GetStringUTFChars(env, myWorld.myString, NULL);
printf ("  helloworld.myString %s\n", strKey);
(*env)->ReleaseStringUTFChars(env, myWorld.myString, strKey);

Notice in this example that the char pointer, strKey, is a const char *. The pointer and the text pointed to that the Java VM provides from the GetStringUTFChars() function should not be modified in any way.

Finally, I have tried to update the comments to provide more information and to better organize the source.

One remaining point is about the GetFieldID() function. There are a number of articles in various places on the web indicating that the GetFieldID() function can be a performance hit. So this function should be used as sparingly as possible including the caching of field identifiers. The field identifier is created at the time the class is loaded and remains the same value until such time as the class is unloaded. One suggestion I came across was to have a native C function that is called at the time a class is loaded allowing the native functionality to obtain the needed field identifiers and to cache them. This approach can improve performance with large Java applications with many classes. However with this example, any such improvement would not be noticed. A minimum precaution would be to lift any use of GetFieldID() out of loops.

Comments on Source Update 25th January, 2015

This is the final update currently envisioned. This update is a further exploration into the C application using the Java Virtual Machine. In this version the C application exports functions and data to the Java application running in the Java VM that has been started by the C application.

A Brief Overview of Source Changes

A couple of new files have been added to both of the projects so as to reduce changes to the existing files from previous versions of the source code for this article. However the new functionality did require changes to the Java application in helloworld.java in order to use the new functionality added to the jvm_data_if.dll as well as a few changes to the C application source in file jvm_test.cpp.

The output generated by the helloworld.java has been changed with some improvements to the output as well as additional output as part of exercising the new functionality.

I also had to make some adjustments to the Properties of the projects the most important being to the jvm_test project so that the C application would link with the jvm_data_if.dll and its library. I also added a new .bat file to the jvm_test project with the commands necessary to run the javah and javap utilities against the Java class files generated by a debug build. The information generated by these utilities can be useful to a JNI programmer.

Details on the Changes

We are using the dynamic link library, jvm_data_if.dll created by the jvm_data_if project, as a way for the C application to provide to the Java application access to exported data and exported functions. The basic procedure is for the C application to call the initialization function in the jvm_data_if.dll and to then start up the Java VM with the Java application.

With this example the C application has three different versions of the interface that it is exporting. The Java application is able to decide which of the three interface versions it wants to use, request that interface version, and then use it. This interface version idea is used by a variety of different Commercial Off The Shelf (COTS) components such as the Microsoft Direct-X. The idea is that a user application can write to a particular interface and the interface vendor can provide updates with new functionality using a new interface version without impacting older user applications that continue to use the older interface.

The source file exportedfuncs.cpp in the project jvm_test which creates the C application contains the functions and data that the C application is exporting. Before the C application starts the Java VM, it calls the function Java_exportedfuncsfactory() providing a pointer to the function ExportedFuncsFactory(). The function ExportedFuncsFactory() is defined in the source file exportedfuncs.cpp and when called specifying a particular version number, it will return a pointer to the interface version requested. Interface versions are pointers to structs composed of function pointers to the functions for that version of the interface.

As a side note, something similar seems to be what is used by the JNI library through the JNIEnv pointer. This pointer is to a struct containing the various JNI functions exported by the Java Virtual Machine which are accessed through a pointer of that type as in for instance (*env)->GetMethodID(...).

So the C application creates what amounts to an interface factory function which looks like the following. This function is defined in the include file exportedfuncs.h which also contains the declarations for the various interface versions. This include file is also included by the native methods file exportedfuncs.c in the jvm_data_if project which provides the JNI functions used by the Java application. The exportedfuncs.h from the jvm_test project provides the interface specification for the functions and data exported by the C application so it must be included in the JNI of the Java application so that both the C application and the Java application have knowledge of the interface and data exported by the C application.

Java
ExportedFuncsUnion ExportedFuncsFactory (ExportedFuncsTypes iType)
{
    ExportedFuncsUnion  retValue = {ExportedFuncsType_0, 0};
    retValue.iType = iType;
    switch (iType) {
        case ExportedFuncsType_1:
            retValue.u.pFuncs_1 = &FuncsStruct_1;
            break;
        case ExportedFuncsType_2:
            retValue.u.pFuncs_2 = &FuncsStruct_2;
            break;
        case ExportedFuncsType_3:
            retValue.u.pFuncs_3 = &FuncsStruct_3;
            break;
    }

    return retValue;
}

When initializing the environment for the Java application, the C application calls a function in the jvm_data_if.dll designed to provide the factory function to the native methods used by the Java application like the following.

Java
// the function prototype is declared in data_get_setter.h in jvm_data_if project.
// this function is part of the jvm_data_if.dll and is used to provide to the
// Java application we are starting up the functions that the C application is exporting.
Java_exportedfuncsfactory (ExportedFuncsFactory, ExportedFuncsType_1);

So there is quite a bit of indirection involved in providing different interface versions. First of all the C application has to provide to the jvm_data_if.dll a pointer to a function that will provide different versions of the interface. These different interface versions are, similar to a C++ vtable or a COM instance, a struct of function pointers. The native functions that the jvm_data_if.dll provides to the Java application access the C application functions through one of the possible structs.

It all comes together in the JNI function Java_helloworld_00024ExportedFuncs_getExportedData() located in the source file exportedfuncs.c in the jvm_data_if project. The function is replicated below to show the use of the Java VM functions need to create an instance from a class, to obtain the correct version of the C application interface, and to then use that interface to obtain data to fill in the newly created object.

Java
/*
 * getExportedData method of the ExportedFuncs inner class of the helloworld class to
 * create an object of the ExportedData class and provide the data back to the c
 * as an object of the class.
 *  public native ExportedData getExportedData(int iVal);
 */
JNIEXPORT jobject JNICALL Java_helloworld_00024ExportedFuncs_getExportedData (JNIEnv *env, jobject obj, jint iValue)
{
    jfieldID fid = (*env)->GetFieldID(env, (*env)->GetObjectClass(env, obj), "theExportedData", "Lhelloworld$ExportedFuncs$ExportedData;");
    jobject newObj = 0;
    jclass cls = (*env)->FindClass(env, "Lhelloworld$ExportedFuncs$ExportedData;");

    // Get the Method ID of the constructor for this inner class.
    // There are two things to notice about this GetMethodID() function call.
    // First, the constructor is requested by specifying the special string "<init>"
    // Second, the signature of the constructor includes the enclosing class in the signature.
    // Also there are no arguments for this constructor. if there were then they would need to be included between the parenthesis
    // for example "(Lhelloworld$ExportedFuncs;I)V" for a single int arg.
    jmethodID midInit = (*env)->GetMethodID(env, cls, "<init>", "(Lhelloworld$ExportedFuncs;)V");
    if (NULL == midInit) return NULL;

    // Call the class constructor to allocate a new instance.  the default constructor has no arguments.
    newObj = (*env)->NewObject(env, cls, midInit);

    // now lets set some values in our new object and return it if the object exists.
    if (newObj) {
        // we were able to create the object so lets fill in the fields of the ExportedData
        // by fetching the data from the C application using the interface provided.
        const char *theString = 0;
        jfieldID fid_theString = (*env)->GetFieldID (env, cls, "theString", "Ljava/lang/String;");
        jfieldID fid_theInt = (*env)->GetFieldID (env, cls, "theInt", "I");
        jstring versionString = 0;
        if ((theString = Java_helloword_ExportedFuncsInterface.getStr (iValue)) != 0) {
            // if the requested string is in the C application table then generate
            // a Java String.  otherwise the value will be NULL.
            versionString = (*env)->NewStringUTF (env, theString);
        }
        (*env)->SetIntField (env, newObj, fid_theInt, iValue);
        (*env)->SetObjectField (env, newObj, fid_theString, versionString);
    }

    return newObj;
}

This native method getExportedData() is called in the Java application source in helloworld.java during the construction of an ExportedFuncs object as part of creating an instance of helloworld in order to create an ExportedData object using a default data value. As part of exploring the JNI I have also used a call with an out of range value to see how the out of range is handled by my native method.

The javah and javap Utilities

With the changes for this article version, I have added a .bat file, genjavah.bat, to the jvm_test project. This .bat file uses the standard Java utilities of javah and javap to provide information about the helloworld.class files. I had not realized how useful the information these utilities can generate with the proper command line options when working with JNI. The .bat file does use the .class files located in the Debug folder generated by a debug build so a debug build needs to be done before running the .bat file in order to generate include file stubs using the javah utility and a file, helloworld_javap.txt, containing the output of the javap utility.

The output of both the javah and javap utilities are helpful for a programmer working with JNI. For instance, the javap utility can be helpful in providing fully qualified names of variables variables and method signatures. The javac Java compiler generates native method signatures in the .class files which the javah utility can read to generate the corresponding C language function prototypes. The output generated by the javap utility is especially useful for complex class structures with inner classes, etc.

A Few Final Thoughts

The work involved in this series of article and source updates for the exploration of what can be done with JNI has been interesting. Since the source has been modified and changed and updated, it is somewhat messy and it shows a number of false starts. My apologies for that.

I have tried to investigate a number of problem areas for aspiring JNI programmers based on questions generated during this exploration as well as questions that I have seen in various forums on the internet. I have pulled together various bits and pieces scattered about in various places attempting to create a whole quilt from various pieces and scraps.

What I suspect is that the approach used of iterating through versions exploring various topics has caused me to miss a more abstract approach. Much of what I have done is procedural in nature using the JNI functions of the Java VM in step by step procedures tied to specific class structures. It is my impression that there is quite a bit of information maintained by the Java VM and that a JNI programmer should be able to interrogate the environment and the objects in order to provide a more abstract approach

Points of Interest

The CLASSPATH Environment Variable with the Java VM

One crucial point about embedding a Java Virtual Machine that I ran into was that the Java VM did not seem to recognize or use the CLASSPATH environment variable. When I tried to use the JSON simple components in my Java application after adding the path to the jar file to the CLASSPATH, the Java application was failing. What I saw in the Visual Studio debugger was that the Java VM thread was signaling completion almost immediately with no output in the console window.

After some probing by commenting source out within the Java application and moving System.out.println() calls to get some output, I discovered that the problem was the creation of the JSON simple parser object. I finally modified the Java VM startup arguments to include on the -Djava.class.path argument the path to the JSON simple jar file and the Java application no longer crashed. This leads me to the conclusion that when starting the Java VM in a C application, the C application must replicate the CLASSPATH environment variable using the -Djava.class.path as an argument to the Virtual Machine when it is started.

The Symbols and Interface for Native Functions Invoked Through JNI

While the normal procedure is to use the javah utility to generate boilerplate or stubs for the C functions, I instead hand coded the C functions following what appeared to be the standard. For this simple example, this approach worked out fine. My understanding is that the native function names would include the package path as part of the naming convention, however for this example I am not using package.

Errors in Interface Causing Unexpected Java VM Termination

There were several times when I modified the interface for a native method in the Java application and forgot to make a similar modification to the actual C function prototype on the native side. This caused run time errors in the Java application in which the application would terminate unexpectedly. In my Visual Studio 2005 development environment, the information provided on the termination was none. Setting a break point in the C function indicates that the Java VM was terminating before the C function was called. In some cases, the debugger would show an actual run time error however in most cases the Java VM was just terminating with no error indication in the Output window of the debugger nor any error indication.

All of the native C functions called by the Java application have the same first two arguments:

  1. JNIEnv *env which is a pointer to a struct containing function pointers for the various Java VM interface functions and
  2. jobject obj which is an opaque pointer to the object where the native function is defined in the Java application

The struct JNIEnv is analogous to a C++ vtable (virtual table) or a COM interface pointer. It provides a way to access the functions that access and convert data from the Java VM with its representation to the native C representation. The jobject is an opaque pointer to a Java object the fields of which are accessed through the various Java VM functions exposed by the JNIEnv pointer.

Using the JNIEnv pointer with C Source

An important point to remember about using the functions that are exposed through the JNIEnv pointer when using C. The JNI interface is (JNIEnv *env, jobject obj, ...) so to use a JNI function such as GetObjectClass() the syntax used with C is (*env)->GetObjectClass(env, obj); which will dereference the JNIEnv pointer and call the GetObjectClass() function through the function pointer stored in the JNIEnv struct. The first argument is always the JNIEnv pointer variable for C source code.

The JNI header file has provisions for C++ source to wrap the JNI functions within a struct that provides the JNIEnv pointer as the this pointer. However C source requires the JNIEnv pointer as the first argument or you will have compile errors. What I ran into with Visual Studio 2005 was that the intellisense prompting was providing the function prototype for C++ so I had to remember to ignore the prompt and always start with the JNIEnv pointer as the first argument to the JNI functions.

Accessing Java Object Variables and Rationale for jSON

To access the Java object variables within a native function is a bit tedious requiring the use of a series of function calls to find the variable within the object and to then access it with a getter or a setter type of function. An example is the following small function that accesses an int variable, gets the current value, sets the variable to zero, and then returns the original value.

Java
JNIEXPORT jint JNICALL Java_helloworld_dataClearMyInt (JNIEnv *env, jobject obj)
{
    // get the reference to the actual object then we will search for the variable
    // we want to modify and if found, we will then copy the old value to return it
    // and set it with a new value of zero.
    jint oldInt = 0;     // define the variable that will contain the old value
    jclass helloworld_obj = (*env)->GetObjectClass(env, obj);
    jfieldID fid = (*env)->GetFieldID (env, helloworld_obj, "myInt", "I");

    if (fid) {
        // this check was originally done with the expectation that we could probe the
        // object to see if a variable was defined or not however what we ran into was
        // the Java VM seems to detect that a GetFieldID() was done on a non-existent
        // variable and it will terminate when this function returns.  So sad!!!
        oldInt = (*env)->GetIntField (env, obj, fid);
        (*env)->SetIntField (env, obj, fid, 0);
    }
    return oldInt;
}

A you can see, the procedure is fairly tedious and error prone. One issue I ran into was that if the variable did not exist in the object, then even though I checked the result, the Java Virtual Machine would still exit when the native function returned. It was as if the Java VM would not allow for the probing of an object and making run time decisions about an object and what variables were actually available.

This is why I thought that using JSON as a representation to communicate between Java and native would work out quite nicely for more complex data structures.

Using JSON to Communicate Between Java Application and C Native

One issue that I have run into in my work is the marshalling and communication of data across interfaces. JSON solves this problem quite nicely as does XML by using a text representation. I have seen XML used to communicate with a COM control in which an XML text string is created and a method in the COM control is called with the XML text string as an argument and the method returns another XML text string containing the results of the operations.

Using XML in this fashion made for a flexible interface in which the XML allowed for options to be specified or left out. It also allowed for a simple COM interface that made the development of any wrappers needed for a particular target language or environment to be straightforward and easy. As long as the language provides a mechanism to instantiate the COM object and a way to call the method with a text string, it is possible to use the COM control.

While XML works well for this kind of communication as well as web applications between client and server, in the last few years JSON is gaining a greater mind share due to its simplicity and the ease of using it with JavaScript. There are a number of different packages that provide JSON capability for Java and C as well as other languages however for this example I picked the cJSON library for the C native library and the JSON simple library for the Java application. There was no particular reason I picked these two over other offerings.

What I like about using JSON is that it can describe an object or record and using it I can specify an update to an existing record with only the fields to be modified. In the Java application, there is a point where I fetch an existing record held by the native library and update just the Age data in the record.

Java
// retrieve a specific record from the database which we get
// as JSON text and then store the data into our Java object.
sJson = jjj.retrieveJsonRecord("1012221234");
jjj.myStruct.storeJson(sJson);
System.out.println("sJson1 = " + sJson);
System.out.println(" sJson2 = Key \"" +jjj.myStruct.key + "\" -> "+
jjj.myStruct.lastName + ", " + jjj.myStruct.firstName + " - Age: " + jjj.myStruct.age);
// now update just the age for this dataBase record then fetch it again to check.
structString = "{\"Age\" : 45 }";
iStatus = jjj.insertupdateJsonRecord(jjj.myStruct.key, structString);
sJson = jjj.retrieveJsonRecord("1012221234");
jjj.myStruct.storeJson(sJson);
System.out.println("    sJson2 = Key \"" +jjj.myStruct.key + "\" -> "+
jjj.myStruct.lastName + ", " + jjj.myStruct.firstName + " - Age: " + jjj.myStruct.age);

On the native library side, the C function using the cJSON library does a series of GetObjectItem() calls for each of the JSON text key words. If the key word was specified in the JSON text, then the return value will be a valid, non-zero pointer and we can then access the value for the key word. By testing the return value for each of the keywords, we are able to make specific changes to the record allowing the Java application to make targeted modifications to a record.

C++
// next we will process the JSON object one field at a time checking to
// see if the field was included in the JSON object.  if a field is
// not specified in the JSON then we will not modify that field in the
// record we have which may be either a new record or a copy of an
// existing record we are modifying.
obj = cJSON_GetObjectItem(root,"FirstName");
if (obj)
    strcpy (newRecord.m_FirstName, obj->valuestring);

obj = cJSON_GetObjectItem(root,"LastName");
if (obj)
    strcpy (newRecord.m_LastName, obj->valuestring);

obj = cJSON_GetObjectItem(root,"Age");
if (obj)
    newRecord.m_Age = obj->valueint;

History

  • 18th January, 2015: Initial version
  • 20th January, 2015: Updated source with example using Java VM functions accessing fields

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)