JSONOneOf
Specify a record that needs to be serialized or deserialized.
Syntax
JSONOneOf is an optional attribute.
Usage
You can set JSONOneOf on a record, elements of a record, or a user-defined type to specify elements that need to be serialized or
deserialized. For example, if you have complex data or data that is flexible in how it may be
represented, then you can define the data with a number of schemas and JSONOneOf to
validate against exactly one of the schemas at runtime.
There are considerations for working with primitive
types in schemas to avoid ambiguity in the oneOf validation. When defining
schemas for JSONOneOf, keep in mind what happens with the conversion of BDL types
to JSON types. For more information on conversion mapping for Genero BDL data types to JSON, go to
OpenAPI types mapping: BDL.
The deserialization error -15807 is returned at runtime if there are more than one of the following types in the schema:
STRINGSTRING format: DATE/DATETIMEBOOLEANINTEGERNUMBER
In this example there is an INTEGER and a DECIMAL, but the JSON
schema will convert DECIMAL to NUMBER; therefore, this schema is
allowed.
PUBLIC TYPE integerNumber RECORD ATTRIBUTE(JSONOneOf)
_selector SMALLINT ATTRIBUTE(JSONSelector),
i INTEGER,
fl DECIMAL
END RECORD
PUBLIC TYPE primType RECORD ATTRIBUTE(JSONOneOf)
_selector SMALLINT ATTRIBUTE(JSONSelector),
a STRING,
b STRING
END RECORDINTEGER,
TINYINT, SMALLINT, and BIGINT, to
INTEGER. PUBLIC TYPE primNumberType RECORD ATTRIBUTE(JSONOneOf)
_selector SMALLINT ATTRIBUTE(JSONSelector),
i INTEGER,
ty TINYINT,
si SMALLINT,
i2 BIGINT
END RECORDDATETIME YEAR TO SECOND is converted to a
STRING with a specific format in JSON (format: date-time);
therefore, this type is allowed. However, if both STRING values are valid for
JSONOneOf, the priority is given to the DATETIME YEAR TO SECOND
value. A special rule is implemented to resolve this conflict. For details, go to Special rulesPUBLIC TYPE stringDatetime RECORD ATTRIBUTE(JSONOneOf)
_selector SMALLINT ATTRIBUTE(JSONSelector),
a STRING,
da DATETIME YEAR TO SECOND
END RECORDSpecial rules
oneOf validation , special rules have to be applied to resolve potential
conflicts involving the STRING/DATE/DATETIME and
INTEGER/NUMBER types. This occurs when the value sent is valid for
both types and the JSON schema cannot resolve oneOf. To resolve this conflict, a
priority selection applies in the following cases:- If there is a valid
STRINGand aDATE/DATETIME, theDATE/DATETIMEwill have priority. - If there is a valid
INTEGERand aNUMBER, theINTEGERwill have priority.
DATE/DATETIME over STRING
is applied with different values, study the examples shown in Table 1, Table 2, and Table 3.To understand how the priority of INTEGER over NUMBER is
applied with different values, study the examples shown in Table 4, Table 5, and Table 6
Before applying the priority rule (shown in the Priority column), deserialization for the value is checked first, and this is shown in the column Deserialization. The Result column shows the resolution applied.
| Type | Deserialization | Priority | Result |
|---|---|---|---|
DATETIME |
YES | YES | DATETIME |
STRING |
YES | NO |
| Type | Deserialization | Priority | Result |
|---|---|---|---|
DATE |
NO | YES | STRING |
STRING |
YES | NO |
| Type | Deserialization | Priority | Result |
|---|---|---|---|
DATETIME |
NO | YES | STRING |
STRING |
YES | NO |
| Type | Deserialization | Priority | Result |
|---|---|---|---|
INTEGER |
YES | YES | INTEGER |
NUMBER |
YES | NO |
| Type | Deserialization | Priority | Result |
|---|---|---|---|
INTEGER |
YES | YES | INTEGER |
NUMBER |
YES | NO |
| Type | Deserialization | Priority | Result |
|---|---|---|---|
INTEGER |
NO | YES | NUMBER |
NUMBER |
YES | NO |
The JSONOneOf attribute represents the oneOf keyword in the
JSON schema property of the Swagger and OpenAPI specification.
The JSONOneOf attribute must be used in combination with the JSONSelector attribute.
Example 1: using JSONOneOf
In this example, the JSONOneOf attribute is set on the input record of the
CreateAccount function. At a request to the
service, you can choose which member of the createAccountType record –
id or name – to use by setting the member of the input record with
the JSONSelector
attribute, _selector in our example, to the index value of the record member.
For example, in a request from your client application, you
might have a statement like this: LET in._SELECTOR=2.
In the CreateAccount function, the CASE
statement tests for the _selector value.
IMPORT COM
PUBLIC TYPE accountType RECORD
id INTEGER,
name STRING,
date DATETIME YEAR TO SECOND,
age INTEGER,
gender BOOLEAN
END RECORD
PRIVATE DEFINE accounts DYNAMIC ARRAY OF accountType
PUBLIC DEFINE accountError RECORD ATTRIBUTE(WSError = 'account service error')
id INTEGER,
msg STRING
END RECORD
TYPE createAccountType RECORD ATTRIBUTE(JSONOneOf)
_selector INTEGER ATTRIBUTE(JSONSelector),
id INTEGER,
name STRING
END RECORD
FUNCTION CreateAccount(
in createAccountType)
ATTRIBUTE(WSPost, WSPath = "/createaccount")
RETURNS(createAccountType)
DEFINE out createAccountType
DEFINE idx INTEGER
LET out = in
CASE
WHEN in._selector = 1
LET idx = accounts.search("id", in.id)
IF idx > 0 THEN
# raise RESTError with accountError
ELSE
CALL accounts.appendElement()
LET accounts[accounts.getLength()].id = in.id
END IF
WHEN in._selector = 2
LET idx = accounts.search("name", in.name)
# ... function code ...
END CASE
RETURN out
END FUNCTION
In the OpenAPI documentation, the GWS engine exposes the oneOf property in the
schema for the record elements defined with JSONOneOf. In the
following sample schema, a request to the operation to create an account can choose to send the
record for the id or name.

