001: /*
002: * This file is part of PFIXCORE.
003: *
004: * PFIXCORE is free software; you can redistribute it and/or modify
005: * it under the terms of the GNU Lesser General Public License as published by
006: * the Free Software Foundation; either version 2 of the License, or
007: * (at your option) any later version.
008: *
009: * PFIXCORE is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public License
015: * along with PFIXCORE; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: *
018: */
019:
020: package de.schlund.pfixcore.webservice.jsonws.deserializers;
021:
022: import java.lang.reflect.Field;
023: import java.lang.reflect.Method;
024: import java.lang.reflect.ParameterizedType;
025: import java.lang.reflect.Type;
026: import java.util.HashMap;
027: import java.util.Iterator;
028: import java.util.Map;
029:
030: import de.schlund.pfixcore.beans.BeanDescriptor;
031: import de.schlund.pfixcore.beans.BeanDescriptorFactory;
032: import de.schlund.pfixcore.webservice.json.JSONObject;
033: import de.schlund.pfixcore.webservice.jsonws.DeserializationContext;
034: import de.schlund.pfixcore.webservice.jsonws.DeserializationException;
035: import de.schlund.pfixcore.webservice.jsonws.Deserializer;
036:
037: /**
038: * @author mleidig@schlund.de
039: */
040: public class BeanDeserializer extends Deserializer {
041:
042: BeanDescriptorFactory beanDescFactory;
043:
044: public BeanDeserializer(BeanDescriptorFactory beanDescFactory) {
045: this .beanDescFactory = beanDescFactory;
046: }
047:
048: @Override
049: public boolean canDeserialize(DeserializationContext ctx,
050: Object jsonValue, Type targetType) {
051: if (jsonValue instanceof JSONObject) {
052: JSONObject jsonObj = (JSONObject) jsonValue;
053: Class<?> targetClass = null;
054: if (targetType instanceof Class)
055: targetClass = (Class<?>) targetType;
056: else if (targetType instanceof ParameterizedType) {
057: Type rawType = ((ParameterizedType) targetType)
058: .getRawType();
059: if (rawType instanceof Class)
060: targetClass = (Class<?>) rawType;
061: else
062: return false;
063: }
064: if (Map.class.isAssignableFrom(targetClass))
065: return true;
066: else {
067: String className = jsonObj.getStringMember("javaClass");
068: if (className != null) {
069: try {
070: Class<?> clazz = Class.forName(className);
071: if (targetClass != null
072: && !targetClass.isAssignableFrom(clazz))
073: return false;
074: targetClass = clazz;
075: } catch (ClassNotFoundException x) {
076: return false;
077: }
078: }
079: if (isInstantiable(targetClass))
080: return true;
081: }
082: }
083: return false;
084: }
085:
086: @SuppressWarnings("unchecked")
087: @Override
088: public Object deserialize(DeserializationContext ctx,
089: Object jsonValue, Type targetType)
090: throws DeserializationException {
091:
092: if (jsonValue instanceof JSONObject) {
093:
094: JSONObject jsonObj = (JSONObject) jsonValue;
095:
096: Class<?> targetClass = null;
097: if (targetType instanceof Class)
098: targetClass = (Class<?>) targetType;
099: else if (targetType instanceof ParameterizedType) {
100: Type rawType = ((ParameterizedType) targetType)
101: .getRawType();
102: if (rawType instanceof Class)
103: targetClass = (Class<?>) rawType;
104: else
105: throw new DeserializationException(
106: "Type not supported: " + targetType);
107: }
108:
109: if (Map.class.isAssignableFrom(targetClass)) {
110:
111: Type valType = null;
112: if (targetType instanceof ParameterizedType) {
113: ParameterizedType paramType = (ParameterizedType) targetType;
114: Type[] argTypes = paramType
115: .getActualTypeArguments();
116: if (argTypes.length == 2) {
117: Type keyType = argTypes[0];
118: if (keyType == String.class) {
119: valType = argTypes[1];
120: } else
121: throw new DeserializationException(
122: "Unsupported Map key type (must be java.lang.String): "
123: + keyType);
124: } else
125: throw new DeserializationException(
126: "Type not supported: " + targetType);
127: } else
128: throw new DeserializationException(
129: "Deserialization of unparameterized Map types isn't supported: "
130: + targetType);
131:
132: Map map = null;
133: if (!targetClass.isInterface()) {
134: try {
135: map = (Map) targetClass.newInstance();
136: } catch (Exception x) {
137: }
138: }
139: if (map == null) {
140: if (targetClass.isAssignableFrom(HashMap.class)) {
141: map = new HashMap<Object, Object>();
142: } else
143: throw new DeserializationException(
144: "Can't create instance of class '"
145: + targetClass.getName() + "'.");
146: }
147:
148: Iterator<String> it = jsonObj.getMemberNames();
149: while (it.hasNext()) {
150: String prop = it.next();
151: if (!prop.equals("javaClass")) {
152: Object res = ctx.deserialize(jsonObj
153: .getMember(prop), valType);
154: map.put(prop, res);
155: }
156: }
157:
158: return map;
159:
160: } else {
161:
162: try {
163:
164: String className = jsonObj
165: .getStringMember("javaClass");
166: if (className != null) {
167: Class<?> clazz = Class.forName(className);
168: if (targetClass != null
169: && !targetClass.isAssignableFrom(clazz))
170: throw new DeserializationException(
171: "Class '"
172: + targetClass.getName()
173: + "' isn't assignable from '"
174: + clazz.getName());
175: targetClass = clazz;
176: }
177: BeanDescriptor bd = beanDescFactory
178: .getBeanDescriptor(targetClass);
179:
180: Object newObj = targetClass.newInstance();
181: Iterator<String> it = jsonObj.getMemberNames();
182: while (it.hasNext()) {
183: String prop = it.next();
184: if (!prop.equals("javaClass")) {
185: Type propTargetType = bd
186: .getPropertyType(prop);
187: if (propTargetType != null) {
188: Object val = jsonObj.getMember(prop);
189: Method meth = bd.getSetMethod(prop);
190: if (meth != null) {
191: if (val == null) {
192: meth.invoke(newObj,
193: new Object[] { null });
194: } else {
195: Object res = ctx.deserialize(
196: val, propTargetType);
197: if (res != null)
198: meth.invoke(newObj, res);
199: }
200: } else {
201: Field field = bd
202: .getDirectAccessField(prop);
203: if (field != null) {
204: if (val == null) {
205: field.set(newObj, null);
206: } else {
207: Object res = ctx
208: .deserialize(val,
209: propTargetType);
210: if (res != null)
211: field.set(newObj, res);
212: }
213: } else
214: throw new DeserializationException(
215: "Bean of type '"
216: + targetClass
217: .getName()
218: + "' doesn't "
219: + " have setter method or direct access to property '"
220: + prop + "'.");
221: }
222: } else
223: throw new DeserializationException(
224: "Bean of type '"
225: + targetClass.getName()
226: + "' doesn't have property '"
227: + prop + "'.");
228: }
229: }
230: return newObj;
231: } catch (Exception x) {
232: if (x instanceof DeserializationException)
233: throw (DeserializationException) x;
234: throw new DeserializationException(
235: "Can't deserialize as bean of type '"
236: + targetClass.getName() + "'.", x);
237: }
238: }
239: } else
240: throw new DeserializationException(
241: "No instance of JSONObject: "
242: + jsonValue.getClass().getName());
243:
244: }
245:
246: private boolean isInstantiable(Class<?> clazz) {
247: if (clazz.isInterface())
248: return false;
249: try {
250: clazz.getConstructor(new Class[0]);
251: } catch (NoSuchMethodException x) {
252: return false;
253: }
254: return true;
255: }
256:
257: }
|