Article
· 8 hr ago 5m read

JSON2Class, the JSON to ObjectScript converter you've always wanted

How many times have you had to receive or generate a JSON and wished you could work on it using DTLs without having to deal with DynamicObjects trying to remember the name of each field? Do you want to break down and make your giant JSON file more digestible?

In my case, never, but I thought that someone might find it useful to have a feature that captures your JSON and breaks it down into a series of ObjectScript classes that you can work with more easily and conveniently.

Well then...behold JSON2Class in all its glory!

How does JSON2Class work?

It's very simple: it leverages Embedded Python's capabilities to slice and parse your JSON and generate the associated classes. These generated classes will be of two types:

  • %Persistent: for the main or root class.
  • %SerialObject: for all subclasses that will be attached to the main one.

To do this, it takes into consideration the following points:

Reserved words

Not just any property name that comes in your JSON is acceptable, so it will be modified by adding to the end of the JSON name, so that " language" will become " languageJSON".

Special characters

Special characters such as "_" are also  removed, so "patient_name" will now be called "patientname".

%JSONFIELDNAME

To prevent the class from changing its name when it is converted back to JSON, the %JSONFIELDNAME attribute has been added to the properties whose names are modified, allowing us to maintain the original label when exporting it to JSON.

Generating the classes

All the functionality is contained within the Utils.JSON2Class  class , and to invoke the generation process we have the following method:

ClassMethod Convert(
    json As %String,
    basePackage As %String = "App.Model",
    rootClassName As %String = "Root",
    outDir As %String = "/shared/generated"
) As %String

Let's analyze the attributes of the ClassMethod:

  • json: This will be our template JSON that we want to generate.
  • basePackage: The package in which all the classes will be implemented.
  • rootClassName: The name of the persistent class that will act as the root.
  • outDir: The local directory where the class files will be generated.

Example:

We started with a typical JSON, such as a FHIR resource of type patient:

{
	"resourceType": "Patient",
	"id": "example",
	"identifier": [
		{
			"use": "usual",
			"type": {
				"coding": [
					{
						"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
						"code": "MR"
					}
				]
			},
			"system": "urn:oid:1.2.36.146.595.217.0.1",
			"value": "12345",
			"period": {
				"start": "2001-05-06"
			},
			"assigner": {
				"display": "Acme Healthcare"
			}
		}
	],
	"active": true,
	"name": [
		{
			"use": "official",
			"family": "Chalmers",
			"given": [
				"Peter",
				"James"
			]
		},
		{
			"use": "usual",
			"given": [
				"Jim"
			]
		},
		{
			"use": "maiden",
			"family": "Windsor",
			"given": [
				"Peter",
				"James"
			],
			"period": {
				"end": "2002"
			}
		}
	],
	"telecom": [
		{
			"use": "home"
		},
		{
			"system": "phone",
			"value": "(03) 5555 6473",
			"use": "work",
			"rank": 1
		},
		{
			"system": "phone",
			"value": "(03) 3410 5613",
			"use": "mobile",
			"rank": 2
		},
		{
			"system": "phone",
			"value": "(03) 5555 8834",
			"use": "old",
			"period": {
				"end": "2014"
			}
		}
	],
	"gender": "male",
	"birthDate": "1974-12-25",
	"_birthDate": {
		"extension": [
			{
				"url": "http://hl7.org/fhir/StructureDefinition/patient-birthTime",
				"valueDateTime": "1974-12-25T14:35:45-05:00"
			}
		]
	},
	"deceasedBoolean": false,
	"address": [
		{
			"use": "home",
			"type": "both",
			"text": "534 Erewhon St\nPeasantVille, Rainbow, Vic3999",
			"line": [
				"534 Erewhon St"
			],
			"city": "PleasantVille",
			"district": "Rainbow",
			"state": "Vic",
			"postalCode": "3999",
			"period": {
				"start": "1974-12-25"
			}
		}
	],
	"contact": [
		{
			"relationship": [
				{
					"coding": [
						{
							"system": "http://terminology.hl7.org/CodeSystem/v2-0131",
							"code": "N"
						}
					]
				}
			],
			"name": {
				"family": "du Marché",
				"_family": {
					"extension": [
						{
							"url": "http://hl7.org/fhir/StructureDefinition/humanname-own-prefix",
							"valueString": "VV"
						}
					]
				},
				"given": [
					"Bénédicte"
				]
			},
			"additionalName": [
				{
					"use": "nickname",
					"given": [
						"Béné"
					]
				}
			],
			"telecom": [
				{
					"system": "phone",
					"value": "+33 (237) 998327"
				}
			],
			"address": {
				"use": "home",
				"type": "both",
				"line": [
					"534 Erewhon St"
				],
				"city": "PleasantVille",
				"district": "Rainbow",
				"state": "Vic",
				"postalCode": "3999",
				"period": {
					"start": "1974-12-25"
				}
			},
			"additionalAddress": [
				{
					"use": "work",
					"line": [
						"123 Smart St"
					],
					"city": "PleasantVille",
					"state": "Vic",
					"postalCode": "3999"
				}
			],
			"gender": "female",
			"period": {
				"start": "2012"
			}
		}
	],
	"managingOrganization": {
		"reference": "Organization/1"
	}
}

Let's now look at the Root object, which will be our main patient class:

Let's now look at the Root object, which will be our main patient class:

Class App.Model.Root Extends (%Persistent, %JSON.Adaptor)
{

Property resourceType As %String;
Property idJSON As %String(%JSONFIELDNAME = "id");
Property identifier As list Of App.Model.Root.Identifier;
Property active As %Boolean;
Property name As list Of App.Model.Root.Name;
Property telecom As list Of App.Model.Root.Telecom;
Property gender As %String;
Property birthDate As %String;
Property deceasedBoolean As %Boolean;
Property address As list Of App.Model.Root.Address;
Property contact As list Of App.Model.Root.Contact;
Property managingOrganization As App.Model.Root.ManagingOrganization;
}

Et voila! We can now store our JSON as a regular object.

Next steps

It's not bad to be able to automatically generate the classes, but it would be interesting to be able to automatically transform the JSON into an instance of the classes we have created, taking into account the particularities of the property names.

We'll leave it in the to-do pile

homer simpson sits on a couch next to a stack of papers and a can of duff beer

Discussion (0)1
Log in or sign up to continue