Spring autoscanning of Components failed - java

I want to schedule a method in my spring application, i've found documentation here http://spring.io/guides/gs/scheduling-tasks/, well it works, but i dont understand why i can't autowire a bean in class annotated with component annotation.
#Service
public void MyService { ... }
#Controller
public void RestController {
#Autowired
private void MyService service;
}
Everything works here, the field "service" is properly set, no warning/exceptions in console
#Component
public void Scheduler {
#Autowired
private void MyService service;
}
There im getting an exception and application wont start. The class Scheduler is in same package as RestController and MyService but im getting exception
SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'Scheduler': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private some.package.MyService some.package.Scheduler.service; nested exception is java.lang.IllegalArgumentException: Can not set some.package.MyService field some.package.Scheduler.service to $Proxy176

Actually Spring tries to create Proxy from your MyService (e.g. because of #Transactional annotation on method). The proxy is not MyService instance and can't be autowired.
You can try to introduce MyService interface and define MyServiceImpl class implementing the interface. Then you can use MyService interface with #Autowired

Because spring is not able to find bean to inject at
#Autowired
private void MyService service;
You don't have to declare a bean in your context file if you
Annotate the class with: #Component or #Service or #Controller or
#Repository
you have given #service on method that's wrong
You need to create bean of class MyService from xml or make class
MyService and use #Component as you have done with Scheduler class

Related

How to initialize bean method defined in Main class into test context

I have created a bean method in the main class:
#SpringBootApplication
#EnableScheduling
public class SpringApplication{
#Bean
Public String getCronValue(ServiceImpl service){
return service.getConfig().get("cron duration");
}
}
using this bean in a scheduled task:
#Component
public Class MySch{
#Scheduled(cron="#{getCronValue}")
public void schedulerMethod(){
//Do something
}
}
Now the problem is when I try to run JUnit tests #Bean GetCronValue is not initialized in test context and #Scheduled annotation throws an exception:
Update:-
It throws an exception:-
BeanCreationException: Error creating bean with name
'SchedulerMethod' : Initialization of bean failed; nested
exception is ' org. springframework.beans.
factory.Beanexpressio exception: Expression parsing
failed; nested exception is org. springframework.
expression.spel.SpelEvaluationException: EL1021E: A
problem occurred whilst attempting to access the
property ' getCronValue' : Error creating bean with name
'getCronValue' : Unsetisfied dependency expressed
through method 'getCronValue' parameter 0; nested
exception is org. springframework. beans. factory.
NoSuchBeanDefinitionException: No qualifying bean of
type 'com.pkg.service.ServiceImpl' available: expected at
least 1 bean which qualifies as a autowire candidate.
Dependemcy annotations: {}'
My Controller test class looks like:-
#Transactional
public class ControllerTest{
#MockBean
private Service service;
.
.
// test cases
}
How to resolve this issue.
I assume that you're using #SpringBootTest annotation.
When you test a Controller you may want narrow the tests to only the web layer by using #WebMvcTest. Any other dependencies required by the controller will be then mocked using #MockBean.
When #WebMvcTest is used Spring Boot instantiates only the web layer rather than the whole context. In an application with multiple controllers, you can even ask for only one to be instantiated for example.
#WebMvcTest(controllers =Controller.class)
public class ControllerTest{
#MockBean
private Service service;
#Autowired
private MockMvc mockMvc;
// test cases
}
I noticed that you have the #Transactional annotation in your example. This can indicate that you maybe giving too match responsibilities to your controller and may consider passing Database access related logic to a service/repostory/DAO
See https://spring.io/guides/gs/testing-web/

spring - ApplicationContext registerBean autowiring fails but getBean works in Spring 5

I'm using a configuration class that uses dynamic bean registration:
#Configuration
public class ConfigClass {
#Autowired
private GenericApplicationContext applicationContext;
#PostConstruct
private void init() {
System.out.println("init");
applicationContext.registerBean("exService", ExecutorService.class, () -> Executors.newFixedThreadPool(10), bd -> bd.setAutowireCandidate(true));
System.out.println("init done");
}
}
If I try to autowire the bean, application startup fails with error Field exService in com.example.DemoApplication required a bean of type 'java.util.concurrent.ExecutorService' that could not be found.
From the logs I can see that the init method on config class wasn't called before the error as the two system out statements were not printed out.
However, when I use applicationContext.getBean(ExecutorService.class) it does work without any issues.
Anyway I can get the bean to Autowire?
I'm deliberately not using the #Bean annotation because I need to register the beans dynamically based on certain conditions.
It could be because you are registering your bean in the middle of the context initialization phase. If your target bean initializes and auto-wires ExecutorService before ConfigClass #PostConstruct is invoked there simply is no bean available.
You can try forcing the initialization order:
#Component
#DependsOn("configClass")
public class MyComponent
#Autowired
private ExecutorService executorService;
However it would be cleaner to register a bean definition using BeanFactoryPostProcessor with BeanDefinitionBuilder:
#Component
public class MyBeanRegistration implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory bf) {
BeanDefinitionRegistry reg = (BeanDefinitionRegistry) bf;
reg.registerBeanDefinition("exService",
BeanDefinitionBuilder
.rootBeanDefinition(ExecutorService.class)
.setFactoryMethod("newWorkStealingPool")
.getBeanDefinition());
}
}
You can do like this:
#Resource
#Lazy
private ExecutorService executorService;
It works.
Actually, I wrote the small infrastructure that deals with such issues. Here is the idea how to do this:
Create a class (lets call it MyClass) that incapsulates ExecutorService.class as a property and declare it as Bean (#Component). Even before that create an Interface (Lets call it MyInterface) that your new class would implement
Create a factory class (Lets call it MyFactory) with method MyInterface getInstance(String) that returnce an instance of your interface. In that factory crate a static property Map[String, MyInterface] and public static method that allows you to add instances of the interface to this map
In MyClass create a constructor that at the end will place newly created instance of itself into that map in the factory with the key of your class name ("MyClass")
Now The trick is that when Spring starts and initializes it creates all its beans. As your MyClass will be created its constructor will place its instance into a factory. So now anywhere in your code you can call:
MyInterface myInterface = MyFactory.getInstance("MyClass");
And you get your bean without worrying about instantiating it. Spring already did it for you. Big extra bonus is non-intrucivness - you don't have to explicitely work with Spring classes

Transactional annotation error

When I put "#Transactional(readOnly=false)" annotation in my Service class I get the following error
Description:
The bean 'studentService' could not be injected as a
'com.student.service.StudentServiceImpl' because it is a JDK dynamic
proxy that implements: com.student.service.StudentService
Sample code:
#Service("studentService")
#Transactional(readOnly=false)
public class StudentServiceImpl implements StudentService {
}
public interface StudentService {
}
Action:
Consider injecting the bean as one of its interfaces or forcing the use of CGLib-based proxies by setting proxyTargetClass=true on #EnableAsync and/or #EnableCaching.
Process finished with exit code 1
What is causing this?
As SO already mentioned on the comment, the error occurs when you are trying to inject/autowire the implementation class instead of interface.
The bean 'studentService' could not be injected as a
'com.student.service.StudentServiceImpl' because it is a JDK dynamic
proxy that implements: com.student.service.StudentService
On the setup posted by SO,
public class StudentServiceImpl implements StudentService {
}
public interface StudentService {
}
If you autowire the interface as below you won't get an error:
#Autowired //or #Inject
StudentService studentService;
in spring boot projects, try to add :
spring.aop.proxy-target-class=true
to your application.properties
OR
#EnableAspectJAutoProxy(proxyTargetClass = true)
to your spring boot entry point.
In your application class file add this:
#SpringBootApplication
#EnableCaching(proxyTargetClass = true)
I had similar problem and resolved in this way

Call service method from non controller class

In HomeController i am doing the following
#Controller
public class HomeController {
#Autowired
private EUserService userDao;
#RequestMapping(value = "/")
public String setupForm(Map<String, Object> map) {
User user=(User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
EUser currentUser = userDao.findUserByName(user.getUsername());
System.out.println(currentUser.getUserName());
}
}
It works fine and shows me the output properly. Now If I do the same thing in a non controller type class like following
public class Utility {
#Autowired
private EUserService userDao;
public void getLoggedUser() {
User user = (User) SecurityContextHolder.getContext()
.getAuthentication().getPrincipal();
EUser currentUser = (EUser) userService.findUserByName(user
.getUsername());
System.out.println(currentUser.getUserName());
}
}
it gives me the following NullPointerException
SEVERE: Servlet.service() for servlet [spring] in context with path [/Ebajar] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
java.lang.NullPointerException
How to fix this??
The problem is not that you are calling this not from controller. The problem is that your are calling this from class that is not managed by Spring, so the userDao is not injected here.
It think that "right" solution is to turn your utility to Spring bean, e.g. marking it as #Service and call it via Spring. Alternatively you can retrieve it programmatically using ApplicationContext.getBean() (see here for details)
you should declare/annotate your Utility class as a spring bean so that let other bean get injected. in this case, it is EUserService
try adding #Component to your Utility class. I assumed your package is involved by spring annotated bean scanning settings.
Only Spring managed bean can autowire an instance. Read here
You annotate Utility with #Component.

#Autowired is not working with beans defined in application context file

I defined a bean in spring context file 'applicationContext.xml' like below :
<bean id="daoBean" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="com.xxx.DAOImpl" />
</bean>
In my service class (ServiceImpl), I am using this bean like below:
#Component("serviceImpl")
public class ServiceImpl{
// other code here
#Autowired
private transient DAOImpl daoBean;
// other code here
}
My service class is being accessed from my JUnit test class.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "/applicationContext.xml" })
public class JUnitTest{
// other code here
#Autowired
private transient ServiceImpl serviceImpl;
// test cases are here
}
When I execute the test case, it gives error saying:
Error creating bean with name 'ServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private transient com.xxx.DAOImpl
When I remove #Autowired from service class and use #Resource(name = "daoBean") the test case works fine.
public class ServiceImpl{
// other code here
#Resource(name = "daoBean")
private transient DAOImpl daoBean;
// other code here
}
My question is why #Autowired is not working in this case? Do I need to configure any thing else with #Autowired, so that it can work properly. I don't want to change my service layer classes to replace #Autowired to #Resource.
Mockito.mock() has a generic return type T which is erased at runtime, so Spring cannot infer the type of the created mock that will be simply registered as Object in the Spring context. That's why #Autowired doesn't work (as it tries to look up the dependency by its type).
Check out this answer for a solution to the problem.

Categories

Resources