Service Component object is not loaded in Spring Batch processor.But which is working fine with Spring Testing.Please help me to find the solution for this.
public class PersonJobProcessor implements ItemProcessor<Person,Person> {
#Autowired
PersonService service;
#Override
public Person process(final Person person) throws Exception {
//user service variable here
}
}
Error Message:-
Action:Consider defining a bean of type 'PersonService' in your configuration.
Below configuration is working fine
#SpringBootTest
#RunWith(SpringRunner.class)
public class PersonServiceTest {
#Autowired
PersonService service;
public void testmethod(){
service.method();// works without issues
}
}
Looks like missing SpringContext inside PersonJobProcessor. Did you add #Component on this class?
Related
I have a standard rest-api spring-boot application.
Controller with injected service
#RestController
#RequestMapping("/foo")
#AllArgsConstructor
public class SomeController {
private final SomeService someService;
public void someMethod(){
someService.toDoSomething();
}
}
and service with injected other beans
#Setter
public class SomeService {
private AnotherVeryImportantBean anotherVeryImportantBean;
private RestTemplateBuilder restTemplate;
public void toDoSomething() {
anotherVeryImportantBean.someAction();
}
In my case, the bean AnotherVeryImportantBean is created in another dependency, which I connect to the spring-boot application. Whether to create a bean or not is decided by a variable in the application.yml file.
like this:
another.service.enabled: true
Of course I have config class for service
#Configuration
#RequiredArgsConstructor
public class SomeConfig {
private final AnotherVeryImportantBean anotherVeryImportantBean;
#Bean
public SomeService someService(RestTemplateBuilder restTemplate) {
SomeService foo = new SomeService();
foo.setAnotherVeryImportantBean(anotherVeryImportantBean);
foo.setRestTemplate(restTemplate);
return foo;
}
The problem is that this controller and service are not the only ones in the application. I would like the application not to crash completely if this particular controller and service are not formed. If the bean is not created for some reason, I just don't use that functionality (this controller).
At this point, the application crashes because AnotherService cannot be injected into someService (In case where, for some reason, it was not created).
I tried adding an annotation to config class
#ConditionalOnBean(AnotherVeryImportantBean.class)
like this:
#ConditionalOnBean(AnotherVeryImportantBean.class)
#Configuration
#RequiredArgsConstructor
public class SomeConfig {
private AnotherVeryImportantBean anotherVeryImportantBean;
#Bean
public SomeService someService(RestTemplateBuilder restTemplate) {
SomeService foo = new SomeService();
foo.setAnotherVeryImportantBean(anotherVeryImportantBean);
foo.setRestTemplate(restTemplate);
return foo;
}
But the problem is that conditional in SomeConfig checks if the bean is in the container before it is created.
How can I handle an error when a bean cannot inject another dependency into itself?
I've already read these questions and none of them worked:
Spring boot MVC - Unable to Autowire Repository in the service class
Why can't #Autowired a JPA repository - Spring boot + JPA
JpaRepository getting Null at service class
And also this one: https://www.baeldung.com/spring-autowired-field-null
Unfortunately, none of them worked.
What I have is:
Service interface:
#Service
public interface DayTradeService {
public List<DayTrade> getDayTrades(List<NotaDeCorretagem> corretagens);
}
Service Implementation:
public class DayTradeServiceImpl implements DayTradeService {
#Autowired
private DayTradeRepository dayTradeRepository;
#Override
public List<DayTrade> getDayTrades(List<NotaDeCorretagem> corretagens) {
// Several lines of code and some of them is trying to use dayTradeRepository.
}
}
My DayTradeRepository:
#Repository
public interface DayTradeRepository extends JpaRepository<DayTrade, Integer> {}
Inside my DayTradeController (annotated with #Controller), I can use a dayTradeRepository with #Autowired. But inside a service class, I cannot use. I get this message:
Cannot invoke "meca.irpf.Repositories.DayTradeRepository.getDayTrades()" because "this.dayTradeRepository" is null"
How can I make it possible?
EDIT after I accepted Nikita's answer:
I didn't post the Controller code, but it didn't have the #Autowired for the service class DayTradeServiceImpl. That was the point I was missing. After Nikita pointing that, I could solve the problem.
You not need create new object. You have to call like this:
#Controller
#RequestMapping("/test")
public class TestController {
#Autowired
private DayTradeServiceImpl dayTradeService;
#GetMapping(value = "/get")
public void getTrades() {
dayTradeService.getDayTrades(...);
}
}
And set annotation #Service for DayTradeServiceImpl.
#Service
public class DayTradeServiceImpl implements DayTradeService {
#Autowired
private DayTradeRepository dayTradeRepository;
#Override
public List<DayTrade> getDayTrades(List<NotaDeCorretagem> corretagens) {
// Several lines of code and some of them is trying to use dayTradeRepository.
}
}
Spring framework use inversion of control, which has container for beans. For detect beans use annotation like: #Service, #Component, #Repository.
How come application.properties will work in a RestController, but not in a service class?
//application.properties
test=test
Works Perfect!
#RestController
public class invitecontroller {
#Autowired inviteconfig inviteconfig;
#PostMapping("/v1/invite")
public void invite(#RequestBody XXX XXX) {
System.out.println(inviteconfig);
}
}
Returns "Null"
#Service
public class inviteservice {
#Autowired inviteconfig inviteconfig;
public void invite() {
System.out.println(inviteconfig);
}
}
#Configuration
#Data
public class inviteconfig {
private String test;
}
The inviteservice class is not configured for Spring IoC (Inversion of Control) as a bean, so Spring will not handle the inviteservice class lifecycle. In this case, #Autowired is useless.
To fix this try to add #Component annotation to invitesevice, to declare it as a component:
#Component
public class inviteservice {
#Autowired inviteconfig inviteconfig;
public void invite() {
System.out.println(inviteconfig);
}
}
In the case of the controller, with #RestController, Spring will recognize your class as a Spring component.
Finally, don't forget to inject inviteservice using Spring IoC (using #Autowired annotation, or other means)
inviteservice class should be annotated with #Component or #Service
#Component
public class inviteservice {
...
Following is the service.
#Service
public class MyService {
public List<Integer> getIds(Filter filter){
// Method body
}
}
And a configuration class.
#Configuration
public static class MyApplicationContext {
#Bean
public Filter filter(ApplicationContext context) {
return new Filter();
}
}
The desired goal is a unit test to confirm getIds() returns the correct result.
See the JUnit test below.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes=MyApplicationContext.class,
loader=AnnotationConfigContextLoader.class)
public class AppTest
{
#Autowired
Filter filter;
#Autowired
MyService service;
}
The compiler finds the correct bean for the Filter class but throws a BeanCreationException: Could not autowire field exception for the service variable. I've tried adding the service class to the ContextConfiguration classes attribute but that results in a IllegalStateException: Failed to load ApplicationContext exception.
How can I add MyService to ContextConfiguration?
Add the following annotation to MyApplicationContext for the service to be scanned #ComponentScan("myservice.package.name")
Add these two annotations to the test class AppTest, like in the following example:
#RunWith(SpringRunner.class )
#SpringBootTest
public class ProtocolTransactionServiceTest {
#Autowired
private ProtocolTransactionService protocolTransactionService;
}
#SpringBootTest loads the whole context.
I have several classes in a Spring Boot project, some work with #Autowired, some do not. Here my code follows:
Application.java (#Autowired works):
package com.example.myproject;
#ComponentScan(basePackages = {"com.example.myproject"})
#Configuration
#EnableAutoConfiguration
#EnableJpaRepositories(basePackages = "com.example.myproject.repository")
#PropertySource({"classpath:db.properties", "classpath:soap.properties"})
public class Application {
#Autowired
private Environment environment;
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
#Bean
public SOAPConfiguration soapConfiguration() {
SOAPConfiguration SOAPConfiguration = new SOAPConfiguration();
SOAPConfiguration.setUsername(environment.getProperty("SOAP.username"));
SOAPConfiguration.setPassword(environment.getProperty("SOAP.password"));
SOAPConfiguration.setUrl(environment.getProperty("SOAP.root"));
return SOAPConfiguration;
}
HomeController (#Autowired works):
package com.example.myproject.controller;
#Controller
class HomeController {
#Resource
MyRepository myRepository;
MyService (#Autowired does not work):
package com.example.myproject.service;
#Service
public class MyServiceImpl implements MyService {
#Autowired
public SOAPConfiguration soapConfiguration; // is null
private void init() {
log = LogFactory.getLog(MyServiceImpl.class);
log.info("starting init, soapConfiguration: " + soapConfiguration);
url = soapConfiguration.getUrl(); // booom -> NullPointerException
I do not get the SOAPConfiguration but my application breaks with a null pointer exception when I try to access it.
I have already read many Threads here and googled around, but did not find a solution yet. I tried to deliver all necessary information, please let me know if anything misses.
I guess you call init() before the autowiring takes place. Annotate init() with #PostConstruct to make it call automatically after all the spring autowiring.
EDIT: after seeing your comment, I guess you are creating it using new MyServiceImpl(). This takes away the control of the MyServiceImpl from Spring and gives it to you. Autowiring won't work in those case
Did you created a bean for the class SOAPConfiguration in any of your configuration classes? If you want to autowire a class in your project, you need to create a bean for it. For example,
#Configuration
public class SomeConfiguration{
#Bean
public SOAPConfiguration createSOAPConfiguration(){
return new SOAPConfiguration();
}
}
public class SomeOtherClass{
#Autowired
private SOAPConfiguration soapConfiguration;
}