In a JAX-RS web-app we make use of subresources:
#Path("/some/things")
public class ThingsListResource {
#Inject
SomeStorage store;
#GET
public List<Thing> getAllThings() {
return store.getAllThings();
}
#Path("{id}")
public ThingResource getThingResource(#PathParam("id") String id) {
return new ThingResource(id); // PROBLEMATIC
}
}
public class ThingResource {
#Inject
SomeOtherDependecy dep;
#Inject
SomeStorage store;
private final String id;
public ThingResource(String id) {
this.id = id;
}
#GET
public Thing getThisThing() {
return store.getThing(id);
}
#DELETE
public void removeThisThing() {
store.removeThing(id);
}
// following is a list of methods useful enough
// to make ThingResource a useable subresource
}
As you noticed, there are injections which are made with Guice and its GuiceResteasyBootstrapServletContextListener. The dependencies of root resources are injected without problems. The problematic line above is marked with PROBLEM: the subresource is created by-hand, which omits all Guice injections.
What is the elegeant way to inject dependencies with Guice into subresources? I can think of a few options here:
Inject the injector into the root resource and use it to create a subresource, probably with some #Assisted magic in the subresource:
#Inject
Injector injector
// ...
return injector.getInstance(ThingResource.class); // via some provider accepting id?
but I can't wrap my head arround injecting the id of the "thing" into the provider or #Assisted injections. Also, it looks like a lot of Guice boilerplate is required here.
Forget about Guice management of the subresource and pass every dependency to its constructor by hand from the root resource. Simple, yet very "dependency injection by hand"-like.
Make the subresource and inner class of ThingsListResource and thus let it have an access to the outer class (injected) fields. Not very extensible (e.g. if one want to have different subresources implementing the common interface), but simple...
Forget about subresources and "upgrade" them to root resources. It's a bit breaking of DRY rule, as you will specify full URL paths to each resource.
Is there any other way to go or simpler way to realize the above ideas?
This is an ideal use-case for assisted inject. You need to define a factory interface:
public interface ThingResourceFactory {
public ThingResource create(String id);
}
Then you bind it in one of your modules:
install(new FactoryModuleBuilder().build(ThingResourceFactory.class));
Then you modify ThingResource constructor:
private final String id;
#Inject
public ThingResource(#Assisted String id) {
this.id = id;
}
(BTW, I would use constructor injection instead of field injection if I were you, but this is just a side note)
Then you inject ThingResourceFactory into your ThingsListResource and use it in your resource method:
#Path("/some/things")
public class ThingsListResource {
#Inject
SomeStorage store;
#Inject
ThingResourceFactory thingResourceFactory;
#GET
public List<Thing> getAllThings() {
return store.getAllThings();
}
#Path("{id}")
public ThingResource getThingResource(#PathParam("id") String id) {
return thingResourceFactory.create(id);
}
}
See, almost no boilerplate and very easy to use! Guice will automatically create ThingResourceFactory instance for you which will pass create() arguments directly to #Assisted parameters in class constructor, injecting other parameters/fields/methods/etc with usual means.
Related
How can I get Jersey to inject classes without creating and registering factories on a one-for-one basis?
I have the following config:
public class MyConfig extends ResourceConfig {
public MyConfig() {
register(new AbstractBinder() {
#Override
protected void configure() {
bindFactory(FooFactory.class).to(Foo.class);
bindFactory(BazFactory.class).to(Baz.class);
}
});
}
}
hk2 will now successfully inject Foo and Baz:
// this works; Foo is created by the registered FooFactory and injected
#GET
#Path("test")
#Produces("application/json")
public Response getTest(#Context Foo foo) {
// code
}
But that's not my goal. My goal is to inject objects that wrap these classes. There are many and they each consume different combinations of Foo and Baz. Some examples:
public class FooExtender implements WrapperInterface {
public FooExtender(Foo foo) {
// code
}
}
public class FooBazExtender implements WrapperInterface {
public FooBazExtender(Foo foo, Baz baz) {
// code
}
}
public class TestExtender implements WrapperInterface {
public TestExtender(Foo foo) {
// code
}
// code
}
And so on.
The following does not work:
// this does not work
#GET
#Path("test")
#Produces("application/json")
public Response getTest(#Context TestExtender test) {
// code
}
I could create a factory for each and register it in my application config class, using the bindFactory syntax like I did with Foo and Baz. But that is not a good approach due to the number of objects in question.
I have read much of the hk2 documentation, and tried a variety of approaches. I just don't know enough of how hk2 actually works to come up with the answer, and it seems like a common enough problem that there should be a straightforward solution.
Factories are really only needed for more complex initializations. If you don't need this, all you need to do is bind the service
#Override
protected void configure() {
// bind service and advertise it as itself in a per lookup scope
bindAsContract(TestExtender.class);
// or bind service as a singleton
bindAsContract(TestExtender.class).in(Singleton.class);
// or bind the service and advertise as an interface
bind(TestExtender.class).to(ITestExtender.class);
// or bind the service and advertise as interface in a scope
bind(TestExtender.class).to(ITestExtender.class).in(RequestScoped.class);
}
You also need to add #Inject on the constructors so HK2 knows to inject the Foo and Baz
#Inject
public TestExtender(Foo foo, Baz baz) {}
I wound up using FastClasspathScanner to grab classes from the package(s) I was interested in. Then I called the appropriate bind methods (bindAsContract or bind) in batches, as mentioned in Paul Samsotha's answer (after also adding the appropriate #Inject annotations).
That seemed to be the most expedient method available to emulate autoscanning and avoid having to manually register each class.
It feels like a hack and I'd be surprised if hk2 doesn't have a better method baked in.
Most of my classes wired up look something like:
#Component
public class MyClassImpl implements MyClass {
private MyService service;
#Autowired
public MyClass(MyService service) {
this.service = service;
}
}
So that makes sense to me, but if I want to do something like this:
#Component
public class MyClassImpl implements MyClass {
private MyService service;
private String id; // this is what I need
#Autowired
public MyClass(MyService service, String id) {
this.service = service;
this.id = id;
}
}
But the problem is String id is not known until runtime. Is there any way to do this? From what I can tell, Spring checks all the dependencies by default at runtime so if I try the second example, it complains about the constructor arguments.
I've seen some examples where you can use a factory to create the actual value later down the line. Or I can create getters and setters in order to set the id when I need it, but that would also mean I'd need to add those getters and setters to the interface MyClass as well. Is there a cleaner way to do this?
You can create a #Bean method for id with logic needed to calculate it.
#Configuration
public class Config {
#Bean
public String idForService() {
return calculateId();
}
}
And then your service constructor will be look like this
#Autowired
public MyClass(MyService service, #Qualifier("idForService") String id) {
this.service = service;
this.id = id;
}
But as others have already mentioned it looks like a bad practice so you'd better consider to redesign your service class.
I am afraid what you are trying to do is not in the spirit of what Spring was created for. Please do have a look at: Runtime dependency injection with Spring
Having said that, there might be a workaround to your problem.
If you have some class that calculates that ID for you, just inject that class in a constructor and bind the result of its calculation to the field id in your class.
I´m using Guice to initalize a class with some arguments from a config file
#Provides
#Singleton
RetryServiceCaller provideMaxRetryAttempts(#Named("config") JsonObject config) throws IOException {
JsonObject retryDetails = config.getJsonObject("retry_details");
return new RetryServiceCaller(retryDetails.getInteger("maxRetryAttempts"), retryDetails.getInteger("upperBoundary"), retryDetails.getInteger("lowerBoundary"),
retryDetails.getLong("multiplicationFactor"), retryDetails.getInteger("timeout"), retryDetails.getInteger("increaseTimeout"));
}
This class is injected in another class which is singleton as well.
class A{
#Inject private RetryServiceCaller retryServiceCaller;
}
But now the problem is that since this new class A is singleton, I need to clone the retryServiceCaller every time that somebody use this class A.
I´ve been investigating FactoryModuleBuilder to use it and create a factory for this class. But since the class has parameters from the config file I could not find the way to make it works.
Something like this
class A{
#Inject private RetryServiceCaller.Factory retryServiceCallerFactory;
}
Then in my RetryServiceCaller implement this
public interface Factory {
#Inject
RetryServiceCaller create();
}
#Inject
public RetryServiceCaller(int maxRetryAttempts, int upperBoundary, int lowerBoundary, long multiplicationFactor, int timeout, int incrementTimeout) {
this.maxRetryAttempts = maxRetryAttempts;
this.upperBoundary = upperBoundary;
this.lowerBoundary = lowerBoundary;
this.multiplicationFactor = multiplicationFactor;
this.timeout = timeout;
this.incrementTimeout = incrementTimeout;
}
But guice throw me errors saying
No implementation for com.proxy.handlers.RetryServiceCaller$Factory was bound
Guice can automatically provide a zero-argument factory: Instead of injecting Foo, you can always inject Provider<Foo>. This allows you to call fooProvider.get() to create an instance whenever and wherever you'd like. You don't have to bind to a Provider or use a Provides method to get access to this; you can inject Foo or Provider<Foo> whether you use a bind(...).to(...) type binding, a toProvider binding, a toInstance binding, a #Provides method, or anything else, and Guice will call get or return an internal Provider automatically.
(The returned Provider will also respect scopes, so you'll need to drop your #Singleton scope in order to get more than one instance, and be aware that toInstance bindings will always return the same instance.)
This is not a job for FactoryModuleBuilder; only use FactoryModuleBuilder when you need to mix injected and non-injected constructor parameters in the same type.
Your finished binding should look like this:
#Provides
/* NOT #Singleton */
RetryServiceCaller provideMaxRetryAttempts(#Named("config") JsonObject config) throws IOException {
JsonObject retryDetails = config.getJsonObject("retry_details");
return new RetryServiceCaller(retryDetails.getInteger("maxRetryAttempts"), retryDetails.getInteger("upperBoundary"), retryDetails.getInteger("lowerBoundary"),
retryDetails.getLong("multiplicationFactor"), retryDetails.getInteger("timeout"), retryDetails.getInteger("increaseTimeout"));
}
And in your class:
#Inject public YourCallerConsumer(Provider<RetryServiceCaller> callerProvider) {
this.callerProvider = callerProvider;
}
public void doAction() {
RetryServiceCaller newCaller = callerProvider.get();
// interact with caller
}
Your first approach should work just fine. If you don't want the RetryServiceCaller to be a singleton, remove the #Singleton annotation from the provider method, and a new instance will be created for every injection point.
Assisted inject could work here too, but it's overkill. If you want to go that route:
interface RetryServiceCallerFactory {
RetryServiceCaller create(String configParam1, String configParam2);
}
public class RetryServiceCaller {
#AssistedInject
public RetryServiceCaller(String configParam1, String configParam2) {}
}
then, in your module
install(new FactoryModuleBuilder().build(Factory.class);
and in your injection points
#Inject RetryServiceCallerFactory factory;
RetryServiceCaller create(JsonObject config) {
return factory.create(config.getFirstParam(), config.getSecondParam());
}
You can refer to the documentation for more extensive examples.
My class depends on some services which needs to take few parameters and then make network call, currently I am passing those parameters and then creating those services via a factory injected into my class. I need to inject those services as a dependency instead, I know that I can create providers for them but in most of the examples I see that the providers are often bound to the fixed values like serveraddres etc. but I need to give then values during run time.
Below is my example code:
public SomeClass {
private final SomeFactory someFactory;
#Inject
SomeClass(SomeFactory factory) {
someFactory = factory;
}
public Foo getFoo(String fooId) {
FooService fooService = someFactory.getFooService(fooId);
return fooService.getFoo();
}
}
What I need to do is:
public SomeClass {
private final FooService fooService;
#Inject
SomeClass(FooService fooService) {
this.fooService = fooService;
}
public Foo getFoo(String fooId) {
return fooService.getFoo();
}
}
Update 1
Making the use case more clear:
#Provides
#RequestScoped
public SomeService provideSomeService(Dep1 dep1, String code) throws IOException {
return new SomeService.Builder()
.withApplicationName("Foo")
.setCode(code)
.build();
}
Here, code can be null by default and when needed I can give some value in it.
Can I somehow pass arguments to the provider before its created?
If you have a binding for your value (here, code is a String without a binding annotation), then your Update 1 is exactly what the code would look like.
In practice, there are a few differences:
Constants like int and String values are generally annotated with a binding annotation, either #Named or a custom annotation.
If you need to inject a value into an object graph after Guice initialization, but have a deep enough object graph that dependency injection is still a good idea, you can create a child injector. This way you can make a #Named("code") String accessible within one action or object, but not across your entire Guice application.
If your value for code is dynamic enough that it can't be provided through Guice as a key of its own, then you'll have to pass it in using a factory of some sort. For a Builder-based object, I'd say that your SomeFactory implementation is the best that I would come up with in your case.
If you don't need to use a Builder, and can let Guice create the object based on your fields or constructor parameters, you can code-generate a Factory.
Guice can generate a factory for you through FactoryModuleBuilder, in a feature known as "assisted injection".
Google's other tool, AutoFactory, will code-generate a factory implementation that works in both Guice and Dagger. (It's bundled as "Auto", which includes a model object generator called AutoValue that also generates annotation implementations.)
I put a small demonstration of a child injector and assisted injection in my other SO answer here.
The best approach here is to parameterize the module and pass the parameter through to a provider that you create at runtime:
public class MyModule extends AbstractModule {
private final String code;
public MyModule(String code) {
this.code = code;
}
#Override public void configure() {
Provider<Dep1> depProvider = getProvider(Dep1.class);
bind(SomeService.class)
.toProvider(() -> new SomeService.Builder()
.withApplicationName("Foo")
.withDep(depProvider.get())
.setCode(code)
.build())
.in(RequestScoped.class);
}
}
I have recently added a Throttler field to a Server class that is to be instantiated only if throttling is enabled (this is a config entry), and if so, the max number of requests per sec (another config entry) is to be passed to its constructor.
Here is the code without dependency injection of Throttler:
public class Server {
private Config config;
private Throttler throttler;
#Inject
public Server(Config config) {
this.config = config;
if (config.isThrottlingEnabled()) {
int maxServerRequestsPerSec = config.getMaxServerRequestsPerSec();
throttler = new Throttler(maxServerRequestsPerSec);
}
}
}
public class Throttler {
private int maxRequestsPerSec;
public Throttler(int maxRequestsPerSec) {
this.maxRequestsPerSec = maxRequestsPerSec
}
}
Now to inject Throttler, I used a Provider, since it doesn't always need to be instantiated. But now I am forced to inject Config into Throttler and let it "configure itself":
public class Server {
private Config config;
private Provider<Throttler> throttlerProvider;
#Inject
public Server(Config config, Provider<Throttler> throttlerProvider) {
this.config = config;
this.throttlerProvider = throttlerProvider;
if (config.isThrottlingEnabled()) {
this.throttler = throttlerProvider.get();
}
}
}
public class Throttler {
private int maxRequestsPerSec;
#Inject
public Throttler(Config config) {
maxRequestsPerSec = config.getMaxServerRequestsPerSec();
}
}
I don't like this solution because:
There is a dependency of an utility class (Throttler) to Config.
Throttler is now tied to a specific configuration entry, which means it cannot be used by anything else but Server.
I would prefer to somehow inject maxRequestsPerSec into the construtor.
Is that possible with Guice?
The Guice FAQ recommends to introduce a factory interface which builds the class with its dependencies and additional parameters passed by the client.
public class Throttler {
...
public static class Factory {
#Inject
public class Factory(... Throttler dependencies ...) {...}
public Throttler create(int maxRequestsPerSec) {
return new Throttler(maxRequestsPerSec /*, injected Throttler dependencies */);
}
}
}
This way, all the direct dependencies of Throttler remain encapsulated in the Throttler class.
You can also use the AssistedInject extension to reduce the boilerplate code.
It totally depends on how you implement the Provider interface and on your application. If the only way to get the maxRequestsPerSec is from the Config,you can do something along these lines:
You could have the specific Provider implementation injected, and have a setter in that. So in your constructor you inject CustomProvider<Throttler> (which implements Provider), then perform setMaxRequestsPerSec, and then use that in the get method when instantiating your Throttler.
If you don't want to inject CustomProvider, you can instead inject the Provider and then do an instanceof check but I think it would be better to inject the CustomProvider.