Coverage Report - org.dozer.propertydescriptor.MapPropertyDescriptor
 
Classes in this File Line Coverage Branch Coverage Complexity
MapPropertyDescriptor
75%
36/48
68%
22/32
3.889
 
 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.propertydescriptor;
 17  
 
 18  
 import org.dozer.MappingException;
 19  
 import org.dozer.fieldmap.FieldMap;
 20  
 import org.dozer.fieldmap.HintContainer;
 21  
 import org.dozer.util.MappingUtils;
 22  
 import org.dozer.util.ReflectionUtils;
 23  
 
 24  
 import java.lang.ref.SoftReference;
 25  
 import java.lang.reflect.Method;
 26  
 
 27  
 
 28  
 /**
 29  
  * Internal class used to read and write values for Map backed objects that use key/value pairs. The specified "key" is
 30  
  * used when invoking getter/setter. It is assumed that Map setter method has two parameters (for "key" and "value"),
 31  
  * but getter method one parameter (for "key").
 32  
  *
 33  
  * Overloaded methods are supported. Map class can have two set methods with different signatures, but class will
 34  
  * choose the one with appropriate number of parameters.
 35  
  *
 36  
  * <p/>
 37  
  * Only intended for internal use.
 38  
  *
 39  
  * @author garsombke.franz
 40  
  * @author tierney.matt
 41  
  * @author dmitry.buzdin
 42  
  */
 43  
 public class MapPropertyDescriptor extends GetterSetterPropertyDescriptor {
 44  
 
 45  
   private final String setMethodName;
 46  
   private final String getMethodName;
 47  
   private final String key;
 48  
 
 49  
   private SoftReference<Method> writeMethod;
 50  
   private SoftReference<Method> readMethod;
 51  
 
 52  
   public MapPropertyDescriptor(Class<?> clazz, String fieldName, boolean isIndexed, int index, String setMethod, String getMethod,
 53  
                                String key, HintContainer srcDeepIndexHintContainer, HintContainer destDeepIndexHintContainer) {
 54  1369
     super(clazz, fieldName, isIndexed, index, srcDeepIndexHintContainer, destDeepIndexHintContainer);
 55  1369
     this.setMethodName = setMethod;
 56  1369
     this.getMethodName = getMethod;
 57  1369
     this.key = key;
 58  1369
   }
 59  
 
 60  
   @Override
 61  
   public Method getWriteMethod() throws NoSuchMethodException {
 62  1558
     if (MappingUtils.isBlankOrNull(setMethodName)) {
 63  20
       throw new MappingException("Custom Map set method not specified for field mapping to class: " + clazz
 64  
           + ".  Perhaps the map-set-method wasn't specified in the dozer mapping file?");
 65  
     }
 66  1538
     if (writeMethod == null || writeMethod.get() == null) {
 67  1193
       Method method = findMapMethod(clazz, setMethodName, 2);
 68  1192
       writeMethod = new SoftReference<Method>(method);
 69  
     }
 70  1537
     return writeMethod.get();
 71  
   }
 72  
 
 73  
   private Method findMapMethod(Class clazz, String methodName, int parameterCount) {
 74  2541
     Method[] methods = clazz.getMethods();
 75  5759
     for (Method method : methods) {
 76  5758
       if (methodName.equals(method.getName()) && method.getParameterTypes().length == parameterCount) {
 77  2540
         return method;
 78  
       }
 79  
     }
 80  1
     throw new MappingException("No map method found for class:" + clazz + " and method name:" + methodName);
 81  
   }
 82  
 
 83  
   @Override
 84  
   public void setPropertyValue(Object bean, Object value, FieldMap fieldMap) {
 85  345
     if (MappingUtils.isDeepMapping(fieldName)) {
 86  0
       writeDeepDestinationValue(bean, value, fieldMap);
 87  
     } else {
 88  345
       if (!getPropertyType().isPrimitive() || value != null) {
 89  
         // Check if dest value is already set and is equal to src value. If true, no need to rewrite the dest value
 90  
         try {
 91  
           // We should map null values to create a new key in the map
 92  345
           if (value != null && getPropertyValue(bean) == value) {
 93  0
             return;
 94  
           }
 95  0
         } catch (Exception e) {
 96  
           // if we failed to read the value, assume we must write, and continue...
 97  345
         }
 98  345
         invokeWriteMethod(bean, value);
 99  
       }
 100  
     }
 101  345
   }
 102  
 
 103  
   @Override
 104  
   protected Method getReadMethod() throws NoSuchMethodException {
 105  1775
     if (MappingUtils.isBlankOrNull(getMethodName)) {
 106  0
       throw new MappingException("Custom Map get method not specified for field mapping to class: " + clazz
 107  
           + ".  Perhaps the map-get-method wasn't specified in the dozer mapping file?");
 108  
     }
 109  1775
     if (readMethod == null || readMethod.get() == null) {
 110  1348
       Method method = findMapMethod(clazz, getMethodName, 1);
 111  1348
       readMethod = new SoftReference<Method>(method);
 112  
     }
 113  1775
     return readMethod.get();
 114  
   }
 115  
 
 116  
   @Override
 117  
   protected String getSetMethodName() throws NoSuchMethodException {
 118  0
     return setMethodName;
 119  
   }
 120  
 
 121  
   @Override
 122  
   protected boolean isCustomSetMethod() {
 123  0
     return true;
 124  
   }
 125  
 
 126  
   @Override
 127  
   protected void invokeWriteMethod(Object target, Object value) {
 128  345
     if (key == null) {
 129  0
       throw new MappingException("key must be specified");
 130  
     }
 131  
     try {
 132  345
       ReflectionUtils.invoke(getWriteMethod(), target, new Object[]{key, value});
 133  0
     } catch (NoSuchMethodException e) {
 134  0
       MappingUtils.throwMappingException(e);
 135  345
     }
 136  345
   }
 137  
 
 138  
   @Override
 139  
   protected Object invokeReadMethod(Object target) {
 140  563
     if (key == null) {
 141  0
       throw new MappingException("key must be specified");
 142  
     }
 143  563
     Object result = null;
 144  
     try {
 145  563
       result = ReflectionUtils.invoke(getReadMethod(), target, new Object[]{key});
 146  0
     } catch (NoSuchMethodException e) {
 147  0
       MappingUtils.throwMappingException(e);
 148  563
     }
 149  563
     return result;
 150  
   }
 151  
 
 152  
 }