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