View Javadoc

1   /*
2    *  Copyright 2003-2004 The Apache Software Foundation
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  package org.apache.commons.convert1;
17  
18  
19  import java.util.Iterator;
20  import java.util.Map;
21  
22  import org.apache.commons.convert1.util.ClassMap;
23  import org.apache.commons.convert1.util.Inheritor;
24  
25  /**
26   * Stores Converters under a dual-key system of fromClass to toClass.
27   * 
28   * @author Henri Yandell
29   * @version $Id: ConvertRegistry.java 155441 2005-02-26 13:19:22Z dirkv $
30   * @since 0.1
31   */
32  
33  public class ConvertRegistry {
34  
35      // ------------------------------------------------------- Class Methods
36  
37      // ------------------------------------------------------- Variables
38  
39  
40      /**
41       * A ClassMap of Class to ClassMap. This then contains 
42       * a Class to {@link Converter} mapping.
43       */
44      private ClassMap converters = new ClassMap();
45  
46      // ------------------------------------------------------- Constructors
47  
48      // TODO: Allow the Inheritor's used by the ClassMap to be set by 
49      //       the user so that different ways of looking up may be used
50      public ConvertRegistry() {
51      }
52  
53      // --------------------------------------------------------- Public Methods
54      
55      // ------------------------------------------------------ Static Properties
56  
57  
58      /**
59       * Convert the specified value into a String.  If the specified value
60       * is an array, the first element (converted to a String) will be
61       * returned.  The registered {@link Converter} for the
62       * <code>java.lang.String</code> class will be used, which allows
63       * applications to customize Object->String conversions (the default
64       * implementation simply uses toString()).
65       *
66       * @param value Value to be converted (may be null)
67       */
68      /*
69      // This whole method appears to be a waste of time. 
70      // It's a way to plugin a StringConverter, but why treat Strings 
71      // in a special way?
72      public String convert(Object value) {
73  
74          if (value == null) {
75              return ((String) null);
76          } else if (value.getClass().isArray()) {
77  
78              //H? This seems bad. String[0] becomes null.
79              //   Why not return String[]??
80              if (Array.getLength(value) < 1) {
81                  return (null);
82              }
83              value = Array.get(value, 0);
84              if (value == null) {
85                  return ((String) null);
86              } else {
87                  Converter converter = lookup(String.class);
88                  return ((String) converter.convert(String.class, value));
89              }
90          } else {
91              Converter converter = lookup(String.class);
92              return ((String) converter.convert(String.class, value));
93          }
94  
95      }
96      */
97  
98  
99      /**
100      * Convert the specified value to an object of the specified class (if
101      * possible).  Otherwise, return a String representation of the value.
102      *
103      * @param value Value to be converted (may be null)
104      * @param clazz Java class to be converted to
105      *
106      * @exception ConversionException if thrown by an underlying Converter
107      */
108     public Object convert(Object value, Class toClass) {
109         //H? If value == null, return null??
110         if(value == null) {
111             return null;
112         }
113 
114         Class fromClass = value.getClass();
115 
116         Converter converter = lookup(value.getClass(), toClass);
117 
118         if (converter == null) {
119             //H? If value.getClass() == toClass, do we auto-return?
120             if(value.getClass() == toClass) {
121                 return value;
122             }
123 
124             Inheritor inh = converters.getInheritor();
125 
126             Iterator itr = inh.iterator();
127 
128             while( itr.hasNext() && converter == null ) {
129                 converter = lookup( value.getClass(), toClass );
130             }
131 
132             //H? Try to treat converter as a Collection concept
133             //   Or should this be a converter of its own? 
134             //   How would it be mapped? To every possible 
135             //   collective type? primitve[], Object[], Collection, 
136             //   Map?
137             //   Yes, this should be a converter.
138 
139             //H? Throw exception?  return null? Treat as String? 
140             //H? How about returning value? Should this be a user choice?
141             if( converter == null ) {
142                 converter = new IdentityConverter();
143             }
144         }
145 
146         //H? Should this check if the returned value is 
147         //   the correct class?
148         return converter.convert(toClass, value);
149 
150     }
151 
152 
153     /**
154      * Convert an array of specified values to an array of objects of the
155      * specified class (if possible).  If the specified Java class is itself
156      * an array class, this class will be the type of the returned value.
157      * Otherwise, an array will be constructed whose component type is the
158      * specified class.
159      *
160      * @param value Value to be converted (may be null)
161      * @param clazz Java array or element class to be converted to
162      *
163      * @exception ConversionException if thrown by an underlying Converter
164      */
165      //H? This method is too specific. It needs to become convertCollective
166      /*
167     public Object convert(String values[], Class clazz) {
168 
169         Class type = clazz;
170         if (clazz.isArray()) {
171             type = clazz.getComponentType();
172         }
173         Converter converter = lookup(type);
174         if (converter == null) {
175             converter = lookup(String.class);
176         }
177         Object array = Array.newInstance(type, values.length);
178         for (int i = 0; i < values.length; i++) {
179             Array.set(array, i, converter.convert(type, values[i]));
180         }
181         return (array);
182 
183     }
184     */
185 
186 
187     /**
188      * Remove all registered {@link Converter}s.
189      */
190     public void clear() {
191 
192 		converters.clear();
193 
194     }
195 
196     /**
197      * Remove any registered {@link Converter} for the specified destination
198      * <code>Class</code>.
199      *
200      * @param clazz Class for which to remove a registered Converter
201      */
202     public void deregister(Class fromClass, Class toClass) {
203 
204         Map map = (Map) converters.get(fromClass);
205         map.remove(toClass);
206 
207     }
208     public void fromClassDeregister(Class fromClass) {
209 
210         converters.remove(fromClass);
211 
212     }
213     public void toClassDeregister(Class toClass) {
214 
215         // loop over every fromClass and remove
216         // a dual indexed map will improve speed
217         Iterator itr = converters.keySet().iterator();
218         while( itr.hasNext() ) {
219             Map map = (Map) itr.next();
220             map.remove(toClass);
221         }
222     }
223 
224     /**
225      * Look up and return any registered {@link Converter} for the specified
226      * destination class; if there is no registered Converter, return
227      * <code>null</code>.
228      *
229      * @param clazz Class for which to return a registered Converter
230      */
231     //H? Should this return an IdentityConverter?
232     public Converter lookup(Class fromClass, Class toClass) {
233 
234         Map map = (Map) converters.get(fromClass);
235 
236         if(map == null) {
237             return null;
238         }
239 
240         Object obj = map.get(toClass);
241 
242         while( obj instanceof ConverterFactory ) {
243             obj = ( (ConverterFactory) obj).create( fromClass, toClass );
244         }
245 
246         //H? check obj is a Converter, or is ClassNotFound good enough?
247 
248         return (Converter) obj;
249 
250     }
251 
252     //H? What to do here? Return a registry with a default fromClass?
253     //H? rename: lookupFromClassRegistry
254     //H? add: lookupToClassRegistry
255 
256 
257     /**
258      * Register a custom {@link Converter} for the specified destination
259      * <code>Class</code>, replacing any previously registered Converter.
260      *
261      * @param converter Converter to be registered
262      * @param clazz Destination class for conversions performed by this
263      *  Converter
264      */
265     public void register(Converter converter, Class fromClass, Class toClass) {
266 
267         Map map = (Map) converters.get(fromClass);
268 
269         if( map == null) {
270             map = new ClassMap();
271             converters.put( fromClass, map );
272         }
273 
274         map.put(toClass, converter);
275 
276     }
277 
278     //H? refactor: registerForFromClass(ConverterRegistry, Class fromClass)
279     //H? refactor: registerForToClass(ConverterRegistry, Class toClass)
280 }