1 /*
2    D-Bus Java Implementation
3    Copyright (c) 2005-2006 Matthew Johnson
4 
5    This program is free software; you can redistribute it and/or modify it
6    under the terms of either the GNU Lesser General Public License Version 2 or the
7    Academic Free Licence Version 2.1.
8 
9    Full licence texts are included in the COPYING file with this program.
10 */
11 package org.freedesktop.dbus;
12 
13 import static org.freedesktop.dbus.Gettext._;
14 
15 import java.lang.reflect.Array;
16 import java.lang.reflect.Constructor;
17 import java.lang.reflect.Field;
18 import java.lang.reflect.GenericArrayType;
19 import java.lang.reflect.Method;
20 import java.lang.reflect.ParameterizedType;
21 import java.lang.reflect.Type;
22 import java.lang.reflect.TypeVariable;
23 import java.text.MessageFormat;
24 import java.util.Arrays;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Vector;
29 
30 import org.freedesktop.dbus.exceptions.DBusException;
31 import org.freedesktop.dbus.types.DBusListType;
32 import org.freedesktop.dbus.types.DBusMapType;
33 import org.freedesktop.dbus.types.DBusStructType;
34 
35 import cx.ath.matthew.debug.Debug;
36 
37 /**
38  * Contains static methods for marshalling values.
39  */
40 public class Marshalling
41 {
42    private static Map<Type, String[]> typeCache = new HashMap<Type, String[]>();
43    /**
44     * Will return the DBus type corresponding to the given Java type.
45     * Note, container type should have their ParameterizedType not their
46     * Class passed in here.
47     * @param c The Java types.
48     * @return The DBus types.
49     * @throws DBusException If the given type cannot be converted to a DBus type.
50     */
getDBusType(Type[] c)51    public static String getDBusType(Type[] c) throws DBusException
52    {
53       StringBuffer sb = new StringBuffer();
54       for (Type t: c)
55          for (String s: getDBusType(t))
56             sb.append(s);
57       return sb.toString();
58    }
59    /**
60     * Will return the DBus type corresponding to the given Java type.
61     * Note, container type should have their ParameterizedType not their
62     * Class passed in here.
63     * @param c The Java type.
64     * @return The DBus type.
65     * @throws DBusException If the given type cannot be converted to a DBus type.
66     */
getDBusType(Type c)67    public static String[] getDBusType(Type c) throws DBusException
68    {
69       String[] cached = typeCache.get(c);
70       if (null != cached) return cached;
71       cached = getDBusType(c, false);
72       typeCache.put(c, cached);
73       return cached;
74    }
75    /**
76     * Will return the DBus type corresponding to the given Java type.
77     * Note, container type should have their ParameterizedType not their
78     * Class passed in here.
79     * @param c The Java type.
80     * @param basic If true enforces this to be a non-compound type. (compound types are Maps, Structs and Lists/arrays).
81     * @return The DBus type.
82     * @throws DBusException If the given type cannot be converted to a DBus type.
83     */
getDBusType(Type c, boolean basic)84    public static String[] getDBusType(Type c, boolean basic) throws DBusException
85    {
86       return recursiveGetDBusType(c, basic, 0);
87    }
88    private static StringBuffer[] out = new StringBuffer[10];
89    @SuppressWarnings("unchecked")
recursiveGetDBusType(Type c, boolean basic, int level)90    public static String[] recursiveGetDBusType(Type c, boolean basic, int level) throws DBusException
91    {
92       if (out.length <= level) {
93          StringBuffer[] newout = new StringBuffer[out.length];
94          System.arraycopy(out, 0, newout, 0, out.length);
95          out = newout;
96       }
97       if (null == out[level]) out[level] = new StringBuffer();
98       else out[level].delete(0, out[level].length());
99 
100       if (basic && !(c instanceof Class))
101          throw new DBusException(c+_(" is not a basic type"));
102 
103       if (c instanceof TypeVariable) out[level].append((char) Message.ArgumentType.VARIANT);
104       else if (c instanceof GenericArrayType) {
105          out[level].append((char) Message.ArgumentType.ARRAY);
106          String[] s = recursiveGetDBusType(((GenericArrayType) c).getGenericComponentType(), false, level+1);
107          if (s.length != 1) throw new DBusException(_("Multi-valued array types not permitted"));
108          out[level].append(s[0]);
109       } else if ((c instanceof Class &&
110                DBusSerializable.class.isAssignableFrom((Class<? extends Object>) c)) ||
111             (c instanceof ParameterizedType &&
112              DBusSerializable.class.isAssignableFrom((Class<? extends Object>) ((ParameterizedType) c).getRawType()))) {
113          // it's a custom serializable type
114          Type[] newtypes = null;
115          if (c instanceof Class)  {
116             for (Method m: ((Class<? extends Object>) c).getDeclaredMethods())
117                if (m.getName().equals("deserialize"))
118                   newtypes = m.getGenericParameterTypes();
119          }
120          else
121             for (Method m: ((Class<? extends Object>) ((ParameterizedType) c).getRawType()).getDeclaredMethods())
122                if (m.getName().equals("deserialize"))
123                   newtypes = m.getGenericParameterTypes();
124 
125          if (null == newtypes) throw new DBusException(_("Serializable classes must implement a deserialize method"));
126 
127          String[] sigs = new String[newtypes.length];
128          for (int j = 0; j < sigs.length; j++) {
129             String[] ss = recursiveGetDBusType(newtypes[j], false, level+1);
130             if (1 != ss.length) throw new DBusException(_("Serializable classes must serialize to native DBus types"));
131             sigs[j] = ss[0];
132          }
133          return sigs;
134       }
135       else if (c instanceof ParameterizedType) {
136          ParameterizedType p = (ParameterizedType) c;
137          if (p.getRawType().equals(Map.class)) {
138             out[level].append("a{");
139             Type[] t = p.getActualTypeArguments();
140             try {
141                String[] s = recursiveGetDBusType(t[0], true, level+1);
142                if (s.length != 1) throw new DBusException(_("Multi-valued array types not permitted"));
143                out[level].append(s[0]);
144                s = recursiveGetDBusType(t[1], false, level+1);
145                if (s.length != 1) throw new DBusException(_("Multi-valued array types not permitted"));
146                out[level].append(s[0]);
147             } catch (ArrayIndexOutOfBoundsException AIOOBe) {
148                if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, AIOOBe);
149                throw new DBusException(_("Map must have 2 parameters"));
150             }
151             out[level].append('}');
152          }
153          else if (List.class.isAssignableFrom((Class<? extends Object>) p.getRawType())) {
154             for (Type t: p.getActualTypeArguments()) {
155                if (Type.class.equals(t))
156                   out[level].append((char) Message.ArgumentType.SIGNATURE);
157                else {
158                   String[] s = recursiveGetDBusType(t, false, level+1);
159                   if (s.length != 1) throw new DBusException(_("Multi-valued array types not permitted"));
160                   out[level].append((char) Message.ArgumentType.ARRAY);
161                   out[level].append(s[0]);
162                }
163             }
164          }
165          else if (p.getRawType().equals(Variant.class)) {
166             out[level].append((char) Message.ArgumentType.VARIANT);
167          }
168          else if (DBusInterface.class.isAssignableFrom((Class<? extends Object>) p.getRawType())) {
169             out[level].append((char) Message.ArgumentType.OBJECT_PATH);
170          }
171          else if (Tuple.class.isAssignableFrom((Class<? extends Object>) p.getRawType())) {
172             Type[] ts = p.getActualTypeArguments();
173             Vector<String> vs = new Vector<String>();
174             for (Type t: ts)
175                for (String s: recursiveGetDBusType(t, false, level+1))
176                   vs.add(s);
177             return vs.toArray(new String[0]);
178          }
179          else
180             throw new DBusException(_("Exporting non-exportable parameterized type ")+c);
181       }
182 
183       else if (c.equals(Byte.class)) out[level].append((char) Message.ArgumentType.BYTE);
184       else if (c.equals(Byte.TYPE)) out[level].append((char) Message.ArgumentType.BYTE);
185       else if (c.equals(Boolean.class)) out[level].append((char) Message.ArgumentType.BOOLEAN);
186       else if (c.equals(Boolean.TYPE)) out[level].append((char) Message.ArgumentType.BOOLEAN);
187       else if (c.equals(Short.class)) out[level].append((char) Message.ArgumentType.INT16);
188       else if (c.equals(Short.TYPE)) out[level].append((char) Message.ArgumentType.INT16);
189       else if (c.equals(UInt16.class)) out[level].append((char) Message.ArgumentType.UINT16);
190       else if (c.equals(Integer.class)) out[level].append((char) Message.ArgumentType.INT32);
191       else if (c.equals(Integer.TYPE)) out[level].append((char) Message.ArgumentType.INT32);
192       else if (c.equals(UInt32.class)) out[level].append((char) Message.ArgumentType.UINT32);
193       else if (c.equals(Long.class)) out[level].append((char) Message.ArgumentType.INT64);
194       else if (c.equals(Long.TYPE)) out[level].append((char) Message.ArgumentType.INT64);
195       else if (c.equals(UInt64.class)) out[level].append((char) Message.ArgumentType.UINT64);
196       else if (c.equals(Double.class)) out[level].append((char) Message.ArgumentType.DOUBLE);
197       else if (c.equals(Double.TYPE)) out[level].append((char) Message.ArgumentType.DOUBLE);
198       else if (c.equals(Float.class) && AbstractConnection.FLOAT_SUPPORT) out[level].append((char) Message.ArgumentType.FLOAT);
199       else if (c.equals(Float.class)) out[level].append((char) Message.ArgumentType.DOUBLE);
200       else if (c.equals(Float.TYPE) && AbstractConnection.FLOAT_SUPPORT) out[level].append((char) Message.ArgumentType.FLOAT);
201       else if (c.equals(Float.TYPE)) out[level].append((char) Message.ArgumentType.DOUBLE);
202       else if (c.equals(String.class)) out[level].append((char) Message.ArgumentType.STRING);
203       else if (c.equals(Variant.class)) out[level].append((char) Message.ArgumentType.VARIANT);
204       else if (c instanceof Class &&
205             DBusInterface.class.isAssignableFrom((Class<? extends Object>) c)) out[level].append((char) Message.ArgumentType.OBJECT_PATH);
206       else if (c instanceof Class &&
207             Path.class.equals((Class<? extends Object>) c)) out[level].append((char) Message.ArgumentType.OBJECT_PATH);
208       else if (c instanceof Class &&
209             ObjectPath.class.equals((Class<? extends Object>) c)) out[level].append((char) Message.ArgumentType.OBJECT_PATH);
210       else if (c instanceof Class &&
211             ((Class<? extends Object>) c).isArray()) {
212          if (Type.class.equals(((Class<? extends Object>) c).getComponentType()))
213             out[level].append((char) Message.ArgumentType.SIGNATURE);
214          else {
215             out[level].append((char) Message.ArgumentType.ARRAY);
216             String[] s = recursiveGetDBusType(((Class<? extends Object>) c).getComponentType(), false, level+1);
217             if (s.length != 1) throw new DBusException(_("Multi-valued array types not permitted"));
218             out[level].append(s[0]);
219          }
220       } else if (c instanceof Class &&
221             Struct.class.isAssignableFrom((Class<? extends Object>) c)) {
222          out[level].append((char) Message.ArgumentType.STRUCT1);
223          Type[] ts = Container.getTypeCache(c);
224          if (null == ts) {
225             Field[] fs = ((Class<? extends Object>) c).getDeclaredFields();
226             ts = new Type[fs.length];
227             for (Field f : fs) {
228                Position p = f.getAnnotation(Position.class);
229                if (null == p) continue;
230                ts[p.value()] = f.getGenericType();
231            }
232             Container.putTypeCache(c, ts);
233          }
234 
235          for (Type t: ts)
236             if (t != null)
237                for (String s: recursiveGetDBusType(t, false, level+1))
238                   out[level].append(s);
239          out[level].append(')');
240       } else {
241          throw new DBusException(_("Exporting non-exportable type ")+c);
242       }
243 
244       if (Debug.debug) Debug.print(Debug.VERBOSE, "Converted Java type: "+c+" to D-Bus Type: "+out[level]);
245 
246       return new String[] { out[level].toString() };
247    }
248 
249    /**
250     * Converts a dbus type string into Java Type objects,
251     * @param dbus The DBus type or types.
252     * @param rv Vector to return the types in.
253     * @param limit Maximum number of types to parse (-1 == nolimit).
254     * @return number of characters parsed from the type string.
255     */
getJavaType(String dbus, List<Type> rv, int limit)256    public static int getJavaType(String dbus, List<Type> rv, int limit) throws DBusException
257    {
258       if (null == dbus || "".equals(dbus) || 0 == limit) return 0;
259 
260       try {
261          int i = 0;
262          for (; i < dbus.length() && (-1 == limit || limit > rv.size()); i++)
263             switch(dbus.charAt(i)) {
264                case Message.ArgumentType.STRUCT1:
265                   int j = i+1;
266                   for (int c = 1; c > 0; j++) {
267                      if (')' == dbus.charAt(j)) c--;
268                      else if (Message.ArgumentType.STRUCT1 == dbus.charAt(j)) c++;
269                   }
270 
271                   Vector<Type> contained = new Vector<Type>();
272                   int c = getJavaType(dbus.substring(i+1, j-1), contained, -1);
273                   rv.add(new DBusStructType(contained.toArray(new Type[0])));
274                   i = j;
275                   break;
276                case Message.ArgumentType.ARRAY:
277                   if (Message.ArgumentType.DICT_ENTRY1 == dbus.charAt(i+1)) {
278                      contained = new Vector<Type>();
279                      c = getJavaType(dbus.substring(i+2), contained, 2);
280                      rv.add(new DBusMapType(contained.get(0), contained.get(1)));
281                      i += (c+2);
282                   } else {
283                      contained = new Vector<Type>();
284                      c = getJavaType(dbus.substring(i+1), contained, 1);
285                      rv.add(new DBusListType(contained.get(0)));
286                      i += c;
287                   }
288                   break;
289                case Message.ArgumentType.VARIANT:
290                   rv.add(Variant.class);
291                   break;
292                case Message.ArgumentType.BOOLEAN:
293                   rv.add(Boolean.class);
294                   break;
295                case Message.ArgumentType.INT16:
296                   rv.add(Short.class);
297                   break;
298                case Message.ArgumentType.BYTE:
299                   rv.add(Byte.class);
300                   break;
301                case Message.ArgumentType.OBJECT_PATH:
302                   rv.add(DBusInterface.class);
303                   break;
304                case Message.ArgumentType.UINT16:
305                   rv.add(UInt16.class);
306                   break;
307                case Message.ArgumentType.INT32:
308                   rv.add(Integer.class);
309                   break;
310                case Message.ArgumentType.UINT32:
311                   rv.add(UInt32.class);
312                   break;
313                case Message.ArgumentType.INT64:
314                   rv.add(Long.class);
315                   break;
316                case Message.ArgumentType.UINT64:
317                   rv.add(UInt64.class);
318                   break;
319                case Message.ArgumentType.DOUBLE:
320                   rv.add(Double.class);
321                   break;
322                case Message.ArgumentType.FLOAT:
323                   rv.add(Float.class);
324                   break;
325                case Message.ArgumentType.STRING:
326                   rv.add(String.class);
327                   break;
328                case Message.ArgumentType.SIGNATURE:
329                   rv.add(Type[].class);
330                   break;
331                case Message.ArgumentType.DICT_ENTRY1:
332                   rv.add(Map.Entry.class);
333                   contained = new Vector<Type>();
334                   c = getJavaType(dbus.substring(i+1), contained, 2);
335                   i+=c+1;
336                   break;
337                default:
338                   throw new DBusException(MessageFormat.format(_("Failed to parse DBus type signature: {0} ({1})."), new Object[] { dbus, dbus.charAt(i) }));
339             }
340          return i;
341       } catch (IndexOutOfBoundsException IOOBe) {
342          if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, IOOBe);
343          throw new DBusException(_("Failed to parse DBus type signature: ")+dbus);
344       }
345    }
346    /**
347     * Recursively converts types for serialization onto DBus.
348     * @param parameters The parameters to convert.
349     * @param types The (possibly generic) types of the parameters.
350     * @return The converted parameters.
351     * @throws DBusException Thrown if there is an error in converting the objects.
352     */
353    @SuppressWarnings("unchecked")
convertParameters(Object[] parameters, Type[] types, AbstractConnection conn)354    public static Object[] convertParameters(Object[] parameters, Type[] types, AbstractConnection conn) throws DBusException
355    {
356       if (null == parameters) return null;
357       for (int i = 0; i < parameters.length; i++) {
358          if (Debug.debug) Debug.print(Debug.VERBOSE,"Converting "+i+" from "+parameters[i]+" to "+types[i]);
359          if (null == parameters[i]) continue;
360 
361          if (parameters[i] instanceof DBusSerializable) {
362             for (Method m: parameters[i].getClass().getDeclaredMethods())
363                if (m.getName().equals("deserialize")) {
364                   Type[] newtypes = m.getParameterTypes();
365                   Type[] expand = new Type[types.length + newtypes.length - 1];
366                   System.arraycopy(types, 0, expand, 0, i);
367                   System.arraycopy(newtypes, 0, expand, i, newtypes.length);
368                   System.arraycopy(types, i+1, expand, i+newtypes.length, types.length-i-1);
369                   types = expand;
370                   Object[] newparams = ((DBusSerializable) parameters[i]).serialize();
371                   Object[] exparams = new Object[parameters.length + newparams.length - 1];
372                   System.arraycopy(parameters, 0, exparams, 0, i);
373                   System.arraycopy(newparams, 0, exparams, i, newparams.length);
374                   System.arraycopy(parameters, i+1, exparams, i+newparams.length, parameters.length-i-1);
375                   parameters = exparams;
376                }
377             i--;
378          } else if (parameters[i] instanceof Tuple) {
379             Type[] newtypes = ((ParameterizedType) types[i]).getActualTypeArguments();
380             Type[] expand = new Type[types.length + newtypes.length - 1];
381             System.arraycopy(types, 0, expand, 0, i);
382             System.arraycopy(newtypes, 0, expand, i, newtypes.length);
383             System.arraycopy(types, i+1, expand, i+newtypes.length, types. length-i-1);
384             types = expand;
385             Object[] newparams = ((Tuple) parameters[i]).getParameters();
386             Object[] exparams = new Object[parameters.length + newparams.length - 1];
387             System.arraycopy(parameters, 0, exparams, 0, i);
388             System.arraycopy(newparams, 0, exparams, i, newparams.length);
389             System.arraycopy(parameters, i+1, exparams, i+newparams.length, parameters.length-i-1);
390             parameters = exparams;
391             if (Debug.debug) Debug.print(Debug.VERBOSE, "New params: "+Arrays.deepToString(parameters)+" new types: "+Arrays.deepToString(types));
392             i--;
393          } else if (types[i] instanceof TypeVariable &&
394                !(parameters[i] instanceof Variant))
395             // its an unwrapped variant, wrap it
396             parameters[i] = new Variant<Object>(parameters[i]);
397          else if (parameters[i] instanceof DBusInterface)
398             parameters[i] = conn.getExportedObject((DBusInterface) parameters[i]);
399       }
400       return parameters;
401    }
402    @SuppressWarnings("unchecked")
deSerializeParameter(Object parameter, Type type, AbstractConnection conn)403    static Object deSerializeParameter(Object parameter, Type type, AbstractConnection conn) throws Exception
404    {
405       if (Debug.debug) Debug.print(Debug.VERBOSE, "Deserializing from "+parameter.getClass()+" to "+type.getClass());
406       if (null == parameter)
407          return null;
408 
409       // its a wrapped variant, unwrap it
410       if (type instanceof TypeVariable
411             && parameter instanceof Variant) {
412          parameter = ((Variant)parameter).getValue();
413       }
414 
415       // Turn a signature into a Type[]
416       if (type instanceof Class
417             && ((Class) type).isArray()
418             && ((Class) type).getComponentType().equals(Type.class)
419             && parameter instanceof String) {
420          Vector<Type> rv = new Vector<Type>();
421          getJavaType((String) parameter, rv, -1);
422          parameter = rv.toArray(new Type[0]);
423       }
424 
425       // its an object path, get/create the proxy
426       if (parameter instanceof ObjectPath) {
427          if (type instanceof Class && DBusInterface.class.isAssignableFrom((Class) type))
428             parameter = conn.getExportedObject(
429                   ((ObjectPath) parameter).source,
430                   ((ObjectPath) parameter).path);
431          else
432             parameter = new Path(((ObjectPath) parameter).path);
433       }
434 
435       // it should be a struct. create it
436       if (parameter instanceof Object[] &&
437             type instanceof Class &&
438             Struct.class.isAssignableFrom((Class) type)) {
439          if (Debug.debug) Debug.print(Debug.VERBOSE, "Creating Struct "+type+" from "+parameter);
440          Type[] ts = Container.getTypeCache(type);
441          if (null == ts) {
442             Field[] fs = ((Class) type).getDeclaredFields();
443             ts = new Type[fs.length];
444             for (Field f : fs) {
445                Position p = f.getAnnotation(Position.class);
446                if (null == p) continue;
447                ts[p.value()] = f.getGenericType();
448            }
449             Container.putTypeCache(type, ts);
450          }
451 
452          // recurse over struct contents
453          parameter = deSerializeParameters((Object[]) parameter, ts, conn);
454          for (Constructor con: ((Class) type).getDeclaredConstructors()) {
455             try {
456                parameter = con.newInstance((Object[]) parameter);
457                break;
458             } catch (IllegalArgumentException IAe) {}
459          }
460       }
461 
462       // recurse over arrays
463       if (parameter instanceof Object[]) {
464          Type[] ts = new Type[((Object[]) parameter).length];
465          Arrays.fill(ts, parameter.getClass().getComponentType());
466          parameter = deSerializeParameters((Object[]) parameter,
467                ts, conn);
468       }
469       if (parameter instanceof List) {
470          Type type2;
471          if (type instanceof ParameterizedType)
472             type2 = ((ParameterizedType) type).getActualTypeArguments()[0];
473          else if (type instanceof GenericArrayType)
474             type2 = ((GenericArrayType) type).getGenericComponentType();
475          else if (type instanceof Class && ((Class) type).isArray())
476             type2 = ((Class) type).getComponentType();
477          else
478             type2 = null;
479          if (null != type2)
480             parameter = deSerializeParameters((List) parameter, type2, conn);
481       }
482 
483       // correct floats if appropriate
484       if (type.equals(Float.class) || type.equals(Float.TYPE))
485          if (!(parameter instanceof Float))
486             parameter = ((Number) parameter).floatValue();
487 
488       // make sure arrays are in the correct format
489       if (parameter instanceof Object[] ||
490             parameter instanceof List ||
491             parameter.getClass().isArray()) {
492          if (type instanceof ParameterizedType)
493             parameter = ArrayFrob.convert(parameter,
494                   (Class<? extends Object>) ((ParameterizedType) type).getRawType());
495          else if (type instanceof GenericArrayType) {
496             Type ct = ((GenericArrayType) type).getGenericComponentType();
497             Class cc = null;
498             if (ct instanceof Class)
499                cc = (Class) ct;
500             if (ct instanceof ParameterizedType)
501                cc = (Class) ((ParameterizedType) ct).getRawType();
502             Object o = Array.newInstance(cc, 0);
503             parameter = ArrayFrob.convert(parameter,
504                   o.getClass());
505          } else if (type instanceof Class &&
506                ((Class) type).isArray()) {
507             Class cc = ((Class) type).getComponentType();
508             if ((cc.equals(Float.class) || cc.equals(Float.TYPE))
509                   && (parameter instanceof double[])) {
510                double[] tmp1 = (double[]) parameter;
511                float[] tmp2 = new float[tmp1.length];
512                for (int i = 0; i < tmp1.length; i++)
513                   tmp2[i] = (float) tmp1[i];
514                parameter = tmp2;
515             }
516             Object o = Array.newInstance(cc, 0);
517             parameter = ArrayFrob.convert(parameter,
518                   o.getClass());
519          }
520       }
521       if (parameter instanceof DBusMap) {
522 			if (Debug.debug) Debug.print(Debug.VERBOSE, "Deserializing a Map");
523 			DBusMap dmap = (DBusMap) parameter;
524 			Type[] maptypes = ((ParameterizedType) type).getActualTypeArguments();
525 			for (int i = 0; i < dmap.entries.length; i++) {
526 				dmap.entries[i][0] = deSerializeParameter(dmap.entries[i][0], maptypes[0], conn);
527 				dmap.entries[i][1] = deSerializeParameter(dmap.entries[i][1], maptypes[1], conn);
528 			}
529       }
530       return parameter;
531    }
deSerializeParameters(List<Object> parameters, Type type, AbstractConnection conn)532    static List<Object> deSerializeParameters(List<Object> parameters, Type type, AbstractConnection conn) throws Exception
533    {
534       if (Debug.debug) Debug.print(Debug.VERBOSE, "Deserializing from "+parameters+" to "+type);
535       if (null == parameters) return null;
536       for (int i = 0; i < parameters.size(); i++) {
537          if (null == parameters.get(i)) continue;
538 
539          /* DO NOT DO THIS! IT'S REALLY NOT SUPPORTED!
540           * if (type instanceof Class &&
541                DBusSerializable.class.isAssignableFrom((Class) types[i])) {
542             for (Method m: ((Class) types[i]).getDeclaredMethods())
543                if (m.getName().equals("deserialize")) {
544                   Type[] newtypes = m.getGenericParameterTypes();
545                   try {
546                      Object[] sub = new Object[newtypes.length];
547                      System.arraycopy(parameters, i, sub, 0, newtypes.length);
548                      sub = deSerializeParameters(sub, newtypes, conn);
549                      DBusSerializable sz = (DBusSerializable) ((Class) types[i]).newInstance();
550                      m.invoke(sz, sub);
551                      Object[] compress = new Object[parameters.length - newtypes.length + 1];
552                      System.arraycopy(parameters, 0, compress, 0, i);
553                      compress[i] = sz;
554                      System.arraycopy(parameters, i + newtypes.length, compress, i+1, parameters.length - i - newtypes.length);
555                      parameters = compress;
556                   } catch (ArrayIndexOutOfBoundsException AIOOBe) {
557                      if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, AIOOBe);
558                      throw new DBusException("Not enough elements to create custom object from serialized data ("+(parameters.size()-i)+" < "+(newtypes.length)+")");
559                   }
560                }
561          } else*/
562             parameters.set(i, deSerializeParameter(parameters.get(i), type, conn));
563       }
564       return parameters;
565    }
566 
567    @SuppressWarnings("unchecked")
deSerializeParameters(Object[] parameters, Type[] types, AbstractConnection conn)568    static Object[] deSerializeParameters(Object[] parameters, Type[] types, AbstractConnection conn) throws Exception
569    {
570       if (Debug.debug) Debug.print(Debug.VERBOSE, "Deserializing from "+Arrays.deepToString(parameters)+" to "+Arrays.deepToString(types));
571       if (null == parameters) return null;
572 
573       if (types.length == 1 && types[0] instanceof ParameterizedType
574             && Tuple.class.isAssignableFrom((Class) ((ParameterizedType) types[0]).getRawType())) {
575          types = ((ParameterizedType) types[0]).getActualTypeArguments();
576       }
577 
578       for (int i = 0; i < parameters.length; i++) {
579          // CHECK IF ARRAYS HAVE THE SAME LENGTH <-- has to happen after expanding parameters
580          if (i >= types.length) {
581             if (Debug.debug) {
582                for (int j = 0; j < parameters.length; j++) {
583                   Debug.print(Debug.ERR, String.format("Error, Parameters difference (%1d, '%2s')", j, parameters[j].toString()));
584                }
585             }
586             throw new DBusException(_("Error deserializing message: number of parameters didn't match receiving signature"));
587          }
588          if (null == parameters[i]) continue;
589 
590          if ((types[i] instanceof Class &&
591                DBusSerializable.class.isAssignableFrom((Class<? extends Object>) types[i])) ||
592                (types[i] instanceof ParameterizedType &&
593                DBusSerializable.class.isAssignableFrom((Class<? extends Object>) ((ParameterizedType) types[i]).getRawType()))) {
594             Class<? extends DBusSerializable> dsc;
595             if (types[i] instanceof Class)
596                dsc = (Class<? extends DBusSerializable>) types[i];
597             else
598                dsc = (Class<? extends DBusSerializable>) ((ParameterizedType) types[i]).getRawType();
599             for (Method m: dsc.getDeclaredMethods())
600                if (m.getName().equals("deserialize")) {
601                   Type[] newtypes = m.getGenericParameterTypes();
602                   try {
603                      Object[] sub = new Object[newtypes.length];
604                      System.arraycopy(parameters, i, sub, 0, newtypes.length);
605                      sub = deSerializeParameters(sub, newtypes, conn);
606                      DBusSerializable sz = dsc.newInstance();
607                      m.invoke(sz, sub);
608                      Object[] compress = new Object[parameters.length - newtypes.length + 1];
609                      System.arraycopy(parameters, 0, compress, 0, i);
610                      compress[i] = sz;
611                      System.arraycopy(parameters, i + newtypes.length, compress, i+1, parameters.length - i - newtypes.length);
612                      parameters = compress;
613                   } catch (ArrayIndexOutOfBoundsException AIOOBe) {
614                      if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, AIOOBe);
615                      throw new DBusException(MessageFormat.format(_("Not enough elements to create custom object from serialized data ({0} < {1})."),
616                                  new Object[] { parameters.length-i, newtypes.length }));
617                   }
618                }
619          } else
620             parameters[i] = deSerializeParameter(parameters[i], types[i], conn);
621       }
622       return parameters;
623    }
624 }
625 
626 
627