JsonHelper220FDW
Utility codeunit for safe reading and writing of JSON objects. Provides typed accessors with optional error handling, upsert-style writers, and array manipulation helpers. Used extensively by MobileRPCState220FDW internally, and available for use in your own service code.
Overview
- Object type: Codeunit
- Object ID: 73167875
- Access: Public
- Namespace:
Aptean.Mesh.SDUI
All read methods accept a ShowError parameter. When true, a missing key raises an error:
Required parameter "%1" is missing
When false, the method returns the type's default value (e.g., 0 for Integer, '' for Text, false for Boolean).
All write methods use upsert semantics -- they replace the value if the key already exists, or add it if it does not.
Read Methods
ReadInteger
procedure ReadInteger(JObj: JsonObject; KeyName: Text; ShowError: Boolean): Integer
Reads an integer value from a JSON object.
Parameters:
| Name | Type | Description |
|---|---|---|
JObj | JsonObject | The JSON object to read from |
KeyName | Text | The key to look up |
ShowError | Boolean | If true, throws an error when the key is missing |
Returns: Integer -- the value, or 0 if not found and ShowError is false.
ReadText
procedure ReadText(JObj: JsonObject; KeyName: Text; ShowError: Boolean): Text
Reads a text value from a JSON object.
Parameters:
| Name | Type | Description |
|---|---|---|
JObj | JsonObject | The JSON object to read from |
KeyName | Text | The key to look up |
ShowError | Boolean | If true, throws an error when the key is missing |
Returns: Text -- the value, or '' if not found and ShowError is false.
ReadDecimal
procedure ReadDecimal(JObj: JsonObject; KeyName: Text; ShowError: Boolean): Decimal
Reads a decimal value from a JSON object.
Parameters:
| Name | Type | Description |
|---|---|---|
JObj | JsonObject | The JSON object to read from |
KeyName | Text | The key to look up |
ShowError | Boolean | If true, throws an error when the key is missing |
Returns: Decimal -- the value, or 0 if not found and ShowError is false.
ReadGuid
procedure ReadGuid(JObj: JsonObject; KeyName: Text; ShowError: Boolean): Guid
Reads a GUID value from a JSON object. The value is stored as text in the JSON and parsed using Evaluate.
Parameters:
| Name | Type | Description |
|---|---|---|
JObj | JsonObject | The JSON object to read from |
KeyName | Text | The key to look up |
ShowError | Boolean | If true, throws an error when the key is missing |
Returns: Guid -- the parsed GUID, or an empty GUID if not found and ShowError is false.
ReadBoolean
procedure ReadBoolean(JObj: JsonObject; KeyName: Text; ShowError: Boolean): Boolean
Reads a boolean value from a JSON object.
Parameters:
| Name | Type | Description |
|---|---|---|
JObj | JsonObject | The JSON object to read from |
KeyName | Text | The key to look up |
ShowError | Boolean | If true, throws an error when the key is missing |
Returns: Boolean -- the value, or false if not found and ShowError is false.
ReadDate
procedure ReadDate(JObj: JsonObject; KeyName: Text; ShowError: Boolean): Date
Reads an ISO 8601 date string (YYYY-MM-DD) from a JSON object and returns it as an AL Date. Always use this method instead of ReadText followed by manual parsing — ReadText is locale-agnostic but format parsing is fragile.
Parameters:
| Name | Type | Description |
|---|---|---|
JObj | JsonObject | The JSON object to read from |
KeyName | Text | The key to look up |
ShowError | Boolean | If true, throws an error when the key is missing |
Returns: Date -- the parsed date, or 0D if not found and ShowError is false.
Dates on the wire must be ISO 8601 strings. ReadDate expects exactly the format that WriteDate produces. Never write dates with Format(Date) — the locale-sensitive output will fail to parse.
ReadObject
procedure ReadObject(JObj: JsonObject; KeyName: Text; var Result: JsonObject): Boolean
Tries to read a nested JSON object from the parent object.
Parameters:
| Name | Type | Description |
|---|---|---|
JObj | JsonObject | The JSON object to read from |
KeyName | Text | The key to look up |
Result | JsonObject | var -- receives the nested object if found |
Returns: Boolean -- true if the key was found and contained an object, false otherwise.
Example:
var
JsonHelper: Codeunit JsonHelper220FDW;
ParentObj, ChildObj : JsonObject;
begin
if JsonHelper.ReadObject(ParentObj, 'address', ChildObj) then
City := JsonHelper.ReadText(ChildObj, 'city', false);
end;
ReadArray
procedure ReadArray(JObj: JsonObject; KeyName: Text; var Result: JsonArray): Boolean
Tries to read a JSON array from the parent object.
Parameters:
| Name | Type | Description |
|---|---|---|
JObj | JsonObject | The JSON object to read from |
KeyName | Text | The key to look up |
Result | JsonArray | var -- receives the array if found |
Returns: Boolean -- true if the key was found and contained an array, false otherwise.
Write Methods
All write methods use upsert semantics: if the key already exists, the value is replaced; if not, it is added.
WriteInteger
procedure WriteInteger(var JObj: JsonObject; KeyName: Text; Value: Integer)
Writes an integer value to a JSON object.
Parameters:
| Name | Type | Description |
|---|---|---|
JObj | JsonObject | var -- the JSON object to write to |
KeyName | Text | The key to set |
Value | Integer | The value to write |
WriteText
procedure WriteText(var JObj: JsonObject; KeyName: Text; Value: Text)
Writes a text value to a JSON object.
WriteBoolean
procedure WriteBoolean(var JObj: JsonObject; KeyName: Text; Value: Boolean)
Writes a boolean value to a JSON object.
WriteDecimal
procedure WriteDecimal(var JObj: JsonObject; KeyName: Text; Value: Decimal)
Writes a decimal value to a JSON object as a native JSON number (not a string). The mobile client performs arithmetic on decimal fields — always use this method instead of WriteText(Format(Qty)).
WriteDate
procedure WriteDate(var JObj: JsonObject; KeyName: Text; Value: Date)
Writes an AL Date as an ISO 8601 string (YYYY-MM-DD) to a JSON object. Always use this method for date fields — Format(Date) is locale-sensitive and will produce different strings on different BC servers, breaking client parsing.
Parameters:
| Name | Type | Description |
|---|---|---|
JObj | JsonObject | var — the JSON object to write to |
KeyName | Text | The key to set |
Value | Date | The date to write. 0D is written as an empty string "". |
Example:
var
JsonHelper: Codeunit JsonHelper220FDW;
Result: JsonObject;
begin
// ✅ Writes: "expiryDate": "2025-12-31"
JsonHelper.WriteDate(Result, 'expiryDate', ExpiryDate);
// ❌ Wrong — locale-sensitive, breaks client parsing in nl-NL
JsonHelper.WriteText(Result, 'expiryDate', Format(ExpiryDate));
end;
WriteObject
procedure WriteObject(var JObj: JsonObject; KeyName: Text; Value: JsonObject)
Writes a nested JSON object to the parent object.
WriteArray
procedure WriteArray(var JObj: JsonObject; KeyName: Text; Value: JsonArray)
Writes a JSON array to the parent object.
Utility Methods
RemoveKey
procedure RemoveKey(var JObj: JsonObject; KeyName: Text)
Removes a key from the JSON object if it exists. No error is raised if the key is not found.
Parameters:
| Name | Type | Description |
|---|---|---|
JObj | JsonObject | var -- the JSON object to modify |
KeyName | Text | The key to remove |
MergeInto
procedure MergeInto(var TargetObj: JsonObject; SourceObj: JsonObject)
Merges all keys from the source object into the target object. Existing keys in the target are overwritten with values from the source.
Parameters:
| Name | Type | Description |
|---|---|---|
TargetObj | JsonObject | var -- the target object that receives merged keys |
SourceObj | JsonObject | The source object whose keys are copied |
Example:
var
JsonHelper: Codeunit JsonHelper220FDW;
Base, Overrides : JsonObject;
begin
// Base: { "color": "red", "size": 10 }
// Overrides: { "color": "blue", "weight": 5 }
JsonHelper.MergeInto(Base, Overrides);
// Result: { "color": "blue", "size": 10, "weight": 5 }
end;
Array Methods
UpdateArrayField
procedure UpdateArrayField(
var JArr: JsonArray;
SearchField: Text;
SearchValue: Text;
UpdateField: Text;
NewValue: Text): Boolean
Finds the first object in the array where SearchField equals SearchValue, then sets UpdateField to NewValue.
Parameters:
| Name | Type | Description |
|---|---|---|
JArr | JsonArray | var -- the array to search and update |
SearchField | Text | The field name to match on |
SearchValue | Text | The value to match |
UpdateField | Text | The field to update in the matched object |
NewValue | Text | The new value to set |
Returns: Boolean -- true if a matching item was found and updated, false otherwise.
Example:
var
JsonHelper: Codeunit JsonHelper220FDW;
Fields: JsonArray;
begin
// Update the "Bin" field's value to "BIN-05" in the info pane fields array
JsonHelper.UpdateArrayField(Fields, 'label', 'Bin', 'value', 'BIN-05');
end;
ArrayContainsField
procedure ArrayContainsField(JArr: JsonArray; SearchField: Text; SearchValue: Text): Boolean
Checks if the array contains an object where SearchField equals SearchValue.
Parameters:
| Name | Type | Description |
|---|---|---|
JArr | JsonArray | The array to search |
SearchField | Text | The field name to match on |
SearchValue | Text | The value to match |
Returns: Boolean -- true if a matching item exists.
UpdateArrayFieldWithGauge
procedure UpdateArrayFieldWithGauge(
var JArr: JsonArray;
SearchField: Text;
SearchValue: Text;
ValueField: Text;
NewValue: Text;
GaugeField: Text;
GaugeValue: Integer): Boolean
Similar to UpdateArrayField, but also sets a gauge field (0--100) on the matched object. The gauge field is only updated if it already exists on the object.
Parameters:
| Name | Type | Description |
|---|---|---|
JArr | JsonArray | var -- the array to search and update |
SearchField | Text | The field name to match on |
SearchValue | Text | The value to match |
ValueField | Text | The field to update with NewValue |
NewValue | Text | The new text value |
GaugeField | Text | The gauge field to update (0--100) |
GaugeValue | Integer | The new gauge percentage |
Returns: Boolean -- true if a matching item was found and updated.
Example:
var
JsonHelper: Codeunit JsonHelper220FDW;
Fields: JsonArray;
Percent: Integer;
begin
Percent := Round(ScannedQty / TotalQty * 100, 1);
JsonHelper.UpdateArrayFieldWithGauge(
Fields, 'label', 'Scanned Qty',
'value', Format(ScannedQty),
'gauge', Percent);
end;
Common Usage Patterns
Reading required vs. optional fields
var
JsonHelper: Codeunit JsonHelper220FDW;
RequestData: JsonObject;
begin
// Required -- throws an error if missing
DocumentNo := JsonHelper.ReadText(RequestData, 'documentNo', true);
// Optional -- returns '' if missing
Notes := JsonHelper.ReadText(RequestData, 'notes', false);
end;
Building a response object
var
JsonHelper: Codeunit JsonHelper220FDW;
Response, Details : JsonObject;
Items: JsonArray;
begin
JsonHelper.WriteText(Response, 'status', 'OK');
JsonHelper.WriteInteger(Response, 'totalCount', 42);
JsonHelper.WriteBoolean(Response, 'hasMore', false);
JsonHelper.WriteObject(Response, 'details', Details);
JsonHelper.WriteArray(Response, 'items', Items);
end;
Safely reading nested objects
var
JsonHelper: Codeunit JsonHelper220FDW;
Root, Address : JsonObject;
begin
if JsonHelper.ReadObject(Root, 'shippingAddress', Address) then begin
City := JsonHelper.ReadText(Address, 'city', false);
PostCode := JsonHelper.ReadText(Address, 'postCode', false);
end;
end;
See Also
- MobileRPCState220FDW -- uses JsonHelper internally for all state operations