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

Reply via email to