Performing both setter and constructor injection - spring

I am new to spring framework. I tried to inject dependency with both the injection methods(Setter and constructor). I was expecting the output defined in setter injection as it is overridden against constructor injection. But, I have received error message like
Bean creation exception:No default constructor found
If we apply both the injection methods,will it throw error?

I tried to inject dependency with both the injection methods(Setter
and constructor).
You should be able to do that. According to the Spring version, the result may differ but I can confirm that it works with the Spring 5 version.
Your error :
Bean creation exception:No default constructor found.
makes think that the constructor with the argument is not considered by Spring as a way to autowire your bean.
In old Spring versions (3 and less and maybe 4 I didn't remember), you have to specify #Autowired in the constructor to make Spring aware of it.
So you should declare :
#Autowired
public void setMyDep(MyDep myDep) {
this.myDep = myDep;
}
#Autowired
public FooBean(MyOtherDep myOtherDep) {
this.myOtherDep = myOtherDep;
}
In recent Spring versions, declaring #Autowired is not required any longer :
#Autowired
public void setMyDep(MyDep myDep) {
this.myDep = myDep;
}
public FooBean(MyOtherDep myOtherDep) {
this.myOtherDep = myOtherDep;
}

Related

Spring Boot Constructor based Dependency Injection

I'm a beginner with Spring Boot and Dependency Injection and I can't get my head around Constructor based Dependency Injection in Spring Boot. I have class called ParameterDate that look like this:
public class ParameterDate {
private Date parameterDateUnadjusted;
private Date parameterDateAdjusted;
private Date parameterDateAdded;
private Date parameterDateChanged;
}
I have another class where I want to use ParameterDate. Normally I would do Field based Injection with
#Autowired
ParameterDate parameterDate;
And where ever needed I just use parameterDate.
How would I do this with Constructor based Injection?
public MyClazzRequiringParameterDate(ParameterDate parameterDate){
this.parameterDate = parameterDate;
}
Since Boot 1.4 #Autowired has been optional on constructors if you have one constructor Spring will try to autowire it. You can just tag the constructor with #Autowired if you want to be explicit about it.
Generally speaking you should favour Constructor > Setter > Field injection. Injecting directly to the field misses the point of DI, it also means your tests are reliant on Spring to inject dependencies into rather than just being able to pass mocks or stubs directly to it. Jurgan Holler has stated that he would remove field injection if at all possible.
#Component
public class ParameterDate {
private Date parameterDate;
#Autowired
public ParameterDate(Date parameterDate){
this.parameterDate = parameterDate;
}
}
Above is an example of constructor injection.
Note that you can use #Autowired annotation also on property's setter method, and since there is no difference between setter method (except of course it's purpose, logic it contains) and any other method, you can use #Autowired on just about any method of the class.
Since autowiring and component scanning go hand in hand, you should mark your class with #Component annotation. This tells Spring that a bean should be created for this class.

POJO Injection in Spring similar to CDI

I have some java objects coming from external library which I need to inject in my spring project. Problem is the classes from library is not aware of any spring api's
If I inject the beans from library to Service using #Autowired I am getting org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type
Following is my service class
#Path("/test")
public class TestService {
#Autowired
SomeOtherClass service;
#GET
public Response get(){
return Response.ok(service.someMethod()).build();
}
}
and following is my class from library which is not aware of spring
public class SomeOtherClass {
public String someMethod(){
return "Data from library";
}
}
When I invoke my service I get exception as
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.SomeOtherClass' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Is there are way in spring to inject a plain Java Object similar to that of injection in **CDI**?
There is one option to define applicationcontext.xml and define SomeOtherClass in xml and use getBean, but I don't want to do that. Is there any other option?
Note:
Following options cannot be considered because I have100's of classes coming from library
Cannot use applicationcontext.xml
Cannot #Configuration #Bean to produce beans.
You could use the #Configuration and #Bean annotations as follows -
Create a new class:
#Configuration
public class AppConfig {
#Bean
SomeOtherClass someOtherClassBean(){ return new SomeOtherClass();}
}
Now the auto wiring shall work.
What it does, is actually creating a bean and letting Spring know about it.
Maybe try adding the beans programatically to the IoC container:
Add Bean Programmatically to Spring Web App Context
You need to find all the classes you want to instantiate and use one of the methods in the linked question.
You can use reflection to add Bean definitions programatically.
#Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
Reflections ref = new Reflections(new ConfigurationBuilder()
.setScanners(new SubTypesScanner(false /* don't exclude Object.class */), new ResourcesScanner())
.setUrls(ClasspathHelper.forPackage(PACKAGE_NAME))
.filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix(PACKAGE_NAME))));
ref.getSubTypesOf(Object.class).stream()
.forEach(clazz -> {
logger.info("Defining pojo bean: {} -> {}", Introspector.decapitalize(clazz.getSimpleName()), clazz.getCanonicalName());
registry.registerBeanDefinition(Introspector.decapitalize(clazz.getSimpleName()),
BeanDefinitionBuilder.genericBeanDefinition(clazz).getBeanDefinition());
});
}
Subsequently, these beans can be #Autowired elsewhere. See Gist: https://gist.github.com/ftahmed/a7dcdbadb8bb7dba31ade463746afd04