Example 2: using JSONOneOf with JSONRequired
In this example, the use of the JSONRequired attribute in addition to the
JSONOneOf attribute is important to validate the schemas. In the
complexType record, there are three sub-records. Each sub-record also has a member
set with the JSONRequired attribute. The effect of this required member is that it
allows the schemas to be validated.
In JSON schema, there is a default to allowing additional properties – properties
that do not correspond to any property name – which has the effect of allowing schemas to be
validated with any properties. Therefore, in our example (with JSONOneOf alone) no
schema could be validated, since they would all be valid. For an example using
JSONOneOf and JSONAdditionalProperties instead of
JSONRequired, go to JSONAdditionalProperties.
With JSONRequired in the validation process, the JSON schema checks that the
required property has been received; otherwise, the schema will be invalid and will be eliminated.
In the end, according to the oneOf requirement, there must remain only one valid
schema in all the possible schemas.
For more information on properties and additional properties, go to the JSON Schema (external link) object page and search for additional properties.
# In this example, a property with attribute JSONRequired is mandatory
# Otherwise, all schemas will be valid and oneOf can only accept one valid schema
TYPE complexType RECORD ATTRIBUTE(JSONOneOf)
_selector INTEGER ATTRIBUTE(JSONSelector),
accountById RECORD
id INTEGER ATTRIBUTE(JSONRequired),
birthday DATE,
gender BOOLEAN
END RECORD,
accountByname RECORD
name STRING ATTRIBUTE(JSONRequired),
birthday DATE,
gender BOOLEAN
END RECORD,
accountBydate RECORD
date DATETIME YEAR TO SECOND ATTRIBUTE(JSONRequired),
birthday DATE,
gender BOOLEAN
END RECORD
END RECORD
FUNCTION echoComplexType(
in complexType)
ATTRIBUTE(WSPost, WSPath = "/echoComplexType")
RETURNS(complexType)
DEFINE out complexType
LET out = in
DISPLAY out._selector
CASE
WHEN out._selector == 2
DISPLAY "This is the schema 1 with id required property: ",
out.accountById.id
WHEN out._selector == 3
DISPLAY "This is the schema 2 with STRING value: ",
out.accountByName.name
WHEN out._selector == 4
DISPLAY "This is the schema 3 with DATE value: ",
out.accountBydate.date
END CASE
RETURN out
END FUNCTION
In the OpenAPI documentation, the GWS creates the JSON schema with oneOf and
required properties.
