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