Coverage Report - org.dozer.factory.ConstructionStrategies
 
Classes in this File Line Coverage Branch Coverage Complexity
ConstructionStrategies
87%
14/16
N/A
2.308
ConstructionStrategies$1
N/A
N/A
2.308
ConstructionStrategies$ByConstructor
68%
22/32
66%
4/6
2.308
ConstructionStrategies$ByCreateMethod
100%
20/20
100%
4/4
2.308
ConstructionStrategies$ByFactory
100%
23/23
100%
10/10
2.308
ConstructionStrategies$ByGetInstance
100%
5/5
100%
4/4
2.308
ConstructionStrategies$ByInterface
90%
10/11
91%
11/12
2.308
ConstructionStrategies$XMLBeansBased
83%
15/18
75%
3/4
2.308
ConstructionStrategies$XmlGregorian
75%
6/8
N/A
2.308
 
 1  
 /**
 2  
  * Copyright 2005-2013 Dozer Project
 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.dozer.factory;
 17  
 
 18  
 import org.dozer.BeanFactory;
 19  
 import org.dozer.MappingException;
 20  
 import org.dozer.config.BeanContainer;
 21  
 import org.dozer.util.DozerClassLoader;
 22  
 import org.dozer.util.MappingUtils;
 23  
 import org.dozer.util.ReflectionUtils;
 24  
 import org.slf4j.Logger;
 25  
 import org.slf4j.LoggerFactory;
 26  
 
 27  
 import javax.xml.datatype.DatatypeConfigurationException;
 28  
 import javax.xml.datatype.DatatypeFactory;
 29  
 import javax.xml.datatype.XMLGregorianCalendar;
 30  
 import java.lang.reflect.Constructor;
 31  
 import java.lang.reflect.InvocationTargetException;
 32  
 import java.lang.reflect.Method;
 33  
 import java.text.DateFormat;
 34  
 import java.util.ArrayList;
 35  
 import java.util.Calendar;
 36  
 import java.util.HashMap;
 37  
 import java.util.HashSet;
 38  
 import java.util.List;
 39  
 import java.util.Map;
 40  
 import java.util.Set;
 41  
 import java.util.concurrent.ConcurrentHashMap;
 42  
 import java.util.concurrent.ConcurrentMap;
 43  
 
 44  
 /**
 45  
  * @author Dmitry Buzdin
 46  
  */
 47  0
 public final class ConstructionStrategies {
 48  
 
 49  1
   private static final BeanCreationStrategy byCreateMethod = new ConstructionStrategies.ByCreateMethod();
 50  1
   private static final BeanCreationStrategy byGetInstance = new ConstructionStrategies.ByGetInstance();
 51  1
   private static final BeanCreationStrategy byInterface = new ConstructionStrategies.ByInterface();
 52  1
   private static final BeanCreationStrategy xmlBeansBased = new ConstructionStrategies.XMLBeansBased();
 53  1
   private static final BeanCreationStrategy constructorBased = new ConstructionStrategies.ByConstructor();
 54  1
   private static final ConstructionStrategies.ByFactory byFactory = new ConstructionStrategies.ByFactory();
 55  1
   private static final BeanCreationStrategy xmlGregorianCalendar = new ConstructionStrategies.XmlGregorian();
 56  
 
 57  
   public static BeanCreationStrategy byCreateMethod() {
 58  1
     return byCreateMethod;
 59  
   }
 60  
 
 61  
   public static BeanCreationStrategy byGetInstance() {
 62  1
     return byGetInstance;
 63  
   }
 64  
 
 65  
   public static BeanCreationStrategy byInterface() {
 66  1
     return byInterface;
 67  
   }
 68  
 
 69  
   public static BeanCreationStrategy xmlBeansBased() {
 70  1
     return xmlBeansBased;
 71  
   }
 72  
 
 73  
   public static BeanCreationStrategy byConstructor() {
 74  1
     return constructorBased;
 75  
   }
 76  
 
 77  
   public static ByFactory byFactory() {
 78  1
     return byFactory;
 79  
   }
 80  
 
 81  
   public static BeanCreationStrategy xmlGregorianCalendar() {
 82  1
     return xmlGregorianCalendar;
 83  
   }
 84  
 
 85  34
   static class ByCreateMethod implements BeanCreationStrategy {
 86  
 
 87  
     public boolean isApplicable(BeanCreationDirective directive) {
 88  172958
       String createMethod = directive.getCreateMethod();
 89  172958
       return !MappingUtils.isBlankOrNull(createMethod);
 90  
     }
 91  
 
 92  
     public Object create(BeanCreationDirective directive) {
 93  16
       Class<?> actualClass = directive.getActualClass();
 94  16
       String createMethod = directive.getCreateMethod();
 95  
 
 96  
       Method method;
 97  16
       if (createMethod.contains(".")) {
 98  1
         String methodName = createMethod.substring(createMethod.lastIndexOf(".") + 1, createMethod.length());
 99  1
         String typeName = createMethod.substring(0, createMethod.lastIndexOf("."));
 100  1
         DozerClassLoader loader = BeanContainer.getInstance().getClassLoader();
 101  1
         Class type = loader.loadClass(typeName);
 102  1
         method = findMethod(type, methodName);
 103  1
       } else {
 104  15
         method = findMethod(actualClass, createMethod);
 105  
       }
 106  15
       return ReflectionUtils.invoke(method, null, null);
 107  
     }
 108  
 
 109  
     private Method findMethod(Class<?> actualClass, String createMethod) {
 110  16
       Method method = null;
 111  
       try {
 112  16
         method = ReflectionUtils.getMethod(actualClass, createMethod, null);
 113  1
       } catch (NoSuchMethodException e) {
 114  1
         MappingUtils.throwMappingException(e);
 115  15
       }
 116  15
       return method;
 117  
     }
 118  
 
 119  
   }
 120  
 
 121  17
   static class ByGetInstance extends ByCreateMethod {
 122  
 
 123  
     // TODO Investigate what else could be here
 124  
 
 125  
     @Override
 126  
     public boolean isApplicable(BeanCreationDirective directive) {
 127  172949
       Class<?> actualClass = directive.getActualClass();
 128  172949
       return Calendar.class.isAssignableFrom(actualClass)
 129  
               || DateFormat.class.isAssignableFrom(actualClass);
 130  
     }
 131  
 
 132  
     public Object create(BeanCreationDirective directive) {
 133  5
       directive.setCreateMethod("getInstance");
 134  5
       return super.create(directive);
 135  
     }
 136  
   }
 137  
 
 138  17
   static class ByFactory implements BeanCreationStrategy {
 139  
 
 140  17
     private final Logger log = LoggerFactory.getLogger(ByFactory.class);
 141  
 
 142  17
     private final ConcurrentMap<String, BeanFactory> factoryCache = new ConcurrentHashMap<String, BeanFactory>();
 143  
 
 144  
     public boolean isApplicable(BeanCreationDirective directive) {
 145  172887
       String factoryName = directive.getFactoryName();
 146  172887
       return !MappingUtils.isBlankOrNull(factoryName);
 147  
     }
 148  
 
 149  
     public Object create(BeanCreationDirective directive) {
 150  36
       Class<?> classToCreate = directive.getActualClass();
 151  36
       String factoryName = directive.getFactoryName();
 152  36
       String factoryBeanId = directive.getFactoryId();
 153  
 
 154  
       // By default, use dest object class name for factory bean id
 155  36
       String beanId = !MappingUtils.isBlankOrNull(factoryBeanId) ? factoryBeanId : classToCreate.getName();
 156  
 
 157  36
       BeanFactory factory = factoryCache.get(factoryName);
 158  36
       if (factory == null) {
 159  9
         Class<?> factoryClass = MappingUtils.loadClass(factoryName);
 160  9
         if (!BeanFactory.class.isAssignableFrom(factoryClass)) {
 161  1
           MappingUtils.throwMappingException("Custom bean factory must implement "
 162  
                   + BeanFactory.class.getName() + " interface : " + factoryClass);
 163  
         }
 164  8
         factory = (BeanFactory) ReflectionUtils.newInstance(factoryClass);
 165  
         // put the created factory in our factory map
 166  8
         factoryCache.put(factoryName, factory);
 167  
       }
 168  
 
 169  35
       Object result = factory.createBean(directive.getSrcObject(), directive.getSrcClass(), beanId);
 170  
 
 171  35
       log.debug("Bean instance created with custom factory -->\n  Bean Type: {}\n  Factory Name: {}",
 172  
               result.getClass().getName(), factoryName);
 173  
 
 174  35
       if (!classToCreate.isAssignableFrom(result.getClass())) {
 175  1
         MappingUtils.throwMappingException("Custom bean factory (" + factory.getClass() +
 176  
                 ") did not return correct type of destination data object. Expected : "
 177  
                 + classToCreate + ", Actual : " + result.getClass());
 178  
       }
 179  34
       return result;
 180  
     }
 181  
 
 182  
     public void setStoredFactories(Map<String, BeanFactory> factories) {
 183  1
       this.factoryCache.putAll(factories);
 184  1
     }
 185  
 
 186  
   }
 187  
 
 188  
 
 189  17
   static class ByInterface implements BeanCreationStrategy {
 190  
 
 191  
     public boolean isApplicable(BeanCreationDirective directive) {
 192  172943
       Class<?> actualClass = directive.getActualClass();
 193  172943
       return Map.class.equals(actualClass) || List.class.equals(actualClass) || Set.class.equals(actualClass);
 194  
     }
 195  
 
 196  
     public Object create(BeanCreationDirective directive) {
 197  43
       Class<?> actualClass = directive.getActualClass();
 198  43
       if (Map.class.equals(actualClass)) {
 199  41
         return new HashMap();
 200  2
       } else if (List.class.equals(actualClass)) {
 201  1
         return new ArrayList();
 202  1
       } else if (Set.class.equals(actualClass)) {
 203  1
         return new HashSet();
 204  
       }
 205  0
       throw new IllegalStateException("Type not expected : " + actualClass);
 206  
     }
 207  
 
 208  
   }
 209  
 
 210  
   static class XMLBeansBased implements BeanCreationStrategy {
 211  
 
 212  
     final BeanFactory xmlBeanFactory;
 213  
     boolean xmlBeansAvailable;
 214  
     private Class<?> xmlObjectType;
 215  
 
 216  
     XMLBeansBased() {
 217  1
       this(new XMLBeanFactory());
 218  1
     }
 219  
 
 220  17
     XMLBeansBased(XMLBeanFactory xmlBeanFactory) {
 221  17
       this.xmlBeanFactory = xmlBeanFactory;
 222  
       try {
 223  17
         xmlObjectType = Class.forName("org.apache.xmlbeans.XmlObject");
 224  17
         xmlBeansAvailable = true;
 225  0
       } catch (ClassNotFoundException e) {
 226  0
         xmlBeansAvailable = false;
 227  17
       }
 228  17
     }
 229  
 
 230  
     public boolean isApplicable(BeanCreationDirective directive) {
 231  172899
       if (!xmlBeansAvailable) {
 232  0
         return false;
 233  
       }
 234  172899
       Class<?> actualClass = directive.getActualClass();
 235  172899
       return xmlObjectType.isAssignableFrom(actualClass);
 236  
     }
 237  
 
 238  
     public Object create(BeanCreationDirective directive) {
 239  15
       Class<?> classToCreate = directive.getActualClass();
 240  15
       String factoryBeanId = directive.getFactoryId();
 241  15
       String beanId = !MappingUtils.isBlankOrNull(factoryBeanId) ? factoryBeanId : classToCreate.getName();
 242  15
       return xmlBeanFactory.createBean(directive.getSrcObject(), directive.getSrcClass(), beanId);
 243  
     }
 244  
 
 245  
   }
 246  
 
 247  17
   static class ByConstructor implements BeanCreationStrategy {
 248  
 
 249  
     public boolean isApplicable(BeanCreationDirective directive) {
 250  172853
       return true;
 251  
     }
 252  
 
 253  
     public Object create(BeanCreationDirective directive) {
 254  172855
       Class<?> classToCreate = directive.getActualClass();
 255  
 
 256  
       try {
 257  172855
         return newInstance(classToCreate);
 258  13
       } catch (Exception e) {
 259  13
         if (directive.getAlternateClass() != null) {
 260  12
           return newInstance(directive.getAlternateClass());
 261  
         } else {
 262  1
           MappingUtils.throwMappingException(e);
 263  
         }
 264  
       }
 265  0
       return null;
 266  
     }
 267  
 
 268  
     private static <T> T newInstance(Class<T> clazz) {
 269  
       //Create using public or private no-arg constructor
 270  172867
       Constructor<T> constructor = null;
 271  
       try {
 272  172867
         constructor = clazz.getDeclaredConstructor(null);
 273  0
       } catch (SecurityException e) {
 274  0
         MappingUtils.throwMappingException(e);
 275  7
       } catch (NoSuchMethodException e) {
 276  7
         MappingUtils.throwMappingException(e);
 277  172860
       }
 278  
 
 279  172860
       if (constructor == null) {
 280  0
         MappingUtils.throwMappingException("Could not create a new instance of the dest object: " + clazz
 281  
                 + ".  Could not find a no-arg constructor for this class.");
 282  
       }
 283  
 
 284  
       // If private, make it accessible
 285  172860
       if (!constructor.isAccessible()) {
 286  172860
         constructor.setAccessible(true);
 287  
       }
 288  
 
 289  172860
       T result = null;
 290  
       try {
 291  172860
         result = constructor.newInstance(null);
 292  0
       } catch (IllegalArgumentException e) {
 293  0
         MappingUtils.throwMappingException(e);
 294  10
       } catch (InstantiationException e) {
 295  10
         MappingUtils.throwMappingException(e);
 296  0
       } catch (IllegalAccessException e) {
 297  0
         MappingUtils.throwMappingException(e);
 298  0
       } catch (InvocationTargetException e) {
 299  0
         MappingUtils.throwMappingException(e);
 300  172850
       }
 301  172850
       return result;
 302  
     }
 303  
 
 304  
   }
 305  
 
 306  2
   private static class XmlGregorian implements BeanCreationStrategy {
 307  
 
 308  
     public boolean isApplicable(BeanCreationDirective directive) {
 309  172943
       Class<?> actualClass = directive.getActualClass();
 310  172943
       return XMLGregorianCalendar.class.isAssignableFrom(actualClass);
 311  
     }
 312  
 
 313  
     public Object create(BeanCreationDirective directive) {
 314  
       DatatypeFactory dataTypeFactory;
 315  
       try {
 316  4
         dataTypeFactory = DatatypeFactory.newInstance();
 317  0
       } catch (DatatypeConfigurationException e) {
 318  0
         throw new MappingException(e);
 319  4
       }
 320  4
       return dataTypeFactory.newXMLGregorianCalendar();
 321  
     }
 322  
 
 323  
   }
 324  
 
 325  
 }