diff --git a/scm-core/src/main/java/sonia/scm/ScmConstraintViolationException.java b/scm-core/src/main/java/sonia/scm/ScmConstraintViolationException.java index 01c628e3dd..a28812eb8a 100644 --- a/scm-core/src/main/java/sonia/scm/ScmConstraintViolationException.java +++ b/scm-core/src/main/java/sonia/scm/ScmConstraintViolationException.java @@ -6,6 +6,22 @@ import java.util.Collection; import static java.util.Collections.unmodifiableCollection; +/** + * Use this exception to handle invalid input values that cannot be handled using + * JEE bean validation. + * Use the {@link Builder} to conditionally create a new exception: + *
+ * Builder
+ *   .doThrow()
+ *   .violation("name or alias must not be empty if not anonymous", "myParameter", "name")
+ *   .violation("name or alias must not be empty if not anonymous", "myParameter", "alias")
+ *   .when(myParameter.getName() == null && myParameter.getAlias() == null && !myParameter.isAnonymous())
+ *   .andThrow()
+ *   .violation("name must be empty if anonymous", "myParameter", "name")
+ *   .when(myParameter.getName() != null && myParameter.isAnonymous());
+ * 
+ * Mind that using this way you do not have to use if-else constructs. + */ public class ScmConstraintViolationException extends RuntimeException implements Serializable { private static final long serialVersionUID = 6904534307450229887L; @@ -19,45 +35,84 @@ public class ScmConstraintViolationException extends RuntimeException implements this.furtherInformation = furtherInformation; } + /** + * The violations that caused this exception. + */ public Collection getViolations() { return unmodifiableCollection(violations); } + /** + * An optional URL for more informations about this constraint violation. + */ public String getUrl() { return furtherInformation; } + /** + * Builder to conditionally create constraint violations. + */ public static class Builder { private final Collection violations = new ArrayList<>(); private String furtherInformation; + /** + * Use this to create a new builder instance. + */ public static Builder doThrow() { return new Builder(); } + /** + * Resets this builder to check for further violations. + * @return this builder instance. + */ public Builder andThrow() { this.violations.clear(); this.furtherInformation = null; return this; } + /** + * Describes the violation with a custom message and the affected property. When more than one property is affected, + * you can call this method multiple times. + * @param message The message describing the violation. + * @param pathElements The affected property denoted by the path to reach this property, + * eg. "someParameter", "complexProperty", "attribute" + * @return this builder instance. + */ public Builder violation(String message, String... pathElements) { this.violations.add(new ScmConstraintViolation(message, pathElements)); return this; } + /** + * Use this to specify a URL with further information about this violation and hints how to solve this. + * This is optional. + * @return this builder instance. + */ public Builder withFurtherInformation(String furtherInformation) { this.furtherInformation = furtherInformation; return this; } - public void when(boolean condition) { + /** + * When the given condition is true, a exception will be thrown. Otherwise this simply resets this + * builder and does nothing else. + * @param condition The condition that indicates a violation of this constraint. + * @return this builder instance. + */ + public Builder when(boolean condition) { if (condition && !this.violations.isEmpty()) { throw new ScmConstraintViolationException(violations, furtherInformation); } + return andThrow(); } } + /** + * A single constraint violation. + */ public static class ScmConstraintViolation implements Serializable { private static final long serialVersionUID = -6900317468157084538L;