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 }