Calling java method contain string as argument and string as return type from c++ in ndk in android - android-ndk

I have one following methods in java:
public native String jniStringMethod();
public String stringMethod(String s) {
Log.d("Testing", "String:" + s);
return s;
}
I am trying to call "stringMethod" method in jniStringMethod() in cpp file in the following way:
jstring Java_ashok_learning_ndk_SampleNDKActivity_jniStringMethod(JNIEnv *env,
jobject obj) {
jstring jstr = env->NewStringUTF("This comes from jni string .");
//jclass clazz = env->GetObjectClass(obj);
jclass clazz = env->FindClass("ashok/learning/ndk/SampleNDKActivity");
if (0 == clazz) {
LOG("clazz class not found!");
}
jmethodID messageMe = env->GetMethodID(clazz, "stringMethod", "(Ljava/lang/String;)Ljava/lang/String;");
if (0 == messageMe) {
LOG("messageMe method not found!");
}
jobject result = env->CallObjectMethod(obj, messageMe, jstr);
LOG("result: %d", result);
const char* str = env->GetStringUTFChars((jstring)result, NULL); // should be released but what a heck, it's a tutorial :)
printf("%s\n", str);
return env->NewStringUTF(str);
}
But it is not getting called..and i am getting log as "messageMe method not found!",means method is not matching with signature...any one can suggest about my mistakes?

Your signture is OK. Are you sure your code is not executed properly even though messageMe is NULL? It has happend to me that my code was running fine despite jmethodID being NULL.

Related

Is there a way to list arguments to a method as a collection?

If I have a method such as this:
void someMethod(int one, int two, int three)
{
log.debug("One = ${one}, two = ${two}, three = ${three}")
}
Is there a way to avoid listing each param in the debit message? I want to print out values for all the parameters without necessarily listing each one separately.
You can just use varargs:
void someMethod( int... args ) {
println "Args = $args"
}
Worried about more than 3 arguments getting used while calling method? Then make sure you only deal with args[0] till args[2] inside the method.
You may also use interceptor construct:
class Sample {
void someMethod(int one, int two, int three) {
// println("One = ${one}, two = ${two}, three = ${three}")
}
}
class SampleInterceptor implements Interceptor {
boolean doInvoke() {
true
}
Object beforeInvoke(Object obj, String name, Object[] args) {
if(name == "someMethod")
println args
}
Object afterInvoke(Object obj, String name, Object[] args, Object result) {
result
}
}
def proxy = ProxyMetaClass.getInstance(Sample)
def interceptor = new SampleInterceptor()
proxy.interceptor = interceptor
proxy.use {
def h = new Sample()
h.someMethod(1,2,3)
}
Have a look at the sample.

haxe "should be int" error

Haxe seems to assume that certain things must be Int. In the following function,
class Main {
static function main() {
function mult_s<T,A>(s:T,x:A):A { return cast s*x; }
var bb = mult_s(1.1,2.2);
}
}
I got (with Haxe 3.01):
Main.hx:xx: characters 48-49 : mult_s.T should be Int
Main.hx:xx: characters 50-51 : mult_s.A should be Int
Can anyone please explain why T and A should be Int instead of Float?
A more puzzling example is this:
class Main {
public static function min<T:(Int,Float)>(t:T, t2:T):T { return t < t2 ? t : t2; }
static function main() {
var a = min(1.1,2.2); //compile error
var b = min(1,2); //ok
}
}
I can't see why t<t2 implies that either t or t2 is Int. But Haxe seems prefer Int: min is fine if called with Int's but fails if called with Float's. Is this reasonable?
Thanks,
min<T:(Int,Float)> means T should be both Int and Float. See the constraints section of Haxe Manual.
Given Int can be converted to Float implicitly, you can safely remove the constraint of Int. i.e. the following will works:
http://try.haxe.org/#420bC
class Test {
public static function min<T:Float>(t:T, t2:T):T { return t < t2 ? t : t2; }
static function main() {
var a = min(1.1,2.2); //ok
$type(a); //Float
trace(a); //1.1
var b = min(1,2); //ok
$type(b); //Int
trace(b); //1
}
}

Who owns returned string from _bstr_t::wchar_t*, _bstr_t::char* operators?

_bstr_t::wchar_t*, _bstr_t::char* operators return string of different types.
Do I need to delete or free them? using which function?
After stepping the implementation using debugger, my conclusion is that there is no need to manually delete/free the returned string. The lifetime of the returned string is managed by _bstr_t internally.
See the following snippets from the implementation:
// Extract a const char_t*
//
inline _bstr_t::operator const char*() const throw(_com_error)
{
return (m_Data != NULL) ? m_Data->GetString() : NULL;
}
inline const char* _bstr_t::Data_t::GetString() const throw(_com_error)
{
if (m_str == NULL) {
m_str = _com_util::ConvertBSTRToString(m_wstr);
if (m_str == NULL && m_wstr != NULL) {
_com_issue_error(E_OUTOFMEMORY);
}
}
return m_str;
}
inline void _bstr_t::Data_t::_Free() throw()
{
if (m_wstr != NULL) {
::SysFreeString(m_wstr);
}
if (m_str != NULL) {
delete [] m_str;
}
}
It is also okay to use unnamed _bstr_t as follows because _bstr_t instance is destroyed after the constructor of CString has finished.
CString abc((LPCTSTR)_bstr_t(OLESTR("ABC")));
AfxMessageBox(abc);

