Polymorphism in methods called by name

  • Thread starter Krzysztof Nogal
  • Start date
K

Krzysztof Nogal

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
 
S

shakah

Krzysztof said:
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

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);
 
K

Krzysztof Nogal

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
 
S

shakah

Krzysztof said:
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

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

Krzysztof Nogal

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
 
S

shakah

Krzysztof said:
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

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

John C. Bollinger

Krzysztof said:
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?

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

Krzysztof Nogal

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.

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

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
 
K

Krzysztof Nogal

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

correct :))
In your latest example, though, isn't it line 7 that causes the
Exception?

My mistake - I thought about line 7 :)
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?

I can think about it but it would be more complicated to indroduce in
my application...

Regards,
Krzysztof Nogal
 
J

John C. Bollinger

Krzysztof said:
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

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.

[...]
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.

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

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).
 
K

Krzysztof Nogal

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

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

My mistake, you are right.
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).

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
 
R

Roedy Green

Could you point me to description how RMI RPC mechanism is realized
without reflection?

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

John C. Bollinger

Krzysztof said:
Could you point me to description how RMI RPC mechanism is realized
without reflection?

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

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

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

Krzysztof Nogal

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

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

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

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

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

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
 
M

Mike Schilling

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

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.)
 
R

Roedy Green

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.

Huh? XML is heavier at least in terms of traffic.
 
T

Tor Iver Wilhelmsen

Roedy Green said:
Huh? XML is heavier at least in terms of traffic.

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.
 

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. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top