Jeremy
Jeremy

Reputation: 5435

Getting around type-checking

This is exceedingly bad OO, but I am not trying to put this in any kind of code that will be used by anyone but the coders themselves -- it can never be called except for testing by coders.

Here is the problem I am facing: I have a series of classes that are defined externally. I cannot modify them in any way (except of course I could subclass or call them). They have a variety of names but they do not extend any superclasses (except Object), or implement any interfaces. However what I know about each of them is that they have a method called 'call'.

For testing, I am trying to write code that will call any one of these classes' call methods. But, of course, I cannot just say Object.call() because call is not defined for every Object.

Essentially, this will work:

MyClassOne classOne = new MyClassOne();
MyClassOneInput classOneInput = new MyclassOneInput();

classOne.call(classOneInput);

But this will not:

Object clazz = getClassFromElsewhere();
Object clazzInput = getClassInputFromElsewhere();

clazz.call(clazzInput).

Obviously, since Java is a strongly typed language.

BUT, for the sake of 10x faster testing for every person working on this system, can I get around that somehow and somehow use the 'call' method for any Class and any ClassInput? I have no problem if it generates an exception or breaks entirely if the wrong classes are passed.

Please help me violate Object Orientation.

Upvotes: 2

Views: 149

Answers (3)

Eran Medan
Eran Medan

Reputation: 45725

Use Reflection

  1. get the class using getClass()
  2. find the "call" method using getMethod()
  3. invoke it on the object if found

e.g.

java.lang.reflect.Method method;
try {
  method = obj.getClass().getMethod(methodName, param1.class, param2.class, ..);
} catch (SecurityException e) {
  // ...
} catch (NoSuchMethodException e) {
  // ...
}

Then

try {
  method.invoke(obj, arg1, arg2,...);
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {

see How do I invoke a Java method when given the method name as a string?

I would also consider looking into Dynamic JVM languages (JRuby, Jython, Groovy) in which doing something like this may look less "Bad OO" and feel more natural

Upvotes: 3

Matt Wonlaw
Matt Wonlaw

Reputation: 12443

You can use reflection to do this. Check out the reflection API

Here is a simple example:

MyClassOne classOne = new MyClassOne();
MyClassOneInput classOneInput = new MyClassOneInput();
Method m = classOne.getClass().getMethod("call", MyClassOneInput.class);
m.invoke(classOne, classOneInput);

Note: you can use getDeclaredMethod to get any method, including private and protected ones but you'll need to call "m.setAccessible(true)" on them if they are private/protected.

Upvotes: 8

Chris Thompson
Chris Thompson

Reputation: 35598

This is a perfect use for Java Reflection. This is a pseudo-code example, but it would look something like this

 Object obj = getExternalObject();
 Method meth = obj.getClass().getDeclaredMethod("call");
 meth.invoke(obj);

Upvotes: 6

Related Questions