problem z z walidacją

0

Witam, mam problem walcze z tym już 2gi dzień. Potrzebuję zwalidować czy taki login już istnieje i tworzę interfejs:

@Documented
@Constraint(validatedBy = UniqueLoginValidator.class)
@Target({ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface UniqueLogin {

    String message() default "This login already exists, please choose another one.";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};

}

następnie klasę:

public class UniqueEmailValidator implements ConstraintValidator<UniqueEmail, User> {

    @Autowired
    private UserService userService;

    @Override
    public void initialize(UniqueEmail uniqueEmail) {
    }

    public boolean isValid(User user, ConstraintValidatorContext context) {

        return !userService.findByEmail(user.getEmail()).isPresent();
    }
}

i niestety wywala mi null pointera - Caused by: java.lang.NullPointerException: null
w dokladnie tym miejscu:

!userService.findByEmail(user.getEmail()).isPresent();

rozbijałem ten kod na części pierwsze i przy właśnie odwołaniu do serwisu jest null. Wszystkie inne funkcjonalności w innych klasach działają tylko w walidatorach mam problem.

Ktoś może mi pomóc?

0

@Stang: obawiam się że nie rozumiesz co robisz... UniqueEmailValidator nie jest komponentem Springa więc nie wstrzyknie Ci tam zalezności więc autowired nie zadziała.
Poza tym ConstraintValidator w tym przypadku to nie jest dobre rozwiązanie, tutaj lepiej zrobić normalnego validatora i nie opierac się o adnotacje...

0

@Stang: dalej nie rozumiem co chcesz zrobić. Ten walidator nie będzie mógł miec dostepu do UserService bo userService nie jest przekazany do niego. Zrób osobna implementacje tej klasy:
https://docs.spring.io/spring[...]ork/validation/Validator.html albo własnego validatora który już będzie komponentem i będziesz mu wstrzyknąc inny bean

0

Tutaj w sumie można by podejść do problemu jeszcze inaczej. Zamiast walidatora springowego czy JSRowego nałożyć ograniczenie na pole na poziomie encji JPA i przechwytywać wyjątek, ale…

… ale to nie będzie dobre rozwiązanie, ponieważ brak unikalności loginu nie jest czymś wyjątkowym. Można to rozwiązać za pomocą jawnej implementacji tego warunku w usłudze. Co też nie jest najlepsze, ale na pewno sensowniejsze, bo lepiej oddaje zamysł biznesowy leżący za tym ograniczeniem.

0

Niestety chyba jestem jeszcze za głupi bo nie mogę sobie poradzić z tymi walidatorami z wstrzykiwaniem. Wiem dlaczego nie mogę tego zrobić ale nie mogę znaleźć żadnego poradnika o walidacji krok po kroku, walidacje typu czy sie hasło zgadza robie bez problemu a z tym miałem taką ścianę...
Poradziłem sobie z tym jedną linijką w kontrolerze:

@PostMapping("/register")
    public String registerNewUser(@Valid User user, BindingResult bindingResult, Model model, RedirectAttributes redirectAttributes) {

if (!userService.uniqueEmail(user.getEmail())) bindingResult.addError(new ObjectError("inValid e-mail", "This e-mail already exists, please choose another one."));

...

z serwisu wyciągam czy już istnieje i tyle, nie waliduje w klasie enity. I tu pytanie, czy ten sposób jest optymalnym rozwiązaniem czy raczej wypadałoby pisać klasę i entity walidować adnotacją?

0

U mnie działa ze Spring Boot 2.1.6.RELEASE & Java 12.

public class MyPojo {

    @MyConstraint
    private String field;

    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }
}
@Documented
@Constraint(validatedBy = MyValidator.class)
@Target( { ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface MyConstraint {
    String message() default "Invalid String";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
public class MyValidator implements ConstraintValidator<MyConstraint, String> {

    @Autowired
    private MyService service;

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (value == null) {
            return true;
        }

        return service.m(value);
    }

    @Override
    public void initialize(MyConstraint constraintAnnotation) {

    }
}
@Service
public class MyService {
    public boolean m(String s) {
        return "a".equals(s);
    }
}
@RestController
public class MyController {

    @PostMapping("/")
    public String m(@Validated @RequestBody MyPojo body) {
        return "ok";
    }
}
@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

Testy manualne:

request:

POST http://localhost:8080
Accept: application/json
Content-Type: application/json

{
    "field": "a"
}

response:

POST http://localhost:8080

HTTP/1.1 200 
Content-Type: application/json;charset=UTF-8
Content-Length: 2
Date: Wed, 19 Jun 2019 20:41:45 GMT

ok

request:

POST http://localhost:8080
Accept: application/json
Content-Type: application/json

{
    "field": "b"
}

response:

POST http://localhost:8080

HTTP/1.1 400 
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 19 Jun 2019 20:46:14 GMT
Connection: close

{
    (...)
    "defaultMessage": "Invalid String",
    (...)
}

6 lat temu, podczas nauki Javy, napisałem CRUDa z webówką na jsp i też mi działało do walidacji formularza (Spring 4.1.4.RELEASE bez Boot, Java 8). Nawet use case ten sam:

public class EmailAvailableValidator implements ConstraintValidator<EmailAvailable, String> {

    @Resource
    private UserService userService;

    public void initialize(EmailAvailable constraintAnnotation) {}

    public boolean isValid(String object, ConstraintValidatorContext constraintContext) {

        if (object == null)
            return true;

        return userService.isEmailAvailable(object);
    }
}
0

Jakiej implmentacji ValidatorFactory używasz? Spring Boot powinien skonfigurować domyślnie tą dzięki której możemy wstrzykiwać serwisy do ConstraintValidator, ale może masz nadpisaną konfigurację na inną.

Zobacz czy dodanie poniższego pomoże:

        @Bean
        public Validator validatorFactory () {
            return new LocalValidatorFactoryBean();
        }

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0