diff --git a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java index c07d2b538e..a396feef2d 100644 --- a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java @@ -27,7 +27,7 @@ import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.ProfileEntityIdInfo; import org.thingsboard.server.common.data.cf.CalculatedField; import org.thingsboard.server.common.data.cf.CalculatedFieldLink; -import org.thingsboard.server.common.data.cf.configuration.CalculatedFieldConfiguration; +import org.thingsboard.server.common.data.cf.configuration.ArgumentsBasedCalculatedFieldConfiguration; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.CalculatedFieldId; import org.thingsboard.server.common.data.id.DeviceId; @@ -482,7 +482,9 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware private void scheduleDynamicArgumentsRefreshTaskForCfIfNeeded(CalculatedFieldCtx cfCtx) { CalculatedField cf = cfCtx.getCalculatedField(); - CalculatedFieldConfiguration cfConfig = cf.getConfiguration(); + if (!(cf.getConfiguration() instanceof ArgumentsBasedCalculatedFieldConfiguration cfConfig)) { + return; + } if (!cfConfig.isScheduledUpdateEnabled()) { return; } diff --git a/application/src/main/java/org/thingsboard/server/controller/CalculatedFieldController.java b/application/src/main/java/org/thingsboard/server/controller/CalculatedFieldController.java index 5945355ef8..25c4322fac 100644 --- a/application/src/main/java/org/thingsboard/server/controller/CalculatedFieldController.java +++ b/application/src/main/java/org/thingsboard/server/controller/CalculatedFieldController.java @@ -44,6 +44,7 @@ import org.thingsboard.script.api.tbel.TbelInvokeService; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EventInfo; import org.thingsboard.server.common.data.cf.CalculatedField; +import org.thingsboard.server.common.data.cf.configuration.ArgumentsBasedCalculatedFieldConfiguration; import org.thingsboard.server.common.data.cf.configuration.CalculatedFieldConfiguration; import org.thingsboard.server.common.data.event.EventType; import org.thingsboard.server.common.data.exception.ThingsboardException; @@ -212,7 +213,8 @@ public class CalculatedFieldController extends BaseController { @RequestBody JsonNode inputParams) { String expression = inputParams.get("expression").asText(); Map arguments = Objects.requireNonNullElse( - JacksonUtil.convertValue(inputParams.get("arguments"), new TypeReference<>() {}), + JacksonUtil.convertValue(inputParams.get("arguments"), new TypeReference<>() { + }), Collections.emptyMap() ); @@ -278,18 +280,20 @@ public class CalculatedFieldController extends BaseController { } private void checkReferencedEntities(CalculatedFieldConfiguration calculatedFieldConfig) throws ThingsboardException { - List referencedEntityIds = calculatedFieldConfig.getReferencedEntities(); - for (EntityId referencedEntityId : referencedEntityIds) { - EntityType entityType = referencedEntityId.getEntityType(); - switch (entityType) { - case TENANT -> { - return; + if (calculatedFieldConfig instanceof ArgumentsBasedCalculatedFieldConfiguration config) { + List referencedEntityIds = config.getReferencedEntities(); + for (EntityId referencedEntityId : referencedEntityIds) { + EntityType entityType = referencedEntityId.getEntityType(); + switch (entityType) { + case TENANT -> { + return; + } + case CUSTOMER, ASSET, DEVICE -> checkEntityId(referencedEntityId, Operation.READ); + default -> + throw new IllegalArgumentException("Calculated fields do not support '" + entityType + "' for referenced entities."); } - case CUSTOMER, ASSET, DEVICE -> checkEntityId(referencedEntityId, Operation.READ); - default -> throw new IllegalArgumentException("Calculated fields do not support '" + entityType + "' for referenced entities."); } } - } } diff --git a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/CalculatedFieldCtx.java b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/CalculatedFieldCtx.java index a5d9fe4b3a..3108b463af 100644 --- a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/CalculatedFieldCtx.java +++ b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/CalculatedFieldCtx.java @@ -25,7 +25,7 @@ import org.thingsboard.server.common.data.cf.CalculatedField; import org.thingsboard.server.common.data.cf.CalculatedFieldType; import org.thingsboard.server.common.data.cf.configuration.Argument; import org.thingsboard.server.common.data.cf.configuration.ArgumentType; -import org.thingsboard.server.common.data.cf.configuration.CalculatedFieldConfiguration; +import org.thingsboard.server.common.data.cf.configuration.ArgumentsBasedCalculatedFieldConfiguration; import org.thingsboard.server.common.data.cf.configuration.Output; import org.thingsboard.server.common.data.cf.configuration.ReferencedEntityKey; import org.thingsboard.server.common.data.cf.configuration.SimpleCalculatedFieldConfiguration; @@ -83,26 +83,29 @@ public class CalculatedFieldCtx { this.tenantId = calculatedField.getTenantId(); this.entityId = calculatedField.getEntityId(); this.cfType = calculatedField.getType(); - CalculatedFieldConfiguration configuration = calculatedField.getConfiguration(); - this.arguments = configuration.getArguments(); + this.arguments = new HashMap<>(); this.mainEntityArguments = new HashMap<>(); this.linkedEntityArguments = new HashMap<>(); - for (Map.Entry entry : arguments.entrySet()) { - var refId = entry.getValue().getRefEntityId(); - var refKey = entry.getValue().getRefEntityKey(); - if (refId == null && entry.getValue().hasDynamicSource()) { - continue; - } - if (refId == null || refId.equals(calculatedField.getEntityId())) { - mainEntityArguments.put(refKey, entry.getKey()); - } else { - linkedEntityArguments.computeIfAbsent(refId, key -> new HashMap<>()).put(refKey, entry.getKey()); + this.argNames = new ArrayList<>(); + if (calculatedField.getConfiguration() instanceof ArgumentsBasedCalculatedFieldConfiguration configuration) { + this.arguments.putAll(configuration.getArguments()); + for (Map.Entry entry : arguments.entrySet()) { + var refId = entry.getValue().getRefEntityId(); + var refKey = entry.getValue().getRefEntityKey(); + if (refId == null && entry.getValue().hasDynamicSource()) { + continue; + } + if (refId == null || refId.equals(calculatedField.getEntityId())) { + mainEntityArguments.put(refKey, entry.getKey()); + } else { + linkedEntityArguments.computeIfAbsent(refId, key -> new HashMap<>()).put(refKey, entry.getKey()); + } } + this.argNames.addAll(arguments.keySet()); + this.output = configuration.getOutput(); + this.expression = configuration.getExpression(); + this.useLatestTs = CalculatedFieldType.SIMPLE.equals(calculatedField.getType()) && ((SimpleCalculatedFieldConfiguration) configuration).isUseLatestTs(); } - this.argNames = new ArrayList<>(arguments.keySet()); - this.output = configuration.getOutput(); - this.expression = configuration.getExpression(); - this.useLatestTs = CalculatedFieldType.SIMPLE.equals(calculatedField.getType()) && ((SimpleCalculatedFieldConfiguration) configuration).isUseLatestTs(); this.tbelInvokeService = tbelInvokeService; this.relationService = relationService; @@ -316,11 +319,13 @@ public class CalculatedFieldCtx { } public boolean hasSchedulingConfigChanges(CalculatedFieldCtx other) { - CalculatedFieldConfiguration thisConfig = calculatedField.getConfiguration(); - CalculatedFieldConfiguration otherConfig = other.calculatedField.getConfiguration(); - boolean refreshTriggerChanged = thisConfig.isScheduledUpdateEnabled() != otherConfig.isScheduledUpdateEnabled(); - boolean refreshIntervalChanged = thisConfig.getScheduledUpdateIntervalSec() != otherConfig.getScheduledUpdateIntervalSec(); - return refreshTriggerChanged || refreshIntervalChanged; + if (calculatedField.getConfiguration() instanceof ArgumentsBasedCalculatedFieldConfiguration thisConfig + && other.calculatedField.getConfiguration() instanceof ArgumentsBasedCalculatedFieldConfiguration otherConfig) { + boolean refreshTriggerChanged = thisConfig.isScheduledUpdateEnabled() != otherConfig.isScheduledUpdateEnabled(); + boolean refreshIntervalChanged = thisConfig.getScheduledUpdateIntervalSec() != otherConfig.getScheduledUpdateIntervalSec(); + return refreshTriggerChanged || refreshIntervalChanged; + } + return false; } public String getSizeExceedsLimitMessage() { diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DefaultEntityExportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DefaultEntityExportService.java index 5c2fcc7dc6..b7b027d785 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DefaultEntityExportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DefaultEntityExportService.java @@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.ExportableEntity; import org.thingsboard.server.common.data.HasVersion; import org.thingsboard.server.common.data.cf.CalculatedField; +import org.thingsboard.server.common.data.cf.configuration.ArgumentsBasedCalculatedFieldConfiguration; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; @@ -153,11 +154,13 @@ public class DefaultEntityExportService calculatedFields = calculatedFieldService.findCalculatedFieldsByEntityId(ctx.getTenantId(), entityId); calculatedFields.forEach(calculatedField -> { calculatedField.setEntityId(getExternalIdOrElseInternal(ctx, entityId)); - calculatedField.getConfiguration().getArguments().values().forEach(argument -> { - if (argument.getRefEntityId() != null) { - argument.setRefEntityId(getExternalIdOrElseInternal(ctx, argument.getRefEntityId())); - } - }); + if (calculatedField.getConfiguration() instanceof ArgumentsBasedCalculatedFieldConfiguration configuration) { + configuration.getArguments().values().forEach(argument -> { + if (argument.getRefEntityId() != null) { + argument.setRefEntityId(getExternalIdOrElseInternal(ctx, argument.getRefEntityId())); + } + }); + } }); return calculatedFields; } diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/BaseEntityImportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/BaseEntityImportService.java index 92fdcb09c4..2b606a2fe8 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/BaseEntityImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/BaseEntityImportService.java @@ -35,6 +35,7 @@ import org.thingsboard.server.common.data.HasVersion; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.cf.CalculatedField; +import org.thingsboard.server.common.data.cf.configuration.ArgumentsBasedCalculatedFieldConfiguration; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; @@ -321,11 +322,13 @@ public abstract class BaseEntityImportService { calculatedField.setTenantId(ctx.getTenantId()); calculatedField.setEntityId(savedEntity.getId()); - calculatedField.getConfiguration().getArguments().values().forEach(argument -> { - if (argument.getRefEntityId() != null) { - argument.setRefEntityId(idProvider.getInternalId(argument.getRefEntityId(), ctx.isFinalImportAttempt())); - } - }); + if (calculatedField.getConfiguration() instanceof ArgumentsBasedCalculatedFieldConfiguration configuration) { + configuration.getArguments().values().forEach(argument -> { + if (argument.getRefEntityId() != null) { + argument.setRefEntityId(idProvider.getInternalId(argument.getRefEntityId(), ctx.isFinalImportAttempt())); + } + }); + } }).toList(); for (CalculatedField existingField : existing) { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/ArgumentsBasedCalculatedFieldConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/ArgumentsBasedCalculatedFieldConfiguration.java new file mode 100644 index 0000000000..389bad04c8 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/ArgumentsBasedCalculatedFieldConfiguration.java @@ -0,0 +1,31 @@ +package org.thingsboard.server.common.data.cf.configuration; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +import java.util.Map; + +public interface ArgumentsBasedCalculatedFieldConfiguration extends CalculatedFieldConfiguration { + + Map getArguments(); + + String getExpression(); + + void setExpression(String expression); + + Output getOutput(); + + void validate(); + + @JsonIgnore + default boolean isScheduledUpdateEnabled() { + return false; + } + + default void setScheduledUpdateIntervalSec(int scheduledUpdateIntervalSec) { + } + + default int getScheduledUpdateIntervalSec() { + return 0; + } + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/BaseCalculatedFieldConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/BaseCalculatedFieldConfiguration.java index ef6450f5b3..2f5c242e80 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/BaseCalculatedFieldConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/BaseCalculatedFieldConfiguration.java @@ -27,7 +27,7 @@ import java.util.Objects; import java.util.stream.Collectors; @Data -public abstract class BaseCalculatedFieldConfiguration implements CalculatedFieldConfiguration { +public abstract class BaseCalculatedFieldConfiguration implements ArgumentsBasedCalculatedFieldConfiguration { protected Map arguments; protected String expression; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/CalculatedFieldConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/CalculatedFieldConfiguration.java index c7b5c6fcaf..ecc17e4e9a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/CalculatedFieldConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/CalculatedFieldConfiguration.java @@ -25,8 +25,8 @@ import org.thingsboard.server.common.data.id.CalculatedFieldId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; +import java.util.Collections; import java.util.List; -import java.util.Map; @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, @@ -44,33 +44,13 @@ public interface CalculatedFieldConfiguration { @JsonIgnore CalculatedFieldType getType(); - Map getArguments(); - - String getExpression(); - - void setExpression(String expression); - - Output getOutput(); - @JsonIgnore - List getReferencedEntities(); - - List buildCalculatedFieldLinks(TenantId tenantId, EntityId cfEntityId, CalculatedFieldId calculatedFieldId); + default List getReferencedEntities() { + return Collections.emptyList(); + } CalculatedFieldLink buildCalculatedFieldLink(TenantId tenantId, EntityId referencedEntityId, CalculatedFieldId calculatedFieldId); - void validate(); - - @JsonIgnore - default boolean isScheduledUpdateEnabled() { - return false; - } - - default void setScheduledUpdateIntervalSec(int scheduledUpdateIntervalSec) { - } - - default int getScheduledUpdateIntervalSec() { - return 0; - } + List buildCalculatedFieldLinks(TenantId tenantId, EntityId cfEntityId, CalculatedFieldId calculatedFieldId); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/GeofencingCalculatedFieldConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/GeofencingCalculatedFieldConfiguration.java index 4f71ef749e..d9968e9926 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/GeofencingCalculatedFieldConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/GeofencingCalculatedFieldConfiguration.java @@ -27,7 +27,7 @@ import java.util.stream.Collectors; @Data @EqualsAndHashCode(callSuper = true) -public class GeofencingCalculatedFieldConfiguration extends BaseCalculatedFieldConfiguration implements CalculatedFieldConfiguration { +public class GeofencingCalculatedFieldConfiguration extends BaseCalculatedFieldConfiguration implements ArgumentsBasedCalculatedFieldConfiguration { public static final String ENTITY_ID_LATITUDE_ARGUMENT_KEY = "latitude"; public static final String ENTITY_ID_LONGITUDE_ARGUMENT_KEY = "longitude"; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/ScriptCalculatedFieldConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/ScriptCalculatedFieldConfiguration.java index c2dde43b8e..0d38059a45 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/ScriptCalculatedFieldConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/ScriptCalculatedFieldConfiguration.java @@ -21,7 +21,7 @@ import org.thingsboard.server.common.data.cf.CalculatedFieldType; @Data @EqualsAndHashCode(callSuper = true) -public class ScriptCalculatedFieldConfiguration extends BaseCalculatedFieldConfiguration implements CalculatedFieldConfiguration { +public class ScriptCalculatedFieldConfiguration extends BaseCalculatedFieldConfiguration implements ArgumentsBasedCalculatedFieldConfiguration { @Override public CalculatedFieldType getType() { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/SimpleCalculatedFieldConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/SimpleCalculatedFieldConfiguration.java index 86c7b9e9b6..46395a3361 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/SimpleCalculatedFieldConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/SimpleCalculatedFieldConfiguration.java @@ -21,7 +21,7 @@ import org.thingsboard.server.common.data.cf.CalculatedFieldType; @Data @EqualsAndHashCode(callSuper = true) -public class SimpleCalculatedFieldConfiguration extends BaseCalculatedFieldConfiguration implements CalculatedFieldConfiguration { +public class SimpleCalculatedFieldConfiguration extends BaseCalculatedFieldConfiguration implements ArgumentsBasedCalculatedFieldConfiguration { private boolean useLatestTs; diff --git a/dao/src/main/java/org/thingsboard/server/dao/cf/BaseCalculatedFieldService.java b/dao/src/main/java/org/thingsboard/server/dao/cf/BaseCalculatedFieldService.java index 1dc1e16144..465e127238 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/cf/BaseCalculatedFieldService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/cf/BaseCalculatedFieldService.java @@ -21,6 +21,7 @@ import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.cf.CalculatedField; import org.thingsboard.server.common.data.cf.CalculatedFieldLink; +import org.thingsboard.server.common.data.cf.configuration.ArgumentsBasedCalculatedFieldConfiguration; import org.thingsboard.server.common.data.cf.configuration.CalculatedFieldConfiguration; import org.thingsboard.server.common.data.id.CalculatedFieldId; import org.thingsboard.server.common.data.id.CalculatedFieldLinkId; @@ -93,14 +94,15 @@ public class BaseCalculatedFieldService extends AbstractEntityService implements } private void updatedSchedulingConfiguration(CalculatedField calculatedField) { - CalculatedFieldConfiguration configuration = calculatedField.getConfiguration(); - if (!configuration.isScheduledUpdateEnabled()) { - return; + if (calculatedField.getConfiguration() instanceof ArgumentsBasedCalculatedFieldConfiguration configuration) { + if (!configuration.isScheduledUpdateEnabled()) { + return; + } + int tenantProfileMinAllowedValue = tbTenantProfileCache.get(calculatedField.getTenantId()) + .getDefaultProfileConfiguration() + .getMinAllowedScheduledUpdateIntervalInSecForCF(); + configuration.setScheduledUpdateIntervalSec(Math.max(configuration.getScheduledUpdateIntervalSec(), tenantProfileMinAllowedValue)); } - int tenantProfileMinAllowedValue = tbTenantProfileCache.get(calculatedField.getTenantId()) - .getDefaultProfileConfiguration() - .getMinAllowedScheduledUpdateIntervalInSecForCF(); - configuration.setScheduledUpdateIntervalSec(Math.max(configuration.getScheduledUpdateIntervalSec(), tenantProfileMinAllowedValue)); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/validator/CalculatedFieldDataValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/validator/CalculatedFieldDataValidator.java index 4fe663ff5d..81192f76a8 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/service/validator/CalculatedFieldDataValidator.java +++ b/dao/src/main/java/org/thingsboard/server/dao/service/validator/CalculatedFieldDataValidator.java @@ -19,7 +19,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.cf.CalculatedField; import org.thingsboard.server.common.data.cf.CalculatedFieldType; -import org.thingsboard.server.common.data.cf.configuration.CalculatedFieldConfiguration; +import org.thingsboard.server.common.data.cf.configuration.ArgumentsBasedCalculatedFieldConfiguration; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; @@ -72,23 +72,25 @@ public class CalculatedFieldDataValidator extends DataValidator } if (CalculatedFieldType.GEOFENCING.equals(calculatedField.getType()) && maxArgumentsPerCF < 3) { throw new DataValidationException("Geofencing calculated field requires at least 3 arguments, but the system limit is " + - maxArgumentsPerCF + ". Contact your administrator to increase the limit." + maxArgumentsPerCF + ". Contact your administrator to increase the limit." ); } - if (calculatedField.getConfiguration().getArguments().size() > maxArgumentsPerCF) { + if (calculatedField.getConfiguration() instanceof ArgumentsBasedCalculatedFieldConfiguration configuration + && configuration.getArguments().size() > maxArgumentsPerCF) { throw new DataValidationException("Calculated field arguments limit reached!"); } } private void validateCalculatedFieldConfiguration(CalculatedField calculatedField) { - CalculatedFieldConfiguration configuration = calculatedField.getConfiguration(); - if (configuration.getArguments().containsKey("ctx")) { - throw new DataValidationException("Argument name 'ctx' is reserved and cannot be used."); - } - try { - configuration.validate(); - } catch (IllegalArgumentException e) { - throw new DataValidationException(e.getMessage(), e); + if (calculatedField.getConfiguration() instanceof ArgumentsBasedCalculatedFieldConfiguration configuration) { + if (configuration.getArguments().containsKey("ctx")) { + throw new DataValidationException("Argument name 'ctx' is reserved and cannot be used."); + } + try { + configuration.validate(); + } catch (IllegalArgumentException e) { + throw new DataValidationException(e.getMessage(), e); + } } }