Dependency Injection

SeedStack development model is based on the dependency injection principle where the dependencies of a class are injected in it by the framework instead of looked up.

You use the javax.inject standard in application code. Injection is done by applying the @Inject annotation on fields, constructors or methods.

The Java type at the injection point determines what to inject.
If present, generic parameters are taken into account.

Objects created with new are not injected automatically.
Only instances created by the framework are injected automatically.

By field

Edit the HelloResource class to inject the Application framework interface in a field:

package org.generated.project.interfaces.rest;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import org.generated.project.application.MyConfig;
import org.seedstack.seed.Application;

@Path("hello")
public class HelloResource {
    @Inject
    private Application application;

    @GET
    public String hello() {
        MyConfig myConfig = application.getConfiguration()
                .get(MyConfig.class);
        return "Hello " + myConfig.getNames().get(0) + "!";
    }
}

Field injection is very concise (which is why it is used in the documentation) but does not play well with testing and does not allow the creation of immutable objects.

By constructor

Edit the HelloResource class to inject the Application framework interface through the constructor:

package org.generated.project.interfaces.rest;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import org.generated.project.application.MyConfig;
import org.seedstack.seed.Application;

@Path("hello")
public class HelloResource {
    private final Application application;

    @Inject
    public HelloResource(Application application) {
        this.application = application;
    }

    @GET
    public String hello() {
        MyConfig myConfig = application.getConfiguration()
                .get(MyConfig.class);
        return "Hello " + myConfig.getNames().get(0) + "!";
    }
}

Constructor injection allows to create immutable objects and allows to easily provide mocks for testing. Constructor injection is the only way to access dependencies from the constructor of an object.

By method

Method injection works similarly to the constructor injection but has the downside of permitting the change of internal state after injection happened. Method injection is NOT recommended.

Singleton or not ?

The default behavior is to re-create an instance each time it is injected. This is a good thing as it avoids complex global state bugs and scales better because no synchronization is needed.

Put a breakpoint in the HelloResource class inside the hello() method. You can see that each time the method is invoked, the resource instance is different.

However when the an object is inherently stateful and/or expensive to create, the @Singleton annotation can be applied on the implementation. The same instance will be reused for the lifetime of the application.

Now edit the HelloResource class to make the resource a singleton:

package org.generated.project.interfaces.rest;

import javax.inject.Singleton;
import javax.ws.rs.GET;
import javax.ws.rs.Path;

@Singleton
@Path("hello")
public class HelloResource {
    @GET
    public String hello() {
        return "Hello World!";
    }
}

Verify with the debugger that the same instance of the resource is reused for the lifetime of the application.

Google Guice

To do dependency injection, SeedStack uses Google Guice, a lightweight dependency injection framework.

Google Guice is completely hidden from normal application code by the use of the javax.inject (JSR 330) injection standard. Unless you are doing something very specific (like writing an extension to SeedStack) your code should not depend upon Guice classes.

Now what ?

On this page you have learned:

  • How to inject a dependency by field injection,
  • How to inject a dependency by constructor injection,
  • When and how to declare an implementation as Singleton.

Troubleshooting

If you can’t get this to work, check the troubleshooting page.

Next step

If you want to learn more, continue on the tutorial to learn how to write a business domain model.

   

On this page


Edit