Browse Source

Merge pull request #15196 from dashevchenko/openApiImpr

Fixed schema fields ordering and refactored TB models with defaultImpl
pull/15239/head
Viacheslav Klimov 7 months ago
committed by GitHub
parent
commit
589e209ee5
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 266
      application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java
  2. 2
      application/src/main/java/org/thingsboard/server/controller/ApiKeyController.java
  3. 22
      application/src/main/java/org/thingsboard/server/controller/DeviceController.java
  4. 6
      application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java
  5. 4
      application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/BaseEntityExportService.java
  6. 8
      application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DefaultEntityExportService.java
  7. 5
      application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DeviceExportService.java
  8. 5
      application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/OtaPackageExportService.java
  9. 5
      application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/RuleChainExportService.java
  10. 5
      application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/WidgetTypeExportService.java
  11. 5
      application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/WidgetsBundleExportService.java
  12. 3
      application/src/test/java/org/thingsboard/server/service/notification/AbstractNotificationApiTest.java
  13. 8
      application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java
  14. 2
      common/data/src/main/java/org/thingsboard/server/common/data/Dashboard.java
  15. 16
      common/data/src/main/java/org/thingsboard/server/common/data/FeaturesInfo.java
  16. 11
      common/data/src/main/java/org/thingsboard/server/common/data/ShortCustomerInfo.java
  17. 2
      common/data/src/main/java/org/thingsboard/server/common/data/SystemInfo.java
  18. 1
      common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java
  19. 8
      common/data/src/main/java/org/thingsboard/server/common/data/event/DebugEventFilter.java
  20. 3
      common/data/src/main/java/org/thingsboard/server/common/data/id/AdminSettingsId.java
  21. 2
      common/data/src/main/java/org/thingsboard/server/common/data/id/AiModelId.java
  22. 4
      common/data/src/main/java/org/thingsboard/server/common/data/id/AlarmId.java
  23. 3
      common/data/src/main/java/org/thingsboard/server/common/data/id/ApiKeyId.java
  24. 4
      common/data/src/main/java/org/thingsboard/server/common/data/id/ApiUsageStateId.java
  25. 4
      common/data/src/main/java/org/thingsboard/server/common/data/id/AssetId.java
  26. 3
      common/data/src/main/java/org/thingsboard/server/common/data/id/AssetProfileId.java
  27. 4
      common/data/src/main/java/org/thingsboard/server/common/data/id/CalculatedFieldId.java
  28. 4
      common/data/src/main/java/org/thingsboard/server/common/data/id/CustomerId.java
  29. 4
      common/data/src/main/java/org/thingsboard/server/common/data/id/DashboardId.java
  30. 4
      common/data/src/main/java/org/thingsboard/server/common/data/id/DeviceId.java
  31. 3
      common/data/src/main/java/org/thingsboard/server/common/data/id/DeviceProfileId.java
  32. 3
      common/data/src/main/java/org/thingsboard/server/common/data/id/DomainId.java
  33. 3
      common/data/src/main/java/org/thingsboard/server/common/data/id/EdgeId.java
  34. 43
      common/data/src/main/java/org/thingsboard/server/common/data/id/EntityId.java
  35. 3
      common/data/src/main/java/org/thingsboard/server/common/data/id/EntityViewId.java
  36. 3
      common/data/src/main/java/org/thingsboard/server/common/data/id/JobId.java
  37. 3
      common/data/src/main/java/org/thingsboard/server/common/data/id/MobileAppBundleId.java
  38. 3
      common/data/src/main/java/org/thingsboard/server/common/data/id/MobileAppId.java
  39. 3
      common/data/src/main/java/org/thingsboard/server/common/data/id/NotificationId.java
  40. 3
      common/data/src/main/java/org/thingsboard/server/common/data/id/NotificationRequestId.java
  41. 3
      common/data/src/main/java/org/thingsboard/server/common/data/id/NotificationRuleId.java
  42. 4
      common/data/src/main/java/org/thingsboard/server/common/data/id/NotificationTargetId.java
  43. 3
      common/data/src/main/java/org/thingsboard/server/common/data/id/NotificationTemplateId.java
  44. 3
      common/data/src/main/java/org/thingsboard/server/common/data/id/OAuth2ClientId.java
  45. 3
      common/data/src/main/java/org/thingsboard/server/common/data/id/OtaPackageId.java
  46. 3
      common/data/src/main/java/org/thingsboard/server/common/data/id/QueueId.java
  47. 3
      common/data/src/main/java/org/thingsboard/server/common/data/id/QueueStatsId.java
  48. 3
      common/data/src/main/java/org/thingsboard/server/common/data/id/RpcId.java
  49. 3
      common/data/src/main/java/org/thingsboard/server/common/data/id/RuleChainId.java
  50. 3
      common/data/src/main/java/org/thingsboard/server/common/data/id/RuleNodeId.java
  51. 3
      common/data/src/main/java/org/thingsboard/server/common/data/id/TbResourceId.java
  52. 3
      common/data/src/main/java/org/thingsboard/server/common/data/id/TenantId.java
  53. 3
      common/data/src/main/java/org/thingsboard/server/common/data/id/TenantProfileId.java
  54. 4
      common/data/src/main/java/org/thingsboard/server/common/data/id/UserId.java
  55. 3
      common/data/src/main/java/org/thingsboard/server/common/data/id/WidgetTypeId.java
  56. 3
      common/data/src/main/java/org/thingsboard/server/common/data/id/WidgetsBundleId.java
  57. 83
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/DefaultNotificationRuleRecipientsConfig.java
  58. 10
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/EscalatedNotificationRuleRecipientsConfig.java
  59. 14
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/NotificationRuleRecipientsConfig.java
  60. 4
      common/data/src/main/java/org/thingsboard/server/common/data/query/RelationsQueryFilter.java
  61. 4
      common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/DeviceExportData.java
  62. 114
      common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/EntityExportData.java
  63. 4
      common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/OtaPackageExportData.java
  64. 4
      common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/RuleChainExportData.java
  65. 4
      common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/WidgetTypeExportData.java
  66. 4
      common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/WidgetsBundleExportData.java
  67. 50
      common/data/src/test/java/org/thingsboard/server/common/data/id/EntityIdTest.java
  68. 52
      common/data/src/test/java/org/thingsboard/server/common/data/sync/ie/EntityExportDataTest.java
  69. 4
      dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotifications.java

