From b19615d6664fd56246d3086953df0103191a3261 Mon Sep 17 00:00:00 2001 From: ArielBerkovich <34457341+ArielBerkovich@users.noreply.github.com> Date: Sun, 31 Mar 2024 07:34:15 +0300 Subject: [PATCH 1/2] added constraint on class api to ValidatorBuilder --- .../am/ik/yavi/builder/ValidatorBuilder.java | 73 +++++++++++++------ .../ik/yavi/core/ConstraintOnClassTest.java | 71 ++++++++++++++++++ 2 files changed, 121 insertions(+), 23 deletions(-) create mode 100644 src/test/java/am/ik/yavi/core/ConstraintOnClassTest.java diff --git a/src/main/java/am/ik/yavi/builder/ValidatorBuilder.java b/src/main/java/am/ik/yavi/builder/ValidatorBuilder.java index b3d17449..1e7086f6 100644 --- a/src/main/java/am/ik/yavi/builder/ValidatorBuilder.java +++ b/src/main/java/am/ik/yavi/builder/ValidatorBuilder.java @@ -15,29 +15,6 @@ */ package am.ik.yavi.builder; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.time.Instant; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.OffsetDateTime; -import java.time.Year; -import java.time.YearMonth; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Deque; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.function.Supplier; - import am.ik.yavi.constraint.BigDecimalConstraint; import am.ik.yavi.constraint.BigIntegerConstraint; import am.ik.yavi.constraint.BooleanConstraint; @@ -111,6 +88,29 @@ import am.ik.yavi.meta.YearMonthConstraintMeta; import am.ik.yavi.meta.ZonedDateTimeConstraintMeta; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.Year; +import java.time.YearMonth; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Deque; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.Supplier; + public class ValidatorBuilder implements Cloneable { private static final String DEFAULT_SEPARATOR = "."; @@ -732,6 +732,33 @@ public ValidatorBuilder _doubleArray(ToDoubleArray f, String name, return this.constraint(f, name, c, DoubleArrayConstraint::new); } + /** + * @since 0.14.0 + */ + public ValidatorBuilder constraintOnClass(Class clazz, + Validator cValidator) { + Validator TValidator = new ValidatorBuilder() + .nest(clazz::cast, clazz.getName(), cValidator).build(); + + return constraintOnCondition(getClassConstraintCondition(clazz), TValidator); + } + + /** + * @since 0.14.0 + */ + public ValidatorBuilder constraintOnClass(Class clazz, + ValidatorBuilderConverter converter) { + ValidatorBuilderConverter tConverter = tValidatorBuilder -> tValidatorBuilder + .nest(clazz::cast, clazz.getName(), converter); + + return constraintOnCondition(getClassConstraintCondition(clazz), tConverter); + } + + private ConstraintCondition getClassConstraintCondition( + Class classCondition) { + return (t, c) -> classCondition.isInstance(t); + } + /** * @since 0.11.0 */ diff --git a/src/test/java/am/ik/yavi/core/ConstraintOnClassTest.java b/src/test/java/am/ik/yavi/core/ConstraintOnClassTest.java new file mode 100644 index 00000000..09f8d46f --- /dev/null +++ b/src/test/java/am/ik/yavi/core/ConstraintOnClassTest.java @@ -0,0 +1,71 @@ +package am.ik.yavi.core; + +import am.ik.yavi.User; +import am.ik.yavi.builder.ValidatorBuilder; +import am.ik.yavi.constraint.CharSequenceConstraint; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.function.Function; +import java.util.stream.Stream; + +import static com.google.common.truth.Truth.assertThat; + +public class ConstraintOnClassTest { + + @ParameterizedTest + @MethodSource("provideValidators") + void testConstraintOnConditionClass(Validator validator) { + User validAdmin = new Admin("admin123", "admin@gmail", 27, "yavi123"); + User invalidAdmin = new Admin("Niraz", "niraz@gmail", 23, "user"); + + assertThat(validator.validate(validAdmin).isValid()).isTrue(); + assertThat(validator.validate(invalidAdmin).isValid()).isFalse(); + } + + @ParameterizedTest + @MethodSource("provideValidators") + void testConstraintOnNonConditionClass(Validator validator) { + User validUser = new User("Rawad", "rawad@gmail", 25); + User invalidUser = new User("Almog", "almog@gmail", 19); + + assertThat(validator.validate(validUser).isValid()).isTrue(); + assertThat(validator.validate(invalidUser).isValid()).isFalse(); + } + + static Stream provideValidators() { + ValidatorBuilder userValidatorBuilder = ValidatorBuilder.of(User.class) + .constraint(User::getAge, "age", c -> c.greaterThan(20)); + Function, CharSequenceConstraint> startsWithAdmin = ( + CharSequenceConstraint c) -> c.startsWith("yavi"); + + return Stream + .of(Arguments.of(new ValidatorBuilder<>(userValidatorBuilder) + .constraintOnClass(Admin.class, + ValidatorBuilder.of(Admin.class) + .constraint(Admin::getGroup, "group", + startsWithAdmin) + .build()) + .build()), Arguments + .of(new ValidatorBuilder<>(userValidatorBuilder) + .constraintOnClass(Admin.class, + b -> b.constraint(Admin::getGroup, + "group", startsWithAdmin)) + .build())); + } + + private static class Admin extends User { + private String group; + + public Admin(String name, String email, int age, String group) { + super(name, email, age); + this.group = group; + } + + public String getGroup() { + return group; + } + } +} From 4c5ccfff69960d09851f2219e2f55e73847dae35 Mon Sep 17 00:00:00 2001 From: ArielBerkovich <34457341+ArielBerkovich@users.noreply.github.com> Date: Tue, 2 Apr 2024 01:13:09 +0300 Subject: [PATCH 2/2] diffrent approach to validating inheritence classes --- .../am/ik/yavi/builder/ValidatorBuilder.java | 54 ++++----------- .../am/ik/yavi/core/InheritanceValidator.java | 50 ++++++++++++++ .../ik/yavi/core/ConstraintOnClassTest.java | 68 +++++++++++-------- 3 files changed, 102 insertions(+), 70 deletions(-) create mode 100644 src/main/java/am/ik/yavi/core/InheritanceValidator.java diff --git a/src/main/java/am/ik/yavi/builder/ValidatorBuilder.java b/src/main/java/am/ik/yavi/builder/ValidatorBuilder.java index 1e7086f6..e7dcbf0d 100644 --- a/src/main/java/am/ik/yavi/builder/ValidatorBuilder.java +++ b/src/main/java/am/ik/yavi/builder/ValidatorBuilder.java @@ -54,6 +54,7 @@ import am.ik.yavi.core.ConstraintPredicate; import am.ik.yavi.core.ConstraintPredicates; import am.ik.yavi.core.CustomConstraint; +import am.ik.yavi.core.InheritanceValidator; import am.ik.yavi.core.NestedCollectionValidator; import am.ik.yavi.core.NestedConstraintCondition; import am.ik.yavi.core.NestedConstraintPredicates; @@ -67,45 +68,12 @@ import am.ik.yavi.fn.Pair; import am.ik.yavi.message.MessageFormatter; import am.ik.yavi.message.SimpleMessageFormatter; -import am.ik.yavi.meta.BigDecimalConstraintMeta; -import am.ik.yavi.meta.BigIntegerConstraintMeta; -import am.ik.yavi.meta.BooleanConstraintMeta; -import am.ik.yavi.meta.ByteConstraintMeta; -import am.ik.yavi.meta.CharacterConstraintMeta; -import am.ik.yavi.meta.DoubleConstraintMeta; -import am.ik.yavi.meta.FloatConstraintMeta; -import am.ik.yavi.meta.InstantConstraintMeta; -import am.ik.yavi.meta.IntegerConstraintMeta; -import am.ik.yavi.meta.LocalDateConstraintMeta; -import am.ik.yavi.meta.LocalDateTimeConstraintMeta; -import am.ik.yavi.meta.LocalTimeConstraintMeta; -import am.ik.yavi.meta.LongConstraintMeta; -import am.ik.yavi.meta.ObjectConstraintMeta; -import am.ik.yavi.meta.OffsetDateTimeConstraintMeta; -import am.ik.yavi.meta.ShortConstraintMeta; -import am.ik.yavi.meta.StringConstraintMeta; -import am.ik.yavi.meta.YearConstraintMeta; -import am.ik.yavi.meta.YearMonthConstraintMeta; -import am.ik.yavi.meta.ZonedDateTimeConstraintMeta; +import am.ik.yavi.meta.*; import java.math.BigDecimal; import java.math.BigInteger; -import java.time.Instant; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.OffsetDateTime; -import java.time.Year; -import java.time.YearMonth; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Deque; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; +import java.time.*; +import java.util.*; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; @@ -737,10 +705,12 @@ public ValidatorBuilder _doubleArray(ToDoubleArray f, String name, */ public ValidatorBuilder constraintOnClass(Class clazz, Validator cValidator) { - Validator TValidator = new ValidatorBuilder() - .nest(clazz::cast, clazz.getName(), cValidator).build(); + Validatable validatable = new InheritanceValidator<>(clazz, cValidator); - return constraintOnCondition(getClassConstraintCondition(clazz), TValidator); + this.conditionalValidators + .add(new Pair<>(getClassConstraintCondition(clazz), validatable)); + + return this; } /** @@ -748,10 +718,9 @@ public ValidatorBuilder constraintOnClass(Class clazz, */ public ValidatorBuilder constraintOnClass(Class clazz, ValidatorBuilderConverter converter) { - ValidatorBuilderConverter tConverter = tValidatorBuilder -> tValidatorBuilder - .nest(clazz::cast, clazz.getName(), converter); + Validator cValidator = converter.apply(new ValidatorBuilder<>()).build(); - return constraintOnCondition(getClassConstraintCondition(clazz), tConverter); + return constraintOnClass(clazz, cValidator); } private ConstraintCondition getClassConstraintCondition( @@ -1025,6 +994,7 @@ protected final ValidatorBuilder nest(Function nested, String name, .forEach(this.appendNestedConditionalValidator(nested, name)); builder.collectionValidators .forEach(appendNestedCollectionValidator(nested, name)); + return this; } diff --git a/src/main/java/am/ik/yavi/core/InheritanceValidator.java b/src/main/java/am/ik/yavi/core/InheritanceValidator.java new file mode 100644 index 00000000..f70b8fa7 --- /dev/null +++ b/src/main/java/am/ik/yavi/core/InheritanceValidator.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2018-2023 Toshiaki Maki + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package am.ik.yavi.core; + +import java.util.Locale; + +/** + * @since 0.14.0 + */ +public class InheritanceValidator implements Validatable { + private final Class nClass; + private final Validatable validator; + + public InheritanceValidator(Class nClass, Validatable validator) { + this.nClass = nClass; + this.validator = validator; + } + + @Override + public ConstraintViolations validate(T target, Locale locale, + ConstraintContext constraintContext) { + final N n = nClass.cast(target); + + return this.validator.validate(n, locale, constraintContext); + } + + @Override + public Validatable failFast(boolean failFast) { + final Validatable validatable = this.validator.failFast(failFast); + return new InheritanceValidator<>(nClass, validatable); + } + + @Override + public boolean isFailFast() { + return this.validator.isFailFast(); + } +} diff --git a/src/test/java/am/ik/yavi/core/ConstraintOnClassTest.java b/src/test/java/am/ik/yavi/core/ConstraintOnClassTest.java index 09f8d46f..4d42f9c5 100644 --- a/src/test/java/am/ik/yavi/core/ConstraintOnClassTest.java +++ b/src/test/java/am/ik/yavi/core/ConstraintOnClassTest.java @@ -17,55 +17,67 @@ public class ConstraintOnClassTest { @ParameterizedTest @MethodSource("provideValidators") - void testConstraintOnConditionClass(Validator validator) { - User validAdmin = new Admin("admin123", "admin@gmail", 27, "yavi123"); - User invalidAdmin = new Admin("Niraz", "niraz@gmail", 23, "user"); + void testConstraintOnConditionClass(Validator validator) { + Parent validChild = new Child(23, "drawing"); + Parent invalidChild = new Child(6, "drawing"); - assertThat(validator.validate(validAdmin).isValid()).isTrue(); - assertThat(validator.validate(invalidAdmin).isValid()).isFalse(); + assertThat(validator.validate(validChild).isValid()).isTrue(); + assertThat(validator.validate(invalidChild).isValid()).isFalse(); } @ParameterizedTest @MethodSource("provideValidators") - void testConstraintOnNonConditionClass(Validator validator) { - User validUser = new User("Rawad", "rawad@gmail", 25); - User invalidUser = new User("Almog", "almog@gmail", 19); + void testConstraintOnNonConditionClass(Validator validator) { + Parent validParent = new Parent(35); + Parent invalidParent = new Parent(19); - assertThat(validator.validate(validUser).isValid()).isTrue(); - assertThat(validator.validate(invalidUser).isValid()).isFalse(); + assertThat(validator.validate(validParent).isValid()).isTrue(); + assertThat(validator.validate(invalidParent).isValid()).isFalse(); } static Stream provideValidators() { - ValidatorBuilder userValidatorBuilder = ValidatorBuilder.of(User.class) - .constraint(User::getAge, "age", c -> c.greaterThan(20)); - Function, CharSequenceConstraint> startsWithAdmin = ( - CharSequenceConstraint c) -> c.startsWith("yavi"); + ValidatorBuilder userValidatorBuilder = ValidatorBuilder.of(Parent.class) + .constraint(Parent::getAge, "age", c -> c.greaterThan(20)); + Function, CharSequenceConstraint> equalsToDrawing = ( + CharSequenceConstraint c) -> c.equalTo("drawing"); return Stream .of(Arguments.of(new ValidatorBuilder<>(userValidatorBuilder) - .constraintOnClass(Admin.class, - ValidatorBuilder.of(Admin.class) - .constraint(Admin::getGroup, "group", - startsWithAdmin) + .constraintOnClass(Child.class, + ValidatorBuilder.of(Child.class) + .constraint(Child::getHobby, "hobby", + equalsToDrawing) .build()) .build()), Arguments .of(new ValidatorBuilder<>(userValidatorBuilder) - .constraintOnClass(Admin.class, - b -> b.constraint(Admin::getGroup, - "group", startsWithAdmin)) + .constraintOnClass(Child.class, + b -> b.constraint(Child::getHobby, + "hobby", equalsToDrawing)) .build())); } - private static class Admin extends User { - private String group; + private static class Child extends Parent { + private String hobby; - public Admin(String name, String email, int age, String group) { - super(name, email, age); - this.group = group; + public Child(int age, String hobby) { + super(age); + this.hobby = hobby; } - public String getGroup() { - return group; + public String getHobby() { + return hobby; + } + } + + private static class Parent { + private final int age; + + public Parent(int age) { + this.age = age; + } + + public int getAge() { + return age; } } }