Skip to content

Commit

Permalink
diffrent approach to validating inheritence classes
Browse files Browse the repository at this point in the history
  • Loading branch information
ArielBerkovich committed Apr 2, 2024
1 parent b19615d commit 4c5ccff
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 70 deletions.
54 changes: 12 additions & 42 deletions src/main/java/am/ik/yavi/builder/ValidatorBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -737,21 +705,22 @@ public ValidatorBuilder<T> _doubleArray(ToDoubleArray<T> f, String name,
*/
public <C extends T> ValidatorBuilder<T> constraintOnClass(Class<C> clazz,
Validator<C> cValidator) {
Validator<T> TValidator = new ValidatorBuilder<T>()
.nest(clazz::cast, clazz.getName(), cValidator).build();
Validatable<T> validatable = new InheritanceValidator<>(clazz, cValidator);

return constraintOnCondition(getClassConstraintCondition(clazz), TValidator);
this.conditionalValidators
.add(new Pair<>(getClassConstraintCondition(clazz), validatable));

return this;
}

/**
* @since 0.14.0
*/
public <C extends T> ValidatorBuilder<T> constraintOnClass(Class<C> clazz,
ValidatorBuilderConverter<C> converter) {
ValidatorBuilderConverter<T> tConverter = tValidatorBuilder -> tValidatorBuilder
.nest(clazz::cast, clazz.getName(), converter);
Validator<C> cValidator = converter.apply(new ValidatorBuilder<>()).build();

return constraintOnCondition(getClassConstraintCondition(clazz), tConverter);
return constraintOnClass(clazz, cValidator);
}

private <C extends T> ConstraintCondition<T> getClassConstraintCondition(
Expand Down Expand Up @@ -1025,6 +994,7 @@ protected final <N> ValidatorBuilder<T> nest(Function<T, N> nested, String name,
.forEach(this.appendNestedConditionalValidator(nested, name));
builder.collectionValidators
.forEach(appendNestedCollectionValidator(nested, name));

return this;
}

Expand Down
50 changes: 50 additions & 0 deletions src/main/java/am/ik/yavi/core/InheritanceValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright (C) 2018-2023 Toshiaki Maki <makingx@gmail.com>
*
* 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<T, N extends T> implements Validatable<T> {
private final Class<N> nClass;
private final Validatable<N> validator;

public InheritanceValidator(Class<N> nClass, Validatable<N> 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<T> failFast(boolean failFast) {
final Validatable<N> validatable = this.validator.failFast(failFast);
return new InheritanceValidator<>(nClass, validatable);
}

@Override
public boolean isFailFast() {
return this.validator.isFailFast();
}
}
68 changes: 40 additions & 28 deletions src/test/java/am/ik/yavi/core/ConstraintOnClassTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,55 +17,67 @@ public class ConstraintOnClassTest {

@ParameterizedTest
@MethodSource("provideValidators")
void testConstraintOnConditionClass(Validator<User> validator) {
User validAdmin = new Admin("admin123", "admin@gmail", 27, "yavi123");
User invalidAdmin = new Admin("Niraz", "niraz@gmail", 23, "user");
void testConstraintOnConditionClass(Validator<Parent> 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<User> validator) {
User validUser = new User("Rawad", "rawad@gmail", 25);
User invalidUser = new User("Almog", "almog@gmail", 19);
void testConstraintOnNonConditionClass(Validator<Parent> 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<Arguments> provideValidators() {
ValidatorBuilder<User> userValidatorBuilder = ValidatorBuilder.of(User.class)
.constraint(User::getAge, "age", c -> c.greaterThan(20));
Function<CharSequenceConstraint<Admin, String>, CharSequenceConstraint<Admin, String>> startsWithAdmin = (
CharSequenceConstraint<Admin, String> c) -> c.startsWith("yavi");
ValidatorBuilder<Parent> userValidatorBuilder = ValidatorBuilder.of(Parent.class)
.constraint(Parent::getAge, "age", c -> c.greaterThan(20));
Function<CharSequenceConstraint<Child, String>, CharSequenceConstraint<Child, String>> equalsToDrawing = (
CharSequenceConstraint<Child, String> 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;
}
}
}

0 comments on commit 4c5ccff

Please sign in to comment.