Polymorphism in methods called by name

Discussion in 'Java' started by Krzysztof Nogal, Oct 3, 2005.

  1. Hello,

    I have got a problem with calling a method by name. I am using for it
    object Method.

    The situation looks like that:

    I have got class A with method: setUserList(java.util.List)
    and following (pseudo)code - it's generally about the idea:

    Object obj = new A();
    List param = new java.util.ArrayList();

    Class[] paramTypes = new Class[1];
    paramTypes[0] = param.getClass();
    Object[] paramValues = new Object[1];
    paramValues[0] = param;

    Method method = obj.getClass().getMethod("setUserList", paramTypes);
    method.invoke(obj, paramValues);

    and at this point I get:
    NoSuchMethodException: A.setUserList(java.util.ArrayList)

    But when I change method signature:
    java.util.ArrayList instead of java.util.List

    and then it runs ok.

    It seems that calling methods by name doesn't support polymorphism.

    TIA

    Krzysztof Nogal
     
    Krzysztof Nogal, Oct 3, 2005
    #1
    1. Advertisements

  2. Krzysztof Nogal

    shakah Guest

    Isn't it more the case that you specifically asked for a
    setUserList(java.util.ArrayList) method instead of a
    setUserList(java.util.List) method? In other words, does the following
    work?

    Object obj = new A();
    List param = new java.util.ArrayList();

    Class[] paramTypes = new Class[1];
    paramTypes[0] = Class.forName("java.util.List") ;
    Object[] paramValues = new Object[1];
    paramValues[0] = param;

    Method method = obj.getClass().getMethod("setUserList", paramTypes);
    method.invoke(obj, paramValues);
     
    shakah, Oct 3, 2005
    #2
    1. Advertisements

  3. It doesn't solve my problem because I can't give the static name for a
    class. I must invoke a method on a given object of a given name and
    list of parameters. I don't know the parameter types. I can read their
    types only through getClass() method. I just gave an example to
    indicate polymorphism problem. Instead List there could be e.g. object
    of type 'Animal' and instead ArrayList object of type 'Dog'. Dog
    extends Animal or implements it. If we had a method that takes Animal
    as parameter and try to call it by name with Dog object then we will
    receive an error.

    Object obj = new ArrayList();
    // this statement isn't true
    obj.getClass().equals(Class.forName("java.util.List"))

    Any ideas how to solve this?

    regards
    Krzysztof Nogal
     
    Krzysztof Nogal, Oct 3, 2005
    #3
  4. Krzysztof Nogal

    shakah Guest

    Your reasoning, or at least the contrived example, strikes me as
    circular. If you have a method that takes an Animal argument, and call
    it by name with Dog object you won't receive an error, i.e. doesn't the
    following work?
    Class [] acParams = new Class[1] ;
    acParams[0] = Class.forName("Animal") ;
    Method m = anObj.getClass().getMethod("type", acParams) ;
    m.invoke(anObj, new Dog()) ;

    In any case, if you can hard code the method name, why can't you hard
    code the argument type? Or if in your actual code you don't hard code
    the method name, why don't you pass in the Class names of the arguments?
     
    shakah, Oct 3, 2005
    #4
  5. Perhaps I didn't make myself clear or my English is not so good but I
    will try to describe what I would like to manage:

    For intput I receive:
    - object instance (as Object - unknown object type)
    - method name (as String - the one that should be called)
    - parameter values for the method (as List - parameter values are held
    in List object and I don't know the types of them)

    I must invoke specified method on given object instance. Everything is
    working fine. Only the situation when there is a parameter which type
    is lower on hierarchy tree then the one specified in given methods
    signature.

    And back to my expamle - I don't have method name hard coded. The
    change you made works:

    1 Object obj = new A();
    2 List param = new java.util.ArrayList();
    3 Class[] paramTypes = new Class[1];
    4 paramTypes[0] = Class.forName("java.util.List") ;
    5 Object[] paramValues = new Object[1];
    6 paramValues[0] = param;
    7 Method method = obj.getClass().getMethod("setUserList", paramTypes);
    8 method.invoke(obj, paramValues);

    and there is method:
    public void setUserList(java.util.List list);
    in Class A

    but change the line 4 to:
    paramTypes[0] = Class.forName("java.util.ArrayList") ;

    and it you will receive error on line 8. Explain me why? ArrayList IS a
    type of List.
    Normally (witthout calling by name) it will run properly:

    A obj = new A();
    List list = new ArrayList();
    // or even ArrayList list = new ArrayList();
    obj.setUserList(list);

    Regards
    Krzysztof Nogal
     
    Krzysztof Nogal, Oct 3, 2005
    #5
  6. Krzysztof Nogal

    shakah Guest

    Your English is fine, and in any case is infinitely better than my
    Polish (?).

    In your latest example, though, isn't it line 7 that causes the
    Exception? There you are looking for a method that specifically takes
    an ArrayList, and you simply don't have one. Maybe your users can pass
    the argument types (in the form of class names) along with the method
    name?
     
    shakah, Oct 3, 2005
    #6
  7. If it were possible, the best solution would be to not use reflection to
    invoke methods. If the problem is an exercise set for you which you
    therefore must solve as written then see below; otherwise redesign your
    application.

    Still with me? Fine. It is the Java compiler that normally selects the
    specific method to invoke in any method invocation expression, based on
    the declared types of the method parameters and the object on which the
    method is invoked. When invoking a method reflectively, however, you
    have to determine the right method yourself. This is problematic when
    you don't know the necessary declared argument types in advance -- you
    have run into one problem in that area; a related one arises when one of
    the actual arguments is null. Sometimes the compiler can't figure it
    out without help in the form of an explicit cast -- your code will be
    unable to resolve such situations without equivalent explicit type
    information. Are you sure you really want to do this?

    The task you have chosen to undertake is described in detail in the Java
    Language Specification. That description covers the above
    considerations, plus some others that you probably have not thought
    about. See section 15.12.2, especially parts 15.12.2.1 - 15.12.2.5.
    (http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.12.2)
    For full generality, your code will need to perform an analysis
    equivalent to the one described there. It is decidedly non-trivial.
    This situation is one of the n reasons to avoid reflection whenever
    possible.
     
    John C. Bollinger, Oct 4, 2005
    #7
  8. If it were possible, the best solution would be to not use reflection to
    I know that it would be best not to use reflection but I couldn't find
    any easy solution to my problem:
    - I don't know the object types and method names
    - I can't predict even the number of objects - they are dynamicaly
    loaded - description in XML file (plugins style)
    - It is something like Remote Procedure Call
    This information is very helpful. Thank you very much.
    In my example the problem is that while invoking a method using
    reflection it doesen't search for super types among parameters. It
    matches only 'exact' types without checking inheritance tree.
    And as you wrote - it is non-trivial. It would take much time to
    implement it. But in my case I can do it other way - I can compare
    instances (with instanceof) because I know that the parameters are
    standard java types from java.lang or implementations of List and Map
    interfaces.

    Regards,
    Krzysztof Nogal
     
    Krzysztof Nogal, Oct 4, 2005
    #8
  9. Your English is fine, and in any case is infinitely better than my
    correct :))
    My mistake - I thought about line 7 :)
    I can think about it but it would be more complicated to indroduce in
    my application...

    Regards,
    Krzysztof Nogal
     
    Krzysztof Nogal, Oct 4, 2005
    #9
  10. But why are you stuck with those problem parameters? Well-designed Java
    plugin mechanisms do not rely on reflective method invocation. Java RMI
    is an RPC mechanism that also does not rely on reflective method
    invocation. These kinds of problems can be solved without reflective
    method invocation, and certainly they can be solved without reflective
    invocation of arbitrary methods on objects of completely unconstrained
    class with unpredictable argument lists. At the very least, you could
    put the declared argument types into the XML file along with the method
    name so that you would not need to figure them out, but that's still an
    ugly hack.

    [...]
    Technically speaking, it's not the invocation that's the problem; it's
    method resolution. You didn't actually get to the point of invoking the
    method.
    That may work despite its kludginess, provided that your arguments are
    never null and are never primitive types. Even so, I think you will
    find it to be very messy. There are likely to be several better ways to
    accomplish your higher-level goal, but I couldn't say what they were
    without knowing what that goal is (i.e. the /purpose/ of the
    requirements you provided above).
     
    John C. Bollinger, Oct 5, 2005
    #10
  11. But why are you stuck with those problem parameters? Well-designed Java
    Could you point me to description how RMI RPC mechanism is realized
    without reflection?
    And about plugin mechanism: Plugins to my application must implement
    given interface and it must have entry in XML file. Then the
    application can load them. What other plugin mechanism can you propose?

    Now I noticed that Eclipse IDE have similar (bigger) plugin system.
    My mistake, you are right.
    I would appreciate help :) Here is what I want to do:

    There is server and many clients. Each connection between client and
    server is made on SSL sockets. The goal is to write mechanism (develop
    interfece) that other people can write their own modules (plugins)
    using that interfece. That mechanism should allow modules to invoke
    methods client -> server and server -> client asynchroniously to the
    corresponding module on server/client side (which does something e.g.
    access to database etc.) I implemented something like XML-RPC but with
    difference that methods can be invoked on existing connection in both
    directions. Of course each object on which methods can be called
    remotly must be registered.
    I would like to know if it is the right way...

    TIA

    Regards,
    Krzysztof Nogal
     
    Krzysztof Nogal, Oct 5, 2005
    #11
  12. Krzysztof Nogal

    Roedy Green Guest

    I won't presume to tell you how RMI actually works just how it COULD
    work, last partially, without reflection.

    In RMI, you know which classes and method calls can go over the wire
    ahead of time, and you get to look at the source code for them and
    from that compose proxy stub classes. Thus the list of possible
    message formats going over the wire is known in advance. They could
    even be given unique numbers to help dispatch them.

    Let us watch a remote method call. I call a method on a local proxy
    object. It bundles up the parameters, and sends them down the wire.

    The other end looks at the message dispatching type and routes the
    message to a proxy on the other end. The proxy takes the message apart
    into fields, and calls the real method on the real object with those
    parameters.

    To do this, no reflection was needed, just a bunch of generated code.

    You could construct an object at the other end in a similar way. You
    need a proxy static method that just calls the constructor.

    However passing an arbitrary object over the wire either as parameter
    or return value I think would require the sort of reflection used
    inside serialisation. You need to be able to set arbitrary fields in
    the newly constructed object whether or not there a setter method.
    You need to be able to set private fields.
     
    Roedy Green, Oct 6, 2005
    #12
  13. I don't have a technical description close at hand, but no reflection is
    needed because the object types are well known at compile time and the
    RMI server remote object, and stub object work together to sort things out.
    Do please recognize that I rather specifically advised you against
    reflective *method invocation*. Avoiding that morass is quite feasible
    in a plugin system. You cannot get away from reflective object
    instantiation if you do not know the actual class at compile time, but
    that is more tractable ground.

    A typical plugin framework works like this:
    (1) the application specifies a Java interface that plugin classes must
    implement.
    (2) at runtime, the application instantiates specified plugins
    reflectively, using a constructor of application-specified signature
    (3) the application assigns the reference obtained in (2) to a variable
    having the interface (1) as its declared type
    (4) the application exercises the plugin's behaviors via normal Java
    method invocation through the methods defined by the interface
    So this isn't just "like Remote Procedure Call"; you are planning a bona
    fide RPC mechanism. I would recommend that you study existing RPC
    mechanisms (Java RMI, Sun RPC), and also consider a web services
    approach. Do note that supposedly you can use RMI over SSL connections;
    the JSDK docs include a document entitled "Using a Custom RMI Socket
    Factory" that might get you started if you wanted to consider just using
    RMI instead of rolling your own.

    The "classic" RPC approach uses a stub object on one end of a connection
    to represent and interact with a real object on the other end. Two-way
    interaction is possible. There might need to be a coordinator running
    on one or both sides to establish a connection between the two, and one
    or both might need to extend some specific class so as to obtain the
    connection infrastructure. You might need to have an extra code
    generator / compiler that you run after the Java compiler (ala the RMI
    compiler, rmic). This is all very well if someone else builds it for
    you, but it is a substantial and tricky undertaking for you to do
    yourself, which leads me to...

    Web services. This might just be the way to go. You can get free Java
    web services stacks (Apache offers one) or purchase them from several
    companies (IBM, I think Bea, probably Oracle). Web services is pretty
    much just another flavor of RPC, and you could probably build on top of
    that. Web services certainly works with SSL connections, and SOAP
    didn't get its name (Simple Object Access Protocol) for nothing. Web
    services can conduct extended sessions of two-way conversation, and
    communication endpoints can be bound to specific objects if necessary.
    (I speak somewhat by faith on that last point.)

    But from your comments it sounds like you have something already that
    either works or almost does. If that's true then I'm impressed. If the
    last detail is to work out this method signature problem, and the XML
    files are programmatically generated rather than human-generated, then
    I'd say just put the declared types of the desired method's arguments
    into the XML file and use them to select the correct method. Don't try
    to infer from the arguments -- your code will be error-prone, if you
    mange to get it working properly then it will be brittle.
     
    John C. Bollinger, Oct 7, 2005
    #13
  14. Do please recognize that I rather specifically advised you against
    It is excatly what I have done. All 4 points. I have also defined
    collection of events in system and notification system, so each plugin
    'knows what is happening' and behaviour is in plugins gesture.
    I considered it and made some tests (also with SSL Connection) before I
    started writing but I decided to use something bit lighter (I think) -
    XML-RPC. Because XML-RPC is defined to act as Webservice I wrote my own
    implementation - so that it can be run on pernament connection in both
    ways. I know that RMI would solve this problem but I needed something
    to work on most mobile devices wich allow only http connections. And it
    is easy to add full xml-rpc functionality by adding http headers.
    This is my design error... I didn't work much with RPC's and I didn't
    know how it can be designed... Now I am to far in implementation.
    I needed a pernament(?) connection because I wanted the server to
    notify connected clients and send them some data. With webservcies it
    would be much complicated, in request - response mechanism clients
    would be asking in given period of time if server has something for
    them. It is not a nice solution and it generates much traffic.
    It is all almost working - I have written almost all - the plugin
    mechanism, rpc mechanism, connection management, including ssl keys,
    server, client. RPC xml calls are generated programmatically but I
    can't add argument types to xml because it would destroy xml-rpc xml
    definition standard. But just now it came to me that I can leave the
    situation as it is beacuse in xml-rpc the number of argument types is
    very limited. So for Map and List interfaces I can define that
    ArrayList and HashMap can be used as arguments for methods that can be
    called remotly. It isn't nice solution but... :)

    Thank you very much for help and opinons.
    (btw. it is a quite big project I am doing on my studies)

    Regards,
    Krzysztof Nogal
     
    Krzysztof Nogal, Oct 7, 2005
    #14
  15. This sounds a lot like RFE 4287725 (and several related bug reports):

    /gordon
     
    Gordon Beaton, Oct 7, 2005
    #15
  16. A nipick: web services vs. reflection is not really a distinction. Apache
    Axis (at least; I'm not familiar with the implementation of any other Java
    web service stacks) uses reflection all over. It's difficult to avoid,
    really, if you want to call a specific Java method based on the contents of
    a text message, or do table-driven serialization or deserialization of an
    XML message. (I suppose that you could create a hash that resolves to
    instances of different classes , but that would assume you care nothing
    about the number of classes you generate to provide slightly different
    behavior.)

    For myself, I would relax your prohibition against reflection to:

    Use it sparingly.

    If you must use reflection, do so in a disciplined fashion. For instance,
    by restricting it to generated code (in the case of web services, code
    generated from a WSDL file.)
     
    Mike Schilling, Oct 15, 2005
    #16
  17. Krzysztof Nogal

    Roedy Green Guest

    Huh? XML is heavier at least in terms of traffic.
     
    Roedy Green, Oct 15, 2005
    #17
  18. I think he meant "lighter [than SOAP]", which XML-RPC certainly is,
    since it drops all the baggage around the method call, parameters and
    return value.
     
    Tor Iver Wilhelmsen, Oct 16, 2005
    #18
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.