Use Jakarta Bean Validation 18/143018/4
authordanielhanrahan <daniel.hanrahan@est.tech>
Mon, 26 Jan 2026 14:48:24 +0000 (14:48 +0000)
committerDaniel Hanrahan <daniel.hanrahan@est.tech>
Fri, 30 Jan 2026 09:27:14 +0000 (09:27 +0000)
Replace custom Policy Framework Validation with standard
Jakarta Bean Validation.

Note @NotBlank annotation behaves differently now:
- In new Jakarta framework, NotBlank implies NotNull.
- In previous framework, NotBlank allowed null values.
- Other annotations such as NotNull, Pattern, and Valid
  behave the same as before.

Issue-ID: POLICY-5509
Change-Id: Ib153db9f94bd191b837e74e1e0da9ece26c08f3c
Signed-off-by: danielhanrahan <daniel.hanrahan@est.tech>
50 files changed:
models/src/main/java/org/onap/policy/clamp/models/acm/concepts/ParticipantSupportedElementType.java
models/src/main/java/org/onap/policy/clamp/models/acm/document/base/DocConceptKey.java
models/src/main/java/org/onap/policy/clamp/models/acm/document/concepts/DocToscaCapabilityAssignment.java
models/src/main/java/org/onap/policy/clamp/models/acm/document/concepts/DocToscaCapabilityType.java
models/src/main/java/org/onap/policy/clamp/models/acm/document/concepts/DocToscaDataType.java
models/src/main/java/org/onap/policy/clamp/models/acm/document/concepts/DocToscaEntity.java
models/src/main/java/org/onap/policy/clamp/models/acm/document/concepts/DocToscaNodeTemplate.java
models/src/main/java/org/onap/policy/clamp/models/acm/document/concepts/DocToscaNodeType.java
models/src/main/java/org/onap/policy/clamp/models/acm/document/concepts/DocToscaParameter.java
models/src/main/java/org/onap/policy/clamp/models/acm/document/concepts/DocToscaPolicy.java
models/src/main/java/org/onap/policy/clamp/models/acm/document/concepts/DocToscaProperty.java
models/src/main/java/org/onap/policy/clamp/models/acm/document/concepts/DocToscaServiceTemplate.java
models/src/main/java/org/onap/policy/clamp/models/acm/document/concepts/DocToscaTopologyTemplate.java
models/src/main/java/org/onap/policy/clamp/models/acm/document/concepts/DocToscaWithToscaProperties.java
models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaAutomationComposition.java
models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaAutomationCompositionDefinition.java
models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaAutomationCompositionElement.java
models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaMessage.java
models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaMessageJob.java
models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaNodeTemplateState.java
models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaParticipant.java
models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaParticipantReplica.java
models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaParticipantSupportedElementType.java
policy-common/pom.xml
policy-common/src/main/java/org/onap/policy/common/parameters/BeanValidator.java
policy-common/src/main/java/org/onap/policy/common/parameters/FieldValidator.java [deleted file]
policy-common/src/main/java/org/onap/policy/common/parameters/ItemValidator.java [deleted file]
policy-common/src/main/java/org/onap/policy/common/parameters/ParameterGroupImpl.java
policy-common/src/main/java/org/onap/policy/common/parameters/ValueValidator.java [deleted file]
policy-common/src/main/java/org/onap/policy/common/parameters/annotations/Min.java [deleted file]
policy-common/src/main/java/org/onap/policy/common/parameters/annotations/NotBlank.java [deleted file]
policy-common/src/main/java/org/onap/policy/common/parameters/annotations/NotNull.java [deleted file]
policy-common/src/main/java/org/onap/policy/common/parameters/annotations/Pattern.java [deleted file]
policy-common/src/main/java/org/onap/policy/common/parameters/annotations/Valid.java [deleted file]
policy-common/src/main/java/org/onap/policy/common/parameters/topic/TopicParameterGroup.java
policy-common/src/main/java/org/onap/policy/common/parameters/topic/TopicParameters.java
policy-common/src/test/java/org/onap/policy/common/parameters/TestBeanValidator.java [deleted file]
policy-common/src/test/java/org/onap/policy/common/parameters/TestFieldValidator.java [deleted file]
policy-common/src/test/java/org/onap/policy/common/parameters/TestItemValidator.java [deleted file]
policy-common/src/test/java/org/onap/policy/common/parameters/TestValueValidator.java [deleted file]
policy-common/src/test/java/org/onap/policy/common/parameters/ValidatorUtil.java [deleted file]
policy-models/src/main/java/org/onap/policy/models/base/PfConceptKey.java
policy-models/src/main/java/org/onap/policy/models/base/PfValidator.java [deleted file]
policy-models/src/main/java/org/onap/policy/models/base/Validated.java
policy-models/src/main/java/org/onap/policy/models/base/validation/annotations/VerifyKey.java
policy-models/src/main/java/org/onap/policy/models/base/validation/annotations/VerifyKeyValidator.java [new file with mode: 0644]
policy-models/src/test/java/org/onap/policy/models/base/PfKeyImplTest.java
policy-models/src/test/java/org/onap/policy/models/base/PfValidatorTest.java [deleted file]
policy-models/src/test/java/org/onap/policy/models/base/ValidatedTest.java [deleted file]
policy-models/src/test/java/org/onap/policy/models/base/validation/annotations/VerifyKeyValidatorTest.java [new file with mode: 0644]

index 68d5001..7d8a867 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- * Copyright (C) 2023 Nordix Foundation.
+ * Copyright (C) 2023-2026 OpenInfra Foundation Europe. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 package org.onap.policy.clamp.models.acm.concepts;
 
+import jakarta.validation.constraints.NotNull;
 import java.util.UUID;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
-import org.onap.policy.common.parameters.annotations.NotNull;
 
 @NoArgsConstructor
 @Data
index 735d453..61f53e1 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2022,2025 OpenInfra Foundation Europe. All rights reserved.
+ *  Copyright (C) 2022-2026 OpenInfra Foundation Europe. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 package org.onap.policy.clamp.models.acm.document.base;
 
+import jakarta.validation.constraints.Pattern;
 import java.io.Serial;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.NonNull;
 import lombok.ToString;
-import org.onap.policy.common.parameters.annotations.Pattern;
 import org.onap.policy.common.utils.validation.Assertions;
 import org.onap.policy.models.base.PfConceptKey;
 import org.onap.policy.models.base.PfKeyImpl;
index 64aa45e..0ba7a32 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2022,2024-2025 OpenInfra Foundation Europe. All rights reserved.
+ *  Copyright (C) 2022-2026 OpenInfra Foundation Europe. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@
 
 package org.onap.policy.clamp.models.acm.document.concepts;
 
+import jakarta.validation.constraints.NotNull;
 import java.io.Serial;
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
@@ -29,7 +30,6 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
 import lombok.ToString;
-import org.onap.policy.common.parameters.annotations.NotNull;
 import org.onap.policy.models.base.PfUtils;
 import org.onap.policy.models.tosca.authorative.concepts.ToscaCapabilityAssignment;
 
index be1d030..87f5735 100644 (file)
@@ -24,8 +24,8 @@ import java.io.Serial;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
-import lombok.NonNull;
-import org.onap.policy.common.parameters.BeanValidationResult;
+import org.onap.policy.models.base.PfConceptKey;
+import org.onap.policy.models.base.validation.annotations.VerifyKey;
 import org.onap.policy.models.tosca.authorative.concepts.ToscaCapabilityType;
 
 @Data
@@ -61,11 +61,8 @@ public class DocToscaCapabilityType extends DocToscaWithToscaProperties<ToscaCap
     }
 
     @Override
-    public BeanValidationResult validate(@NonNull String fieldName) {
-        var result = super.validate(fieldName);
-
-        validateKeyVersionNotNull(result, "key", getConceptKey());
-
-        return result;
+    @VerifyKey(keyNotNull = false, nameNotNull = false, versionNotNull = true)
+    public PfConceptKey getConceptKey() {
+        return super.getConceptKey();
     }
 }
index dffb4cf..0d48140 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2022,2025 OpenInfra Foundation Europe. All rights reserved.
+ *  Copyright (C) 2022-2026 OpenInfra Foundation Europe. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 package org.onap.policy.clamp.models.acm.document.concepts;
 
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotNull;
 import java.io.Serial;
 import java.util.List;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
-import org.onap.policy.common.parameters.annotations.NotNull;
-import org.onap.policy.common.parameters.annotations.Valid;
 import org.onap.policy.models.base.PfUtils;
 import org.onap.policy.models.tosca.authorative.concepts.ToscaDataType;
 
index b931d4e..f7477e7 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2022,2024 Nordix Foundation.
+ *  Copyright (C) 2022-2026 OpenInfra Foundation Europe. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -21,6 +21,8 @@
 package org.onap.policy.clamp.models.acm.document.concepts;
 
 import com.google.gson.annotations.SerializedName;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
 import java.io.Serial;
 import java.io.Serializable;
 import java.util.LinkedHashMap;
@@ -30,8 +32,6 @@ import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
 import org.apache.commons.lang3.ObjectUtils;
 import org.onap.policy.clamp.models.acm.document.base.DocConceptKey;
-import org.onap.policy.common.parameters.annotations.NotBlank;
-import org.onap.policy.common.parameters.annotations.NotNull;
 import org.onap.policy.models.base.PfAuthorative;
 import org.onap.policy.models.base.PfConceptKey;
 import org.onap.policy.models.base.PfKey;
@@ -60,9 +60,8 @@ public class DocToscaEntity<T extends ToscaEntity> extends Validated
     private String derivedFrom;
 
     @SuppressWarnings("squid:S1948")
-    private Map<@NotNull @NotBlank String, @NotNull @NotBlank Object> metadata = new LinkedHashMap<>();
+    private Map<@NotBlank String, @NotNull Object> metadata = new LinkedHashMap<>();
 
-    @NotBlank
     private String description;
 
     private transient T toscaEntity;
index 8a20c12..241c1bb 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2022,2025 OpenInfra Foundation Europe. All rights reserved.
+ *  Copyright (C) 2022-2026 OpenInfra Foundation Europe. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@
 
 package org.onap.policy.clamp.models.acm.document.concepts;
 
+import jakarta.validation.Valid;
 import java.io.Serial;
 import java.util.List;
 import java.util.Map;
@@ -28,7 +29,6 @@ import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
 import lombok.ToString;
 import org.onap.policy.clamp.models.acm.document.base.DocUtil;
-import org.onap.policy.common.parameters.annotations.Valid;
 import org.onap.policy.models.base.PfUtils;
 import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate;
 
index 6e40592..ca9600f 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2022,2025 OpenInfra Foundation Europe. All rights reserved.
+ *  Copyright (C) 2022-2026 OpenInfra Foundation Europe. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@
 
 package org.onap.policy.clamp.models.acm.document.concepts;
 
+import jakarta.validation.Valid;
 import java.io.Serial;
 import java.util.List;
 import java.util.Map;
@@ -27,7 +28,6 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
 import org.onap.policy.clamp.models.acm.document.base.DocUtil;
-import org.onap.policy.common.parameters.annotations.Valid;
 import org.onap.policy.models.base.PfUtils;
 import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeType;
 
index 5a252b8..dd111fc 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2022,2024 Nordix Foundation.
+ *  Copyright (C) 2022-2026 OpenInfra Foundation Europe. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 package org.onap.policy.clamp.models.acm.document.concepts;
 
 import com.google.gson.annotations.SerializedName;
+import jakarta.validation.constraints.NotNull;
 import java.io.Serial;
 import java.io.Serializable;
 import lombok.Data;
 import lombok.NoArgsConstructor;
-import org.onap.policy.common.parameters.annotations.NotNull;
 import org.onap.policy.models.base.PfAuthorative;
 import org.onap.policy.models.base.PfKey;
 import org.onap.policy.models.base.PfUtils;
index 888da93..c85db2f 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2022 Nordix Foundation.
+ *  Copyright (C) 2022-2026 OpenInfra Foundation Europe. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -27,7 +27,8 @@ import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
 import lombok.NonNull;
 import lombok.ToString;
-import org.onap.policy.common.parameters.BeanValidationResult;
+import org.onap.policy.models.base.PfConceptKey;
+import org.onap.policy.models.base.validation.annotations.VerifyKey;
 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
 
 @Data
@@ -85,11 +86,8 @@ public class DocToscaPolicy extends DocToscaWithTypeAndStringProperties<ToscaPol
     }
 
     @Override
-    public BeanValidationResult validate(String fieldName) {
-        var result = super.validate(fieldName);
-
-        validateKeyVersionNotNull(result, "key", getConceptKey());
-
-        return result;
+    @VerifyKey(keyNotNull = false, nameNotNull = false, versionNotNull = true)
+    public PfConceptKey getConceptKey() {
+        return super.getConceptKey();
     }
 }
index 774f045..63f9805 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2022,2024 Nordix Foundation.
+ *  Copyright (C) 2022-2026 OpenInfra Foundation Europe. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -21,6 +21,8 @@
 package org.onap.policy.clamp.models.acm.document.concepts;
 
 import com.google.gson.annotations.SerializedName;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotNull;
 import java.io.Serial;
 import java.io.Serializable;
 import java.util.LinkedHashMap;
@@ -31,9 +33,6 @@ import lombok.NoArgsConstructor;
 import org.apache.commons.lang3.ObjectUtils;
 import org.onap.policy.clamp.models.acm.document.base.DocConceptKey;
 import org.onap.policy.clamp.models.acm.document.base.DocUtil;
-import org.onap.policy.common.parameters.annotations.NotBlank;
-import org.onap.policy.common.parameters.annotations.NotNull;
-import org.onap.policy.common.parameters.annotations.Valid;
 import org.onap.policy.models.base.PfAuthorative;
 import org.onap.policy.models.base.PfUtils;
 import org.onap.policy.models.tosca.authorative.concepts.ToscaProperty;
@@ -55,11 +54,9 @@ public class DocToscaProperty implements PfAuthorative<ToscaProperty>, Serializa
     @NotNull
     private String typeVersion;
 
-    @NotBlank
     private String description;
 
     @SerializedName("default")
-    @NotBlank
     @SuppressWarnings("squid:S1948")
     private Object defaultValue;
 
index 42f7099..1eb3cac 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2022,2025 OpenInfra Foundation Europe. All rights reserved.
+ *  Copyright (C) 2022-2026 OpenInfra Foundation Europe. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -21,6 +21,8 @@
 package org.onap.policy.clamp.models.acm.document.concepts;
 
 import com.google.gson.annotations.SerializedName;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotBlank;
 import java.io.Serial;
 import java.util.LinkedHashMap;
 import java.util.Map;
@@ -28,9 +30,6 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 import org.apache.commons.lang3.ObjectUtils;
 import org.onap.policy.clamp.models.acm.document.base.DocUtil;
-import org.onap.policy.common.parameters.annotations.NotBlank;
-import org.onap.policy.common.parameters.annotations.NotNull;
-import org.onap.policy.common.parameters.annotations.Valid;
 import org.onap.policy.models.base.PfKey;
 import org.onap.policy.models.base.PfUtils;
 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
@@ -47,7 +46,6 @@ public class DocToscaServiceTemplate extends DocToscaEntity<ToscaServiceTemplate
     public static final String DEFAULT_VERSION = "1.0.0";
 
     @SerializedName("tosca_definitions_version")
-    @NotNull
     @NotBlank
     private String toscaDefinitionsVersion;
 
index 83f5096..3cbd4aa 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2022 Nordix Foundation.
+ *  Copyright (C) 2022-2026 OpenInfra Foundation Europe. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
 package org.onap.policy.clamp.models.acm.document.concepts;
 
 import com.google.gson.annotations.SerializedName;
+import jakarta.validation.Valid;
 import java.io.Serial;
 import java.io.Serializable;
 import java.util.LinkedHashMap;