Casting on run time using implicit con version

I have the following code which copies property values from one object to another objects by matching their property names:
public static void CopyProperties(object source, object target,bool caseSenstive=true)
{
PropertyInfo[] targetProperties = target.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
PropertyInfo[] sourceProperties = source.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo tp in targetProperties)
{
var sourceProperty = sourceProperties.FirstOrDefault(p => p.Name == tp.Name);
if (sourceProperty == null && !caseSenstive)
{
sourceProperty = sourceProperties.FirstOrDefault(p => p.Name.ToUpper() == tp.Name.ToUpper());
}
// If source doesn't have this property, go for next one.
if(sourceProperty ==null)
{
continue;
}
// If target property is not writable then we can not set it;
// If source property is not readable then cannot check it's value
if (!tp.CanWrite || !sourceProperty.CanRead)
{
continue;
}
MethodInfo mget = sourceProperty.GetGetMethod(false);
MethodInfo mset = tp.GetSetMethod(false);
// Get and set methods have to be public
if (mget == null)
{
continue;
}
if (mset == null)
{
continue;
}
var sourcevalue = sourceProperty.GetValue(source, null);
tp.SetValue(target, sourcevalue, null);
}
}
This is working well when the type of properties on target and source are the same. But when there is a need for casting, the code doesn't work.
For example, I have the following object:
class MyDateTime
{
public static implicit operator DateTime?(MyDateTime myDateTime)
{
return myDateTime.DateTime;
}
public static implicit operator DateTime(MyDateTime myDateTime)
{
if (myDateTime.DateTime.HasValue)
{
return myDateTime.DateTime.Value;
}
else
{
return System.DateTime.MinValue;
}
}
public static implicit operator MyDateTime(DateTime? dateTime)
{
return FromDateTime(dateTime);
}
public static implicit operator MyDateTime(DateTime dateTime)
{
return FromDateTime(dateTime);
}
}
If I do the following, the implicit cast is called and everything works well:
MyDateTime x= DateTime.Now;
But when I have a two objects that one of them has a DateTime and the other has MyDateTime, and I am using the above code to copy properties from one object to other, it doesn't and generate an error saying that DateTime can not converted to MyTimeDate.
How can I fix this problem?
One ghastly approach which should work is to mix dynamic and reflection:
private static T ConvertValue<T>(dynamic value)
{
return value; // This will perform conversion automatically
}
Then:
var sourceValue = sourceProperty.GetValue(source, null);
if (sourceProperty.PropertyType != tp.PropertyType)
{
var method = typeof(PropertyCopier).GetMethod("ConvertValue",
BindingFlags.Static | BindingFlags.NonPublic);
method = method.MakeGenericMethod(new[] { tp.PropertyType };
sourceValue = method.Invoke(null, new[] { sourceValue });
}
tp.SetValue(target, sourceValue, null);
We need to use reflection to invoke the generic method with the right type argument, but dynamic typing will use the right conversion operator for you.
Oh, and one final request: please don't include my name anywhere near this code, whether it's in comments, commit logs. Aargh.

Can a Thread use a value of a global variable?

i´m creating a thread that takes as parameter dispatchInputs which is an CString array
but in mean while i need to use "env" in DispFrontEnd function, can a thread use the global variable "env" ? if not how how can i pass it as argument to DispFrontEnd ?
static JNIEnv *env;
static JavaVM *jvm;
JNIEnv* startJVM()
{
JNIEnv *env;
JavaVM * jvm;
env = create_vm(&jvm);
if ( env == NULL) { logloc->LogDebug("1env == NULL ******************");}
return env;
}
env = startJVM();
hDispThread = (HANDLE)_beginthread(DispFrontEnd,0,(void *)dispatchInputs);
static void DispFrontEnd(void * indArr)
{
CString str;
CString dest[56];
char* orig_idx_ptr = reinterpret_cast(indArr);
int array_size = 56;
memcpy(dest, orig_idx_ptr, array_size);
str.Format("DISPATCH INPUTS: (Trace Detail)[%s] (Session State ID)[%s] (SessionID)[%s] (MediaTypeID)[%s] (MediaCode)[%s] (5)[%s] (6)[%s] (7)[%s] (8)[%s] (9)[%s] (10)[%s] (11)[%s] (12)[%s] (13)[%s] " , dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7], dest[8], dest[9], dest[10], dest[11], dest[12], dest[13]);
logloc->LogMethod(str );
if (env != NULL)
{
jclass clsR = NULL;
jclass arqClass = NULL;
jclass messageToHostClass = NULL;
jobject jobjRetData = NULL;
jobjectArray jobjWOArr = NULL;
jobjectArray getResponseArray = NULL;
jmethodID getResponse = NULL;
jmethodID getMessageToHost = NULL;
arqClass = env->FindClass("BizB/Arq");
}
Tks
Rev
yes a thread can use the value of a global variable!
See Is it ok to save JavaVM * and JNIEnv * as a global variable and use it elsewhere?
The JNIEnv "represents a context for a specific JNI method invocation. It is dependent on the current thread, the arguments to the current method, the local references that have been created by the current method, all sorts of things, and it becomes invalid once that JNI method returns."
Also this answer: How to create static JNI Environment Pointer?
"It's generally unsafe to cache a JNIEnv* instance and keep using it"

Resources