This project demonstrates a clean and scalable implementation of the Specification Pattern in Java 21, applying the Open-Closed Principle (from the SOLID principles) to filter a dynamic product catalog of over 1500 items.
It’s built with Gradle, features functional composition (AND, NOT), and includes a dynamic, adaptive test suite using JUnit 5.
- ✅ Java 21 + Gradle
- ✅ Custom
Specification<T>interface - ✅ Dynamic filtering by:
- Color
- Size
- Price thresholds
- Stock availability
- ✅ Functional-style composition (AND / NOT)
- ✅ Fluent utility
Specsbuilder - ✅ 1500+ randomly generated products
- ✅ Adaptive and resilient unit tests with JUnit 5
vendomita/
├── build.gradle
├── settings.gradle
├── README.md
├── src/
│ ├── main/
│ │ └── java/com/terabyte/specfilter/
│ │ ├── App.java
│ │ ├── model/
│ │ ├── spec/
│ │ └── util/
│ └── test/
│ └── java/com/terabyte/specfilter/
│ └── ProductFilterTest.java
- Java 21
- Gradle 8.x (or use the wrapper
./gradlew)
git clone https://github.com/darklatiz/vendomita.git
cd vendomita
./gradlew build
./gradlew testThe main app will generate 15000 random products and filter them using composed specifications (e.g., in stock AND price < 1000).
If you get a “no main class” error, make sure your build.gradle contains:
application {
mainClass = 'com.terabyte.specfilter.App'
}This project uses JUnit 5 with adaptive assertions (no hardcoded values) based on the generated data.
./gradlew testAll test cases will pass dynamically even as the dataset changes with every execution.
This pattern helps you decouple business rules from filtering logic and supports:
- Composability (
AND,OR,NOT) - Testability (unit test each rule independently)
- Reusability (use rules in different contexts: APIs, batch, etc.)
- Extensibility (Open-Closed Principle in action)
Instead of writing dozens of filterByXAndYAndZ() methods, you can combine small specs dynamically.
Specification<Product> spec = Specs.and(
new InStockSpecification(),
new PriceLessThanSpecification(BigDecimal.valueOf(1000)),
new SizeSpecification(Size.MEDIUM)
);
productFilter.filter(products, spec)
.forEach(p -> System.out.println("MATCH: " + p.name()));Laboratorios Terabyte Built with ❤️ by @darklatiz
This project is licensed under the MIT License.