I declared a service in package service like:
import a.b.c.d.soapapim.SoapApimMiddlewareService;
#Service
#EnableDefaultExceptionHandling
public class MyService{
private final SoapApimMiddlewareService myService;
public MyService(SoapApimMiddlewareService myService){
this.myService = myService;
}
public Response pullEvents(numEvents){
myService.pullEvents(numEvents);
}
}
SoapApimMiddlewareService is a dependency in my spring boot project declared in my project's pom.xml in the package a.b.c.d.soapapim
in my application.java:
#ComponentScan({"a.b.c.d.soapapim", "service", "scheduler"})
SpringBootApplication
#EnableScheduling
public class Application implements WebMvcConfigurer {ยด
public static void main(String[] args){
SpringApplication app = new SpringApplication(Application.class);
app.setRegisterShutdownHook(false);
app.run(args);
}
}
I also have a scheduler:
#Component
public class Scheduler {
private MyService myService;
#Scheduled(fixedRate = 1200)
public void myScheduledTask(){
myService.pullEvents(1);
}
}
I am getting the following error:
UnsatisfiedDependencyException: Error creating bean with name MyService No qualifying bean of type 'a.b.c.d.soapapim.SoapApimMiddlewareService'
I can't annotate that class because its a dependency I don't have access to. I just declare it as a dependency on the pom.xml of my project.
How can I get this bean into the context of my spring boot application?
You can declare it as spring bean using #Bean annotation in config class
#Bean
public SoapApimMiddlewareService soapApimMiddlewareService() {
return new SoapApimMiddlewareService():
}
Related
I have 2 spring boot microservice let's say core and persistence. where persistence has a dependency on core.
I have defined an interface in core whose implementation is inside persistence as below:
core
package com.mine.service;
public interface MyDaoService {
}
Persistence
package com.mine.service.impl;
#Service
public class MyDaoServiceImpl implements MyDaoService {
}
I am trying to inject MyDaoService in another service which is in core only:
core
package com.mine.service;
#Service
public class MyService {
private final MyDaoService myDaoService;
public MyService(MyDaoService myDaoService) {
this.myDaoService = myDaoService;
}
}
while doing this i am getting this weird error:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.mine.service.MyService required a bean of type 'com.mine.service.MyDaoService' that could not be found.
Action:
Consider defining a bean of type 'com.mine.service.MyDaoService' in your configuration.
can anyone explain me why ?
NOTE: i have already included com.mine.service in componentscan of springbootapplication as below
package com.mine.restpi;
#SpringBootApplication
#EnableScheduling
#ComponentScan(basePackages = "com.mine")
public class MyRestApiApplication {
public static void main(String[] args) {
SpringApplication.run(MyRestApiApplication.class, args);
}
}
Try adding the #Service annotation to your impl classes and the #Autowired annotation to the constructor.
// Include the #Service annotation
#Service
public class MyServiceImpl implements MyService {
}
// Include the #Service annotation and #Autowired annotation on the constructor
#Service
public class MyDaoServiceImpl implements MyDaoService {
private final MyService myService ;
#Autowired
public MyDaoServiceImpl(MyService myService){
this.myService = myService;
}
}
As stated in the error message hint: Consider defining a bean of type 'com.mine.service.MyDaoService' in your configuration to solve this problem you can define in your package com.mine a configuration class named MyConfiguration annotated with #Configuration including a bean named myDaoService like below:
#Configuration
public class MyConfiguration {
#Bean
public MyDaoService myDaoService() {
return new MyDaoServiceImpl();
}
}
Try the following, move MyRestApiApplication class to com.mine package and remove #ComponentScan annotation.
package com.mine;
#SpringBootApplication
#EnableScheduling
public class MyRestApiApplication {
public static void main(String[] args) {
SpringApplication.run(MyRestApiApplication.class, args);
}
}
i want to create the non-web spring boot application. But i am getting following error
#SpringBootApplication
public class TaskApplication implements CommandLineRunner {
#Autowired
TaskService taskService;
public static void main(String[] args) {
SpringApplication.run(TaskApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
taskService.print();
}
}
public interface TaskService {
public void print();
}
public class TaskServiceImpl implements TaskService {
#Override
public void print() {
System.out.println("sam");
}
}
properties:
spring.datasource.url=jdbc:mysql://localhost:3306/demo?verifyServerCertificate=false&useSSL=false&requireSSL=false&allowPublicKeyRetrieval=true
spring.datasource.username=root
spring.datasource.password=root#123
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.jpa.show-sql=true
spring.jpa.hibernate.dialect=org.hibernate.dialect.MySQLDialect
spring.main.allow-bean-definition-overriding=true
##spring.jpa.hibernate.ddl-auto=update
error
***************************
APPLICATION FAILED TO START
***************************
Description:
Field taskService in com.example.task.TaskApplication required a bean of type 'com.example.task.service.TaskService' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.example.task.service.TaskService' in your configuration.
#M. Deinum already explained in comments. You need to mark classes with #Service or #Component annotation to create the spring bean and autowired in main methods.
// mark it with service annotation.
#Service
public class TaskServiceImpl implements TaskService {
#Override
public void print() {
System.out.println("sam");
}
}
To understand why those annotation is necessary here please visit this link : #Component vs #Repository and #Service in Spring
you need to configure #EnableAutoConfiguration on main class and your TaskService must be annotated with #Service
I have following project structure:
-module1
--src/main/java/at.flobau.demo.module1
---model
----Product.java
---service
----ProductService.java
---TestConfiguration.java
--src/test/java/at.flobau.demo.module1.service
---ProductServiceTest.java
-module2
--src/main/java/at.flobau.demo.main
---MainApplication.java
The Application class looks like this:
#SpringBootApplication(scanBasePackages = {"at.flobau.demo.main"})
#PropertySource(value = "classpath:application.properties")
#EnableJpaRepositories("at.flobau.demo.module1")
#EntityScan(basePackages = {"at.flobau.demo.module1"})
public class PocApplication {
public static void main(String[] args) {
SpringApplication.run(PocApplication.class, args);
}
}
The Service looks like this:
#Service
public class ProductService implements IProductService {
#Autowired
private IProductRepository productRepository;
...
}
The test Class looks like this:
#SpringBootTest
#ContextConfiguration(classes = { TestConfiguration.class }, loader =
AnnotationConfigContextLoader.class)
#RunWith(SpringRunner.class)
public class ProductServiceTest {
#Autowired
private ProductService productService;
...
}
The test configuration file looks like this:
#Configuration
#ComponentScan("at.flobau.demo")
public class TestConfiguration{ }
IntelliJ tells me, that the ProductService inside the test cannot be autowired. When i do run the test i get an exepction:
Error creating bean with name 'ProductServiceTest': Unsatisfied dependency expressed through field
'productService'; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type
'at.flobau.demo.module1.products.service.ProductService' available: expected at least 1 bean which
qualifies as autowire candidate. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
You should avoid using field injection (even though is possible) and use constructor injection. This will solve this problem as you will be able to pass the service from the constructor but it will also be useful in the future as you can locate usages and trace objects in your code way better than field injections which are "hidden"
So I recommend instead of trying to solve your problem here to refactor your class in constructor injection and pass the service from there either by directly creating the object in your test or by creating a configuration for your test that will generate the object and give the arguments it requires
something like
#ContextConfiguration(classes = { GeneralTester.TestConfig.class })
#RunWith(SpringRunner.class)
public class GeneralTester {
#TestConfiguration
public static class TestConfig {
#Bean
public IProductService productService(final IProductRepository productRepository){
return new ProductService(productRepository);
}
#Bean
public IProductRepository productRepository(){
return mock(IProductRepository.class);
}
}
#Autowire
public IProductService productService;
#Autowire
public IProductRepository productRepository;
#Before
public void setUp() {
reset(productRepository);
}
#After
public void tearDown() {
verifyNoMoreInteractions(productRepository);
}
#Test
public void doSmth() {
//... your setup
when(productRepository.save(any())).thenReturn("something");
//... your call and assertions
verify(productRepository).save(any());
}
}
You can annotate your test class with #SpringBootTest(classes = ProductService.class)
Have you tried creating a bean of the service in the test configuration class?
#TestConfiguration
#ComponentScan("at.flobau.demo")
public class TestConfiguration {
#Bean
public ProductService productService() {
return new ProductService();
}
}
I am using a mock repository for my application.
Here is snippet how service looks:
#Service
public class WeatherStationService {
#Autowired
private WeatherStationRepositoryMock weatherRepository;
Here is repository code:
#Repository
public class WeatherStationRepositoryMock {
#Getter
private List<WeatherStation> stations = new ArrayList<>(
Arrays.asList(
new WeatherStation("huston", "Huston station", RandomGenerator.getRandomGeoInformation()),
new WeatherStation("colorado", "Colorado station", RandomGenerator.getRandomGeoInformation())
)
);
It works fine when I am executing main() with #SpringBootApplication.
However, when I want to run test class:
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = MockConfig.class)
#DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
public class WeatherStationServiceTest {
#Autowired
#Real
private WeatherStationService weatherService;
It fails with the following stacktrace:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'edu.lelyak.repository.WeatherStationRepositoryMock' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Here is MockConfig content:
#Configuration
public class MockConfig {
//**************************** REAL BEANS ******************************
#Bean
#Real
public WeatherStationService weatherServiceReal() {
return new WeatherStationService();
}
Real is marker annotation for real instances:
#Retention(RUNTIME)
#Qualifier
public #interface Real {
}
I can fix it with next initialization at service:
#Service
public class WeatherStationService {
private WeatherStationRepositoryMock weatherRepository = new WeatherStationRepositoryMock();
It works fine.
Why does this happen?
How to fix autowiring for my custom repository class?
#SpringBootApplication implicitly defines #ComponentScan, which scans all subpackages for beans.
When you run a test using MockConfig's, it doesn't scan for beans.
Solution - use #ComponentScan OR define beans in MockConfig
(1) Using #ComponentScan:
#Configuration
#ComponentScan //Make sure MockConfig is below all beans to discover
public class MockConfig {
#Bean
#Real
public WeatherStationService weatherServiceReal() {
return new WeatherStationService();
}
}
(2) or define required beans:
#Configuration
public class MockConfig {
#Bean
#Real
public WeatherStationService weatherServiceReal() {
return new WeatherStationService();
}
#Bean
public WeatherStationRepositoryMock weatherStationRepository() {
return new WeatherStationRepositoryMock()
}
}
I have created a custom API jar library where I'd like to provide some commonly used services.
But I'd like to use and autowire some of these services optionally in my implementation projects. They should not get autowired automatically.
How could I tell Spring explicit to include the following StatsLogger?
API jar:
package my.spring.config
//#Component
public class MyStatsLogger {
#Autowired
private MyService someOtherServiceForLogging;
#Scheduled(fixedDelay = 60000)
public void log() {
//logging
}
}
IMPL project:
#Configuration
#EnableScheduling
public class AppConfig {
}
Simply add the service to your context:
#Configuration
#EnableScheduling
public class AppConfig {
#Bean
public MyStatsLogger myStatsLogger() {
return new MyStatsLogger();
}
}
Since MyStatsLogger has a default constructor, all you need to is the following:
#Configuration
#EnableScheduling
public class AppConfig {
#Bean
public MyStatsLogger myStatsLogger() {
return new MyStatsLogger();
}
}
The MyService dependency in MyStatsLogger will automatically be wired by Spring if of course there is a bean of type MyService declared.