Perhaps you'd have a different method on the "registry" like this:
Converter<F,T> createConverterPath(Class<F> fromType, Class<T> toType); This way, you're specifically letting the registry know that you're okay with it filling in the blanks in between fromType and toType. On Thu, Aug 15, 2013 at 9:24 AM, Gary Gregory <garydgreg...@gmail.com> wrote: > On Thu, Aug 15, 2013 at 9:09 AM, James Carman > <ja...@carmanconsulting.com>wrote: > >> 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. >> > > Yes, and be careful of the shortest path too: > > I can have: > > String -> Long > String -> Date > Date -> Long > > So when I ask for String -> Long, I do not want String -> Date -> Long! > > I have something like this at work I use for for (complex) objects. > > The other aspect is caching, let's say I have a Customer and I want to > convert it to XML and JSON, I want to cache the results of the conversion > and invalidate that cache if I change the customer. Is that out of scope? I > would be some kind of project object that holds on to a Customer, a JSON > string, and an XML document (both bytes and String). > > Gary > > >> >> >> 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 >> >> > > > -- > E-Mail: garydgreg...@gmail.com | ggreg...@apache.org > Java Persistence with Hibernate, Second > Edition<http://www.manning.com/bauer3/> > JUnit in Action, Second Edition <http://www.manning.com/tahchiev/> > Spring Batch in Action <http://www.manning.com/templier/> > Blog: http://garygregory.wordpress.com > Home: http://garygregory.com/ > Tweet! http://twitter.com/GaryGregory --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org For additional commands, e-mail: dev-h...@commons.apache.org