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