Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
ConvertRegistry |
|
| 2.5;2.5 |
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 | 0 | 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 | 0 | public ConvertRegistry() { |
51 | 0 | } |
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 | 0 | if(value == null) { |
111 | 0 | return null; |
112 | } | |
113 | ||
114 | 0 | Class fromClass = value.getClass(); |
115 | ||
116 | 0 | Converter converter = lookup(value.getClass(), toClass); |
117 | ||
118 | 0 | if (converter == null) { |
119 | //H? If value.getClass() == toClass, do we auto-return? | |
120 | 0 | if(value.getClass() == toClass) { |
121 | 0 | return value; |
122 | } | |
123 | ||
124 | 0 | Inheritor inh = converters.getInheritor(); |
125 | ||
126 | 0 | Iterator itr = inh.iterator(); |
127 | ||
128 | 0 | while( itr.hasNext() && converter == null ) { |
129 | 0 | 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 | 0 | if( converter == null ) { |
142 | 0 | converter = new IdentityConverter(); |
143 | } | |
144 | } | |
145 | ||
146 | //H? Should this check if the returned value is | |
147 | // the correct class? | |
148 | 0 | 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 | 0 | converters.clear(); |
193 | ||
194 | 0 | } |
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 | 0 | Map map = (Map) converters.get(fromClass); |
205 | 0 | map.remove(toClass); |
206 | ||
207 | 0 | } |
208 | public void fromClassDeregister(Class fromClass) { | |
209 | ||
210 | 0 | converters.remove(fromClass); |
211 | ||
212 | 0 | } |
213 | public void toClassDeregister(Class toClass) { | |
214 | ||
215 | // loop over every fromClass and remove | |
216 | // a dual indexed map will improve speed | |
217 | 0 | Iterator itr = converters.keySet().iterator(); |
218 | 0 | while( itr.hasNext() ) { |
219 | 0 | Map map = (Map) itr.next(); |
220 | 0 | map.remove(toClass); |
221 | 0 | } |
222 | 0 | } |
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 | 0 | Map map = (Map) converters.get(fromClass); |
235 | ||
236 | 0 | if(map == null) { |
237 | 0 | return null; |
238 | } | |
239 | ||
240 | 0 | Object obj = map.get(toClass); |
241 | ||
242 | 0 | while( obj instanceof ConverterFactory ) { |
243 | 0 | obj = ( (ConverterFactory) obj).create( fromClass, toClass ); |
244 | } | |
245 | ||
246 | //H? check obj is a Converter, or is ClassNotFound good enough? | |
247 | ||
248 | 0 | 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 | 0 | Map map = (Map) converters.get(fromClass); |
268 | ||
269 | 0 | if( map == null) { |
270 | 0 | map = new ClassMap(); |
271 | 0 | converters.put( fromClass, map ); |
272 | } | |
273 | ||
274 | 0 | map.put(toClass, converter); |
275 | ||
276 | 0 | } |
277 | ||
278 | //H? refactor: registerForFromClass(ConverterRegistry, Class fromClass) | |
279 | //H? refactor: registerForToClass(ConverterRegistry, Class toClass) | |
280 | } |