266
application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.config;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
@ -47,6 +48,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.customizers.OpenApiCustomizer;
import org.springdoc.core.customizers.OperationCustomizer;
import org.springdoc.core.discoverer.SpringDocParameterNameDiscoverer;
import org.springdoc.core.utils.SpringDocUtils;
import org.springdoc.core.models.GroupedOpenApi;
import org.springdoc.core.properties.SpringDocConfigProperties;
import org.springdoc.core.properties.SwaggerUiConfigProperties;
@ -68,14 +70,18 @@ import org.thingsboard.server.service.security.auth.rest.LoginResponse;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.nio.ByteBuffer;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Deque;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors;
@ -90,6 +96,8 @@ public class SwaggerConfiguration {
@PostConstruct
public void configureModelResolver() {
ModelResolver.enumsAsRef = true;
SpringDocUtils.getConfig().replaceWithSchema(ByteBuffer.class,
new Schema<String>().type("string").format("byte"));
}
public static final String LOGIN_ENDPOINT = "/api/auth/login";
@ -304,23 +312,62 @@ public class SwaggerConfiguration {
schema.setProperties(null);
}
}
} else if (schema != null && schema.getProperties() != null && !schema.getProperties().isEmpty()) {
try {
var beanDesc = Json.mapper().getSerializationConfig().introspect(javaType);
var orderedNames = resolvePropertyOrder(cls, beanDesc);
if (!orderedNames.isEmpty()) {
@SuppressWarnings("unchecked")
Map<String, Schema> current = schema.getProperties();
var reordered = new LinkedHashMap<String, Schema>();
for (String name : orderedNames) {
Schema prop = current.get(name);
if (prop != null) reordered.put(name, prop);
} else if (schema != null) {
boolean hasAllOf = schema.getAllOf() != null;
boolean hasProps = schema.getProperties() != null && !schema.getProperties().isEmpty();
if (hasAllOf || hasProps) {
try {
var beanDesc = Json.mapper().getSerializationConfig().introspect(javaType);
var orderedNames = resolvePropertyOrder(cls, beanDesc);
// Reorder top-level properties if present.
// When orderedNames is empty (e.g. for interfaces where Jackson
// returns no properties from beanDesc), fall through to the
// TreeMap fallback which sorts remaining properties alphabetically.
if (hasProps) {
@SuppressWarnings("unchecked")
Map<String, Schema> current = schema.getProperties();
var reordered = new LinkedHashMap<String, Schema>();
for (String name : orderedNames) {
Schema prop = current.get(name);
if (prop != null) reordered.put(name, prop);
}
// Any properties not covered by orderedNames are appended
// alphabetically to guarantee a deterministic stable order.
new TreeMap<>(current).forEach((k, v) -> reordered.putIfAbsent(k, v));
schema.setProperties(reordered);
}
// Also reorder properties inside allOf inline elements, and mark
// which properties are declared in cls itself (not inherited from
// a superclass) so deduplicateAllOfProperties can strip inherited
// ones without touching own-class properties.
if (hasAllOf) {
Set<String> ownProps = computeOwnPropNames(cls, beanDesc);
if (!ownProps.isEmpty()) {
schema.addExtension("x-tb-own-props", List.copyOf(ownProps));
}
@SuppressWarnings("unchecked")
List<Schema> allOfList = schema.getAllOf();
for (Schema allOfElement : allOfList) {
if (allOfElement.get$ref() != null) continue;
@SuppressWarnings("unchecked")
Map<String, Schema> inlineProps = allOfElement.getProperties();
if (inlineProps == null || inlineProps.isEmpty()) continue;
var reordered = new LinkedHashMap<String, Schema>();
for (String name : orderedNames) {
Schema prop = inlineProps.get(name);
if (prop != null) reordered.put(name, prop);
}
new TreeMap<>(inlineProps).forEach((k, v) -> reordered.putIfAbsent(k, v));
allOfElement.setProperties(reordered);
}
}
} catch (Exception e) {
log.debug("Failed to resolve property order for {}: {}", cls.getName(), e.getMessage());
// Fallback: at minimum sort alphabetically for determinism
if (hasProps) {
schema.setProperties(new LinkedHashMap<>(new TreeMap<>(schema.getProperties())));
}
current.forEach((k, v) -> reordered.putIfAbsent(k, v));
schema.setProperties(reordered);
}
} catch (Exception ignored) {
log.trace("Failed to resolve property order for {}", cls.getName(), ignored);
}
}
}
@ -406,6 +453,19 @@ public class SwaggerConfiguration {
}
});
// Deduplicate allOf child schemas: remove properties that are already defined
// in the referenced parent schema to avoid duplication (e.g. EntityId children),
// then clean up the internal marker extension used during deduplication.
schemas.values().forEach(schema -> {
deduplicateAllOfProperties(schema, schemas);
if (schema.getExtensions() != null) {
schema.getExtensions().remove("x-tb-own-props");
if (schema.getExtensions().isEmpty()) {
schema.setExtensions(null);
}
}
});
// Fix polymorphic request/response bodies: replace inline oneOf with base type $ref
paths.values().stream()
.flatMap(pathItem -> pathItem.readOperationsMap().values().stream())
@ -530,6 +590,9 @@ public class SwaggerConfiguration {
if (prop.getDescription() != null) {
refSchema.setDescription(prop.getDescription());
}
if (prop.getReadOnly() != null) {
refSchema.setReadOnly(prop.getReadOnly());
}
schema.getProperties().put(propName, refSchema);
log.debug("Replaced oneOf with $ref to {} in property {}", baseType, propName);
}
@ -540,7 +603,7 @@ public class SwaggerConfiguration {
private String tagItemFromPathItem(PathItem item) {
var operations = item.readOperationsMap().values();
var operation = operations.stream().findAny();
var operation = operations.stream().findFirst();
if (operation.isPresent()) {
var tags = operation.get().getTags();
if (tags != null && !tags.isEmpty()) {
@ -676,15 +739,170 @@ public class SwaggerConfiguration {
return new ApiResponse().description(description).content(content);
}
/**
* Recursively collects all property names reachable from {@code schemaName}, walking the
* ancestor chain through allOf $ref entries (to handle multi-level inheritance).
* {@code visited} prevents infinite loops in case of circular references.
*/
@SuppressWarnings("unchecked")
private void collectAllProperties(String schemaName, Map<String, Schema> allSchemas,
Set<String> result, Set<String> visited) {
if (!visited.add(schemaName)) {
return;
}
Schema<?> schema = allSchemas.get(schemaName);
if (schema == null) {
return;
}
if (schema.getProperties() != null) {
result.addAll(schema.getProperties().keySet());
}
if (schema.getAllOf() != null) {
for (Schema<?> allOfElement : schema.getAllOf()) {
String ref = allOfElement.get$ref();
if (ref != null) {
String refName = ref.substring(ref.lastIndexOf('/') + 1);
collectAllProperties(refName, allSchemas, result, visited);
} else if (allOfElement.getProperties() != null) {
result.addAll(allOfElement.getProperties().keySet());
}
}
}
}
@SuppressWarnings("unchecked")
private void deduplicateAllOfProperties(Schema<?> schema, Map<String, Schema> allSchemas) {
if (schema.getAllOf() == null) {
return;
}
// Properties declared in the class's own fields (not inherited from a superclass).
// These must NOT be stripped from the inline even if they also appear in a parent
// schema (e.g. a field that also has a corresponding interface getter in the parent).
Set<String> ownProps = new LinkedHashSet<>();
if (schema.getExtensions() != null
&& schema.getExtensions().get("x-tb-own-props") instanceof List<?> list) {
for (Object v : list) {
if (v instanceof String s) ownProps.add(s);
}
}
// Collect properties defined in any $ref'd parent within the allOf, recursively
// walking the ancestor chain (each parent may itself use allOf to extend a grandparent).
Set<String> parentProperties = new LinkedHashSet<>();
for (Schema<?> allOfElement : schema.getAllOf()) {
String ref = allOfElement.get$ref();
if (ref != null) {
String refName = ref.substring(ref.lastIndexOf('/') + 1);
collectAllProperties(refName, allSchemas, parentProperties, new LinkedHashSet<>());
}
}
if (parentProperties.isEmpty()) {
return;
}
// Properties to strip: in parent schema AND not declared as own-class fields.
// This removes inherited properties (from superclasses or pure interface getters)
// while keeping properties the class declares as its own fields.
Set<String> toStrip = new LinkedHashSet<>(parentProperties);
toStrip.removeAll(ownProps);
if (toStrip.isEmpty()) {
return;
}
// Strip from inline (non-$ref) allOf elements
schema.getAllOf().removeIf(allOfElement -> {
if (allOfElement.get$ref() != null) {
return false;
}
if (allOfElement.getProperties() != null) {
Map<String, Schema> filtered = new LinkedHashMap<>(allOfElement.getProperties());
filtered.keySet().removeAll(toStrip);
allOfElement.setProperties(filtered.isEmpty() ? null : filtered);
}
return allOfElement.getProperties() == null
&& allOfElement.getRequired() == null
&& allOfElement.getType() == null;
});
// Remove stripped properties from the schema's required list
if (schema.getRequired() != null) {
List<String> required = new ArrayList<>(schema.getRequired());
required.removeAll(toStrip);
schema.setRequired(required.isEmpty() ? null : required);
}
}
/**
* Returns the JSON property names that are backed by fields declared directly in {@code cls}
* (not inherited from a superclass). Used to distinguish "own" from "inherited" properties
* when deduplicating allOf inline elements.
*/
private static Set<String> computeOwnPropNames(Class<?> cls, com.fasterxml.jackson.databind.BeanDescription beanDesc) {
Map<String, String> allFieldToJson = new LinkedHashMap<>();
for (var prop : beanDesc.findProperties()) {
if (prop.getField() != null && prop.couldSerialize()) {
allFieldToJson.put(prop.getField().getName(), prop.getName());
}
}
Set<String> own = new LinkedHashSet<>();
for (Field f : cls.getDeclaredFields()) {
if (Modifier.isStatic(f.getModifiers())) continue;
String jsonName = allFieldToJson.get(f.getName());
if (jsonName != null) own.add(jsonName);
}
return own;
}
/**
* Resolves the property ordering for a schema class.
*
* <p>Returns a list of JSON property names in the order they should appear in the
* OpenAPI schema. The caller uses this list to reorder the schema's property map;
* any properties <b>not</b> present in the returned list are appended alphabetically
* by the caller's {@code TreeMap} fallback, guaranteeing a stable, deterministic order.
*
* <p><b>Resolution strategy (first match wins):</b>
* <ol>
* <li>If {@code @JsonPropertyOrder} with an explicit {@code value()} is found on the
* class or any interface in its ancestry, that list is returned as-is. Note: if the
* annotation lists only a subset of fields, those fields are ordered first and the
* remaining properties fall through to the caller's alphabetical fallback — consistent
* with Jackson's own behaviour for partial {@code @JsonPropertyOrder}.</li>
* <li>Otherwise, field-backed properties are returned in declaration order (superclass
* fields first). Getter-only properties are intentionally excluded to avoid
* non-deterministic ordering across restarts.</li>
* </ol>
*/
private static List<String> resolvePropertyOrder(Class<?> cls, com.fasterxml.jackson.databind.BeanDescription beanDesc) {
// If an explicit @JsonPropertyOrder is present on the class or any interface in its
// ancestry, honour it directly. Walk up the class hierarchy; for each class also walk
// the full interface hierarchy (including super-interfaces) via BFS.
for (Class<?> c = cls; c != null && c != Object.class; c = c.getSuperclass()) {
JsonPropertyOrder propOrder = c.getAnnotation(JsonPropertyOrder.class);
if (propOrder != null && !propOrder.alphabetic() && propOrder.value().length > 0) {
return Arrays.asList(propOrder.value());
}
Deque<Class<?>> ifaceQueue = new ArrayDeque<>(Arrays.asList(c.getInterfaces()));
Set<Class<?>> visitedIfaces = new LinkedHashSet<>();
while (!ifaceQueue.isEmpty()) {
Class<?> iface = ifaceQueue.poll();
if (!visitedIfaces.add(iface)) continue;
propOrder = iface.getAnnotation(JsonPropertyOrder.class);
if (propOrder != null && !propOrder.alphabetic() && propOrder.value().length > 0) {
return Arrays.asList(propOrder.value());
}
ifaceQueue.addAll(Arrays.asList(iface.getInterfaces()));
}
}
// Map backing field names to their JSON property names (respects @JsonProperty)
Map<String, String> fieldToJsonName = new LinkedHashMap<>();
LinkedHashSet<String> getterOnlyNames = new LinkedHashSet<>();
for (var prop : beanDesc.findProperties()) {
if (prop.getField() != null) {
if (prop.getField() != null && prop.couldSerialize()) {
fieldToJsonName.put(prop.getField().getName(), prop.getName());
} else {
getterOnlyNames.add(prop.getName());
}
}
@ -702,8 +920,12 @@ public class SwaggerConfiguration {
}
}
// Append getter-only properties (no backing field) at the end
ordered.addAll(getterOnlyNames);
// Return only field-backed properties in declaration order.
// Getter-only properties (no backing field) are intentionally excluded: their set can vary
// between restarts (e.g. Optional-typed getters depend on Jackson module registration order),
// so including them here would make their position non-deterministic when some are in orderedNames
// and others are only in the schema map. The converter's TreeMap fallback handles ALL
// non-field-backed properties together in one alphabetical pass, guaranteeing stable order.
return ordered;
}

2
application/src/main/java/org/thingsboard/server/controller/ApiKeyController.java

@ -68,7 +68,7 @@ public class ApiKeyController extends BaseController {
private final ApiKeyService apiKeyService;
@ApiOperation(value = "Save API key for user (saveApiKey)",
notes = "Creates an API key for the given user and returns the token ONCE as 'ApiKey <value>'." + AVAILABLE_FOR_ANY_AUTHORIZED_USER)
notes = "Creates an API key for the given user and returns the token ONCE as 'ApiKey {value}'." + AVAILABLE_FOR_ANY_AUTHORIZED_USER)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN', 'CUSTOMER_USER')")
@PostMapping(value = "/apiKey")
public ApiKey saveApiKey(

22
application/src/main/java/org/thingsboard/server/controller/DeviceController.java

@ -206,16 +206,16 @@ public class DeviceController extends BaseController {
notes = "Create or update the Device. When creating device, platform generates Device Id as " + UUID_WIKI_LINK +
"Requires to provide the Device Credentials object as well as an existing device profile ID or use \"default\".\n" +
"You may find the example of device with different type of credentials below: \n\n" +
"- Credentials type: <b>\"Access token\"</b> with <b>device profile ID</b> below: \n\n" +
"- Credentials type: **\"Access token\"** with **device profile ID** below: \n\n" +
DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_ACCESS_TOKEN_DESCRIPTION_MARKDOWN + "\n\n" +
"- Credentials type: <b>\"Access token\"</b> with <b>device profile default</b> below: \n\n" +
"- Credentials type: **\"Access token\"** with **device profile default** below: \n\n" +
DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_ACCESS_TOKEN_DEFAULT_DESCRIPTION_MARKDOWN + "\n\n" +
"- Credentials type: <b>\"X509\"</b> with <b>device profile ID</b> below: \n\n" +
"Note: <b>credentialsId</b> - format <b>Sha3Hash</b>, <b>certificateValue</b> - format <b>PEM</b> (with \"--BEGIN CERTIFICATE----\" and -\"----END CERTIFICATE-\").\n\n" +
"- Credentials type: **\"X509\"** with **device profile ID** below: \n\n" +
"Note: **credentialsId** - format **Sha3Hash**, **certificateValue** - format **PEM** (with \"--BEGIN CERTIFICATE----\" and -\"----END CERTIFICATE-\").\n\n" +
DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_X509_CERTIFICATE_DESCRIPTION_MARKDOWN + "\n\n" +
"- Credentials type: <b>\"MQTT_BASIC\"</b> with <b>device profile ID</b> below: \n\n" +
"- Credentials type: **\"MQTT_BASIC\"** with **device profile ID** below: \n\n" +
DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_MQTT_BASIC_DESCRIPTION_MARKDOWN + "\n\n" +
"- You may find the example of <b>LwM2M</b> device and <b>RPK</b> credentials below: \n\n" +
"- You may find the example of **LwM2M** device and **RPK** credentials below: \n\n" +
"Note: LwM2M device - only existing device profile ID (Transport configuration -> Transport type: \"LWM2M\".\n\n" +
DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION_MARKDOWN + "\n\n" +
"Remove 'id', 'tenantId' and optionally 'customerId' from the request body example (below) to create new Device entity. " +
@ -322,14 +322,14 @@ public class DeviceController extends BaseController {
"Then use current method to update the credentials type and value. It is not possible to create multiple device credentials for the same device.\n" +
"The structure of device credentials id and value is simple for the 'ACCESS_TOKEN' but is much more complex for the 'MQTT_BASIC' or 'LWM2M_CREDENTIALS'.\n" +
"You may find the example of device with different type of credentials below: \n\n" +
"- Credentials type: <b>\"Access token\"</b> with <b>device ID</b> and with <b>device ID</b> below: \n\n" +
"- Credentials type: **\"Access token\"** with **device ID** and with **device ID** below: \n\n" +
DEVICE_UPDATE_CREDENTIALS_PARAM_ACCESS_TOKEN_DESCRIPTION_MARKDOWN + "\n\n" +
"- Credentials type: <b>\"X509\"</b> with <b>device profile ID</b> below: \n\n" +
"Note: <b>credentialsId</b> - format <b>Sha3Hash</b>, <b>certificateValue</b> - format <b>PEM</b> (with \"--BEGIN CERTIFICATE----\" and -\"----END CERTIFICATE-\").\n\n" +
"- Credentials type: **\"X509\"** with **device profile ID** below: \n\n" +
"Note: **credentialsId** - format **Sha3Hash**, **certificateValue** - format **PEM** (with \"--BEGIN CERTIFICATE----\" and -\"----END CERTIFICATE-\").\n\n" +
DEVICE_UPDATE_CREDENTIALS_PARAM_X509_CERTIFICATE_DESCRIPTION_MARKDOWN + "\n\n" +
"- Credentials type: <b>\"MQTT_BASIC\"</b> with <b>device profile ID</b> below: \n\n" +
"- Credentials type: **\"MQTT_BASIC\"** with **device profile ID** below: \n\n" +
DEVICE_UPDATE_CREDENTIALS_PARAM_MQTT_BASIC_DESCRIPTION_MARKDOWN + "\n\n" +
"- You may find the example of <b>LwM2M</b> device and <b>RPK</b> credentials below: \n\n" +
"- You may find the example of **LwM2M** device and **RPK** credentials below: \n\n" +
"Note: LwM2M device - only existing device profile ID (Transport configuration -> Transport type: \"LWM2M\".\n\n" +
DEVICE_UPDATE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION_MARKDOWN + "\n\n" +
"Update to real value:\n" +

6
application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java

@ -214,19 +214,19 @@ public class EntitiesVersionControlController extends BaseController {
" \"timestamp\": 1655198593000,\n" +
" \"id\": \"fd82625bdd7d6131cf8027b44ee967012ecaf990\",\n" +
" \"name\": \"Devices and assets - v2.0\",\n" +
" \"author\": \"John Doe <johndoe@gmail.com>\"\n" +
" \"author\": \"John Doe (johndoe@gmail.com)\"\n" +
" },\n" +
" {\n" +
" \"timestamp\": 1655198528000,\n" +
" \"id\": \"682adcffa9c8a2f863af6f00c4850323acbd4219\",\n" +
" \"name\": \"Update my device\",\n" +
" \"author\": \"John Doe <johndoe@gmail.com>\"\n" +
" \"author\": \"John Doe (johndoe@gmail.com)\"\n" +
" },\n" +
" {\n" +
" \"timestamp\": 1655198280000,\n" +
" \"id\": \"d2a6087c2b30e18cc55e7cdda345a8d0dfb959a4\",\n" +
" \"name\": \"Devices and assets - v1.0\",\n" +
" \"author\": \"John Doe <johndoe@gmail.com>\"\n" +
" \"author\": \"John Doe (johndoe@gmail.com)\"\n" +
" }\n" +
" ],\n" +
" \"totalPages\": 1,\n" +

4
application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/BaseEntityExportService.java

@ -42,10 +42,6 @@ public abstract class BaseEntityExportService<I extends EntityId, E extends Expo
protected void setRelatedEntities(EntitiesExportCtx<?> ctx, E mainEntity, D exportData) {
}
protected D newExportData() {
return (D) new EntityExportData<E>();
}
public abstract Set<EntityType> getSupportedEntityTypes();
protected void replaceUuidsRecursively(EntitiesExportCtx<?> ctx, JsonNode node, Set<String> skippedRootFields, Pattern includedFieldsPattern) {

8
application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DefaultEntityExportService.java

@ -70,7 +70,8 @@ public class DefaultEntityExportService<I extends EntityId, E extends Exportable
@Override
public final D getExportData(EntitiesExportCtx<?> ctx, I entityId) throws ThingsboardException {
D exportData = newExportData();
@SuppressWarnings("unchecked")
D exportData = (D) EntityExportData.newInstance(entityId.getEntityType());
E entity = exportableEntitiesService.findEntityByTenantIdAndId(ctx.getTenantId(), entityId);
if (entity == null) {
@ -78,7 +79,6 @@ public class DefaultEntityExportService<I extends EntityId, E extends Exportable
}
exportData.setEntity(entity);
exportData.setEntityType(entityId.getEntityType());
setAdditionalExportData(ctx, entity, exportData);
if (entity instanceof HasVersion hasVersion) {
hasVersion.setVersion(null);
@ -223,8 +223,4 @@ public class DefaultEntityExportService<I extends EntityId, E extends Exportable
return internalUuid;
}
protected D newExportData() {
return (D) new EntityExportData<E>();
}
}

5
application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DeviceExportService.java

@ -48,11 +48,6 @@ public class DeviceExportService extends BaseEntityExportService<DeviceId, Devic
}
}
@Override
protected DeviceExportData newExportData() {
return new DeviceExportData();
}
@Override
public Set<EntityType> getSupportedEntityTypes() {
return Set.of(EntityType.DEVICE);

5
application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/OtaPackageExportService.java

@ -36,11 +36,6 @@ public class OtaPackageExportService extends BaseEntityExportService<OtaPackageI
otaPackage.setDeviceProfileId(getExternalIdOrElseInternal(ctx, otaPackage.getDeviceProfileId()));
}
@Override
protected OtaPackageExportData newExportData() {
return new OtaPackageExportData();
}
@Override
public Set<EntityType> getSupportedEntityTypes() {
return Set.of(EntityType.OTA_PACKAGE);

5
application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/RuleChainExportService.java

@ -61,11 +61,6 @@ public class RuleChainExportService extends BaseEntityExportService<RuleChainId,
}
}
@Override
protected RuleChainExportData newExportData() {
return new RuleChainExportData();
}
@Override
public Set<EntityType> getSupportedEntityTypes() {
return Set.of(EntityType.RULE_CHAIN);

5
application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/WidgetTypeExportService.java

@ -38,11 +38,6 @@ public class WidgetTypeExportService extends BaseEntityExportService<WidgetTypeI
}
}
@Override
protected WidgetTypeExportData newExportData() {
return new WidgetTypeExportData();
}
@Override
public Set<EntityType> getSupportedEntityTypes() {
return Set.of(EntityType.WIDGET_TYPE);

5
application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/WidgetsBundleExportService.java

@ -45,11 +45,6 @@ public class WidgetsBundleExportService extends BaseEntityExportService<WidgetsB
exportData.setFqns(fqns);
}
@Override
protected WidgetsBundleExportData newExportData() {
return new WidgetsBundleExportData();
}
@Override
public Set<EntityType> getSupportedEntityTypes() {
return Set.of(EntityType.WIDGETS_BUNDLE);

3
application/src/test/java/org/thingsboard/server/service/notification/AbstractNotificationApiTest.java

@ -188,8 +188,7 @@ public abstract class AbstractNotificationApiTest extends AbstractControllerTest
rule.setTriggerType(triggerConfig.getTriggerType());
rule.setTriggerConfig(triggerConfig);
DefaultNotificationRuleRecipientsConfig recipientsConfig = new DefaultNotificationRuleRecipientsConfig();
recipientsConfig.setTriggerType(triggerConfig.getTriggerType());
DefaultNotificationRuleRecipientsConfig recipientsConfig = DefaultNotificationRuleRecipientsConfig.forTriggerType(triggerConfig.getTriggerType());
recipientsConfig.setTargets(DaoUtil.toUUIDs(targets));
rule.setRecipientsConfig(recipientsConfig);

8
application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java

@ -211,7 +211,6 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
notificationRule.setTriggerConfig(triggerConfig);
EscalatedNotificationRuleRecipientsConfig recipientsConfig = new EscalatedNotificationRuleRecipientsConfig();
recipientsConfig.setTriggerType(NotificationRuleTriggerType.ALARM);
Map<Integer, List<UUID>> escalationTable = new HashMap<>();
recipientsConfig.setEscalationTable(escalationTable);
Map<Integer, NotificationApiWsClient> clients = new HashMap<>();
@ -329,7 +328,6 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
notificationRule.setTriggerConfig(triggerConfig);
EscalatedNotificationRuleRecipientsConfig recipientsConfig = new EscalatedNotificationRuleRecipientsConfig();
recipientsConfig.setTriggerType(NotificationRuleTriggerType.ALARM);
Map<Integer, List<UUID>> escalationTable = new HashMap<>();
recipientsConfig.setEscalationTable(escalationTable);
@ -640,8 +638,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
EntityActionNotificationRuleTriggerConfig triggerConfig = new EntityActionNotificationRuleTriggerConfig();
rule.setTriggerConfig(triggerConfig);
DefaultNotificationRuleRecipientsConfig recipientsConfig = new DefaultNotificationRuleRecipientsConfig();
recipientsConfig.setTriggerType(NotificationRuleTriggerType.ENTITY_ACTION);
DefaultNotificationRuleRecipientsConfig recipientsConfig = DefaultNotificationRuleRecipientsConfig.forTriggerType(NotificationRuleTriggerType.ENTITY_ACTION);
recipientsConfig.setTargets(List.of(createNotificationTarget(tenantAdminUserId).getUuidId()));
rule.setRecipientsConfig(recipientsConfig);
rule = saveNotificationRule(rule);
@ -671,8 +668,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
triggerConfig.setCreated(true);
rule.setTriggerConfig(triggerConfig);
NotificationTarget target = createNotificationTarget(tenantAdminUserId);
DefaultNotificationRuleRecipientsConfig recipientsConfig = new DefaultNotificationRuleRecipientsConfig();
recipientsConfig.setTriggerType(NotificationRuleTriggerType.ENTITY_ACTION);
DefaultNotificationRuleRecipientsConfig recipientsConfig = DefaultNotificationRuleRecipientsConfig.forTriggerType(NotificationRuleTriggerType.ENTITY_ACTION);
recipientsConfig.setTargets(List.of(target.getUuidId()));
rule.setRecipientsConfig(recipientsConfig);
rule = saveNotificationRule(rule);

2
common/data/src/main/java/org/thingsboard/server/common/data/Dashboard.java

@ -33,7 +33,7 @@ import java.util.Optional;
import java.util.stream.Collectors;
@EqualsAndHashCode(callSuper = true)
@JsonPropertyOrder({"title", "image", "mobileHide", "mobileOrder", "configuration", "name", "resources"})
@JsonPropertyOrder({"id", "createdTime", "tenantId", "title", "name", "image", "mobileHide", "mobileOrder", "assignedCustomers", "configuration", "resources", "version"})
public class Dashboard extends DashboardInfo implements ExportableEntity<DashboardId> {
private static final long serialVersionUID = 872682138346187503L;

16
common/data/src/main/java/org/thingsboard/server/common/data/FeaturesInfo.java

@ -15,13 +15,29 @@
*/
package org.thingsboard.server.common.data;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@JsonPropertyOrder({
"emailEnabled",
"smsEnabled",
"notificationEnabled",
"oauthEnabled",
"twoFaEnabled"
})
@Schema
@Data
public class FeaturesInfo {
@JsonProperty("emailEnabled")
boolean isEmailEnabled;
@JsonProperty("smsEnabled")
boolean isSmsEnabled;
@JsonProperty("notificationEnabled")
boolean isNotificationEnabled;
@JsonProperty("oauthEnabled")
boolean isOauthEnabled;
@JsonProperty("twoFaEnabled")
boolean isTwoFaEnabled;
}

11
common/data/src/main/java/org/thingsboard/server/common/data/ShortCustomerInfo.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.common.data;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Getter;
@ -39,9 +40,15 @@ public class ShortCustomerInfo {
@NoXss
private String title;
@JsonProperty("isPublic")
@Schema(description = "Indicates special 'Public' customer used to embed dashboards on public websites.")
@Getter @Setter
private boolean isPublic;
private boolean publicCustomer;
@JsonProperty("isPublic")
public boolean isPublic() { return publicCustomer; }
@JsonProperty("isPublic")
public void setPublic(boolean publicCustomer) { this.publicCustomer = publicCustomer; }
@Override
public boolean equals(Object o) {

2
common/data/src/main/java/org/thingsboard/server/common/data/SystemInfo.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.common.data;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@ -23,6 +24,7 @@ import java.util.List;
@Data
public class SystemInfo {
@Schema(description = "Is monolith.")
@JsonProperty("monolith")
private boolean isMonolith;
@Schema(description = "System data.")
private List<SystemInfoData> systemData;

1
common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java

@ -84,6 +84,7 @@ public class Alarm extends BaseData<AlarmId> implements HasName, HasTenantId, Ha
@Schema(description = "Timestamp of the alarm assignment, in milliseconds", example = "1634115928465")
private long assignTs;
@Schema(description = "JSON object with alarm details")
@JsonProperty
private transient JsonNode details;
@Schema(description = "Propagation flag to specify if alarm should be propagated to parent entities of alarm originator", example = "true")
private boolean propagate;

8
common/data/src/main/java/org/thingsboard/server/common/data/event/DebugEventFilter.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.common.data.event;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.thingsboard.server.common.data.StringUtils;
@ -26,10 +27,17 @@ public abstract class DebugEventFilter implements EventFilter {
@Schema(description = "String value representing the server name, identifier or ip address where the platform is running", example = "ip-172-31-24-152")
protected String server;
@Schema(description = "Boolean value to filter the errors", allowableValues = {"false", "true"})
@JsonProperty("isError")
protected boolean isError;
@Schema(description = "The case insensitive 'contains' filter based on error message", example = "not present in the DB")
protected String errorStr;
@JsonProperty("isError")
public boolean isError() {
return isError;
}
@JsonProperty("isError")
public void setIsError(boolean isError) {
this.isError = isError;
}

3
common/data/src/main/java/org/thingsboard/server/common/data/id/AdminSettingsId.java

@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.io.Serial;
import java.util.UUID;
@Schema(allOf = EntityId.class)
public class AdminSettingsId extends UUIDBased implements EntityId {
@Serial
@ -33,7 +34,7 @@ public class AdminSettingsId extends UUIDBased implements EntityId {
super(id);
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "ADMIN_SETTINGS", allowableValues = "ADMIN_SETTINGS")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "ADMIN_SETTINGS", allowableValues = "ADMIN_SETTINGS")
@Override
public EntityType getEntityType() {
return EntityType.ADMIN_SETTINGS;

2
common/data/src/main/java/org/thingsboard/server/common/data/id/AiModelId.java

@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.io.Serial;
import java.util.UUID;
@Schema(allOf = EntityId.class)
public final class AiModelId extends UUIDBased implements EntityId {
@Serial
@ -36,6 +37,7 @@ public final class AiModelId extends UUIDBased implements EntityId {
@Override
@Schema(
requiredMode = Schema.RequiredMode.REQUIRED,
accessMode = Schema.AccessMode.READ_ONLY,
description = "Entity type of the AI model",
example = "AI_MODEL",
allowableValues = "AI_MODEL"

4
common/data/src/main/java/org/thingsboard/server/common/data/id/AlarmId.java

@ -22,7 +22,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@Schema
@Schema(allOf = EntityId.class)
public class AlarmId extends UUIDBased implements EntityId {
private static final long serialVersionUID = 1L;
@ -36,7 +36,7 @@ public class AlarmId extends UUIDBased implements EntityId {
return new AlarmId(UUID.fromString(alarmId));
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "ALARM", allowableValues = "ALARM")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "ALARM", allowableValues = "ALARM")
@Override
public EntityType getEntityType() {
return EntityType.ALARM;

3
common/data/src/main/java/org/thingsboard/server/common/data/id/ApiKeyId.java

@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.io.Serial;
import java.util.UUID;
@Schema(allOf = EntityId.class)
public class ApiKeyId extends UUIDBased implements EntityId {
@Serial
@ -38,7 +39,7 @@ public class ApiKeyId extends UUIDBased implements EntityId {
}
@Override
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "API_KEY", allowableValues = "API_KEY")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "API_KEY", allowableValues = "API_KEY")
public EntityType getEntityType() {
return EntityType.API_KEY;
}

4
common/data/src/main/java/org/thingsboard/server/common/data/id/ApiUsageStateId.java

@ -22,7 +22,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@Schema
@Schema(allOf = EntityId.class)
public class ApiUsageStateId extends UUIDBased implements EntityId {
@JsonCreator
@ -34,7 +34,7 @@ public class ApiUsageStateId extends UUIDBased implements EntityId {
return new ApiUsageStateId(UUID.fromString(userId));
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "API_USAGE_STATE", allowableValues = "API_USAGE_STATE")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "API_USAGE_STATE", allowableValues = "API_USAGE_STATE")
@Override
public EntityType getEntityType() {
return EntityType.API_USAGE_STATE;

4
common/data/src/main/java/org/thingsboard/server/common/data/id/AssetId.java

@ -22,7 +22,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@Schema
@Schema(allOf = EntityId.class)
public class AssetId extends UUIDBased implements EntityId {
private static final long serialVersionUID = 1L;
@ -36,7 +36,7 @@ public class AssetId extends UUIDBased implements EntityId {
return new AssetId(UUID.fromString(assetId));
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "ASSET", allowableValues = "ASSET")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "ASSET", allowableValues = "ASSET")
@Override
public EntityType getEntityType() {
return EntityType.ASSET;

3
common/data/src/main/java/org/thingsboard/server/common/data/id/AssetProfileId.java

@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@Schema(allOf = EntityId.class)
public class AssetProfileId extends UUIDBased implements EntityId {
private static final long serialVersionUID = 1L;
@ -35,7 +36,7 @@ public class AssetProfileId extends UUIDBased implements EntityId {
return new AssetProfileId(UUID.fromString(assetProfileId));
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "ASSET_PROFILE", allowableValues = "ASSET_PROFILE")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "ASSET_PROFILE", allowableValues = "ASSET_PROFILE")
@Override
public EntityType getEntityType() {
return EntityType.ASSET_PROFILE;

4
common/data/src/main/java/org/thingsboard/server/common/data/id/CalculatedFieldId.java

@ -23,7 +23,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.io.Serial;
import java.util.UUID;
@Schema
@Schema(allOf = EntityId.class)
public class CalculatedFieldId extends UUIDBased implements EntityId {
@Serial
@ -38,7 +38,7 @@ public class CalculatedFieldId extends UUIDBased implements EntityId {
return new CalculatedFieldId(UUID.fromString(calculatedFieldId));
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "CALCULATED_FIELD", allowableValues = "CALCULATED_FIELD")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "CALCULATED_FIELD", allowableValues = "CALCULATED_FIELD")
@Override
public EntityType getEntityType() {
return EntityType.CALCULATED_FIELD;

4
common/data/src/main/java/org/thingsboard/server/common/data/id/CustomerId.java

@ -22,7 +22,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@Schema
@Schema(allOf = EntityId.class)
public final class CustomerId extends UUIDBased implements EntityId {
private static final long serialVersionUID = 1L;
@ -32,7 +32,7 @@ public final class CustomerId extends UUIDBased implements EntityId {
super(id);
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "CUSTOMER", allowableValues = "CUSTOMER")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "CUSTOMER", allowableValues = "CUSTOMER")
@Override
public EntityType getEntityType() {
return EntityType.CUSTOMER;

4
common/data/src/main/java/org/thingsboard/server/common/data/id/DashboardId.java

@ -22,7 +22,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@Schema
@Schema(allOf = EntityId.class)
public class DashboardId extends UUIDBased implements EntityId {
@JsonCreator
@ -34,7 +34,7 @@ public class DashboardId extends UUIDBased implements EntityId {
return new DashboardId(UUID.fromString(dashboardId));
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "DASHBOARD", allowableValues = "DASHBOARD")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "DASHBOARD", allowableValues = "DASHBOARD")
@Override
public EntityType getEntityType() {
return EntityType.DASHBOARD;

4
common/data/src/main/java/org/thingsboard/server/common/data/id/DeviceId.java

@ -22,7 +22,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@Schema
@Schema(allOf = EntityId.class)
public class DeviceId extends UUIDBased implements EntityId {
private static final long serialVersionUID = 1L;
@ -37,7 +37,7 @@ public class DeviceId extends UUIDBased implements EntityId {
}
@Override
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "DEVICE", allowableValues = "DEVICE")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "DEVICE", allowableValues = "DEVICE")
public EntityType getEntityType() {
return EntityType.DEVICE;
}

3
common/data/src/main/java/org/thingsboard/server/common/data/id/DeviceProfileId.java

@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@Schema(allOf = EntityId.class)
public class DeviceProfileId extends UUIDBased implements EntityId {
private static final long serialVersionUID = 1L;
@ -35,7 +36,7 @@ public class DeviceProfileId extends UUIDBased implements EntityId {
return new DeviceProfileId(UUID.fromString(deviceProfileId));
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "DEVICE_PROFILE", allowableValues = "DEVICE_PROFILE")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "DEVICE_PROFILE", allowableValues = "DEVICE_PROFILE")
@Override
public EntityType getEntityType() {
return EntityType.DEVICE_PROFILE;

3
common/data/src/main/java/org/thingsboard/server/common/data/id/DomainId.java

@ -17,10 +17,12 @@ package org.thingsboard.server.common.data.id;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@Schema(allOf = EntityId.class)
public class DomainId extends UUIDBased implements EntityId {
@JsonCreator
@ -32,6 +34,7 @@ public class DomainId extends UUIDBased implements EntityId {
return new DomainId(UUID.fromString(oauth2DomainId));
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "DOMAIN", allowableValues = "DOMAIN")
@Override
public EntityType getEntityType() {
return EntityType.DOMAIN;

3
common/data/src/main/java/org/thingsboard/server/common/data/id/EdgeId.java

@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.io.Serial;
import java.util.UUID;
@Schema(allOf = EntityId.class)
public class EdgeId extends UUIDBased implements EntityId {
@Serial
@ -43,7 +44,7 @@ public class EdgeId extends UUIDBased implements EntityId {
return new EdgeId(UUID.fromString(edgeId));
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "EDGE", allowableValues = "EDGE")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "EDGE", allowableValues = "EDGE")
@Override
public EntityType getEntityType() {
return EntityType.EDGE;

43
common/data/src/main/java/org/thingsboard/server/common/data/id/EntityId.java

@ -18,6 +18,7 @@ package org.thingsboard.server.common.data.id;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import io.swagger.v3.oas.annotations.media.DiscriminatorMapping;
import io.swagger.v3.oas.annotations.media.Schema;
import org.thingsboard.server.common.data.EntityType;
@ -26,7 +27,47 @@ import java.util.UUID;
@JsonDeserialize(using = EntityIdDeserializer.class)
@JsonSerialize(using = EntityIdSerializer.class)
@Schema
@Schema(
discriminatorProperty = "entityType",
discriminatorMapping = {
@DiscriminatorMapping(value = "ADMIN_SETTINGS", schema = AdminSettingsId.class),
@DiscriminatorMapping(value = "AI_MODEL", schema = AiModelId.class),
@DiscriminatorMapping(value = "ALARM", schema = AlarmId.class),
@DiscriminatorMapping(value = "API_KEY", schema = ApiKeyId.class),
@DiscriminatorMapping(value = "API_USAGE_STATE", schema = ApiUsageStateId.class),
@DiscriminatorMapping(value = "ASSET", schema = AssetId.class),
@DiscriminatorMapping(value = "ASSET_PROFILE", schema = AssetProfileId.class),
@DiscriminatorMapping(value = "CALCULATED_FIELD", schema = CalculatedFieldId.class),
@DiscriminatorMapping(value = "CUSTOMER", schema = CustomerId.class),
@DiscriminatorMapping(value = "DASHBOARD", schema = DashboardId.class),
@DiscriminatorMapping(value = "DEVICE", schema = DeviceId.class),
@DiscriminatorMapping(value = "DEVICE_PROFILE", schema = DeviceProfileId.class),
@DiscriminatorMapping(value = "DOMAIN", schema = DomainId.class),
@DiscriminatorMapping(value = "EDGE", schema = EdgeId.class),
@DiscriminatorMapping(value = "ENTITY_VIEW", schema = EntityViewId.class),
@DiscriminatorMapping(value = "JOB", schema = JobId.class),
@DiscriminatorMapping(value = "MOBILE_APP", schema = MobileAppId.class),
@DiscriminatorMapping(value = "MOBILE_APP_BUNDLE", schema = MobileAppBundleId.class),
@DiscriminatorMapping(value = "NOTIFICATION", schema = NotificationId.class),
@DiscriminatorMapping(value = "NOTIFICATION_REQUEST", schema = NotificationRequestId.class),
@DiscriminatorMapping(value = "NOTIFICATION_RULE", schema = NotificationRuleId.class),
@DiscriminatorMapping(value = "NOTIFICATION_TARGET", schema = NotificationTargetId.class),
@DiscriminatorMapping(value = "NOTIFICATION_TEMPLATE", schema = NotificationTemplateId.class),
@DiscriminatorMapping(value = "OAUTH2_CLIENT", schema = OAuth2ClientId.class),
@DiscriminatorMapping(value = "OTA_PACKAGE", schema = OtaPackageId.class),
@DiscriminatorMapping(value = "QUEUE", schema = QueueId.class),
@DiscriminatorMapping(value = "QUEUE_STATS", schema = QueueStatsId.class),
@DiscriminatorMapping(value = "RPC", schema = RpcId.class),
@DiscriminatorMapping(value = "RULE_CHAIN", schema = RuleChainId.class),
@DiscriminatorMapping(value = "RULE_NODE", schema = RuleNodeId.class),
@DiscriminatorMapping(value = "TB_RESOURCE", schema = TbResourceId.class),
@DiscriminatorMapping(value = "TENANT", schema = TenantId.class),
@DiscriminatorMapping(value = "TENANT_PROFILE", schema = TenantProfileId.class),
@DiscriminatorMapping(value = "USER", schema = UserId.class),
@DiscriminatorMapping(value = "WIDGETS_BUNDLE", schema = WidgetsBundleId.class),
@DiscriminatorMapping(value = "WIDGET_TYPE", schema = WidgetTypeId.class)
}
)
public interface EntityId extends HasUUID, Serializable { //NOSONAR, the constant is closely related to EntityId
UUID NULL_UUID = UUID.fromString("13814000-1dd2-11b2-8080-808080808080");

3
common/data/src/main/java/org/thingsboard/server/common/data/id/EntityViewId.java

@ -25,6 +25,7 @@ import java.util.UUID;
/**
* Created by Victor Basanets on 8/27/2017.
*/
@Schema(allOf = EntityId.class)
public class EntityViewId extends UUIDBased implements EntityId {
private static final long serialVersionUID = 1L;
@ -38,7 +39,7 @@ public class EntityViewId extends UUIDBased implements EntityId {
return new EntityViewId(UUID.fromString(entityViewID));
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "ENTITY_VIEW", allowableValues = "ENTITY_VIEW")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "ENTITY_VIEW", allowableValues = "ENTITY_VIEW")
@Override
public EntityType getEntityType() {
return EntityType.ENTITY_VIEW;

3
common/data/src/main/java/org/thingsboard/server/common/data/id/JobId.java

@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.io.Serial;
import java.util.UUID;
@Schema(allOf = EntityId.class)
public class JobId extends UUIDBased implements EntityId {
@Serial
@ -33,7 +34,7 @@ public class JobId extends UUIDBased implements EntityId {
super(id);
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "JOB", allowableValues = "JOB")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "JOB", allowableValues = "JOB")
@Override
public EntityType getEntityType() {
return EntityType.JOB;

3
common/data/src/main/java/org/thingsboard/server/common/data/id/MobileAppBundleId.java

@ -17,10 +17,12 @@ package org.thingsboard.server.common.data.id;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@Schema(allOf = EntityId.class)
public class MobileAppBundleId extends UUIDBased implements EntityId{
@JsonCreator
@ -32,6 +34,7 @@ public class MobileAppBundleId extends UUIDBased implements EntityId{
return new MobileAppBundleId(UUID.fromString(mobileAppId));
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "MOBILE_APP_BUNDLE", allowableValues = "MOBILE_APP_BUNDLE")
@Override
public EntityType getEntityType() {
return EntityType.MOBILE_APP_BUNDLE;

3
common/data/src/main/java/org/thingsboard/server/common/data/id/MobileAppId.java

@ -17,10 +17,12 @@ package org.thingsboard.server.common.data.id;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@Schema(allOf = EntityId.class)
public class MobileAppId extends UUIDBased implements EntityId{
@JsonCreator
@ -32,6 +34,7 @@ public class MobileAppId extends UUIDBased implements EntityId{
return new MobileAppId(UUID.fromString(mobileAppId));
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "MOBILE_APP", allowableValues = "MOBILE_APP")
@Override
public EntityType getEntityType() {
return EntityType.MOBILE_APP;

3
common/data/src/main/java/org/thingsboard/server/common/data/id/NotificationId.java

@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@Schema(allOf = EntityId.class)
public class NotificationId extends UUIDBased implements EntityId {
@JsonCreator
@ -29,7 +30,7 @@ public class NotificationId extends UUIDBased implements EntityId {
super(id);
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "NOTIFICATION", allowableValues = "NOTIFICATION")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "NOTIFICATION", allowableValues = "NOTIFICATION")
@Override
public EntityType getEntityType() {
return EntityType.NOTIFICATION;

3
common/data/src/main/java/org/thingsboard/server/common/data/id/NotificationRequestId.java

@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@Schema(allOf = EntityId.class)
public class NotificationRequestId extends UUIDBased implements EntityId {
@JsonCreator
@ -29,7 +30,7 @@ public class NotificationRequestId extends UUIDBased implements EntityId {
super(id);
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "NOTIFICATION_REQUEST", allowableValues = "NOTIFICATION_REQUEST")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "NOTIFICATION_REQUEST", allowableValues = "NOTIFICATION_REQUEST")
@Override
public EntityType getEntityType() {
return EntityType.NOTIFICATION_REQUEST;

3
common/data/src/main/java/org/thingsboard/server/common/data/id/NotificationRuleId.java

@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@Schema(allOf = EntityId.class)
public class NotificationRuleId extends UUIDBased implements EntityId {
@JsonCreator
@ -29,7 +30,7 @@ public class NotificationRuleId extends UUIDBased implements EntityId {
super(id);
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "NOTIFICATION_RULE", allowableValues = "NOTIFICATION_RULE")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "NOTIFICATION_RULE", allowableValues = "NOTIFICATION_RULE")
@Override
public EntityType getEntityType() {
return EntityType.NOTIFICATION_RULE;

4
common/data/src/main/java/org/thingsboard/server/common/data/id/NotificationTargetId.java

@ -22,7 +22,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@Schema
@Schema(allOf = EntityId.class)
public class NotificationTargetId extends UUIDBased implements EntityId {
@JsonCreator
@ -30,7 +30,7 @@ public class NotificationTargetId extends UUIDBased implements EntityId {
super(id);
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "NOTIFICATION_TARGET", allowableValues = "NOTIFICATION_TARGET")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "NOTIFICATION_TARGET", allowableValues = "NOTIFICATION_TARGET")
@Override
public EntityType getEntityType() {
return EntityType.NOTIFICATION_TARGET;

3
common/data/src/main/java/org/thingsboard/server/common/data/id/NotificationTemplateId.java

@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@Schema(allOf = EntityId.class)
public class NotificationTemplateId extends UUIDBased implements EntityId {
@JsonCreator
@ -29,7 +30,7 @@ public class NotificationTemplateId extends UUIDBased implements EntityId {
super(id);
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "NOTIFICATION_TEMPLATE", allowableValues = "NOTIFICATION_TEMPLATE")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "NOTIFICATION_TEMPLATE", allowableValues = "NOTIFICATION_TEMPLATE")
@Override
public EntityType getEntityType() {
return EntityType.NOTIFICATION_TEMPLATE;

3
common/data/src/main/java/org/thingsboard/server/common/data/id/OAuth2ClientId.java

@ -17,10 +17,12 @@ package org.thingsboard.server.common.data.id;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@Schema(allOf = EntityId.class)
public class OAuth2ClientId extends UUIDBased implements EntityId {
@JsonCreator
@ -32,6 +34,7 @@ public class OAuth2ClientId extends UUIDBased implements EntityId {
return new OAuth2ClientId(UUID.fromString(oauth2ClientId));
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "OAUTH2_CLIENT", allowableValues = "OAUTH2_CLIENT")
@Override
public EntityType getEntityType() {
return EntityType.OAUTH2_CLIENT;

3
common/data/src/main/java/org/thingsboard/server/common/data/id/OtaPackageId.java

@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.io.Serial;
import java.util.UUID;
@Schema(allOf = EntityId.class)
public class OtaPackageId extends UUIDBased implements EntityId {
@Serial
@ -37,7 +38,7 @@ public class OtaPackageId extends UUIDBased implements EntityId {
return new OtaPackageId(UUID.fromString(firmwareId));
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "OTA_PACKAGE", allowableValues = "OTA_PACKAGE")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "OTA_PACKAGE", allowableValues = "OTA_PACKAGE")
@Override
public EntityType getEntityType() {
return EntityType.OTA_PACKAGE;

3
common/data/src/main/java/org/thingsboard/server/common/data/id/QueueId.java

@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@Schema(allOf = EntityId.class)
public class QueueId extends UUIDBased implements EntityId {
private static final long serialVersionUID = 1L;
@ -35,7 +36,7 @@ public class QueueId extends UUIDBased implements EntityId {
return new QueueId(UUID.fromString(queueId));
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "QUEUE", allowableValues = "QUEUE")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "QUEUE", allowableValues = "QUEUE")
@Override
public EntityType getEntityType() {
return EntityType.QUEUE;

3
common/data/src/main/java/org/thingsboard/server/common/data/id/QueueStatsId.java

@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@Schema(allOf = EntityId.class)
public class QueueStatsId extends UUIDBased implements EntityId {
private static final long serialVersionUID = 1L;
@ -35,7 +36,7 @@ public class QueueStatsId extends UUIDBased implements EntityId {
return new QueueStatsId(UUID.fromString(queueId));
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "QUEUE_STATS", allowableValues = "QUEUE_STATS")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "QUEUE_STATS", allowableValues = "QUEUE_STATS")
@Override
public EntityType getEntityType() {
return EntityType.QUEUE_STATS;

3
common/data/src/main/java/org/thingsboard/server/common/data/id/RpcId.java

@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@Schema(allOf = EntityId.class)
public final class RpcId extends UUIDBased implements EntityId {
private static final long serialVersionUID = 1L;
@ -31,7 +32,7 @@ public final class RpcId extends UUIDBased implements EntityId {
super(id);
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "RPC", allowableValues = "RPC")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "RPC", allowableValues = "RPC")
@Override
public EntityType getEntityType() {
return EntityType.RPC;

3
common/data/src/main/java/org/thingsboard/server/common/data/id/RuleChainId.java

@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@Schema(allOf = EntityId.class)
public class RuleChainId extends UUIDBased implements EntityId {
@JsonCreator
@ -29,7 +30,7 @@ public class RuleChainId extends UUIDBased implements EntityId {
super(id);
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "RULE_CHAIN", allowableValues = "RULE_CHAIN")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "RULE_CHAIN", allowableValues = "RULE_CHAIN")
@Override
public EntityType getEntityType() {
return EntityType.RULE_CHAIN;

3
common/data/src/main/java/org/thingsboard/server/common/data/id/RuleNodeId.java

@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@Schema(allOf = EntityId.class)
public class RuleNodeId extends UUIDBased implements EntityId {
@JsonCreator
@ -29,7 +30,7 @@ public class RuleNodeId extends UUIDBased implements EntityId {
super(id);
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "RULE_NODE", allowableValues = "RULE_NODE")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "RULE_NODE", allowableValues = "RULE_NODE")
@Override
public EntityType getEntityType() {
return EntityType.RULE_NODE;

3
common/data/src/main/java/org/thingsboard/server/common/data/id/TbResourceId.java

@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@Schema(allOf = EntityId.class)
public class TbResourceId extends UUIDBased implements EntityId {
private static final long serialVersionUID = 1L;
@ -31,7 +32,7 @@ public class TbResourceId extends UUIDBased implements EntityId {
super(id);
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "TB_RESOURCE", allowableValues = "TB_RESOURCE")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "TB_RESOURCE", allowableValues = "TB_RESOURCE")
@Override
public EntityType getEntityType() {
return EntityType.TB_RESOURCE;

3
common/data/src/main/java/org/thingsboard/server/common/data/id/TenantId.java

@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.io.Serial;
import java.util.UUID;
@Schema(allOf = EntityId.class)
public final class TenantId extends UUIDBased implements EntityId {
@JsonIgnore
@ -54,7 +55,7 @@ public final class TenantId extends UUIDBased implements EntityId {
return this.equals(SYS_TENANT_ID);
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "TENANT", allowableValues = "TENANT")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "TENANT", allowableValues = "TENANT")
@Override
public EntityType getEntityType() {
return EntityType.TENANT;

3
common/data/src/main/java/org/thingsboard/server/common/data/id/TenantProfileId.java

@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@Schema(allOf = EntityId.class)
public class TenantProfileId extends UUIDBased implements EntityId {
private static final long serialVersionUID = 1L;
@ -35,7 +36,7 @@ public class TenantProfileId extends UUIDBased implements EntityId {
return new TenantProfileId(UUID.fromString(tenantProfileId));
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "TENANT_PROFILE", allowableValues = "TENANT_PROFILE")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "TENANT_PROFILE", allowableValues = "TENANT_PROFILE")
@Override
public EntityType getEntityType() {
return EntityType.TENANT_PROFILE;

4
common/data/src/main/java/org/thingsboard/server/common/data/id/UserId.java

@ -22,7 +22,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@Schema
@Schema(allOf = EntityId.class)
public class UserId extends UUIDBased implements EntityId {
@JsonCreator
@ -34,7 +34,7 @@ public class UserId extends UUIDBased implements EntityId {
return new UserId(UUID.fromString(userId));
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "USER", allowableValues = "USER")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "USER", allowableValues = "USER")
@Override
public EntityType getEntityType() {
return EntityType.USER;

3
common/data/src/main/java/org/thingsboard/server/common/data/id/WidgetTypeId.java

@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@Schema(allOf = EntityId.class)
public final class WidgetTypeId extends UUIDBased implements EntityId {
private static final long serialVersionUID = 1L;
@ -31,7 +32,7 @@ public final class WidgetTypeId extends UUIDBased implements EntityId {
super(id);
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "WIDGET_TYPE", allowableValues = "WIDGET_TYPE")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "WIDGET_TYPE", allowableValues = "WIDGET_TYPE")
@Override
public EntityType getEntityType() {
return EntityType.WIDGET_TYPE;

3
common/data/src/main/java/org/thingsboard/server/common/data/id/WidgetsBundleId.java

@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@Schema(allOf = EntityId.class)
public final class WidgetsBundleId extends UUIDBased implements EntityId {
private static final long serialVersionUID = 1L;
@ -31,7 +32,7 @@ public final class WidgetsBundleId extends UUIDBased implements EntityId {
super(id);
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "WIDGETS_BUNDLE", allowableValues = "WIDGETS_BUNDLE")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_ONLY, description = "string", example = "WIDGETS_BUNDLE", allowableValues = "WIDGETS_BUNDLE")
@Override
public EntityType getEntityType() {
return EntityType.WIDGETS_BUNDLE;

83
common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/DefaultNotificationRuleRecipientsConfig.java

@ -25,62 +25,127 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
@Schema(description = "Default notification rule recipients configuration", allOf = NotificationRuleRecipientsConfig.class)
@Schema(description = "Default notification rule recipients configuration")
@Data
@EqualsAndHashCode(callSuper = true)
public class DefaultNotificationRuleRecipientsConfig extends NotificationRuleRecipientsConfig {
@EqualsAndHashCode
public abstract class DefaultNotificationRuleRecipientsConfig implements NotificationRuleRecipientsConfig {
@NotEmpty
private List<UUID> targets;
@Override
@Schema(hidden = true)
public NotificationRuleTriggerType getTriggerType() {
return super.getTriggerType();
}
@Override
public Map<Integer, List<UUID>> getTargetsTable() {
return Map.of(0, targets);
}
public static DefaultNotificationRuleRecipientsConfig forTriggerType(NotificationRuleTriggerType triggerType) {
return switch (triggerType) {
case ENTITY_ACTION -> new EntityActionRecipientsConfig();
case ALARM_COMMENT -> new AlarmCommentRecipientsConfig();
case ALARM_ASSIGNMENT -> new AlarmAssignmentRecipientsConfig();
case DEVICE_ACTIVITY -> new DeviceActivityRecipientsConfig();
case RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT -> new RuleEngineComponentLifecycleEventRecipientsConfig();
case EDGE_CONNECTION -> new EdgeConnectionRecipientsConfig();
case EDGE_COMMUNICATION_FAILURE -> new EdgeCommunicationFailureRecipientsConfig();
case NEW_PLATFORM_VERSION -> new NewPlatformVersionRecipientsConfig();
case ENTITIES_LIMIT -> new EntitiesLimitRecipientsConfig();
case API_USAGE_LIMIT -> new ApiUsageLimitRecipientsConfig();
case RATE_LIMITS -> new RateLimitsRecipientsConfig();
case TASK_PROCESSING_FAILURE -> new TaskProcessingFailureRecipientsConfig();
case RESOURCES_SHORTAGE -> new ResourceShortageRecipientsConfig();
default -> throw new IllegalArgumentException("Unsupported trigger type for default recipients config: " + triggerType);
};
}
public static class EntityActionRecipientsConfig extends DefaultNotificationRuleRecipientsConfig {
@Override
public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.ENTITY_ACTION;
}
}
public static class AlarmCommentRecipientsConfig extends DefaultNotificationRuleRecipientsConfig {
@Override
public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.ALARM_COMMENT;
}
}
public static class AlarmAssignmentRecipientsConfig extends DefaultNotificationRuleRecipientsConfig {
@Override
public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.ALARM_ASSIGNMENT;
}
}
public static class DeviceActivityRecipientsConfig extends DefaultNotificationRuleRecipientsConfig {
@Override
public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.DEVICE_ACTIVITY;
}
}
public static class RuleEngineComponentLifecycleEventRecipientsConfig extends DefaultNotificationRuleRecipientsConfig {
@Override
public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT;
}
}
public static class EdgeConnectionRecipientsConfig extends DefaultNotificationRuleRecipientsConfig {
@Override
public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.EDGE_CONNECTION;
}
}
public static class EdgeCommunicationFailureRecipientsConfig extends DefaultNotificationRuleRecipientsConfig {
@Override
public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.EDGE_COMMUNICATION_FAILURE;
}
}
public static class NewPlatformVersionRecipientsConfig extends DefaultNotificationRuleRecipientsConfig {
@Override
public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.NEW_PLATFORM_VERSION;
}
}
public static class EntitiesLimitRecipientsConfig extends DefaultNotificationRuleRecipientsConfig {
@Override
public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.ENTITIES_LIMIT;
}
}
public static class ApiUsageLimitRecipientsConfig extends DefaultNotificationRuleRecipientsConfig {
@Override
public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.API_USAGE_LIMIT;
}
}
public static class RateLimitsRecipientsConfig extends DefaultNotificationRuleRecipientsConfig {
@Override
public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.RATE_LIMITS;
}
}
public static class TaskProcessingFailureRecipientsConfig extends DefaultNotificationRuleRecipientsConfig {
@Override
public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.TASK_PROCESSING_FAILURE;
}
}
public static class ResourceShortageRecipientsConfig extends DefaultNotificationRuleRecipientsConfig {
@Override
public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.RESOURCES_SHORTAGE;
}
}
}

10
common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/EscalatedNotificationRuleRecipientsConfig.java

@ -19,6 +19,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType;
import java.util.List;
import java.util.Map;
@ -26,12 +27,17 @@ import java.util.UUID;
@Schema(description = "Escalated notification rule recipients configuration")
@Data
@EqualsAndHashCode(callSuper = true)
public class EscalatedNotificationRuleRecipientsConfig extends NotificationRuleRecipientsConfig {
@EqualsAndHashCode
public class EscalatedNotificationRuleRecipientsConfig implements NotificationRuleRecipientsConfig {
@NotEmpty
private Map<Integer, List<UUID>> escalationTable;
@Override
public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.ALARM;
}
@Override
public Map<Integer, List<UUID>> getTargetsTable() {
return escalationTable;

14
common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/NotificationRuleRecipientsConfig.java

@ -17,14 +17,11 @@ package org.thingsboard.server.common.data.notification.rule;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import io.swagger.v3.oas.annotations.media.DiscriminatorMapping;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType;
import java.io.Serializable;
@ -51,7 +48,7 @@ import java.util.UUID;
@DiscriminatorMapping(value = "RESOURCES_SHORTAGE", schema = DefaultNotificationRuleRecipientsConfig.ResourceShortageRecipientsConfig.class)
})
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "triggerType", visible = true, include = JsonTypeInfo.As.EXISTING_PROPERTY)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "triggerType", include = JsonTypeInfo.As.EXISTING_PROPERTY)
@JsonSubTypes({
@Type(name = "ALARM", value = EscalatedNotificationRuleRecipientsConfig.class),
@Type(name = "ENTITY_ACTION", value = DefaultNotificationRuleRecipientsConfig.EntityActionRecipientsConfig.class),
@ -68,14 +65,11 @@ import java.util.UUID;
@Type(name = "TASK_PROCESSING_FAILURE", value = DefaultNotificationRuleRecipientsConfig.TaskProcessingFailureRecipientsConfig.class),
@Type(name = "RESOURCES_SHORTAGE", value = DefaultNotificationRuleRecipientsConfig.ResourceShortageRecipientsConfig.class)
})
@Data
public abstract class NotificationRuleRecipientsConfig implements Serializable {
public interface NotificationRuleRecipientsConfig extends Serializable {
@NotNull
@JsonProperty("triggerType")
private NotificationRuleTriggerType triggerType;
NotificationRuleTriggerType getTriggerType();
@JsonIgnore
public abstract Map<Integer, List<UUID>> getTargetsTable();
Map<Integer, List<UUID>> getTargetsTable();
}

4
common/data/src/main/java/org/thingsboard/server/common/data/query/RelationsQueryFilter.java

@ -15,16 +15,17 @@
*/
package org.thingsboard.server.common.data.query;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.relation.EntitySearchDirection;
import org.thingsboard.server.common.data.relation.RelationEntityTypeFilter;
import java.util.List;
import java.util.Set;
@Schema
@Data
public class RelationsQueryFilter implements EntityFilter {
@ -34,6 +35,7 @@ public class RelationsQueryFilter implements EntityFilter {
}
private AliasEntityId rootEntity;
@JsonProperty("multiRoot")
private boolean isMultiRoot;
private EntityType multiRootEntitiesType;
private Set<String> multiRootEntityIds;

4
common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/DeviceExportData.java

@ -23,6 +23,7 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.security.DeviceCredentials;
@Schema
@ -31,6 +32,9 @@ import org.thingsboard.server.common.data.security.DeviceCredentials;
@Data
public class DeviceExportData extends EntityExportData<Device> {
@Override
public EntityType getEntityType() { return EntityType.DEVICE; }
@JsonProperty(index = 3)
@JsonIgnoreProperties({"id", "deviceId", "createdTime", "version"})
private DeviceCredentials credentials;

114
common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/EntityExportData.java

@ -65,6 +65,7 @@ import java.util.Map;
@Type(name = "DEVICE_PROFILE", value = EntityExportData.DeviceProfileExportData.class),
@Type(name = "ENTITY_VIEW", value = EntityExportData.EntityViewExportData.class),
@Type(name = "NOTIFICATION_TEMPLATE", value = EntityExportData.NotificationTemplateExportData.class),
@Type(name = "NOTIFICATION_TARGET", value = EntityExportData.NotificationTargetExportData.class),
@Type(name = "NOTIFICATION_RULE", value = EntityExportData.NotificationRuleExportData.class),
@Type(name = "AI_MODEL", value = EntityExportData.AiModelExportData.class)
})
@ -92,7 +93,7 @@ import java.util.Map;
}
)
@Data
public class EntityExportData<E extends ExportableEntity<? extends EntityId>> {
public abstract class EntityExportData<E extends ExportableEntity<? extends EntityId>> {
public static final Comparator<EntityRelation> relationsComparator = Comparator
.comparing(EntityRelation::getFrom, Comparator.comparing(EntityId::getId))
@ -111,7 +112,7 @@ public class EntityExportData<E extends ExportableEntity<? extends EntityId>> {
private E entity;
@JsonProperty(index = 1)
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
private EntityType entityType;
public abstract EntityType getEntityType();
@JsonProperty(index = 100)
@ArraySchema(schema = @Schema(implementation = EntityRelation.class))
@ -124,6 +125,28 @@ public class EntityExportData<E extends ExportableEntity<? extends EntityId>> {
@ArraySchema(schema = @Schema(implementation = CalculatedField.class))
private List<CalculatedField> calculatedFields;
public static EntityExportData<?> newInstance(EntityType entityType) {
return switch (entityType) {
case DEVICE -> new DeviceExportData();
case RULE_CHAIN -> new RuleChainExportData();
case WIDGET_TYPE -> new WidgetTypeExportData();
case WIDGETS_BUNDLE -> new WidgetsBundleExportData();
case OTA_PACKAGE -> new OtaPackageExportData();
case CUSTOMER -> new CustomerExportData();
case TB_RESOURCE -> new TbResourceExportData();
case DASHBOARD -> new DashboardExportData();
case ASSET_PROFILE -> new AssetProfileExportData();
case ASSET -> new AssetExportData();
case DEVICE_PROFILE -> new DeviceProfileExportData();
case ENTITY_VIEW -> new EntityViewExportData();
case NOTIFICATION_TEMPLATE -> new NotificationTemplateExportData();
case NOTIFICATION_TARGET -> new NotificationTargetExportData();
case NOTIFICATION_RULE -> new NotificationRuleExportData();
case AI_MODEL -> new AiModelExportData();
default -> throw new IllegalArgumentException("Unsupported entity type: " + entityType);
};
}
public EntityExportData<E> sort() {
if (relations != null && !relations.isEmpty()) {
relations.sort(relationsComparator);
@ -163,26 +186,91 @@ public class EntityExportData<E extends ExportableEntity<? extends EntityId>> {
}
@Schema
public static class CustomerExportData extends EntityExportData<Customer> {}
public static class CustomerExportData extends EntityExportData<Customer> {
@Override
public EntityType getEntityType() {
return EntityType.CUSTOMER;
}
}
@Schema
public static class TbResourceExportData extends EntityExportData<TbResource> {}
public static class TbResourceExportData extends EntityExportData<TbResource> {
@Override
public EntityType getEntityType() {
return EntityType.TB_RESOURCE;
}
}
@Schema
public static class DashboardExportData extends EntityExportData<Dashboard> {}
public static class DashboardExportData extends EntityExportData<Dashboard> {
@Override
public EntityType getEntityType() {
return EntityType.DASHBOARD;
}
}
@Schema
public static class AssetProfileExportData extends EntityExportData<AssetProfile> {}
public static class AssetProfileExportData extends EntityExportData<AssetProfile> {
@Override
public EntityType getEntityType() {
return EntityType.ASSET_PROFILE;
}
}
@Schema
public static class AssetExportData extends EntityExportData<Asset> {}
public static class AssetExportData extends EntityExportData<Asset> {
@Override
public EntityType getEntityType() {
return EntityType.ASSET;
}
}
@Schema
public static class DeviceProfileExportData extends EntityExportData<DeviceProfile> {}
public static class DeviceProfileExportData extends EntityExportData<DeviceProfile> {
@Override
public EntityType getEntityType() {
return EntityType.DEVICE_PROFILE;
}
}
@Schema
public static class EntityViewExportData extends EntityExportData<EntityView> {}
public static class EntityViewExportData extends EntityExportData<EntityView> {
@Override
public EntityType getEntityType() {
return EntityType.ENTITY_VIEW;
}
}
@Schema
public static class NotificationTemplateExportData extends EntityExportData<NotificationTemplate> {}
public static class NotificationTemplateExportData extends EntityExportData<NotificationTemplate> {
@Override
public EntityType getEntityType() {
return EntityType.NOTIFICATION_TEMPLATE;
}
}
@Schema
public static class NotificationTargetExportData extends EntityExportData<NotificationTarget> {}
public static class NotificationTargetExportData extends EntityExportData<NotificationTarget> {
@Override
public EntityType getEntityType() {
return EntityType.NOTIFICATION_TARGET;
}
}
@Schema
public static class NotificationRuleExportData extends EntityExportData<NotificationRule> {}
public static class NotificationRuleExportData extends EntityExportData<NotificationRule> {
@Override
public EntityType getEntityType() {
return EntityType.NOTIFICATION_RULE;
}
}
@Schema
public static class AiModelExportData extends EntityExportData<AiModel> {}
public static class AiModelExportData extends EntityExportData<AiModel> {
@Override
public EntityType getEntityType() {
return EntityType.AI_MODEL;
}
}
}

4
common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/OtaPackageExportData.java

@ -18,12 +18,16 @@ package org.thingsboard.server.common.data.sync.ie;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.OtaPackage;
@Schema
@EqualsAndHashCode(callSuper = true)
public class OtaPackageExportData extends EntityExportData<OtaPackage> {
@Override
public EntityType getEntityType() { return EntityType.OTA_PACKAGE; }
/*
* OtaPackage is not a versioned entity; its 'version' field is part of the domain model (not used for optimistic locking)
* We override both methods to ensure 'version' is not ignored during (de)serialization.

4
common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/RuleChainExportData.java

@ -21,6 +21,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
@ -30,6 +31,9 @@ import org.thingsboard.server.common.data.rule.RuleChainMetaData;
@Data
public class RuleChainExportData extends EntityExportData<RuleChain> {
@Override
public EntityType getEntityType() { return EntityType.RULE_CHAIN; }
@JsonProperty(index = 3)
@JsonIgnoreProperties({"ruleChainId", "version"})
private RuleChainMetaData metaData;

4
common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/WidgetTypeExportData.java

@ -18,6 +18,7 @@ package org.thingsboard.server.common.data.sync.ie;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.widget.WidgetTypeDetails;
@Schema
@ -25,4 +26,7 @@ import org.thingsboard.server.common.data.widget.WidgetTypeDetails;
@EqualsAndHashCode(callSuper = true)
public class WidgetTypeExportData extends EntityExportData<WidgetTypeDetails> {
@Override
public EntityType getEntityType() { return EntityType.WIDGET_TYPE; }
}

4
common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/WidgetsBundleExportData.java

@ -22,6 +22,7 @@ import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.widget.WidgetsBundle;
import java.util.ArrayList;
@ -32,6 +33,9 @@ import java.util.List;
@EqualsAndHashCode(callSuper = true)
public class WidgetsBundleExportData extends EntityExportData<WidgetsBundle> {
@Override
public EntityType getEntityType() { return EntityType.WIDGETS_BUNDLE; }
@ArraySchema(arraySchema = @Schema(description = "List of widgets in the bundle"), schema = @Schema(implementation = JsonNode.class))
@JsonProperty(index = 3)
private List<ObjectNode> widgets;

50
common/data/src/test/java/org/thingsboard/server/common/data/id/EntityIdTest.java

@ -15,8 +15,18 @@
*/
package org.thingsboard.server.common.data.id;
import io.swagger.v3.oas.annotations.media.DiscriminatorMapping;
import io.swagger.v3.oas.annotations.media.Schema;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.thingsboard.server.common.data.EntityType;
import java.util.Arrays;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
public class EntityIdTest {
@ -25,4 +35,44 @@ public class EntityIdTest {
Assertions.assertEquals("13814000-1dd2-11b2-8080-808080808080", EntityId.NULL_UUID.toString());
}
@Test
public void allEntityIdImplementors_shouldBeInDiscriminatorMapping() {
Schema schemaAnnotation = EntityId.class.getAnnotation(Schema.class);
assertThat(schemaAnnotation).as("EntityId must have @Schema annotation").isNotNull();
DiscriminatorMapping[] mappings = schemaAnnotation.discriminatorMapping();
Map<String, Class<?>> discriminatorMap = Arrays.stream(mappings)
.collect(Collectors.toMap(DiscriminatorMapping::value, DiscriminatorMapping::schema));
UUID testUuid = UUID.randomUUID();
for (EntityType entityType : EntityType.values()) {
EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, testUuid);
String typeName = entityType.name();
assertThat(discriminatorMap)
.as("EntityId @Schema discriminatorMapping is missing entry for EntityType." + typeName)
.containsKey(typeName);
assertThat(discriminatorMap.get(typeName))
.as("Discriminator mapping for " + typeName + " should point to " + entityId.getClass().getSimpleName())
.isEqualTo(entityId.getClass());
}
}
@Test
public void allEntityIdImplementors_shouldHaveAllOfEntityId() {
UUID testUuid = UUID.randomUUID();
for (EntityType entityType : EntityType.values()) {
EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, testUuid);
Class<?> idClass = entityId.getClass();
Schema schemaAnnotation = idClass.getAnnotation(Schema.class);
assertThat(schemaAnnotation)
.as(idClass.getSimpleName() + " must have @Schema annotation")
.isNotNull();
assertThat(schemaAnnotation.allOf())
.as(idClass.getSimpleName() + " @Schema must include allOf = EntityId.class")
.contains(EntityId.class);
}
}
}

52
common/data/src/test/java/org/thingsboard/server/common/data/sync/ie/EntityExportDataTest.java

@ -0,0 +1,52 @@
/**
* Copyright © 2016-2026 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.sync.ie;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import org.junit.jupiter.api.Test;
import org.thingsboard.server.common.data.EntityType;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
public class EntityExportDataTest {
@Test
public void newInstance_shouldSupportAllJsonSubTypes() {
JsonSubTypes subTypes = EntityExportData.class.getAnnotation(JsonSubTypes.class);
assertThat(subTypes).as("EntityExportData must have @JsonSubTypes annotation").isNotNull();
Set<String> jsonSubTypeNames = Arrays.stream(subTypes.value())
.map(JsonSubTypes.Type::name)
.collect(Collectors.toSet());
for (String typeName : jsonSubTypeNames) {
EntityType entityType = EntityType.valueOf(typeName);
EntityExportData<?> instance = EntityExportData.newInstance(entityType);
assertThat(instance)
.as("newInstance(%s) should not return null", typeName)
.isNotNull();
assertThat(instance.getEntityType())
.as("newInstance(%s).getEntityType() should return %s", typeName, entityType)
.isEqualTo(entityType);
}
}
}

4
dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotifications.java

@ -511,12 +511,10 @@ public class DefaultNotifications {
rule.setTriggerConfig(defaultRule.getTriggerConfig());
if (rule.getTriggerType() == NotificationRuleTriggerType.ALARM) {
EscalatedNotificationRuleRecipientsConfig recipientsConfig = new EscalatedNotificationRuleRecipientsConfig();
recipientsConfig.setTriggerType(rule.getTriggerType());
recipientsConfig.setEscalationTable(Map.of(0, toUUIDs(List.of(targets))));
rule.setRecipientsConfig(recipientsConfig);
} else {
DefaultNotificationRuleRecipientsConfig recipientsConfig = new DefaultNotificationRuleRecipientsConfig();
recipientsConfig.setTriggerType(rule.getTriggerType());
DefaultNotificationRuleRecipientsConfig recipientsConfig = DefaultNotificationRuleRecipientsConfig.forTriggerType(rule.getTriggerType());
recipientsConfig.setTargets(toUUIDs(List.of(targets)));
rule.setRecipientsConfig(recipientsConfig);
}

Loading…
Cancel
Save