Coverage Report - org.apache.camel.impl.converter.DefaultTypeConverter
 
Classes in this File Line Coverage Branch Coverage Complexity
DefaultTypeConverter
88% 
97% 
0
 
 1  
 /**
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  *
 9  
  *      http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 package org.apache.camel.impl.converter;
 18  
 
 19  
 import java.io.IOException;
 20  
 import java.util.ArrayList;
 21  
 import java.util.HashMap;
 22  
 import java.util.List;
 23  
 import java.util.Map;
 24  
 import java.util.Set;
 25  
 
 26  
 import org.apache.camel.RuntimeCamelException;
 27  
 import org.apache.camel.TypeConverter;
 28  
 import org.apache.camel.spi.Injector;
 29  
 import org.apache.camel.spi.TypeConverterAware;
 30  
 import org.apache.camel.util.FactoryFinder;
 31  
 import org.apache.camel.util.NoFactoryAvailableException;
 32  
 import org.apache.camel.util.ObjectHelper;
 33  
 import org.apache.commons.logging.Log;
 34  
 import org.apache.commons.logging.LogFactory;
 35  
 
 36  
 /**
 37  
  * @version $Revision: 563607 $
 38  
  */
 39  
 public class DefaultTypeConverter implements TypeConverter, TypeConverterRegistry {
 40  3
     private static final transient Log LOG = LogFactory.getLog(DefaultTypeConverter.class);
 41  351
     private Map<TypeMapping, TypeConverter> typeMappings = new HashMap<TypeMapping, TypeConverter>();
 42  
     private Injector injector;
 43  351
     private List<TypeConverterLoader> typeConverterLoaders = new ArrayList<TypeConverterLoader>();
 44  351
     private List<TypeConverter> fallbackConverters = new ArrayList<TypeConverter>();
 45  
     private boolean loaded;
 46  
 
 47  351
     public DefaultTypeConverter(Injector injector) {
 48  351
         typeConverterLoaders.add(new AnnotationTypeConverterLoader());
 49  351
         this.injector = injector;
 50  351
         addFallbackConverter(new PropertyEditorTypeConverter());
 51  351
         addFallbackConverter(new ToStringTypeConverter());
 52  351
         addFallbackConverter(new ArrayTypeConverter());
 53  351
     }
 54  
 
 55  
     public <T> T convertTo(Class<T> toType, Object value) {
 56  603
         if (toType.isInstance(value)) {
 57  345
             return toType.cast(value);
 58  258
         } else if (toType.isPrimitive()) {
 59  9
             Class primitiveType = ObjectHelper.convertPrimitiveTypeToWrapperType(toType);
 60  9
             if (primitiveType != toType) {
 61  3
                 return (T)convertTo(primitiveType, value);
 62  
             }
 63  
         }
 64  255
         checkLoaded();
 65  255
         TypeConverter converter = getOrFindTypeConverter(toType, value);
 66  255
         if (converter != null) {
 67  168
             return converter.convertTo(toType, value);
 68  
         }
 69  
 
 70  87
         for (TypeConverter fallback : fallbackConverters) {
 71  234
             T rc = fallback.convertTo(toType, value);
 72  234
             if (rc != null) {
 73  30
                 return rc;
 74  
             }
 75  204
         }
 76  
 
 77  
         // lets avoid NullPointerException when converting to boolean for null
 78  
         // values
 79  57
         if (boolean.class.isAssignableFrom(toType)) {
 80  6
             return (T)Boolean.FALSE;
 81  
         }
 82  
 
 83  51
         return null;
 84  
     }
 85  
 
 86  
     public void addTypeConverter(Class toType, Class fromType, TypeConverter typeConverter) {
 87  10152
         TypeMapping key = new TypeMapping(toType, fromType);
 88  10152
         synchronized (typeMappings) {
 89  10152
             TypeConverter converter = typeMappings.get(key);
 90  10152
             if (converter != null) {
 91  0
                 LOG.warn("Overriding type converter from: " + converter + " to: " + typeConverter);
 92  
             }
 93  10152
             typeMappings.put(key, typeConverter);
 94  10152
         }
 95  10152
     }
 96  
 
 97  
     public void addFallbackConverter(TypeConverter converter) {
 98  1053
         fallbackConverters.add(converter);
 99  1053
         if (converter instanceof TypeConverterAware) {
 100  0
             TypeConverterAware typeConverterAware = (TypeConverterAware)converter;
 101  0
             typeConverterAware.setTypeConverter(this);
 102  
         }
 103  1053
     }
 104  
 
 105  
     public TypeConverter getTypeConverter(Class toType, Class fromType) {
 106  228
         TypeMapping key = new TypeMapping(toType, fromType);
 107  228
         synchronized (typeMappings) {
 108  228
             return typeMappings.get(key);
 109  0
         }
 110  
     }
 111  
 
 112  
     public Injector getInjector() {
 113  207
         return injector;
 114  
     }
 115  
 
 116  
     public void setInjector(Injector injector) {
 117  0
         this.injector = injector;
 118  0
     }
 119  
 
 120  
     protected <T> TypeConverter getOrFindTypeConverter(Class toType, Object value) {
 121  255
         Class fromType = null;
 122  255
         if (value != null) {
 123  201
             fromType = value.getClass();
 124  
         }
 125  255
         TypeMapping key = new TypeMapping(toType, fromType);
 126  
         TypeConverter converter;
 127  255
         synchronized (typeMappings) {
 128  255
             converter = typeMappings.get(key);
 129  255
             if (converter == null) {
 130  114
                 converter = findTypeConverter(toType, fromType, value);
 131  114
                 if (converter != null) {
 132  27
                     typeMappings.put(key, converter);
 133  
                 }
 134  
             }
 135  255
         }
 136  255
         return converter;
 137  
     }
 138  
 
 139  
     /**
 140  
      * Tries to auto-discover any available type converters
 141  
      */
 142  
     protected TypeConverter findTypeConverter(Class toType, Class fromType, Object value) {
 143  
         // lets try the super classes of the from type
 144  177
         if (fromType != null) {
 145  123
             Class fromSuperClass = fromType.getSuperclass();
 146  123
             if (fromSuperClass != null && !fromSuperClass.equals(Object.class)) {
 147  
 
 148  63
                 TypeConverter converter = getTypeConverter(toType, fromSuperClass);
 149  63
                 if (converter == null) {
 150  60
                     converter = findTypeConverter(toType, fromSuperClass, value);
 151  
                 }
 152  63
                 if (converter != null) {
 153  30
                     return converter;
 154  
                 }
 155  
             }
 156  240
             for (Class type : fromType.getInterfaces()) {
 157  156
                 TypeConverter converter = getTypeConverter(toType, type);
 158  156
                 if (converter != null) {
 159  9
                     return converter;
 160  
                 }
 161  
             }
 162  
 
 163  
             // lets test for arrays
 164  84
             if (fromType.isArray() && !fromType.getComponentType().isPrimitive()) {
 165  
                 // TODO can we try walking the inheritence-tree for the element
 166  
                 // types?
 167  12
                 if (!fromType.equals(Object[].class)) {
 168  9
                     fromSuperClass = Object[].class;
 169  
 
 170  9
                     TypeConverter converter = getTypeConverter(toType, fromSuperClass);
 171  9
                     if (converter == null) {
 172  3
                         converter = findTypeConverter(toType, fromSuperClass, value);
 173  
                     }
 174  9
                     if (converter != null) {
 175  9
                         return converter;
 176  
                     }
 177  
                 }
 178  
             }
 179  
         }
 180  
 
 181  
         // lets try classes derived from this toType
 182  129
         if (fromType != null) {
 183  75
             Set<Map.Entry<TypeMapping, TypeConverter>> entries = typeMappings.entrySet();
 184  75
             for (Map.Entry<TypeMapping, TypeConverter> entry : entries) {
 185  4986
                 TypeMapping key = entry.getKey();
 186  4986
                 Class aToType = key.getToType();
 187  4986
                 if (toType.isAssignableFrom(aToType)) {
 188  252
                     if (fromType.isAssignableFrom(key.getFromType())) {
 189  9
                         return entry.getValue();
 190  
                     }
 191  
                 }
 192  4977
             }
 193  
         }
 194  
 
 195  
         // TODO look at constructors of toType?
 196  120
         return null;
 197  
     }
 198  
 
 199  
     /**
 200  
      * Checks if the registry is loaded and if not lazily load it
 201  
      */
 202  
     protected synchronized void checkLoaded() {
 203  255
         if (!loaded) {
 204  141
             loaded = true;
 205  
             try {
 206  141
                 for (TypeConverterLoader typeConverterLoader : typeConverterLoaders) {
 207  141
                     typeConverterLoader.load(this);
 208  141
                 }
 209  
 
 210  
                 // lets try load any other failback converters
 211  
                 try {
 212  141
                     loadFallbackTypeConverters();
 213  141
                 } catch (NoFactoryAvailableException e) {
 214  
                     // ignore its fine to have none
 215  0
                 }
 216  0
             } catch (Exception e) {
 217  0
                 throw new RuntimeCamelException(e);
 218  141
             }
 219  
         }
 220  255
     }
 221  
 
 222  
     protected void loadFallbackTypeConverters() throws IOException, ClassNotFoundException {
 223  141
         FactoryFinder finder = new FactoryFinder();
 224  141
         List<TypeConverter> converters = finder.newInstances("FallbackTypeConverter", getInjector(),
 225  
                                                              TypeConverter.class);
 226  0
         for (TypeConverter converter : converters) {
 227  0
             addFallbackConverter(converter);
 228  0
         }
 229  0
     }
 230  
 
 231  
     /**
 232  
      * Represents a mapping from one type (which can be null) to another
 233  
      */
 234  
     protected static class TypeMapping {
 235  
         Class toType;
 236  
         Class fromType;
 237  
 
 238  10635
         public TypeMapping(Class toType, Class fromType) {
 239  10635
             this.toType = toType;
 240  10635
             this.fromType = fromType;
 241  10635
         }
 242  
 
 243  
         public Class getFromType() {
 244  252
             return fromType;
 245  
         }
 246  
 
 247  
         public Class getToType() {
 248  4986
             return toType;
 249  
         }
 250  
 
 251  
         @Override
 252  
         public boolean equals(Object object) {
 253  159
             if (object instanceof TypeMapping) {
 254  159
                 TypeMapping that = (TypeMapping)object;
 255  159
                 return ObjectHelper.equals(this.fromType, that.fromType)
 256  
                        && ObjectHelper.equals(this.toType, that.toType);
 257  
             }
 258  0
             return false;
 259  
         }
 260  
 
 261  
         @Override
 262  
         public int hashCode() {
 263  20814
             int answer = toType.hashCode();
 264  20814
             if (fromType != null) {
 265  20760
                 answer *= 37 + fromType.hashCode();
 266  
             }
 267  20814
             return answer;
 268  
         }
 269  
 
 270  
         @Override
 271  
         public String toString() {
 272  0
             return "[" + fromType + "=>" + toType + "]";
 273  
         }
 274  
     }
 275  
 }