开发者

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...

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