I am trying to use hk2 dependency injection in jersey application. I have a class named ClassA implements IClassA interface. I want to use dependency injection for ClassB object in ClassA :
package com.example.test
public class ClassA implements IClassA {
#Inject
ClassB classB;
#Override
public void method() {
classB.doSomething();
}
}
ClassB :
package com.example.test
public class ClassB {
public void doSomething() {
}
}
I created ResourceConfig class.
package com.example.test.di
public class App extends ResourceConfig {
public App() {
register(new MyApplicationBinder());
packages(true, new String[]{"com.example.test"});
}
}
I created AbstractBinder class.
package com.example.test.di
public class MyApplicationBinder extends AbstractBinder {
#Override
protected void configure() {
bind(ClassB.class).to(ClassB.class).in(Singleton.class);
}
}
I addded Application to web.xml
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.example.test.di.App</param-value>
</init-param>
I created ClassA object like this :
IClassA classA = new ClassA();
classA.method(); //--> classB is null
My problem is classB object is always null in ClassA. I cannot find what is wrong.
Thanks.
You have bound ClassB in the Singleton scope (which means hk2 will only create one of them). Instead, bind ClassB into the PerLookup scope. Then also inject a javax.inject.Provider. Every time you call the get method of Provider you should get a new instance of ClassB
Related
I am new to Guice so this might be a basic question. Guice beans get created correctly with below code in Module
public class MyModule extends AbstractModule {
#Override
protected void configure() {
ClassA classAObj = ClassA.standard().build();
bind(ClassA.class).toInstance(classAObj);
ClassB classBObj = new ClassB(classAObj);
bind(ClassA.class).toInstance(classBObj);
}
}
but I want to create beans for ClassA and ClassB using annotations. I tried below code in Module:
public class MyModule extends AbstractModule {
#Provides #Singleton public ClassA getClassA() {
return ClassA.standard().build();
}
#Provides #Singleton public ClassB getClassB() {
Injector injector = Guice.createInjector(new MyModule());
return new ClassB(injector.getInstance(ClassA.class));
}
}
I also tried few other combinations but they don't seem to be working. Can someone please let me know
How to inject bean of ClassA as constructor parameter while creating bean of ClassB using annotations in Guice?
AND/OR
How to set bean of ClassA as class level variable of ClassB(without constructor route)?
You can simply write the following:
#Provides #Singleton
public ClassB getClassB(ClassA classA) {
return new ClassB(classA);
}
By passing ClassA as parameter of getClassB, Guice will consider that ClassB depends on ClassA, and will know that it must call getClassA() before calling getClassB(ClassA).
I upgrade Jersey in my project to 2.26 version.
My code is:
import org.glassfish.jersey.server.internal.inject.AbstractContainerRequestValueFactory;
public class ClassA extends AbstractContainerRequestValueFactory<ClassB> {
#Override
public ClassB provide() {
.....
}
}
AbstractContainerRequestValueFactory class was removed, and I didn't found how to fix this.
From https://github.com/jersey/jersey/commit/1f4614787c4cfddb5d9177c6c2a663b96ab673cc#diff-bcd9d3f0cfac8ea5e8e9a6b00119237b
commit we can see we should use below code instead.
private static final class BeanParamValueProvider implements Function<ContainerRequest, Object> {
Alternatively, we can use custom HK2 bindings, that are configured as part of Jersey application. Add jersey-hk2 dependency dependency in the classpath org.glassfish.jersey.inject:jersey-hk2
Define the Factory class to generate the instance based on the resource scopes
import org.glassfish.hk2.api.Factory;
import javax.ws.rs.ext.Provider;
#Provider
public class ClassA implements Factory<ClassB> {
#Override
public ClassB provide() {
// construct ClassB instance based on your requirement
//here I am simply returning the object
return new ClassB();
}
#Override
public void dispose(ClassB instance) {/**Noop**/}
}
Registering the custom factory class
For instance, I have to inject ClassB instance for every request then I can register the above factory with the scope of RequestScoped, in such case, for every request ClassA#provide will be called to create the value of ClassB instance that can be retrieved as #Context ClassB classB
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.process.internal.RequestScoped;
import org.glassfish.jersey.server.ResourceConfig;
import javax.ws.rs.ext.Provider;
#Provider
class ApplicationConfig extends ResourceConfig {
public ApplicationConfig() {
register(new AbstractBinder() {
#Override
protected void configure() {
bindFactory(ClassA.class)
.to(ClassB.class)
.in(RequestScoped.class);
}
});
}
}
The following scopes are currently supported by Jersey
I have the following scenario in Spring :
public class ClassA{
#Autowired
private ClassB classB;
}
I'm using (Autowiring to be more precise) ClassA in my Test class. But what I'd like to do somehow is to modify ClassB just for my Junit, so with that, When ClassA is autowired in my test class, it loads the modified ClassB (instead of the original one).
Is there a way to achive that?
Can't think of another way to do this without Bean Configuration.
You can configure this in 2 ways:
First:
#Configuration
public class AppConfig {
#Bean
public ClassB classB() {
return new ClassB() {
// this is a subclass that inherits everything from ClassB, so override what you want here
}
}
}
Second: (taken from here)
#RunWith(SpringRunner.class)
#SpringBootTest
public class SomeTest {
// do this if you only want the modified classB in 1 place
#Configuration
static class TestConfig {
#Bean
public ClassB classB () {
return new ClassB() {
// same as the first
}
}
}
#Test
public void testMethod() {
// test
}
}
Finally, you could create a new interface ClassB and ClassBImpl in your main folder and ClassBTestImpl in your test folder. You still need to use one of the configuration.
I am trying to inject a custom annotation using the Guice bindInterceptor into my currently instantiated Service.java class. Unfortunately when I call myMethod() the OnAnnotationEvent::invoke method is not called. How can I use Guice to call OnAnnotationEvent::invoke when the #OnAnnotation annotation tag is used on a method in the current class?
My code looks like this:
Service.java
//Instantiated by another service
public class Service extends AbstractVerticle {
private DataAccess dataAccess;
#Inject
public void setDataAccess(DataAccess dataAccess){
this.dataAccess = dataAccess;
}
#Override
public void start() throws Exception {
Guice.createInjector(new DataAccessModule()).injectMembers(this);
myMethod();
}
#MyAnnotation
public void myMethod() {
dataAccess.doStuff();
}
}
DataAccessModule.java
public class DataAccessModule extends AbstractModule {
#Override
protected void configure() {
OnAnnotationEvent onAnnotationEvent = new OnAnnotationEvent();
bindInterceptor(Matchers.any(), Matchers.annotatedWith(MyAnnotation.class), onAnnotationEvent);
bind(DataAcess.class).to(DataAccessImpl.class);
}
}
OnAnnotationEvent
public class OnAnnotationEvent implements MethodInterceptor {
#Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("Annotation called on: " + invocation.getMethod().getName();
return invocation.proceed();
}
}
MyAnnotation
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface MyAnnotation {}
I think that your problem is that you creating new injector that does not knows anything about your class. If you just need injector in your class - use #Inject private Injector injector;. If you need to load some aditional modules locally you just need to create child injector :
#Inject private baseInjector;
...
injector = baseInjector.createChildInjector(new Module1(),new Moddule2());
This doesn't work because your Service instance isn't managed by Guice. To make it work you must either create Service with Guice or annotate method doStuff in DataAccessImpl with MyAnnotation.
In my spring-based project I have a core module ('core') with a class
#Component
public class Superclass {
// stuff
}
instances of which are injected by type throughout the code like this:
public class AService {
#Autowired
private Superclass superclass;
// service stuff
}
I also have two other modules that depend on the core module and one of which (let's call it 'module1') extends Superclass:
#component
public class Subclass extends Superclass {
// overridden stuff
}
The other module ('module2') uses Superclass as is.
Now I want that when I compile and run 'child1' an instance of Subclass is used everywhere an instance of Superclass is expected. So I write a configuration class:
#Configuration
public class Module2Configuration {
#Bean
public Superclass superclass(){
return new Subclass();
}
}
When I run this I see both Superclass and Subclass instantiated which is definitely not what I want. How do specify in 'module1' which type Spring should instantiate?
You can use #Qualifier("some name") annotation.
There is more information about that: http://blogs.sourceallies.com/2011/08/spring-injection-with-resource-and-autowired/
Spring eagerly instantiates singleton beans as stated in the documentation:
By default, ApplicationContext implementations eagerly create and configure all singleton beans as part of the initialization process.
which might explain why both #Components are created.
To specifiy which implementation is provided as a dependency you might want to check on Qualifiers that enable to choose between different implementations. In combination with lazy loading this should do the trick.
Depending on your personal taste you could also use delegation instead of inheritance using a separated interface:
public interface MyService {
public String foobar(int baz);
}
public static class CommonBehavior {
// whatever is used by Superclass and Subclass
}
#Component #Lazy
public class FormerSuperClass implements MyService {
private final CommonBehavior ...;
...
}
#Component #Lazy
public class FormerSubClass implements MyService {
private final CommonBehavior ...;
...
}
Good luck!
There are 2 methods: Use #Qualifier("SubclassName") Or Mark your subclass as #Component and declare the subclass when #Autowired
In your case:
Use #Qualifier("SubclassName")
#Component
public class Superclass {
// stuff
}
#component
public class Subclass extends Superclass {
// overridden stuff
}
public class AService {
#Autowired
#Qualifier("Subclass")
private Superclass superclass;
// service stuff
}
2.Mark your subclass as #Component and declare the subclass when #Autowired
public class Superclass {
// stuff
}
#component
public class Subclass extends Superclass {
// overridden stuff
}
public class AService {
#Autowired
private Subclass subclass;
// service stuff
}