Coverage Report - org.dozer.loader.MappingsParser
 
Classes in this File Line Coverage Branch Coverage Complexity
MappingsParser
98%
65/66
94%
47/50
10.333
 
 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.loader;
 17  
 
 18  
 import org.dozer.classmap.ClassMap;
 19  
 import org.dozer.classmap.ClassMappings;
 20  
 import org.dozer.classmap.Configuration;
 21  
 import org.dozer.classmap.MappingDirection;
 22  
 import org.dozer.fieldmap.DozerField;
 23  
 import org.dozer.fieldmap.ExcludeFieldMap;
 24  
 import org.dozer.fieldmap.FieldMap;
 25  
 import org.dozer.fieldmap.GenericFieldMap;
 26  
 import org.dozer.fieldmap.MapFieldMap;
 27  
 import org.dozer.util.DozerConstants;
 28  
 import org.dozer.util.MappingUtils;
 29  
 import org.dozer.util.ReflectionUtils;
 30  
 
 31  
 import java.util.HashSet;
 32  
 import java.util.Iterator;
 33  
 import java.util.List;
 34  
 import java.util.Set;
 35  
 
 36  
 import static org.dozer.util.MappingUtils.isSupportedMap;
 37  
 
 38  
 /**
 39  
  * Internal class that decorates raw ClassMap objects and performs various validations on the explicit field mappings.
 40  
  * It applies global configuration and class level attributes to raw class mappings. It also creates the ClassMap
 41  
  * "prime" instance for bi-directional mappings. The ClassMap prime is created by copying the original ClassMap and
 42  
  * reversing the attributes. Only intended for internal use.
 43  
  * 
 44  
  * @author garsombke.franz
 45  
  */
 46  
 public final class MappingsParser {
 47  
 
 48  1
   private static final MappingsParser INSTANCE = new MappingsParser();
 49  
 
 50  
   public static MappingsParser getInstance() {
 51  5
     return INSTANCE;
 52  
   }
 53  
 
 54  1
   private MappingsParser() {
 55  1
   }
 56  
 
 57  
   /**
 58  
    * Decorates raw ClassMap objects and performs various validations on the explicit field mappings.
 59  
    * It applies global configuration and class level attributes to raw class mappings.
 60  
    * @param classMaps Input class maps.
 61  
    * @param globalConfiguration Global configuration.
 62  
    * @return Resulting class mappings.
 63  
    */
 64  
   public ClassMappings processMappings(List<ClassMap> classMaps, Configuration globalConfiguration) {
 65  623
     if (globalConfiguration == null) {
 66  0
       throw new IllegalArgumentException("Global configuration parameter cannot be null");
 67  
     }
 68  623
     ClassMappings result = new ClassMappings();
 69  623
     if (classMaps == null || classMaps.size() == 0) {
 70  21
       return result;
 71  
     }
 72  
     FieldMap fieldMapPrime;
 73  
     // need to create bi-directional mappings now.
 74  
     ClassMap classMapPrime;
 75  602
     Set<String> mapIds = new HashSet<String>();
 76  602
     for (ClassMap classMap : classMaps) {
 77  5401
       classMap.setGlobalConfiguration(globalConfiguration);
 78  
 
 79  
       // add our first class map to the result map and initialize PropertyDescriptor Cache
 80  5401
       ReflectionUtils.findPropertyDescriptor(classMap.getSrcClassToMap(), "", null);
 81  5401
       ReflectionUtils.findPropertyDescriptor(classMap.getDestClassToMap(), "", null);
 82  
 
 83  
       // Check to see if this is a duplicate map id, irregardless of src and dest class names. 
 84  
       // Duplicate map-ids are not allowed
 85  5401
       if (!MappingUtils.isBlankOrNull(classMap.getMapId())) {
 86  667
         if (mapIds.contains(classMap.getMapId())) {
 87  1
           throw new IllegalArgumentException("Duplicate Map Id's Found. Map Id: " + classMap.getMapId());
 88  
         }
 89  666
         mapIds.add(classMap.getMapId());
 90  
       }
 91  
 
 92  5400
       result.add(classMap.getSrcClassToMap(), classMap.getDestClassToMap(), classMap.getMapId(), classMap);
 93  
       // now create class map prime
 94  5398
       classMapPrime = new ClassMap(globalConfiguration);
 95  5398
       MappingUtils.reverseFields(classMap, classMapPrime);
 96  
 
 97  5398
       if (classMap.getFieldMaps() != null) {
 98  5398
         List<FieldMap> fms = classMap.getFieldMaps();
 99  
         // iterate through the fields and see wether or not they should be mapped
 100  
         // one way class mappings we do not need to add any fields
 101  5398
         if (!MappingDirection.ONE_WAY.equals(classMap.getType())) {
 102  18821
           for (FieldMap fieldMap : fms.toArray(new FieldMap[]{})) {
 103  13596
             fieldMap.validate();
 104  
 
 105  
             // If we are dealing with a Map data type, transform the field map into a MapFieldMap type
 106  
             // only apply transformation if it is map to non-map mapping.
 107  13596
             if (!(fieldMap instanceof ExcludeFieldMap)) {
 108  12782
               if ( ( isSupportedMap(classMap.getDestClassToMap()) ^ isSupportedMap(classMap.getSrcClassToMap()) )
 109  
                || ( isSupportedMap(fieldMap.getDestFieldType(classMap.getDestClassToMap()))
 110  
                     ^ isSupportedMap(fieldMap.getSrcFieldType(classMap.getSrcClassToMap())) ) ) {
 111  1277
                 FieldMap fm = new MapFieldMap(fieldMap);
 112  1277
                 classMap.removeFieldMapping(fieldMap);
 113  1277
                 classMap.addFieldMapping(fm);
 114  1277
                 fieldMap = fm;
 115  
               }
 116  
             }
 117  
             
 118  
             // if the source is a java.util.Map, and not already mapped as key=>value,
 119  
             // map the field as key=>value, not as bean property
 120  13592
             if (isSupportedMap(classMap.getSrcClassToMap()) && fieldMap.getSrcFieldKey() == null) {
 121  134
               DozerField newSrcField = fieldMap.getSrcFieldCopy();
 122  134
               newSrcField.setName(DozerConstants.SELF_KEYWORD);
 123  134
               newSrcField.setKey(fieldMap.getSrcFieldName());
 124  134
               fieldMap.setSrcField(newSrcField);
 125  
             }
 126  
             // like above but the reverse: 
 127  
             // if the destination is a java.util.Map, and not already mapped as key=>value,
 128  
             // map the field as key=>value, not as bean property
 129  13592
             if (isSupportedMap(classMap.getDestClassToMap()) && fieldMap.getDestFieldKey() == null) {
 130  117
               DozerField newDestField = fieldMap.getDestFieldCopy();
 131  117
               newDestField.setName(DozerConstants.SELF_KEYWORD);
 132  117
               newDestField.setKey(fieldMap.getDestFieldName());
 133  117
               fieldMap.setDestField(newDestField);
 134  
             }
 135  
 
 136  13592
             if (!(MappingDirection.ONE_WAY.equals(fieldMap.getType()) && !(fieldMap instanceof ExcludeFieldMap))) {
 137  
               // make a prime field map
 138  13040
               fieldMapPrime = (FieldMap) fieldMap.clone();
 139  13040
               fieldMapPrime.setClassMap(classMapPrime);
 140  
               // check to see if it is only an exclude one way
 141  13040
               if (fieldMapPrime instanceof ExcludeFieldMap && MappingDirection.ONE_WAY.equals(fieldMap.getType())) {
 142  
                 // need to make a generic field map for the other direction
 143  108
                 fieldMapPrime = new GenericFieldMap(classMapPrime);
 144  
               }
 145  
               // reverse the fields
 146  13040
               MappingUtils.reverseFields(fieldMap, fieldMapPrime);
 147  
 
 148  
               // iterate through copyByReferences and set accordingly
 149  13040
               if (!(fieldMap instanceof ExcludeFieldMap)) {
 150  12226
                 MappingUtils.applyGlobalCopyByReference(globalConfiguration, fieldMap, classMap);
 151  
               }
 152  13040
               if (!(fieldMapPrime instanceof ExcludeFieldMap)) {
 153  12334
                 MappingUtils.applyGlobalCopyByReference(globalConfiguration, fieldMapPrime, classMapPrime);
 154  
               }
 155  
             } else { // if it is a one-way field map make the other field map excluded
 156  
               // make a prime field map
 157  552
               fieldMapPrime = new ExcludeFieldMap(classMapPrime);
 158  552
               MappingUtils.reverseFields(fieldMap, fieldMapPrime);
 159  
             }
 160  13592
             classMapPrime.addFieldMapping(fieldMapPrime);
 161  
           }
 162  
         } else {
 163  
           // since it is one-way...we still need to validate if it has some type of method mapping and validate the
 164  
           // field maps
 165  642
           for (FieldMap oneWayFieldMap : fms.toArray(new FieldMap[]{})) {
 166  473
             oneWayFieldMap.validate();
 167  
 
 168  473
             MappingUtils.applyGlobalCopyByReference(globalConfiguration, oneWayFieldMap, classMap);
 169  
             // check to see if we need to exclude the map
 170  473
             if (MappingDirection.ONE_WAY.equals(oneWayFieldMap.getType())) {
 171  1
               fieldMapPrime = new ExcludeFieldMap(classMapPrime);
 172  1
               MappingUtils.reverseFields(oneWayFieldMap, fieldMapPrime);
 173  1
               classMapPrime.addFieldMapping(fieldMapPrime);
 174  
             }
 175  
           }
 176  
         }
 177  
       }
 178  
       // if it is a one way mapping or a method/iterate method mapping we can not bi-directionally map
 179  
       // Map Prime could actually be empty
 180  5394
       if (!MappingDirection.ONE_WAY.equals(classMap.getType())) {
 181  5225
         result.add(classMap.getDestClassToMap(), classMap.getSrcClassToMap(), classMap.getMapId(), classMapPrime);
 182  
       }
 183  5394
     }
 184  595
     return result;
 185  
   }
 186  
 
 187  
 }