Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom constraint with dependencies #12

Closed
enricosecondulfo opened this issue Mar 7, 2019 · 8 comments
Closed

Custom constraint with dependencies #12

enricosecondulfo opened this issue Mar 7, 2019 · 8 comments
Labels
question Further information is requested

Comments

@enricosecondulfo
Copy link

Hello,
thank you so much for your great work, i need to validate a dto based on the presence or absence of an object contained within mongodb. In this case I need to inject a repository. How can I do this with yavi?

@making
Copy link
Owner

making commented Mar 7, 2019

@enricosecondulfo Can you provide a sample code?

@enricosecondulfo
Copy link
Author

enricosecondulfo commented Mar 15, 2019

I'm sorry to answer that now. I'll give you a very common example of a custom validation that I often use:

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = NotExistsValidator.class)
public @interface NotExists {

    String message() default "already exists";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    String parameter() default "";

    Class<?> clazz() default String.class;
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class NotExistsValidator implements ConstraintValidator<NotExists, Object> {

    @Autowired
    private MongoOperations mongoOperations;

    private NotExists constraintAnnotation;

    @Override
    public void initialize(NotExists constraintAnnotation) {
        this.constraintAnnotation = constraintAnnotation;
    }

    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {
        Criteria criteria = Criteria.where(this.constraintAnnotation.parameter()).is(value);
        return !this.mongoOperations.exists(new Query(criteria), this.constraintAnnotation.clazz());
    }
}

Thank your so much

@enricosecondulfo
Copy link
Author

@making Can i archive this? Thank you

@making
Copy link
Owner

making commented Mar 18, 2019

I think you can do if you define the validator in the constructor of the controller or service class after MongoOpearation injected

@enricosecondulfo
Copy link
Author

@making Could you give me a practical example of how to create such a custom validation, please?

@making
Copy link
Owner

making commented Mar 18, 2019

@enricosecondulfo

public class Foo {

    private final String id;

    public Foo(String id) {
        this.id = id;
    }

    public String getId() {
        return id;
    }
}
import am.ik.yavi.core.ConstraintViolations;
import am.ik.yavi.core.Validator;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.function.Function;

@RestController
public class FooController {

    private final FooService fooService;

    private final Validator<Foo> validator;

    public FooController(FooService fooService) {
        this.fooService = fooService;
        this.validator = Validator.<Foo>builder()
            .constraintOnObject(Function.identity(), "foo.id", c -> c.predicate(new FooCustomConstraint(this.fooService)))
            .build();
    }

    @PostMapping("/{id}")
    public Object post(@PathVariable("id") Foo foo) {
        return this.validator.validateToEither(foo)
            .fold(ConstraintViolations::details, x -> "OK");
    }
}
import am.ik.yavi.core.CustomConstraint;

public class FooCustomConstraint implements CustomConstraint<Foo> {

    private final FooService fooService;

    public FooCustomConstraint(FooService fooService) {
        this.fooService = fooService;
    }

    @Override
    public String messageKey() {
        return "foo.unique";
    }

    @Override
    public String defaultMessageFormat() {
        return "{0} must be unique.";
    }

    @Override
    public boolean test(Foo foo) {
        return !this.fooService.isExists(foo);
    }
}
import org.springframework.stereotype.Service;

@Service
public class FooService {

    public boolean isExists(Foo foo) {
        return "1".equals(foo.getId());
    }
}

@enricosecondulfo
Copy link
Author

@making thank you a lot, the example is very clear and exhaustive

@making making added the question Further information is requested label Mar 18, 2019
@making
Copy link
Owner

making commented Mar 18, 2019

You're welcome

@making making closed this as completed Mar 18, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants