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

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.

Related

Using Prototype scope to create DataSource

I'm trying to create a Prototyped Scoped Spring bean using the given configuration. The details for url, username, password, driver will be determined at runtime. Here's my configuration:
#Configuration
class Cfg {
#Bean
public Function<DataSourcePropertiesMap, DriverManagerDataSource> functionOfDriverMgrDS() {
return this::driverManagerDataSource;
}
#Lazy
#Bean
#Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public DriverManagerDataSource driverManagerDataSource(DataSourcePropertiesMap dbPropsMap) {
var ds = new DriverManagerDataSource(dbPropsMap.getDbURL(), dbPropsMap.getDbUsername(), dbPropsMap.getDbPassword());
ds.setDriverClassName(dbPropsMap.getDbDriver());
return ds;
}
}
And the DataSourcePropertiesMap is simply a container for the four arguments as below:
#Getter
#AllArgsConstructor
public class DataSourcePropertiesMap {
#NonNull private final String dbURL;
#NonNull private final String dbUsername;
#NonNull private final String dbPassword;
#NonNull private final String dbDriver;
}
Whenever, I boot the application it throws the following exception:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'healthContributorRegistry' defined in class path resource [org/springframework/boot/actuate/autoconfigure/health/HealthEndpointConfiguration.class]: Unsatisfied dependency expressed through method 'healthContributorRegistry' parameter 2; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'dbHealthContributor' defined in class path resource [org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthContributorAutoConfiguration.class]: Unsatisfied dependency expressed through method 'dbHealthContributor' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'driverManagerDataSource' defined in class path resource [Cfg.class]: Unsatisfied dependency expressed through method 'driverManagerDataSource' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'DataSourcePropertiesMap' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
Why Spring still requires arguments for DriverManagerDataSource with valid driver class for Prototyped Scoped beans. My assumption is it will register a bean someway and create a new instance whenever a call is made with the arguments. If I create a default bean of type DataSourcePropertiesMap with dummy values it requires a valid driverclass.
Editing my original answer since I have not seen this part of the question
The details for url, username, password, driver will be determined at
runtime.
As of spring boot 2.x there is still no automatic way of loading properties on runntime. You would have to manually parse the file and read those properties inside this prototype bean method.

Performing both setter and constructor injection

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;
}

Spring Test + Mockito.mock - Spring fails because it tries to load the mocked bean #Autowired dependencies

