2

Context

An application that utilizes Spring 4.1.7. All configurations are in XML files (not using annotations) and I rather keep it that way (but I can change the ways things are done if I must).

Problem

I have created a new class that comes with a builder class.

Now I'd like to inject other beans into this new class. I can probably use lookup-methods and similar solutions to do that and then use the new class's builder in the caller beans to create an instance. However, I rather an instance of this new class to be injected to its caller beans then they creating one through the builder. This is where I'm not sure how I can do that. For example, this looks like an Abstract Factory to me, but I don't know how I can pass those parameters (which are passed to the builder) at runtime to the Abstract Factory and subsequently the factories it builds.

Some code snippets to make the question clearer:

public final class Processor {

    private final StatusEnum newStatus;
    private final Long timeOut;

    // I'd like this to be be injected by Spring through its setter (below)
    private DaoBean daoInstance;

    private Processor() {
        this.newStatus = null;
        this.timeOut = null;
    }

    private Processor(Builder builder) {
        this.newStatus = builder.getNewStatus();
        this.timeOut = builder.getTimeOut();
    }

    // To be called by Spring
    public void setDaoInstance(DaoBean instance) {
        this.daoInstance = instance;
    }

    public void updateDatabase() {
        daoInstance.update(newStatus, timeOut);
    }

    // Builder class
    public static final class Builder {
        private StatusEnum newStatus;
        private Long timeOut;
        // lots of other fields

        public Long getTimeOut() {
             return this.timeOut;
        }

        public StatusEnum getNewStatus() {
             return this.newStatus;
        }

        public Builder withTimeOut(Long timeOut) {
             this.timeOut = timeOut;
             return this;
        }

        public Builder withNewStatus(StatusEnum newStatus) {
             this.newStatus = newStatus;
             return this;
        }

        public Processor build() {
             return new Processor(this);
        }
    }
}

I'd like an instance of "DaoBean" to be injected to the "Processor" class. But to do that, Processor will have to be a bean or otherwise I have to utilize something like lookup-methods. On the other hand, wherever I want to use processor, I have to do something like this:

new Processor.Builder()
   .withTimeOut(1000L)
   .withNewStatus(StatusEnum.UPDATED)
   .build()
   .updateDatabase();

Instead of this, I wonder if I can make the Processor a bean that Spring can inject to its callers whilst maintaining its immutability. An instance of DaoBean can then be injected to the Processor by Spring. That way I'd be able to segregate the wiring code and the business logic.

It's worth mentioning that the Builder has a lot more than 2 fields and not all of them have to be set. This is why I thought an abstract factory is the way to go (building instances of the Processor in different ways).

Amir Keibi
  • 1,991
  • 28
  • 45

1 Answers1

3

One solution, while keeping the builder, would probably be to simply making the Builder itself a Spring bean...

This allows something like this..

@Autowired
private Builder builder;

public void someMethod() {
    Result = builder.withX(...).doSomething();
}

This way, your Result object is immutable, can be created via a nice builder and the builder can inject the Spring bean (dao, in your case) into it without anyone even noticing that it's there.

And the only thing that changes is, that you don't create the builder yourself, but let Spring create it for you...

@Component
@Scope("prototype") // normally a good idea
public static class Builder {
    @Autowired
    private DaoBean dao;

    // your logic here
}

(Same works with JavaConfig or XML config, if you don't want to scan.)

Especially with many combinations, I prefer a builder pattern, since a factory would need complex method signatures. Of course, the builder has the disadvantage that you cannot check at compile time if a given combination of attribute types is at least theoretically acceptable. Ok, you could simulate that with various builders, but that would probably be overkill.

Florian Schaetz
  • 10,454
  • 5
  • 32
  • 58
  • Thanks. What would you suggest I do with the Processor's dependencies (e.g.: DaoBean)? Also, I didn't quite understand what you meant by "the builder has the disadvantage ..". I normally validate the parameters in the build function. – Amir Keibi Aug 28 '16 at 00:54
  • The Processor's dependencies, e.g. DaoBean, get injected into the Builder by Spring and then given to the Processor by the builder. (I tend to make a (potentially private) Constructor that takes the Builder itself, thus removing the need for complex constructor signatures or hidden setter methods). And I just noted that you have no chance of telling anyone "You have the choice of String, String, int or String, int or just int" with the signatures alone (at compile time), so all the checks must be done at runtime (but that's a very minor drawback with TDD). – Florian Schaetz Aug 28 '16 at 05:11