Java Native Interface: "Translate" java call to JNI, how to pass parameters, how to show exception  
Author Message
ckirchho





PostPosted: 2006-9-15 19:09:00 Top

java-programmer, Java Native Interface: "Translate" java call to JNI, how to pass parameters, how to show exception Hallo,

I am at least one step further, now I need to pass the properties to
the call and are now sure how:

Remember: The call I want to implement in Delphi is
java -Xmx256m -cp
"lib\fop\fop.jar;lib\fop\avalon-framework-4.1.3.jar;lib\fop\JimiProClasses.zip"
org.apache.fop.apps.Fop -fo "Data.xml" -c "lib\fop\Config.xml" -pdf
"Data.pdf"

So the parameters that have to be passed are:
-fo "Data.xml"
-c "lib\fop\Config.xml"
-pdf "Data.pdf"

If I do
JNIEnv.CallStaticVoidMethod(Cls, Mid, ['-fo "Data.xml" -c
"Config.xml"-pdf "Cover.pdf"']);
(all parameters in one string) or
JNIEnv.CallStaticVoidMethod(Cls, Mid, ['-fo "Data.xml"', '-c
"Config.xml"', '-pdf "Cover.pdf"']);
(each parameter in a separate string)

...then JNIEnv.ExceptionOccurred is not NULL after the call, thus some
exception occured.

The parameter Args in the call CallStaticVoidMethod() is an array of
const. In CallStaticVoidMethod() the array elements are converted to
JValues with ArgsToJValues().
The exemplary C++ code in the doc PDF works with an ObjectArray created
with NewObjectArray(). I tried that, but CallStaticVoidMethod() won't
accept an ObjectArray, nor would the similar procedures
CallStaticVoidMethodA() or CallStaticVoidMethodV().

By the way: My Delphi app runs in a window, its not a console
application. Can I get the description of the exception with any other
function, or how would I have to use ExceptionDescribe() in this
context?

Regards,

Christian Kirchhoff

 
Gordon Beaton





PostPosted: 2006-9-15 19:43:00 Top

java-programmer >> Java Native Interface: "Translate" java call to JNI, how to pass parameters, how to show exception On 15 Sep 2006 04:09:03 -0700, email***@***.com wrote:
> The parameter Args in the call CallStaticVoidMethod() is an array of
> const. In CallStaticVoidMethod() the array elements are converted to
> JValues with ArgsToJValues().
> The exemplary C++ code in the doc PDF works with an ObjectArray created
> with NewObjectArray(). I tried that, but CallStaticVoidMethod() won't
> accept an ObjectArray, nor would the similar procedures
> CallStaticVoidMethodA() or CallStaticVoidMethodV().

Keep in mind that even though you pass several "program arguments" to
the JVM, the method you are invoking takes only one argument, an array
of String. When you run this from a command shell, the launcher
collects the arguments into a single array of String.

So with CallStaticVoidMethod() you need to create an array of String
objects, i.e. one String per program argument, and pass that to the
method. Note that this is *not* the same as a Delphi array of pointers
to the Delphi string type, you need to create actual Java String
objects and a Java String array. I showed you how to do that in my
earlier code example.

I don't know what the conversion ArgsToJValues does, so I can't help
you there.

If you want to use CallStaticVoidMethodA() instead, then you would
still need to create the Strings and the String array, but you would
additionally need an array of jvalue, whose element 0 is a reference
to the String array. There is little point in using that function in
this case.

Finally I doubt that CallStaticVoidV() is what you want (and I doubt
that you can even create the necessary va_list in Delphi).

Since this is a common thing to do, I'm sure you should be able to
find Delphi examples somewhere that show you how to do this.

> By the way: My Delphi app runs in a window, its not a console
> application. Can I get the description of the exception with any
> other function, or how would I have to use ExceptionDescribe() in
> this context?

AFAIK there is only ExceptionDescribe().

/gordon

--
[ don't email me support questions or followups ]
g o r d o n + n e w s @ b a l d e r 1 3 . s e
 
ckirchho





PostPosted: 2006-9-15 22:30:00 Top

java-programmer >> Java Native Interface: "Translate" java call to JNI, how to pass parameters, how to show exception Hallo,

> So with CallStaticVoidMethod() you need to create an array of String
> objects, i.e. one String per program argument, and pass that to the
> method. Note that this is *not* the same as a Delphi array of pointers
> to the Delphi string type, you need to create actual Java String
> objects and a Java String array. I showed you how to do that in my
> earlier code example.

Unfortunately not. Here is the definition of the procedure in Delphi:
procedure CallStaticVoidMethod(AClass: JClass; MethodID: JMethodID;
const Args: array of const);

Args is an "array of const". I tried creating the Object array with
NewObjectArray, adding additional ObjectArrayElements, and pass that as
Args to CallStaticVoidMethod, but the compiler errored "Incompatible
Types 'Array' and 'JObject'"

I have to use an array of const, but in the way I described earlier it
doesn't seem to work.

Regards,

Christian

 
 
Gordon Beaton





PostPosted: 2006-9-15 22:51:00 Top

java-programmer >> Java Native Interface: "Translate" java call to JNI, how to pass parameters, how to show exception On 15 Sep 2006 07:29:58 -0700, email***@***.com wrote:
> Args is an "array of const".

I haven't got a clue what "array of const" is.

> I tried creating the Object array with NewObjectArray, adding
> additional ObjectArrayElements, and pass that as Args to
> CallStaticVoidMethod, but the compiler errored "Incompatible Types
> 'Array' and 'JObject'"

But Array should be assignable to JObject. The corresponding types in
Java and JNI are compatible (Arrays are Objects), so perhaps you need
to use an explicit cast, or you need to assign the result of the array
creation to a JObject instead of an Array and pass that. Other than
that, I'm out of ideas.

/gordon

--
[ don't email me support questions or followups ]
g o r d o n + n e w s @ b a l d e r 1 3 . s e
 
 
ckirchho





PostPosted: 2006-9-15 22:55:00 Top

java-programmer >> Java Native Interface: "Translate" java call to JNI, how to pass parameters, how to show exception P.S.: Here is the code for the preocedure CallStaticVoidMethod in
Delphi:

procedure TJNIEnv.CallStaticVoidMethod(AClass: JClass; MethodID:
JMethodID; const Args: array of const);
begin
Env^.CallStaticVoidMethodA(Env, AClass, MethodID,
ArgsToJValues(Args));
end;

ArgsToJValues returns a PJValue, by the way.

My problem seems to be which syntax I have to use for the parameters.
JNIEnv.CallStaticVoidMethod(Cls, Mid, ['-fo "Data.xml"', '-c
"Config.xml"', '-pdf Cover.pdf"']);
seems to be wrong

JNIEnv.CallStaticVoidMethod(Cls, Mid, ['fo="Data.xml"',
'c="Config.xml"', 'pdf="Cover.pdf"']);
is wrong, too.

JNIEnv.CallStaticVoidMethod(Cls, Mid, ['fo=Data.xml', 'c=Config.xml',
'pdf=Cover.pdf']);
is wrong, too.

But then again, in my actual code I use full path names, and maybe here
I have to use another syntax. But I tried it with slashes instead of
backslashes, too, and it doesn't work...

Christian

 
 
ckirchho





PostPosted: 2006-9-15 23:48:00 Top

java-programmer >> Java Native Interface: "Translate" java call to JNI, how to pass parameters, how to show exception I managed to change the code and use CallStaticVoidMethodA in a way
that the compiler doesn't throw an error.
Args := JNIEnv.NewObjectArray(3, StrClass, JStr1);
JNIEnv.SetObjectArrayElement(Args, 2, JStr2);
JNIEnv.SetObjectArrayElement(Args, 3, JStr3);
JNIEnv.CallStaticVoidMethodA(Cls, Mid, @Args);

@Args means that the pointer to Args is passed as the paranmeter. But
when I run this code, the programmcloses itself without an error or
exception, which is even worse than before.

So I went back to CallStaticVoidMethod(). I found a way to show the
error, at least as a number:
AException := JNIEnv.ExceptionOccurred;
if AException <> nil then
ShowMessage(Format('CheckJava: %d', [DWORD(AException)]));

I tried to make the call in two ways:
Pass all parameters in one string:
JNIEnv.CallStaticVoidMethod(Cls, Mid, ['-fo "Data.xml" -c "Config.xml"
-pdf Cover.pdf"']);
ErrorCode 180098752

Pass the parameters in separate strings:
JNIEnv.CallStaticVoidMethod(Cls, Mid, ['-fo "Data.xml"', '-c
"Config.xml"', '-pdf Cover.pdf"']);
ErrorCode 180098744

Just a test: Pass an empty string
JNIEnv.CallStaticVoidMethod(Cls, Mid, ['']);
ErrorCode 180098756

I believe that it's just the way the parameter string is set up that is
wrong. The syntax seems to be different than starting java from a batch
file.

Like with the problem I had before where just the quotes were wrong and
had to be deleted.

Does anybody by any chance now what those error codes mean?

By the way: Is there any way to get the messages that a java method
prints (e.g. in a DOS Box when the script is started from within a DOS
Box) when the method is called from within Delphi?

I will be on vacation til Oct 3rd, and hopefully I will find a solution
afterwards.

Best Regards,

Christian.

Gordon Beaton wrote:
> On 15 Sep 2006 07:29:58 -0700, email***@***.com wrote:
> > Args is an "array of const".
>
> I haven't got a clue what "array of const" is.
>
> > I tried creating the Object array with NewObjectArray, adding
> > additional ObjectArrayElements, and pass that as Args to
> > CallStaticVoidMethod, but the compiler errored "Incompatible Types
> > 'Array' and 'JObject'"
>
> But Array should be assignable to JObject. The corresponding types in
> Java and JNI are compatible (Arrays are Objects), so perhaps you need
> to use an explicit cast, or you need to assign the result of the array
> creation to a JObject instead of an Array and pass that. Other than
> that, I'm out of ideas.
>
> /gordon
>
> --
> [ don't email me support questions or followups ]
> g o r d o n + n e w s @ b a l d e r 1 3 . s e

 
 
Chris Uppal





PostPosted: 2006-9-16 0:23:00 Top

java-programmer >> Java Native Interface: "Translate" java call to JNI, how to pass parameters, how to show exception email***@***.com wrote:

> Args is an "array of const". I tried creating the Object array with
> NewObjectArray, adding additional ObjectArrayElements, and pass that as
> Args to CallStaticVoidMethod, but the compiler errored "Incompatible
> Types 'Array' and 'JObject'"

Can you clarify exactly which of the three forms of CallStaticVoidMethod() you
are using ? There are three of them:

CallStaticVoidMethod()
CallStaticVoidMethodA()
CallStaticVoidMethodV()

Also, can we be clear that you are attempting to provide /one/ Java object as
the single parameter to the Java method you want to call ? That object is an
Java array (created with NewObjectArray()) but it is a single object.

If you were working in C, then once you have created and populated that single
Java object, there would then be three different ways you could invoke the
method.

Using CallStaticVoidMethod()
In this case you pass the jobject as one parameter to the call (in
addition to the class and method ID). You should be wary of using
this form from Delphi; unless Delphi understands 'C' variadic functions
(functions which take variable numbers of arguments like C's printf()).
I doubt whether it does, at least on the basis that 'C'-style variadic
functions are incompatible with both the semantics and typical
implementations of Pascal. It is possible that Borland have extended
that so that Delphi can work with 'C's variadic functions, but you should
check. Note that the ability to work with variadic functions at all
doesn't necessarily imply the ability to work with the specific
stack layout used by a MSVC variadic __stdcall function (I vaguely
seem to remember that Borland's C++Builder didn't use the same
layouts but that's a very long time ago...)

Using CallStaticVoidMethodA()
In this case you pass a /C/ array as the parameter to the call. That
array holds each of the parameters which should be passed to the
Java method. So in this case that array should contain one element
which itself is a Java array containing your parameter strings.

Using CallStaticVoidMethodV()
If you are working in C and know what you are doing then this can
be useful. In other circumstances -- such as seem to apply here -- you
should just ignore it.

BTW: going back to an earlier post of yours. You said that you were setting a
classpath like:
-Djava.class.path=C:\subfolder1\subfolder2\HWJava.class
If that's still true, and if 'HWJava.class' is not the (very strange) name of a
directory, then your application is only working by the most bizarre of
accidents -- there should never be any .class files explicitly mentioned on the
classpath. Just directories and JAR files (re-read Gordon's earlier post if
that's not clear).

-- chris


 
 
ckirchho





PostPosted: 2006-10-10 0:52:00 Top

java-programmer >> Java Native Interface: "Translate" java call to JNI, how to pass parameters, how to show exception Hallo Chris,

sorry for the late answer, I was on vacation for a couple of weeks.
Here are some answers to your questions/comments:

Chris Uppal wrote:
> email***@***.com wrote:
>
> > Args is an "array of const". I tried creating the Object array with
> > NewObjectArray, adding additional ObjectArrayElements, and pass that as
> > Args to CallStaticVoidMethod, but the compiler errored "Incompatible
> > Types 'Array' and 'JObject'"
>
> Can you clarify exactly which of the three forms of CallStaticVoidMethod() you
> are using ? There are three of them:
>
> CallStaticVoidMethod()
> CallStaticVoidMethodA()
> CallStaticVoidMethodV()

Right now I concentrate on CallStaticVoidMethod()

>
> Also, can we be clear that you are attempting to provide /one/ Java object as
> the single parameter to the Java method you want to call ? That object is an
> Java array (created with NewObjectArray()) but it is a single object.
>

Well, as I wrote before CallStaticVoidMethod is defined with an array
of const as the parameter. It is a Delphi type. So I have to deal with
that
CallStaticVoidMethodA() works with a PJValue, which is defined in unit
JNI.
CallStaticVoidMethodV() works with a type called va_list, which is
Delphi again.
Yes, in any case it is one single object, that is passed

> If you were working in C, then once you have created and populated that single
> Java object, there would then be three different ways you could invoke the
> method.
>
> Using CallStaticVoidMethod()
> In this case you pass the jobject as one parameter to the call (in
> addition to the class and method ID). You should be wary of using
> this form from Delphi; unless Delphi understands 'C' variadic functions
> (functions which take variable numbers of arguments like C's printf()).
> I doubt whether it does, at least on the basis that 'C'-style variadic
> functions are incompatible with both the semantics and typical
> implementations of Pascal. It is possible that Borland have extended
> that so that Delphi can work with 'C's variadic functions, but you should
> check. Note that the ability to work with variadic functions at all
> doesn't necessarily imply the ability to work with the specific
> stack layout used by a MSVC variadic __stdcall function (I vaguely
> seem to remember that Borland's C++Builder didn't use the same
> layouts but that's a very long time ago...)
>
> Using CallStaticVoidMethodA()
> In this case you pass a /C/ array as the parameter to the call. That
> array holds each of the parameters which should be passed to the
> Java method. So in this case that array should contain one element
> which itself is a Java array containing your parameter strings.
>
> Using CallStaticVoidMethodV()
> If you are working in C and know what you are doing then this can
> be useful. In other circumstances -- such as seem to apply here -- you
> should just ignore it.
>
> BTW: going back to an earlier post of yours. You said that you were setting a
> classpath like:
> -Djava.class.path=C:\subfolder1\subfolder2\HWJava.class
> If that's still true, and if 'HWJava.class' is not the (very strange) name of a
> directory, then your application is only working by the most bizarre of
> accidents -- there should never be any .class files explicitly mentioned on the
> classpath. Just directories and JAR files (re-read Gordon's earlier post if
> that's not clear).

That was for testing reasons and I corrected that later. My actual
project sets the classpath to folder, JAR files and ZIP files.

I'll try to find out if I get CallStaticVoidMethod(),
CallStaticVoidMethodA() or CallStaticVoidMethodV() to work anyhow...

Rgeards,

Christian