How to access JSON data passed to c in jni? - c

My java program passes JSONObject to native program like this:
import org.json.simple.JSONObject;
class json{
static{
System.loadLibrary("json");
}
private native void json(JSONObject j);
public static void main(String args[]){
json js = new json();
JSONObject j = new JSONObject();
j.put("name","someone");
j.put("age", 15);
js.json(j);
}
}
how to access these data in c?
#include<stdio.h>
#include<jni.h>
#include "json.h"
#include "cJSON.h"
JNIEXPORT void JNICALL Java_json_json(JNIEnv *env, jobject obj, jobject j){
return;
}
i couldn't find any reference on how to access json data from jobject in c.
I'm new to jni. is there any other way to do it?

Accessing the JSON data from the C code via JNI is not much different from accessing it via Java. In Java you would write:
System.out.println("name = " + j.get("name"));
System.out.println("age = " + j.get("age"));
The C code is basically the same, just much more verbose, since
You need to get the class object to call methods on them
You need to construct jstring instances for the keys passed to get
You must convert the jstring you get from j.get("name") to a C string
You must release that string after use
You must manually unbox the java.lang.Integer that you get
The code below does just that:
#include<stdio.h>
#include<jni.h>
#include "json.h"
// Notice that "cJSON.h" is not needed
JNIEXPORT void JNICALL Java_json_json(JNIEnv *env, jobject obj, jobject json) {
// Get the Class object for JSONObject.
jclass JSONObjectClass = (*env)->GetObjectClass(env, json);
// Get the ID of the "get" method that we must call.
// Notice that due to type erasure, both the parameter and the return value
// are just plain Objects in the type signature.
jmethodID getID = (*env)->GetMethodID(env, JSONObjectClass, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
if (getID == NULL) return;
// Create java.lang.String instances for the keys we pass to j.get.
jstring nameKey = (*env)->NewStringUTF(env, "name");
jstring ageKey = (*env)->NewStringUTF(env, "age");
if (nameKey == NULL || ageKey == NULL) return;
// Actually get the name object. Since we know that the value added
// in the Java code is a string, we just cast the jobject to jstring.
jstring name = (jstring) (*env)->CallObjectMethod(env, json, getID, nameKey);
if (name == NULL) return;
// Get a C string that can be used with the usual C functions.
const char *name_cstr = (*env)->GetStringUTFChars(env, name, NULL);
if (name_cstr == NULL) return;
printf("name = %s\n", name_cstr);
// Once done, the string must be released.
(*env)->ReleaseStringUTFChars(env, name, name_cstr);
name_cstr = NULL;
// Get the java.lang.Integer object representing the age.
jobject ageObj = (*env)->CallObjectMethod(env, json, getID, ageKey);
if (ageObj == NULL) return;
// Unbox the java.lang.Integer manually.
jclass IntegerClass = (*env)->GetObjectClass(env, ageObj);
jmethodID intValueID = (*env)->GetMethodID(env, IntegerClass, "intValue", "()I");
if (intValueID == NULL) return;
jint age = (*env)->CallIntMethod(env, ageObj, intValueID);
printf("age = %d\n", (int) age);
}
More complicated use is done the same way: Check what you would write in Java, and find a way to call the same methods with the same values in C using the JNI functions.

Related

Kotlin/Native to C dylib : How to access class members in a instance object which returned by a method?

I am trying to learn Kotlin/Native C interop
I exported some Kotlin classes as C dynamic Lib and succeeded in access methods with primitive return types
But When trying to access class members in a instance object which returned by a method, the object contains something named as pinned
Code sample:
#Serializable
data class Persons (
val results: Array<Result>,
val info: Info
)
class RandomUserApiJS {
fun getPersonsDirect() : Persons {
return runBlocking {
RandomUserApi().getPersons()
}
}
}
Now when using them in C codeblocks,
In this image, note that the persons obj only showing a field named pinned and no other member functions found.
Since I don't know that much in C/C++ and can't investigate further.
Please help me to understand to access instance members of Kotlin Class in exported C lib?
Header file for ref:
https://gist.github.com/RageshAntony/a0b9007376084fa8b213b022b58f9886
for your gist
https://gist.github.com/RageshAntony/a0b9007376084fa8b213b022b58f9886
I modified the following:
// I comment this annotation
// #Serializable
data class Persons(
val results: List<Result>,
val info: Info,
/**
* the Result's properties too many
* I will use a simple data class for this example
* how to get c array from Persons (also suitable any iterable)
*/
val testList: List<Simple>,
) {
public fun toJson() = Json.encodeToString(this)
companion object {
public fun fromJson(json: String) = Json.decodeFromString<Persons>(json)
}
val arena = Arena()
fun getTestListForC(size: CPointer<IntVar>): CPointer<COpaquePointerVar> {
size.pointed.value = testList.size
return arena.allocArray<COpaquePointerVar>(testList.size) {
this.value = StableRef.create(testList[it]).asCPointer()
}
}
fun free() {
arena.clear()
}
}
/**
* kotlin <-> c bridge is primitive type
* like int <-> Int
* like char* <-> String
* so the Simple class has two primitive properties
*/
data class Simple(
val name: String,
val age: Int,
)
#include <stdio.h>
#include "libnative_api.h"
int main(int argc, char **argv) {
libnative_ExportedSymbols* lib = libnative_symbols();
libnative_kref_MathNative mn = lib->kotlin.root.MathNative.MathNative();
const char *a = lib->kotlin.root.MathNative.mul(mn,5,6); // working
printf ("Math Resullt %s\n",a);
libnative_kref_RandomUserApiJS pr = lib->kotlin.root.RandomUserApiJS.RandomUserApiJS();
libnative_kref_Persons persons = lib->kotlin.root.RandomUserApiJS.getPersonsDirect(pr);
// when accessing above persons obj, only a field 'pinned' availabe, nothing else
int size;
libnative_kref_Simple* list = (libnative_kref_Simple *)lib->kotlin.root.Persons.getTestListForC(persons, &size);
printf("size = %d\n", size);
for (int i = 0; i < size; ++i) {
const char *name = lib->kotlin.root.Simple.get_name(list[i]);
int age = lib->kotlin.root.Simple.get_age(list[i]);
printf("%s\t%d\n", name, age);
}
lib->kotlin.root.Persons.free(persons);
return 0;
}
// for output
Math Resullt The answer is 30
size = 3
name1 1
name2 2
name3 3
But I don't think calling kotlin lib through C is a good behavior, because kotlin native is not focused on improving performance for now, in my opinion, all functions that can be implemented with kotlin native can find solutions implemented in pure c, So I'm more focused on how to access the c lib from kotlin. Of course, it's a good solution if you absolutely need to access klib from c, but I'm still not very satisfied with it, then I may create a github template to better solve kotlin-interop from c.But that's not the point of this answer.

Extracting jansson JSON data

I am using the C jansson library http://www.digip.org/jansson/
It's quite easy to use https://jansson.readthedocs.org/en/2.7/tutorial.html#the-program
But I cannot get a simple int out of my JSON string. I can successfully receive and load a string of JSON (as in I get no errors, nothing is null) but when I use the jansson get functions to get an int, my int is always 0 even though using steps and breakpoints, the jansson function process an in is not returning 0.
The JSON string looks like this:
{"type":3}
Here is the code:
static void foo(json_t *jsonRoot) {
// json root is error checked even before this, and is not null
if (jsonRoot == NULL) {
return;
}
// Trying to get type = 3
json_t *j_type;
int type = 0;
j_type = json_object_get(jsonRoot, "type");
if (!json_is_integer(j_type)) {
printf("Not an int!\n");
return;
} else {
// I get in to the else
// json_integer_value has a its own internal check and
// will return 0 if the value is not an int, but it is not
// returning 0. It is running the macro json_to_integer(json)->value
type = json_integer_value(j_type);
}
printf("type is %d\n", type);
// type is 0
}
My issue was with strtoll. I had to redefine it.

Pointers, functions and arrays in D Programming Language

I'm writing a method to output to several output streams at once, the way I got it set up right now is that I have a LogController, LogFile and LogConsole, the latter two are implementations of the Log interface.
What I'm trying to do right now adding a method to the LogController that attaches any implementation of the Log interface.
How I want to do this is as follows: in the LogController I have an associative array, in which I store pointers to Log objects. When the writeOut method of the LogController is called, I want it to then run over the elements of the array and call their writeOut methods too. The latter I can do, but the previous is proving to be difficult.
Mage/Utility/LogController.d
module Mage.Utility.LogController;
import std.stdio;
interface Log {
public void writeOut(string s);
}
class LogController {
private Log*[string] m_Logs;
public this() {
}
public void attach(string name, ref Log l) {
foreach (string key; m_Logs.keys) {
if (name is key) return;
}
m_Logs[name] = &l;
}
public void writeOut(string s) {
foreach (Log* log; m_Logs) {
log.writeOut(s);
}
}
}
Mage/Utility/LogFile.d
module Mage.Utility.LogFile;
import std.stdio;
import std.datetime;
import Mage.Utility.LogController;
class LogFile : Log {
private File fp;
private string path;
public this(string path) {
this.fp = File(path, "a+");
this.path = path;
}
public void writeOut(string s) {
this.fp.writefln("[%s] %s", this.timestamp(), s);
}
private string timestamp() {
return Clock.currTime().toISOExtString();
}
}
I've already tried multiple things with the attach functions, and none of them. The build fails with the following error:
Mage\Root.d(0,0): Error: function Mage.Utility.LogController.LogController.attach (string name, ref Log l) is not callable using argument types (string, LogFile)
This is the incriminating function:
public void initialise(string logfile = DEFAULT_LOG_FILENAME) {
m_Log = new LogController();
LogFile lf = new LogFile(logfile);
m_Log.attach("Log File", lf);
}
Can anyone tell me where I'm going wrong here? I'm stumped and I haven't been able to find the answer anywhere. I've tried a multitude of different solutions and none of them work.
Classes and interfaces in D are reference types, so Log* is redundant - remove the *. Similarly, there is no need to use ref in ref Log l - that's like taking a pointer by reference in C++.
This is the cause of the error message you posted - variables passed by reference must match in type exactly. Removing the ref should solve the error.

How to access python class from C extension?

I have my extension for Python written in C. Currently I need to process in a function of my extension objects of a type declared in some external pure python module (Say, its name is ext_module). First of all I need to ensure that input object type corresponds some class from ext_module. How can I implement this?
Some additional code:
static PyObject * extensionFunction( PyObject* self, PyObject *args ) {
const char *inputString = NULL;
PyObject *inputList = NULL;
if ( 0 == PyArg_ParseTuple( args, "sO", &inputString, &inputList ) ) {
return NULL;
}
if ( 0 != PyList_Check( inputList ) ) {
// here I need to check whether the list items are instances of ext_module.ExtClass
} else {
PyErr_SetString( PyExc_TypeError, "extensionFunction: expected list" );
return NULL;
}
// process arguments
Py_RETURN_NONE;
}
Actually I can just try to call the expected methods and get an exception NotImplementedError, but I'm not sure if this is correct approach.

How do I use Control.Invoke if I need to pass in a mixture of reference and value types?

How do I do something like the following?
private delegate void RenameOperation(string name, string uniqueName, int position);
private void AssignColumnNames(string name, string uniqueName, int position)
{
dataGridView1.Columns[position].HeaderCell.Value = name;
dataGridView1.Columns[position].HeaderCell.Tag = uniqueName;
}
void SomeFunction()
{
int colCount = 0;
// ... some other code
if (dataGridView1.InvokeRequired)
{
RenameOperation rename = new RenameOperation(AssignColumnNames);
dataGridView1.Invoke(rename, member.Name, member.UniqueName, colCount);
}
}
Each time I do this I get Object of type 'System.Int32[]' cannot be converted to type 'System.Int32' and I don't know how to solve my problem at all. I could probably code this very differently but I'm interested in why I can't do this.
Managed to solve my own problem here - for anyone who is interested I had passed colCount into invoke between declaring it and calling this invoke, but had written: dataGridView1.Invoke(new ResizeOperation(AddColumn), new[] { colCount }); because I thought the type information there was redundant.

Resources