APIs available in server-side JavaScript:
- JSON → business object: JSON.parse gives a plain JavaScript object; assign it field by field to a new tw.object.<Type>(), or build a small generic mapper; lists become new tw.object.listOf.Order(). The REST integration step of BAW (Call REST service, BAW 18+) maps JSON to business objects automatically when the types match the schema - prefer it for straightforward payloads.
- Business object → JSON: JSON.stringify(tw.local.order) works on BAW's TWObjects (properties are enumerable); dates become ISO strings; lists become arrays; unset properties are omitted.
- XML: tw.system.serializer.toXml(tw.local.order) returns an XML element (E4X style) and tw.system.serializer.fromXml(xml) builds the business object from XML that follows the business object's schema; toXmlString gives a string.
- ANY: a variable of type ANY holds whatever is assigned (a business object, a list, a primitive); check its shape in scripts (typeof, .listLength, the presence of fields) before use; ANY is the right type for generic services (the REST framework style) and the wrong type for anything a coach must bind to.
// generic JSON -> business object mapper (server script): copies fields the type knows, recurses into nested types and lists
function toBO(typeName, obj) {
if (obj == null) return null;
var bo = new tw.object[typeName]();
for (var k in obj) {
var v = obj[k];
if (v == null) continue;
if (Array.isArray(v)) { // list: element type from the object's definition, or strings
var elemType = bo.propertyType ? bo.propertyType(k) : null;
var list = new tw.object.listOf.String();
for (var i = 0; i < v.length; i++) list.insertIntoList(list.listLength, typeof v[i] === "object" ? toBO(elemType, v[i]) : v[i]);
bo[k] = list;
} else if (typeof v === "object") bo[k] = toBO(k.charAt(0).toUpperCase() + k.slice(1), v); // convention: property name = type name
else bo[k] = v;
}
return bo;
}
tw.local.order = toBO("Order", JSON.parse(tw.local.responseText));
// the other direction
tw.local.requestBody = JSON.stringify({ order: tw.local.order, requestedBy: tw.system.user_loginName });// XML in and out with the serializer
var xml = tw.system.serializer.toXml(tw.local.order); // <order><number>ORD-42</number>...</order>
tw.local.xmlText = String(tw.system.serializer.toXmlString(tw.local.order));
tw.local.order2 = tw.system.serializer.fromXml(new XML(tw.local.xmlText)); // element name and content must match the business object's schema
Traps: property names are case-sensitive and must match the business object's; numbers arriving as strings stay strings unless converted (a Decimal field with "12.5" fails later in SQL); dates need explicit parsing (new Date(isoString) or the Java formatter with a zone - question on time zones); JSON nulls become undefined properties; huge payloads should be parsed once and only the needed parts kept in tw.local (execution context size); and never eval untrusted JSON - always JSON.parse.
References