Mapping to JSON

Rules for the construction of JSON payloads matching an Aspect Model

payloads

For understanding the construction rules, we define the following terms:

  • A Constraint of the Property’s Characteristic defined with a Trait is applied to the characteristic referred in the samm-c:baseCharacteristic .

  • A Property’s effective data type means the Property’s Characteristic’s samm:dataType.

  • A data type is scalar, if it is one of the allowed data types, but not a samm:Entity.

In order to create JSON payloads that correspond to an Aspect Model, the following rules are applied. The other way round they can also be used to describe a validation algorithm.

  • An Aspect Model is always serialized as an unnamed JSON object.

  • For each Property:

    • If it is marked as optional, it may or may not be included in the payload. If, and only if, the Property is marked as optional and is included in the payload, then its value may be null, which is equivalent to it not being included in the payload.

    • If the Property’s effective data type is scalar with any date type other than rdf:langString, the Property is serialized as ${propertyName}: ${value} where ${value} is the JSON serialization of the respective Property’s value, details on mapping of the data types are given in Data type mappings. The value must adhere to the value range defined by the Property’s effective data type and possible Constraints on the Property’s Characteristic.

    • If the Property’s effective data type is scalar with the data type rdf:langString, the Property is serialized as a named JSON object (with ${propertyName} being the name of the JSON property), with keys for each available language tag of the Property and the corresponding localized string as the value.

    • If the Property’s effective data type is not scalar, it is serialized as a named JSON object (with ${propertyName} being the name of the JSON property), recursively using the same rules.

    • If the Property’s effective data type is an Entity which extends another Entity, it is serialized as a named JSON object (with ${propertyName} being the name of the JSON property). The Properties included for the Entity, are the Properties from the Entity itself as well as all Properties from the extended Entities, i.e. all Properties from ?thisEntity samm:extends* [].

    • If the Property’s Characteristic is a Collection, List, Set or Sorted Set, it is serialized as a named JSON array (with ${propertyName} being the name of the JSON array property).

  • Characteristics defined in the Aspect Model other than the ones mentioned above are not subject to serialization.

  • Operations defined in the Aspect Model are not subject to serialization.

  • Events defined in the Aspect Model are not subject to serialization.

Example

Aspect Model

@prefix : <urn:samm:com.mycompany.myapplication:1.0.0#> .
@prefix samm: <urn:samm:org.eclipse.esmf.samm:meta-model:2.1.0#> .
@prefix samm-c: <urn:samm:org.eclipse.esmf.samm:characteristic:2.1.0#> .
@prefix samm-e: <urn:samm:org.eclipse.esmf.samm:entity:2.1.0#> .
@prefix unit: <urn:samm:org.eclipse.esmf.samm:unit:2.1.0#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

:Movement a samm:Aspect ;
   samm:preferredName "movement"@en ;
   samm:properties ( :isMoving :speed ) ;
   samm:operations ( ) ;
   samm:events ( ) .

:isMoving a samm:Property ;
   samm:preferredName "is moving"@en ;
   samm:characteristic samm-c:Boolean .

:speed a samm:Property ;
   samm:preferredName "speed"@en ;
   samm:characteristic :Speed ;
   samm:exampleValue "0.5"^^xsd:float .

:Speed a samm-c:Measurement ;
   samm:preferredName "speed"@en ;
   samm:dataType xsd:float ;
   samm-c:unit unit:kilometrePerHour .

Payload

{
  "isMoving": true,
  "speed": 0.5
}

Data type mappings

A rich type tree is used in an Aspect Model. As JSON offers only a very limited set of data types for primitive type values there are less options on how to represent the data. The mappings are described in the following table.

Aspect Model data type

Corresponding JSON data type

Core Types

xsd:string

String

xsd:boolean

Boolean

xsd:decimal

Number

xsd:integer

Number

IEEE-floating-point numbers

xsd:double

Number

xsd:float

Number

Time and date

xsd:date

String

xsd:time

String

xsd:dateTime

String

xsd:dateTimeStamp

String

Recurring and partial dates

xsd:gYear

String

xsd:gMonth

String

xsd:gDay

String

xsd:gYearMonth

String

xsd:gMonthDay

String

xsd:duration

String

xsd:yearMonthDuration

String

xsd:dayTimeDuration

String

Limited-range integer numbers

xsd:byte

Number

xsd:short

Number

xsd:int

Number

xsd:long

Number

xsd:unsignedByte

Number

xsd:unsignedShort

Number

xsd:unsignedInt

Number

xsd:unsignedLong

Number

xsd:positiveInteger

Number

xsd:nonNegativeInteger

