i am getting java.lang.Byte[] from c(jbyteArray in JNI) . How to convert this jbyteArray to string in java.
c function is
jbyteArray Java_eu_ratikal_helloc_MainActivity_getNameBytes(JNIEnv* env, jobject thiz) {
int n=0;
jstring na ="HelloAndroidString";
char* p = "HelloAndroidString";
while(*p++){
n++;
}
jbyteArray arr = (*env)->NewByteArray(env, n);
(*env)->SetByteArrayRegion(env,arr,0,n, (jbyte*)na);
char* b = (char*)arr;
return arr;
}
java code is
byte[] bytes = getNameBytes();
Getting compilation error like
Incompatible types
Required byte[]
Found java.lang.Byte[]
You need to return
public native byte[] getNamBytes();
but to convert it into a String you need to use new String e.g.
public String String getName() {
return new String(getNameBytes(), "UTF-8");
}
Related
I am using JNI (and now JNA to see if the issue changes) to connect Java to a C code. This code has two methods that I am trying to use and they should be called from Java code many times, however, when I do the native calls, I got it:
Call method one = I got a response
Call method two = I got a response
Call method one again = Attempt to reference unallocated memory
(Signal SIGSEGV)
Execution stops with this failure.
I tried to call the first and second methods alone (not calling them one after other) and the issue doesn't occur. It just happens when I call one after other, just like they should work. Looks like I am not freeing the memory as I should or JNA/JNI is doing it.
C code (JNI)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "struct1.h"
#include "struct2.h"
#include "struct3.h"
#include "CALLExternMethod1s.h" //Interface External method
#include "CALLExternMethod2s.h" //Interface External method
#include "com_Method1Java.h" //Interface to Java Class
#include "com_Method2Java.h" //Interface to Java Class
void printStruct(void * structPar, int structSize) {
char buffer[structSize + 1];
memcpy(buffer, structPar, structSize);
buffer[structSize] = 0x00;
printf("{'%s'}\n", buffer);
}
JNIEXPORT jstring JNICALL Java_com_Method1Java_method1(JNIEnv *env, jobject obj, jstring input){
jboolean isCopy;
const char *request = (*env)->GetStringUTFChars(env, input, &isCopy);
struct1 struct1rec;
struct2 struct2rec;
char* response;
int reqLen = strlen(request);
reqLen = (reqLen <= sizeof(struct1)) ? reqLen : sizeof(struct1);
memcpy(&struct1rec, request, reqLen );
printf(" \n------ Struct1 Request ------\n ");
printStruct(&struct1rec, sizeof(struct1));
cob_init(0,NULL);
CALLExternMethod1(&struct1rec,&struct2rec); //Method overrides struct2rec with the response
response = malloc(sizeof(struct2) + 1);
memset(response, 0x20, sizeof(struct2) );
memcpy(response, &struct2rec, sizeof(struct2));
response[sizeof(struct2)] = '\0';
printf(" \n------ Struct2 Response ------\n ");
printStruct(response, sizeof(struct2));
(*env)->ReleaseStringUTFChars(env, input, request);
jstring result = (*env)->NewStringUTF(env, response);
free(response);
(*env)->PopLocalFrame(env,NULL);
printf("--- end of method1 JNI ---\n");
return result;
}
JNIEXPORT jstring JNICALL Java_com_Method2Java__struct3(JNIEnv *env, jobject obj, jstring input){
jboolean isCopy;
const char *request = (*env)->GetStringUTFChars(env, input, &isCopy);
struct3 struct3rec;
char* response;
int reqLen = strlen(request);
reqLen = (reqLen <= sizeof(struct3)) ? reqLen : sizeof(struct3);
memcpy(&struct3rec, request, reqLen );
printf("\n------ Struct3 Request ------\n");
printStruct(&struct3rec, sizeof(struct3));
cob_init(0,NULL);
CALLExternMethod2(&struct3rec); //Method overrides struct3Rec with the response
response = malloc(sizeof(struct3) + 1);
memset(response, 0x20, sizeof(struct3) );
memcpy(response, &struct3rec, sizeof(struct3));
response[sizeof(struct3)] = '\0';
printf("\n------ Struct3 Response ------\n");
printStruct(response, sizeof(struct3));
(*env)->ReleaseStringUTFChars(env, input, request);
jstring result = (*env)->NewStringUTF(env, response);
free(response);
printf("--- end of method2 JNI ---\n");
(*env)->PopLocalFrame(env,NULL);
return result;
}
C code (JNA)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "struct1.h"
#include "struct2.h"
#include "struct3.h"
#include "CALLExternMethod1s.h" //Interface External method
#include "CALLExternMethod2s.h" //Interface External method
void printStruct(void * structPar, int structSize) {
char buffer[structSize + 1];
memcpy(buffer, structPar, structSize);
buffer[structSize] = 0x00;
printf("{'%s'}\n", buffer);
}
char* method1(char *request){
struct1 struct1rec;
struct2 struct2rec;
char* response;
int reqLen = strlen(request);
reqLen = (reqLen <= sizeof(struct1)) ? reqLen : sizeof(struct1);
memcpy(&struct1rec, request, reqLen);
printf("\n------ Struct1 Request -------- \n");
printStruct(&struct1rec, sizeof(struct1));
CALLExternMethod1(&struct1rec, &struct2rec); //Method overrides struct2rec with the response
printf("\n------ Struct2 Response -------- \n");
printStruct(&struct2rec, sizeof(struct2));
response = malloc(sizeof(struct2) + 1);
memset(response, 0x20, sizeof(struct2) );
memcpy(response, &struct2rec, sizeof(struct2));
response[sizeof(struct2)] = '\0';
char* result;
memset(result, 0x20, sizeof(struct2));
result = response;
free(response);
return result;
}
char* method2(char *request){
struct3 struct3Rec;
char* response;
memcpy(&struct3Rec,request, sizeof(struct3));
printf("\n------ Struct3 Request -------- \n");
printStruct(&struct3Rec, sizeof(struct3));
CALLExternMethod2(&struct3Rec); //Method overrides struct3Rec with the response
printf("\n------ Struct3 Response -------- \n");
printStruct(&struct3Rec,sizeof(struct3));
response = malloc(sizeof(struct3) + 1);
memset(response, 0x20, sizeof(struct3) );
memcpy(response, &struct3Rec, sizeof(struct3));
response[sizeof(struct3)] = '\0';
char* result;
memcpy(result, response, sizeof(struct3));
return result;
}
int main(int argc, char** args){
return 0;
}
Java Call
(...)
static {
System.loadLibrary("libstuff");
}
public static synchronized native String method1(String struct);
(...)
CALLExternMethod1 and CALLExternMethod2 are not the problem. The issue happens even when there is fake response and methods are not used.
Anybody with the same issue?
I am new to JNI and have a requirement to convert a char[] to jcharArray and then create a String in JAVA. This String will be passed in a Parcel to other layers. When reading from the Parcel I want the other component to get the same byte sequence as of char array.
jchar *jcharBuffer1 = (jchar *)calloc(sizeof(jchar), length+1);
for (count = 0; count<length; count ++) {
jcharBuffer1[count] = (jchar)c_array[count];
}
jcharArray str1 = env->NewCharArray(length+1);
env->SetCharArrayRegion (str1, 0, length+1, jcharBuffer1);
This is my java code
public void testing(char[] array){
String test_str = new String(array);
Setdata(test_str)
}
public void Setdata(String data) {
Parcel request = Parcel.obtain();
Parcel resp = Parcel.obtain();
try {
.
.
request.writeString(data);
}
}
In the whole process I want the same byte sequence to arrive even after converting in to string. These bytes are decoded output from Base64 string from a server.
1. The jchar is 16bits but C-byte is 8 bit. So how can I achieve this requirement?
I'm working on a Android app that acts as TCP server/client i want to send data from the app to a server/client that is written in c/c++(made with the boost libraray). I have a normal Java function that calls a native c function for string converstion to bytes:
The function is defined as followed (the native function is Convert String:
// Send buffer, the method can be used by both client and server objects.
public void SendBuffer(String Buffer){
try {
// Convert char to string to byte
byte[] Temp = new byte[10];
String Teststring = "AAAAAAAABB";
Temp = ConvertString(Teststring);
//byte[] Temp = new String(Buffer).getBytes();
// Get socket output stream
OutputStream OutputBuffer = ClientSocket.getOutputStream();
//Write byte data to outputstream
OutputBuffer.write(Temp);
// Neatly flush and close the outputbuffer
OutputBuffer.flush();
OutputBuffer.close();
}
catch (IOException e) {
Log.e("TCPIPCommunicator: ", "Client: Failed to send", e);
e.printStackTrace();
}
}
The function ConvertString is a native function that converts the Java string to a C/C++ string and returns it as Java bytes, it is defined as followed:
JNIEXPORT jbyteArray JNICALL Java_com_example_communicationmoduleTCPIP_communicationmoduleTCPIP_ConvertString(
JNIEnv * env, jobject,
jstring Buffer)
{
// Array to fill with data
jbyteArray Array;
// Init java byte array
Array = env->NewByteArray(10);
const char* NewBuffer = env->GetStringUTFChars(Buffer, 0);
// Set byte array region with the size of the SendData CommStruct.
// Now we can send the data back.
env->SetByteArrayRegion(Array, 0, 10, (jbyte*)NewBuffer);
env->ReleaseStringUTFChars(Buffer, NewBuffer);
// Return java array
return Array;
}
}
When i run the program i get two 'AAAA' on the c side but not as a whole array ( so no 'AAAAAAAADD). I think the problem is that the server sends 2 'AAAA' and not the whole array at once. The client crashes with the following error:
'boost::exception_detail::clone_impl >'
what(): read: End of file
Does the java server sends the data wrong? can anyone give me a suggestion? all feedback is welcome!
Are you willing to send the data or to make the JNI stuff work?
In the former case, use Java to convert a string into UTF-8 (which will be ASCII for English.)
Conversion of text byte[] -> byte[] is not exactly what you need, but you'll get the idea:
//byte[] result;
//byte[] source;
String s = new String(source,"UTF-8");
result = s.getBytes("UTF-16LE");
For the 2nd case, I can share a portion of working code; it calls Java to convert from one encoding to another
// it returns NULL in the case of an exception
// the returned memory is calloc()'d; it's the caller's responsibility to free() it.
char* changeEncoding(const char*source, int len, int direction)
{
JNIEnv* env = threadUnsafeInfo.env;
jobject obj = threadUnsafeInfo.obj;
if (!source) {
JNU_ThrowByName(env, "java/lang/NullPointerException", 0);
return NULL;
}
jbyteArray srcArray = env->NewByteArray(len);
jclass cls = env->FindClass("com/xyz/MyClass");
jmethodID mid = env->GetMethodID(cls, "convert", "([BI)[B");
if (mid != NULL && srcArray != NULL) {
env->SetByteArrayRegion(srcArray, 0, len, (jbyte*)source);
env->ExceptionClear();
//jbyteArray resArray = (jbyteArray)env->CallStaticObjectMethod(cls, mid, srcArray, direction);
jbyteArray resArray = (jbyteArray)env->CallObjectMethod(obj, mid, srcArray, direction);
if(env->ExceptionOccurred()) {
DLOG("exception in convert ([BI)[B");
env->ExceptionDescribe();
//env->ExceptionClear(); // ??
return NULL;
}
int resultLen = env->GetArrayLength(resArray);
char* result = (char*)calloc(2 + resultLen,1); // why 2: a bit of healthy paranoia ain't gonna hurt anyone
if (result == 0) {
JNU_ThrowByName(env, "java/lang/OutOfMemoryError", 0);
return NULL;
}
env->GetByteArrayRegion(resArray, 0, resultLen, (jbyte *)result);
env->DeleteLocalRef(cls);
env->DeleteLocalRef(resArray);
env->DeleteLocalRef(srcArray);
return result;
} else {
JNU_ThrowByName(env, "java/lang/NullPointerException", 0);
myassert(("method id = 0",0));
}
return NULL;
}
In the code that I have at hand
I did not use jstrings, preferring the byte arrays.
I have a Java method that process a bitmap and returns a String.
When I call this method from JNI (VS 2010) it works, but if I call this method many times,
the memory of the process grown up until crash.
The instruction that use a lot of memory is:
jbyteArray jBuff = _env->NewByteArray(b->Length);
My code:
static jobject staticArray=0;
System::String^ MyClass::ExecuteJavaMethod(System::Drawing::Bitmap^ bmp)
{
JNIEnv *_env;
System::String^ out;
unsigned const char * buff;
int res = jvm->AttachCurrentThread((void **)&_env, NULL);
if (jvm->GetEnv((void**) &_env, JNI_VERSION_1_6) != JNI_OK)
{
return "GetEnv ERROR";
}
//save the bitmap in the stream
MemoryStream^ ms = gcnew MemoryStream();
bmp->Save(ms, ImageFormat::Bmp);
//get the bitmap buffer
array<unsigned char>^b = ms->GetBuffer() ;
//unmanaged conversion
buff = GetUnmanaged(b,b->Length);
//fill the buffer
jbyteArray jBuff = _env->NewByteArray(b->Length);
_env->SetByteArrayRegion(jBuff, 0, b->Length, (jbyte*) buff);
//call the java method
jstring str = (jstring) _env->CallStaticObjectMethod ( Main,
javaMethod,
jBuff);
// _env->ReleaseByteArrayElements(jBuff,(jbyte*)buff), 0); //NOT WORKING
//staticArray= _env->NewGlobalRef(jBuff); NOT
//_env->DeleteLocalRef(jBuff); WORKING
//return the string result of the java method
return gcnew String(env->GetStringUTFChars(str, 0));
}
the answer is: _env->DeleteLocalRef(jBuff);
You didn't call DetachCurrentThread() for each AttachCurrentThread(), which is requested in Java Native Interface Specification. That makes the local references (jBuff and str) unable to be freed automatically. Also, the const char* fetched through GetStringUTFChars() needs to be released.
The correct way is change
return gcnew String(env->GetStringUTFChars(str, 0));
into
const char* cstr = env->GetStringUTFChars(str, 0);
System::String^ retstr = gcnew String(cstr);
env->ReleaseStringUTFChars(str, cstr);
jvm->DetachCurrentThread();
return retstr;
I want to send Hangul (Korean symbols using UTF) text from C to JAVA.
But JAVA gets incorrect results
Example:
JNIEXPORT jstring JNICALL Java_get_1term
(JNIEnv *env, jobject, jint termInd)
{
const char *str = "음뮤원음직음원샘";
return (env)->NewStringUTF(str);
}
but in that case JAVA got incorrect string.
I couldn't find answer to my question in other posts, if there is same question please give me link to them
try with this (taken and adapted from here):
jstring WindowsToJstring(JNIEnv* pEnv, char* cstr) {
jstring retJstring = NULL;
int slen = strlen(cstr);
int length = MultiByteToWideChar( CP_ACP, 0, (LPCSTR)cstr, slen, NULL, 0 );
unsigned short* tempbuffer = (unsigned short *)malloc( length*2 + 1 );
MultiByteToWideChar( CP_ACP, 0, (LPCSTR)cstr, slen, (LPWSTR)tempbuffer, length );
retJstring = (pEnv)->NewString((jchar*)tempbuffer, length );
free( tempbuffer );
return retJstring;
}
EDIT As correctly noted by #Kerrek SB this is a Windows only solution