I can't find out why the following simple scenario is failing: I have a Spring application with a filter that loads a Spring bean from the application context:
public class MyFilter implements Filter{
private IPermissionService permissionService;
public void init(FilterConfig filterConfig) throws ServletException {
WebApplicationContext ac = null;
try{
ac = WebApplicationContextUtils.getRequiredWebApplicationContext(filterConfig.getServletContext());
permissionService = ac.getBean(PermissionServiceImpl.class);
PermissionServiceImpl has an #Autowired attribute dataSource so in my TestNG test, I mock it in the Spring applicationContext:
#Configuration
public class MyFilterSpringTestConfig{
#Bean
public IPermissionService permissionService(){
return Mockito.mock(PermissionServiceImpl.class);
}
MyTest:
#Test
#WebAppConfiguration
#ContextConfiguration(classes=MyFilterSpringTestConfig.class)
public class MyFilterSpringTest extends BaseSpringFilterTest{
...
The problem is that on Spring initialization I get an exception complaining that PermissionServiceImpl's dataSource dependency is not satisfied. Since I wrapped it with a mock, why is it still failing? How could I fix it?
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true), #org.springframework.beans.factory.annotation.Qualifier(value=myDataSource)}
When mocking a class using Mockito (or any other mocking framework) that class is still an instance of the original class. With that comes that it also contains all the annotations and class information with it.
So when you create a mock of the class it still detects all annotations on it and tries to full fill that. I.e. #Autowire other instances.
Either don't use auto wiring or don't mock the class but the interface (which doesn't contain that information).

How to create a Spring bean for apache logging Log class?

I'd like to create an autowired bean in a Dao class in order to do logging opperations. My way was hitherto static final statement like this:
private static final Log log = LogFactory.getLog(LoggedClass.class);
But now I'm trying to use IoC to turn classes decoupled.
If just add configuration in pom.xml and try to do sth like
#Autowired
Log log;
I receive an error message:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'funciDaoImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.apache.commons.logging.Log br.com.bb.dirco.dao.impl.FunciDaoImpl.log; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'log' defined in class path resource [com/company/project/util/PersistenceConfig.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [java.lang.Class]: : No qualifying bean of type [java.lang.Class] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [java.lang.Class] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
In order to get a logger, I had to provide a class to getLog method on LogFactory class and attribute it to Log instance. There's a way to do it using #Autowired Spring IoC? Thanks!
You can inject only those objects which are managed/created by Spring container. You have to register your bean (or factory method creating the bean) with container (with annotations like #Component/#Singleton/... or directly in xml)
In your case it's not very applicable since you have to have many different types (for every class) of logger objects provided by Spring and then when you inject they would have to be identified by different name/type for every class.
P.S. I don't see any problem using it the way you use it now
Where I work we have implemented support for #Autowired SLF4J Loggers using Springs BeanPostProcessor.
First you need to define an Logger placeholder bean in your application context. This bean is going to be injected by Spring into all bean with a #Autowired Logger field.
#Configuration
public class LoggerConfig {
#Bean
public Logger placeHolderLogger() {
return PlaceHolder.LOGGER;
}
#Bean
public AutowiredLoggerBeanPostProcessor loggerPostProcessor() {
return new AutowiredLoggerBeanPostProcessor();
}
}
Then you an AutowiredLoggerBeanPostProcessor which inspects all beans, indetify bean that contain Logger fields annotated with #Autowired (at this point should contain a reference to the Logger placeholder bean), create a new Logger for the partilcar bean an assigned it to the fields.
#Component
public class AutowiredLoggerBeanPostProcessor implements BeanPostProcessor, PriorityOrdered {
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
attachLogger(bean);
return bean;
}
#Override
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
attachLogger(bean);
return bean;
}
private void attachLogger(final Object bean) {
ReflectionUtils.doWithFields(bean.getClass(), new FieldCallback() {
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
if (Logger.class.isAssignableFrom(field.getType()) &&
(field.isAnnotationPresent(Autowired.class) ||
field.isAnnotationPresent(Inject.class))) {
ReflectionUtils.makeAccessible(field);
if (field.get(bean) == PlaceHolder.LOGGER) {
field.set(bean, LoggerFactory.getLogger(bean.getClass()));
}
}
}
});
}
#Override
public int getOrder() {
return HIGHEST_PRECEDENCE;
}
}

Spring expected at least 1 bean which qualifies as autowire candidate for this dependency

I have a trouble with this Autowire:
#Controller
public class ChiusuraController {
#Autowired
private ChiusuraProvider chiusuraProvider;
}
with this bean:
#Service #Transactional
public class ChiusuraProvider extends ThreadProvider {
public void run() {}
}
that extends
public abstract class ThreadProvider extends Thread implements InitializingBean, Runnable, DisposableBean {
...
}
I get this error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'chiusuraController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.cinebot.service.ChiusuraProvider com.cinebot.web.controller.ChiusuraController.chiusuraProvider; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.cinebot.service.ChiusuraProvider] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
I saw that I did not get this error if I remove extends ThreadProvider of autowired class, but I really need ThreadProvider abstract class.
If there is an interface anywhere in the ThreadProvider hierarchy try putting the name of the Interface as the type of your service provider, eg. if you have say this structure:
public class ThreadProvider implements CustomInterface{
...
}
Then in your controller try this:
#Controller
public class ChiusuraController {
#Autowired
private CustomInterface chiusuraProvider;
}
The reason why this is happening is, in your first case when you DID NOT have ChiusuraProvider extend ThreadProvider Spring probably was underlying creating a CGLIB based proxy for you(to handle the #Transaction).
When you DID extend from ThreadProvider assuming that ThreadProvider extends some interface, Spring in that case creates a Java Dynamic Proxy based Proxy, which would appear to be an implementation of that interface instead of being of ChisuraProvider type.
If you absolutely need to use ChisuraProvider you can try AspectJ as an alternative or force CGLIB based proxy in the case with ThreadProvider also this way:
<aop:aspectj-autoproxy proxy-target-class="true"/>
Here is some more reference on this from the Spring Reference site: http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/classic-aop-spring.html#classic-aop-pfb
You should put this line in your application context:
<context:component-scan base-package="com.cinebot.service" />
Read more about Automatically detecting classes and registering bean definitions in documentation.

Resources