# Object Type Modification
Type modification functionality allows users to change the object's type definition via the PUT endpoint:
As a result, the existing object becomes an instance of a different type (while retaining its original objectId).
# Overview
Object type modification functionality supports the following cases in a type
change:
- Major version change (upgrade and downgrade)
- Change to a different type (including subtype for currently used type)
# Major version change
Major version change supports updating the object model with the same type definition, but a different major version of it (i.e., from "Type@Major1" to "Type@Major2")
The illustration below shows how updating type's MINOR or PATCH version
automatically updates the objects of this type. However, updating the MAJOR
version of any type does not automatically update the objects (since the
MAJOR update is a potential breaking change). If the objects need to be
updated to the new major type version, such operation needs to be invoked
explicitly, using the PUT
endpoint.
Here is a simple example of object's type change:
Let's assume that the following two type definitions exist on the Platform:
{
"typeId": "Type.A",
"version": "1.0.0",
"model": "abb.ability.configuration",
"properties": {
"serialNumber": {
"dataType": "string",
"isMandatory": true
},
"hubName": {
"dataType": "string",
"isMandatory": true
}
}
}
{
"typeId": "Type.A",
"version": "2.0.0",
"model": "abb.ability.configuration",
"properties": {
"hubName": {
"dataType": "string",
"isMandatory": true
}
}
}
The following object also exists. Currently, it is based on Type.A@1:
{
"objectId": "ec9581d3-8ff6-4542-85b1-059db23242d5",
"model":"abb.ability.configuration",
"type":"Type.A@1",
"version":1,
"properties":{
"serialNumber":{
"value":"0000000-00000-0000-0000-000000000000"
},
"hubName":{
"value":"IoT-12345"
}
},
"version": 1
}
We want this object to use Type.A@2 instead. The following API call needs to be executed:
{
"objectId": "ec9581d3-8ff6-4542-85b1-059db23242d5",
"type": "Type.A@2",
"model": "abb.ability.configuration",
"properties": {
"hubName": {
"value":"IoT-12345"
}
},
"version":1
}
As a result, the object looks like below:
{
"objectId": "ec9581d3-8ff6-4542-85b1-059db23242d5",
"model":"abb.ability.configuration",
"type":"Type.A@2",
"version":1,
"properties":{
"hubName":{
"value":"IoT-12345"
}
},
"version": 2
}
Type.A@1
and @2
are compatible. PUT
payload is consistent with the new
Type Definition.
# Change to a different type
Objects may be updated with a completely different type than the one used originally. In an example below, an object was created as an instance of type@1.0.0. Through the lifetime of the solution, this type has gone through two updates - patch and minor ones. Since the major version has stayed the same, the object did not need to be explicitly updated.
Then, at some point in time, the object needed to be updated with a different type definition. In the illustration, you can see that the original type@x.x.x was replaced with different.type@1.0.0). The old type stays in the type definition registry, however, the object instance is not using it anymore. From now on, it is an instance of different.type@1.0.0.
# Change to subtype
All the base type elements are available in a subtype - it is the most compatible type change for the object model.
Type definitions:
{
"typeId": "baseType",
"version": "4.0.0",
"model": "abb.ability.device",
"properties": {
"velocity": {
"dataType": "integer",
"isMandatory": true,
"value": 700
}
}
}
{
"typeId": "subType",
"version": "4.0.0",
"model": "abb.ability.device",
"baseTypes": ["baseType@4.0.0"],
"properties": {
"frequency": {
"dataType": "integer",
"isMandatory": true,
"value": 2000
}
}
}
Object model before the update:
{
"objectId": "168f3ea5-1021-4cba-877c-d4d0ef745621",
"type": "baseType@4",
"model": "abb.ability.device",
"properties": {
"velocity": {
"value":775
}
},
"version":1
}
Update operation:
{
"objectId": "168f3ea5-1021-4cba-877c-d4d0ef745621",
"type": "subType@4",
"model": "abb.ability.device",
"properties": {
"frequency": {
"value": 7000
}
},
"version":1
}
The end-result - object model uses a subType@4:
{
"objectId": "168f3ea5-1021-4cba-877c-d4d0ef745621",
"type": "subType@4",
"model": "abb.ability.device",
"properties": {
"frequency": {
"value": 7000
}
},
"version":2
}
# Validation
The type change is not always possible. Requirements for a valid update are below:
the "new" type definition needs to be of the same model definition as the old one
the "new" type cannot be a deleted one. It is forbidden to create new objects based on a deleted type, and switching an existing object to such type is also not allowed.
if some object has an extension, you cannot change its type to a one that does not support extensions. You can do that only after removing an extension from the object.
if some object has an extension, and the "new" type also allows extensions, make sure that the object's extension does not collide with the content of the "new" type definition - i.e., if your object's extension adds a property called "nominalVoltage" to it, the "new" type should not have such a property defined. Extensions cannot override what already exists on the object's type.
the uniquness of properties has to be respected. If some object has a unique property, and there already exists another object with the same unique property, and the same value under a new type, the switch is not allowed. The uniqueness would be broken.
The following example shows that:
Type definitions:
{ "typeId": "Type.A", "version": "1.0.0", "isExtensible": true, "unique": ["serialNumber"], "model": "abb.ability.configuration", "properties": { "serialNumber": { "dataType": "string", "isMandatory": true }, "hubName": { "dataType": "string", "isMandatory": true } } } { "typeId": "Type.B", "version": "1.0.0", "model": "abb.ability.configuration", "unique": ["serialNumber"], "properties": { "serialNumber": { "dataType": "string", "isMandatory": true } } }
Object models:
{ "objectId": "85d6f391-65c7-49c0-8713-00353579fb7e", "model":"abb.ability.configuration", "type":"Test.A@1", "version": 1, "properties":{ "serialNumber":{ "value":"0000000-00000-0000-0000-000000000000" }, "hubName": { "value":"IoT-12345" } }, "version":1 } { "objectId": "e3695dbf-32a6-4cfc-a189-2a72f8b4bda7", "model":"abb.ability.configuration", "type":"Test.B@1", "version": 1, "properties":{ "serialNumber":{ "value":"0000000-00000-0000-0000-000000000000" } }, "version":1 }
The following operation would be invalid, because there already is another object (e3695dbf-32a6-4cfc-a189-2a72f8b4bda7) of type Test.B@1 with the same value of the unique property serialNumber.
PUT/objects/85d6f391-65c7-49c0-8713-00353579fb7e/models/abb.ability.configuration{ "objectId": "85d6f391-65c7-49c0-8713-00353579fb7e", "type": "Type.B@1", "model": "abb.ability.configuration", "properties": { "serialNumber":{ "value":"0000000-00000-0000-0000-000000000000" } }, "version":1 }
# References and Extensions Compatibility Checks
PUT
operations on object model will update existing outgoing references with minor changes of references:isContainment
changes from type to type and,isHierarchical
: True-> False.isHierarchical
change from True-> False: can be compatible only in case of the absence of loops and number of parents constrain.The following error message is displayed if the existing references are not compatible with the new Type Definition:
400:BadRequest "Existing references are incompatible with the new type definition for this object model."While updating the object model with incoming references during a major version upgrade, the following points can be taken to update references in type definition:
- Consider an example
Existing Reference Type Definition
{ "typeId": "ReferenceType.A", "version": "1.0.0", "model": "abb.ability.configuration", "properties": { "prop1": { "dataType": "string" } } }
Existing Type Definition with above Reference Definition
{ "typeId": "Type.A", "version": "1.0.0", "references": { "modules": { "isHierarchical": true, "isContainment": true, "to": [ { "type": " ReferenceType.A@1" } ] } }, "model": "abb.ability.configuration", "properties": { "serialNumber": { "dataType": "string", "isMandatory": true }, "hubName": { "dataType": "string", "isMandatory": true } } }
- We will now do a major version upgrade of ReferenceType.A and Type.A.
{ "typeId": "ReferenceType.A", "version": "2.0.0", "model": "abb.ability.configuration", "properties": { "prop1": { "dataType": "string" } } }
Upgrading Type.A with both versions of incoming ReferenceType.A
{ "typeId": "Type.A", "version": "2.0.0", "references": { "modules": { "isHierarchical": true, "isContainment": true, "to": [ { "type": "ReferenceType.A@1" }, { "type": "ReferenceType.A@2" } ] } }, "model": "abb.ability.configuration", "properties": { "serialNumber": { "dataType": "string", "isMandatory": true }, "hubName": { "dataType": "string", "isMandatory": true } } }
- The following object also exists. Currently, it is based on Type.A@1:
{ "objectId": "ec9581d3-8ff6-4542-85b1-059db23242d5", "model":"abb.ability.configuration", "type":"Type.A@1", "version":1, "properties":{ "serialNumber":{ "value":"0000000-00000-0000-0000-000000000000" }, "hubName":{ "value":"IoT-12345" } }, "version": 1 }
- We want this object to use new upgraded version i.e. Type.A@2 instead. The following API call needs to be executed:
PUT/objects/ec9581d3-8ff6-4542-85b1-059db23242d5/models/abb.ability.configuration{ "objectId": "ec9581d3-8ff6-4542-85b1-059db23242d5", "type": "Type.A@2", "model": "abb.ability.configuration", "properties": { "hubName": { "value":"IoT-12345" } }, "version":1 }
As a result, the object looks like below:
{ "objectId": "ec9581d3-8ff6-4542-85b1-059db23242d5", "model":"abb.ability.configuration", "type":"Type.A@2", "version":1, "properties":{ "hubName":{ "value":"IoT-12345" } }, "version": 2 }
This will make sure the object type are compatible with both references.
To change the reference definition from a definite Type to any Type is allowed during the type switch, while the contrary scenario is not allowed.
During the update, it is validated if the type change are compatible with the existing object model extension. Extensions life cycle allows the principal to remove extension if it is not consistent with the proposed Type Definition.