Iterating on non-iterable classes
Posted by Lucio Benfante Fri, 27 Jul 2007 11:42:00 GMT
(You’ll find all the code of this post in Benfante’s Utilities mini-library)
One of the futures I ‘m reappraising is the JDK 5 enhanced for statement.
I still consider it too limited, but it’s very comfortable in the simplest (and maybe common) cases.
But…what if the elements on which you want to iterate are not managed by an Iterable class?
For example, this happens with the XOM library, where the Element.getChildElements returns an instance of the Elements class, wich is neither a Collection, or an Iterable class. So, for iterating on children elements, you have to use the basic for statement:
for (int i=0; i < elements.size(); i++) {
Element element = elements.get(i);
// etc...
}I would like to write simply:
for (Element element: elements) {
// etc...
}So I wrote an Iterabletor class that builds a proxy around a class, enhancing it with the Iterable interface.
Now You can write:
Iterable<Element> iterable =
new Iterabletor<Element>(elements).getIterable();
for (Element element: iterable) {
// etc...
}Take a look at how I realaized this.
First, the Iterabletor class:
package com.benfante.utils.iterabletor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Iterator;
/**
* A class for add iterability to another class
*
* @author lucio
*/
public class Iterabletor<T> implements InvocationHandler {
private final Object obj;
private Class<? extends Iterator> iteratorClass;
/**
* Prepare for iterability the passed object using a XOMIterator.
*
* @param The object on which iterate.
*/
@SuppressWarnings(value = "unchecked")
public Iterabletor(Object obj) {
this.obj = obj;
this.iteratorClass = XOMIterator.class;
}
/**
* Prepare for iterability the passed object using the passed iterator class.
*
* @param The object on which iterate.
*/
public Iterabletor(Object obj, Class<? extends Iterator> iteratorClass) {
this.obj = obj;
this.iteratorClass = iteratorClass;
}
@SuppressWarnings(value = "unchecked")
public synchronized Iterable<T> getIterable() {
Class<?> objClass = obj.getClass();
Class<?>[] oldInterfaces = objClass.getInterfaces();
Class<?>[] newInterfaces = new Class<?>[oldInterfaces.length + 1];
System.arraycopy(oldInterfaces, 0, newInterfaces, 0, oldInterfaces.length);
newInterfaces[newInterfaces.length - 1] = Iterable.class;
return (Iterable<T>) Proxy.newProxyInstance(objClass.getClassLoader(),
newInterfaces,
this);
}
@SuppressWarnings(value = "unchecked")
private Iterator<T> iterator() {
try {
return (Iterator<T>) iteratorClass
.getConstructor(Object.class).newInstance(obj);
} catch (Exception e) {
throw new UnsupportedOperationException("No contructor(object)", e);
}
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("iterator")) {
return this.iterator();
} else {
try {
return method.invoke(obj, args);
} catch (InvocationTargetException ite) {
throw ite.getCause();
}
}
}
}The default Iterator is XOMIterator (you can imagine why this name :) ), which reflect on the “collection”, calling the get(int) and size() methods:
package com.benfante.utils.iterabletor;
import java.util.Iterator;
import org.apache.log4j.Logger;
/**
* An Iterator for XOM-like collection classes
* ...i.e. classes with get(int) and size() methods.
*
* @author lucio
*/
public class XOMIterator<T> implements Iterator<T> {
private static final Logger logger = Logger.getLogger(XOMIterator.class);
private Object obj;
private int index;
public XOMIterator(Object obj) {
this.obj = obj;
}
public boolean hasNext() {
try {
int count = ((java.lang.Integer) obj.getClass()
.getMethod("size", new Class[0])
.invoke(obj)).intValue();
return index < count;
} catch (Exception ex) {
logger.error("No size() method in the target object ("
+ obj.getClass().getName() + ")", ex);
throw
new UnsupportedOperationException(
"No size() method in the target object ("
+ obj.getClass().getName() + ")", ex);
}
}
@SuppressWarnings(value = "unchecked")
public T next() {
try {
return (T) obj.getClass()
.getMethod("get", new Class<?>[]{int.class})
.invoke(obj, new Integer(index++));
} catch (Exception ex) {
logger.error("No get(int) method in the target object ("
+ obj.getClass().getName() + ")", ex);
throw
new UnsupportedOperationException(
"No get(int) method in the target object ("
+ obj.getClass().getName() + ")", ex);
}
}
public void remove() {
throw new UnsupportedOperationException("Not supported.");
}
}Of course, You can use a different Iterator:
Iterator<MyElement> iterable =
new Iterabletor<MyElement>(element, MyIterator.class)
.getIterable();



It seems interesting. It would be convenient to define a lot of Iterator class for all the commons collection-like-class, i.e. Elements of Xom.
Looking for a nursing home in derby, with high quality nursing care with restbite nursing care assisted living. High quality purpose built nursing home is located in Swadlincote, Derbyshire nr Derby, the ideal nursing home. Nursing home Swadlincote
BestFreelanceJob.com is the contract work marketplace where clients post contract jobs and freelance programmers, graphic designers, translators, consultants and other professionals bid for those jobs.
For more details visit at: http://www.bestfreelancejob.com/
Swarovski purses are well known by their special crystals and their high quality. Of course we cannot ignore the unique style of the swarovski clutch bags .We have already known that swarovski evening bags are well known not only in USA, but also even in the world. Since years of its beginning in fashion world, swarovski fashion purses have make great efforts in introducing the new era. They believe that creating new crystal clutches which could attract people’s attention and best sold in a short time based on the ideas that the public gives us endless inspiration. So imagination in designing these gemstone purses as well as crystal bridal bags plays a rather important role when it comes to swarovski bags designers. And also inspiration is not easy to get. Designer crystal bags would only achieve by experiencing new thing. http://www.crystalpurseshop.com/
Blingsoul purses are well known by their special crystals and their high quality. Of course we cannot ignore the unique style of the bling soul clutch bags .We have already known that bling soul evening bags are well known not only in USA, but also even in the world. Since years of its beginning in fashion world, bling soul fashion purses have make great efforts in introducing the new era. They believe that creating new crystal clutches which could attract people’s attention and best sold in a short time based on the ideas that the public gives us endless inspiration. So imagination in designing these gemstone purses as well as crystal bridal bags plays a rather important role when it comes to bling soul purses designers. And also inspiration is not easy to get. Designer crystal bags would only achieve by experiencing new thing.
http://www.blingsoul.com/