Hi Rony,
On 01/07/2017 03:53 PM, Rony G. Flatscher wrote:
Hi Peter,
thank you very much for your efforts!
However, in this context there is a problem at hand, that there is no
information available what Java method returned what object and what
cast was carried out, if any. To understand this, maybe I should give
a little bit more information about the Rexx-Java bridge: Rexx/ooRexx
(originally developed by IBM, now in opensource) is an interpreter for
a dynamically typed, caseless programming language with a rather easy
to learn syntax, yet powerful implemented concepts. ooRexx is
implemented in C++.
The Rexx-Java-bridge uses JNI and a Java package (for ooRexx
programmers it is an external function package called BSF4ooRexx,
which allows to camouflage all of Java as the dynamically typed,
caseless ooRexx). It is possible with this package to create Rexx
proxy objects for Java objects (and the other way around as well).
This is realized by storing proxied Java objects on the Java side in a
Map ("registry") and using a common (unique) string value as the key.
So when the Rexx side invokes a Java method, briefly the following
steps take place (there is much more to this, but not important in
this context):
* the Rexx side uses JNI and supplies the string identifying the
Java object in the Map, the method name in uppercase (caselessness
is realized in Rexx by uppercasing all Rexx tokens outside of
quotes) and the arguments, if any,
* the Java side fetches the Java object from the Java registry and
inspects it for its available methods, picks those that have
caselessly the same name as the supplied method name, then checks
whether the arguments are type-compatible and invokes the method;
any returned Java object will be placed in the Java "registry" and
its key (a unique string) is returned to Rexx.
Couldn't you save also the method's return type besides the result under
the same key into the registry, so next time you have to invoke a method
on such object, you retrive the object and the type you use to find
methods on?
So after returning control to Rexx, there is no information available
about the Java object in the Java registry other than the string
serving as the key to fetch that Java object on the Java side.
Not on the Rexx side, but on the Java side in the registry. Right where
you need it, right?
Take this Rexx code as an example (the tilde is the message operator
in ooRexx and can have white space around it):
clzToolkit = bsf.import("java.awt.Toolkit")
dim = clzToolkit ~getDefaultToolkit ~getScreenSize
will be transformed internally by Rexx into:
CLZTOOLKIT=BSF.IMPORT("java.awt.Toolkit")
DIM=CLZTOOLKIT~GETDEFAULTTOOLKIT~GETSCREENSIZE
and the Java bridge gets used (via JNI) as follows:
* step 1: BSF.IMPORT() is an external Rexx function that will use
JNI and cause a Java class object to be loaded (and stored in the
Java registry) and boxed as an ooRexx proxy class object upon
return and assigned to the Rexx variable CLZTOOLKIT,
This time the 'type' to search methods on is the same as the class
object you just "imported".
*
* step 2: the CLZTOOLKIT~GETDEFAULTTOOLKIT statement contains a Rexx
message that will cause JNI to be used and the Java method
GETDEFAULTTOOLKIT to be executed for the Java object referenced by
CLZTOOLKIT (which incorporates the unique string for that proxied
Java class object); the returned Java object will be stored in the
Java registry, its unique key (a string) returned, boxed as an
ooRexx proxy object value which will be the receiver of the next
Rexx message,
Right and if you also save the return type of the method you just called
into the registry besides the returned object on the Java side, you can
use it later...
*
* step 3: the returned value gets the GETSCREENSIZE Rexx message
sent to it causing JNI to be used and the Java method
GETSCREENSIZE to be located and executed for the Java object
returned from the previous step;
The method should then use the saved method return type from previous
step for looking up the GETSCREENSIZE method...
* the returned Java object will be stored in the Java registry, its
unique key (a string) returned, boxed as an ooRexx proxy object
value that gets assigned to the Rexx variable DIM.
You should then store the getScreenSize() method's return type besides
the returned object under the key... You see the pattern?
*
Each step gets carried out contextless, i.e. there is no Java context
available, that we (or the Java compiler) can see/infer when looking
at a Java program.
When you invoke them method you not only store the returned object but
also the method's return type.
If you need casting, then this would need to be explicit (like in Java).
There's one problem with this scheme. What is the key you use to
register returned object? Is it based on object identity? When methods
return the same instance, is it saved under the same key? If yes, which
is understandable, then there might be a problem when two methods with
different return types return the same instance. Which return type
should you use to find methods for following invocations then? Maybe the
most specific type (if they are related) or both (all) of them if they
are not and then use them all to search for methods.
Regards, Peter
---rony
P.S.: Also it might be interesting to know, that with that same
Rexx-Java bridge it is possible to implement Java methods from
interface or abstract classes in Rexx! In that case there is a Java
proxy class available for proxying Rexx objects and on the Rexx side
there is a Rexx Directory to maintain the proxied Rexx objects for
their Java proxies. Fun stuff! :)
On 06.01.2017 23:22, Peter Levart wrote:
Hi Rony,
On 01/06/2017 02:28 PM, Rony G. Flatscher wrote:
>The j.l.r.Method object on which you call invoke() should not be obtained by
inspecting the
>methods of the implementation class given by getDefaultToolkit().getClass().
Implementation
>classes (i.e. classes in non-exported packages) cannot be instantiated, nor
their members
>manipulated, by code outside their module.
>
>The j.l.r.Method object on which you call invoke() should be obtained by
inspecting the methods of
>the "public Java class" java.awt.Toolkit. The first argument that you pass to
invoke(), indicating
>the receiver, can still be instanceof the implementation class.
As was noted earlier, the information that some Java object xyz was created by
some public method
"getDefaultToolkit()" and hence knowing that its return type would be that of
the java.desktop
public class java.awt.Toolkit is not available at runtime.
But it is. The method Toolkit.getDefaultToolkit() has a return type.
You can use reflection to find out that return type of that method:
Method getDefKitMeth = Toolkit.class.getMethod("getDefaultToolkit");
Class<?> tkClass = getDefKitMeth.getReturnType();
// now you can obtain the toolkit instance:
Object tkInst = getDefKitMeth.invoke(null);
// and obtain a method to be called upon it
Method getScrSizMeth = tkClass.getMethod("getScreenSize");
// and invoke it:
Object screenSize = getScrSizMeth.invoke(tkInst);
... and so on...
You see, I never had to mention java.awt.Toolkit type explicitly to
invoke getScreenSize on an object of that type (or subtype). If you
think what a programmer does when he codes this in straight Java
without using reflection, it is the following:
1. He finds out a factory method on Toolkit class:
Toolkit.getDefaultToolkit()
2. He looks up the return type of that method (in javadocs).
3. He uses that type to declare a local variable to which it assigns
the result of the method invocation:
java.awt.Toolkit tkInst = java.awt.Toolkit.getDefaultToolkit();
4. He looks up and finds an instance method to call in type
java.awt.Toolkit: java.awt.Toolkit.getScreenSize() and writes it down:
tkInst.getScreenSize();
Above invocation is using static type java.awt.Toolkit - the return
type of Toolkit.getDefaultToolkit().
You can do similar things with reflection. Instead of using
anInstance.getClass() to get the runtime class of the instance, you
can use Method.getReturnType() of the method that was used to obtain
the instance. If API is designed so that no casts are needed when you
chain calls, then this should work.
Regards, Peter