





Recently I have been working on code with frequent need to convert a Collection, Map or Array of one type of objects to a similar container containing another type of objects—for example, to convert an array of java.io.File objects to an array of java.net.URI objects representing the same files. This kind of requirement is common when different APIs expect different representations of the same things. In this case, I was passing a set of files returned from a JFileChooser to an API which read data from any kind of resource using URIs.
Of course, there’s nothing really special about type conversion. It’s merely calling the same method repeatedly on a bunch of objects and returning the results as another bunch of objects. It’s only type conversion because you’re not intending to change the content of the objects—only their representation.
In the past, I have always used the Apache Commons BeanUtils’ ConvertUtils to do this kind of job, but now I’m in the exciting world of Java 5+ and generics, I thought there must be a cleaner way to do simple conversions. I came up with a Transformer object. At its simplest, it looks like this:
public abstract class Transformer<I,O> {
public abstract O transform(I input);
}Nothing clever, it’s a class which converts an input type I to an output type O. How it does that is irrelevant. Here’s an example:
public class FileToUriTransformer extends Transformer<File, URI> {
@Override
public URI transform(File file) {
return file.toURI();
}
};The real power of generics comes with a few static methods on the Transformer base class. As an example, here’s a method to convert a collection of one type to a collection of another.
public abstract class Transformer<I,O> {
...
public static <I,O,C extends Collection<? super O>> C transform(
Collection<? extends I> inputs, C outputs, Transformer<I,O> transformer) {
for (I input : inputs) {
outputs.add(transformer.transform(input));
}
return outputs;
}
}This method takes a transformer from I to O, an input collection and an output collection, and calls the transformer repeatedly to populate the output collection. For convenience, it returns the output collection and the whole thing is type-safe thanks to generics. Here’s how to use it:
List<File> files = fileChooser.getFileList();
List<URI> uris = Transformer.transform(files, new ArrayList<URI>(files.size()),
new FileToUriTransformer());Of course, the transformers themselves are typically stateless and so for convenience, they can be created as opaque static members of the Transformer class itself, leading to the following even neater code:
import static Transformer.FILE_TO_URI;
...
List<URI> uris = Transformer.transform(files, new ArrayList<URI>(files.size()),
FILE_TO_URI);Similar (very simple) mechanisms can be used to convert arrays and maps as follows:
public abstract class Transformer<I,O> {
...
public static <I,O> O[] transform(I[] inputs, O[] outputs,
Transformer<I,O> transformer) {
for (int i = 0; i < outputs.length && i < inputs.length; i++) {
outputs[i] = transformer.transform(inputs[i]);
}
return outputs;
}
public static <K,I,O> Map<K,O> transform(Map<K,I> inputs,
Map<K,O> outputs, Transformer<I,O> transformer) {
for (Map.Entry<K,I> entry : inputs.entrySet()) {
outputs.put(entry.getKey(), transformer.transform(entry.getValue()));
}
return outputs;
}
}The final enhancement to the class, apart from the creation of more static transformers, is the ability to compose transformations by chaining them together. For example, to convert a file to a URI string for display one needs to convert the java.io.File to the java.net.URI then call toString on the URI object. A generic TO_STRING converter can be added, together with a method to chain converters:
public abstract class Transformer<I,O> {
...
public final static Transformer<Object, String> TO_STRING =
new Transformer<Object, String>() {
@Override
public String transform(Object input) {
return input.toString();
}
};
public final static Transformer<File, URI> FILE_TO_URI = ...
...
public final <P> Transformer<I,P> followedBy(Transformer<? super O,P> chainedTransformer) {
return chain(this, chainedTransformer);
}
private static <I,O,M> Transformer<I,O> chain(final Transformer<I,M> first,
final Transformer<? super M,O> second) {
return new Transformer<I,O>() {
@Override
public O transform(I input) {
return second.transform(first.transform(input));
}
};
}
}The chain internal helper method joins two transformers through an intermediate type M which is output by the first transfer and accepted as input by the second. A followedBy convenience method then allows the desired transform to be executed this:
import static Transformer.FILE_TO_URI;
import static Transformer.TO_STRING;
...
List<String> uriStrs = Transformer.transform(files, new LinkedList<String>(),
FILE_TO_URI.followedBy(TO_STRING));
Although intended primarily for making bulk transformation more readable by reducing repetitive code, occasionally the static transformers are useful for improving code readability on their own.
I have a number of objects which have configurable regular expression pattern matching (for extracting text from files, in case you were interested). The regular expressions are specified as properties in the Spring context of my application. Of course, Spring treats these as strings, but for performance I want to hold them as compiled regular expression java.text.Patterns with consistent options. My managed object looks a bit like this:
class Characteristic {
final static Transformer<String,Pattern> STRING_TO_PATTERN =
new Transformer<String, Pattern>() {
@Override
public Pattern transform(String s) {
return Pattern.compile(s, Pattern.LITERAL);
}
};
Pattern startPattern;
Set<Pattern> endPatterns;
...
public void setStartRegex(String startRegex) {
this.startPattern = STRING_TO_PATTERN.transform(startRegex);
}
public void setEndRegexes(Set<String> endRegexes) {
this.endPatterns = Transformer.transform(endRegexes,
new HashSet<Pattern>(endRegexes.size()), STRING_TO_PATTERN);
}
}Of course, in reality the transformer is defined in Transformer and reused across the whole project.
I have found this class invaluable both for bulk and single conversions (especially for creating regular expressions from String values injected by ), and hope it may also be useful to anyone else who stumbles across this page looking for type-safe Java object conversion as an alternative to ConvertUtils. The full source is downloadable from
http://homepage.mac.com/tapinacom/code/Transformer.java and is in the public domain.