bind feign target to guice - java

is there a way to bind a feign target to guice?
My usecase case is as follows:
I have a service, which can be either started in the same JVM or as a separate service.
if the service is started in same JVM, then I will bind it using Guice.
if the service is started outside the jvm, I want to bind the service using fiegn and have guice inject the same.

I solved this using a Provider implementation in Google Guice.
Here is a sample
public class Main {
public static AccountService get() {
return Feign.builder()
.contract(new JAXRSContract())
.decoder(new GsonDecoder())
.target(AccountService.class, "http://localhost:9090");
}
static class RestClientProvider implements Provider<AccountService> {
RestClientProvider() {
}
#Override
public AccountService get() {
return Main.get();
}
}
static class AppInjector extends AbstractModule {
#Override
protected void configure() {
Provider<AccountService> prov = new RestClientProvider();
bind(AccountService.class).toProvider(prov);
}
}
public static void main (String... args) {
Injector inj = Guice.createInjector(new AppInjector());
AccountService ac = inj.getInstance(AccountService.class);
Account a = ac.getAccountByName("Mihir");
System.out.println(a.getName());
}
}

Related

Is there a more convinient to provide (bind to guice module) already created instances?

I use Guice in a desktop application and I want to add generic bindings for services. These services are singleton (binded) instances and are created during application startup manually. I use the IoC container only to create the GUI. I create these services manually because during start up I want to publish the progress.
Since the GUI consume these services, they must been binded to the guice GUI module.
I can't think of a way to bind them without using a class with setter and getter for each class.
Let's say I have CarService and EngineService. What I have now is:
public class GuiceServices {
public static void main(String[] args) {
ServicesModule servicesModule = new ServicesModule();
CarService carService = new CarServiceImpl();
servicesModule.setCarService(carService);
System.out.println("progress: 50%");
EngineService engineService = new EngineServiceImpl();
servicesModule.setEngineService(engineService);
System.out.println("Progress: 100%");
Injector i = Guice.createInjector(new GuiModule(), servicesModule);
i.getInstance(MainView.class).show();
}
class ServicesModule extends AbstractModule {
private CarService carService;
private EngineService engineService;
#Override
protected void configure() {
}
public void setCarService(CarService carService) {
this.carService = carService;
}
public void setEngineService(EngineService engineService) {
this.engineService = engineService;
}
#Provides
public CarService getCarService() {
return carService;
}
#Provides
public EngineService getEngineService() {
return engineService;
}
}
}
But it is kind of pain since these services are plenty.
Is there a way to avoid this?
Ideally, a map is more convenient. Something like:
public class GuiceServices {
public static void main(String[] args) {
ServicesMap servicesMap = new ServicesMap();
CarService carService = new CarServiceImpl();
servicesMap.put(CarService.class, carService);
System.out.println("progress: 50%");
EngineService engineService = new EngineServiceImpl();
servicesMap.put(EngineService.class, engineService);
System.out.println("Progress: 100%");
Injector i = Guice.createInjector(new GuiModule(), new ServicesModule(servicesMap));
i.getInstance(MainView.class).show();
}
class ServicesModule extends AbstractModule {
private ServicesMap services;
public SerrvicesModule(ServicesMap services) {
this.services = services;
}
#Override
protected void configure() {
for (Class<?> serviceType : services.keySet())
{
bind(serviceType).toInstance(services.get(serviceType));
}
}
}
}
But I cannot find a way to create-implement this "servicesMap". Because the bind method returns a generic builder. Does Guice (or Guava) provide something for cases like this?
I know that I can use Guice to create the services and publish the progress using an injection/type listener, but my business package (module) that contains all the services has no javax.inject dependency. Plus, the creation of these services is complex hence is better to make it manually. Also, publishing a GUI progress within a Guice module sounds too complex to be in a Guice module.
So, is there a way? Instead of the System.out.println in the above snippets, there is a splash screen that is created manually as well.
Just move the code that builds each service impl inside the body of the #Provides method for the corresponding service interface. You mentioned wanting these to be singletons, so you'll also want to annotate the provider methods with #Singleton.
As for the map, you could do something like that with a Multibinder, but I'd want to understand your design better before recommending that.
I actually achieved it myself.
What I did is to create a List<Consumer<Binder>> inside the module and then consme them inside configure() method.
class ServicesModule extends AbstractModule {
private List<Consumer<Binder>> consumers = new ArrayList<>();
ServicesModule() {
}
#Override
protected void configure() {
consumers.forEach(c -> c.accept(binder()));
}
<T> void putService(Class<T> clazz, T instance) {
consumers.add(t -> t.bind(clazz).toInstance(instance));
}
}
And then, during application start up I can feed the service dependencies gradually:
public static void main(String[] args) {
ServicesModule services = new ServicesModule();
CarService carService = new CarServiceImpl();
serviceModule.putService(CarService.class, carService);
publishProgress(35);
EngineService engineService = new EngineServiceImpl(carService);
serviceModule.putService(EngineService.class, engineService);
publishProgres(50);
//...
Injector i = Guice.createInjector(new GuiModule(), services);
i.getInstance(MainView.class).show();
}
Your proposed answer requires knowledge about the dependencies of the service-impl classes to be spread outside those classes. The whole idea of dependency injection is to encapsulate implementation dependencies. For example, only EngineServiceImpl should know that it depends on CarService. Encapsulation makes your code much easier to reason about and test.
class ServiceModule extends AbstractModule {
protected void configure() {
bind(CarService.class).to(CarServiceImpl.class).in(Singleton.class);
bind(EngineService.class).to(EngineServiceImpl.class).in(Singleton.class);
}
}
class CarServiceImpl implements CarService {
#Inject
CarServiceImpl() {} // Not necessary, but adds clarity
// ...
}
class EngineServiceImpl implements EngineService {
private final CarService carService;
#Inject
EngineServiceImpl(CarService carService) {
this.carService = carService;
}
// ...
}
class Main {
public static void main(String[] args) {
// I find it clearer to get the starting-point class instance from the injector
// creation chain, then operate on that instance.
MainView mainView =
Guice.createInjector(new GuiModule(), new ServiceModule())
.getInstance(MainView.class);
mainView.show();
}
}

