Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: method-chaining and dependency injection

Is it acceptable to use method-chaining, when working with a service that is managed by a dependency injection framework (say HK2)?

I'm unsure if it is allowed to "cache" the instance, even if its only within the scope of the injection.

Example Service that creates a pizza:

@Service
public class PizzaService {

    private boolean peperoni = false;
    private boolean cheese = false;
    private boolean bacon = false;

    public PizzaService withPeperoni() {
        peperoni = true;
        return this;
    }

    public PizzaService withCheese() {
        cheese = true;
        return this;
    }

    public PizzaService withBacon() {
        bacon = true;
        return this;
    }

    public Pizza bake() {
        // create the instance and return it
    }
}

Here the service is injected into a JAX-RS resource:

@Path('pizza')
public class PizzaResource {

    @Inject
    PizzaService pizzaService;

    @GET
    public Response getPizza() {
        Pizza pizza = pizzaService
            .withPeperoni()
            .withCheese()
            .bake();

        return Response.ok(pizza).build();
    }
}
like image 359
Hank Avatar asked Oct 30 '22 03:10

Hank


1 Answers

What you are doing has a side effect for all other users of the service. They all share the same instance of the service, so if you call withPeperoni it will change the value of that boolean for all those who have a reference to the service.

What you seem to want is to use a Builder. Perhaps your service can instantiate a new builder that will have the responsibility to build the perfect pizza for you. That way you avoid all possible side effects :

@GET
public Response getPizza() {
    Pizza pizza = pizzaService.newPizzaBuilder()
        .withPeperoni()
        .withCheese()
        .bake();

    return Response.ok(pizza).build();
}

And PizzaBuilder :

public class PizzaBuilder {

    private boolean peperoni = false;
    private boolean cheese = false;
    private boolean bacon = false;

    public PizzaBuilder withPeperoni() {
        peperoni = true;
        return this;
    }

    public PizzaBuilder withCheese() {
        cheese = true;
        return this;
    }

    public PizzaBuilder withBacon() {
        bacon = true;
        return this;
    }

    public Pizza bake() {
        // create the instance and return it
    }
}

And PizzaService :

@Service
public class PizzaService {

    public PizzaBuilder newPizzaBuilder() {
        return new PizzaBuilder();
    }
}

This solution is not perfect, because there is not much use of a service that only instantiates a Builder, however it at least prevents the side effects you'll encounter with your solution.

like image 127
zlandorf Avatar answered Nov 15 '22 03:11

zlandorf