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    import java.util.Map.Entry;
027    
028    import org.granite.messaging.amf.io.convert.Converter;
029    import org.granite.messaging.amf.io.convert.Converters;
030    import org.granite.messaging.amf.io.convert.IllegalConverterArgumentException;
031    import org.granite.util.TypeUtil;
032    import org.granite.util.MapUtil;
033    
034    /**
035     * @author Franck WOLFF
036     */
037    public class Map2Map extends Converter {
038    
039        public Map2Map(Converters converters) {
040            super(converters);
041        }
042    
043        @Override
044            protected boolean internalCanConvert(Object value, Type targetType) {
045    
046            Type[] targetComponentTypes = MapUtil.getComponentTypes(targetType);
047            if (targetComponentTypes == null)
048                return false; // not a map.
049    
050            if (value == null)
051                return true;
052    
053            if (!(value instanceof Map<?, ?>))
054                return false;
055    
056            Type keyType = targetComponentTypes[0];
057            Type valueType = targetComponentTypes[1];
058    
059            if ((keyType.equals(Object.class) || keyType instanceof WildcardType) &&
060                (valueType.equals(Object.class) || valueType instanceof WildcardType))
061                return true;
062    
063            Converter keyConverter = null;
064            Converter valueConverter = null;
065            for (Map.Entry<?, ?> item : ((Map<?, ?>)value).entrySet()) {
066    
067                if (keyConverter == null)
068                    keyConverter = converters.getConverter(item.getKey(), keyType);
069                else if (!keyConverter.canConvert(item.getKey(), keyType))
070                    keyConverter = converters.getConverter(item.getKey(), keyType);
071                if (keyConverter == null)
072                    return false;
073    
074                if (valueConverter == null)
075                    valueConverter = converters.getConverter(item.getValue(), valueType);
076                else if (!valueConverter.canConvert(item.getValue(), valueType))
077                    valueConverter = converters.getConverter(item.getValue(), valueType);
078                if (valueConverter == null)
079                    return false;
080            }
081    
082            return true;
083        }
084    
085        @Override
086            protected Object internalConvert(Object value, Type targetType) {
087    
088            if (value == null)
089                return null;
090    
091            if (value instanceof Map<?, ?>) {
092                Map<?, ?> map = (Map<?, ?>)value;
093    
094                Type[] targetComponentTypes = MapUtil.getComponentTypes(targetType);
095                if (targetComponentTypes != null) {
096                    Type keyType = targetComponentTypes[0];
097                    Type valueType = targetComponentTypes[1];
098    
099                    Class<?> targetClass = TypeUtil.classOfType(targetType);
100                    if (targetClass.isInstance(value) &&
101                        (keyType.equals(Object.class) || keyType instanceof WildcardType) &&
102                        (valueType.equals(Object.class) || valueType instanceof WildcardType))
103                        return value;
104                    
105                    // Check if all keys and values are compatible
106                    if (targetClass.isInstance(value)) {
107                            Class<?> keyClass = TypeUtil.classOfType(keyType);
108                            Class<?> valueClass = TypeUtil.classOfType(valueType);
109                            
110                            boolean compatible = true;                      
111                            for (Entry<?, ?> entry : ((Map<?, ?>)value).entrySet()) {
112                                    if (!keyClass.isInstance(entry.getKey()) || !valueClass.isInstance(entry.getValue())) {
113                                            compatible = false;
114                                            break;
115                                    }
116                            }
117                            if (compatible)
118                                    return value;
119                    }
120                    
121                    Map<Object, Object> targetInstance = null;
122                    try {
123                        targetInstance = MapUtil.newMap(targetClass, map.size());
124                    } catch (Exception e) {
125                        throw new IllegalConverterArgumentException(this, value, targetType, e);
126                    }
127    
128                    Converter keyConverter = null;
129                    Converter valueConverter = null;
130                    for (Map.Entry<?, ?> item : ((Map<?, ?>)value).entrySet()) {
131    
132                        if (keyConverter == null)
133                            keyConverter = converters.getConverter(item.getKey(), keyType);
134                        else if (!keyConverter.canConvert(item.getKey(), keyType))
135                            keyConverter = converters.getConverter(item.getKey(), keyType);
136                        if (keyConverter == null)
137                            throw new IllegalConverterArgumentException(this, value, targetType);
138    
139                        if (valueConverter == null)
140                            valueConverter = converters.getConverter(item.getValue(), valueType);
141                        else if (!valueConverter.canConvert(item.getValue(), valueType))
142                            valueConverter = converters.getConverter(item.getValue(), valueType);
143                        if (valueConverter == null)
144                            throw new IllegalConverterArgumentException(this, value, targetType);
145    
146                        targetInstance.put(
147                            keyConverter.convert(item.getKey(), keyType),
148                            valueConverter.convert(item.getValue(), valueType)
149                        );
150                    }
151    
152                    return targetInstance;
153                }
154            }
155    
156            throw new IllegalConverterArgumentException(this, value, targetType);
157        }
158    }