Am 15.08.2013 15:33, schrieb James Carman:
> 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.
> 

The problem is that this stuff becomes pretty fast very complex.
Therefore, a strategy could be to handle this in separate layers.

- There would be a core layer providing basic converters from type A to
B. AIUI, this is what [convert] currently has.
- Then there is a layer of handling more complex conversions, e.g. the
transitive stuff and maybe also conversions with collections and arrays
involved. I guess, to implement this layer, you will need a registry and
some more meta data about the converters available.
- Another layer would be an integration layer into custom applications.
Here different patterns could be provided for triggering conversions
with more or less magic.

Oliver

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


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org
For additional commands, e-mail: dev-h...@commons.apache.org

Reply via email to