I personally think we're over-thinking this thing. Keep it simple, folks:
public interface Converter<F,T>
{
T convert(F from);
}
You can auto-detect the F/T parameters when a Converter is registered.
On Thu, Aug 15, 2013 at 4:42 AM, Jörg Schaible
<[email protected]> wrote:
> Hi,
>
> Emmanuel Bourg wrote:
>
>> Le 14/08/2013 17:39, Adrian Crum a écrit :
>>
>>> Instead of
>>>
>>> int columnInt = record.getValueAsInt(1);
>>>
>>> the developer would use
>>>
>>> Integer columnInt = Util.convertTo(record.getValue(1), Integer.class);
>>
>> +1 for the static method, that would allow the use of a static import
>> and a very concise syntax like:
>>
>> Integer columnInt = to(Integer.class, record.getValue(1));
>>
>>
>> That being said, [convert] could offer several patterns to perform type
>> conversion, and the use of proxies could be one of them.
>
> I never had a look at [convert], but this proposed syntax reminds me
> strongly to an own little framework, where I have following methods in an
> interface to convert strings into arbitrary objects:
>
> ================= %< ==============
> <T> T get(Class<T> type, String key);
> <T> T get(ValueConverter<T> converter, String key);
> ================= %< ==============
>
> The value converter itself is very primitive:
>
> ================= %< ==============
> public interface ValueConverter<T>
> {
> T get(CharSequence value);
> }
> ================= %< ==============
>
> The question is now, how to know about existing converters. I was inspired
> by XStream and use a class ConverterLookup that has following method:
>
> ================= %< ==============
> public <T> ValueConverter<T> lookup(final Class<T> type)
> {
> ValueConverter<?> converter = converterCache.get(type);
> if (converter == null) {
> for (final Iterator<ConverterFactory> iter = converters.iterator();
> converter == null && iter.hasNext();) {
> converter = iter.next().willConvert(type);
> }
>
> synchronized (converterCache) {
> if (converter != null) {
> converterCache.putIfAbsent(type, converter);
> }
> }
> }
>
> @SuppressWarnings("unchecked")
> final ValueConverter<T> checkedConverter = (ValueConverter<T>) converter;
> return checkedConverter;
> }
> ================= %< ==============
>
> I.e. the ConverterLookup has a (priorized) set of ConverterFactory
> implementations that can be requested for a ValueConverter of the given
> type.
>
> The ConverterLookup has additionally one static method "getDefaultLookup()"
> that returns an instance of the ConverterLookup where the set of
> ConverterFactory implementations is detected and instantiated using the Java
> SPI mechanism. That makes it very convenient to add new ConverterFactory
> implementations even to the default ConverterLookup. Therefore the
> implementation of the two get methods is quite simple:
>
> ================= %< ==============
> @Override
> public <T> T get(final Class<T> type, final String key)
> {
> final ValueConverter<T> converter =
> ConverterFactory.getDefaultLookup().lookup(type);
> return get(converter, key);
> }
>
> @Override
> public <T> T get(final ValueConverter<T> converter, final String key)
> {
> final String value = retrieveString(key); // get String to convert
> return converter.get(value);
> }
> ================= %< ==============
>
> You may ask, why there is an additional ConverterFactory to create the
> ValueConverter instances? Actually it can be useful for a converter to
> implement both interfaces:
>
> ================= %< ==============
> public abstract class AbstractFactoryConverter<T> implements
> ValueConverter<T>, ConverterFactory
> {
> private final Class<? super T> type;
> protected AbstractFactoryConverter(final Class<? super T> type)
> {
> this.type = type;
> }
>
> @Override
> public int getPriority()
> {
> return getClass().getAnnotation(Priority.class).value();
> }
>
> @Override
> public ValueConverter<?> willConvert(final Class<?> type)
> {
> return this.type == type ? this : null;
> }
> }
>
> @Priority
> public class StringConverter extends AbstractFactoryConverter<String>
> {
> public StringConverter()
> {
> super(String.class);
> }
>
> @Override
> public String get(final CharSequence value)
> {
> return value == null ? null : value.toString();
> }
> }
> ================= %< ==============
>
> However, to handle types in a generic way, the factory provides a much
> better possibility. See the implementation of my EnumConverterFactory:
>
> ================= %< ==============
> public class EnumConverterFactory implements ConverterFactory
> {
> @Override
> public ValueConverter<?> willConvert(final Class<?> type)
> {
> if (Enum.class.isAssignableFrom(type)) {
> return new ValueConverter<Enum<?>>() {
> @Override
> @SuppressWarnings({"rawtypes", "unchecked"})
> public Enum<?> get(final CharSequence value)
> {
> return Enum.valueOf((Class<Enum>) type, value.toString());
> }
> };
> }
> return null;
> }
>
> @Override
> public int getPriority()
> {
> return Priority.LOW;
> }
> }
> ================= %< ==============
>
> Apart from those factories, I have one for all the primitive types, one for
> arrays and one based on reflection that uses a given type's constructor
> taking a single String. That allows me to write following code for an
> instance 'store' that owns the two get methods above:
>
> ================= %< ==============
> int i = store.get(int.class, "42");
> Long l = store.get(Long.class, "42");
> URL url = store.get(URL.class, "http://www.apache.org/");
> Priority p = store.get(Priority.class, "LOW"); // an enum
> Priority[] pArray = store.get(Priority[].class, "LOW,HIGH");
>
> ValueConverter<URL[].class> converter =
> new ArrayConverterFactory('|').willConvert(URL[].class);
> URL[] urlArray = store.get(converter,
> "http://www.apache.org/|http://commons.apache.org/");
> ================= %< ==============
>
> The code above is a bit simplified (stripped exception handling), but
> the complete stuff contains just 2 interfaces, 1 annotation, one exception
> and 7 classes with not too much code. I always intended to add this to
> [lang] in a package 'converter', when I learned that we have a [convert]
> component. Now I am not sure what to do with it ...
>
> - Jörg
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [email protected]
> For additional commands, e-mail: [email protected]
>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]