Number

xsd:negativeInteger

Number

xsd:nonPositiveInteger

Number

Encoded binary data

xsd:hexBinary

String

xsd:base64Binary

String

Miscellaneous types

xsd:anyURI

String

samm:curie

String

rdf:langString

A JSON object with a structure as described in the rules above.

For example, a Property errorMessage with effective data type rdf:langString and the value "Could not load data"@en would be serialized in the JSON payload as follows:

{
  "errorMessage": {
    "en": "Could not load data"
  }
}

A Property errorMessages with a Collection Characteristic and effective data type rdf:langString could yield the payload:

{
  "errorMessages": [
    { "en": "Could not load data" },
    { "de": "Konnte Daten nicht laden" }
  ]
}

Specific payload mappings for Characteristics

This section describes how data payloads look like for specific Characteristics.

Characteristic Name

Corresponding JSON data type

samm-c:Either

A JSON object with exactly either a left or right key. If the left key is present, its data type is the effective data type of the Characteristic referred to by samm-c:left; if the right key is present, its data type is the effective data type of the Characteristic referred to by samm-c:right.

The following example Aspect uses samm-c:Either to express that the Property speedValue can either return the integer value for speed, or an Error message (using an Entity), if the value could not be determined (cf. Declaring Either).

So, assuming an Aspect Model has a Property speedProperty with its samm:characteristic set to :Result according to the following definition:

:speedProperty a samm:Property ;
  samm:characteristic :Result .

:Result a samm-c:Either ;
  samm-c:left :ErrorMessage ;
  samm-c:right :SpeedValue .

:ErrorMessage a samm-c:SingleEntity ;
  samm:dataType :ErrorEntity .

:SpeedValue a samm-c:Quantifiable ;
  samm:dataType xsd:integer .

:ErrorEntity a samm:Entity ;
   samm:properties ( :errorCode :errorDescription ) .

the corresponding JSON payload either contains a left key with the error description:

{
  "result": {
    "left": {
      "errorCode": "...",
      "errorDescription": "..."
    }
  }
}

or it can contain a right key with the success status:

{
  "result": {
    "right": {
      "status": "..."
    }
  }
}

In the following example the Property speedProperty can either return the integer value for speed SpeedValue, or an Error, if the value could not be determined. Error can either return the samm-c:Text with simple error text or ErrorMessage (using an Entity) for details of error like errorCode and errorDescription.

So, assuming the Property speedProperty with samm-characteristics set to :Result according to the following definition:

:speedProperty a samm:Property ;
  samm:characteristic :Result .

:Result a samm-c:Either ;
  samm:description "The result is either an error or a SpeedValue"@en ;
  samm-c:left :Error ;
  samm-c:right :SpeedValue .

:Error a samm-c:Either ;
  samm:description """An error can be either a simple text,  or a complex object with separate errorCode and errorDescription"""@en ;
  samm-c:left samm-c:Text ;
  samm-c:right :ErrorMessage .

:SpeedValue a samm-c:Quantifiable ;
  samm:dataType xsd:integer .

:ErrorMessage a samm:Characteristic ;
  samm:dataType :ErrorEntity .

:ErrorEntity a samm:Entity ;
  samm:properties ( :errorCode :errorDescription ) .

:errorCode a samm:Property ;
  samm:characteristic samm-c:Text .

:errorDescription a samm:Property ;
  samm:characteristic samm-c:Text .

it can contain right key with the speed value:

{
  "speedProperty": {
    "right": 60
  }
}

or possible left key of Error contains Error message:

{
  "speedProperty" : {
    "left" : {
      "right" : {
        "errorDescription" : "...",
        "errorCode" : "..."
      }
    }
  }
}

or it can contain right key of Error with simple error text:

{
  "speedProperty" : {
    "left" : {
      "left" : "Simple error description..."
    }
  }
}
If the model is invalid, it might be impossible to build a JSON payload that corresponds to the model. For example, if a Set of xsd:boolean values has a Length Constraint of samm-c:minValue 3, no valid payload can be constructed.

Limitations

Due to the limits in the represention of numbers in JSON, the maximum integer number that can be used without losing precision is 2⁵³-1 (defined as Number.MAX_SAFE_INTEGER). This means that even if the Aspect Model data type would allow higher or lower values, if they can not be represented in JSON, they can not be used. Affected data types are the unbounded numeric types xsd:decimal, xsd:integer, xsd:positiveInteger, xsd:nonNegativeInteger, xsd:negativeInteger, xsd:nonPositiveInteger and the bounded type xsd:unsignedLong. The other numeric types are not affected.