diff --git a/nrich-validation-api/src/main/java/net/croz/nrich/validation/api/constraint/DisableConstraints.java b/nrich-validation-api/src/main/java/net/croz/nrich/validation/api/constraint/DisableConstraints.java new file mode 100644 index 00000000..93889e12 --- /dev/null +++ b/nrich-validation-api/src/main/java/net/croz/nrich/validation/api/constraint/DisableConstraints.java @@ -0,0 +1,69 @@ +/* + * Copyright 2020-2023 CROZ d.o.o, the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package net.croz.nrich.validation.api.constraint; + +import jakarta.validation.Payload; +import java.lang.annotation.Annotation; +import java.lang.annotation.Documented; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE_USE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Adds support for disabling constraints. Constraints can be disabled either on property, method or type level. + */ +@SuppressWarnings("unused") +@Target({ METHOD, FIELD, ANNOTATION_TYPE, TYPE_USE }) +@Retention(RUNTIME) +@Repeatable(DisableConstraints.List.class) +@Documented +public @interface DisableConstraints { + + /** + * Array of constraint types to disable. + * @return array of constraint types to disable + */ + Class[] value(); + + /** + * Property name for which to disable constraints (only applicable on type). + * @return property name for which to disable constraints + */ + String propertyName() default ""; + + Class[] payload() default {}; + + /** + * Defines several {@link DisableConstraints} annotations on the same element. + * + * @see DisableConstraints + */ + @Target({ METHOD, FIELD, ANNOTATION_TYPE, TYPE_USE }) + @Retention(RUNTIME) + @Documented + @interface List { + + DisableConstraints[] value(); + } +} diff --git a/nrich-validation/README.md b/nrich-validation/README.md index e1792c5a..6c337bc0 100644 --- a/nrich-validation/README.md +++ b/nrich-validation/README.md @@ -367,3 +367,65 @@ public class ExampleRequest { ``` Above request will require that the date property is before the end of the day + +Module also adds support for disabling inherited constraints with the following annotation: + +#### DisableConstraints + +Assuming the following parent class: + +```java + +@Setter +@Getter +public class ExampleParentRequest { + + @Size(max = 200) + @NotBlank + private String name; + + @NotNull + private Integer age; + +} + + +``` + +Constraints on name and age can be disabled by either using type annotation (if property name or constraint is not found it will just be ignored): + +```java + +@DisableConstraints(value = { NotBlank.class, Size.class }, propertyName = "name") +@DisableConstraints(value = NotNull.class, propertyName = "age") +@Setter +@Getter +public class ExampleTypeRequest extends ExampleParentRequest { + + +} + + +``` + +or by using method/property annotation: + +```java + +public class ExampleMethodRequest extends ExampleParentRequest { + + @DisableConstraints({ NotBlank.class, Size.class }) + @Override + public String getName() { + return super.getName(); + } + + @DisableConstraints(NotNull.class) + @Override + public Integer getAge() { + return super.getAge(); + } +} + + +``` diff --git a/nrich-validation/src/main/java/net/croz/nrich/validation/constraint/support/disableconstraints/BeanDescriptorAdapter.java b/nrich-validation/src/main/java/net/croz/nrich/validation/constraint/support/disableconstraints/BeanDescriptorAdapter.java new file mode 100644 index 00000000..c1405b57 --- /dev/null +++ b/nrich-validation/src/main/java/net/croz/nrich/validation/constraint/support/disableconstraints/BeanDescriptorAdapter.java @@ -0,0 +1,103 @@ +/* + * Copyright 2020-2023 CROZ d.o.o, the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package net.croz.nrich.validation.constraint.support.disableconstraints; + +import lombok.RequiredArgsConstructor; + +import jakarta.validation.metadata.BeanDescriptor; +import jakarta.validation.metadata.ConstraintDescriptor; +import jakarta.validation.metadata.ConstructorDescriptor; +import jakarta.validation.metadata.MethodDescriptor; +import jakarta.validation.metadata.MethodType; +import jakarta.validation.metadata.PropertyDescriptor; +import java.lang.annotation.Annotation; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +public class BeanDescriptorAdapter implements BeanDescriptor { + + private final BeanDescriptor target; + + private final Map>> disabledConstraintsPathMap; + + @Override + public PropertyDescriptor getConstraintsForProperty(String propertyName) { + String path = PathUtil.getPath(target.getElementClass(), propertyName); + + return new PropertyDescriptorAdapter(target.getConstraintsForProperty(propertyName), disabledConstraintsPathMap.getOrDefault(path, Collections.emptyList())); + } + + @Override + public Set getConstrainedProperties() { + return target.getConstrainedProperties().stream() + .map(propertyDescriptor -> getConstraintsForProperty(propertyDescriptor.getPropertyName())) + .collect(Collectors.toSet()); + } + + @Override + public ConstraintFinder findConstraints() { + ConstraintFinder finder = target.findConstraints(); + String path = PathUtil.getPath(target.getElementClass(), null); + + return new ConstraintFinderAdapter(finder, disabledConstraintsPathMap.getOrDefault(path, Collections.emptyList())); + } + + @Override + public boolean isBeanConstrained() { + return target.isBeanConstrained(); + } + + @Override + public MethodDescriptor getConstraintsForMethod(String methodName, Class... parameterTypes) { + return target.getConstraintsForMethod(methodName, parameterTypes); + } + + @Override + public Set getConstrainedMethods(MethodType methodType, MethodType... methodTypes) { + return target.getConstrainedMethods(methodType, methodTypes); + } + + @Override + public ConstructorDescriptor getConstraintsForConstructor(Class... parameterTypes) { + return target.getConstraintsForConstructor(parameterTypes); + } + + @Override + public Set getConstrainedConstructors() { + return target.getConstrainedConstructors(); + } + + @Override + public boolean hasConstraints() { + return target.hasConstraints(); + } + + @Override + public Class getElementClass() { + return target.getElementClass(); + } + + @Override + public Set> getConstraintDescriptors() { + return target.getConstraintDescriptors(); + } +} diff --git a/nrich-validation/src/main/java/net/croz/nrich/validation/constraint/support/disableconstraints/ConstraintFinderAdapter.java b/nrich-validation/src/main/java/net/croz/nrich/validation/constraint/support/disableconstraints/ConstraintFinderAdapter.java new file mode 100644 index 00000000..6ef89f08 --- /dev/null +++ b/nrich-validation/src/main/java/net/croz/nrich/validation/constraint/support/disableconstraints/ConstraintFinderAdapter.java @@ -0,0 +1,71 @@ +/* + * Copyright 2020-2023 CROZ d.o.o, the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package net.croz.nrich.validation.constraint.support.disableconstraints; + +import lombok.RequiredArgsConstructor; + +import jakarta.validation.metadata.ConstraintDescriptor; +import jakarta.validation.metadata.ElementDescriptor; +import jakarta.validation.metadata.Scope; +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +public class ConstraintFinderAdapter implements ElementDescriptor.ConstraintFinder { + + private final ElementDescriptor.ConstraintFinder target; + + private final List> disabledConstraintTypes; + + @Override + public Set> getConstraintDescriptors() { + Set> constraintDescriptors = target.getConstraintDescriptors(); + + return constraintDescriptors.stream().filter(constraintDescriptor -> !disabledConstraintTypes.contains(constraintDescriptor.getAnnotation().annotationType())) + .collect(Collectors.toSet()); + } + + @Override + public ElementDescriptor.ConstraintFinder unorderedAndMatchingGroups(Class... groups) { + target.unorderedAndMatchingGroups(groups); + + return this; + } + + @Override + public ElementDescriptor.ConstraintFinder lookingAt(Scope scope) { + target.lookingAt(scope); + + return this; + } + + @Override + public ElementDescriptor.ConstraintFinder declaredOn(ElementType... types) { + target.declaredOn(types); + + return this; + } + + @Override + public boolean hasConstraints() { + return target.hasConstraints(); + } +} diff --git a/nrich-validation/src/main/java/net/croz/nrich/validation/constraint/support/disableconstraints/DisableConstraintsAnnotationProcessor.java b/nrich-validation/src/main/java/net/croz/nrich/validation/constraint/support/disableconstraints/DisableConstraintsAnnotationProcessor.java new file mode 100644 index 00000000..2e790472 --- /dev/null +++ b/nrich-validation/src/main/java/net/croz/nrich/validation/constraint/support/disableconstraints/DisableConstraintsAnnotationProcessor.java @@ -0,0 +1,82 @@ +/* + * Copyright 2020-2023 CROZ d.o.o, the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package net.croz.nrich.validation.constraint.support.disableconstraints; + +import net.croz.nrich.validation.api.constraint.DisableConstraints; +import org.springframework.util.ReflectionUtils; +import org.springframework.util.StringUtils; + +import java.lang.annotation.Annotation; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class DisableConstraintsAnnotationProcessor { + + private static final Pattern GETTER_METHOD_PATTERN = Pattern.compile("^(get|is)([A-Z].*)$"); + + private final ConcurrentMap, Map>>> disableConstraintsHolderMap = new ConcurrentHashMap<>(); + + public Map>> getDisabledConstraintForType(Class type) { + return disableConstraintsHolderMap.computeIfAbsent(type, this::createDisableConstraintsPathMap); + } + + private Map>> createDisableConstraintsPathMap(Class type) { + Map>> pathHolderMap = new HashMap<>(); + + ReflectionUtils.doWithFields(type, field -> { + DisableConstraints[] disableConstraints = field.getAnnotationsByType(DisableConstraints.class); + + registerDisableConstraints(pathHolderMap, disableConstraints, PathUtil.getPath(type, field.getName()), false); + }); + + ReflectionUtils.doWithMethods(type, method -> { + DisableConstraints[] disableConstraints = method.getAnnotationsByType(DisableConstraints.class); + Matcher matcher = GETTER_METHOD_PATTERN.matcher(method.getName()); + + if (matcher.matches()) { + String propertyName = StringUtils.uncapitalize(matcher.group(2)); + + registerDisableConstraints(pathHolderMap, disableConstraints, PathUtil.getPath(type, propertyName), false); + } + }); + + DisableConstraints[] disableConstraints = type.getAnnotationsByType(DisableConstraints.class); + + registerDisableConstraints(pathHolderMap, disableConstraints, PathUtil.getPath(type, null), true); + + return pathHolderMap; + } + + private void registerDisableConstraints(Map>> pathHolderMap, DisableConstraints[] disableConstraints, String path, boolean isTypeAnnotation) { + Arrays.stream(disableConstraints).forEach(disableConstraint -> { + if (StringUtils.hasText(disableConstraint.propertyName()) && !isTypeAnnotation) { + throw new IllegalArgumentException("Property name not allowed on method or property annotation."); + } + + String fullPath = PathUtil.getPath(path, disableConstraint.propertyName()); + + pathHolderMap.put(fullPath, List.of(disableConstraint.value())); + }); + } +} diff --git a/nrich-validation/src/main/java/net/croz/nrich/validation/constraint/support/disableconstraints/HibernateValidatorAdapter.java b/nrich-validation/src/main/java/net/croz/nrich/validation/constraint/support/disableconstraints/HibernateValidatorAdapter.java new file mode 100644 index 00000000..82f04f72 --- /dev/null +++ b/nrich-validation/src/main/java/net/croz/nrich/validation/constraint/support/disableconstraints/HibernateValidatorAdapter.java @@ -0,0 +1,38 @@ +/* + * Copyright 2020-2023 CROZ d.o.o, the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package net.croz.nrich.validation.constraint.support.disableconstraints; + +import org.hibernate.validator.HibernateValidator; +import org.hibernate.validator.internal.engine.ValidatorFactoryImpl; + +import jakarta.validation.Validator; +import jakarta.validation.ValidatorFactory; +import jakarta.validation.spi.ConfigurationState; + +public class HibernateValidatorAdapter extends HibernateValidator { + + @Override + public ValidatorFactory buildValidatorFactory(ConfigurationState configurationState) { + return new ValidatorFactoryImpl(configurationState) { + @Override + public Validator getValidator() { + return new ValidatorAdapter(super.getValidator()); + } + }; + } +} diff --git a/nrich-validation/src/main/java/net/croz/nrich/validation/constraint/support/disableconstraints/PathUtil.java b/nrich-validation/src/main/java/net/croz/nrich/validation/constraint/support/disableconstraints/PathUtil.java new file mode 100644 index 00000000..55657efb --- /dev/null +++ b/nrich-validation/src/main/java/net/croz/nrich/validation/constraint/support/disableconstraints/PathUtil.java @@ -0,0 +1,44 @@ +/* + * Copyright 2020-2023 CROZ d.o.o, the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package net.croz.nrich.validation.constraint.support.disableconstraints; + +import org.springframework.util.StringUtils; + +public final class PathUtil { + + private static final String PATH_FORMAT = "%s.%s"; + + private PathUtil() { + } + + public static String getPath(Class type, String propertyName) { + if (type == null) { + return propertyName; + } + + return getPath(type.getName(), propertyName); + } + + public static String getPath(String typePath, String propertyName) { + if (StringUtils.hasText(propertyName)) { + return String.format(PATH_FORMAT, typePath, propertyName); + } + + return typePath; + } +} diff --git a/nrich-validation/src/main/java/net/croz/nrich/validation/constraint/support/disableconstraints/PropertyDescriptorAdapter.java b/nrich-validation/src/main/java/net/croz/nrich/validation/constraint/support/disableconstraints/PropertyDescriptorAdapter.java new file mode 100644 index 00000000..932b2a7e --- /dev/null +++ b/nrich-validation/src/main/java/net/croz/nrich/validation/constraint/support/disableconstraints/PropertyDescriptorAdapter.java @@ -0,0 +1,82 @@ +/* + * Copyright 2020-2023 CROZ d.o.o, the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package net.croz.nrich.validation.constraint.support.disableconstraints; + +import lombok.RequiredArgsConstructor; + +import jakarta.validation.metadata.ConstraintDescriptor; +import jakarta.validation.metadata.ContainerElementTypeDescriptor; +import jakarta.validation.metadata.GroupConversionDescriptor; +import jakarta.validation.metadata.PropertyDescriptor; +import java.lang.annotation.Annotation; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +public class PropertyDescriptorAdapter implements PropertyDescriptor { + + private final PropertyDescriptor target; + + private final List> disabledConstraintTypes; + + @Override + public Set> getConstraintDescriptors() { + Set> constraintDescriptors = target.getConstraintDescriptors(); + + return constraintDescriptors.stream().filter(constraintDescriptor -> !disabledConstraintTypes.contains(constraintDescriptor.getAnnotation().annotationType())) + .collect(Collectors.toSet()); + } + + @Override + public ConstraintFinder findConstraints() { + ConstraintFinder finder = target.findConstraints(); + + return new ConstraintFinderAdapter(finder, disabledConstraintTypes); + } + + @Override + public String getPropertyName() { + return target.getPropertyName(); + } + + @Override + public boolean isCascaded() { + return target.isCascaded(); + } + + @Override + public Set getGroupConversions() { + return target.getGroupConversions(); + } + + @Override + public Set getConstrainedContainerElementTypes() { + return target.getConstrainedContainerElementTypes(); + } + + @Override + public boolean hasConstraints() { + return target.hasConstraints(); + } + + @Override + public Class getElementClass() { + return target.getElementClass(); + } +} diff --git a/nrich-validation/src/main/java/net/croz/nrich/validation/constraint/support/disableconstraints/ValidatorAdapter.java b/nrich-validation/src/main/java/net/croz/nrich/validation/constraint/support/disableconstraints/ValidatorAdapter.java new file mode 100644 index 00000000..a9ee4b4c --- /dev/null +++ b/nrich-validation/src/main/java/net/croz/nrich/validation/constraint/support/disableconstraints/ValidatorAdapter.java @@ -0,0 +1,103 @@ +/* + * Copyright 2020-2023 CROZ d.o.o, the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package net.croz.nrich.validation.constraint.support.disableconstraints; + +import lombok.RequiredArgsConstructor; + +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validator; +import jakarta.validation.executable.ExecutableValidator; +import jakarta.validation.metadata.BeanDescriptor; +import java.lang.annotation.Annotation; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Enables usage of {@link net.croz.nrich.validation.api.constraint.DisableConstraints} annotation for disabling validation constraints. + */ +@RequiredArgsConstructor +public class ValidatorAdapter implements Validator { + + private final DisableConstraintsAnnotationProcessor constraintAnnotationProcessor = new DisableConstraintsAnnotationProcessor(); + + private final Validator targetValidator; + + @Override + public Set> validate(T object, Class... groups) { + Set> constraintViolations = targetValidator.validate(object, groups); + + return filterConstraints(constraintViolations, object.getClass()); + } + + @Override + public Set> validateProperty(T object, String propertyName, Class... groups) { + Set> constraintViolations = targetValidator.validateProperty(object, propertyName, groups); + + return filterConstraints(constraintViolations, object.getClass()); + } + + @Override + public Set> validateValue(Class beanType, String propertyName, Object value, Class... groups) { + Set> constraintViolations = targetValidator.validateValue(beanType, propertyName, value, groups); + + return filterConstraints(constraintViolations, beanType); + } + + @Override + public BeanDescriptor getConstraintsForClass(Class type) { + BeanDescriptor beanDescriptor = targetValidator.getConstraintsForClass(type); + + return new BeanDescriptorAdapter(beanDescriptor, constraintAnnotationProcessor.getDisabledConstraintForType(type)); + } + + @Override + public T unwrap(Class type) { + return targetValidator.unwrap(type); + } + + @Override + public ExecutableValidator forExecutables() { + return targetValidator.forExecutables(); + } + + private Set> filterConstraints(Set> originalViolations, Class type) { + if (originalViolations.isEmpty()) { + return originalViolations; + } + + Map>> pathHolderMap = constraintAnnotationProcessor.getDisabledConstraintForType(type); + + if (pathHolderMap.isEmpty()) { + return originalViolations; + } + + return originalViolations.stream().filter(constraintViolation -> { + Class annotationType = constraintViolation.getConstraintDescriptor().getAnnotation().annotationType(); + Class beanType = constraintViolation.getRootBeanClass(); + String propertyName = constraintViolation.getPropertyPath().toString(); + + String path = PathUtil.getPath(beanType, propertyName); + + return !(pathHolderMap.getOrDefault(path, Collections.emptyList()).contains(annotationType)); + + }).collect(Collectors.toSet()); + } +} diff --git a/nrich-validation/src/main/resources/META-INF/services/jakarta.validation.spi.ValidationProvider b/nrich-validation/src/main/resources/META-INF/services/jakarta.validation.spi.ValidationProvider new file mode 100644 index 00000000..2889008d --- /dev/null +++ b/nrich-validation/src/main/resources/META-INF/services/jakarta.validation.spi.ValidationProvider @@ -0,0 +1,18 @@ +# +# Copyright 2020-2023 CROZ d.o.o, the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://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. +# +# + +net.croz.nrich.validation.constraint.support.disableconstraints.HibernateValidatorAdapter diff --git a/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/BeanDescriptorAdapterTest.java b/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/BeanDescriptorAdapterTest.java new file mode 100644 index 00000000..affa831f --- /dev/null +++ b/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/BeanDescriptorAdapterTest.java @@ -0,0 +1,212 @@ +/* + * Copyright 2020-2023 CROZ d.o.o, the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package net.croz.nrich.validation.constraint.support.disableconstraints; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import jakarta.validation.constraints.NotNull; +import jakarta.validation.metadata.BeanDescriptor; +import jakarta.validation.metadata.ConstraintDescriptor; +import jakarta.validation.metadata.ConstructorDescriptor; +import jakarta.validation.metadata.ElementDescriptor; +import jakarta.validation.metadata.MethodDescriptor; +import jakarta.validation.metadata.MethodType; +import jakarta.validation.metadata.PropertyDescriptor; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class BeanDescriptorAdapterTest { + + @Mock + private BeanDescriptor target; + + private BeanDescriptorAdapter beanDescriptorAdapter; + + @BeforeEach + void setUp() { + beanDescriptorAdapter = new BeanDescriptorAdapter(target, Map.of("propertyName", List.of(NotNull.class))); + } + + @Test + void shouldReturnWhetherBeanIsConstrained() { + // given + doReturn(true).when(target).isBeanConstrained(); + + // when + boolean result = beanDescriptorAdapter.isBeanConstrained(); + + // then + assertThat(result).isTrue(); + } + + @Test + void shouldGetConstraintsForProperty() { + // given + String propertyName = "propertyName"; + + doReturn(mock(PropertyDescriptor.class)).when(target).getConstraintsForProperty(propertyName); + + // when + PropertyDescriptor result = beanDescriptorAdapter.getConstraintsForProperty(propertyName); + + // then + assertThat(result).isInstanceOf(PropertyDescriptorAdapter.class); + } + + @Test + void shouldGetConstrainedProperties() { + // given + when(target.getConstrainedProperties()).thenReturn(Set.of(mock(PropertyDescriptor.class))); + + doReturn(Object.class).when(target).getElementClass(); + + // when + Set result = beanDescriptorAdapter.getConstrainedProperties(); + + // then + assertThat(result).isNotEmpty().allMatch(value -> value instanceof PropertyDescriptorAdapter); + } + + @Test + void shouldGetConstraintsForMethod() { + // given + String methodName = "exampleMethod"; + Class[] parameterTypes = new Class[] { String.class, Integer.class }; + MethodDescriptor methodDescriptor = mock(MethodDescriptor.class); + + doReturn(methodDescriptor).when(target).getConstraintsForMethod(methodName, parameterTypes); + + // when + MethodDescriptor result = beanDescriptorAdapter.getConstraintsForMethod(methodName, parameterTypes); + + // then + assertThat(result).isNotNull(); + } + + @Test + void shouldGetConstrainedMethods() { + // given + MethodType methodType = MethodType.GETTER; + MethodType[] methodTypes = new MethodType[] { MethodType.NON_GETTER }; + Set methodDescriptors = Set.of(mock(MethodDescriptor.class)); + + doReturn(methodDescriptors).when(target).getConstrainedMethods(methodType, methodTypes); + + // when + Set result = beanDescriptorAdapter.getConstrainedMethods(methodType, methodTypes); + + // then + assertThat(result).isEqualTo(methodDescriptors); + } + + @Test + void shouldGetConstraintsForConstructor() { + // given + Class[] parameterTypes = new Class[] { String.class, Integer.class }; + ConstructorDescriptor constructorDescriptor = mock(ConstructorDescriptor.class); + + doReturn(constructorDescriptor).when(target).getConstraintsForConstructor(parameterTypes); + + // when + ConstructorDescriptor result = beanDescriptorAdapter.getConstraintsForConstructor(parameterTypes); + + // then + assertThat(result).isEqualTo(constructorDescriptor); + } + + @Test + void shouldGetConstrainedConstructors() { + // given + Set constructorDescriptors = Set.of(mock(ConstructorDescriptor.class)); + + doReturn(constructorDescriptors).when(target).getConstrainedConstructors(); + + // when + Set result = beanDescriptorAdapter.getConstrainedConstructors(); + + // then + assertThat(result).isEqualTo(constructorDescriptors); + } + + @Test + void shouldCheckWhetherBeanHasConstraints() { + // given + doReturn(true).when(target).hasConstraints(); + + // when + boolean result = beanDescriptorAdapter.hasConstraints(); + + // then + assertThat(result).isTrue(); + } + + @Test + void shouldGetElementClass() { + // given + Class elementClass = String.class; + + doReturn(elementClass).when(target).getElementClass(); + + // when + Class result = beanDescriptorAdapter.getElementClass(); + + // then + assertThat(result).isEqualTo(elementClass); + } + + @Test + void shouldGetConstraintDescriptors() { + // given + @SuppressWarnings("unchecked") + Set> constraintDescriptors = Set.of(mock(ConstraintDescriptor.class)); + + doReturn(constraintDescriptors).when(target).getConstraintDescriptors(); + + // when + Set> result = beanDescriptorAdapter.getConstraintDescriptors(); + + // then + assertThat(result).isEqualTo(constraintDescriptors); + } + + @Test + void shouldGetConstraintFinderAdapter() { + // given + ElementDescriptor.ConstraintFinder finder = mock(ElementDescriptor.ConstraintFinder.class); + + doReturn(finder).when(target).findConstraints(); + doReturn(Object.class).when(target).getElementClass(); + + // when + ElementDescriptor.ConstraintFinder result = beanDescriptorAdapter.findConstraints(); + + // then + assertThat(result).isInstanceOf(ConstraintFinderAdapter.class); + } +} diff --git a/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/ConstraintFinderAdapterTest.java b/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/ConstraintFinderAdapterTest.java new file mode 100644 index 00000000..8ddb8774 --- /dev/null +++ b/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/ConstraintFinderAdapterTest.java @@ -0,0 +1,120 @@ +/* + * Copyright 2020-2023 CROZ d.o.o, the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package net.croz.nrich.validation.constraint.support.disableconstraints; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.metadata.ConstraintDescriptor; +import jakarta.validation.metadata.ElementDescriptor; +import jakarta.validation.metadata.Scope; +import java.lang.annotation.ElementType; +import java.util.List; +import java.util.Set; + +import static net.croz.nrich.validation.constraint.support.disableconstraints.testutil.ConstraintDescriptorTestUtil.createConstraintDescriptor; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +@ExtendWith(MockitoExtension.class) +class ConstraintFinderAdapterTest { + + @Mock + private ElementDescriptor.ConstraintFinder target; + + private ConstraintFinderAdapter constraintFinderAdapter; + + @BeforeEach + void setup() { + constraintFinderAdapter = new ConstraintFinderAdapter(target, List.of(NotNull.class)); + } + + @Test + void shouldSpecifyUnorderedAndMatchingGroupsOnTarget() { + // given + Class group = Object.class; + + // when + ElementDescriptor.ConstraintFinder result = constraintFinderAdapter.unorderedAndMatchingGroups(group); + + // then + assertThat(result).isInstanceOf(ConstraintFinderAdapter.class); + verify(target).unorderedAndMatchingGroups(group); + } + + @Test + void shouldSpecifyLookingAtOnTarget() { + // given + Scope scope = Scope.LOCAL_ELEMENT; + + doReturn(target).when(target).lookingAt(scope); + + // when + ElementDescriptor.ConstraintFinder result = constraintFinderAdapter.lookingAt(scope); + + // then + assertThat(result).isInstanceOf(ConstraintFinderAdapter.class); + verify(target).lookingAt(scope); + } + + @Test + void shouldSpecifyDeclaredOnTarget() { + // given + ElementType elementType = ElementType.TYPE; + + // when + ElementDescriptor.ConstraintFinder result = constraintFinderAdapter.declaredOn(elementType); + + // then + assertThat(result).isInstanceOf(ConstraintFinderAdapter.class); + verify(target).declaredOn(elementType); + } + + @Test + void shouldFilterConstraintDescriptors() { + // given + ConstraintDescriptor first = createConstraintDescriptor(NotNull.class); + ConstraintDescriptor second = createConstraintDescriptor(NotEmpty.class); + + doReturn(Set.of(first, second)).when(target).getConstraintDescriptors(); + + // when + Set> result = constraintFinderAdapter.getConstraintDescriptors(); + + // then + assertThat(result).containsExactly(second); + } + + @Test + void shouldReturnWhetherTargetHasConstraints() { + // given + doReturn(true).when(target).hasConstraints(); + + // when + boolean result = constraintFinderAdapter.hasConstraints(); + + // then + assertThat(result).isTrue(); + } +} diff --git a/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/DisableConstraintsAnnotationProcessorTest.java b/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/DisableConstraintsAnnotationProcessorTest.java new file mode 100644 index 00000000..6d9be8f6 --- /dev/null +++ b/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/DisableConstraintsAnnotationProcessorTest.java @@ -0,0 +1,63 @@ +/* + * Copyright 2020-2023 CROZ d.o.o, the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package net.croz.nrich.validation.constraint.support.disableconstraints; + +import net.croz.nrich.validation.constraint.support.disableconstraints.stub.DisableConstraintsAnnotationProcessorInvalidTestRequest; +import net.croz.nrich.validation.constraint.support.disableconstraints.stub.DisableConstraintsAnnotationProcessorTestRequest; +import org.junit.jupiter.api.Test; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import java.lang.annotation.Annotation; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; + +class DisableConstraintsAnnotationProcessorTest { + + private final DisableConstraintsAnnotationProcessor constraintAnnotationProcessor = new DisableConstraintsAnnotationProcessor(); + + @Test + void shouldGetDisabledConstraintsForType() { + // when + Map>> result = constraintAnnotationProcessor.getDisabledConstraintForType(DisableConstraintsAnnotationProcessorTestRequest.class); + + // then + assertThat(result).containsExactlyInAnyOrderEntriesOf( + Map.of( + "net.croz.nrich.validation.constraint.support.disableconstraints.stub.DisableConstraintsAnnotationProcessorTestRequest", List.of(NotNull.class), + "net.croz.nrich.validation.constraint.support.disableconstraints.stub.DisableConstraintsAnnotationProcessorTestRequest.age", List.of(NotNull.class), + "net.croz.nrich.validation.constraint.support.disableconstraints.stub.DisableConstraintsAnnotationProcessorTestRequest.employmentDuration", List.of(Min.class), + "net.croz.nrich.validation.constraint.support.disableconstraints.stub.DisableConstraintsAnnotationProcessorTestRequest.name", List.of(NotBlank.class, Size.class) + ) + ); + } + + @Test + void shouldThrowExceptionWhenPropertyNameIsDefinedOnNonTypeAnnotation() { + // when + Throwable thrown = catchThrowable(() -> constraintAnnotationProcessor.getDisabledConstraintForType(DisableConstraintsAnnotationProcessorInvalidTestRequest.class)); + + // then + assertThat(thrown).isInstanceOf(IllegalArgumentException.class).hasMessage("Property name not allowed on method or property annotation."); + } +} diff --git a/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/PathUtilTest.java b/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/PathUtilTest.java new file mode 100644 index 00000000..1757f1c5 --- /dev/null +++ b/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/PathUtilTest.java @@ -0,0 +1,62 @@ +/* + * Copyright 2020-2023 CROZ d.o.o, the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package net.croz.nrich.validation.constraint.support.disableconstraints; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class PathUtilTest { + + @Test + void shouldReturnPropertyNameWhenTypeIsNull() { + // given + String propertyName = "propertyName"; + + // when + String result = PathUtil.getPath((Class) null, propertyName); + + // then + assertThat(result).isEqualTo(propertyName); + } + + @Test + void shouldReturnTypeNameWhenPropertyNameIsNull() { + // given + Class type = Object.class; + + // when + String result = PathUtil.getPath(type, null); + + // then + assertThat(result).isEqualTo(type.getName()); + } + + @Test + void shouldReturnPath() { + // given + Class type = Object.class; + String propertyName = "propertyName"; + + // when + String result = PathUtil.getPath(type, propertyName); + + // then + assertThat(result).isEqualTo("java.lang.Object.propertyName"); + } +} diff --git a/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/PropertyDescriptorAdapterTest.java b/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/PropertyDescriptorAdapterTest.java new file mode 100644 index 00000000..c349f9c0 --- /dev/null +++ b/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/PropertyDescriptorAdapterTest.java @@ -0,0 +1,162 @@ +/* + * Copyright 2020-2023 CROZ d.o.o, the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package net.croz.nrich.validation.constraint.support.disableconstraints; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.metadata.ConstraintDescriptor; +import jakarta.validation.metadata.ContainerElementTypeDescriptor; +import jakarta.validation.metadata.ElementDescriptor; +import jakarta.validation.metadata.GroupConversionDescriptor; +import jakarta.validation.metadata.PropertyDescriptor; +import java.util.List; +import java.util.Set; + +import static net.croz.nrich.validation.constraint.support.disableconstraints.testutil.ConstraintDescriptorTestUtil.createConstraintDescriptor; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + +@ExtendWith(MockitoExtension.class) +class PropertyDescriptorAdapterTest { + + @Mock + private PropertyDescriptor target; + + private PropertyDescriptorAdapter propertyDescriptorAdapter; + + @BeforeEach + void setup() { + propertyDescriptorAdapter = new PropertyDescriptorAdapter(target, List.of(NotNull.class)); + } + + @Test + void shouldGetPropertyName() { + // given + String propertyName = "propertyName"; + + doReturn(propertyName).when(target).getPropertyName(); + + // when + String result = propertyDescriptorAdapter.getPropertyName(); + + // then + assertThat(result).isEqualTo(propertyName); + } + + @Test + void shouldReturnWhetherIsCascaded() { + // given + doReturn(true).when(target).isCascaded(); + + // when + boolean result = propertyDescriptorAdapter.isCascaded(); + + // then + assertThat(result).isTrue(); + } + + @Test + void shouldGetGroupConversions() { + // given + Set groupConversionDescriptors = Set.of(mock(GroupConversionDescriptor.class)); + + doReturn(groupConversionDescriptors).when(target).getGroupConversions(); + + // when + Set result = propertyDescriptorAdapter.getGroupConversions(); + + // then + assertThat(result).isEqualTo(groupConversionDescriptors); + } + + @Test + void shouldGetConstrainedContainerElementTypes() { + // given + Set containerElementTypeDescriptors = Set.of(mock(ContainerElementTypeDescriptor.class)); + + doReturn(containerElementTypeDescriptors).when(target).getConstrainedContainerElementTypes(); + + // when + Set result = propertyDescriptorAdapter.getConstrainedContainerElementTypes(); + + // then + assertThat(result).isEqualTo(containerElementTypeDescriptors); + } + + @Test + void shouldReturnWhetherHasConstraints() { + // given + doReturn(true).when(target).hasConstraints(); + + // when + boolean result = propertyDescriptorAdapter.hasConstraints(); + + // then + assertThat(result).isTrue(); + } + + @Test + void shouldGetElementClass() { + // given + Class elementClass = Object.class; + + doReturn(elementClass).when(target).getElementClass(); + + // when + Class result = propertyDescriptorAdapter.getElementClass(); + + // then + assertThat(result).isEqualTo(elementClass); + } + + @Test + void shouldFilterConstraintDescriptors() { + // given + ConstraintDescriptor first = createConstraintDescriptor(NotNull.class); + ConstraintDescriptor second = createConstraintDescriptor(NotEmpty.class); + + doReturn(Set.of(first, second)).when(target).getConstraintDescriptors(); + + // when + Set> result = propertyDescriptorAdapter.getConstraintDescriptors(); + + // then + assertThat(result).containsExactly(second); + } + + @Test + void shouldGetConstraintFinderAdapter() { + // given + ElementDescriptor.ConstraintFinder constraintFinder = mock(ElementDescriptor.ConstraintFinder.class); + + doReturn(constraintFinder).when(target).findConstraints(); + + // when + ElementDescriptor.ConstraintFinder result = propertyDescriptorAdapter.findConstraints(); + + // then + assertThat(result).isInstanceOf(ConstraintFinderAdapter.class); + } +} diff --git a/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/ValidatorAdapterTest.java b/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/ValidatorAdapterTest.java new file mode 100644 index 00000000..d0e8325e --- /dev/null +++ b/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/ValidatorAdapterTest.java @@ -0,0 +1,154 @@ +/* + * Copyright 2020-2023 CROZ d.o.o, the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package net.croz.nrich.validation.constraint.support.disableconstraints; + +import net.croz.nrich.validation.ValidationTestConfiguration; +import net.croz.nrich.validation.constraint.support.disableconstraints.stub.DisableConstraintsParentTestRequest; +import net.croz.nrich.validation.constraint.support.disableconstraints.stub.DisableConstraintsPropertyAnnotationTestRequest; +import net.croz.nrich.validation.constraint.support.disableconstraints.stub.DisableConstraintsTypeAnnotationTestRequest; +import org.hibernate.validator.HibernateValidatorFactory; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; + +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validator; +import jakarta.validation.executable.ExecutableValidator; +import jakarta.validation.metadata.BeanDescriptor; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringJUnitConfig(ValidationTestConfiguration.class) +class ValidatorAdapterTest { + + @Autowired + private Validator validator; + + @Test + void shouldNotReportErrorForPropertyDisabledConstraints() { + // given + DisableConstraintsPropertyAnnotationTestRequest request = new DisableConstraintsPropertyAnnotationTestRequest(null, null); + + // when + Set> constraintViolationList = validator.validate(request); + + // then + assertThat(constraintViolationList).isEmpty(); + + // and when + constraintViolationList = validator.validateProperty(request, "age"); + + // then + assertThat(constraintViolationList).isEmpty(); + + // and when + constraintViolationList = validator.validateValue(DisableConstraintsPropertyAnnotationTestRequest.class, "age", null); + + // then + assertThat(constraintViolationList).isEmpty(); + } + + @Test + void shouldNotReportErrorForTypeDisabledConstraints() { + // given + DisableConstraintsTypeAnnotationTestRequest request = new DisableConstraintsTypeAnnotationTestRequest(null, null); + + // when + Set> constraintViolationList = validator.validate(request); + + // then + assertThat(constraintViolationList).isEmpty(); + + // and when + constraintViolationList = validator.validateProperty(request, "age"); + + // then + assertThat(constraintViolationList).isEmpty(); + + // and when + constraintViolationList = validator.validateValue(DisableConstraintsTypeAnnotationTestRequest.class, "age", null); + + // then + assertThat(constraintViolationList).isEmpty(); + } + + @Test + void shouldReportErrorsForParentValidation() { + // given + DisableConstraintsParentTestRequest request = new DisableConstraintsParentTestRequest(null, null); + + // when + Set> constraintViolationList = validator.validate(request); + + // then + assertThat(constraintViolationList).isNotEmpty(); + } + + @Test + void shouldNotReturnDisabledConstraintsOnProperty() { + // when + BeanDescriptor result = validator.getConstraintsForClass(DisableConstraintsPropertyAnnotationTestRequest.class); + + // then + assertThat(result.getConstraintsForProperty("name").getConstraintDescriptors()).isEmpty(); + assertThat(result.getConstraintsForProperty("age").getConstraintDescriptors()).isEmpty(); + } + + @Test + void shouldNotReturnDisabledConstraintsOnType() { + // when + BeanDescriptor result = validator.getConstraintsForClass(DisableConstraintsTypeAnnotationTestRequest.class); + + // then + assertThat(result.getConstraintsForProperty("name").getConstraintDescriptors()).isEmpty(); + assertThat(result.getConstraintsForProperty("name").findConstraints().getConstraintDescriptors()).isEmpty(); + assertThat(result.getConstraintsForProperty("age").getConstraintDescriptors()).isEmpty(); + assertThat(result.getConstraintsForProperty("age").findConstraints().getConstraintDescriptors()).isEmpty(); + } + + @Test + void shouldReturnConstraintsOnType() { + // when + BeanDescriptor result = validator.getConstraintsForClass(DisableConstraintsParentTestRequest.class); + + // then + assertThat(result.getConstraintsForProperty("name").getConstraintDescriptors()).isNotEmpty(); + assertThat(result.getConstraintsForProperty("name").findConstraints().getConstraintDescriptors()).isNotEmpty(); + assertThat(result.getConstraintsForProperty("age").getConstraintDescriptors()).isNotEmpty(); + assertThat(result.getConstraintsForProperty("age").findConstraints().getConstraintDescriptors()).isNotEmpty(); + } + + @Test + void shouldUnwrap() { + // when + Object result = validator.unwrap(HibernateValidatorFactory.class); + + // then + assertThat(result).isNotNull(); + } + + @Test + void shouldReturnForExecutableValidator() { + // when + ExecutableValidator result = validator.forExecutables(); + + // then + assertThat(result).isNotNull(); + } +} diff --git a/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/stub/DisableConstraintsAnnotationProcessorInvalidTestRequest.java b/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/stub/DisableConstraintsAnnotationProcessorInvalidTestRequest.java new file mode 100644 index 00000000..b50e18f8 --- /dev/null +++ b/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/stub/DisableConstraintsAnnotationProcessorInvalidTestRequest.java @@ -0,0 +1,30 @@ +/* + * Copyright 2020-2023 CROZ d.o.o, the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package net.croz.nrich.validation.constraint.support.disableconstraints.stub; + +import net.croz.nrich.validation.api.constraint.DisableConstraints; + +import jakarta.validation.constraints.Min; + +public class DisableConstraintsAnnotationProcessorInvalidTestRequest { + + @SuppressWarnings("unused") + @DisableConstraints(value = Min.class, propertyName = "someOtherPropertyName") + private Integer employmentDuration; + +} diff --git a/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/stub/DisableConstraintsAnnotationProcessorTestRequest.java b/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/stub/DisableConstraintsAnnotationProcessorTestRequest.java new file mode 100644 index 00000000..09998234 --- /dev/null +++ b/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/stub/DisableConstraintsAnnotationProcessorTestRequest.java @@ -0,0 +1,39 @@ +/* + * Copyright 2020-2023 CROZ d.o.o, the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package net.croz.nrich.validation.constraint.support.disableconstraints.stub; + +import net.croz.nrich.validation.api.constraint.DisableConstraints; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +@DisableConstraints(NotNull.class) +@DisableConstraints(value = NotNull.class, propertyName = "age") +public class DisableConstraintsAnnotationProcessorTestRequest { + + @SuppressWarnings("unused") + @DisableConstraints(Min.class) + private Integer employmentDuration; + + @DisableConstraints({ NotBlank.class, Size.class }) + public String getName() { + return "name"; + } +} diff --git a/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/stub/DisableConstraintsParentTestRequest.java b/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/stub/DisableConstraintsParentTestRequest.java new file mode 100644 index 00000000..542a261a --- /dev/null +++ b/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/stub/DisableConstraintsParentTestRequest.java @@ -0,0 +1,39 @@ +/* + * Copyright 2020-2023 CROZ d.o.o, the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package net.croz.nrich.validation.constraint.support.disableconstraints.stub; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + +@RequiredArgsConstructor +@Getter +public class DisableConstraintsParentTestRequest { + + @NotBlank + private final String name; + + private final Integer age; + + @NotNull + public Integer getAge() { + return age; + } +} diff --git a/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/stub/DisableConstraintsPropertyAnnotationTestRequest.java b/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/stub/DisableConstraintsPropertyAnnotationTestRequest.java new file mode 100644 index 00000000..a9fb3034 --- /dev/null +++ b/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/stub/DisableConstraintsPropertyAnnotationTestRequest.java @@ -0,0 +1,42 @@ +/* + * Copyright 2020-2023 CROZ d.o.o, the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package net.croz.nrich.validation.constraint.support.disableconstraints.stub; + +import net.croz.nrich.validation.api.constraint.DisableConstraints; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + +public class DisableConstraintsPropertyAnnotationTestRequest extends DisableConstraintsParentTestRequest { + + public DisableConstraintsPropertyAnnotationTestRequest(String name, Integer age) { + super(name, age); + } + + @DisableConstraints(NotBlank.class) + @Override + public String getName() { + return super.getName(); + } + + @DisableConstraints(NotNull.class) + @Override + public Integer getAge() { + return super.getAge(); + } +} diff --git a/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/stub/DisableConstraintsTypeAnnotationTestRequest.java b/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/stub/DisableConstraintsTypeAnnotationTestRequest.java new file mode 100644 index 00000000..84165e12 --- /dev/null +++ b/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/stub/DisableConstraintsTypeAnnotationTestRequest.java @@ -0,0 +1,32 @@ +/* + * Copyright 2020-2023 CROZ d.o.o, the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package net.croz.nrich.validation.constraint.support.disableconstraints.stub; + +import net.croz.nrich.validation.api.constraint.DisableConstraints; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + +@DisableConstraints(value = NotBlank.class, propertyName = "name") +@DisableConstraints(value = NotNull.class, propertyName = "age") +public class DisableConstraintsTypeAnnotationTestRequest extends DisableConstraintsParentTestRequest { + + public DisableConstraintsTypeAnnotationTestRequest(String name, Integer age) { + super(name, age); + } +} diff --git a/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/testutil/ConstraintDescriptorTestUtil.java b/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/testutil/ConstraintDescriptorTestUtil.java new file mode 100644 index 00000000..38516151 --- /dev/null +++ b/nrich-validation/src/test/java/net/croz/nrich/validation/constraint/support/disableconstraints/testutil/ConstraintDescriptorTestUtil.java @@ -0,0 +1,42 @@ +/* + * Copyright 2020-2023 CROZ d.o.o, the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package net.croz.nrich.validation.constraint.support.disableconstraints.testutil; + +import jakarta.validation.metadata.ConstraintDescriptor; +import java.lang.annotation.Annotation; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + +public final class ConstraintDescriptorTestUtil { + + private ConstraintDescriptorTestUtil() { + } + + public static ConstraintDescriptor createConstraintDescriptor(Class constraintAnnotationType) { + T annotation = mock(constraintAnnotationType); + doReturn(constraintAnnotationType).when(annotation).annotationType(); + + @SuppressWarnings("unchecked") + ConstraintDescriptor constraintDescriptor = mock(ConstraintDescriptor.class); + doReturn(annotation).when(constraintDescriptor).getAnnotation(); + + return constraintDescriptor; + } + +}