I have this problem.
Consider I have classes definitions like:
public interface ABCInterface
{
}
And its implementation:
public class ABCImpl
{
#Inject
private XYZ xyz;
}
When the Guice Config is like this:
public class MasterConfig extends AbstractModule
{
#Override
protected void configure()
{
// TODO Auto-generated method stub
bind(ABCInterface.class)
.to(ABCImpl.class);
}
}
And run it, then everything works fine and XYZ gets injected into it.
But when I use provider methods like this:
public class MasterConfig extends AbstractModule {
#Override
protected void configure() {
// TODO Auto-generated method stub
}
#Provides
public ABCInterface abc() {
return new ABCImpl();
}
}
Then, in this case, I get a null pointer exception when I try to use the injected XYZ, because that object remains null. I am suspecting, this is beacuse, I am returning a new object of ABCImpl and hence Guice is not able to build a dependency graph. Please correct me if I am wrong here?
Can anyone suggest, how to write the Provider method, so that everything gets injected properly like it does when I mention in the configure method.
Indeed, when you write new ABCImpl(), Guice doesn't get a chance to inject its dependencies. You can do this:
#Provides
ABCInterface abc(ABCImpl impl) {
return impl;
}
but you might as well just write bind(ABCInterface.class).to(ABCImpl.class); in that case, unless your provider method has some extra logic.
Related
I'm building a package that is trying to intercept a function's return value based on a flag. My design involves some AOP. The idea is that a class FirstIntercept intercepts a call firstCall and stores parameters in a Parameters object. Then later, a second class SecondIntercept intercepts another call secondCall and does some logic based on what is populated in Parameters:
// pseudoish code
public class FirstIntercept {
private Parameters param;
#AfterReturning(pointcut = "execution(* ...firstCall(..))", returning = "payload")
public void loadParam(Joinpoint joinPoint, Object payload) {
// logic handling payload returned from firstCall()
// logic provides a Boolean flag
this.param = new Parameters(flag);
}
}
public class Parameters {
#Getter
private Boolean flag;
public Parameters(Boolean flag) {
this.flag = flag;
}
}
public class SecondIntercept {
private static Parameters params;
#Around("execution(* ...secondCall(..))")
public void handleSecondCallIntercept(ProceedingJoinPoint joinPoint) {
// want to do logic here based on what params contains
}
}
What I want to achieve is that the Parameters object is loaded once and for all when FirstIntercept.loadParam is invoked through AOP. I'm not too sure how I can go about with this persistence. I looked online and Google guice seems to be promising. I believe a first step would to use dependency injection on the Parameters, but I'm really not sure. Can someone help point me in the right direction?
edit:
So I tried this setup:
public class FirstIntercept implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("invoked!");
return invocation.proceed();
}
#AfterReturning(pointcut = "execution(* ...firstCall(..))", returning = "payload")
public void loadParam(Joinpoint joinPoint, Object payload) {
// do stuff
}
public String firstCall() {
return "hello";
}
}
public class InterceptionModule extends AbstractModule {
protected void configure() {
FirstIntercept first = new FirstIntercept();
bindInterceptor(Matchers.any(), Matchers.annotatedWith(AfterReturning.class), first);
}
}
public class FirstIterceptTest {
#Test
public void dummy() {
Injector injector = Guice.createInjector(new InterceptionModule());
FirstIntercept intercept = injector.getInstance(FirstIntercept.class);
intercept.firstCall();
}
}
When I do .firstCall(), I can see the #AfterReturning running but the invoke is not being called.
If you expand upon the documentation for AOP https://github.com/google/guice/wiki/AOP you should get something close to:
public class FirstInterceptor implements MethodInterceptor {
#Inject Parameters parameters; // Injected with singleton Parameter
public Object invoke(MethodInvocation invocation) throws Throwable {
Object result = invocation.proceed();
// your logic based on result to set parameters.setFlag()
return result;
}
}
Then the second:
public class SecondInterceptor implements MethodInterceptor {
#Inject Parameters parameters; // Injected with singleton Parameter
public Object invoke(MethodInvocation invocation) throws Throwable {
boolean flag = parameters.getFlag();
// your logic here
return invocation.proceed(); // maybe maybe not?
}
}
Your parameters is the key, you'll need to ensure it's thread safe, which is another topic. But to inject these you need:
public class InterceptionModule extends AbstractModule {
protected void configure() {
// Ensure there is only ever one Parameter injected
bind(Parameter.class).in(Scopes.SINGLETON);
// Now inject and bind the first interceptor
FirstInterceptor firstInterceptor = new FirstInterceptor();
requestInjection(firstInterceptor );
bindInterceptor(Matchers.any(), Matchers.annotatedWith(AfterReturning.class),
firstInterceptor);
// Now inject and bind the second interceptor
SecondInterceptor SecondInterceptor = new SecondInterceptor ();
requestInjection(firstInterceptor);
bindInterceptor(Matchers.any(), Matchers.annotatedWith(AfterReturning.class),
SecondInterceptor);
}
}
Edit
Look at what you're doing.
You're telling Guice to wrap a method with #AfterReturn with the FirstInterceptor
Then you're calling interceptor.firstCall()
First call does not have #AfterReturn annotation, so why would it be matched against that configuration?
I'm guessing if you called:
intercept.loadParam();
you would see the invoke method. Also, this is great for a test, but in real life you want to have a Service level class have the #AfterReturn which is then Injected into another Api/Job/Etc that will call LoadParam.
edit
Oh no. Take a look at this line
bindInterceptor(Matchers.any(), // a class with this matcher
Matchers.annotatedWith(AfterReturning.class), // a method with this
firstInterceptor);
This means that the injector only fires on the loadParams. You need to annotate the method of the class youw ish to cause the interception with #AfterReturning. And you want the loadParams to be the invoke method.
I am using Guice for Dependency injection. I want to use #CheckedProvides as object construction may throw exception and I do not want it to be wrapped up in ProvisionException. I found this useful but I am not able to get the complete picture. I have created an interface which is extending CheckedProvider interface. Now I want to know what the implementing class of this interface will contain?
My interface looks like
public interface TokenEncrypterProvider <T> extends CheckedProvider<T> {
T get() throws ExceptionInInitializerError;
}
i want it to be used as
#Provides
public TokenManager getTokenManager(SomeClass obj) {
return new TokenManager(obj);
}
#CheckedProvides(TokenEncrypterProvider.class)
public SomeClass getEncrypter() {
try {
return new SomeClassFactory()
.buildEncryptionClient(AppConfig.findString("xyz"));
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
public class TokenManager {
private final SomeClass obj;
#Inject
public TokenManager(SomeClass obj) {
this.obj = obj;
}
...
}
now for binding what should I write
bind(TokenEncrypterProvider.class).toProvider(WHICHCLASS?.class);
or if it is not the way to use CheckedProvides, please suggest a correct one.
I am assuming you are using Guice 3+ or 4+. You don't have to bind your provider if you are using CheckedProvides annotations.
You have to add install(ThrowingProviderBinder.forModule(this)) in the configure() method of your module to be able to use #CheckedProvides methods.
Documentation
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.
#Path("/test")
public class MyClass {
#GET
public Response response() {
// Generating some expensive object here.
}
Right now I load the data into arrays etc inside the "response" function, but I want to do it before the query is even made. This way, I want to avoid reloading the data every time a a query is made. How do I achieve this?
This depends on your framework. Are you using the reference implementation Jersey? Jersey comes bundled with HK2 automatically. Then you could add
#Path("/test")
public class MyClass {
#Inject
private MyState stateful;
// here comes your code...
}
to your resource. Of course, you would still need to configure what to inject into this field. With HK2, you use an AbstractBinder for this purpose:
class MyBinder extends AbstractBinder {
private final MyState stateful;
public MyBinder (MyState stateful) {
this.stateful = stateful;
}
#Override
protected void configure() {
bind(stateful).to(MyState.class);
}
}
Finally, you need to add this binder on the application's setup. For this purpose, JAX-RS Application object can be queried for singletons. Simply add the required instance to the application such that it is returned by Application#getSingletons as here:
class MyJaxRSApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
return Collections.singletonSet(MyClass.class);
}
#Override
public Set<Object> getSingletons() {
return Collections.singletonSet(new MyBinder(new MyStateImpl()));
}
}
You can now run your application where MyStateImpl is always injected into MyClass.
I have the following Guice module:
class MyModule extends AbstractModule {
#Override
protected void configure() {
bindListener(Matchers.any(), new TypeListener() {...});
}
#Provides
SomeClass createSomeClass(final Parameter param) {
log(param.getValue()); <-- this gets logged
...
}
}
What I found strange is that my TypeListener doesn't get notified about the Parameter type. Even though the provider is beign called and returns SomeClass. I also see the log statement so clearly the Parameter was injected by Guice.
#Override
protected void configure() {
bind(Parameter.class);
bindListener(Matchers.any(), new TypeListener() {...});
}
I'm aware of Untargetted bindings and the statement:
An untargetted binding informs the injector about a type, so it may prepare dependencies eagerly.
I would still expect Guice to call the TypeListener for any type which is either explicitly binded or injected for the first time.
So do I need to make untargetted binding for such classes as a rule of thumb?
NOTE: marking the Parameter constructor with #Inject doesn't solve the problem.
EDIT:
The complete example (hope I din't leave too much garbage) is as follows:
public class TestGuice {
public static void main(String[] args) {
Injector parentInjector = Guice.createInjector(new ParentModule());
Injector childInjector = parentInjector.createChildInjector(new SubModule());
childInjector.getInstance(Runnable.class).run();
}
static class ParentModule extends AbstractModule {
#Override
protected void configure() {
}
}
static class SubModule extends AbstractModule {
#Override
protected void configure() {
bind(SampleInjectedClass.class); // <-- Comment/uncomment here
final TypeListener typeListener = new TypeListener() {
public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
System.out.println("Type: " + type.getRawType());
}
};
bindListener(Matchers.any(), typeListener);
}
#Provides
Runnable createRunnable(final SampleInjectedClass sampleClass) {
return new Runnable() {
#Override
public void run() {
sampleClass.test();
}
};
}
}
static class SampleInjectedClass {
public void test() {
System.out.println("Test");
}
}
}
If the line is present the output is:
Type: class com.barcap.test.TestGuice$SampleInjectedClass
Type: class com.google.inject.internal.ProviderMethod
Test
If I remove the line I get:
Type: class com.google.inject.internal.ProviderMethod
Test
I noticed that if the injector wasn't created via the createChildInjector code the bind(...) is not necessary.
Just-in-time bindings created for child injectors will be created in an ancestor injector whenever possible. This means that, without the bind(SampleInjectedClass.class); line, the binding for SampleInjectedClass is created in the parent injector. Since the parent injector doesn't have your TypeListener, it won't be triggered.
Can you check your code? In my test on Guice 3, I couldn't reproduce what you're seeing.
Also, from the TypeListener docs, emphasis mine and typo sic:
public abstract void hear (TypeLiteral<I> type, TypeEncounter<I> encounter)
Invoked when Guice encounters a new type eligible for constructor or members injection. Called during injector creation (or afterwords if Guice encounters a type at run time and creates a JIT binding).
Though all the rest of your dependencies will be called on the TypeListener immediately when the injector is created, implicit ("just-in-time") bindings will not.
However, based on my example above, it appears that when a parameter is included in a provider method, it is registered on the same listener immediately. Can you produce a short self-contained example that shows the behavior you're asking about?