0 votes
21 views
ago by (30.6k points)
Our integrations return JSON and legacy XML; we need to turn them into business objects and back, and sometimes handle an unknown structure (ANY). Which APIs exist in server scripts and what are the traps?

1 Answer

0 votes
ago by (30.6k points)

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

Related questions

723 questions

807 answers

98 comments

4.8k users

Join BPM Community Discord Channel

Welcome to BPM Tips Q&A, Community wiki/forum where you can ask questions and receive answers from other IBM BPM experts and members of the community. Users with 2000 points will automatically be promoted to expert level.
Created by Dosvak LLC
Our Youtube Channel
...