Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 37 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,46 @@
## Description
Provides a variety of components that reduce the overhead of composing and maintaining Specifications.

SpecificationFactory is used to generate Specification instances. It encapsulates anonymous Specification subclasses and provides null-safe handling.
[SpecificationFactory ](https://github.com/quinnandrews/spring-data-specification-builder/blob/a93b9a84805d3c20b1461ca634abd3a50695d245/src/main/java/io/github/quinnandrews/spring/data/specification/builder/SpecificationFactory.java)is used to generate Specification instances. It encapsulates anonymous Specification subclasses and provides null-safe handling.

SpecificationBuilder puts a fluent API on top of SpecificationFactory to compose compound Specifications with ease.
[SpecificationBuilder](https://github.com/quinnandrews/spring-data-specification-builder/blob/a93b9a84805d3c20b1461ca634abd3a50695d245/src/main/java/io/github/quinnandrews/spring/data/specification/builder/SpecificationBuilder.java) puts a fluent API on top of SpecificationFactory to compose compound Specifications with ease.

SpecificationUtil is used by SpecificationFactory to assist with null checking, wildcard detection and String conversions, etc.
[SpecificationUtil](https://github.com/quinnandrews/spring-data-specification-builder/blob/a93b9a84805d3c20b1461ca634abd3a50695d245/src/main/java/io/github/quinnandrews/spring/data/specification/builder/SpecificationUtil.java) is used by SpecificationFactory to assist with null checking, wildcard detection and String conversions, etc.

The Specifications Annotation is available as a convenience, an alias of Spring's Component Annotation to mark Specification Beans as a distinct type.
The [Specifications Annotation](https://github.com/quinnandrews/spring-data-specification-builder/blob/a93b9a84805d3c20b1461ca634abd3a50695d245/src/main/java/io/github/quinnandrews/spring/data/specification/annotations/Specifications.java) is available as a convenience, an alias of Spring's Component Annotation to mark Specification Beans as a particular kind of Bean.

SpecificationFactory and SpecificationUtil may be used independently, if desired. However, the intent is to use SpecificationBuilder exclusively, without being aware of either SpecificationFactory or SpecificationUtil, but it is not mandatory. Both SpecificationFactory and SpecificationUtil are declared with public access.

## Features

- Built-in null handling makes conditional query composition simple and easy – no need to wrap Specification conjunctions with a check for parameter state when parameters are optional.
- Built-in support for efficient eager fetching provides query optimization – an entire Aggregate can be loaded with one query instead of many.
- A fluent API encapsulating boilerplate code makes queries that are both strongly typed and easy to read – the risk of error is reduced while comprehension of query logic is enhanced.
- A `@Specifications` Annotation complements Spring's `@Controller`, `@Service` and `@Repository` Annotations, allowing one to declare Specification Beans in a similar fashion and being able to identify these kinds of Beans for special use cases, like when defining rules with ArchUnit, for example.
- A fluent API encapsulating boilerplate code makes queries that are both strongly typed and easy to read – the risk of error is reduced while query logic is more coherent.
- A `@Specifications` Annotation complements Spring's `@Controller`, `@Service` and `@Repository` AnnotationsSpecification Beans can be identified as a special kind of Bean by both developers and processes (like the execution of rules with [ArchUnit](https://github.com/TNG/ArchUnit), for example).

## Requirements
### Java 17
https://adoptium.net/temurin/releases/?version=17

### Hibernate JPA Metamodel Generator (or equivalent)
https://hibernate.org/orm/tooling/

Add the Hibernate JPA Metamodel Generator to the Maven Compiler Plugin as an Annotation Processor:
```xml
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>6.3.1.Final</version>
</dependency>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>6.3.1.Final</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
```

## Dependencies
Expand All @@ -44,12 +55,12 @@ Add this project's artifact to your project as a dependency:
<dependency>
<groupId>io.github.quinnandrews</groupId>
<artifactId>spring-data-specification-builder</artifactId>
<version>1.0.0</version>
<version>2.0.0</version>
</dependency>
```
(NOTE: This project's artifact is NOT yet available in Maven Central, but is available from GitHub Packages.)

Then extend your Repository Interfaces with JPASpecificationExecutor:
Then extend your Repository Interfaces with JPASpecificationExecutor so that Specification methods are available:
```java
import io.github.quinnandrews.spring.data.specification.builder.application.data.guitarpedals.GuitarPedal;
import org.springframework.data.jpa.repository.JpaRepository;
Expand All @@ -61,7 +72,7 @@ public interface GuitarPedalRepository extends JpaRepository<GuitarPedal, Long>,
JpaSpecificationExecutor<GuitarPedal> {
}
```
Next, define your Specifications:
Next, define your Specifications in a Specifications Bean (this is optional – you can also define Specification queries where they are used, in a Service, a Test, etc.)

```java
import io.github.quinnandrews.spring.data.specification.annotations.Specifications;
Expand Down Expand Up @@ -111,26 +122,26 @@ public class GuitarPedalService {
```

## Examples
The examples and tests use the Domain of Guitar Pedals (I'm also a musician and I enjoy exploring the vast array of sounds offered by the world of guitar pedals). It was simply more fun than using the Domains of TODOs or Employees, for example.
The examples and tests use the Domain of Guitar Pedals (I'm a musician). It was simply more fun than using the Domains of TODOs or Employees.

### GuitarPedalSpecifications.class
GuitarPedalSpecifications contains the most comprehensive set of examples. It compares defining the same queries with and without the SpecificationBuilder, details gotchas and goes into more complex things like working with collections, for instance. Begin from the top and work your way down.
[GuitarPedalSpecifications](https://github.com/quinnandrews/spring-data-specification-builder/blob/a93b9a84805d3c20b1461ca634abd3a50695d245/src/test/java/io/github/quinnandrews/spring/data/specification/builder/application/data/guitarpedals/specifications/GuitarPedalSpecifications.java) contains the most comprehensive set of examples. It compares defining the same queries with and without the SpecificationBuilder, details gotchas and goes into more complex things like working with collections, for instance. Begin from the top and work your way down.

### GuitarPedalSpecificationsIntegrationTest.class
GuitarPedalSpecificationsIntegrationTest contains the Integrations Tests of the examples in GuitarPedalSpecifications. This may be useful to look at as well, or to run the examples yourself and see the sql output with your own eyes.
[GuitarPedalSpecificationsIntegrationTest](https://github.com/quinnandrews/spring-data-specification-builder/blob/a93b9a84805d3c20b1461ca634abd3a50695d245/src/test/java/io/github/quinnandrews/spring/data/specification/builder/GuitarPedalSpecificationsIntegrationTest.java) contains the Integrations Tests of the examples in GuitarPedalSpecifications. This may be useful to look at as well, or to run the examples yourself and see the sql output with your own eyes.

### SpecificationBuilderIntegrationTest.class
SpecificationBuilderIntegrationTest contains Integration Tests for the methods in SpecificationBuilder. Some of these tests cover cases that are not included in GuitarPedalSpecifications.
[SpecificationBuilderIntegrationTest](https://github.com/quinnandrews/spring-data-specification-builder/blob/a93b9a84805d3c20b1461ca634abd3a50695d245/src/test/java/io/github/quinnandrews/spring/data/specification/builder/SpecificationBuilderIntegrationTest.java) contains Integration Tests for the methods in SpecificationBuilder. Some of these tests cover cases that are not included in GuitarPedalSpecifications.

### Other Test Classes
SpecificationBuilderTest, SpecificationFactoryTest and SpecificationUtilTest contain Unit Tests for the methods in their corresponding Classes. These may useful to look at as well, in order to understand more about how things work under the hood, but it is not necessary.
[SpecificationBuilderTest](https://github.com/quinnandrews/spring-data-specification-builder/blob/a93b9a84805d3c20b1461ca634abd3a50695d245/src/test/java/io/github/quinnandrews/spring/data/specification/builder/SpecificationBuilderTest.java), [SpecificationFactoryTest](https://github.com/quinnandrews/spring-data-specification-builder/blob/a93b9a84805d3c20b1461ca634abd3a50695d245/src/test/java/io/github/quinnandrews/spring/data/specification/builder/SpecificationFactoryTest.java) and [SpecificationUtilTest](https://github.com/quinnandrews/spring-data-specification-builder/blob/a93b9a84805d3c20b1461ca634abd3a50695d245/src/test/java/io/github/quinnandrews/spring/data/specification/builder/SpecificationUtilTest.java) contain Unit Tests for the methods in their corresponding Classes. These may be useful to look at as well, in order to understand more about how things work under the hood, but it is not necessary.

## Roadmap
1) ~~**Add `and()` Methods in the Builder**<br>
Add `and()` Methods to make the fluent-API more fluent & legible, and to better resemble the Specification Interface.~~
2) **Build Specifications on Associations**<br>
1) **Build Specifications on Associations**<br>
Add versions of `where` methods that operate on Associations. It is expected the builder will need to maintain an instance variable containing Joins already created, so that they can be re-used during the build process if there is more than one Specification to apply to an Association.
3) **Define JoinType of Associations**<br>
Add versions of `withFetch()` that allow definition of JoinType. Should it be applied to `where` methods on Associations as well?
4) **Consider Adding a `not()` Method in the Builder**
5) **Consider Adding a `clear()` Method in the Builder**
2) **Define JoinType of Associations**<br>
Add versions of `fetchOf()` that allow definition of JoinType. (Should it be applied to `where` methods on Associations as well?)
3) **Add a `not()` Method in the Builder**
4) **Add a `clear()` Method in the Builder**
5) **Implement a SortBuilder to complement the SpecificationBuilder**<br/>
Implement with the same sort of fluent-api and require Attributes instead of Strings for type safety.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@

import java.lang.annotation.*;

/**
* An alias of {@link Component @Component} indicating that the
* annotated class contains Specifications. Complements
* {@link org.springframework.stereotype.Controller @Controller},
* {@link org.springframework.stereotype.Service @Service}, and
* {@link org.springframework.stereotype.Repository @Repository}.
*
* @author Quinn Andrews
* @see Component
* @see org.springframework.stereotype.Controller
* @see org.springframework.stereotype.Service
* @see org.springframework.stereotype.Repository
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
Expand Down
Loading