DEPENDENCY injection in Analytic suite
guice by google
CONSTRUCTOR INJECTION
public class myClass {
private Service myService;
public myClass(URL url) {
this.myService = new Service(url);
}
...
}
public class myController {
private final Service myService;
@Inject
public myController(Service service) {
this.myService = service;
}
...
}
Before
After
Modules
public class serviceModule extends AbstractService {
public configure() {
bind(Service.class).to(ServiceImpl.class);
}
...
}
public interface Service {
...
}
public class ServiceImpl implements Service {
...
}
Modules Annotation
public class serviceModule extends AbstractService {
public configure() {
bind(Service.class)
.annotatedWith(Service1.class)
.to(ServiceImpl1.class);
bind(Service.class)
.annotatedWith(Service2.class)
.to(ServiceImpl2.class);
}
...
}
public interface Service {
...
}
public class ServiceImpl1 implements Service {
...
}
public class ServiceImpl2 implements Service {
...
}
@Inject
public myClass(
@Service1 Service service) {
this.service = service;
}
Providers
public class serviceModule extends AbstractService {
public configure() {
bind(Service.class).toProvider(ServiceProvider.class);
}
...
}
public class ServiceProvider implements Provider<Service> {
public Service get() {
return new Service();
}
}
Singleton with providers
public class serviceModule extends AbstractService {
public configure() {
bind(Service.class).toProvider(ServiceProvider.class).in(Singleton.class);
}
...
}
public class ServiceProvider implements Provider<Service> {
private final Service service;
public ServiceProvider() {
this.service = new Service();
}
public Service get() {
return this.service;
}
}
Throwing providers
public class serviceModule extends AbstractService {
public configure() {
ThrowingProviderBinder.create(binder())
.bind(ServiceProvider.class, Service.class)
.to(ServiceProviderImpl.class)
.in(Singleton.class);
}
...
}
public interface ServiceProvider<T> extends CheckedProvider<T> {
T get() throws ServiceException;
}
public class ServiceProviderImpl implements ServiceProvider<Service> {
public Service get() throws ServiceException {
try {
return new Service();
} catch(MalformedURLException e) {
throw new ServiceException("cannot connect", e);
}
}
}
guice With play
controller instance
public class VersionCTRL extends Controller {
private static final Logger.ALogger LOG = Logger.of(VersionCTRL.class);
/**
* Get the current commit version
*
* @return a Result object with the commit version
*/
public static Result get() {
LOG.debug("get the project version");
try {
return ok(toJson(new VersionOutput(Configuration.getApplicationVersion())));
} catch (Exception e) {
LOG.error("an error occurred", e);
return internalServerError();
}
}
}
Before
controller instance
public class VersionCTRL extends Controller {
private static final Logger.ALogger LOG = Logger.of(VersionCTRL.class);
private final String version;
@Inject
public VersionCTRL(@ConfigParam(Property.APPLICATION_VERSION) String version) {
this.version = version;
}
/**
* Get the current commit version
*
* @return a Result object with the commit version
*/
public Result get() {
LOG.debug("get the project version");
return ok(toJson(new VersionOutput(version)));
}
}
After
guice In analytic suite
Configuration
No more class Configuration
@Inject
public VersionCTRL(@ConfigParam(Property.APPLICATION_VERSION) String version)
Use ConfigParam annotation
public enum Property {
...
APPLICATION_VERSION("application.version",
"Version of the application",
new TypeLiteral<String>() {
},
"x.x.x"),
...
}
Add configuration in enum Property
application.version = "0.9-SNAPSHOT"
Add line in configuration file
globals.configuration.Property
conf/application.conf
Tests
Mock it all!
public class ControllerTest extends WithAuthenticatedApplication {
private Service mockService = mock(Service.class);
@Override
protected Application provideApplication() {
return new GuiceApplicationBuilder()
.in(new File("."))
.global(new GlobalSettings())
.bindings(new AuthModule(), new ConfigurationModule(), new TestModule())
.build();
}
//test methods
...
class TestModule extends AbstractModule {
@Override
protected void configure() {
bind(Service.class).toInstance(mockService);
}
}
}
BONUS : Initializers
new global
public class Global extends GlobalSettings {
@Override
public void onStart(Application application) {
Logger.info("Starting app");
startApp();
Logger.info("Starting done");
}
private void startApp() {
MainInitializer mainInitializer = new MainInitializer();
try {
mainInitializer.init();
Logger.info("STARTUP SERVICE :)");
} catch (InitializerException e) {
stopApplication();
}
}
private void stopApplication() {
Logger.error("Exiting the application");
System.exit(1);
}
}
Main initializer
public class MainInitializer implements Initializer {
protected static final Logger.ALogger LOG = Logger.of(MainInitializer.class);
private final List<Initializer> initializers;
public MainInitializer() {
this.initializers = new LinkedList<>();
LOG.debug("Initializing initializers");
initializers.add(getInitializer(DatabaseInitializer.class));
initializers.add(getInitializer(MsHadoopInitializer.class));
initializers.add(getInitializer(MsIndexInitializer.class));
initializers.add(getInitializer(UserInitializer.class));
initializers.add(getInitializer(ImpalaInitializer.class));
}
private Initializer getInitializer(Class<? extends Initializer> clazz) {
return Play.application().injector().instanceOf(clazz);
}
@Override
public void init() throws InitializerException {
final ArrayList<Throwable> throwables = new ArrayList<>();
LOG.info("Launching initializers");
initializers.forEach(i -> {
try {
i.init();
LOG.info("" + i.getClass().getName() + " OK");
} catch (InitializerException e) {
throwables.add(e);
}
});
if (!throwables.isEmpty()) {
InitializerException e = new InitializerException("Main initializer throwable");
throwables.forEach(e::addSuppressed);
throw e;
}
}
MS INDEX INITIALIZER
public class MsHadoopInitializer implements Initializer {
private final HadoopClientProvider hadoopClientProvider;
private final TemporaryRepositoryInitializer temporaryRepositoryProvider;
@Inject
public MsHadoopInitializer(
HadoopClientProvider hadoopClientProvider,
TemporaryRepositoryInitializer temporaryRepositoryProvider
) {
this.hadoopClientProvider = hadoopClientProvider;
this.temporaryRepositoryProvider = temporaryRepositoryProvider;
}
@Override
public void init() throws InitializerException {
try {
hadoopClientProvider.get();
} catch (ConfigurationException e) {
throw new InitializerException("Bad MS URI format in configuration", e);
}
try {
temporaryRepositoryProvider.init();
} catch (InitializerException ie) {
InitializerException e = new InitializerException("Cannot create temporary repository");
e.addSuppressed(ie);
throw e;
}
}
}
DEPENDENCY injection in Analytic suite
By Erwann Cloarec
DEPENDENCY injection in Analytic suite
- 474