How to get instance of prototype bean in Grails?

In Spring, if I define a prototype bean, I can inject it using lookup method injection at the current time of Spring Framework 4.3.0.RELEASE.
In Grails, how do I inject a prototype bean at runtime? Grails 2.5.4 docs show how to set bean.scope = 'prototype" and bean.singleton = false but does not actually give an example of how to inject a non-singleton bean.
I haven't seen much use of prototype-scope beans in Grails, and what I've seen uses the pattern described in the Spring docs that works directly with the ApplicationContext. I assume that you could use the same method injection approach in Grails that you use in Spring, but here's a simple factory class that doesn't involve CGLIB subclassing but is otherwise similar. It does retrieve a prototype instance from the ApplicationContext, but that's hidden in the implementation and doesn't clutter your application code:
package com.yourcompany
import groovy.transform.CompileStatic
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationContextAware
#CompileStatic
class PrototypeFactory<T> implements ApplicationContextAware {
ApplicationContext applicationContext
final Class<T> beanClass
final String beanName
PrototypeFactory(Class<T> beanClass, String beanName) {
this.beanClass = beanClass
this.beanName = beanName
}
T getInstance() {
applicationContext.getBean(beanName, beanClass)
}
}
To use it, register a bean for the class, providing the bean name and bean class of the prototype bean (in resources.groovy, or in a plugin's doWithSpring):
beans = {
cartFactory(PrototypeFactory, ShoppingCart, 'shoppingCart')
}
Now you can inject the factory bean and call getInstance(), and it will return a new prototype instance, and since it's using generics you don't need any casts:
class SomeClass {
PrototypeFactory<ShoppingCart> cartFactory
...
def someMethod() {
ShoppingCart newCart = cartFactory.instance
...
}
}
You can reuse the factory class to register as many of these as you want for various prototype beans as long as they have unique bean names.
None of the names are significant, so change getInstance() to whatever you prefer, and change 'Factory' to 'Manager' or whatever.

Does Spring expects all the beans when starting the web application?

I have a Spring web application. The bean I showed below is not required by the web application. So I mentioned the condition not to load on web application.
Also I am not scanning the package where this bean is defined in my ApplicationConfig.java. But I am still getting the exception
Could not autowire field: private com.Foo; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.Foo] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.
#Bean
#ConditionalOnNotWebApplication
#ConditionalOnProperty(name=LNACALL, havingValue = "true")
public Foo createFoo() {
return new Foo();
}
It looks like you might have an #Autowired annotation somewhere else in your application that expects a bean of that type. You can try doing one of the following:
#Autowired(required=false) with field injection to indicate that it is optional
#Autowired(required=false) private Foo foo;
Use setter injection instead by putting the #Autowired on a setter:
#Autowired(required=false)
public void setFoo(Foo foo) {
this.foo = foo;
}
To sum up, constructor based dependency injection (#Autowired on the constructor) is for mandatory dependencies. The required flag in #Autowired will be ignored and the bean must be present.
Setter based and field injection can be used for optional dependencies if the #Autowired required flag is set to false. If the required flag is set to false, then Spring will inject the bean if it is present. If it is not present, then the the value will be null.

Spring 3.0.5 prototype Bean Instance variables become null after method call

Having the strangest Spring problem where after a Spring bean is created using Dependency Injection, and then running some method on the bean, the instance variables that are set during the bean method call all return to their default Java values. Found this happening after we moved from Spring 2.5.5 to Spring 3.0.5.
So for clarity sake here is the example
The Prototype bean:
#Component("bean1")
#Scope("prototype")
public class Bean1{
String someString;//There are other instance variables but same happens to them
#Autowired
#Qualifier("otherBean")
private OtherBean otherBean;
public void doSomething(){
someString="1234ABC";
}
//setters and getters ....
}
And the code that grabs the bean from spring and uses it:
Bean1 bean1 = (Bean1) applicationContext.getBean("bean1");
bean1.doSomething();//updates some instance variables in bean1
String value = bean1.getSomeString(); //Instance variables is null
Object otherObject = bean1.getOtherBean(); //This Spring injected bean is correctly initialized
So if I debug into the code, the instance variables (someString) is set in bean while in the doSomething method call but right after I return, the value goes back to null.
Worst thing is that this all works as expected in 2.5.5 but not in the updated Spring 3.0.5
This is legacy code so I know that you are supposed to code to interfaces and so the Bean1 should be an interface and the class that implements the interface should do the actual work. I changed the code to this model as well and still does not work.
Try #Scope(value="prototype", proxyMode=ScopedProxyMode.TARGET_CLASS)
I was facing the same issue but couldn't got the exact solution. Then I just changed the scope to request.

Resources