I am building a Spring Boot project for work. In this project I have service which is tasked with getting certain Documents from another backend. There a quite a lot of different scenarios where the documents have to meet certain criteria e.g. be from a certain date, which can be matched freely. Currently this is accomplished with normal method like so:
@Service
public class DocumentService(){
private OtherService otherService;
@Autowire
public DocumentService(OtherService otherService){
this.otherService = otherService;
}
public List<Document> getDocuments() {
...
}
public List<Document> getDocuments(LocalDate date) {
...
}
public List<Document> getDocuments(String name){
...
}
public List<Document> getDocuments(String name, LocalDate date){
...
}
}
I find this to be a rather bad solution because for every new combination there would need to be a new method. For that reason I'd like to use a fluent style interface for that, something like this:
//Some other class that uses DocumentService
documentService().getDocuments().withDate(LocalDate date).withName(String name).get();
I'm familiar with the Builder Pattern and method chaining but I don't see a way how I can adapt either one of those. Seeing as, per my understanding, @Service-classes are singletons in Spring Boot.
Is this at all possible with Spring Boot?
Doesn't have to be a Spring Boot solution, why not just introduce a POJO builder-like local class:
@Service
public class DocumentService(){
public Builder documents() {
return new Builder();
}
public class Builder {
private LocalDate date;
private String name;
public Builder withDate(LocalDate date) {
this.date = date;
return this;
}
// etc
public List<String> get() {
final List<SomeDTO> results = otherService.doQuery(name, date, ...);
// TODO - tranform DTO to List<String>
return list;
}
}
}
Obviously make it static if it doesn't need access to the parent component.
You could make the Spring component and the builder be the same object but that does feel contrived, also I expect you would like to be able to support multiple builders.
Also I'm assuming the parent component is genuinely a service, i.e. it doesn't contain any state or mutators, otherwise you are introducing potential synchronization problems.
EDIT: Just for illustration the builder maintains the arguments to be passed to the otherService
and performs any service-like transforms.