Conception problem on generic class
I have a conception problem on my ConverterManager. ConverterManager is an object that convert a type to an other type. As you can see below, I got an error when I'm tyring to create "convert" function.
public class StringIntegerConverter implements Converter<String, Integer> {
@Override
public Integer convert(String from) {
//...
return Integer.valueOf(from);
}
}
public class ConverterManager {
private static Map<Key,Converter<?,?>> converterRegistry;
{
converterRegistry = new HashMap<Key, Converter<?,?>>();
converterRegistry.put(new Key(String.class, Integer.class), new StringIntegerConverter());
}
public <T> T convert(Object source, Class<T> toType)
{
//**ERROR HERE : cause "source" is an Object**
return converterRegistry.get(new Key(source.getClass(),toType)).convert(source);
}
}
- Is there a way to solve this problem ? (I don't want to change my Strin开发者_如何学GogIntegerConverter to accepet converting from Object)
Thank you for reading, I hope someone will help me ;)
I can see one "problem" - your initializer block isn't static
, but it refers to a static field. This means that while it "works", the static instance will be replaced every time a new instance of the class is instantiated. Try this:
private static Map<Key,Converter<?,?>> converterRegistry;
....
static { // ADD static KEYWORD!
converterRegistry = new HashMap<Key, Converter<?,?>>();
converterRegistry.put(new Key(String.class, Integer.class), new StringIntegerConverter());
}
...
A more elegant option is to use an instance block within an anonymous class (often erroneously called the "double brace" initializer, when in fact there is no such thing):
private static Map<Key,Converter<?,?>> converterRegistry = new HashMap<Key, Converter<?,?>>() {{
put(new Key(String.class, Integer.class), new StringIntegerConverter());
}};
Basically you'll have to perform an unsafe conversion - at execution time, the JVM can't check that you've really got a Converter<String, Integer>
. That leaves the problem of persuading it to accept the input. You can do that via a "proxying" converter class which implements Converter<Object, ?>
:
class ConverterConverter<T, U> implements Converter<Object, U>
{
private final Converter<T, U> original;
ConverterConverter(Converter<T, U> original)
{
this.original = original;
}
public U convert(Object input)
{
return original.convert((T) input);
}
}
class ConverterManager {
private Map<Key,Converter<Object,?>> converterRegistry;
ConverterManager()
{
converterRegistry = new HashMap<Key, Converter<Object,?>>();
converterRegistry.put(new Key(String.class, Integer.class),
new ConverterConverter<String, Integer>
(new StringIntegerConverter()));
}
public <T> T convert(Object source, Class<T> toType)
{
Key key = new Key(source.getClass(), toType);
Converter<Object, ?> converter = converterRegistry.get(key);
return (T) converter.convert(source);
}
}
This is messy and it feels like there should be a better way, but it's all I've got at the moment...
精彩评论