Quantas vezes você teve que receber ou gerar um JSON e desejou poder trabalhar nele usando DTLs sem ter que lidar com DynamicObjects tentando lembrar o nome de cada campo? Você quer dividir e tornar seu arquivo JSON gigante mais digerível?

No meu caso, nunca, mas pensei que alguém poderia achar útil ter um recurso que captura seu JSON e o divide em uma série de classes ObjectScript com as quais você pode trabalhar de forma mais fácil e conveniente.
Pois bem... contemplem o JSON2Class em toda a sua glória!
Como o JSON2Class funciona?
É muito simples: ele aproveita os recursos do Embedded Python para fatiar e analisar seu JSON e gerar as classes associadas. Essas classes geradas serão de dois tipos:
- %Persistent: para a classe principal ou raiz.
- %SerialObject: para todas as subclasses que serão anexadas à principal.
Para fazer isso, ele leva em consideração os seguintes pontos:
Palavras reservadas
Nem todo nome de propriedade que vem no seu JSON é aceitável, então ele será modificado adicionando ao final do nome JSON, de modo que " language" se tornará " languageJSON".
Caracteres especiais
Caracteres especiais como "_" também são removidos, então "patient_name" passará a ser chamado de "patientname".
%JSONFIELDNAME
Para evitar que a classe mude de nome quando for convertida de volta para JSON, o atributo %JSONFIELDNAME foi adicionado às propriedades cujos nomes são modificados, permitindo manter o rótulo original ao exportá-lo para JSON.
Gerando as classes
Toda a funcionalidade está contida na classe Utils.JSON2Class , e para invocar o processo de geração temos o seguinte método:
ClassMethod Convert(
json As %String,
basePackage As %String = "App.Model",
rootClassName As %String = "Root",
outDir As %String = "/shared/generated"
) As %String
Vamos analisar os atributos do ClassMethod:
- json: Este será nosso JSON modelo que queremos gerar.
- basePackage: O pacote no qual todas as classes serão implementadas.
- rootClassName: O nome da classe persistente que atuará como a raiz.
- outDir: O diretório local onde os arquivos de classe serão gerados.
Exemplo:
Começamos com um JSON típico, como um recurso FHIR do tipo 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"
}
}
Vamos agora olhar para o objeto Root, que será nossa classe principal de paciente:
.png)
Vamos agora olhar para o objeto Root, que será nossa classe principal de paciente:
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 voilà! Agora podemos armazenar nosso JSON como um objeto regular.
Próximos passos
Não é ruim poder gerar automaticamente as classes, mas seria interessante poder transformar automaticamente o JSON em uma instância das classes que criamos, levando em conta as particularidades dos nomes das propriedades.