How to pass utf8 strings from jni to java?

4,042 views
Skip to first unread message

dmitry

unread,
Sep 15, 2010, 6:47:02 AM9/15/10
to android-ndk
I am porting application to android , which makes huge string
processing. I want to leave it in C++, how do I pass resulting strings
to Java to show em on screen?

Thanks in advance.

mic _

unread,
Sep 15, 2010, 7:02:14 AM9/15/10
to andro...@googlegroups.com
Use NewStringUTF to create a jstring that you can return back to java. See http://java.sun.com/docs/books/jni/html/objtypes.html#4013

/Michael



--
You received this message because you are subscribed to the Google Groups "android-ndk" group.
To post to this group, send email to andro...@googlegroups.com.
To unsubscribe from this group, send email to android-ndk...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/android-ndk?hl=en.


dmitry chernov

unread,
Sep 15, 2010, 8:41:26 AM9/15/10
to andro...@googlegroups.com
When I am trying exmaple from part 8.2 Writing Internationalized Code here http://java.sun.com/docs/books/jni/html/other.html#26018 I get errors : Class_java_lang_String undeclared, MID_String_init undeclared. If these are not declared in <jni.h> than where are they?

Thanks for the reply

dmitry chernov

unread,
Sep 15, 2010, 10:10:27 AM9/15/10
to andro...@googlegroups.com


On Wed, Sep 15, 2010 at 6:09 PM, dmitry chernov <diman4ik...@gmail.com> wrote:
Finally I found out how to construct java string from char. But still can't see proper value in eclipse debuger. (it shows squares instead). When I use English string everything is ok.

