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.

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.

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,

  * 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,

  * 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 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.

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.

---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
>

Reply via email to