How do you get DI to work in a webapp? So far I've done the following:
1) Annotate setter method with #Inject
2) Extend AbstractModule so that it binds the interface class to the implementation class for the attribute whose setter was annotated in step 1
3) Extend GuiceContextServletListener and overrode getInjector so that it returns Guice.createInjector(new ExtendedAbstractModule())
4) Registered the extended GuiceContextServletListener in web.xml as a listener
I've verified that the extended GuiceContextServletListener.getInjector() method is called when the webapp is started. The attribute whose setter was annotated is not being injected and remains null.
I went ahead and created a ServletModule that serves the servlet that instantiates the object with the #Inject setter. After instantiating the object I get the Injector from the ServletContext and call the injectMembers method passing it the instantiated object.
What annotation are are you using on the setter?
I normally use #Named annotation to get attribute values which can be pointed to a property file or setup individually.
http://code.google.com/p/google-guice/wiki/BindingAnnotations
#Inject
void somethingSetter(#Named('Tag')String s) {
}
There is a tutorial of how to setup a complete Java web service using Guice and Sitebricks here:
http://www.techtraits.ca/five-minute-guide-to-setting-up-a-java-webserver/
Related
I have a Quarkus application that works in batch mode. I have a QuarkusMain class, with a method that implements QuarkusApplication interface.
That method is a static method, so I'm not able to inject Beans because they have a null value.
What is the way to inject Beans in Quarkus from a static method in a QuarkusMain class?
Thanks.
Are you really after creating beans in the static method, or more just after how to startup Quarkus ?
In main method the only thing you need to do is call Quarkus.run(YourMain.class, args); which then will make YourMain class a bean and in here allow #Inject.
You can also use picocli which also ends up with a class you can use #Inject.
Example of that I have here: https://github.com/jbangdev/jbang-catalog/blob/master/catalog2readme.java
You can use Arc class in this way:
Annotate your beans with a #Startup annotation.
https://quarkus.io/guides/lifecycle#startup_annotation
Then, in your static method:
YourBean yourBean = Arc.container().instance(YourBean.class).get();
I want to define a annotation like #PlatformRelated, once it is marked in a interface, there will be a proxy bean at spring context, and this proxy bean should be #Priority.I want this proxy could invoke different implement according to key parameter #KeyPrameter.And I still wanna use spring features like #Async,#Trasaction,etc... at my Implement1 and Implement2.
#PlatformRelated
interface MyInterface {
method(#KeyPrameter String parameter);
}
#Component
class Implement1 implements MyInterface {
method(String parameter){
//do something 111
}
}
#Component
class Implement2 implements MyInterface {
method(String parameter){
//do something 222
}
}
#Service
class BusinessService{
#Autowired
private MyInterface myInterface;
public void doSomething() {
myInterface.method("key1");
//Implement1 work
myInterface.method("key2");
//Implement2 work
}
}
Do you guys have some good idea to complete it?
I must admit I haven't totally understood the meaning #Priority, however, I can say that if you want to implement this feature in spring, you should probably take a look at Bean Post Processors.
BeanPostProcessors are essentially a hook to Bean Creation process in spring intended for altering bean behavior.
Among other things, they allow wrapping the underlying bean into the proxy (CGLIB/java.lang.Proxy if you're working with interfaces, or even using programmatically Spring AOP), these proxies can provide a hook to the method execution that can read your annotations (like mentioned #KeyParameter) and execute a code in a way similar to Aspect's code that you already make use of.
Not all bean post processor wrap the bean into the proxy. For example, if you want to implement a BPP that uses "#Autowire", you will return the same bean, just "inject" (read, put by reflection) its dependencies. On the other hand, if you want to implement with BPP #Transactional behavior, then yes, you should wrap the bean into a proxy that would take care of transaction management capabilities before and after the method execution.
It's totally ok to have a spring bean that gets "altered" by many post processors, some of them would wrap it into a proxy other will just modify-and-return the same bean, If there are many BPP-s that wrap the bean into proxy we'll get "proxy inside proxy inside proxy" (you get the idea). Each layer of proxy will handle one specific behavior.
As an example, I suggest you take a look at existing Spring postprocessors, or, for instance, a source code of the following library: Spring Boot metering integration library
This library contains some implementations of post processors that allow metrics infrastructure integration by defining annotations on methods of Spring Beans.
I have a Wicket panel in which I want to inject bean using #SpringBean
public class SomePanel extends Panel {
#SpringBean
private BlogSummaryMailGenerator blogSummaryMailGenerator;
}
But this BlogSummaryMailGenerator has injection via constructor defined like this:
#Component
public class BlogSummaryMailGenerator {
private BlogRepository blogRepository;
private BlogPostRepository blogPostRepository;
#Autowired
public BlogSummaryMailGenerator(BlogRepository blogRepository,
BlogPostRepository blogPostRepository) {
this.blogRepository = blogRepository;
this.blogPostRepository = blogPostRepository;
}
}
And when SomePanel is instantiated I am getting an exception
Caused by: java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
at net.sf.cglib.proxy.Enhancer.emitConstructors(Enhancer.java:721) ~[cglib-3.1.jar:na]
at net.sf.cglib.proxy.Enhancer.generateClass(Enhancer.java:499) ~[cglib-3.1.jar:na]
at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25) ~[cglib-3.1.jar:na]
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216) ~[cglib-3.1.jar:na]
at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377) ~[cglib-3.1.jar:na]
at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:285) ~[cglib-3.1.jar:na]
at org.apache.wicket.proxy.LazyInitProxyFactory.createProxy(LazyInitProxyFactory.java:191) ~[wicket-ioc-7.2.0.jar:7.2.0]
Adding empty no-args constructor to the BlogSummaryMailGenerator solves this issue but adding such code only to make injection work is wrong and I would like to avoid it.
Any suggestions how to make #SpringBean work with beans using injection via constructor?
The real problem is in CGLIB. It requires a default constructor to be able to create the proxy instance. The real Spring bean is created separately by Spring and has no such restrictions. The default constructor needed by CGLIB could be even private as far as I remember.
Update: Since Wicket 9.5.0 Wicket could also use ByteBuddy instead of CGLib.
Another solution is to use an interface for this bean. Then Wicket will use JDK Proxy instead of CGLIB and in this case there is no need of default constructor in the implementation.
Solution
To be able to take advantage of constructor injection for #SpringBean in Wicket components you just have to add Objenesis to your compile time dependencies.
Explanation
Objenesis is a little and less known byte code manipulation library which (in opposite to CGLIB provided together with Wicket) is able to create a proxy object for a class which has no default (no args) constructor. If you add it as a compile dependency to your project then Wicket will switch it's internal lazily initializable proxy creation logic to take advantage of Objenesis (instead CGLIB which requires no args constructor) while instantiating a proxy. Unfortunately this feature is not documented but I can confirm it works in my case.
The error message is pretty clear. Wicked trying to create instance of proxy class for BlogSummaryMailGenerator with CGLIB library. Since you didn't (or you can't) provide arguments to constructor, it looking for contstructor with no arguments. But it can't, and you get error.
Just replace constructor injection with property injection, and create no argument constructor:
#Component
public class BlogSummaryMailGenerator {
#Autowired
private BlogRepository blogRepository;
#Autowired
private BlogPostRepository blogPostRepository;
public BlogSummaryMailGenerator() {}
}
Actually, you do not need to declare an empty constructor. I did it just for clarity. Note, that BlogRepository and BlogPostRepository should be declared as beans (marked with #Component annotation, or created as #Bean in Spring configuration).
UPDATE:
When you add SpringComponentInjector in your WebApplication.init(), you can specify false for third paramter, which means 'wrapInProxies'. Wicket will never wrap Spring beans in porxy, and you can use #Autowired for constructors.
#Override
public void init()
{
super.init();
AnnotationConfigApplicationContext springContext =
new AnnotationConfigApplicationContext();
springContext.register(SpringConfig.class);
springContext.refresh();
getComponentInstantiationListeners().add(new SpringComponentInjector(this,
springContext, false));
}
The correct way to solve this is not to add Objenesis to your project, but to inject interfaces instead of concrete implementations, as #martin-g already explained (of course, we do not always have the privilege to be able to do the right thing, but when we do, we should do it).
I have a project that started to give the exact same error and stack after a library update I still don't exactly understand (complete Maven dependency hell, I inherited it, go easy on me). The reason was that I was creating a Spring request-scoped bean from a concrete subclass of ListModel<MyClass> and Wicket was hell bent on wrapping that class into a lazy loaded proxy, which it couldn't do because there was no zero-args-constructor.
I fixed it by changing the configuration class to create a named instance of IModel<List<MyClass>> and by defining the injected dependency using the name.
In the configuration class:
#Bean(name = "namedModel")
#RequestScope
public IModel<List<MyClass>> myObjectList() {
return new MyClass(parameters);
}
In the component:
#Inject
#Named("namedModel")
private IModel<List<MyClass>> myModel;
I have a utility class which I want to initialize when the application starts in Spring MVC. So I am implementing InitializingBean. Now I have to create an object for the same and save it in Application scope so that I can access the same instance everywhere. But I am not able to get hold of this.
Here is my try:
public class DashboardInitializer implements InitializingBean, ApplicationContextAware {
private ApplicationContext mApplication;
#Override
public void afterPropertiesSet() throws Exception {
initializeConfigurationUtil();
ConfigurationUtil util = ConfigurationUtil.getInstance();
/* Save the util to application scope */
}
#Override
public void setApplicationContext(ApplicationContext pApplication) throws BeansException {
this.mApplication = pApplication;
}
}
Is this approach correct or there is a better way to do that?
I think you need to simplify this a little bit.
You want the utility class to be initialized after your application context is loaded, but you also want your util class to be in the application context?
Seems the util class has some dependency objects configured in the application context, and the util class is in turn a dependency of some classes in the application context.
If you can express these dependencies in the form of beans (util is a bean, which has its dependency beans injected into it, and beans that need util have util injected into them), Spring will ensure that all dependencies of util are initialized first, then util is initialized and then it is injected into classes that need util.
You should not try to add something to an initialized context.. Its not possible.
If you cannot express util and its dependencies as beans, you can also take this approach:
1. Configure util as a bean in the application context, add a default constructor that does nothing. So this object would be created, but not initialized when the spring context is loaded.
In the ApplicationContextAware implementation you have, modify the setApplicationContext method. Get the util bean you configured earlier from the context.
You can now initialize (execute some code that you want to execute) the util instance, just make sure you do not try to reassign the bean to some other instance of util.
Hope this helps.
You can use #postconstruct annotation on methods to perform business logic immediately after the application has been initilized. And properties can simply be injected using placeholder in config and #Value annotation on java fields.
Application Server: JBOss 4.2
I have a method which I want to intercept.Its a method annotated #Timeout and invoked by javax.ejb.TimerService instance.
The method signature:
#Stateless
class A
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
#Timeout
#Interceptors(AnInterceptor.class)
public void doSomething(Timer timer)...
Now I have the interceptor class:
public class AnInterceptor {
#AroundInvoke
public Object intercept(InvocationContext ic) throws Exception{...
System.out.prin(...)
It does work on other method methods (which are not annotated with #Timeout)
Thanks,
Rod
Per the spec, AroundInvoke is not supported for timeout methods (business interface, component interface, and webservice endpoint only). Searching Google, AroundTimeout appears to be coming in EJB 3.1 (pages 12 and 22):
http://www.ow2.org/xwiki/bin/download/Events2009AnnualConference/Program/JavaEE6-EasyBeans-F-Benoit.pdf
In the meantime, you can workaround the issue by injecting a reference to the same bean into itself. In other words inject (or lookup) another "A" from within "A", and then create and invoke a new "doTimeout" method from your "doSomething" method.
Instead of using #AroundInvoke, try using #AroundTimeout
"Interceptors for EJB timer service timeout methods may be defined using the #AroundTimeout annotation on methods in the target class or in an interceptor class. Only one #AroundTimeout method per class is allowed."
Here you can see how to use it, under the section "Intercepting Timeout Events"
http://docs.oracle.com/javaee/6/tutorial/doc/gkedm.html#gkedu