Discussion:
Generics for XStream's converters?
Jörg Schaible
2014-02-26 19:18:01 UTC
Permalink
Hi mates,

it is about time to introduce also the "newer" language features, since
XStream 1.5.x will require Java 6 as minimum.

One question are generics for the Converter and SingleValueConverter
interfaces. I've played a bit with Converter<T> and SingleValueConverter<T>,
but I wonder what XStream really gains from it. XStream's core uses
basically Class and Object anyway, there is no advantage for a typed
converter. Only a programmer implementing a converter might have an
advantage, but it seems very limited:

In a first take, I tried to generify Converter. However, I stopped it, when
I tried to apply the changes to the collection converters, see following
snippets:

===================== %< =====================
class MapConverter<T extends Map<? extends K, ? extends V>, K, V> extends
AbstractCollectionConverter<T> {

MapConverter(Mapper mapper, Class<T> type) {
super(mapper, type);
}
}

class TreeMapConverter<K,V> extends
MapConverter<TreeMap<? extends K, ? extends V>, K, V> {

// this does not even compile
// TreeMapConverter(Mapper mapper) {
// super(mapper, TreeMap.class);
// }

TreeMapConverter(Mapper mapper) {
super(mapper, TreeMapConverter.<K,V>getClass());
}
static <K,V> Class<TreeMap<? extends K, ? extends V>> getClass() {
Class<?> type = TreeMap.class;
return (Class<TreeMap<? extends K,? extends V>>)type;
}
}
===================== %< =====================

In the end it was a little nightmare to generify all the methods that handle
the individual items of the collections. The code was flooded with casts,
because you cannot create new instances with unbounded types. The example
with the derived TreeMapConverter demonstrates on top that the generics are
more a hassle than a help - even for a developer of converters. Therefore I
did not apply generics for Converter for now.

In my sandbox I have currently still SingleValueConverter<T>. It works
better, because the implementation is typically simpler. However, most of
the time you spare simply a single cast:

===================== %< =====================
class IntegerConverter implements SingleValueConverter {
String toString(Object o) {
return String.valueOf(((Integer)o).intValue());
}
Object fromString(String s) {
return Integer.valueOf(s);
}
}
===================== %< =====================

vs.

===================== %< =====================
class IntegerConverter implements SingleValueConverter<Integer> {
String toString(Integer o) {
return String.valueOf(o.intValue());
}
Integer fromString(String s) {
return Integer.valueOf(s);
}
}
===================== %< =====================

with the consequence that the second implementation is no longer compatible
with existing 3rd party code, if someone derived from it:

===================== %< =====================
class ShortConverter extends IntegerConverter {
String toString(Object o) {
return super.toString(Integer.ValueOf(((Short)o).shortValue()));
}
Object fromString(String s) {
return Short.valueOf((short)((Integer)super.fromString(s)).intValue());
}
}
===================== %< =====================

Is it worth? What do you think?

Cheers,
Jörg

Loading...