Simulating duck typing in Java
Question: I think I can generally access any property / field in Java Ojbect in Java, just like dynamic language (groovy, JavaScript) I was writing this pipeline code at that time. I didn't know what type of object it was or what attribute / field name it was But when I use it, I will know the property / field name
My current solution: so far, I have written a simple wrapper class that uses Java beans. Introspector to get the properties of bean / POJO and take them as map < string, object & gt This is rough, but applies to simple cases My question is, what other ways to deal with this problem besides reflection / conversion to map? Before I go any further, I wonder if anyone knows how to get from rhino or javax Break down something in script ** This concept has a thoughtful implementation Or maybe it's a completely different approach, which I haven't considered Editor: Yes, I am familiar with reflection (I believe what introspector uses under the hood) If there are any other well thought out solutions, I'm just curious to edit 2: it seems that the most popular answers include 1) reflection directly or through auxiliary classes, and / or 2) mapping to interfaces that implement the required class members I'm interested in comments about using groovy Because Groovy has a real duck type, it is a JVM language. Is there a way to create a simple assistant in Groovy and call it from Java? It's really cool, maybe more flexible and perform better A: I marked Mike's answer as the best because it is the closest complete concept In this case, I may not go that route, but it is certainly a useful method Anyone reading this should be sure to read the dialogue here, because there is a lot of useful information there thank you!
Solution
If you know the API set to be exposed, for example, you need to access the length method and iterator method, you can define an interface:
public interface TheInterfaceIWant { int length(); void quack(); }
If you want to use this interface to access the corresponding methods on instances that do not implement this interface, you can use the proxy class: http://download.oracle.com/javase/1.4.2/docs/api/java/lang/reflect/Proxy.html
So you create a proxy
final Object aDuck = ...; TheInterfaceIWant aDuckWrapper = (TheInterfaceIWant) Proxy.newProxyInstance( TheInterfaceIWant.class.getClassLoader(),new Class[] { TheInterfaceIWant.class },new InvocationHandler() { public Object invoke( Object proxy,Method method,Object[] args) throws Throwable { return aDuck.getClass().getmethod( method.getName(),method.getParameterTypes()).invoke(aDuck,args); } });
Then you can use wrappers, just like ducks using dynamically typed languages
if (aDuckWrapper.length() > 0) { aDuckWrapper.quack(); }
This is a full-length runnable example that prints "quack" four times using the wrapper:
import java.lang.reflect.*; public class Duck { // The interface we use to access the duck typed object. public interface TheInterfaceIWant { int length(); void quack(); } // The underlying instance that does not implement TheInterfaceIWant! static final class Foo { public int length() { return 4; } public void quack() { System.out.println("Quack"); } } public static void main(String[] args) throws Exception { // Create an instance but cast away all useful type info. final Object aDuck = new Foo(); TheInterfaceIWant aDuckWrapper = (TheInterfaceIWant) Proxy.newProxyInstance( TheInterfaceIWant.class.getClassLoader(),new InvocationHandler() { public Object invoke( Object proxy,Object[] args) throws Throwable { return aDuck.getClass().getmethod( method.getName(),args); } }); for (int n = aDuckWrapper.length(); --n >= 0;) { // Calling aDuck.quack() here would be invalid since its an Object. aDuckWrapper.quack(); } } }