001    /*
002      GRANITE DATA SERVICES
003      Copyright (C) 2011 GRANITE DATA SERVICES S.A.S.
004    
005      This file is part of Granite Data Services.
006    
007      Granite Data Services is free software; you can redistribute it and/or modify
008      it under the terms of the GNU Library General Public License as published by
009      the Free Software Foundation; either version 2 of the License, or (at your
010      option) any later version.
011    
012      Granite Data Services is distributed in the hope that it will be useful, but
013      WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014      FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
015      for more details.
016    
017      You should have received a copy of the GNU Library General Public License
018      along with this library; if not, see <http://www.gnu.org/licenses/>.
019    */
020    
021    package org.granite.messaging.amf.io.convert.impl;
022    
023    import java.lang.reflect.Type;
024    import java.lang.reflect.WildcardType;
025    import java.util.Map;
026    
027    import org.granite.messaging.amf.io.convert.Converter;
028    import org.granite.messaging.amf.io.convert.Converters;
029    import org.granite.messaging.amf.io.convert.IllegalConverterArgumentException;
030    import org.granite.util.ClassUtil;
031    import org.granite.util.MapUtil;
032    
033    /**
034     * @author Franck WOLFF
035     */
036    public class Map2Map extends Converter {
037    
038        public Map2Map(Converters converters) {
039            super(converters);
040        }
041    
042        @Override
043            protected boolean internalCanConvert(Object value, Type targetType) {
044    
045            Type[] targetComponentTypes = MapUtil.getComponentTypes(targetType);
046            if (targetComponentTypes == null)
047                return false; // not a map.
048    
049            if (value == null)
050                return true;
051    
052            if (!(value instanceof Map<?, ?>))
053                return false;
054    
055            Type keyType = targetComponentTypes[0];
056            Type valueType = targetComponentTypes[1];
057    
058            if ((keyType.equals(Object.class) || keyType instanceof WildcardType) &&
059                (valueType.equals(Object.class) || valueType instanceof WildcardType))
060                return true;
061    
062            Converter keyConverter = null;
063            Converter valueConverter = null;
064            for (Map.Entry<?, ?> item : ((Map<?, ?>)value).entrySet()) {
065    
066                if (keyConverter == null)
067                    keyConverter = converters.getConverter(item.getKey(), keyType);
068                else if (!keyConverter.canConvert(item.getKey(), keyType))
069                    keyConverter = converters.getConverter(item.getKey(), keyType);
070                if (keyConverter == null)
071                    return false;
072    
073                if (valueConverter == null)
074                    valueConverter = converters.getConverter(item.getValue(), valueType);
075                else if (!valueConverter.canConvert(item.getValue(), valueType))
076                    valueConverter = converters.getConverter(item.getValue(), valueType);
077                if (valueConverter == null)
078                    return false;
079            }
080    
081            return true;
082        }
083    
084        @Override
085            protected Object internalConvert(Object value, Type targetType) {
086    
087            if (value == null)
088                return null;
089    
090            if (value instanceof Map<?, ?>) {
091                Map<?, ?> map = (Map<?, ?>)value;
092    
093                Type[] targetComponentTypes = MapUtil.getComponentTypes(targetType);
094                if (targetComponentTypes != null) {
095                    Type keyType = targetComponentTypes[0];
096                    Type valueType = targetComponentTypes[1];
097    
098                    Class<?> targetClass = ClassUtil.classOfType(targetType);
099                    if (targetClass.isInstance(value) &&
100                        (keyType.equals(Object.class) || keyType instanceof WildcardType) &&
101                        (valueType.equals(Object.class) || valueType instanceof WildcardType))
102                        return value;
103    
104                    Map<Object, Object> targetInstance = null;
105                    try {
106                        targetInstance = MapUtil.newMap(targetClass, map.size());
107                    } catch (Exception e) {
108                        throw new IllegalConverterArgumentException(this, value, targetType, e);
109                    }
110    
111                    Converter keyConverter = null;
112                    Converter valueConverter = null;
113                    for (Map.Entry<?, ?> item : ((Map<?, ?>)value).entrySet()) {
114    
115                        if (keyConverter == null)
116                            keyConverter = converters.getConverter(item.getKey(), keyType);
117                        else if (!keyConverter.canConvert(item.getKey(), keyType))
118                            keyConverter = converters.getConverter(item.getKey(), keyType);
119                        if (keyConverter == null)
120                            throw new IllegalConverterArgumentException(this, value, targetType);
121    
122                        if (valueConverter == null)
123                            valueConverter = converters.getConverter(item.getValue(), valueType);
124                        else if (!valueConverter.canConvert(item.getValue(), valueType))
125                            valueConverter = converters.getConverter(item.getValue(), valueType);
126                        if (valueConverter == null)
127                            throw new IllegalConverterArgumentException(this, value, targetType);
128    
129                        targetInstance.put(
130                            keyConverter.convert(item.getKey(), keyType),
131                            valueConverter.convert(item.getValue(), valueType)
132                        );
133                    }
134    
135                    return targetInstance;
136                }
137            }
138    
139            throw new IllegalConverterArgumentException(this, value, targetType);
140        }
141    }