Seeding Dagger 2 Factory with Config

I'm just getting started with Dagger & Dependency Injection and wondering about configuration at runtime for some of the lower-level dependencies. Is there a way to provide a low-level injected Singleton with a configuration object at runtime?
Basic idea of what I'm after:
#Singleton
class DatabaseService {
#Inject
public DatabaseService(DatabaseConnectionConfig config) { // how can this arg be passed in at runtime?
// make the connection
}
}
#Singleton
class HighLevelService {
#Inject
public HighLevelService(DatabaseService db) {
}
}
#Module
class Module {
#Binds
abstract HighLevelService bindHighLevelService(HighLevelService svc);
#Binds
abstract DatabaseService bindDatabaseService(DatabaseService svc);
}
#Singleton
#Component(modules = {
Module.class
})
interface Factory {
HighLevelService highLevelService();
static Factory create() {
return DaggerFactory.create();
}
}
public class App {
public static void main(String[] args) {
// get the config details from the arguments
DatabaseConnectionConfig config = parseDBConfigFromArgs(args);
// is there a way to configure the DatabaseConnectionConfig from here?
HighLevelService svc = Factory.create().highLevelService();
}
}
You can use a #Component.Factory (or #Component.Builder) with #BindsInstance.
#Singleton
#Component
interface Factory {
HighLevelService highLevelService();
// This nested interface is typically called "Factory", but I
// don't want to look up how to access Factory from Factory.Factory
#Component.Factory
interface MyFactory {
Factory create(#BindsInstance DatabaseConnectionConfig config);
}
static Factory create(DatabaseConnectionConfig config) {
return DaggerFactory.factory().create(config);
}
}
public class App {
public static void main(String[] args) {
DatabaseConnectionConfig config = parseDBConfigFromArgs(args);
HighLevelService svc = Factory.create(config).highLevelService();
}
}

Jersey 2 inject dependencies into unit test

I have a controller like this
#Path("/")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class AccountController implements CRUDController<Long, Account> {
private AccountDao accountDao;
private AccountService accountService;
#Inject
public AccountController(AccountDao accountDao, AccountService accountService) {
this.accountDao = accountDao;
this.accountService = accountService;
}
...
I'm injecting AccountDao and AccountService using
ResourceConfig config = new ResourceConfig()
.packages("controller", "exception")
.register(new MyDIBinder());
Where MyDIBinder is contains all the bindings (e.g
AccountDaoImpl accountDaoImpl = new AccountDaoImpl();
bind(accountDaoImpl).to(AccountDao.class);
)
Now I want to write a unit test for this controller, is it possible to inject the whole AccountController instance with all of it's transitive dependencies into the test?
Something like
#Inject
AccountController accountController;
You can use the main IoC container, and just explicitly inject the test class. Jersey uses HK2 as its DI framework, and its IoC container is the ServiceLocator, which has a method inject(anyObject) that can inject any objects with dependencies that are in its registry.
For example you could do something like
public class InjectionTest {
#Inject
private TestController controller;
#Before
public void setUp() {
final Binder b = new AbstractBinder() {
#Override
public void configure() {
bindAsContract(TestController.class);
}
};
final ServiceLocator locator = ServiceLocatorUtilities.bind(new TestBinder(), b);
locator.inject(this);
}
#Test
public void doTest() {
assertNotNull(controller);
String response = controller.get();
assertEquals("Hello Tests", response);
}
}
The ServiceLocatorUtilities class is a helper class that allows us to easily create the ServiceLocator, and then we just call inject(this) to inject the InjectionTest.
If it seems repetitive to do this for all your controller tests, you may want to create an abstract base test class. Maybe something like
public abstract class AbstractControllerTest {
protected ServiceLocator locator;
private final Class<?> controllerClass;
protected AbstractControllerTest(Class<?> controllerClass) {
this.controllerClass = controllerClass;
}
#Before
public void setUp() {
final AbstractBinder binder = new AbstractBinder() {
#Override
public void configure() {
bindAsContract(controllerClass);
}
};
locator = ServiceLocatorUtilities.bind(new TestBinder(), binder);
locator.inject(this);
}
#After
public void tearDown() {
if (locator != null) {
locator.shutdown();
}
}
}
Then in your concrete class
public class TestControllerTest extends AbstractControllerTest {
public TestControllerTest() {
super(TestController.class);
}
#Inject
private TestController controller;
#Test
public void doTest() {
assertNotNull(controller);
assertEquals("Hello Tests", controller.get());
}
}
If you spent some more time, I'm sure you could come up with a better abstract test class design. It was the first thing that came to mind for me.
Note: For anything request scoped, you mayb need to just mock it. When running the unit tests, there is no request context, so the test will fail.
See Also:
Using Jersey's Dependency Injection in a Standalone application
HK2 documentation
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.utilities.ServiceLocatorUtilities;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
#BeforeClass
public static void doTest() {
ServiceLocator serviceLocator = ServiceLocatorUtilities.bind(new AbstractBinder() {
#Override
protected void configure() {
bindAsContract(YourClass1.class);
bindAsContract(YourClass2.class);
bindAsContract(YourClass3.class);
}
});
YourClass1 yourClass1 = serviceLocator.getService(YourClass1.class);
...

how to implement a global state with guice?

I want to create a global state (data object, not a service object).
I have created class MyDataObject.
I want to avoid regular global state,
but prefer using Guice dependency injection.
However all the tutorials show how to set a DI for service object with registration to interface.
How can I use Guice injection for my need?
Edit
I have tried:
public class AppInjector extends AbstractModule {
#Override
protected void configure() {
bind(E2eResult.class).toInstance(new E2eResult());
}
}
with:
#Test
public void sendSearchRequest() throws Exception {
...
e2eResult = injector.getInstance(E2eResult.class);
timerUtils.setTimeOut(criticalBlockTimeOutMilli);
timerUtils.startStopWatch();
...
long timeElapsed = timerUtils.stopStopWatch();
e2eResult.runTime = timeElapsed;
...
}
and:
public static void main(String... args) throws ClassNotFoundException, IOException {
Injector injector = Guice.createInjector(new AppInjector());
Result result = runTest(classAndMethod);
E2eResult e2eResult = injector.getInstance(E2eResult.class);
}
and yet I saw the in the main was without the new long value.
To inject GlobalState class you should first a create an instance of it(set it as you like) and then bind class to instance:
bind(GlobalState.class)
.toInstance(globalState);
GlobalState can be created and configured in your "module", you can read about it more here:
https://github.com/google/guice/wiki/GettingStarted
So you have a plain old java object GlobalState:
public class GlobalState {
// whatever...
}
You can use the singleton mechanism provided by guice:
bind(GlobalState.class).in(Singleton.class);
Or use the instance binding:
bind(GlobalState.class).toInstance(new GlobalState());
In this way, you will be able to inject an unique instance of GlobalState in your application.
I eventually create an "old" bad singleton
No need for special binding
because i didn't have any pre-loaded object.
#Override
protected void configure() {
}
just to carry a one and only guice injector
public class InjectorSingleton {
public Injector guiceInjector;
private static InjectorSingleton singleton;
private InjectorSingleton() {
guiceInjector = Guice.createInjector(new AppInjector());
}
public static InjectorSingleton getInstance() {
if (singleton == null) {
singleton = new InjectorSingleton();
}
return singleton;
}
}
and I call this from my main class and from my test class
InjectorSingleton.getInstance().guiceInjector.getInstance(MyDataObject.class);
Fashionably late to the party. I just wanted to share this pattern.
package modules;
public class MetricsModule extends AbstractModule {
#Override
protected void configure() {
// The initializer is an eager singleton
bind(modules.MetricsModule.MeterRegistryInitializer.class).asEagerSingleton();
}
private static class MeterRegistryInitializer {
#Inject
// When initialized, Guice will handle the injection as usual
public MeterRegistryInitializer(Config config, MeterRegistry registry) {
var instance = config.getString("instance.id");
registry.config().commonTags(List.of(
Tag.of("instance", instance)
));
// This is global state
Metrics.addRegistry(registry);
}
}
#Provides
#Singleton
MeterRegistry provideMeterRegistry(
#MetricsDriver String driver,
PrometheusMeterRegistry prometheusRegistry
) {
MeterRegistry registry;
switch (driver) {
case "none":
registry = new CompositeMeterRegistry();
break;
case "prometheus":
registry = prometheusRegistry;
break;
default:
throw new UnsupportedOperationException();
}
return registry;
}
}

Guice: Forcing a binding to be injected as a provider

I'm looking for a way to force certain Guice bindings to be injected as providers only. For example, when there is a configuration like
interface ResultLogger {
void log(String resultAsString);
}
class ResultLoggerProvider implements Provider<ResultLogger> {
// ...
}
class ResultDisplayModule extends AbstractModule {
#Override
protected void configure() {
bind(ResultLogger.class).toProvider(ResultLoggerProvider.class);
}
}
I would like to have way to configure my module so that a class like
#Singleton
class ResultParser {
private final Provider<ResultLogger> loggerProvider;
#Inject
public ResultParser(Provider<ResultLogger> loggerProvider) {
this.loggerProvider = loggerProvider;
}
}
can be injected just fine, but an implementation like
#Singleton
class ResultParser {
private final ResultLogger resultLogger;
#Inject
public ResultParser(ResultLogger resultLogger) {
this.resultLogger = resultLogger;
}
}
should throw a RuntimeException which notifies the developer that ResultLogger is only available via a provider. The exception would ideally be thrown as soon as possible, e.g. during construction of the injector. I'm looking for an easy way to achieve this using the existing API in Guice 3.0.
Maybe you should not implement Provider at all and just have a
#Singleton
public class ResultLoggerProvider {
public ResultLogger get() {...}
// ...
}
#Singleton
class ResultParser {
private final ResultLoggerProvider loggerProvider;
#Inject
public ResultParser(ResultLoggerProvider loggerProvider) {
this.loggerProvider = loggerProvider;
}
}
and remove the other bindings.
I think that it isn't right way. I guess you need smt like
interface ResultLogger {
void log(String resultAsString);
}
class ResultLoggerWrapper implements ResultLogger {
#Inject #Named("day") ResultLogger dayLogger;
#Inject #Named("night") ResultLogger nightLogger;
public void log(String resultAsString){
if(isDay()) {
dayLogger.log(resultAsString)
} else {
nightLogger.log(resultAsString)
}
}
}
bind(ResultLogger.class).to(ResultLoggerWrapper.class);
It should work to bind Provider instead of ResultLogger. That is in your module
bind(new TypeLiteral<Provider<ResultLogger>>(){}).to(ResultLoggerProvider.class);

Categories