devonfw / IDEasy

Tool to automate the setup and updates of a development environment for any project (Successor of devonfw-ide).
Apache License 2.0
7 stars 18 forks source link

Introduce ValidationState #438

Open hohwille opened 3 days ago

hohwille commented 3 days ago

Currently our validation is not implemented well: https://github.com/devonfw/IDEasy/blob/eae8fd2796e382f6ff84def23cb6ca550d760930/cli/src/main/java/com/devonfw/tools/ide/commandlet/Commandlet.java#L202-L216 https://github.com/devonfw/IDEasy/blob/eae8fd2796e382f6ff84def23cb6ca550d760930/cli/src/main/java/com/devonfw/tools/ide/property/Property.java#L456-L467

So we have validation result as boolean and also the concept to throw an exception if the validation fails in a properties validator. Both approaches are not well designed.

Instead we should create an interface ValidationResult

public interface ValidationResult {
  boolean isValid();

  String getErrorMessage();
}

Then we can create an implementation ValidationState:

public class ValidationState implements ValidationResult {
  private final StringBuilder errorMessage;

  public boolean isValid() {
    return (this.errorMessage == null);
  }

  public String getErrorMessage() {
    if (this.errorMessage == null) {
      return null;
    }
    return this.errorMessage.toString();
  }

  public void addErrorMessage(String error) {
    if (this.errorMessage == null) {
      this.errorMessage = new StringBuilder(error.length());
    } else {
      this.errorMessage.append('\n');
    }
    this.errorMessage.append(error);
  }
}

This is just a design suggestion as starting point. We can also have a immutable implementation(s) of ValidationResult and have a ValidationResult toResult() method in ValidationState.

The final idea is that internal validation methods will take a ValidationState object as argument. This also applies for the validators of the Property classes. Here we need to change from Consumer<V> to a custom interface:

@FunctionalInterface
public interface PropertyValidator<V> {
  void validate(V value, ValidationState validationState);
}

The main API should take no argument and return ValidationResult.

An alternative approach is to skip the ValidationState and always return ValidationState and then add some aggregation logic that can compose multiple ValidationState objects into one. IMHO the latter approach is slightly more complex.

hohwille commented 3 days ago

FYI: some inspiration for more complex design: