foreach in Java

Here’s a cool but unfortunately useless example of java generics, combined with reflection, combined with dynamic proxies.

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;

import sun.reflect.generics.reflectiveObjects.NotImplementedException;
import sun.reflect.generics.tree.ReturnType;

public class Foreach {
  @SuppressWarnings("unchecked")
  public static <T> T foreach(T... elements) {
    ApplyOnArrray<T> handler = new ApplyOnArrray<T>(elements);
    return (T) Proxy.newProxyInstance(elements[0].getClass().getClassLoader(),
      new Class[] { elements[0].getClass().getInterfaces()[0] },
      handler);
  }

  public static <ReturnType> List<ReturnType> get(ReturnType returnValue) {
    Collector collector = (Collector) Proxy.getInvocationHandler(returnValue);
    return collector.getReturnValues();
  }

  public static void main(String[] args) {
    IFoo f1 = new Foo();
    IFoo f2 = new Foo();
    IFoo f3 = new Foo();
    IFoo f4 = new Foo();

    List<IString> list = get(foreach(f1, f2, f3, f4).sayFoo());
    System.out.println(list);
  }
}

class Collector implements InvocationHandler {
  private final List returnValues;

  public Collector(List returnValues) {
    this.returnValues = returnValues;
  }

  public List getReturnValues() {
    return returnValues;
  }

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    // TODO get(foreach(elements).method(args))
    throw new NotImplementedException();
  }
}

interface IString { String toString(); }

  class StringImpl implements IString {
    private String s;
    public StringImpl(String s) { this.s = s; }
    public String toString() { return s; }
  }

interface IFoo { IString sayFoo(); };

class Foo implements IFoo {
  public IString sayFoo() {
    System.out.println("foo");
    return new StringImpl("foo");
  }
};

class ApplyOnArrray<T> implements InvocationHandler {
  private final T[] elements;

  public ApplyOnArrray(T... elements) { this.elements = elements; }

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    Method targetMethod = elements[0].getClass().getMethod(method.getName(), method.getParameterTypes());

    List returnValues = new ArrayList();
    for (T element : elements) returnValues.add(targetMethod.invoke(element, args));

    // return a proxy for the result
    return (T) Proxy.newProxyInstance(elements[0].getClass().getClassLoader(),
    new Class[] { targetMethod.getReturnType() },
    new Collector(returnValues));
  }

}

I had this idea in a dream (too much work) and fortunately I could still remember it in the morning. Who knows, I might have dreamt also a solution that works with classes.

Advertisements

3 comments

  1. Nilushi

    excellent tutorial. Thanx very much for it. 🙂

  2. And the example also shows the danger of code completion in Eclipse – once you have committed a spelling error like “Arrray” you are doomed to repeat it forever!

  3. jaksa

    LOL, good catch Immo.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s