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