problem z z walidacją

problem z z walidacją
ST
  • Rejestracja:prawie 9 lat
  • Ostatnio:prawie 2 lata
  • Postów:75
0

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

Kopiuj
@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ę:

Kopiuj
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:

Kopiuj
!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?

Koziołek
Moderator
  • Rejestracja:prawie 18 lat
  • Ostatnio:13 dni
  • Lokalizacja:Stacktrace
  • Postów:6821
0

Sięgam tam, gdzie wzrok nie sięga… a tam NullPointerException
ST
Mam walidację zgodności haseł i jest ok bo bez wstrzykiwania niczego dlatego wiem że coś w tym kierunku jest nie tak. Myslalem że będzie prosto i przyjemnie ale widzę że nie za bardzo. A to jest moja pierwsza walidacja której się staram nauczyć
S9
  • Rejestracja:ponad 10 lat
  • Ostatnio:6 miesięcy
  • Lokalizacja:Warszawa
  • Postów:3573
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...


"w haśle <młody dynamiczny zespół> nie chodzi o to ile masz lat tylko jak często zmienia się skład"
ST
Rozumiem że nie jest komponentem ale tonący brzytwy się chwyta. Adnotacja wydawała się najszybsza i najmniej skomplikowana
jarekr000000
Kolizja szkół magicznych. Ojojoj. Jak mi przykro...
S9
  • Rejestracja:ponad 10 lat
  • Ostatnio:6 miesięcy
  • Lokalizacja:Warszawa
  • Postów:3573
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/docs/current/javadoc-api/org/springframework/validation/Validator.html albo własnego validatora który już będzie komponentem i będziesz mu wstrzyknąc inny bean


"w haśle <młody dynamiczny zespół> nie chodzi o to ile masz lat tylko jak często zmienia się skład"
Koziołek
Moderator
  • Rejestracja:prawie 18 lat
  • Ostatnio:13 dni
  • Lokalizacja:Stacktrace
  • Postów:6821
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.


Sięgam tam, gdzie wzrok nie sięga… a tam NullPointerException
ST
  • Rejestracja:prawie 9 lat
  • Ostatnio:prawie 2 lata
  • Postów:75
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:

Kopiuj
@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ą?

KA
  • Rejestracja:około 9 lat
  • Ostatnio:prawie 6 lat
  • Postów:51
0

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

Kopiuj
public class MyPojo {

    @MyConstraint
    private String field;

    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }
}
Kopiuj
@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 {};
}
Kopiuj
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) {

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

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

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

}

Testy manualne:

request:

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

{
    "field": "a"
}

response:

Kopiuj
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:

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

{
    "field": "b"
}

response:

Kopiuj
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:

Kopiuj
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);
    }
}
edytowany 4x, ostatnio: Karister
S8
  • Rejestracja:ponad 6 lat
  • Ostatnio:8 miesięcy
  • Postów:63
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:

Kopiuj
        @Bean
        public Validator validatorFactory () {
            return new LocalValidatorFactoryBean();
        }
edytowany 1x, ostatnio: Seti87

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.