jstring 
Java_com_example_hellojni_HelloJni_stringNative(JNIEnv *env, jobject obj)
{
const char *str = "я строка";
//const char *str = "I am string";

jstring result;
jbyteArray bytes = 0;
int len;
if ((*env)->EnsureLocalCapacity(env, 2) < 0) {
return NULL; /* out of memory error */
}
len = strlen(str);
bytes = (*env)->NewByteArray(env, len);

if (bytes != NULL) { 
jclass string_class;
string_class = (*env)->FindClass(env,"java/lang/String");
(*env)->SetByteArrayRegion(env, bytes, 0, len,
(jbyte *)str);
jmethodID stringConstructor = (*env)->GetMethodID(env, string_class, "<init>", "([B)V" );

if( stringConstructor != NULL )
result = (*env)->NewObject(env, string_class, stringConstructor, bytes);
(*env)->DeleteLocalRef(env, bytes);
return result;
} /* else fall through */
return NULL;

dmitry chernov

unread,
Sep 15, 2010, 10:09:42 AM9/15/10
to andro...@googlegroups.com
Finally I found out how to construct java string from char. But still can't see proper value in eclipse debuger. (it shows squares instead). When I use English string everything is ok.

jstring 
Java_com_example_hellojni_HelloJni_stringNative(JNIEnv *env, jobject obj)
{
const char *str = "я строка";
const char *str = "I am string";

jstring result;
jbyteArray bytes = 0;
int len;
if ((*env)->EnsureLocalCapacity(env, 2) < 0) {
return NULL; /* out of memory error */
}
len = strlen(str);
bytes = (*env)->NewByteArray(env, len);

if (bytes != NULL) { 
jclass string_class;
string_class = (*env)->FindClass(env,"java/lang/String");
(*env)->SetByteArrayRegion(env, bytes, 0, len,
(jbyte *)str);
jmethodID stringConstructor = (*env)->GetMethodID(env, string_class, "<init>", "([B)V" );

if( stringConstructor != NULL )
result = (*env)->NewObject(env, string_class, stringConstructor, bytes);
(*env)->DeleteLocalRef(env, bytes);
return result;
} /* else fall through */
return NULL;
}


On Wed, Sep 15, 2010 at 4:41 PM, dmitry chernov <diman4ik...@gmail.com> wrote:

dmitry chernov

unread,
Sep 15, 2010, 10:52:06 AM9/15/10
to andro...@googlegroups.com
Finally it came to this variant :

jstring 
Java_com_example_hellojni_HelloJni_stringNative(JNIEnv *env, jobject obj)
{
const char *str = "я строка";
        //const char *str = "I am string";
jstring result;
jbyteArray bytes = 0;
int len;
if ((*env)->EnsureLocalCapacity(env, 2) < 0) {
return NULL; /* out of memory error */
}
len = strlen(str);
bytes = (*env)->NewByteArray(env, len);

if (bytes != NULL) { 
jclass string_class;
string_class = (*env)->FindClass(env,"java/lang/String");
(*env)->SetByteArrayRegion(env, bytes, 0, len,
(jbyte *)str);
jmethodID stringConstructor = (*env)->GetMethodID(env, string_class, "<init>", "([BLjava/lang/String;)V" );

if( stringConstructor != NULL )
result = (*env)->NewObject(env, string_class, stringConstructor, bytes, "ru_RU" );
(*env)->DeleteLocalRef(env, bytes);
return result;
} /* else fall through */
return NULL;
}

But this time Dalvik VM crashes on NewObjecy call. What is it? No error messages in log. It simply writes that Dalvik VM is aborting.

On Wed, Sep 15, 2010 at 6:09 PM, dmitry chernov <diman4ik...@gmail.com> wrote:
Finally I found out how to construct java string from char. But still can't see proper value in eclipse debuger. (it shows squares instead). When I use English string everything is ok.

jstring 
Java_com_example_hellojni_HelloJni_stringNative(JNIEnv *env, jobject obj)
{
const char *str = "я строка";
//const char *str = "I am string";

Tim Mensch

unread,
Sep 15, 2010, 11:42:14 AM9/15/10
to andro...@googlegroups.com
The earlier reply from Michael should have worked. It works for me. NewStringUTF() should create a string from UTF-8 characters.

To make it work, though, you need to be sure your C++ source is UTF-8 encoded. In Eclipse, you can look under Edit/Set Encoding. Similarly if the entire project is set to be UTF-8, AND your debugger is using a font that includes the appropriate Unicode pages, then the debugger SHOULD work, but I haven't verified that.

In general I've found that the best way to handle non-ASCII is to put UTF-8 strings in an external file and use a translation layer. It's easier to ensure that one file is properly UTF-8 encoded, and then when it comes time to produce a new translation, there's only one file that needs to be updated.

Tim

fadden

unread,
Sep 15, 2010, 4:13:59 PM9/15/10
to android-ndk
On Sep 15, 7:52 am, dmitry chernov <diman4ik.cher...@gmail.com> wrote:
> Finally it came to this variant :
>
> jstring
> Java_com_example_hellojni_HelloJni_stringNative(JNIEnv *env, jobject obj)
> {
> const char *str = "я строка";

This is doing it the hard way.

If the input string is UTF-8, you can use NewStringUTF. If it's some
other encoding format (e.g. iso-latin1), NewStringUTF won't know what
to do with it. Can you print the binary representation of "str"?
e.g.:

int main() {
const char* str = "я строка";

while (*str != '\0') {
printf("%02x ", (unsigned char) *str++);
}
putchar('\n');

return 0;
}

The mail message you sent used UTF-8 encoding, so when I copied &
pasted the string out of it I got:

d1 8f 20 d1 81 d1 82 d1 80 d0 be d0 ba d0 b0

If yours comes out differently, you have a problem with your source
file encoding (see Tim Mensch's message).


> But this time Dalvik VM crashes on NewObjecy call. What is it? No error
> messages in log. It simply writes that Dalvik VM is aborting.

What appears in the log above the message that indicates the VM is
aborting? What does the failure message itself look like?

My guess is that passing the C constant "ru_RU" instead of a String
object is causing the failure. If CheckJNI is enabled, recent
versions of the VM will detect the bad object reference and abort
after reporting the problem. If it's not enabled, the VM will
probably crash with a segmentation fault when it tries to traverse the
non-existent object header.

Also, if you turn CheckJNI on, strings passed to NewStringUTF are
checked for UTF-8 validity.
Reply all
Reply to author
Forward
0 new messages