JSONOneOf
Defines a record that matches exactly one of several possible JSON schemas during serialization or deserialization.
Syntax
JSONOneOf is an optional attribute.
This serializer-specific attribute is supported only by json.Serializer and does not work with util.JSON.
Usage
Set JSONOneOf on a record, elements of a record, or a user-defined type to define a polymorphic JSON
structure where exactly one variant member is used during serialization or deserialization.
Every JSONOneOf record must include one field marked with JSONSelector. At runtime, you
set the value of that field to select which variant to use. The value is a 1-based positional index
across the whole record, counting the JSONSelector field itself as position 1. When the JSONSelector field is the first member of the record (as in these examples), the first variant is therefore index 2; setting the selector to 1 is invalid and causes error
-15807.
For example:
TYPE createAccountType RECORD ATTRIBUTE(JSONOneOf)
_selector INTEGER ATTRIBUTE(JSONSelector), # position 1
id INTEGER, # position 2: LET _selector = 2
name STRING # position 3: LET _selector = 3
END RECORD
When defining schemas, keep in mind how Genero BDL types map to JSON types; see OpenAPI types mapping: BDL.
During deserialization, error -15807 is
returned if an incoming value is valid for two or more variants that map to the same JSON type. For
example, this record causes -15807 because both street_address and
po_box map to JSON STRING:
TYPE deliveryAddressType RECORD ATTRIBUTE(JSONOneOf)
_selector SMALLINT ATTRIBUTE(JSONSelector),
street_address STRING, # maps to JSON STRING
po_box STRING # maps to JSON STRING: error -15807
END RECORD
The following JSON types can conflict:
STRINGSTRING format: DATE/DATETIMEBOOLEANINTEGERNUMBER
Note that TINYINT, SMALLINT, and BIGINT all
map to INTEGER, and DECIMAL maps to NUMBER; schemas that appear distinct in BDL may conflict once converted.
When a value could match more than one type, special priority rules apply; see Special rules.
JSONOneOf represents the oneOf keyword in the OpenAPI JSON
schema specification.
Special rules
When a oneOf value is valid for more than one type, the GWS engine resolves
the conflict with a priority rule:
DATEorDATETIMEtakes priority overSTRING.INTEGERtakes priority overNUMBER.
Priority applies only when deserialization succeeds for the higher-priority type. The Deserialization, Priority, and Result columns in the tables below show how the rule is applied for each type combination.
| 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 |
Example 1: using JSONOneOf
In this example, JSONOneOf is set on the input record of the
CreateAccount function. To select a variant,
set _selector to the positional index of the variant field: 2 for
id, 3 for name.
For example, in a request from your client application, you
might have a statement like this: LET in._selector=2.
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 = 2
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 = 3
LET idx = accounts.search("name", in.name)
# ... function code ...
END CASE
RETURN out
END FUNCTION
The GWS engine exposes the oneOf property in the OpenAPI schema for records
defined with JSONOneOf. The following schema shows both variants:

Example 2: using JSONOneOf with JSONRequired
By default, JSON schema allows additional properties, so all variant schemas validate against
any submitted document and oneOf cannot resolve. Adding
JSONRequired to one distinctive field per variant causes the GWS engine to reject
any schema that is missing that field, leaving exactly one valid schema. For an alternative
approach using JSONAdditionalProperties, see Example 3: using JSONOneOf with JSONAdditionalProperties.
# 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 "schema 1, id: ", out.accountById.id
WHEN out._selector = 3
DISPLAY "schema 2, name: ", out.accountByname.name
WHEN out._selector = 4
DISPLAY "schema 3, date: ", out.accountBydate.date
END CASE
RETURN out
END FUNCTION
In the OpenAPI documentation, the GWS creates the JSON schema with oneOf and
required properties.
