Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simulating duck typing in Java

The problem: I'd like to be able to generically access in Java any property/field on a Java ojbect similarly to how a dynamic language (think Groovy, JavaScript) would. I won't know at the time I'm writing this plumbing code what type of object it is or what the property/field name will be. But I will know the property/field name when I go to use it.

My current solution: So far I've written a simple wrapper class that uses java.beans.Introspector to grab the properties of a Bean/POJO and expose them as a Map<String, Object>. It's crude but works for simple cases.

My question is what other methodologies are there for approaching this problem besides reflection / converting to a Map?

Before I go too much further down this path, I'd like to know if anyone knows how I could cannibalize something out of Rhino or perhaps javax.script.* which has a well thought out implementation of this concept. Or perhaps an entirely different approach that I haven't considered.

Edit: yes I'm familiar with reflection (which I believe is what Introspector is using under the hood anyway). I was just curious if there was any other well thought out solutions.

Edit 2: It appears that the most popular answers involve 1) reflection either directly or via helper classes, and/or 2) mapping to interfaces which implement the desired class members. I'm really intrigued by the comment which talks about leveraging Groovy. Since Groovy has true duck-typing and it is a JVM language, is there a way to make a simple helper in Groovy and call it from Java? This would be really cool and probably more flexible and perform better.

Answer: I marked Mike's answer as the best since it is a complete concept which comes the closest. I probably won't go that route for this particular case, but it is certainly a useful approach. Anyone looking through this should be sure to read the conversations on here as there is a lot of useful info in there as well.

Thanks!

like image 575
mckamey Avatar asked Dec 01 '10 23:12

mckamey


People also ask

Is duck typing possible in Java?

Java does not support duck typing. The method signature has to specify the correct type for each argument. For example, an argument has to implement the “duck” interface. It is not enough for a class to have the same methods that are provided for in the interface; no, it is necessary to actually write implements Duck.

Is duck typing dynamic typing?

Duck typing is a concept related to dynamic typing, where the type or the class of an object is less important than the methods it defines. When you use duck typing, you do not check types at all. Instead, you check for the presence of a given method or attribute.

What is the difference between duck typing and polymorphism?

Polymorphism is the ability of object of different types to be handled by a common interface. While duck typing, is a kind of dynamic typing that allows objects of different types to respond to the same methods.

Is duck typing good?

advantage is that it leads to fewer lines of code. This makes it look cleaner; thus making your code easier to read and faster to write. practices, it really is useful functionality!


2 Answers

If you know the set of APIs that you want to expose, say you know you want access to a length method and an iterator method, you can define an interface:

public interface TheInterfaceIWant {
  int length();
  void quack();
}

and you want to be able to use this interface to access corresponding methods on instances that do not implement this interface, you can use Proxy classes : 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 the wrapper as you would the duck in a dynamically typed language.

if (aDuckWrapper.length() > 0) {
  aDuckWrapper.quack();
}

Here's a full length runnable example that prints "Quack" four times using a 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 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);
          }
        });

    for (int n = aDuckWrapper.length(); --n >= 0;) {
      // Calling aDuck.quack() here would be invalid since its an Object.
      aDuckWrapper.quack();
    }
  }
}
like image 188
Mike Samuel Avatar answered Sep 20 '22 18:09

Mike Samuel


Another method that I just came across which leverages (abuses?) type erasure is kind of interesting:

http://rickyclarkson.blogspot.com/2006/07/duck-typing-in-java-and-no-reflection.html

I'm not sure that I buy that this is much different from simply using the interfaces directly but perhaps it is useful to someone else.

like image 33
mckamey Avatar answered Sep 17 '22 18:09

mckamey