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 }