@@ -30,7 +31,6 @@ import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
 import org.apache.commons.lang3.ObjectUtils;
 import org.onap.policy.clamp.models.acm.document.base.DocUtil;
-import org.onap.policy.common.parameters.annotations.Valid;
 import org.onap.policy.models.base.PfAuthorative;
 import org.onap.policy.models.base.PfUtils;
 import org.onap.policy.models.base.Validated;
index b961222..7ad2fb1 100644 (file)
@@ -20,6 +20,9 @@
 
 package org.onap.policy.clamp.models.acm.document.concepts;
 
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
 import java.io.Serial;
 import java.util.Collection;
 import java.util.LinkedHashMap;
@@ -33,9 +36,6 @@ import lombok.NoArgsConstructor;
 import org.apache.commons.collections4.CollectionUtils;
 import org.onap.policy.clamp.models.acm.document.base.DocConceptKey;
 import org.onap.policy.clamp.models.acm.document.base.DocUtil;
-import org.onap.policy.common.parameters.annotations.NotBlank;
-import org.onap.policy.common.parameters.annotations.NotNull;
-import org.onap.policy.common.parameters.annotations.Valid;
 import org.onap.policy.models.base.PfUtils;
 import org.onap.policy.models.tosca.authorative.concepts.ToscaWithToscaProperties;
 import org.onap.policy.models.tosca.utils.ToscaUtils;
@@ -49,7 +49,7 @@ public class DocToscaWithToscaProperties<T extends ToscaWithToscaProperties> ext
     private static final long serialVersionUID = 1L;
 
     @SuppressWarnings("squid:S1948")
-    private Map<@NotNull @NotBlank String, @NotNull @Valid DocToscaProperty> properties;
+    private Map<@NotBlank String, @NotNull @Valid DocToscaProperty> properties;
 
     /**
      * Copy constructor.
index 95437a4..5006b5a 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- * Copyright (C) 2021-2025 OpenInfra Foundation Europe. All rights reserved.
+ * Copyright (C) 2021-2026 OpenInfra Foundation Europe. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -32,6 +32,8 @@ import jakarta.persistence.InheritanceType;
 import jakarta.persistence.JoinColumn;
 import jakarta.persistence.OneToMany;
 import jakarta.persistence.Table;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotNull;
 import java.sql.Timestamp;
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
@@ -48,8 +50,6 @@ import org.onap.policy.clamp.models.acm.concepts.LockState;
 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
 import org.onap.policy.clamp.models.acm.concepts.SubState;
 import org.onap.policy.clamp.models.acm.utils.TimestampHelper;
-import org.onap.policy.common.parameters.annotations.NotNull;
-import org.onap.policy.common.parameters.annotations.Valid;
 import org.onap.policy.models.base.PfAuthorative;
 import org.onap.policy.models.base.PfUtils;
 import org.onap.policy.models.base.Validated;
index 9837dd2..95a96c2 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2022-2025 OpenInfra Foundation Europe. All rights reserved.
+ *  Copyright (C) 2022-2026 OpenInfra Foundation Europe. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -32,6 +32,9 @@ import jakarta.persistence.InheritanceType;
 import jakarta.persistence.JoinColumn;
 import jakarta.persistence.OneToMany;
 import jakarta.persistence.Table;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Pattern;
 import java.sql.Timestamp;
 import java.util.HashSet;
 import java.util.Set;
@@ -43,9 +46,6 @@ import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionDefinition
 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
 import org.onap.policy.clamp.models.acm.document.concepts.DocToscaServiceTemplate;
 import org.onap.policy.clamp.models.acm.utils.TimestampHelper;
-import org.onap.policy.common.parameters.annotations.NotNull;
-import org.onap.policy.common.parameters.annotations.Pattern;
-import org.onap.policy.common.parameters.annotations.Valid;
 import org.onap.policy.models.base.PfAuthorative;
 import org.onap.policy.models.base.PfKey;
 import org.onap.policy.models.base.Validated;
index ab3a4c3..e33b0ab 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- * Copyright (C) 2021-2025 OpenInfra Foundation Europe. All rights reserved.
+ * Copyright (C) 2021-2026 OpenInfra Foundation Europe. All rights reserved.
  * ================================================================================
  * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
@@ -30,6 +30,8 @@ import jakarta.persistence.Id;
 import jakarta.persistence.Inheritance;
 import jakarta.persistence.InheritanceType;
 import jakarta.persistence.Table;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotNull;
 import java.util.Map;
 import java.util.UUID;
 import java.util.function.UnaryOperator;
@@ -42,8 +44,6 @@ import org.onap.policy.clamp.models.acm.concepts.DeployState;
 import org.onap.policy.clamp.models.acm.concepts.LockState;
 import org.onap.policy.clamp.models.acm.concepts.MigrationState;
 import org.onap.policy.clamp.models.acm.concepts.SubState;
-import org.onap.policy.common.parameters.annotations.NotNull;
-import org.onap.policy.common.parameters.annotations.Valid;
 import org.onap.policy.models.base.PfAuthorative;
 import org.onap.policy.models.base.PfConceptKey;
 import org.onap.policy.models.base.PfUtils;
@@ -72,6 +72,7 @@ public class JpaAutomationCompositionElement extends Validated
     @NotNull
     private String instanceId;
 
+    @Valid
     @VerifyKey
     @NotNull
     @AttributeOverride(name = "name",    column = @Column(name = "definition_name"))
index eb730fe..2696983 100644 (file)
@@ -28,13 +28,13 @@ import jakarta.persistence.Index;
 import jakarta.persistence.Inheritance;
 import jakarta.persistence.InheritanceType;
 import jakarta.persistence.Table;
+import jakarta.validation.constraints.NotNull;
 import java.sql.Timestamp;
 import java.util.UUID;
 import lombok.Data;
 import lombok.NonNull;
 import org.onap.policy.clamp.models.acm.document.concepts.DocMessage;
 import org.onap.policy.clamp.models.acm.utils.TimestampHelper;
-import org.onap.policy.common.parameters.annotations.NotNull;
 import org.onap.policy.models.base.PfAuthorative;
 import org.onap.policy.models.base.Validated;
 
index e9cac40..8acf0b8 100644 (file)
@@ -26,13 +26,13 @@ import jakarta.persistence.Id;
 import jakarta.persistence.Inheritance;
 import jakarta.persistence.InheritanceType;
 import jakarta.persistence.Table;
+import jakarta.validation.constraints.NotNull;
 import java.sql.Timestamp;
 import java.util.UUID;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.NonNull;
 import org.onap.policy.clamp.models.acm.utils.TimestampHelper;
-import org.onap.policy.common.parameters.annotations.NotNull;
 import org.onap.policy.models.base.Validated;
 
 @Entity
index f79e12e..b92b239 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2023,2025 OpenInfra Foundation Europe. All rights reserved.
+ *  Copyright (C) 2023-2026 OpenInfra Foundation Europe. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -28,6 +28,8 @@ import jakarta.persistence.Id;
 import jakarta.persistence.Inheritance;
 import jakarta.persistence.InheritanceType;
 import jakarta.persistence.Table;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotNull;
 import java.util.Map;
 import java.util.UUID;
 import java.util.function.UnaryOperator;
@@ -35,8 +37,6 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
 import org.onap.policy.clamp.models.acm.concepts.NodeTemplateState;
-import org.onap.policy.common.parameters.annotations.NotNull;
-import org.onap.policy.common.parameters.annotations.Valid;
 import org.onap.policy.models.base.PfAuthorative;
 import org.onap.policy.models.base.PfConceptKey;
 import org.onap.policy.models.base.PfUtils;
@@ -62,6 +62,7 @@ public class JpaNodeTemplateState extends Validated implements PfAuthorative<Nod
     @Column
     private String participantId;
 
+    @Valid
     @VerifyKey
     @NotNull
     @AttributeOverride(name = "name",    column = @Column(name = "nodeTemplate_name"))
index 6bbe6ad..9d67fbb 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- * Copyright (C) 2021-2025 OpenInfra Foundation Europe. All rights reserved.
+ * Copyright (C) 2021-2026 OpenInfra Foundation Europe. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -31,6 +31,8 @@ import jakarta.persistence.InheritanceType;
 import jakarta.persistence.JoinColumn;
 import jakarta.persistence.OneToMany;
 import jakarta.persistence.Table;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotNull;
 import java.io.Serial;
 import java.io.Serializable;
 import java.util.ArrayList;
@@ -42,8 +44,6 @@ import lombok.EqualsAndHashCode;
 import lombok.NonNull;
 import org.apache.commons.lang3.ObjectUtils;
 import org.onap.policy.clamp.models.acm.concepts.Participant;
-import org.onap.policy.common.parameters.annotations.NotNull;
-import org.onap.policy.common.parameters.annotations.Valid;
 import org.onap.policy.models.base.PfAuthorative;
 import org.onap.policy.models.base.Validated;
 
index beaab60..0218422 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- * Copyright (C) 2024 Nordix Foundation.
+ * Copyright (C) 2024-2026 OpenInfra Foundation Europe. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -26,6 +26,7 @@ import jakarta.persistence.Id;
 import jakarta.persistence.Inheritance;
 import jakarta.persistence.InheritanceType;
 import jakarta.persistence.Table;
+import jakarta.validation.constraints.NotNull;
 import java.sql.Timestamp;
 import java.util.UUID;
 import lombok.Data;
@@ -34,7 +35,6 @@ import lombok.NonNull;
 import org.onap.policy.clamp.models.acm.concepts.ParticipantReplica;
 import org.onap.policy.clamp.models.acm.concepts.ParticipantState;
 import org.onap.policy.clamp.models.acm.utils.TimestampHelper;
-import org.onap.policy.common.parameters.annotations.NotNull;
 import org.onap.policy.models.base.PfAuthorative;
 import org.onap.policy.models.base.Validated;
 
index 1eef949..6ac71ab 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- * Copyright (C) 2023 Nordix Foundation.
+ * Copyright (C) 2023-2026 OpenInfra Foundation Europe. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -26,13 +26,13 @@ import jakarta.persistence.Id;
 import jakarta.persistence.Inheritance;
 import jakarta.persistence.InheritanceType;
 import jakarta.persistence.Table;
+import jakarta.validation.constraints.NotNull;
 import java.util.UUID;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.NonNull;
 import org.apache.commons.lang3.ObjectUtils;
 import org.onap.policy.clamp.models.acm.concepts.ParticipantSupportedElementType;
-import org.onap.policy.common.parameters.annotations.NotNull;
 import org.onap.policy.models.base.PfAuthorative;
 import org.onap.policy.models.base.Validated;
 
@@ -48,6 +48,7 @@ public class JpaParticipantSupportedElementType extends Validated
     @Column
     @Id
     private String id;
+
     @NotNull
     @Column
     private String participantId;
index a572311..167f335 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
   ============LICENSE_START=======================================================
-  Copyright (C) 2025 OpenInfra Foundation Europe. All rights reserved.
+  Copyright (C) 2025-2026 OpenInfra Foundation Europe. All rights reserved.
   ================================================================================
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
             <groupId>ch.qos.logback</groupId>
             <artifactId>logback-classic</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.yaml</groupId>
             <artifactId>snakeyaml</artifactId>
index 0e5d644..c3ed5f5 100644 (file)
@@ -1,9 +1,7 @@
 /*-
  * ============LICENSE_START=======================================================
- * ONAP
- * ================================================================================
  * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights reserved.
- * Modifications Copyright (C) 2024 Nordix Foundation
+ * Modifications Copyright (C) 2024-2026 OpenInfra Foundation Europe. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
  * ============LICENSE_END=========================================================
  */
 
 package org.onap.policy.common.parameters;
 
-import java.lang.reflect.Field;
-import java.util.Collection;
-import java.util.Map;
-import java.util.Map.Entry;
-import org.apache.commons.lang3.StringUtils;
-import org.onap.policy.common.parameters.annotations.Min;
-import org.onap.policy.common.parameters.annotations.NotBlank;
-import org.onap.policy.common.parameters.annotations.NotNull;
-import org.onap.policy.common.parameters.annotations.Pattern;
-import org.onap.policy.common.parameters.annotations.Valid;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import jakarta.validation.Validation;
+import jakarta.validation.Validator;
+import jakarta.validation.ValidatorFactory;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
 
