Walidacja i problem z optional boolean

0

Mam encję z następującymi metodami:

public Optional<Boolean> isDescriptionLengthCorrect(final TextLengthValidator validator) {

       return Optional
               .ofNullable(validator)
               .map(validatorArg -> validatorArg.isCorrect(description));
    }

    public Optional<Boolean> isDuplicate(final TaskDuplicateValidator validator) {

      return Optional.ofNullable(validator)
               .map(validatorArg -> validatorArg.isDuplicate(description));
    }

Jak teraz połączyć to w serwisie w metodzie agregującej, która ma zwróci wartość boolean/Optional<boolean> na podstawie prawdziwości tych 2 warunków?

1

Monady łączy się za pomocą flatMap

var dlcOpt = isDescriptionLengthCorrect(tlValidator);
var dOpt = isDuplicate(tdValidator);

var flattenedOpt = dlcOpt.flatMap ( alc -> 
  dOpt.map ( d ->
    alc && d
  )
)
2

Moim zdaniem to jakis srogi WTF. Ja bym sugerował jednak interfejs w stylu Either<Error, T> validate(T object) który dla obiektu T zwraca albo błąd walidacji albo oryginalny obiekt. Bo taki Optional<Boolean> to nie bardzo rozumiem co ci sensownego powie.

I z takimi walidatorami możesz sobie je wygodnie składać flatMap

A zamiast przekazywania nulli w argumentach i bawienia się w Optional.ofNullable() może lepiej zrobić FalseValidator który zawsze failuje i używać go jako defaultu i dzięki temu nigdy nie musieć się zastanawiać czy coś jest gdzieś nullem? (ewentualnie analogicznie TrueValidator w zalezności od tego jaki chcemy mieć domyślny efekt).

0
Shalom napisał(a):

Moim zdaniem to jakis srogi WTF.

Racja, na to nie spojrzałem

Ja bym sugerował jednak interfejs w stylu Either<Error, T> validate(T object) który dla obiektu T zwraca albo błąd walidacji albo oryginalny obiekt. Bo taki Optional<Boolean> to nie bardzo rozumiem co ci sensownego powie.

Either<Error, T> jest dobry. Either<List<Error>, T> jeszcze lepszy. Ale jeśli Opa nie interesuje typ zwracany (bo to tylko walidacja) to można to zrobić na samej liście:

public List<Error> isDescriptionLengthCorrect(final TextLengthValidator validator) {
  return validatorArg.isCorrect(description) ? List.of(ERROR.LENGHT_IS_NOT_CORRECT) : List.of();
}

public List<Error> isDuplicate(final TaskDuplicateValidator validator) {
  return validatorArg.isDuplicate(description) ? List. of(ERROR.DUPLICATED_TASK) : List.of();
}

A potem:

var dlcErrors = isDescriptionLengthCorrect(tlValidator);
var dErrors = isDuplicate(tdValidator);
var errors = Stream.concat(dlcErrors.stream(), dErrors.stream()).collect(Collectors.toList());

if (errors.isEmpty()) {
  log.info("Every thinks is OK)
} else {
  log.error("Some errors :" + errors")
}
0

Macie racje. Optional tu nie ma racji bytu.

1

Jak jesteśmy w temacie walidacji - to wiadomo, że Either jest zwykle lepszy od Option (na Optional z java.util nie patrze nawet).
Ale zwykle najsensowniejszy jest Validation http://baeldung.com/vavr-validation-api
Ma bardziej przyjazne do walidacji API: zwracanie wiele błędów na raz + dodatkowe API/goodies. (combine, For).

0

Ogólnie Optional<Boolean> to jest taki twór, że zamiast dwóch możesz otrzymać trzy rezultaty i przeważnie 2 z nich chcesz obsłużyć tak samo

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