· Apr 18, 2023

Allow string or number values for a property with JSON adaptor

I have a class using the JSON adaptor:

Class pbarton.test Extends (%RegisteredObject, %JSON.Adaptor)

Property Version As %String;


The Version property could be either a string or a number in the JSON source data. If it's a string, importing it will succeed. If it's a number, importing fails.

set t = ##class(pbarton.test).%New()

w t.%JSONImport({"Version": "3"})

zw t.%JSONImport({"Version": 3})
"0 "_$lb($lb(9406,"Version","class base",,,,,,,$lb(,"USER",$lb("e^%JSONImportInternal+16^pbarton.test.1^1","e^%JSONImport+12^%JSON.Adaptor.1^1","e^^^0"))))/* ERROR #9406: Unexpected format for value of field, Version, using class base mapping [e^%JSONImportInternal+16^pbarton.test.1^1 e^%JSONImport+12^%JSON.Adaptor.1^1 e^^^0:USER] */

Is there anything I can do to make the class resilient to either string or number formatted values in the imported JSON?

Product version: IRIS 2022.1
Discussion (1)2
Log in or sign up to continue

Hi Pravin,

The following pattern could work for you. Override and add a callback with a single line edit. Then maintaining the custom logic in a supporting callback. Will need to track behavior changes for %JSONImport when upgrading.

Method OnJSONImport(%JSONObject As %Library.DynamicAbstractObject)
  set %JSONObject.Version=""_%JSONObject.Version

/// %JSONImport imports JSON or dynamic object input into this object.<br>
/// The input argument is either JSON as a string or stream, or a subclass of %DynamicAbstractObject.<br>
/// mappingName is the name of the mapping to use for the import. The base mapping is represented by "" and is the default.
Method %JSONImport(input, %mappingName As %String = "") As %Status [ ServerOnly = 1 ]
Try {
  Set sc=$$$OK
  New %JSONObject
  If $isobject(input),input.%IsA("%Library.DynamicAbstractObject") {
    // Already a dynamic object
    Set %JSONObject=input
Else {
    // A JSON stream or string
    Set %JSONObject=##class(%Library.DynamicAbstractObject).%FromJSON(input)
   // Add callback
  Do ..OnJSONImport(%JSONObject)
  // Do the import now.
  Set sc=..%JSONImportInternal() Catch ex {
  Set sc=ex.AsStatus()
  } Quit sc