From dca73ee137b3fc31ac2e7fc5a3afc223f9ba6327 Mon Sep 17 00:00:00 2001 From: Oliver Drotbohm Date: Wed, 18 Dec 2024 19:17:01 +0100 Subject: [PATCH] GH-995 - Allow filtering violations. --- .../modulith/core/ApplicationModule.java | 1 - .../modulith/core/Violation.java | 86 +++++++++++++++++++ .../modulith/core/Violations.java | 30 +++++-- .../modulith/core/ViolationsUnitTests.java | 10 +++ 4 files changed, 120 insertions(+), 7 deletions(-) create mode 100644 spring-modulith-core/src/main/java/org/springframework/modulith/core/Violation.java diff --git a/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModule.java b/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModule.java index b7ffa212..468e1239 100644 --- a/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModule.java +++ b/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModule.java @@ -40,7 +40,6 @@ import org.springframework.lang.Nullable; import org.springframework.modulith.core.Types.JMoleculesTypes; import org.springframework.modulith.core.Types.JavaTypes; import org.springframework.modulith.core.Types.SpringTypes; -import org.springframework.modulith.core.Violations.Violation; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.util.function.SingletonSupplier; diff --git a/spring-modulith-core/src/main/java/org/springframework/modulith/core/Violation.java b/spring-modulith-core/src/main/java/org/springframework/modulith/core/Violation.java new file mode 100644 index 00000000..79aeee54 --- /dev/null +++ b/spring-modulith-core/src/main/java/org/springframework/modulith/core/Violation.java @@ -0,0 +1,86 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.modulith.core; + +import java.util.Objects; + +import org.springframework.util.Assert; + +/** + * An individual architectural violation. + * + * @author Oliver Drotbohm + * @since 1.3.1 + */ +public class Violation { + + final String message; + + Violation(String message) { + this.message = message; + } + + /** + * Returns the violation message. + * + * @return the message + */ + public String getMessage() { + return message; + } + + /** + * Returns whether the {@link Violation}'s message contains the given candidate. + * + * @param candidate must not be {@literal null} or empty. + */ + public boolean hasMessageContaining(String candidate) { + + Assert.hasText(candidate, "Candidate must not be null or empty!"); + + return message.contains(candidate); + } + + /* + * (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return message; + } + + /* + * (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + + return this == obj + || obj instanceof Violation that + && Objects.equals(this.message, that.message); + } + + /* + * (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return Objects.hashCode(message); + } +} \ No newline at end of file diff --git a/spring-modulith-core/src/main/java/org/springframework/modulith/core/Violations.java b/spring-modulith-core/src/main/java/org/springframework/modulith/core/Violations.java index 258c005b..911ac5d1 100644 --- a/spring-modulith-core/src/main/java/org/springframework/modulith/core/Violations.java +++ b/spring-modulith-core/src/main/java/org/springframework/modulith/core/Violations.java @@ -20,6 +20,7 @@ import static java.util.stream.Collectors.*; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.function.Predicate; import java.util.stream.Collector; import java.util.stream.Collectors; @@ -57,7 +58,7 @@ public class Violations extends RuntimeException { * @return will never be {@literal null}. */ static Collector toViolations() { - return mapping(Violation::new, collectingAndThen(Collectors.toList(), Violations::new)); + return mapping(Violation::new, newViolations()); } /* @@ -68,7 +69,7 @@ public class Violations extends RuntimeException { public String getMessage() { return violations.stream() // - .map(Violation::message) // + .map(Violation::getMessage) // .collect(Collectors.joining("\n- ", "- ", "")); } @@ -81,7 +82,7 @@ public class Violations extends RuntimeException { public List getMessages() { return violations.stream() // - .map(Violation::message) + .map(Violation::getMessage) .toList(); } @@ -104,6 +105,21 @@ public class Violations extends RuntimeException { } } + /** + * Returns {@link Violations} that match the given {@link Predicate}. + * + * @param filter must not be {@literal null}. + * @return + */ + public Violations filter(Predicate filter) { + + Assert.notNull(filter, "Filter must not be null!"); + + return violations.stream() + .filter(filter) + .collect(newViolations()); + } + /** * Creates a new {@link Violations} with the given {@link RuntimeException} added to the current ones? * @@ -142,14 +158,16 @@ public class Violations extends RuntimeException { var result = new ArrayList<>(left); - var messages = left.stream().map(Violation::message).toList(); + var messages = left.stream().map(Violation::getMessage).toList(); right.stream() - .filter(it -> !messages.contains(it.message())) + .filter(it -> !messages.contains(it.message)) .forEach(result::add); return result.size() == left.size() ? left : result; } - static record Violation(String message) {} + private static Collector newViolations() { + return collectingAndThen(Collectors.toList(), Violations::new); + } } diff --git a/spring-modulith-core/src/test/java/org/springframework/modulith/core/ViolationsUnitTests.java b/spring-modulith-core/src/test/java/org/springframework/modulith/core/ViolationsUnitTests.java index a86aa280..e2243756 100644 --- a/spring-modulith-core/src/test/java/org/springframework/modulith/core/ViolationsUnitTests.java +++ b/spring-modulith-core/src/test/java/org/springframework/modulith/core/ViolationsUnitTests.java @@ -51,4 +51,14 @@ class ViolationsUnitTests { assertThat(violations.getMessages()) .containsExactlyInAnyOrder("First", "Second", "Third"); } + + @Test // GH-995 + void allowsFilteringViolations() { + + var violations = Violations.NONE.and("First").and("Second") + .filter(it -> it.hasMessageContaining("Sec")); + + assertThat(violations.getMessages()) + .containsExactly("Second"); + } }