diff options
author | Jim Hahn <jrh3@att.com> | 2021-01-06 11:15:45 -0500 |
---|---|---|
committer | Jim Hahn <jrh3@att.com> | 2021-01-06 13:04:34 -0500 |
commit | 8208cc4b1d8855eee3fe59c7a832abccb2a67ed7 (patch) | |
tree | 13676da07d974013935ed2980f7b08a7917bf0c3 /common-parameters/src/test | |
parent | f9add40e0d87baff4ed56529bc61c31a577dc93d (diff) |
Support annotations on parameterized types
It appears that java.validation allows validation annotations to be used
on the type parameters of Collection and Map classes. Updated the
validation code to support that. Once policy-models has been updated to
use this approach, the original @Items and @Entries annotations will be
deprecated.
Issue-ID: POLICY-2648
Change-Id: Ic953be485ebafc9869f72407518f6549585353c9
Signed-off-by: Jim Hahn <jrh3@att.com>
Diffstat (limited to 'common-parameters/src/test')
4 files changed, 257 insertions, 5 deletions
diff --git a/common-parameters/src/test/java/org/onap/policy/common/parameters/TestBeanValidator.java b/common-parameters/src/test/java/org/onap/policy/common/parameters/TestBeanValidator.java index 5d539260..00ed972c 100644 --- a/common-parameters/src/test/java/org/onap/policy/common/parameters/TestBeanValidator.java +++ b/common-parameters/src/test/java/org/onap/policy/common/parameters/TestBeanValidator.java @@ -23,6 +23,7 @@ package org.onap.policy.common.parameters; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertTrue; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; @@ -30,7 +31,6 @@ import java.util.function.Consumer; import lombok.Getter; import org.junit.Before; import org.junit.Test; -import org.onap.policy.common.parameters.annotations.Entries; import org.onap.policy.common.parameters.annotations.Items; import org.onap.policy.common.parameters.annotations.Max; import org.onap.policy.common.parameters.annotations.Min; @@ -489,11 +489,10 @@ public class TestBeanValidator { public void testVerMap() { @Getter class Container { - @Entries(key = @Items(), value = @Items(min = {@Min(5)})) - Map<String, Integer> items; + Map<String, @Min(5) Integer> items; - // not a map - should not be checked - @Entries(key = @Items(), value = @Items(min = {@Min(5)})) + // not a map + @NotBlank String strValue; String noAnnotations; @@ -521,6 +520,26 @@ public class TestBeanValidator { assertTrue(validator.validateTop(TOP, cont).isValid()); } + @Test + public void testGetEntryName() { + assertThat(validator.getEntryName(makeEntry(null, 0))).isEmpty(); + assertThat(validator.getEntryName(makeEntry("", 0))).isEmpty(); + assertThat(validator.getEntryName(makeEntry(STRING_VALUE, 0))).isEqualTo(STRING_VALUE); + } + + /** + * Makes a Map entry with the given key and value. + * + * @param key desired key + * @param value desired value + * @return a new Map entry + */ + private Map.Entry<String, Integer> makeEntry(String key, int value) { + HashMap<String, Integer> map = new HashMap<>(); + map.put(key, value); + return map.entrySet().iterator().next(); + } + private <T> void assertNumeric(String testName, T object, Consumer<Integer> setter, String fieldName, String expectedText, int inside, int edge, int outside) { setter.accept(inside); diff --git a/common-parameters/src/test/java/org/onap/policy/common/parameters/TestFieldValidator.java b/common-parameters/src/test/java/org/onap/policy/common/parameters/TestFieldValidator.java index e4432c8d..29b4b0e3 100644 --- a/common-parameters/src/test/java/org/onap/policy/common/parameters/TestFieldValidator.java +++ b/common-parameters/src/test/java/org/onap/policy/common/parameters/TestFieldValidator.java @@ -25,13 +25,18 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; +import java.util.List; +import java.util.Map; import lombok.Getter; import org.junit.Before; import org.junit.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; public 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; @@ -44,6 +49,24 @@ public class TestFieldValidator extends ValidatorUtil { @Getter private int intValue; + @Getter + private List<@Min(1) Integer> intList; + + @Getter + private Map<@NotBlank String, @Min(1) Integer> intMap; + + @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; @@ -153,6 +176,52 @@ public class TestFieldValidator extends ValidatorUtil { } @Test + public 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 + public 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("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("\" \"", "-10"); + } + + @Test public void testValidateField_testGetValue() { // unannotated BeanValidationResult result = new BeanValidationResult(MY_NAME, this); @@ -180,6 +249,38 @@ public class TestFieldValidator extends ValidatorUtil { } @Test + public 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 + public 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 public void testClassOnly() { // class-level annotation has no bearing on a static field assertThat(new FieldValidator(bean, ClassAnnot.class, getField(ClassAnnot.class, "staticValue")).isEmpty()) diff --git a/common-parameters/src/test/java/org/onap/policy/common/parameters/TestItem2Validator.java b/common-parameters/src/test/java/org/onap/policy/common/parameters/TestItem2Validator.java new file mode 100644 index 00000000..f8d38642 --- /dev/null +++ b/common-parameters/src/test/java/org/onap/policy/common/parameters/TestItem2Validator.java @@ -0,0 +1,121 @@ +/*- + * ============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 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.Before; +import org.junit.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; + +public class TestItem2Validator 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; + + + @Before + public void setUp() { + bean = new BeanValidator(); + } + + @Test + public void testGetAnnotation() { + // no matches + assertThat(new Item2Validator(bean, getAnnotType("noAnnotations"), true).isEmpty()).isTrue(); + + // had a match + assertThat(new Item2Validator(bean, getAnnotType("match"), true).checkers).hasSize(1); + + // multiple matches + Item2Validator validator = new Item2Validator(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 + public void testItem2ValidatorBeanValidatorAnnotation() { + assertThat(new Item2Validator(bean, getAnnotType("match")).isEmpty()).isFalse(); + } + + @Test + public void testItem2ValidatorBeanValidatorAnnotationBoolean() { + assertThat(new Item2Validator(bean, getAnnotType("match"), true).isEmpty()).isFalse(); + + assertThat(new Item2Validator(bean, getAnnotType("match"), false).isEmpty()).isTrue(); + } + + // these annotations are not recognized by the BeanValidator + + @Retention(RUNTIME) + @Target(FIELD) + public @interface Simple { + + } +} diff --git a/common-parameters/src/test/java/org/onap/policy/common/parameters/ValidatorUtil.java b/common-parameters/src/test/java/org/onap/policy/common/parameters/ValidatorUtil.java index 4df014f7..e39b5b86 100644 --- a/common-parameters/src/test/java/org/onap/policy/common/parameters/ValidatorUtil.java +++ b/common-parameters/src/test/java/org/onap/policy/common/parameters/ValidatorUtil.java @@ -21,6 +21,7 @@ package org.onap.policy.common.parameters; import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedType; import java.lang.reflect.Field; /** @@ -44,6 +45,16 @@ public class ValidatorUtil { } /** + * 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 |