/**
  * Recursively serialise objects to a JSONWriter.
  *
  * <p>Handles basic Java type suitable for the current messaging implementation.
  *
  * @param writer JSONWriter for output
  * @param name Name of the current value, can be null for array item
  * @param obj Object representing the value to serialise
  */
 static void serialiseMessageObjects(
     final JSONWriter writer, final String name, final Serializable obj) throws IOException {
   if (obj instanceof Map) {
     // recursively serialise the map entries
     if (name != null) {
       writer.startValue(name);
     }
     writer.startObject();
     Map<String, Serializable> map = (Map<String, Serializable>) obj;
     for (final String key : map.keySet()) {
       serialiseMessageObjects(writer, key, map.get(key));
     }
     writer.endObject();
     if (name != null) {
       writer.endValue();
     }
   } else if (obj instanceof List) {
     // recursively serialise the list items
     if (name != null) {
       writer.startValue(name);
     }
     writer.startArray();
     for (final Object item : (List) obj) {
       serialiseMessageObjects(writer, null, (Serializable) item);
     }
     writer.endArray();
     if (name != null) {
       writer.endValue();
     }
   } else if (obj instanceof Integer) {
     if (name != null) {
       writer.writeValue(name, (Integer) obj);
     } else {
       writer.writeValue((Integer) obj);
     }
   } else if (obj instanceof Boolean) {
     if (name != null) {
       writer.writeValue(name, (Boolean) obj);
     } else {
       writer.writeValue((Boolean) obj);
     }
   } else if (obj instanceof Date) {
     if (name != null) {
       writer.writeValue(name, ISO8601DateFormat.format((Date) obj));
     } else {
       writer.writeValue(ISO8601DateFormat.format((Date) obj));
     }
   } else if (obj == null) {
     if (name != null) {
       writer.writeNullValue(name);
     } else {
       writer.writeNullValue();
     }
   } else {
     if (name != null) {
       writer.writeValue(name, obj.toString());
     } else {
       writer.writeValue(obj.toString());
     }
   }
 }
 @Override
 public String toString() {
   // serialise message to JSON and return final message string data
   try {
     final StringBuilderWriter buffer = new StringBuilderWriter(512);
     final JSONWriter writer = new JSONWriter(buffer);
     writer.startObject();
     writer.writeValue(ClusterMessage.JSON_SENDER, getSender());
     writer.startValue(ClusterMessage.JSON_MESSAGE);
     writer.startObject();
     writer.writeValue(ClusterMessage.JSON_TYPE, getType());
     writer.startValue(ClusterMessage.JSON_PAYLOAD);
     serialiseMessageObjects(writer, null, (Serializable) this.payload);
     writer.endValue();
     writer.endObject();
     writer.endValue();
     writer.endObject();
     return buffer.toString();
   } catch (IOException e) {
     throw new IllegalStateException(
         "Failed to serialise cluster message: " + e.getMessage(), e);
   }
 }