You mean if it has a converter from A -> B and B -> C and you ask for a conversion from A -> C, it would figure it out? That's and interesting idea. I guess you'd need to make sure there is no loss of fidelity when doing the conversions.
On Thu, Aug 15, 2013 at 8:00 AM, Gary Gregory <garydgreg...@gmail.com> wrote: > Should the framework try to convert transitively? > > Gary > > On Aug 15, 2013, at 6:56, James Carman <ja...@carmanconsulting.com> wrote: > >> 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 >> <joerg.schai...@scalaris.com> 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: dev-unsubscr...@commons.apache.org >>> For additional commands, e-mail: dev-h...@commons.apache.org >> >> --------------------------------------------------------------------- >> To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org >> For additional commands, e-mail: dev-h...@commons.apache.org >> > > --------------------------------------------------------------------- > To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org > For additional commands, e-mail: dev-h...@commons.apache.org > --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org For additional commands, e-mail: dev-h...@commons.apache.org