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