Archived

This forum has been archived. Please start a new discussion on GitHub.

Casting a proxy to the most derived interface

I have an hierarchy of interfaces:
interface I1 {...}

interface I2 extends I1 {...}

interface I3 extends I1 {...}
and I need to do something with a proxy which depends on the type of object (not the static type). That is,
ObjectPrx prx = ...

I1Prx i1 = I1PrxHelper.checkedCast(prx);
if (i1 != null) then ...

I2Prx i2 = I2PrxHelper.checkedCast(prx);
if (i2 != null) ...

I3Prx i1 = I3PrxHelper.checkedCast(prx);
if (i3 != null) ...
However, the above requires a lot of remote calls and 2 more will be added each time a new interface is introduced.

Now, if there was a method which cast a proxy to its actual type, I could write
ObjectPrx precisePrx = castToActualType(prx);
if (precisePrx instanceOf I1Prx) ...
if (precisePrx instanceOf I2Prx) ...
if (precisePrx instanceOf I3Prx) ...

I could write it using reflection (error checking omitted):
ObjectPrx castToActualType(ObjectPrx prx) {
    String type_id = prx.ice_id();
    String prxInterfaceName = type_id.substring(2).replaceAll("::", ".") ++ "Prx";
    String helperName = prxInterfaceName ++ "Helper";

    Class<?> klass = Class.forName(helperName);
    Method castMethod = klass.getMethod("checkedCast");
    return (ObjectPrx) castMethod.invoke(null, prx);
}
Is there a simpler way to do it? Or an explanation why this is a bad idea?

Comments

  • benoit
    benoit Rennes, France
    Hi,

    I would go with the following option:
    String typeId = prx.ice_id();
    if (typeId.equals(_I1Disp.ice_staticId()) 
    {
        I1Prx p = I1PrxHelper.uncheckedCast(prx);
        ...
    }
    if (typeId.equals(_I2Disp.ice_staticId()) 
    {
        I2Prx p = I2PrxHelper.uncheckedCast(prx);
        ...
    }
    if (typeId.equals(_I3Disp.ice_staticId()) 
    {
        I3Prx p = I3PrxHelper.uncheckedCast(prx);
        ...
    }
    

    Note that it's a bit unfortunate that you have to use the generated _<interface name>Disp type here to get the type ID, it would be nicer if ice_staticId() was a static operation of the PrxHelper class, we'll discuss adding this.

    One issue with your solution that uses reflection is that it assumes that the Slice type ID maps to an equivalent Java class name. This might not always be the case if the [noparse]"java:package:com.foo"[/noparse] metadata is used in the Slice to generate the Java classes in a given package.

    Cheers,
    Benoit.
  • Yes, this looks nicer (UPDATED: but it doesn't do quite what I need. The block for I1 only runs for objects which are precisely I1, while I want it to run for all subtypes of I1 as well). The problem it doesn't handle is, what happens if I later add
    interface I4 extends I3
    
    but want to still execute blocks for I1, I2, and I3 only. In the solution using reflection I don't need to do any changes; with this solution I need to add a case for I4 to the dispatch method.
  • Is there a way to check, given two type IDs, whether one is a subtype of the other? Because this would do what I want:
    String typeId = prx.ice_id();
    if (isSubtype(typeId, _I1Disp.ice_staticId()) 
    {
        I1Prx p = I1PrxHelper.uncheckedCast(prx);
        ...
    }
    if (isSubtype(typeId, _I2Disp.ice_staticId()) 
    {
        I2Prx p = I2PrxHelper.uncheckedCast(prx);
        ...
    }
    if (isSubtype(typeId, _I3Disp.ice_staticId()) 
    {
        I3Prx p = I3PrxHelper.uncheckedCast(prx);
        ...
    }
    
  • benoit
    benoit Rennes, France
    You can use prx.ice_ids() to retrieve the list of type IDs implemented by the Ice object. With this list, you should be able to implement isSubtype().

    That being said, such checks usually indicate that you're not taking advantage of polymorphism. Why are you checking for the type of the proxies? Is it to call some specific methods on the proxies afterwards? Perhaps you can add a method on the base interface to simplify this code?

    Cheers,
    Benoit.
  • I want to show one tab with properties of I1, another tab with properties of I2, etc. The interfaces do not (and should not) know anything about my GUI.
  • benoit
    benoit Rennes, France
    Perhaps you can add a parallel "Info" hierarchy to get the properties of your Ice objects? For example:
    class Info { };
    interface IBase
    {
       Info  getInfo();
    };
    
    class InfoI1 extends Info
    {
    ...
    };
    
    interface I1 extends IBase
    {
    ...
    }
    
    class InfoI2 extends InfoI1
    {
    ...
    };
    
    interface I2 extends I1
    {
    ...
    }
    

    This way, you can retrieve all the properties with a single request and you can check for the type of the result of getInfo() to display the properties of each object:
    Info info = prx.getInfo();
    if(info instanceof InfoI1)
    {
    ...
    }
    if(info instanceof InfoI2)
    {
    ...
    }
    

    Cheers,
    Benoit.
  • No, I can't change the interfaces (since the server is already implemented). I could add my own interfaces, but implementing getInfo() would require this sort of checks anyway.
  • benoit
    benoit Rennes, France
    Ok, I understand. In this case, retrieving the type IDs implemented by the object and adding a isSubtype helper method would be my preferred approach. Your solution which uses reflection also works as long as you are sure the Slice type ID always "match" the class name (i.e.: you're not using the java:package metadata).

    Cheers,
    Benoit.
  • Thank you for your help!