-/**
- * Bean validator, supporting the parameter annotations.
- */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
 public class BeanValidator {
-    public static final Logger logger = LoggerFactory.getLogger(BeanValidator.class);
+    private static final ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
+    private static final Validator validator = factory.getValidator();
 
     /**
-     * Validates top level fields within an object. For each annotated field, it retrieves
-     * the value using the public "getter" method for the field. If there is no public
-     * "getter" method, then it throws an exception. Otherwise, it validates the retrieved
-     * value based on the annotations. This recurses through super classes looking for
-     * fields to be verified, but it does not examine any interfaces.
+     * Validates the given bean.
      *
-     * @param name name of the object being validated
-     * @param object object to be validated. If {@code null}, then an empty result is
-     *        returned
+     * @param <T>  the type of the bean
+     * @param bean the bean to validate
+     * @param beanDescription description of the bean
      * @return the validation result
      */
-    public BeanValidationResult validateTop(String name, Object object) {
-        var result = new BeanValidationResult(name, object);
-        if (object == null) {
-            return result;
+    public static <T> BeanValidationResult validate(final String beanDescription, final T bean) {
+        final var result = new BeanValidationResult(beanDescription, bean);
+        final var violations = validator.validate(bean);
+        for (final var violation : violations) {
+            result.addResult(
+                    violation.getPropertyPath().toString(),
+                    violation.getInvalidValue(),
+                    ValidationStatus.INVALID,
+                    violation.getMessage());
         }
-
-        // check class hierarchy - don't need to check interfaces
-        for (Class<?> clazz = object.getClass(); clazz != null; clazz = clazz.getSuperclass()) {
-            validateFields(result, object, clazz);
-        }
-
         return result;
     }
-
-    /**
-     * Adds validators based on the annotations that are available.
-     *
-     * @param validator where to add the validators
-     */
-    protected void addValidators(ValueValidator validator) {
-        validator.addAnnotation(NotNull.class, this::verNotNull);
-        validator.addAnnotation(NotBlank.class, this::verNotBlank);
-        validator.addAnnotation(Min.class, this::verMin);
-        validator.addAnnotation(Pattern.class, this::verRegex);
-        validator.addAnnotation(Valid.class, this::verCascade);
-    }
-
-    /**
-     * Performs validation of all annotated fields found within the class.
-     *
-     * @param result validation results are added here
-     * @param object object whose fields are to be validated
-     * @param clazz class, within the object's hierarchy, to be examined for fields to be
-     *        verified
-     */
-    private void validateFields(BeanValidationResult result, Object object, Class<?> clazz) {
-        for (Field field : clazz.getDeclaredFields()) {
-            var validator = makeFieldValidator(clazz, field);
-            validator.validateField(result, object);
-        }
-    }
-
-    /**
-     * Verifies that the value is not null.
-     *
-     * @param result where to add the validation result
-     * @param fieldName field whose value is being verified
-     * @param value value to be verified
-     * @return {@code true} if the next check should be performed, {@code false} otherwise
-     */
-    public boolean verNotNull(BeanValidationResult result, String fieldName, Object value) {
-        if (value == null) {
-            result.addResult(fieldName, xlate(value), ValidationStatus.INVALID, "is null");
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
-     * Verifies that the value is not blank. Note: this does <i>not</i> verify that the
-     * value is not {@code null}.
-     *
-     * @param result where to add the validation result
-     * @param fieldName field whose value is being verified
-     * @param value value to be verified
-     * @return {@code true} if the next check should be performed, {@code false} otherwise
-     */
-    public boolean verNotBlank(BeanValidationResult result, String fieldName, Object value) {
-        if (value instanceof String && StringUtils.isBlank(value.toString())) {
-            result.addResult(fieldName, xlate(value), ValidationStatus.INVALID, "is blank");
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
-     * Verifies that the value matches a regular expression.
-     *
-     * @param result where to add the validation result
-     * @param fieldName field whose value is being verified
-     * @param annot annotation against which the value is being verified
-     * @param value value to be verified
-     * @return {@code true} if the next check should be performed, {@code false} otherwise
-     */
-    public boolean verRegex(BeanValidationResult result, String fieldName, Pattern annot, Object value) {
-        try {
-            if (value instanceof String && com.google.re2j.Pattern.matches(annot.regexp(), value.toString())) {
-                return true;
-            }
-
-        } catch (RuntimeException e) {
-            logger.warn("validation error for regular expression: {}", annot.regexp(), e);
-        }
-
-        result.addResult(fieldName, xlate(value), ValidationStatus.INVALID,
-                        "does not match regular expression " + annot.regexp());
-        return false;
-    }
-
-    /**
-     * Verifies that the value is >= the minimum value.
-     *
-     * @param result where to add the validation result
-     * @param fieldName field whose value is being verified
-     * @param annot annotation against which the value is being verified
-     * @param value value to be verified
-     * @return {@code true} if the next check should be performed, {@code false} otherwise
-     */
-    public boolean verMin(BeanValidationResult result, String fieldName, Min annot, Object value) {
-        return verMin(result, fieldName, annot.value(), value);
-    }
-
-    /**
-     * Verifies that the value is >= the minimum value.
-     *
-     * @param result where to add the validation result
-     * @param fieldName field whose value is being verified
-     * @param min minimum against which the value is being verified
-     * @param value value to be verified
-     * @return {@code true} if the next check should be performed, {@code false} otherwise
-     */
-    public boolean verMin(BeanValidationResult result, String fieldName, long min, Object value) {
-        if (!(value instanceof Number)) {
-            return true;
-        }
-
-        Number num = (Number) value;
-        if (num instanceof Integer || num instanceof Long) {
-            if (num.longValue() >= min) {
-                return true;
-            }
-
-        } else if (num instanceof Float || num instanceof Double) {
-            if (num.doubleValue() >= min) {
-                return true;
-            }
-
-        } else {
-            return true;
-        }
-
-        result.addResult(fieldName, xlate(value), ValidationStatus.INVALID,
-                        "is below the minimum value: " + min);
-        return false;
-    }
-
-    /**
-     * Verifies that the value is valid by recursively invoking
-     * {@link #validateTop(String, Object)}.
-     *
-     * @param result where to add the validation result
-     * @param fieldName field whose value is being verified
-     * @param value value to be verified
-     * @return {@code true} if the next check should be performed, {@code false} otherwise
-     */
-    public boolean verCascade(BeanValidationResult result, String fieldName, Object value) {
-        if (value == null || value instanceof Collection || value instanceof Map) {
-            return true;
-        }
-
-        BeanValidationResult result2 = (value instanceof ParameterGroup parameterGroup ? parameterGroup.validate()
-                        : validateTop(fieldName, value));
-
-        if (result2.isClean()) {
-            return true;
-        }
-
-        result.addResult(result2);
-
-        return result2.isValid();
-    }
-
-    /**
-     * Validates the items in a collection.
-     *
-     * @param result where to add the validation result
-     * @param fieldName name of the field containing the collection
-     * @param itemValidator validator for individual items within the list
-     * @param value value to be verified
-     * @return {@code true} if the next check should be performed, {@code false} otherwise
-     */
-    public boolean verCollection(BeanValidationResult result, String fieldName, ValueValidator itemValidator,
-                    Object value) {
-
-        if (!(value instanceof Collection)) {
-            return true;
-        }
-
-        Collection<?> list = (Collection<?>) value;
-
-        var result2 = new BeanValidationResult(fieldName, value);
-        var count = 0;
-        for (Object item : list) {
-            itemValidator.validateValue(result2, String.valueOf(count++), item);
-        }
-
-        if (result2.isClean()) {
-            return true;
-        }
-
-        result.addResult(result2);
-        return false;
-    }
-
-    /**
-     * Validates the items in a Map.
-     *
-     * @param result where to add the validation result
-     * @param fieldName name of the field containing the map
-     * @param keyValidator validator for an individual key within the Map entry
-     * @param valueValidator validator for an individual value within the Map entry
-     * @param value value to be verified
-     * @return {@code true} if the next check should be performed, {@code false} otherwise
-     */
-    public boolean verMap(BeanValidationResult result, String fieldName, ValueValidator keyValidator,
-                    ValueValidator valueValidator, Object value) {
-
-        if (!(value instanceof Map)) {
-            return true;
-        }
-
-        Map<?, ?> map = (Map<?, ?>) value;
-
-        var result2 = new BeanValidationResult(fieldName, value);
-
-        for (Entry<?, ?> entry : map.entrySet()) {
-            String name = getEntryName(entry);
-
-            var result3 = new BeanValidationResult(name, entry);
-            keyValidator.validateValue(result3, "key", entry.getKey());
-            valueValidator.validateValue(result3, "value", entry.getValue());
-
-            if (!result3.isClean()) {
-                result2.addResult(result3);
-            }
-        }
-
-        if (result2.isClean()) {
-            return true;
-        }
-
-        result.addResult(result2);
-        return false;
-    }
-
-    /**
-     * Gets a name for an entry.
-     *
-     * @param entry entry whose name is to be determined
-     * @return a name for the entry
-     */
-    protected <K, V> String getEntryName(Map.Entry<K, V> entry) {
-        var key = entry.getKey();
-        if (key == null) {
-            return "";
-        }
-
-        return key.toString();
-    }
-
-    /**
-     * Makes a field validator.
-     *
-     * @param clazz class containing the field
-     * @param field field of interest
-     * @return a validator for the given field
-     */
-    protected FieldValidator makeFieldValidator(Class<?> clazz, Field field) {
-        return new FieldValidator(this, clazz, field);
-    }
-
-    /**
-     * Translates a value to something printable, for use by
-     * {@link ObjectValidationResult}. This default method simply returns the original
-     * value.
-     *
-     * @param value value to be translated
-     * @return the translated value
-     */
-    public Object xlate(Object value) {
-        return value;
-    }
 }
diff --git a/policy-common/src/main/java/org/onap/policy/common/parameters/FieldValidator.java b/policy-common/src/main/java/org/onap/policy/common/parameters/FieldValidator.java
deleted file mode 100644 (file)
index d441c28..0000000
+++ /dev/null
@@ -1,292 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * ONAP
- * ================================================================================
- * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights reserved.
- * ================================================================================
- * 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.
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.policy.common.parameters;
-
-import com.google.gson.annotations.SerializedName;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.AnnotatedParameterizedType;
-import java.lang.reflect.AnnotatedType;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Collection;
-import java.util.Map;
-import lombok.AccessLevel;
-import lombok.Getter;
-import lombok.Setter;
-import org.apache.commons.lang3.StringUtils;
-import org.onap.policy.common.parameters.annotations.NotNull;
-
-/**
- * Validator of the contents of a field, supporting the parameter annotations.
- */
-public class FieldValidator extends ValueValidator {
-
-    /**
-     * {@code True} if there is a field-level annotation, {@code false} otherwise.
-     */
-    @Getter
-    @Setter(AccessLevel.PROTECTED)
-    private boolean fieldAnnotated = false;
-
-    /**
-     * Class containing the field of interest.
-     */
-    private final Class<?> clazz;
-
-    /**
-     * Field of interest.
-     */
-    private final Field field;
-
-    /**
-     * Name of the field when serialized (i.e., as the client would know it).
-     */
-    private final String serializedName;
-
-    /**
-     * Method to retrieve the field's value.
-     */
-    private Method accessor;
-
-
-    /**
-     * Constructs the object.
-     *
-     * @param validator provider of validation methods
-     * @param clazz class containing the field
-     * @param field field whose value is to be validated
-     */
-    public FieldValidator(BeanValidator validator, Class<?> clazz, Field field) {
-        this.clazz = clazz;
-        this.field = field;
-
-        String fieldName = field.getName();
-        if (fieldName.contains("$")) {
-            serializedName = fieldName;
-            return;
-        }
-
-        SerializedName serAnnot = field.getAnnotation(SerializedName.class);
-        serializedName = (serAnnot != null ? serAnnot.value() : fieldName);
-
-        validator.addValidators(this);
-        addListValidator(validator);
-        addMapValidator(validator);
-
-        if (checkers.isEmpty()) {
-            // has no annotations - nothing to check
-            return;
-        }
-
-        // verify the field type is of interest
-        int mod = field.getModifiers();
-        if (Modifier.isStatic(mod)) {
-            classOnly(clazz.getName() + "." + fieldName + " is annotated but the field is static");
-            checkers.clear();
-            return;
-        }
-
-        // get the field's "getter" method
-        accessor = getAccessor(clazz, fieldName);
-        if (accessor == null) {
-            classOnly(clazz.getName() + "." + fieldName + " is annotated but has no \"get\" method");
-            checkers.clear();
-            return;
-        }
-
-        // determine if null is allowed
-        if (field.getAnnotation(NotNull.class) != null || clazz.getAnnotation(NotNull.class) != null) {
-            setNullAllowed(false);
-        }
-    }
-
-    /**
-     * Adds validators for the individual items within a collection, if the field is a
-     * collection.
-     *
-     * @param validator provider of validation methods
-     */
-    private void addListValidator(BeanValidator validator) {
-        if (!Collection.class.isAssignableFrom(field.getType())) {
-            return;
-        }
-
-        var tannot = field.getAnnotatedType();
-        if (!(tannot instanceof AnnotatedParameterizedType)) {
-            return;
-        }
-
-        AnnotatedType[] targs = ((AnnotatedParameterizedType) tannot).getAnnotatedActualTypeArguments();
-        if (targs.length != 1) {
-            return;
-        }
-
-        var itemValidator = new ItemValidator(validator, targs[0]);
-        if (itemValidator.isEmpty()) {
-            return;
-        }
-
-        checkers.add((result, fieldName, value) -> validator.verCollection(result, fieldName, itemValidator, value));
-    }
-
-    /**
-     * Adds validators for the individual entries within a map, if the field is a map.
-     *
-     * @param validator provider of validation methods
-     */
-    private void addMapValidator(BeanValidator validator) {
-        if (!Map.class.isAssignableFrom(field.getType())) {
-            return;
-        }
-
-        var tannot = field.getAnnotatedType();
-        if (!(tannot instanceof AnnotatedParameterizedType)) {
-            return;
-        }
-
-        AnnotatedType[] targs = ((AnnotatedParameterizedType) tannot).getAnnotatedActualTypeArguments();
-        if (targs.length != 2) {
-            return;
-        }
-
-        var keyValidator = new ItemValidator(validator, targs[0]);
-        var valueValidator = new ItemValidator(validator, targs[1]);
-        if (keyValidator.isEmpty() && valueValidator.isEmpty()) {
-            return;
-        }
-
-        checkers.add((result, fieldName, value) -> validator.verMap(result, fieldName, keyValidator, valueValidator,
-                        value));
-    }
-
-    /**
-     * Performs validation of a single field.
-     *
-     * @param result validation results are added here
-     * @param object object whose field is to be validated
-     */
-    public void validateField(BeanValidationResult result, Object object) {
-        if (isEmpty()) {
-            // has no annotations - nothing to check
-            return;
-        }
-
-        // get the value
-        Object value = getValue(object, accessor);
-
-        validateValue(result, serializedName, value);
-    }
-
-    /**
-     * Gets the value from the object using the accessor function.
-     *
-     * @param object object whose value is to be retrieved
-     * @param accessor "getter" method
-     * @return the object's value
-     */
-    private Object getValue(Object object, Method accessor) {
-        try {
-            return accessor.invoke(object);
-
-        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
-            throw new IllegalArgumentException(clazz.getName() + "." + field.getName() + " accessor threw an exception",
-                            e);
-        }
-    }
-
-    /**
-     * Throws an exception if there are field-level annotations.
-     *
-     * @param exceptionMessage exception message
-     */
-    private void classOnly(String exceptionMessage) {
-        if (isFieldAnnotated()) {
-            throw new IllegalArgumentException(exceptionMessage);
-        }
-    }
-
-    /**
-     * Gets an annotation from the field or the class.
-     *
-     * @param annotClass annotation class of interest
-     * @return the annotation, or {@code null} if neither the field nor the class has the
-     *         desired annotation
-     */
-    @Override
-    public <T extends Annotation> T getAnnotation(Class<T> annotClass) {
-
-        // field annotation takes precedence over class annotation
-        var annot = field.getAnnotation(annotClass);
-        if (annot != null) {
-            setFieldAnnotated(true);
-            return annot;
-        }
-
-        return clazz.getAnnotation(annotClass);
-    }
-
-    /**
-     * Gets an accessor method for the given field.
-     *
-     * @param clazz class whose methods are to be searched
-     * @param fieldName field whose "getter" is to be identified
-     * @return the field's "getter" method, or {@code null} if it is not found
-     */
-    private Method getAccessor(Class<?> clazz, String fieldName) {
-        var capname = StringUtils.capitalize(fieldName);
-        var accessor2 = getMethod(clazz, "get" + capname);
-        if (accessor2 != null) {
-            return accessor2;
-        }
-
-        return getMethod(clazz, "is" + capname);
-    }
-
-    /**
-     * Gets the "getter" method having the specified name.
-     *
-     * @param clazz class whose methods are to be searched
-     * @param methodName name of the method of interest
-     * @return the method, or {@code null} if it is not found
-     */
-    private Method getMethod(Class<?> clazz, String methodName) {
-        for (Method method : clazz.getMethods()) {
-            if (methodName.equals(method.getName()) && validMethod(method)) {
-                return method;
-            }
-        }
-
-        return null;
-    }
-
-    /**
-     * Determines if a method is a valid "getter".
-     *
-     * @param method method to be checked
-     * @return {@code true} if the method is a valid "getter", {@code false} otherwise
-     */
-    private boolean validMethod(Method method) {
-        int mod = method.getModifiers();
-        return !(Modifier.isStatic(mod) || method.getReturnType() == void.class || method.getParameterCount() != 0);
-    }
-}
diff --git a/policy-common/src/main/java/org/onap/policy/common/parameters/ItemValidator.java b/policy-common/src/main/java/org/onap/policy/common/parameters/ItemValidator.java
deleted file mode 100644 (file)
index 44b70cd..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * ONAP
- * ================================================================================
- * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
- * ================================================================================
- * 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.
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.policy.common.parameters;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.AnnotatedType;
-
-/**
- * Validator of an "item", which is typically found in a collection, or the key or value
- * components of an entry in a Map.
- */
-public class ItemValidator extends ValueValidator {
-    private final AnnotatedType annotatedType;
-
-    /**
-     * Constructs the object.
-     *
-     * @param validator provider of validation methods
-     * @param annotatedType a type having validation annotations to be
-     *        applied to the item
-     */
-    public ItemValidator(BeanValidator validator, AnnotatedType annotatedType) {
-        this(validator, annotatedType, true);
-    }
-
-    /**
-     * Constructs the object.
-     *
-     * @param validator provider of validation methods
-     * @param annotatedType a type having validation annotations to be
-     *        applied to the item
-     * @param addValidators {@code true} if to add validators
-     */
-    public ItemValidator(BeanValidator validator, AnnotatedType annotatedType, boolean addValidators) {
-        this.annotatedType = annotatedType;
-
-        if (addValidators) {
-            validator.addValidators(this);
-        }
-    }
-
-    /**
-     * Gets an annotation from the field or the class.
-     *
-     * @param annotClass annotation class of interest
-     * @return the annotation, or {@code null} if the {@link #annotatedType} does
-     *         not contain the desired annotation
-     */
-    @Override
-    public <T extends Annotation> T getAnnotation(Class<T> annotClass) {
-        return annotatedType.getAnnotation(annotClass);
-    }
-}
index 8a987bd..3faf5fe 100644 (file)
@@ -3,6 +3,7 @@
  * ONAP
  * ================================================================================
  * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights reserved.
+ * Modifications Copyright (C) 2026 OpenInfra Foundation Europe. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 package org.onap.policy.common.parameters;
 
+import jakarta.validation.constraints.NotBlank;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
 import lombok.NoArgsConstructor;
 import lombok.Setter;
-import org.onap.policy.common.parameters.annotations.NotBlank;
-import org.onap.policy.common.parameters.annotations.NotNull;
 
 /**
  * Implementation of a parameter group.
  */
-@NotNull
-@NotBlank
 @Getter
 @Setter
 @NoArgsConstructor
@@ -40,10 +38,11 @@ public class ParameterGroupImpl implements ParameterGroup {
     /**
      * Group name.
      */
+    @NotBlank
     private String name;
 
     @Override
     public BeanValidationResult validate() {
-        return new BeanValidator().validateTop(getClass().getSimpleName(), this);
+        return BeanValidator.validate(getClass().getSimpleName(), this);
     }
 }
diff --git a/policy-common/src/main/java/org/onap/policy/common/parameters/ValueValidator.java b/policy-common/src/main/java/org/onap/policy/common/parameters/ValueValidator.java
deleted file mode 100644 (file)
index faf4100..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * ONAP
- * ================================================================================
- * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights reserved.
- * ================================================================================
- * 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.
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.policy.common.parameters;
-
-import java.lang.annotation.Annotation;
-import java.util.ArrayList;
-import java.util.List;
-import lombok.AccessLevel;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.Setter;
-import org.onap.policy.common.parameters.annotations.NotNull;
-
-/**
- * Validator of a value.
- * <p/>
- * Note: this currently does not support Min/Max validation of "short" or "byte"; these
- * annotations are simply ignored for these types.
- */
-@NoArgsConstructor
-public class ValueValidator {
-
-    /**
-     * {@code True} if the value is allowed to be {@code null}, {@code false} otherwise.
-     * Subclasses are expected to set this, typically based on the validation annotations
-     * associated with the value.
-     */
-    @Getter
-    @Setter(AccessLevel.PROTECTED)
-    private boolean nullAllowed = true;
-
-    /**
-     * Predicates to invoke to validate an object.
-     * <p/>
-     * Note: each predicate is expected to return {@code true} if the next check is
-     * allowed to proceed, {@code false} otherwise. In addition, if {@link #nullAllowed}
-     * is {@code true}, then the predicates must be prepared to deal with a {@code null}
-     * Object as their input parameter.
-     */
-    protected List<Checker> checkers = new ArrayList<>(10);
-
-    /**
-     * Determines if the validator has anything to check.
-     *
-     * @return {@code true} if the validator is empty (i.e., has nothing to check)
-     */
-    public boolean isEmpty() {
-        return checkers.isEmpty();
-    }
-
-    /**
-     * Performs validation of a single field.
-     *
-     * @param result validation results are added here
-     * @param fieldName field whose value is being verified
-     * @param value value to be validated
-     */
-    protected void validateValue(BeanValidationResult result, String fieldName, Object value) {
-
-        if (value == null && isNullAllowed()) {
-            // value is null and null is allowed - just return
-            return;
-        }
-
-        for (Checker checker : checkers) {
-            if (!checker.test(result, fieldName, value)) {
-                // invalid - don't bother with additional checks
-                return;
-            }
-        }
-    }
-
-    /**
-     * Looks for an annotation at the class or field level. If an annotation is found at
-     * either the field or class level, then it adds a verifier to
-     * {@link ValueValidator#checkers}.
-     *
-     * @param annotClass class of annotation to find
-     * @param checker function to validate the value
-     */
-    public <T extends Annotation> void addAnnotation(Class<T> annotClass, Checker checker) {
-        var annot = getAnnotation(annotClass);
-        if (annot != null) {
-            checkers.add(checker);
-
-            if (annotClass == NotNull.class) {
-                setNullAllowed(false);
-            }
-        }
-    }
-
-    /**
-     * Looks for an annotation at the class or field level. If an annotation is found at
-     * either the field or class level, then it adds a verifier to
-     * {@link ValueValidator#checkers}.
-     *
-     * @param annotClass class of annotation to find
-     * @param checker function to validate the value
-     */
-    public <T extends Annotation> void addAnnotation(Class<T> annotClass, CheckerWithAnnot<T> checker) {
-        var annot = getAnnotation(annotClass);
-        if (annot != null) {
-            checkers.add((result, fieldName, value) -> checker.test(result, fieldName, annot, value));
-        }
-    }
-
-    /**
-     * Gets an annotation from the field or the class. The default method simply returns
-     * {@code null}.
-     *
-     * @param annotClass annotation class of interest
-     * @return the annotation, or {@code null} if neither the field nor the class has the
-     *         desired annotation
-     */
-    public <T extends Annotation> T getAnnotation(Class<T> annotClass) {
-        return null;
-    }
-
-    // functions to validate a value extracted from a field
-
-    public static interface Checker {
-        boolean test(BeanValidationResult result, String fieldName, Object value);
-    }
-
-    public static interface CheckerWithAnnot<T extends Annotation> {
-        boolean test(BeanValidationResult result, String fieldName, T annotation, Object value);
-    }
-}
diff --git a/policy-common/src/main/java/org/onap/policy/common/parameters/annotations/Min.java b/policy-common/src/main/java/org/onap/policy/common/parameters/annotations/Min.java
deleted file mode 100644 (file)
index 305d981..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- * ONAP
- * ================================================================================
- * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights reserved.
- * ================================================================================
- * 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.
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.policy.common.parameters.annotations;
-
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.TYPE_USE;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-@Retention(RUNTIME)
-@Target({FIELD, TYPE_USE})
-public @interface Min {
-
-    /**
-     * The minimum value allowed.
-     *
-     * @return the minimum value allowed
-     */
-    long value();
-}
diff --git a/policy-common/src/main/java/org/onap/policy/common/parameters/annotations/NotBlank.java b/policy-common/src/main/java/org/onap/policy/common/parameters/annotations/NotBlank.java
deleted file mode 100644 (file)
index 0744beb..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- * ONAP
- * ================================================================================
- * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights reserved.
- * ================================================================================
- * 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.
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.policy.common.parameters.annotations;
-
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.TYPE;
-import static java.lang.annotation.ElementType.TYPE_USE;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * Indicates that a field (i.e., String) may not be empty.
- */
-@Retention(RUNTIME)
-@Target({TYPE, FIELD, TYPE_USE})
-public @interface NotBlank {
-
-}
diff --git a/policy-common/src/main/java/org/onap/policy/common/parameters/annotations/NotNull.java b/policy-common/src/main/java/org/onap/policy/common/parameters/annotations/NotNull.java
deleted file mode 100644 (file)
index 8135600..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- * ONAP
- * ================================================================================
- * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights reserved.
- * ================================================================================
- * 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.
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.policy.common.parameters.annotations;
-
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.TYPE;
-import static java.lang.annotation.ElementType.TYPE_USE;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * Indicates that a field may not be null.
- */
-@Retention(RUNTIME)
-@Target({TYPE, FIELD, TYPE_USE})
-public @interface NotNull {
-
-}
diff --git a/policy-common/src/main/java/org/onap/policy/common/parameters/annotations/Pattern.java b/policy-common/src/main/java/org/onap/policy/common/parameters/annotations/Pattern.java
deleted file mode 100644 (file)
index 91a74d7..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * ONAP
- * ================================================================================
- * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights reserved.
- * ================================================================================
- * 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.
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.policy.common.parameters.annotations;
-
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.TYPE_USE;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-@Retention(RUNTIME)
-@Target({FIELD, TYPE_USE})
-public @interface Pattern {
-
-    /**
-     * Regular expression to be matched.
-     */
-    String regexp();
-}
diff --git a/policy-common/src/main/java/org/onap/policy/common/parameters/annotations/Valid.java b/policy-common/src/main/java/org/onap/policy/common/parameters/annotations/Valid.java
deleted file mode 100644 (file)
index 227a726..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * ONAP
- * ================================================================================
- * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights reserved.
- * ================================================================================
- * 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.
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.policy.common.parameters.annotations;
-
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.TYPE;
-import static java.lang.annotation.ElementType.TYPE_USE;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-@Retention(RUNTIME)
-@Target({TYPE, FIELD, TYPE_USE})
-public @interface Valid {
-
-}
index c9d5e3e..5e4f662 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2019, 2024 Nordix Foundation.
+ *  Copyright (C) 2019-2026 OpenInfra Foundation Europe. All rights reserved.
  *  Modifications Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,6 +21,8 @@
 
 package org.onap.policy.common.parameters.topic;
 
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotNull;
 import java.util.List;
 import lombok.Getter;
 import lombok.Setter;
@@ -28,22 +30,20 @@ import org.apache.commons.lang3.StringUtils;
 import org.onap.policy.common.parameters.BeanValidationResult;
 import org.onap.policy.common.parameters.ParameterGroupImpl;
 import org.onap.policy.common.parameters.ValidationStatus;
-import org.onap.policy.common.parameters.annotations.NotBlank;
-import org.onap.policy.common.parameters.annotations.NotNull;
 
 /**
  * Class to hold all parameters needed for topic properties.
  *
  * @author Ajith Sreekumar (ajith.sreekumar@est.tech)
  */
-@NotNull
-@NotBlank
 @Getter
 @Setter
 public class TopicParameterGroup extends ParameterGroupImpl {
 
-    private List<TopicParameters> topicSources;
-    private List<TopicParameters> topicSinks;
+    @NotNull
+    private List<@Valid TopicParameters> topicSources;
+    @NotNull
+    private List<@Valid TopicParameters> topicSinks;
 
     public TopicParameterGroup() {
         super(TopicParameterGroup.class.getSimpleName());
index 2b8bfbd..744d7d5 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2019, 2024 Nordix Foundation.
+ *  Copyright (C) 2019-2026 OpenInfra Foundation Europe. All rights reserved.
  *  Modifications Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
 
 package org.onap.policy.common.parameters.topic;
 
+import jakarta.validation.constraints.NotBlank;
 import lombok.EqualsAndHashCode;
 import lombok.Getter;
 import lombok.Setter;
-import org.onap.policy.common.parameters.annotations.NotBlank;
-import org.onap.policy.common.parameters.annotations.NotNull;
 
 /**
  * Class to hold topic details such as name, server and topicCommInfrastructure.
  *
  * @author Ajith Sreekumar (ajith.sreekumar@est.tech)
  */
-@NotNull
-@NotBlank
 @Getter
 @Setter
 @EqualsAndHashCode(callSuper = false)
 public class TopicParameters extends BusTopicParams {
+    @NotBlank
     private String topicCommInfrastructure;
 
     public TopicParameters() {
diff --git a/policy-common/src/test/java/org/onap/policy/common/parameters/TestBeanValidator.java b/policy-common/src/test/java/org/onap/policy/common/parameters/TestBeanValidator.java
deleted file mode 100644 (file)
index d37ef62..0000000
+++ /dev/null
@@ -1,461 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * ONAP
- * ================================================================================
- * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights reserved.
- * Modifications Copyright (C) 2024 Nordix Foundation
- * ================================================================================
- * 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.
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.policy.common.parameters;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.function.Consumer;
-import lombok.Getter;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.onap.policy.common.parameters.annotations.Min;
-import org.onap.policy.common.parameters.annotations.NotBlank;
-import org.onap.policy.common.parameters.annotations.NotNull;
-import org.onap.policy.common.parameters.annotations.Pattern;
-import org.onap.policy.common.parameters.annotations.Valid;
-
-class TestBeanValidator {
-    private static final String TOP = "top";
-    private static final String STR_FIELD = "strValue";
-    private static final String INT_FIELD = "intValue";
-    private static final String NUM_FIELD = "numValue";
-    private static final String STRING_VALUE = "string value";
-    private static final int INT_VALUE = 20;
-
-    private BeanValidator validator;
-
-    @BeforeEach
-    void setUp() {
-        validator = new BeanValidator();
-    }
-
-    @Test
-    void testValidateTop_testValidateFields() {
-        // validate null
-        assertTrue(validator.validateTop(TOP, null).isValid());
-
-        // validate something that has no annotations
-        assertTrue(validator.validateTop(TOP, validator).isValid());
-
-        @NotNull
-        @Getter
-        class Data {
-            String strValue;
-        }
-
-        // one failure case
-        Data data = new Data();
-        BeanValidationResult result = validator.validateTop(TOP, data);
-        assertInvalid("testValidateFields", result, STR_FIELD, "null");
-        assertTrue(result.getResult().contains(TOP));
-
-        // one success case
-        data.strValue = STRING_VALUE;
-        assertTrue(validator.validateTop(TOP, data).isValid());
-
-        @Getter
-        class Derived extends Data {
-            @Min(10)
-            int intValue;
-        }
-
-        Derived derived = new Derived();
-        derived.strValue = STRING_VALUE;
-        derived.intValue = INT_VALUE;
-
-        // success case
-        assertTrue(validator.validateTop(TOP, derived).isValid());
-
-        // failure cases
-        derived.strValue = null;
-        assertInvalid("testValidateFields", validator.validateTop(TOP, derived), STR_FIELD, "null");
-        derived.strValue = STRING_VALUE;
-
-        derived.intValue = 1;
-        assertInvalid("testValidateFields", validator.validateTop(TOP, derived), INT_FIELD, "minimum");
-        derived.intValue = INT_VALUE;
-
-        // both invalid
-        derived.strValue = null;
-        derived.intValue = 1;
-        result = validator.validateTop(TOP, derived);
-        assertInvalid("testValidateFields", result, STR_FIELD, "null");
-        assertInvalid("testValidateFields", result, INT_FIELD, "minimum");
-        derived.strValue = STRING_VALUE;
-        derived.intValue = INT_VALUE;
-    }
-
-    @Test
-    void testVerNotNull() {
-        @Getter
-        class NotNullCheck {
-            @Min(1)
-            @NotNull
-            Integer intValue;
-        }
-
-        NotNullCheck notNullCheck = new NotNullCheck();
-        assertInvalid("testVerNotNull", validator.validateTop(TOP, notNullCheck), INT_FIELD, "null");
-
-        notNullCheck.intValue = INT_VALUE;
-        assertTrue(validator.validateTop(TOP, notNullCheck).isValid());
-
-        notNullCheck.intValue = 0;
-        assertInvalid("testVerNotNull", validator.validateTop(TOP, notNullCheck), INT_FIELD, "minimum");
-    }
-
-    @Test
-    void testVerNotBlank() {
-        @Getter
-        class NotBlankCheck {
-            @NotBlank
-            String strValue;
-        }
-
-        NotBlankCheck notBlankCheck = new NotBlankCheck();
-
-        // null
-        assertTrue(validator.validateTop(TOP, notBlankCheck).isValid());
-
-        // empty
-        notBlankCheck.strValue = "";
-        assertInvalid("testVerNotNull", validator.validateTop(TOP, notBlankCheck), STR_FIELD, "blank");
-
-        // spaces
-        notBlankCheck.strValue = "  ";
-        assertInvalid("testVerNotNull", validator.validateTop(TOP, notBlankCheck), STR_FIELD, "blank");
-
-        // not blank
-        notBlankCheck.strValue = STRING_VALUE;
-        assertTrue(validator.validateTop(TOP, notBlankCheck).isValid());
-
-        /*
-         * Class with "blank" annotation on an integer.
-         */
-        @Getter
-        class NotBlankInt {
-            @NotBlank
-            int intValue;
-        }
-
-        NotBlankInt notBlankInt = new NotBlankInt();
-        notBlankInt.intValue = 0;
-        assertTrue(validator.validateTop(TOP, notBlankInt).isValid());
-    }
-
-    @Test
-    void testVerRegex() {
-        @Getter
-        class RegexCheck {
-            @Pattern(regexp = "[a-f]*")
-            String strValue;
-        }
-
-        RegexCheck regexCheck = new RegexCheck();
-
-        // does not match
-        regexCheck.strValue = "xyz";
-        assertInvalid("testVerRegex", validator.validateTop(TOP, regexCheck), STR_FIELD,
-                        "does not match regular expression [a-f]");
-
-        // matches
-        regexCheck.strValue = "abcabc";
-        assertTrue(validator.validateTop(TOP, regexCheck).isValid());
-
-        // invalid regex
-        @Getter
-        class InvalidRegexCheck {
-            @Pattern(regexp = "[a-f")
-            String strValue;
-        }
-
-        InvalidRegexCheck invalidRegexCheck = new InvalidRegexCheck();
-
-        // does not match
-        invalidRegexCheck.strValue = "abc";
-        assertInvalid("testVerRegex", validator.validateTop(TOP, invalidRegexCheck), STR_FIELD,
-                        "does not match regular expression [a-f");
-
-        // matches
-        regexCheck.strValue = "abcabc";
-        assertTrue(validator.validateTop(TOP, regexCheck).isValid());
-
-        /*
-         * Class with "regex" annotation on an integer.
-         */
-        @Getter
-        class RegexInt {
-            @Pattern(regexp = "[a-f]*")
-            int intValue;
-        }
-
-        RegexInt regexInt = new RegexInt();
-        regexInt.intValue = 0;
-        assertInvalid("testVerRegex", validator.validateTop(TOP, regexInt), INT_FIELD,
-                        "does not match regular expression [a-f]");
-    }
-
-    @Test
-    void testVerMin() {
-        /*
-         * Field is not a number.
-         */
-        @Getter
-        class NonNumeric {
-            @Min(10)
-            String strValue;
-        }
-
-        NonNumeric nonNumeric = new NonNumeric();
-        nonNumeric.strValue = STRING_VALUE;
-        assertTrue(validator.validateTop(TOP, nonNumeric).isValid());
-
-        /*
-         * Integer field.
-         */
-        @Getter
-        class IntField {
-            @Min(10)
-            Integer intValue;
-        }
-
-        // ok value
-        IntField intField = new IntField();
-        assertNumeric(intField, value -> {
-            intField.intValue = value;
-        }, INT_FIELD, "minimum", 10, 1);
-
-        /*
-         * Long field.
-         */
-        @Getter
-        class LongField {
-            @Min(10)
-            Long numValue;
-        }
-
-        // ok value
-        LongField longField = new LongField();
-        assertNumeric(longField, value -> {
-            longField.numValue = (long) value;
-        }, NUM_FIELD, "minimum", 10, 1);
-
-        /*
-         * Float field.
-         */
-        @Getter
-        class FloatField {
-            @Min(10)
-            Float numValue;
-        }
-
-        // ok value
-        FloatField floatField = new FloatField();
-        assertNumeric(floatField, value -> {
-            floatField.numValue = (float) value;
-        }, NUM_FIELD, "minimum", 10, 1);
-
-        /*
-         * Double field.
-         */
-        @Getter
-        class DoubleField {
-            @Min(10)
-            Double numValue;
-        }
-
-        // ok value
-        DoubleField doubleField = new DoubleField();
-        assertNumeric(doubleField, value -> {
-            doubleField.numValue = (double) value;
-        }, NUM_FIELD, "minimum", 10, 1);
-
-        /*
-         * Atomic Integer field (which is a subclass of Number).
-         */
-        @Getter
-        class AtomIntValue {
-            @Min(10)
-            AtomicInteger numValue;
-        }
-
-        // ok value
-        AtomIntValue atomIntField = new AtomIntValue();
-        atomIntField.numValue = new AtomicInteger(INT_VALUE);
-        assertTrue(validator.validateTop(TOP, atomIntField).isValid());
-
-        // invalid value - should be OK, because it isn't an Integer
-        atomIntField.numValue.set(101);
-        assertTrue(validator.validateTop(TOP, atomIntField).isValid());
-    }
-
-    @Test
-    void testVerCascade() {
-        @Getter
-        class Item {
-            @NotNull
-            Integer intValue;
-        }
-
-        @Getter
-        class Container {
-            @Valid
-            Item checked;
-
-            Item unchecked;
-
-            @Valid
-            List<Item> items;
-
-            @Valid
-            Map<String, Item> itemMap;
-        }
-
-        Container cont = new Container();
-        cont.unchecked = new Item();
-        cont.items = List.of(new Item());
-        cont.itemMap = Map.of(STRING_VALUE, new Item());
-
-        cont.checked = null;
-        assertTrue(validator.validateTop(TOP, cont).isValid());
-
-        cont.checked = new Item();
-
-        assertInvalid("testVerCascade", validator.validateTop(TOP, cont), INT_FIELD, "null");
-
-        cont.checked.intValue = INT_VALUE;
-        assertTrue(validator.validateTop(TOP, cont).isValid());
-    }
-
-    @Test
-    void testVerCollection() {
-        @Getter
-        class Container {
-            List<@Min(5) Integer> items;
-
-            // not a collection - should not be checked
-            @Valid
-            String strValue;
-
-            String noAnnotations;
-        }
-
-        Container cont = new Container();
-        cont.strValue = STRING_VALUE;
-        cont.noAnnotations = STRING_VALUE;
-
-        // null collection - always valid
-        assertTrue(validator.validateTop(TOP, cont).isValid());
-
-        // empty collection - always valid
-        cont.items = List.of();
-        assertTrue(validator.validateTop(TOP, cont).isValid());
-
-        cont.items = List.of(-10, -20);
-        assertThat(validator.validateTop(TOP, cont).getResult()).contains("\"0\"", "-10", "\"1\"", "-20", "minimum");
-
-        cont.items = List.of(10, -30);
-        assertThat(validator.validateTop(TOP, cont).getResult()).contains("\"1\"", "-30", "minimum")
-                        .doesNotContain("\"0\"");
-
-        cont.items = List.of(10, 20);
-        assertTrue(validator.validateTop(TOP, cont).isValid());
-    }
-
-    @Test
-    void testVerMap() {
-        @Getter
-        class Container {
-            Map<String, @Min(5) Integer> items;
-
-            // not a map
-            @NotBlank
-            String strValue;
-
-            String noAnnotations;
-        }
-
-        Container cont = new Container();
-        cont.strValue = STRING_VALUE;
-        cont.noAnnotations = STRING_VALUE;
-
-        // null map - always valid
-        assertTrue(validator.validateTop(TOP, cont).isValid());
-
-        // empty map - always valid
-        cont.items = Map.of();
-        assertTrue(validator.validateTop(TOP, cont).isValid());
-
-        cont.items = Map.of("abc", -10, "def", -20);
-        assertThat(validator.validateTop(TOP, cont).getResult()).contains("abc", "-10", "def", "-20", "minimum");
-
-        cont.items = Map.of("abc", 10, "def", -30);
-        assertThat(validator.validateTop(TOP, cont).getResult()).contains("def", "-30", "minimum")
-                        .doesNotContain("abc");
-
-        cont.items = Map.of("abc", 10, "def", 20);
-        assertTrue(validator.validateTop(TOP, cont).isValid());
-    }
-
-    @Test
-    void testGetEntryName() {
-        assertThat(validator.getEntryName(makeEntry(null))).isEmpty();
-        assertThat(validator.getEntryName(makeEntry(""))).isEmpty();
-        assertThat(validator.getEntryName(makeEntry(STRING_VALUE))).isEqualTo(STRING_VALUE);
-    }
-
-    /**
-     * Makes a Map entry with the given key and value.
-     *
-     * @param key desired key
-     * @return a new Map entry
-     */
-    private Map.Entry<String, Integer> makeEntry(String key) {
-        HashMap<String, Integer> map = new HashMap<>();
-        map.put(key, 0);
-        return map.entrySet().iterator().next();
-    }
-
-    private <T> void assertNumeric(T object, Consumer<Integer> setter, String fieldName,
-                                   String expectedText, int edge, int outside) {
-        setter.accept(TestBeanValidator.INT_VALUE);
-        assertTrue(validator.validateTop(TOP, object).isValid());
-
-        // on the edge
-        setter.accept(edge);
-        assertTrue(validator.validateTop(TOP, object).isValid());
-
-        // invalid
-        setter.accept(outside);
-        assertInvalid("testVerNotNull", validator.validateTop(TOP, object), fieldName, expectedText);
-    }
-
-
-    private void assertInvalid(String testName, BeanValidationResult result, String... text) {
-        assertThat(result.getResult()).describedAs(testName).contains(text);
-    }
-}
diff --git a/policy-common/src/test/java/org/onap/policy/common/parameters/TestFieldValidator.java b/policy-common/src/test/java/org/onap/policy/common/parameters/TestFieldValidator.java
deleted file mode 100644 (file)
index 2f8e44e..0000000
+++ /dev/null
@@ -1,370 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * ONAP
- * ================================================================================
- * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
- * Modifications Copyright (C) 2023-2025 OpenInfra Foundation Europe. All rights reserved.
- * ================================================================================
- * 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.
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.policy.common.parameters;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-import com.google.gson.annotations.SerializedName;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.util.List;
-import java.util.Map;
-import lombok.Getter;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.onap.policy.common.parameters.annotations.Min;
-import org.onap.policy.common.parameters.annotations.NotBlank;
-import org.onap.policy.common.parameters.annotations.NotNull;
-
-class TestFieldValidator extends ValidatorUtil {
-    private static final String INT_LIST_FIELD = "intList";
-    private static final String INT_MAP_FIELD = "intMap";
-    private static final String UNANNOTATED_FIELD = "unannotated";
-    private static final String INT_FIELD = "intValue";
-    private static final int VALID_INT = 10;
-    private static final int INVALID_INT = -10;
-
-    @Getter
-    private int unannotated;
-
-    @Min(0)
-    @Getter
-    private int intValue;
-
-    @Getter
-    private List<@Min(1) Integer> intList;
-
-    @Getter
-    private Map<@NotBlank String, @Min(1) Integer> intMap;
-
-    @SerializedName("annotated_key_map")
-    @Getter
-    private Map<@NotBlank String, Integer> annotatedKeyMap;
-
-    @Getter
-    private Map<String, @Min(1) Integer> annotatedValueMap;
-
-    @Getter
-    private List<Integer> unannotatedList;
-
-    @Getter
-    private Map<String, Integer> unannotatedMap;
-
-    @NotNull
-    @Getter
-    private boolean boolValue;
-
-    @NotNull
-    @Getter
-    private String notNullValue;
-
-    @Min(0)
-    @Getter
-    private static int staticField;
-
-    /**
-     * Has no accessor.
-     */
-    @Min(0)
-    private int noMethod;
-
-    /**
-     * Accessor is {@link #getStaticMethod()}, which is static.
-     */
-    @Min(0)
-    private int staticMethod;
-
-    /**
-     * Accessor is {@link #getVoidMethod()}, which returns a void.
-     */
-    @Min(0)
-    private int voidMethod;
-
-    /**
-     * Accessor is {@link #getParameterizedMethod(boolean)}, which requires a parameter.
-     */
-    @Min(0)
-    private int parameterizedMethod;
-
-    /**
-     * Accessor is {@link #getExMethod()}, which throws an exception.
-     */
-    @Min(0)
-    private int exMethod;
-
-
-    @BeforeEach
-    void setUp() {
-        bean = new BeanValidator();
-    }
-
-    @Test
-    void testGetAnnotation() {
-        // field-level annotation
-        assertThat(new FieldValidator(bean, TestFieldValidator.class, getField(INT_FIELD)).isEmpty()).isFalse();
-
-        // class-level annotation
-        assertThat(new FieldValidator(bean, ClassAnnot.class, getField(ClassAnnot.class, "text")).isEmpty()).isFalse();
-    }
-
-    @Test
-    void testFieldValidator() throws SecurityException {
-        /*
-         * Class with no annotations.
-         */
-        @NotNull
-        class NoAnnotations {
-            @SuppressWarnings("unused")
-            String strValue;
-        }
-
-        // unannotated
-        assertThat(new FieldValidator(bean, TestFieldValidator.class, getField("unannotated")).isEmpty()).isTrue();
-
-        // these are invalid for various reasons
-
-        Field staticField2 = getField("staticField");
-        assertThatThrownBy(() -> new FieldValidator(bean, TestFieldValidator.class, staticField2))
-                        .isInstanceOf(IllegalArgumentException.class);
-
-        Field noMethodField = getField("noMethod");
-        assertThatThrownBy(() -> new FieldValidator(bean, TestFieldValidator.class, noMethodField))
-                        .isInstanceOf(IllegalArgumentException.class);
-
-        // annotated
-        assertThat(new FieldValidator(bean, TestFieldValidator.class, getField(INT_FIELD)).isEmpty()).isFalse();
-    }
-
-    @Test
-    void testFieldValidator_SetNullAllowed() {
-        // default - null is allowed
-        assertThat(new FieldValidator(bean, TestFieldValidator.class, getField(INT_FIELD)).isNullAllowed()).isTrue();
-
-        // field-level NotNull
-        assertThat(new FieldValidator(bean, TestFieldValidator.class, getField("notNullValue")).isNullAllowed())
-                        .isFalse();
-
-        // class-level NotNull
-        assertThat(new FieldValidator(bean, ClassAnnot.class, getField(ClassAnnot.class, "noMethod")).isNullAllowed())
-                        .isFalse();
-    }
-
-    @Test
-    void testAddListValidator() {
-
-        // unannotated
-        assertThat(new FieldValidator(bean, TestFieldValidator.class, getField("unannotatedList")).isEmpty()).isTrue();
-
-        // annotated
-        assertThat(new FieldValidator(bean, TestFieldValidator.class, getField(INT_LIST_FIELD)).isEmpty()).isFalse();
-    }
-
-    @Test
-    void testAddMapValidator() {
-
-        // unannotated
-        assertThat(new FieldValidator(bean, TestFieldValidator.class, getField("unannotatedMap")).isEmpty()).isTrue();
-
-        // annotated
-        assertThat(new FieldValidator(bean, TestFieldValidator.class, getField(INT_MAP_FIELD)).isEmpty()).isFalse();
-
-        // only the key is annotated
-        FieldValidator validator = new FieldValidator(bean, TestFieldValidator.class, getField("annotatedKeyMap"));
-        assertThat(validator.isEmpty()).isFalse();
-
-        BeanValidationResult result = new BeanValidationResult(MY_NAME, this);
-        annotatedKeyMap = Map.of("abc", -10);
-        validator.validateField(result, this);
-        assertThat(result.getResult()).isNull();
-
-        annotatedKeyMap = Map.of(" ", -10);
-        validator.validateField(result, this);
-        assertThat(result.getResult()).contains("annotated_key_map", "blank").doesNotContain("-10");
-
-        // only the value is annotated
-        validator = new FieldValidator(bean, TestFieldValidator.class, getField("annotatedValueMap"));
-        assertThat(validator.isEmpty()).isFalse();
-
-        result = new BeanValidationResult(MY_NAME, this);
-        annotatedValueMap = Map.of(" ", 10);
-        validator.validateField(result, this);
-        assertThat(result.getResult()).isNull();
-
-        annotatedValueMap = Map.of(" ", -10);
-        validator.validateField(result, this);
-        assertThat(result.getResult()).doesNotContain("blank").contains("annotatedValueMap", "\" \"", "-10");
-    }
-
-    @SuppressWarnings("deprecation")
-    @Test
-    void testValidateField_testGetValue() {
-        // unannotated
-        BeanValidationResult result = new BeanValidationResult(MY_NAME, this);
-        new FieldValidator(bean, getClass(), getField(UNANNOTATED_FIELD)).validateField(result, this);
-        assertThat(result.getResult()).isNull();
-
-        // valid
-        intValue = VALID_INT;
-        result = new BeanValidationResult(MY_NAME, this);
-        new FieldValidator(bean, getClass(), getField(INT_FIELD)).validateField(result, this);
-        assertThat(result.getResult()).isNull();
-
-        // invalid
-        intValue = INVALID_INT;
-        result = new BeanValidationResult(MY_NAME, this);
-        new FieldValidator(bean, getClass(), getField(INT_FIELD)).validateField(result, this);
-        assertThat(result.getResult()).contains(INT_FIELD);
-
-        // throws an exception
-        FieldValidator validator = new FieldValidator(bean, TestFieldValidator.class, getField("exMethod"));
-        BeanValidationResult result2 = new BeanValidationResult(MY_NAME, this);
-        assertThatThrownBy(() -> validator.validateField(result2, this)).isInstanceOf(IllegalArgumentException.class)
-                        .getCause().isInstanceOf(InvocationTargetException.class).getCause()
-                        .hasMessage("expected exception");
-    }
-
-    @Test
-    void testValidateField_testGetValue_ListField() {
-        // valid
-        BeanValidationResult result = new BeanValidationResult(MY_NAME, this);
-        intList = List.of(10, 20, 30, 40);
-        new FieldValidator(bean, getClass(), getField(INT_LIST_FIELD)).validateField(result, this);
-        assertThat(result.getResult()).isNull();
-
-        // invalid
-        result = new BeanValidationResult(MY_NAME, this);
-        intList = List.of(9, -8, 7, -6);
-        new FieldValidator(bean, getClass(), getField(INT_LIST_FIELD)).validateField(result, this);
-        assertThat(result.getResult()).doesNotContain("0", "9").contains("1", "-8").doesNotContain("2", "7")
-                        .contains("3", "-6");
-    }
-
-    @Test
-    void testValidateField_testGetValue_MapField() {
-        // valid
-        BeanValidationResult result = new BeanValidationResult(MY_NAME, this);
-        intMap = Map.of("ten", 10, "twenty", 20, "thirty", 30, "forty", 40);
-        new FieldValidator(bean, getClass(), getField(INT_MAP_FIELD)).validateField(result, this);
-        assertThat(result.getResult()).isNull();
-
-        // invalid
-        result = new BeanValidationResult(MY_NAME, this);
-        intMap = Map.of("ten", 9, "twenty", -8, "thirty", 7, "forty", -6);
-        new FieldValidator(bean, getClass(), getField(INT_MAP_FIELD)).validateField(result, this);
-        assertThat(result.getResult()).doesNotContain("ten", "9").contains("twenty", "-8").doesNotContain("thirty", "7")
-                        .contains("forty", "-6");
-    }
-
-    @Test
-    void testClassOnly() {
-        // class-level annotation has no bearing on a static field
-        assertThat(new FieldValidator(bean, ClassAnnot.class, getField(ClassAnnot.class, "staticValue")).isEmpty())
-                        .isTrue();
-
-        // field-level annotation on a static field
-        Field staticField2 = getField("staticField");
-        assertThatThrownBy(() -> new FieldValidator(bean, TestFieldValidator.class, staticField2))
-                        .isInstanceOf(IllegalArgumentException.class);
-    }
-
-    @Test
-    void testGetAccessor() {
-        // uses "getXxx"
-        assertThat(new FieldValidator(bean, TestFieldValidator.class, getField(INT_FIELD)).isEmpty()).isFalse();
-
-        // uses "isXxx"
-        assertThat(new FieldValidator(bean, TestFieldValidator.class, getField("boolValue")).isEmpty()).isFalse();
-    }
-
-    @Test
-    void testGetMethod() {
-        assertThat(new FieldValidator(bean, TestFieldValidator.class, getField(INT_FIELD)).isEmpty()).isFalse();
-
-        // these are invalid for various reasons
-
-        Field noMethodField = getField("noMethod");
-        assertThatThrownBy(() -> new FieldValidator(bean, TestFieldValidator.class, noMethodField))
-                        .isInstanceOf(IllegalArgumentException.class);
-
-        Field staticMethodField = getField("staticMethod");
-        assertThatThrownBy(() -> new FieldValidator(bean, TestFieldValidator.class, staticMethodField))
-                        .isInstanceOf(IllegalArgumentException.class);
-    }
-
-    @Test
-    void testValidMethod() {
-        assertThat(new FieldValidator(bean, TestFieldValidator.class, getField(INT_FIELD)).isEmpty()).isFalse();
-
-        // these are invalid for various reasons
-
-        Field staticMethodField = getField("staticMethod");
-        assertThatThrownBy(() -> new FieldValidator(bean, TestFieldValidator.class, staticMethodField))
-                        .isInstanceOf(IllegalArgumentException.class);
-
-        Field voidMethodField = getField("voidMethod");
-        assertThatThrownBy(() -> new FieldValidator(bean, TestFieldValidator.class, voidMethodField))
-                        .isInstanceOf(IllegalArgumentException.class);
-
-        Field paramMethodField = getField("parameterizedMethod");
-        assertThatThrownBy(() -> new FieldValidator(bean, TestFieldValidator.class, paramMethodField))
-                        .isInstanceOf(IllegalArgumentException.class);
-    }
-
-    @Test
-    void testIsFieldAnnotated_testSetFieldAnnotated() {
-        // annotated at the field level
-        assertThat(new FieldValidator(bean, getClass(), getField(INT_FIELD)).isFieldAnnotated()).isTrue();
-
-        // unannotated
-        assertThat(new FieldValidator(bean, getClass(), getField(UNANNOTATED_FIELD)).isFieldAnnotated()).isFalse();
-    }
-
-    public static int getStaticMethod() {
-        return -1000;
-    }
-
-    void getVoidMethod() {
-        // do nothing
-    }
-
-    public int getParameterizedMethod(boolean flag) {
-        return flag ? 0 : 1;
-    }
-
-    public int getExMethod() {
-        throw new RuntimeException("expected exception");
-    }
-
-    @NotNull
-    public static class ClassAnnot {
-        @Getter
-        private String text;
-
-        // no "get" method
-        @SuppressWarnings("unused")
-        private String noMethod;
-
-        @Getter
-        private static int staticValue;
-    }
-}
diff --git a/policy-common/src/test/java/org/onap/policy/common/parameters/TestItemValidator.java b/policy-common/src/test/java/org/onap/policy/common/parameters/TestItemValidator.java
deleted file mode 100644 (file)
index b2686fd..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * ONAP
- * ================================================================================
- * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
- * Modifications Copyright (C) 2024 Nordix Foundation
- * ================================================================================
- * 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.
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.policy.common.parameters;
-
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.onap.policy.common.parameters.annotations.Min;
-import org.onap.policy.common.parameters.annotations.NotBlank;
-import org.onap.policy.common.parameters.annotations.NotNull;
-
-class TestItemValidator extends ValidatorUtil {
-
-    // annotated fields - each field must have exactly one annotation
-
-    /**
-     * This annotation does not contain a method returning an array.
-     */
-    @Min(value = 0)
-    private int notArray;
-
-    /**
-     * This annotation doesn't contain any annotations that the {@link BeanValidator}
-     * recognizes.
-     */
-    @Simple
-    private int mismatch;
-
-    /**
-     * No annotations.
-     */
-    @SuppressWarnings("unused")
-    private int noAnnotations;
-
-    /**
-     * One matching annotation.
-     */
-    @NotNull
-    private int match;
-
-    /**
-     * Multiple matching annotations.
-     */
-    @NotNull
-    @NotBlank
-    private String multiMatch;
-
-
-    @BeforeEach
-    void setUp() {
-        bean = new BeanValidator();
-    }
-
-    @Test
-    void testGetAnnotation() {
-        // no matches
-        assertThat(new ItemValidator(bean, getAnnotType("noAnnotations"), true).isEmpty()).isTrue();
-
-        // had a match
-        assertThat(new ItemValidator(bean, getAnnotType("match"), true).checkers).hasSize(1);
-
-        // multiple matches
-        ItemValidator validator = new ItemValidator(bean, getAnnotType("multiMatch"), true);
-        assertThat(validator.checkers).hasSize(2);
-
-        BeanValidationResult result = new BeanValidationResult(MY_NAME, this);
-        validator.validateValue(result, MY_FIELD, HELLO);
-        assertThat(result.getResult()).isNull();
-
-        result = new BeanValidationResult(MY_NAME, this);
-        validator.validateValue(result, MY_FIELD, null);
-        assertThat(result.getResult()).isNotNull();
-
-        result = new BeanValidationResult(MY_NAME, this);
-        validator.validateValue(result, MY_FIELD, "");
-        assertThat(result.getResult()).isNotNull();
-    }
-
-    @Test
-    void testItemValidatorBeanValidatorAnnotation() {
-        assertThat(new ItemValidator(bean, getAnnotType("match")).isEmpty()).isFalse();
-    }
-
-    @Test
-    void testItemValidatorBeanValidatorAnnotationBoolean() {
-        assertThat(new ItemValidator(bean, getAnnotType("match"), true).isEmpty()).isFalse();
-
-        assertThat(new ItemValidator(bean, getAnnotType("match"), false).isEmpty()).isTrue();
-    }
-
-    // these annotations are not recognized by the BeanValidator
-
-    @Retention(RUNTIME)
-    @Target(FIELD)
-    public @interface Simple {
-
-    }
-}
diff --git a/policy-common/src/test/java/org/onap/policy/common/parameters/TestValueValidator.java b/policy-common/src/test/java/org/onap/policy/common/parameters/TestValueValidator.java
deleted file mode 100644 (file)
index 1b42876..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * ONAP
- * ================================================================================
- * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
- * Modifications Copyright (C) 2024-2025 Nordix Foundation
- * ================================================================================
- * 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.
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.policy.common.parameters;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.lang.annotation.Annotation;
-import java.util.concurrent.atomic.AtomicBoolean;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.onap.policy.common.parameters.annotations.Min;
-import org.onap.policy.common.parameters.annotations.NotBlank;
-import org.onap.policy.common.parameters.annotations.NotNull;
-
-class TestValueValidator extends ValidatorUtil {
-
-    private ValueValidator validator;
-
-    // these fields just provide place-holders for annotations
-
-    @NotNull
-    @NotBlank
-    private final int annotField = 1;
-
-
-    @BeforeEach
-    void setUp() {
-        validator = new MyValueValidator();
-    }
-
-    @Test
-    void testIsEmpty() {
-        assertThat(validator.isEmpty()).isTrue();
-
-        validator.addAnnotation(NotNull.class, (result2, fieldName, value) -> true);
-        assertThat(validator.isEmpty()).isFalse();
-    }
-
-    @Test
-    void testValidateValue_NullValue() {
-        BeanValidationResult result = new BeanValidationResult(MY_NAME, this);
-
-        validator.validateValue(result, MY_FIELD, null);
-        assertThat(result.getResult()).isNull();
-
-        validator.addAnnotation(NotNull.class, BeanValidationResult::validateNotNull);
-        validator.validateValue(result, MY_FIELD, null);
-        assertThat(result.getResult()).contains(MY_FIELD, "null");
-    }
-
-    @Test
-    void testValidateValue_NotNullValue() {
-        BeanValidationResult result = new BeanValidationResult(MY_NAME, this);
-
-        validator.validateValue(result, MY_FIELD, HELLO);
-        assertThat(result.getResult()).isNull();
-
-        validator.addAnnotation(NotNull.class, BeanValidationResult::validateNotNull);
-        validator.validateValue(result, MY_FIELD, HELLO);
-        assertThat(result.getResult()).isNull();
-    }
-
-    @Test
-    void testAddAnnotationClassOfTChecker() {
-        // the field does not have this annotation
-        validator.addAnnotation(Min.class, (result2, fieldName, value) -> true);
-        assertThat(validator.isEmpty()).isTrue();
-
-        // "null" flag should stay true with this annotation
-        assertThat(validator.isNullAllowed()).isTrue();
-        validator.addAnnotation(NotBlank.class, (result2, fieldName, value) -> true);
-        assertThat(validator.isNullAllowed()).isTrue();
-
-        // "null" flag should become false with this annotation
-        validator.addAnnotation(NotNull.class, (result2, fieldName, value) -> true);
-        assertThat(validator.isNullAllowed()).isFalse();
-    }
-
-    @Test
-    void testAddAnnotationClassOfTCheckerWithAnnotOfT() {
-        // the field does not have this annotation
-        validator.addAnnotation(Min.class, (result2, fieldName, annot, value) -> true);
-        assertThat(validator.isEmpty()).isTrue();
-
-        // indicates the annotation value
-        AtomicBoolean wasNull = new AtomicBoolean(false);
-
-        // the field DOES have this annotation
-        validator.addAnnotation(NotNull.class, (result2, fieldName, annot, value) -> {
-            wasNull.set(annot != null);
-            return result2.validateNotNull(fieldName, value);
-        });
-        assertThat(validator.isEmpty()).isFalse();
-
-        // ensure that the checker is invoked
-        BeanValidationResult result = new BeanValidationResult(MY_NAME, this);
-        validator.validateValue(result, MY_FIELD, HELLO);
-        assertThat(result.getResult()).isNull();
-
-        assertThat(wasNull.get()).isTrue();
-    }
-
-    @Test
-    void testGetAnnotation() {
-        assertThat(new ValueValidator().getAnnotation(NotNull.class)).isNull();
-    }
-
-    /**
-     * Checks for annotations on the "annotField" field.
-     */
-    private static class MyValueValidator extends ValueValidator {
-        @Override
-        public <T extends Annotation> T getAnnotation(Class<T> annotClass) {
-            try {
-                return TestValueValidator.class.getDeclaredField("annotField").getAnnotation(annotClass);
-            } catch (NoSuchFieldException | SecurityException e) {
-                throw new RuntimeException(e);
-            }
-        }
-    }
-}
diff --git a/policy-common/src/test/java/org/onap/policy/common/parameters/ValidatorUtil.java b/policy-common/src/test/java/org/onap/policy/common/parameters/ValidatorUtil.java
deleted file mode 100644 (file)
index e39b5b8..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * ONAP
- * ================================================================================
- * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
- * ================================================================================
- * 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.
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.policy.common.parameters;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.AnnotatedType;
-import java.lang.reflect.Field;
-
-/**
- * Utilities for validator tests.
- */
-public class ValidatorUtil {
-    protected static final String MY_NAME = "My-Name";
-    protected static final String MY_FIELD = "My-Field";
-    protected static final String HELLO = "hello";
-
-    protected BeanValidator bean;
-
-    /**
-     * Gets the single annotation for a given field.
-     *
-     * @param fieldName name of the field having the desired annotation
-     * @return the given field's annotation
-     */
-    protected Annotation getAnnot(String fieldName) {
-        return getField(fieldName).getAnnotations()[0];
-    }
-
-    /**
-     * Gets the annotated type for a given field.
-     *
-     * @param fieldName name of the field of interest
-     * @return the given field's annotated type
-     */
-    protected AnnotatedType getAnnotType(String fieldName) {
-        return getField(fieldName).getAnnotatedType();
-    }
-
-    /**
-     * Gets a field from this object.
-     *
-     * @param fieldName name of the field of interest
-     * @return the given field
-     */
-    protected Field getField(String fieldName) {
-        return getField(getClass(), fieldName);
-    }
-
-    /**
-     * Gets a field from a given class.
-     *
-     * @param clazz class containing the field
-     * @param fieldName name of the field of interest
-     * @return the given field
-     */
-    protected Field getField(Class<?> clazz, String fieldName) {
-        try {
-            return clazz.getDeclaredField(fieldName);
-
-        } catch (NoSuchFieldException | SecurityException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-}
index cda2bbf..2d3255c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2019 Nordix Foundation.
+ *  Copyright (C) 2019-2026 OpenInfra Foundation Europe. All rights reserved.
  *  Modifications Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,12 +23,12 @@ package org.onap.policy.models.base;
 
 import jakarta.persistence.Column;
 import jakarta.persistence.Embeddable;
+import jakarta.validation.constraints.Pattern;
 import java.io.Serial;
 import lombok.EqualsAndHashCode;
 import lombok.Getter;
 import lombok.NonNull;
 import lombok.ToString;
-import org.onap.policy.common.parameters.annotations.Pattern;
 import org.onap.policy.common.utils.validation.Assertions;
 
 /**
diff --git a/policy-models/src/main/java/org/onap/policy/models/base/PfValidator.java b/policy-models/src/main/java/org/onap/policy/models/base/PfValidator.java
deleted file mode 100644 (file)
index 1bd7f50..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * ONAP
- * ================================================================================
- * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights reserved.
- * Modifications Copyright (C) 2023-2024 Nordix Foundation.
- * ================================================================================
- * 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.
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.policy.models.base;
-
-import org.onap.policy.common.parameters.BeanValidationResult;
-import org.onap.policy.common.parameters.BeanValidator;
-import org.onap.policy.common.parameters.ValidationResult;
-import org.onap.policy.common.parameters.ValidationStatus;
-import org.onap.policy.common.parameters.ValueValidator;
-import org.onap.policy.models.base.validation.annotations.VerifyKey;
-
-public class PfValidator extends BeanValidator {
-
-    @Override
-    protected void addValidators(ValueValidator validator) {
-        super.addValidators(validator);
-
-        validator.addAnnotation(VerifyKey.class, this::verKey);
-    }
-
-    /**
-     * Invokes the value's {@link Validated#validate(String) validate()} method, if the
-     * value is of type {@link Validated}.
-     */
-    @Override
-    public boolean verCascade(BeanValidationResult result, String fieldName, Object value) {
-        if (value instanceof Validated validated) {
-            ValidationResult result2 = validated.validate(fieldName);
-            if (result2 == null) {
-                return true;
-            }
-
-            if (!result2.isClean()) {
-                result.addResult(result2);
-            }
-
-            return result2.isValid();
-        }
-
-        return super.verCascade(result, fieldName, value);
-    }
-
-    /**
-     * Validates a key.
-     *
-     * @param result where to add the validation result
-     * @param fieldName name of the field containing the key
-     * @param annot validation annotations for the key
-     * @param value value to be verified
-     * @return {@code true} if the next check should be performed, {@code false} otherwise
-     */
-    public boolean verKey(BeanValidationResult result, String fieldName, VerifyKey annot, Object value) {
-        if (!(value instanceof PfKey pfkey)) {
-            return true;
-        }
-
-        if (annot.keyNotNull() && pfkey.isNullKey()) {
-            result.addResult(fieldName, xlate(pfkey), ValidationStatus.INVALID, Validated.IS_A_NULL_KEY);
-            return false;
-        }
-
-        if (annot.valid()) {
-            verCascade(result, fieldName, value);
-        }
-
-        if (!(pfkey instanceof PfKeyImpl keyimpl)) {
-            return true;
-        }
-
-        var result2 = new BeanValidationResult(fieldName, value);
-
-        if (annot.nameNotNull() && keyimpl.isNullName()) {
-            result2.addResult("name", pfkey.getName(), ValidationStatus.INVALID, Validated.IS_NULL);
-        }
-
-        if (annot.versionNotNull() && keyimpl.isNullVersion()) {
-            result2.addResult("version", pfkey.getVersion(), ValidationStatus.INVALID, Validated.IS_NULL);
-        }
-
-        if (!result2.isClean()) {
-            result.addResult(result2);
-        }
-
-        return result2.isValid();
-    }
-
-    @Override
-    public Object xlate(Object value) {
-        return (value instanceof PfKey pfKey ? pfKey.getId() : value);
-    }
-}
index 333317e..daade23 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2019-2021 AT&T Intellectual Property. All rights reserved.
- *  Modifications Copyright (C) 2024 Nordix Foundation
+ *  Modifications Copyright (C) 2024-2026 OpenInfra Foundation Europe. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -23,100 +23,23 @@ package org.onap.policy.models.base;
 
 import lombok.NonNull;
 import org.onap.policy.common.parameters.BeanValidationResult;
-import org.onap.policy.common.parameters.ObjectValidationResult;
-import org.onap.policy.common.parameters.ValidationResult;
-import org.onap.policy.common.parameters.ValidationStatus;
+import org.onap.policy.common.parameters.BeanValidator;
 
 /**
  * Classes that can be validated. This can be used as a super class or as a stand-alone
  * utility class.
  */
 public class Validated {
-    public static final String IS_A_NULL_KEY = "is a null key";
-    public static final String IS_NULL = "is null";
     public static final String NOT_FOUND = "not found";
-    public static final String KEY_TOKEN = "key";
-    public static final String VALUE_TOKEN = "value";
 
     /**
-     * Validates the fields of the object. The default method uses a {@link PfValidator}
+     * Validates the fields of the object. The default method uses a {@link BeanValidator}
      * to validate the object.
      *
      * @param fieldName name of the field containing this
      * @return the result, or {@code null}
      */
-    public BeanValidationResult validate(@NonNull String fieldName) {
-        return new PfValidator().validateTop(fieldName, this);
-    }
-
-    /**
-     * Adds a result indicating that a value is invalid.
-     *
-     * @param result where to put the result
-     * @param fieldName name of the field containing the value
-     * @param value the field's value
-     * @param errorMessage the error message
-     */
-    public static void addResult(@NonNull BeanValidationResult result, @NonNull String fieldName, Object value,
-                    @NonNull String errorMessage) {
-        result.addResult(fieldName, getKeyId(value), ValidationStatus.INVALID, errorMessage);
-    }
-
-    /**
-     * Makes a result that indicates a value is invalid, because it is null.
-     *
-     * @param fieldName name of the field containing the value
-     * @param value the field's value
-     * @return a result indicating the value is invalid
-     */
-    public static ValidationResult makeNullResult(@NonNull String fieldName, Object value) {
-        return new ObjectValidationResult(fieldName, getKeyId(value), ValidationStatus.INVALID, IS_NULL);
-    }
-
-    /**
-     * Validates a key, ensuring that it isn't null and that it's structurally sound.
-     *
-     * @param result where to add the validation result
-     * @param fieldName name of the field containing the key
-     * @param key the field's value
-     */
-    public static void validateKeyNotNull(BeanValidationResult result, @NonNull String fieldName, PfKey key) {
-        if (key == null) {
-            result.addResult(fieldName, key, ValidationStatus.INVALID, IS_A_NULL_KEY);
-            return;
-        }
-
-        if (key.isNullKey()) {
-            result.addResult(fieldName, key.getId(), ValidationStatus.INVALID, IS_A_NULL_KEY);
-            return;
-        }
-
-        result.addResult(key.validate(fieldName));
-    }
-
-    /**
-     * Validates a key's version, ensuring that it isn't null.
-     *
-     * @param result where to add the validation result
-     * @param fieldName name of the field containing the key
-     * @param key the field's value
-     */
-    public static void validateKeyVersionNotNull(BeanValidationResult result, @NonNull String fieldName,
-                    PfConceptKey key) {
-        if (key != null && key.isNullVersion()) {
-            var result2 = new BeanValidationResult(fieldName, key);
-            result2.addResult(makeNullResult(PfKeyImpl.VERSION_TOKEN, key.getVersion()));
-            result.addResult(result2);
-        }
-    }
-
-    /**
-     * Gets a key's ID, if the value is a {@link PfKey}.
-     *
-     * @param value value from which to get the ID
-     * @return the value's ID, if it's a key, the original value otherwise
-     */
-    private static Object getKeyId(Object value) {
-        return (value instanceof PfKey pfKey ? pfKey.getId() : value);
+    public final BeanValidationResult validate(@NonNull String fieldName) {
+        return BeanValidator.validate(fieldName, this);
     }
 }
index cc8c882..b7e4b41 100644 (file)
@@ -1,8 +1,7 @@
 /*-
  * ============LICENSE_START=======================================================
- * ONAP
- * ================================================================================
  * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
+ * Modifications Copyright (C) 2026 OpenInfra Foundation Europe. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
  * ============LICENSE_END=========================================================
  */
 
 package org.onap.policy.models.base.validation.annotations;
 
 import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
+import jakarta.validation.Constraint;
+import jakarta.validation.Payload;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
 /**
- * Validates a key.
+ * Verifies a key is not a null key. Note @Valid annotation should also be used with this one to fully validate the key.
  */
 @Retention(RUNTIME)
-@Target(FIELD)
+@Target({FIELD, METHOD})
+@Constraint(validatedBy = VerifyKeyValidator.class)
 public @interface VerifyKey {
 
     /**
@@ -49,9 +54,17 @@ public @interface VerifyKey {
     boolean versionNotNull() default false;
 
     /**
-     * Invokes key.validate(), avoiding the need to include the "Valid" annotation. Note:
-     * if this is {@code true}, then the "Valid" annotation should not be specified, as
-     * that would result in duplicate validation checks.
+     * The error message template.
+     */
+    String message() default "Key validation failed";
+
+    /**
+     * The groups the constraint belongs to.
+     */
+    Class<?>[] groups() default {};
+
+    /**
+     * The payload associated to the constraint.
      */
-    boolean valid() default true;
+    Class<? extends Payload>[] payload() default {};
 }
diff --git a/policy-models/src/main/java/org/onap/policy/models/base/validation/annotations/VerifyKeyValidator.java b/policy-models/src/main/java/org/onap/policy/models/base/validation/annotations/VerifyKeyValidator.java
new file mode 100644 (file)
index 0000000..33048d9
--- /dev/null
@@ -0,0 +1,67 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2026 OpenInfra Foundation Europe. All rights reserved.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.models.base.validation.annotations;
+
+import jakarta.validation.ConstraintValidator;
+import jakarta.validation.ConstraintValidatorContext;
+import org.onap.policy.models.base.PfKey;
+import org.onap.policy.models.base.PfKeyImpl;
+
+public class VerifyKeyValidator implements ConstraintValidator<VerifyKey, PfKey> {
+
+    private VerifyKey annotation;
+
+    @Override
+    public void initialize(VerifyKey constraintAnnotation) {
+        this.annotation = constraintAnnotation;
+    }
+
+    @Override
+    public boolean isValid(PfKey pfkey, ConstraintValidatorContext context) {
+        if (pfkey == null) {
+            return true;
+        }
+
+        context.disableDefaultConstraintViolation();
+        boolean valid = true;
+
+        if (annotation.keyNotNull() && pfkey.isNullKey()) {
+            context.buildConstraintViolationWithTemplate("is a null key").addConstraintViolation();
+            return false;
+        }
+
+        if (pfkey instanceof PfKeyImpl keyimpl) {
+            if (annotation.nameNotNull() && keyimpl.isNullName()) {
+                context.buildConstraintViolationWithTemplate("is null")
+                    .addPropertyNode("name").addConstraintViolation();
+                valid = false;
+            }
+
+            if (annotation.versionNotNull() && keyimpl.isNullVersion()) {
+                context.buildConstraintViolationWithTemplate("is null")
+                    .addPropertyNode("version").addConstraintViolation();
+                valid = false;
+            }
+        }
+
+        return valid;
+    }
+}
index df7b5bc..ceb58c7 100644 (file)
@@ -30,6 +30,7 @@ import static org.junit.jupiter.api.Assertions.assertNotEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
+import jakarta.validation.constraints.Pattern;
 import java.lang.reflect.Field;
 import lombok.EqualsAndHashCode;
 import lombok.Getter;
@@ -37,8 +38,8 @@ import lombok.NoArgsConstructor;
 import lombok.Setter;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
+import org.onap.policy.common.parameters.BeanValidator;
 import org.onap.policy.common.parameters.ValidationResult;
-import org.onap.policy.common.parameters.annotations.Pattern;
 import org.onap.policy.models.base.PfKey.Compatibility;
 
 class PfKeyImplTest {
@@ -201,7 +202,7 @@ class PfKeyImplTest {
         nameField.set(testKey, "TheKey");
         nameField.setAccessible(false);
         assertThat(validationResult.getResult()).contains("\"name\"").doesNotContain("\"version\"")
-            .contains("does not match regular expression " + PfKey.NAME_REGEXP);
+            .contains("must match \"" + PfKey.NAME_REGEXP + "\"");
 
         Field versionField = testKey.getClass().getDeclaredField("version");
         versionField.setAccessible(true);
@@ -210,7 +211,7 @@ class PfKeyImplTest {
         versionField.set(testKey, VERSION001);
         versionField.setAccessible(false);
         assertThat(validationResult2.getResult()).doesNotContain("\"name\"").contains("\"version\"")
-            .contains("does not match regular expression " + PfKey.VERSION_REGEXP);
+                .contains("must match \"" + PfKey.VERSION_REGEXP + "\"");
     }
 
     @Getter
diff --git a/policy-models/src/test/java/org/onap/policy/models/base/PfValidatorTest.java b/policy-models/src/test/java/org/onap/policy/models/base/PfValidatorTest.java
deleted file mode 100644 (file)
index 3f0b108..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * ONAP
- * ================================================================================
- * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
- * Modifications Copyright (C) 2023, 2024 Nordix Foundation.
- * ================================================================================
- * 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.
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.policy.models.base;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import jakarta.validation.Valid;
-import java.io.Serial;
-import java.util.concurrent.atomic.AtomicBoolean;
-import lombok.Getter;
-import lombok.NonNull;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.onap.policy.common.parameters.BeanValidationResult;
-import org.onap.policy.common.parameters.annotations.NotNull;
-import org.onap.policy.common.utils.coder.CoderException;
-import org.onap.policy.common.utils.coder.StandardCoder;
-import org.onap.policy.models.base.validation.annotations.VerifyKey;
-
-class PfValidatorTest {
-    private static final String KEY_FIELD = "key";
-
-    private static final String STRING_VALUE = "abc";
-
-    private PfValidator validator;
-
-    @BeforeEach
-    void setUp() {
-        validator = new PfValidator();
-    }
-
-    @Test
-    void testAddValidatorsValueValidator() {
-        // verify that standard annotations work
-        StdAnnotation data = new StdAnnotation();
-        data.strValue = STRING_VALUE;
-        assertThat(validator.validateTop("", data).getResult()).isNull();
-
-        data.strValue = null;
-        assertThat(validator.validateTop("", data).getResult()).contains("strValue", "null");
-    }
-
-    @Test
-    void testVerCascadeBeanValidationResultStringObject() {
-        CascadeChecker checker = new CascadeChecker();
-        checker.plain = new StdAnnotation();
-
-        // valid
-        checker.plain.strValue = STRING_VALUE;
-        BeanValidationResult result = new BeanValidationResult("", this);
-        assertThat(validator.verCascade(result, "", checker)).isTrue();
-
-        // invalid
-        checker.plain.strValue = null;
-
-        result = new BeanValidationResult("", this);
-        assertThat(validator.verCascade(result, "", checker.plain)).isFalse();
-        assertThat(result.getResult()).contains("null");
-
-        result = new BeanValidationResult("", this);
-        assertThat(validator.verCascade(result, "", checker)).isFalse();
-        assertThat(result.getResult()).contains("null").doesNotContain("plain");
-
-        // validator returns null result - should be treated as valid
-        checker = new CascadeChecker() {
-            @Override
-            public BeanValidationResult validate(@NonNull String fieldName) {
-                return null;
-            }
-        };
-        checker.plain = new StdAnnotation();
-        result = new BeanValidationResult("", this);
-        assertThat(validator.verCascade(result, "", checker)).isTrue();
-    }
-
-    @Test
-    void testVerKey() throws CoderException {
-        FullKeyAnnot data = new FullKeyAnnot();
-
-        // not a key
-        data.key = STRING_VALUE;
-        assertThat(validator.validateTop("", data).getResult()).isNull();
-
-        // null key
-        data.key = new PfConceptKey();
-        assertThat(validator.validateTop("", data).getResult())
-            .contains(KEY_FIELD, "NULL:0.0.0", Validated.IS_A_NULL_KEY).doesNotContain("name", "version");
-
-        // invalid version - should invoke verCascade() which will invoke key.validate()
-        data.key = new StandardCoder().decode("{'name':'abc', 'version':'xyzzy'}".replace('\'', '"'),
-            PfConceptKey.class);
-        assertThat(validator.validateTop("", data).getResult())
-            .contains(KEY_FIELD, "version", "xyzzy", "regular expression").doesNotContain("name");
-
-        // not a PfKeyImpl - should not check individual fields
-        PfKey pfkey = mock(PfKey.class);
-        data.key = pfkey;
-        assertThat(validator.validateTop("", data).getResult()).isNull();
-
-        when(pfkey.isNullKey()).thenReturn(true);
-        assertThat(validator.validateTop("", data).getResult()).contains(KEY_FIELD, Validated.IS_A_NULL_KEY);
-
-        // null name
-        data.key = new PfConceptKey(PfKey.NULL_KEY_NAME, "2.3.4");
-        assertThat(validator.validateTop("", data).getResult()).contains(KEY_FIELD, "name", "null")
-            .doesNotContain("version", "2.3.4");
-
-        // null version
-        data.key = new PfConceptKey(STRING_VALUE, PfKey.NULL_KEY_VERSION);
-        assertThat(validator.validateTop("", data).getResult()).contains(KEY_FIELD, "version", "null")
-            .doesNotContain("name", STRING_VALUE);
-
-        // null name, invalid version - should get two messages
-        data.key = new StandardCoder().decode("{'name':'NULL', 'version':'xyzzy'}".replace('\'', '"'),
-            PfConceptKey.class);
-        assertThat(validator.validateTop("", data).getResult()).contains(KEY_FIELD, "name", "null", "version", "xyzzy",
-            "regular expression");
-
-        /*
-         * Tests with all flags set to "false" (i.e., no validations).
-         */
-
-        EmptyKeyAnnot data2 = new EmptyKeyAnnot();
-
-        // build a key that is totally invalid
-        AtomicBoolean called = new AtomicBoolean();
-
-        data2.key = new PfConceptKey() {
-            @Serial
-            private static final long serialVersionUID = 1L;
-
-            @Override
-            public BeanValidationResult validate(@NonNull String fieldName) {
-                called.set(true);
-                return null;
-            }
-        };
-
-        // should be ok, since no validations are performed
-        assertThat(validator.validateTop("", data2).getResult()).isNull();
-        assertThat(called.get()).isFalse();
-    }
-
-    @Test
-    void testXlateObject() {
-        assertThat(validator.xlate(null)).isNull();
-        assertThat(validator.xlate("hello")).isEqualTo("hello");
-
-        PfConceptKey key = new PfConceptKey("hello", "1.2.3");
-        assertThat(validator.xlate(key)).isEqualTo("hello:1.2.3");
-    }
-
-    public static class StdAnnotation {
-        @Getter
-        @NotNull
-        private String strValue;
-    }
-
-    public static class CascadeChecker extends Validated {
-        @Getter
-        @Valid
-        private StdAnnotation plain;
-
-        @Override
-        public BeanValidationResult validate(@NonNull String fieldName) {
-            // directly validates "plain"
-            return new PfValidator().validateTop(fieldName, plain);
-        }
-    }
-
-    public static class FullKeyAnnot {
-        @Getter
-        @VerifyKey(keyNotNull = true, nameNotNull = true, versionNotNull = true, valid = true)
-        private Object key;
-    }
-
-    public static class EmptyKeyAnnot {
-        @Getter
-        @VerifyKey(keyNotNull = false, nameNotNull = false, versionNotNull = false, valid = false)
-        private PfKey key;
-    }
-}
diff --git a/policy-models/src/test/java/org/onap/policy/models/base/ValidatedTest.java b/policy-models/src/test/java/org/onap/policy/models/base/ValidatedTest.java
deleted file mode 100644 (file)
index 6d12614..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * ONAP
- * ================================================================================
- * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights reserved.
- * Modifications Copyright (C) 2024 Nordix Foundation
- * ================================================================================
- * 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.
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.policy.models.base;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatCode;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-
-import lombok.AllArgsConstructor;
-import lombok.NonNull;
-import org.junit.jupiter.api.Test;
-import org.onap.policy.common.parameters.BeanValidationResult;
-import org.onap.policy.common.parameters.ValidationResult;
-import org.onap.policy.common.parameters.ValidationStatus;
-import org.onap.policy.common.utils.coder.CoderException;
-import org.onap.policy.common.utils.coder.StandardCoder;
-
-class ValidatedTest {
-    private static final @NonNull String MY_FIELD = "myField";
-    private static final @NonNull String Q_KEY = "\"" + Validated.KEY_TOKEN + "\"";
-    private static final @NonNull String Q_VALUE = "\"" + Validated.VALUE_TOKEN + "\"";
-    private static final String NOT_SAME = "not same";
-    private static final String TEXT = "some text";
-    private static final String OTHER = "other text";
-    private static final String NAME = "myKey";
-    private static final String VERSION = "1.0.0";
-
-    @Test
-    void testAddResult() {
-        BeanValidationResult result = new BeanValidationResult("", this);
-        Validated.addResult(result, MY_FIELD, TEXT, "some message");
-        assertThat(result.getResult()).contains(MY_FIELD).contains(TEXT).contains("some message");
-
-        assertThatThrownBy(() -> Validated.addResult(null, MY_FIELD, TEXT, OTHER))
-                        .isInstanceOf(NullPointerException.class);
-
-        assertThatThrownBy(() -> Validated.addResult(result, null, TEXT, OTHER))
-                        .isInstanceOf(NullPointerException.class);
-
-        assertThatCode(() -> Validated.addResult(result, MY_FIELD, null, OTHER)).doesNotThrowAnyException();
-
-        assertThatThrownBy(() -> Validated.addResult(result, MY_FIELD, TEXT, null))
-                        .isInstanceOf(NullPointerException.class);
-    }
-
-    @Test
-    void testMakeNullResult() {
-        ValidationResult rnull = Validated.makeNullResult(MY_FIELD, TEXT);
-        assertEquals(MY_FIELD, rnull.getName());
-        assertThat(rnull.getResult()).contains(MY_FIELD).contains(TEXT).contains(Validated.IS_NULL);
-        assertFalse(rnull.isValid());
-
-        assertThatThrownBy(() -> Validated.makeNullResult(null, TEXT)).isInstanceOf(NullPointerException.class);
-
-        assertThatCode(() -> Validated.makeNullResult(MY_FIELD, null)).doesNotThrowAnyException();
-    }
-
-    @Test
-    void testValidateKeyNotNull() throws CoderException {
-        BeanValidationResult result = new BeanValidationResult("", this);
-        Validated.validateKeyNotNull(result, MY_FIELD, new PfConceptKey(NAME, VERSION));
-        assertThat(result.getResult()).isNull();
-
-        result = new BeanValidationResult("", this);
-        Validated.validateKeyNotNull(result, MY_FIELD, new PfConceptKey(NAME, PfConceptKey.NULL_KEY_VERSION));
-        assertThat(result.getResult()).isNull();
-
-        result = new BeanValidationResult("", this);
-        Validated.validateKeyNotNull(result, MY_FIELD, new PfConceptKey(PfConceptKey.NULL_KEY_NAME, VERSION));
-        assertThat(result.getResult()).isNull();
-
-        // key is null
-        result = new BeanValidationResult("", this);
-        Validated.validateKeyNotNull(result, MY_FIELD, new PfConceptKey());
-        assertThat(result.getResult()).contains(MY_FIELD, Validated.IS_A_NULL_KEY)
-                        .doesNotContain("\"name\"", "\"version\"");
-
-        /*
-         * Key is not null, but key.validate() should fail due to an invalid version.
-         * Note: have to create the key by decoding from json, as the class will prevent
-         * an invalid version from being assigned.
-         */
-        PfConceptKey key = new StandardCoder().decode("{'name':'myKey','version':'bogus'}".replace('\'', '"'),
-                        PfConceptKey.class);
-        result = new BeanValidationResult("", this);
-        Validated.validateKeyNotNull(result, MY_FIELD, key);
-        assertThat(result.getResult()).contains(MY_FIELD, "version", "does not match regular expression");
-
-        BeanValidationResult result2 = new BeanValidationResult("", this);
-
-        // null parameter tests
-        PfConceptKey conceptKey = new PfConceptKey();
-        assertThatThrownBy(() -> Validated.validateKeyNotNull(result2, null, conceptKey))
-                        .isInstanceOf(NullPointerException.class);
-
-        assertThatCode(() -> Validated.validateKeyNotNull(result2, MY_FIELD, null)).doesNotThrowAnyException();
-    }
-
-    @Test
-    void testValidateKeyVersionNotNull() {
-        BeanValidationResult result = new BeanValidationResult("", this);
-        Validated.validateKeyVersionNotNull(result, MY_FIELD, null);
-        assertThat(result.getResult()).isNull();
-
-        result = new BeanValidationResult("", this);
-        Validated.validateKeyVersionNotNull(result, MY_FIELD, new PfConceptKey(NAME, VERSION));
-        assertThat(result.getResult()).isNull();
-
-        result = new BeanValidationResult("", this);
-        Validated.validateKeyVersionNotNull(result, MY_FIELD, new PfConceptKey(NAME, PfConceptKey.NULL_KEY_VERSION));
-        assertThat(result.getResult()).contains(MY_FIELD).contains("version").contains(Validated.IS_NULL);
-
-        BeanValidationResult result2 = new BeanValidationResult("", this);
-        PfConceptKey conceptKey = new PfConceptKey();
-        assertThatThrownBy(() -> Validated.validateKeyVersionNotNull(result2, null, conceptKey))
-                        .isInstanceOf(NullPointerException.class);
-
-        assertThatCode(() -> Validated.validateKeyVersionNotNull(result2, MY_FIELD, null)).doesNotThrowAnyException();
-    }
-
-    @Test
-    void testGetKeyId() {
-        // not a key field - should just use the given value
-        BeanValidationResult result = new BeanValidationResult("", this);
-        Validated.addResult(result, MY_FIELD, TEXT, "some message");
-        assertThat(result.getResult()).contains(MY_FIELD).contains(TEXT).contains("some message");
-
-        // repeat with a key field - should use the key's ID
-        result = new BeanValidationResult("", this);
-        Validated.addResult(result, MY_FIELD, new PfConceptKey(NAME, VERSION), "some message");
-        assertThat(result.getResult()).contains(MY_FIELD).contains("myKey:1.0.0").contains("some message");
-    }
-
-    @AllArgsConstructor
-    private static class MyString extends Validated {
-        private final String text;
-
-        @Override
-        public BeanValidationResult validate(String fieldName) {
-            if (TEXT.equals(text)) {
-                return null;
-            }
-
-            BeanValidationResult result = new BeanValidationResult(fieldName, this);
-            result.addResult(fieldName, text, ValidationStatus.INVALID, NOT_SAME);
-            return result;
-        }
-    }
-}
diff --git a/policy-models/src/test/java/org/onap/policy/models/base/validation/annotations/VerifyKeyValidatorTest.java b/policy-models/src/test/java/org/onap/policy/models/base/validation/annotations/VerifyKeyValidatorTest.java
new file mode 100644 (file)
index 0000000..a39455a
--- /dev/null
@@ -0,0 +1,140 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2026 OpenInfra Foundation Europe. All rights reserved.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.models.base.validation.annotations;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotNull;
+import lombok.Getter;
+import org.junit.jupiter.api.Test;
+import org.onap.policy.common.parameters.BeanValidator;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.models.base.PfConceptKey;
+import org.onap.policy.models.base.PfKey;
+
+class VerifyKeyValidatorTest {
+    private static final String IS_A_NULL_KEY = "is a null key";
+    private static final String IS_NULL = "is null";
+    private static final String KEY_FIELD = "key";
+    private static final String STRING_VALUE = "abc";
+
+    @Test
+    void testStandardAnnotation() {
+        StdAnnotation data = new StdAnnotation();
+        data.strValue = STRING_VALUE;
+        assertThat(BeanValidator.validate("", data).getResult()).isNull();
+
+        data.strValue = null;
+        assertThat(BeanValidator.validate("", data).getResult()).contains("strValue", "null");
+    }
+
+    @Test
+    void testVerifyKey() throws CoderException {
+        FullKeyAnnot data = new FullKeyAnnot();
+
+        // null key - Jakarta validation will include all constraint violations
+        data.key = new PfConceptKey();
+        assertThat(BeanValidator.validate("", data).getResult())
+            .contains(KEY_FIELD, IS_A_NULL_KEY);
+
+        // invalid version - should invoke cascade validation
+        data.key = new StandardCoder().decode("{'name':'abc', 'version':'xyzzy'}".replace('\'', '"'),
+            PfConceptKey.class);
+        assertThat(BeanValidator.validate("", data).getResult())
+            .contains(KEY_FIELD, "version", "xyzzy", "must match");
+
+        // null name
+        data.key = new PfConceptKey(PfKey.NULL_KEY_NAME, "2.3.4");
+        assertThat(BeanValidator.validate("", data).getResult()).contains(KEY_FIELD, "name", IS_NULL);
+
+        // null version
+        data.key = new PfConceptKey(STRING_VALUE, PfKey.NULL_KEY_VERSION);
+        assertThat(BeanValidator.validate("", data).getResult()).contains(KEY_FIELD, "version", IS_NULL);
+
+        // null name, invalid version - should get two messages
+        data.key = new StandardCoder().decode("{'name':'NULL', 'version':'xyzzy'}".replace('\'', '"'),
+            PfConceptKey.class);
+        assertThat(BeanValidator.validate("", data).getResult())
+            .contains(KEY_FIELD, "name", IS_NULL, "version", "xyzzy", "must match");
+    }
+
+    @Test
+    void testEmptyKeyAnnotation() {
+        EmptyKeyAnnot data = new EmptyKeyAnnot();
+        data.key = new PfConceptKey(); // totally invalid key
+
+        // should be ok, since no validations are performed
+        assertThat(BeanValidator.validate("", data).getResult()).isNull();
+    }
+
+    @Test
+    void testVerifyKeyOnGetters() {
+        GetterKeyAnnot data = new GetterKeyAnnot();
+
+        var result = BeanValidator.validate("", data);
+        assertThat(result.getResult())
+                .contains("nullKey", IS_A_NULL_KEY)
+                .contains("nullVersionKey", "version", IS_NULL)
+                .doesNotContain("validKey");
+    }
+
+    public static class StdAnnotation {
+        @Getter
+        @NotNull
+        private String strValue;
+    }
+
+    public static class FullKeyAnnot {
+        @Getter
+        @Valid
+        @VerifyKey(keyNotNull = true, nameNotNull = true, versionNotNull = true)
+        private PfKey key;
+    }
+
+    public static class EmptyKeyAnnot {
+        @Getter
+        @Valid
+        @VerifyKey(keyNotNull = false, nameNotNull = false, versionNotNull = false)
+        private PfKey key;
+    }
+
+    public static class GetterKeyAnnot {
+        @Valid
+        @VerifyKey(versionNotNull = true)
+        public PfConceptKey getValidKey() {
+            return new PfConceptKey("validName", "1.0.0");
+        }
+
+        @Valid
+        @VerifyKey(versionNotNull = true)
+        public PfConceptKey getNullKey() {
+            return new PfConceptKey(PfKey.NULL_KEY_NAME, PfKey.NULL_KEY_VERSION);
+        }
+
+        @Valid
+        @VerifyKey(versionNotNull = true)
+        public PfConceptKey getNullVersionKey() {
+            return new PfConceptKey("validName", PfKey.NULL_KEY_VERSION);
+        }
+    }
+}