luni, 3 martie 2008

Java 5 for and Enumerations: don't stop, add type tokens

Some time ago I bumped into this blog post that presented an Adapter from Enumeration to Iterable/Iterator. It was so simple and yet incredibly useful. How could I have not though of this? Imagine my 'dooh' moment, especially since I was working for some time now with an API that's exclusively based on Enumerations (I guess they are keen on extreme backwards compatibility - no iterators, not one!) and I was using JDK 1.5...

However, I think we can push things a little bit further (well, we can always do this, can't we?). Follow me on this one.

One of the main applications of the Adapter design pattern is to support legacy code or code that we can't change (like the one in vendor/third-party libs) but we need/would like it to conform to a certain interface (Iterable in our case).

Now, if we think a bit, most (if not all) of the legacy code based on Enumerations is not likely to support Generics either so simply using iterate() over raw Enumerations would end up in a bunch of unchecked warnings. We could leave it this way or we could add @SupressWarnings("unchecked") (which is not really a satisfying solution, is it?).

What we could do to improve things a little is to add an extra method (see the code below), similar to iterate(), that takes an additional type token as the second argument representing the expected type of the elements of the adapted Enumeration (one could read more about type tokens in Gilad Bracha's really nice Generics tutorial). I've also taken the liberty to rename the methods to in() to come closer to another nice topic - fluent interfaces that is.

01 package ro.thon.util;
02
03 import static ro.thon.util.Assert.notNull;
04
05 import java.util.Enumeration;
06 import java.util.Iterator;
07
08 public final class Iterators {
09
10 private Iterators() { /* prevent any instantiation... */ }
11
12 private static final class IterableEnumeration<E> implements Iterable<E>, Iterator<E> {
14
15 private Enumeration<?> enumeration;
16
17 private Class<? extends E> klass;
18
19 public IterableEnumeration(Enumeration<?> enumeration, Class<?
20 extends E> klass) {
21 notNull(enumeration, "non-null enumeration expected");
22 notNull(klass, "non-null type token expected");
23 this.enumeration = enumeration;
24 this.klass = klass;
25 }
26
27 public IterableEnumeration(Enumeration<? extends E> enumeration) {
28 notNull(enumeration, "non-null enumeration expected");
29 this.enumeration = enumeration;
30 }
31
32 public Iterator<E> iterator() { return this; }
33
34 public boolean hasNext() { return enumeration.hasMoreElements(); }
35
36 @SuppressWarnings("unchecked")
37 public E next() {
38 Object next = enumeration.nextElement();
39 return (klass == null) ? (E) next : klass.cast(next);
40 }
41
42 public void remove() { throw new UnsupportedOperationException(); }
43 }
44
45 public static <E> Iterable<E> in(Enumeration<?> enumeration,
46 Class<? extends E> klass) {
47 return new IterableEnumeration<E>(enumeration, klass);
48 }
49
50 public static <E> Iterable<E> in(Enumeration<? extends E> enumeration) {
51 return new IterableEnumeration<E>(enumeration);
52 }
53 }

Now, calling the second version of in() eliminates those (really) annoying unchecked warnings.

Note that this is not entirely type safe, since we could easily pass a raw Enumeration of another type or (relying too much on code completion) we could pass another class token (with a similar name) but at least we got rid of the pesky warnings.

Anyway, great blog Stephan, thanks again. Me friend! :)

duminică, 20 ianuarie 2008

Ave Mundi!

I finally decided to listen to one of my good friends and stop spamming him with technology-related, ranting e-mails and create some blog entries... (so here I am Luci, with my first real blog :))

This blog will be _mostly_ about software development, since this is my current hobby, and my current means to make a living (ain't I a lucky one...). To be more specific, my current interests are in the fields of Design Patterns (and how to stay away from them), typing (in general - static, dynamic, generics), Java, Ruby and other related stuff (I guess this is the most generic phrase I can find right now :)).

The main reason I started this blog is for me to learn more things related to software development (could one imagine a more selfish reason?), but I really, really hope others will find the things I (and the repliers) discuss here helpful too.

P.S. The thing about how to stay away from Design Patterns - what I really meant was how to learn to use them when appropriate and make the most out of them :) ...