commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From James Carman <ja...@carmanconsulting.com>
Subject Re: [convert] Automatic conversion based on proxies
Date Thu, 15 Aug 2013 13:33:35 GMT
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 <garydgregory@gmail.com> wrote:
> On Thu, Aug 15, 2013 at 9:09 AM, James Carman <james@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 <garydgregory@gmail.com>
>> wrote:
>> > Should the framework try to convert transitively?
>> >
>> > Gary
>> >
>> > On Aug 15, 2013, at 6:56, James Carman <james@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.Schaible@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-unsubscribe@commons.apache.org
>> >>> For additional commands, e-mail: dev-help@commons.apache.org
>> >>
>> >> ---------------------------------------------------------------------
>> >> To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
>> >> For additional commands, e-mail: dev-help@commons.apache.org
>> >>
>> >
>> > ---------------------------------------------------------------------
>> > To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
>> > For additional commands, e-mail: dev-help@commons.apache.org
>> >
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
>> For additional commands, e-mail: dev-help@commons.apache.org
>>
>>
>
>
> --
> E-Mail: garydgregory@gmail.com | ggregory@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-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org


Mime
View raw message