Many times the objects in a list must be converted into some others objects, i.e. when
we need to get a different list with converted objects. It's trivial from first glance:
ListtoJmsMessageList(List originalMyMessageList) { List resultList = new ArrayList (originalMyMessageList.size()); for(MyMessage msg : originalMyMessageList) { resultList.add(Converter.convert(msg)); } return resultList; }
Nothing wrong with the above code, except:
1. it's boring and verbose
2. it creates new list
3. it iterates over original list
4. problems might occur when original list is ORM proxy list obtained as a result
of sql query, so operations such as size() on it - would cause problems such as retrieval of whole result set' content into memory
So, here's solution. What I actually want - convert list' stuff into list of another stuff, I would like to have something like:
List resultList = ListFactory.createList(originalList, callback);
So whenever resultList iteration being called I want to have already converted stuff in it! So, here's what I came to:
List createList(final Iterator originalIterator, final Callable c) { // iteration handler for custom list implementation InvocationHandler invocationHandler = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) { if (method.getName().equals("iterator")) { return new Iterator () { @Override public boolean hasNext() { return originalIterator.hasNext(); } @Override public T next() { try { // call 'custom behavior' return c.call(); } catch (Exception e) { log.error("Error during user defined operation on originalIterator", e); throw new RuntimeException(e); } } @Override public void remove() { // 'remove' isn't supported throw new UnsupportedOperationException(); } }; } // everthying other than iteration isn't supported throw new UnsupportedOperationException(); } }; return (List) Proxy.newProxyInstance( Thread.currentThread().getClass().getClassLoader(), new Class[] {List.class}, invocationHandler); }
Here's possible use cases:
return ListFactory.createList(originalListIterator, new Callable() { private int fetchedNum = 0; // the number of fetched objects @Override public MessageEntity call() { if (++fetchedNum % fetchSize == 0) { // remove fetched MessageEntity entities from iternal jpa's identity map // when number of fetched objects reaches 'fetchedNum' getEntityManager().clear(); } // don't forget call iterator.next() return originalListIterator.next(); } });
or
ListFactory.createList(messagesIterator, new Callable() { @Override public Entry call() { try { return toEntry(messagesIterator.next()); } catch (Exception e) { log.error("Error occured while converting list of jms messages", e); throw new RuntimeException(e); } } });
Thanks for reading.