Spring - No default constructor found - java

I have a class which looks like this:
#Service("myService")
public class MyServiceImpl {
#Autowired
private SimpMessagingTemplate simpMessagingTemplate;
and I also have a test class which looks like this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {
MyServiceImpl.class})
...
I get this exception:
Injection of autowired dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not autowire
field: private org.springframework.messaging.simp.SimpMessagingTemplate
myPackage.MyServiceImpl.simpMessagingTemplate; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.messaging.simp.SimpMessagingTemplate] 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)}
Does anyone know what I can do in order to get it work, SimpMessagingTemplate does not have a default constructor.

SimpMessagingTemplate seems to have either no default constructor or is not annotated with #Component (or #Service or another sub-class of #Component); or both.
Please check that a default constructor is available and the class is configured to be a Spring bean.

Its not related to missing constructor, but Spring fails to find proper bean to inject into your test class,
Two options to solve it as I see
#ContextConfiguration(classes = {
MyServiceImpl.class, SimpMessagingTemplate.class})
Add #mock SimpMessagingTemplate simpMessagingTemplate; to your test class

Related

Wiring beans during integration tests with embedded mongo

I am using spring-boot (2.2.7.RELEASE) with webflux for a small-ish rest service with mongodb. I have 2 repositories (ARepository, BRepository) implemented something like this:
#Repository
public interface ARepository extends ReactiveMongoRepository<DataDTO, Integer> {
}
I also have an extra service which is using these 2 and a ReactiveMongoTemplate instance. It's wired something like this:
#Slf4j
#Service
public class DefaultTheService implements TheService {
private final ARepository aRepository;
private final BRepository bRepository;
private final ReactiveMongoTemplate mongoTemplate;
#Autowired
public DefaultTheService(ARepository aRepository, BRepository bRepository, ReactiveMongoTemplate mongoTemplate) {
this.aRepository = aRepository;
this.bRepository = bRepository;
this.mongoTemplate = mongoTemplate;
}
}
All is good, it works as it should, no problems there.
Now, I want to write some integration tests and I started like this:
#DataMongoTest
#Slf4j
class DefaultTheServiceTest {
#Autowired
private ARepository aRepository;
#Autowired
private BRepository bRepository;
#Autowired
private ReactiveMongoTemplate reactiveMongoTemplate;
#Autowired
private DefaultTheService defaultTheService;
#Test
void runTheMagicTest() {
// empty body, I just want to see if everything wires up correctly.
}
}
When I want to execute runTheMagicTest (junit5), I am always getting this error:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.example.DefaultTheServiceTest': Unsatisfied dependency expressed through field 'defaultTheService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.DefaultTheService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:643)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:130)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.DefaultTheService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1716)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1272)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1226)
*! notice the bean name: DefaultTheServiceTest
Normally, I could maybe get away simply creating an instance of DefaultTheService before each test and then calling the methods I want to test, but I'd like to give it a try using spring.
If I simply remove the private DefaultTheService defaultTheService declaration - the test is "running". I am pretty sure I am missing something stupid and I am chasing my tail.
So, can someone ease my pain and point me to the (possibly?) obvious error I am making?
Thanks!
#DataMongoTest:
Annotation that can be used for a MongoDB test that focuses only on MongoDB components.
Using this annotation will disable full auto-configuration and instead apply only configuration relevant to MongoDB tests.
Try a #SpringBootTest for a "full"/default application context instead.
For general information refer to:
https://docs.spring.io/spring-framework/docs/current/reference/html/testing.html#testing
For (auto-)configuration details & refinement to:
https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.testing
... setting #DataMongoTest(useDefaultFilters = false) (+ fine tuning include-/excludeFilters) can also do the desired.

Autowiring Embedded Elastic with Spring

I'm trying to build a rest api with Spring and Embedded Elastic. I'm getting an NoSuchBeanDefinitionException when trying to start my application.
Currently, I have this for wiring the elastic db:
#Configuration
public class EsConfig {
Node node;
#Bean
public Client es() {
node = nodeBuilder().local(true).node();
return node.client();
}
(Destructor)
}
and in the controller:
#RestController
public class Controller {
#Autowired
public Client elasticSearchClient;
...
}
But when I start it up, I get this exception:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'controller': Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: public org.elasticsearch.client.Client package.Controller.elasticSearchClient;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type [org.elasticsearch.client.Client] 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've tried a few different annotations but I'm obviously way off.
No qualifying bean of type [some.Thing] means that spring knowns no class that is applicable for this interface.
Reasons for that can be
The class that has the #Bean method is not a #Configuration class
The #Configuration class is not picked up by the classpath component scanner.
Spring boot by default will only scan the child package hierarchy of the #SpringBootApplication. If you want to include code outside of that you can change the scanning behavior via the #ComponentScan annotation.
#SpringBootApplication
#ComponentScan(basePackageClasses = {MyApp.class, SomeOtherClassInARootPackage.class})
public class MyApp {
...
Would add the package (and sub packages) of some other class, while keeping the packages of the application scanned as well.

How to create a mock spring bean for a class having autowired dependencies

Suppose I have a class called MainClass.
public class MainClass {
#Autowired
AutoWiredClass autoWiredClass;
}
I am trying to create a mock bean of MainClass using Mockito.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class AutowiringTest {
#Configuration
static class AutowiringTestConfiguration{
#Bean
public MainClass mainClass() {
return Mockito.mock(MainClass.class);
}
}
#Autowired
MainClass mainClass;
#Test
public void testBeanCreation(){
assertNotNull(mainClass);
}
}
I am getting this error while running the test case.
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: autowiring.AutoWiredClass autowiring.MainClass.autoWiredClass; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [autowiring.AutoWiredClass] 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 know I can achieve this using #Mock and #InjectMocks. But that's not the solution I want.
My requirement is to create a mock bean of MainClass without creating an actual bean of AutowiredClass. Please help me how to achieve this.
As Florian has already commented, you should try to create tests that do not need Spring at all, and you will not have those problems.
But, if there is no workaround possible, you can use a bit of magic with the AutoMockRegistryPostProcessor.
You just need to add the AutoMockRegistryPostProcessor to the #ContextConfiguration, and it will create mocks for your missing dependencies:
#ContextConfiguration(classes = { AutowiringTest.class, AutoMockRegistryPostProcessor.class })
public class AutowiringTest {
// no complains anymore, a mockito mock will be created for AutoWiredClass
The AutoMockRegistryPostProcessor class is not in maven, you will need to copy it in your project.
The docu is here.

How to Autowired in ConversionService in springboot

Trying to access the ConversionControl in model in springboot, no luck.
#Component
public class CityHelperService {
#Autowired
ConversionService conversionService;// = ConversionServiceFactory.registerConverters();
public City toEntity(CityDTO dto){
City entity = conversionService.convert(dto, City.class);
return entity;
}
public CityDTO toDTO(City entity){
CityDTO dto = conversionService.convert(entity, CityDTO.class);
return dto;
}
}
It shows the following error:
Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.lumiin.mytalk.model.CityModel com.lumiin.mytalk.controllers.CityController.cityModel;
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'cityModel' defined in file : Unsatisfied dependency expressed through constructor argument with index 1 of type [com.lumiin.mytalk.dao.CityHelperService]: : Error creating bean with name 'cityHelperService': Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.springframework.core.convert.ConversionService com.lumiin.mytalk.dao.CityHelperService.conversionService;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.core.convert.ConversionService] 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)};
nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cityHelperService': Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.springframework.core.convert.ConversionService com.lumiin.mytalk.dao.CityHelperService.conversionService;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.core.convert.ConversionService] 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)}
Apparently there is no ConversionService bean available, judging by the last nested exception:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.core.convert.ConversionService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.
A look into the Spring documentation reveals, that you should declare a ConversionService bean. In the XML configuration it would look like this:
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="example.MyCustomConverter"/>
</set>
</property>
</bean>
And since you're using Spring Boot, I assume you are creating the context programatically, so you should create a method annotated with #Bean, which returns a ConverstionService, like this (explained here):
#Bean(name="conversionService")
public ConversionService getConversionService() {
ConversionServiceFactoryBean bean = new ConversionServiceFactoryBean();
bean.setConverters(...); //add converters
bean.afterPropertiesSet();
return bean.getObject();
}
Not totally agreed with the accepted answers, because there would be a default ConverstionService named mvcConversionService so you would get duplicate bean exception. Instead addConverter to FormatterRegistry, here is the link for the part answer:
Java Config equivalent for conversionService / FormattingConversionServiceFactoryBean
Also you would need (in some cases) to define to at least an empty Component for ConversionService, something like below:
#Component #Primary
public class MyConversionService extends DefaultConversionService implements ConversionService {
// an empty ConversionService to initiate call to register converters
}
This is to force spring container to initiate a call to:
class WebMvcConfigurerAdapter {
...
public void addFormatters(FormatterRegistry registry) {
//registry.addConverter(...);
}
}
Existing answers didn't work for me:
Customizing via WebMvcConfigurerAdapter.addFormatters (or simply annotating the converter with #Component) only works in the WebMvc context and I want my custom converter to be available everywhere, including #Value injections on any bean.
Defining a ConversionService bean (via ConversionServiceFactoryBean #Bean or #Component) causes Spring Boot to replace the default ApplicationConversionService on the SpringApplication bean factory with the custom bean you've defined, which will probably be based on DefaultConversionService (in AbstractApplicationContext.finishBeanFactoryInitialization). The problem is that Spring Boot adds some handy converters such as StringToDurationConverter to the standard set in DefaultConversionService, so by replacing it you lose those conversions. This may not be an issue for you if you don't use them, but it means that solution won't work for everyone.
I created the following #Configuration class which did the trick for me. It basically adds custom converters to the ConversionService instance used by Environment (which is then passed on to BeanFactory). This maintains as much backwards compatibility as possible while still adding your custom converter into the conversion services in use.
#Configuration
public class ConversionServiceConfiguration {
#Autowired
private ConfigurableEnvironment environment;
#PostConstruct
public void addCustomConverters() {
ConfigurableConversionService conversionService = environment.getConversionService();
conversionService.addConverter(new MyCustomConverter());
}
}
Obviously you can autowire a list of custom converters into this configuration class and loop over them to add them to the conversion service instead of the hard-coded way of doing it above, if you want the process to be more automatic.
To make sure this configuration class gets run before any beans are instantiated that might require the converter to have been added to the ConversionService, add it as a primary source in your spring application's run() call:
#SpringBootApplication
public class MySpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(new Class<?>[] { MySpringBootApplication.class, ConversionServiceConfiguration.class }, args);
}
}
If you don't do this, it might work, or not, depending on the order in which your classes end up in the Spring Boot JAR, which determines the order in which they are scanned. (I found this out the hard way: it worked when compiling locally with an Oracle JDK, but not on our CI server which was using a Azul Zulu JDK.)
Note that for this to work in #WebMvcTests, I had to also combine this configuration class along with my Spring Boot application class into a #ContextConfiguration:
#WebMvcTest(controllers = MyController.class)
#ContextConfiguration(classes = { MySpringBootApplication.class, ConversionServiceConfiguration.class })
#TestPropertySource(properties = { /* ... properties to inject into beans, possibly using your custom converter ... */ })
class MyControllerTest {
// ...
}

Spring autowiring dillema when using injection by both interface and implementation

Consider we have interface CountryService, which has one implementation: CountryServiceImpl which is annotated with #Service
We also have ITTest for CountryImpl.
The problem:
Frequently when running tests we want to explicitly show what we are testing so we are autowiring by implementation, so we create ITTest:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = Application.class, loader = SpringApplicationContextLoader.class)
#ActiveProfiles(ProfileConstants.SPRING_PROFILE_DEVELOPMENT)
public class CountryServiceITTest {
#Autowired
CountryServiceImpl countryServiceImpl;
#Test
public void test() {
countryServiceImpl.getAllCountriesTranslationsInLanguage("en");
}
So far so good. We run our test and it is green. Now lets make life little more fun.
We add a CountryResource with CountryResourceImpl #RestController which #Autowire (s) CountryService.
We run our test again and suddenly we receive error message causing maddness:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'countryResourceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com....service.CountryService com....rest.CountryResourceImpl.countryService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com....service.CountryService] 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)}
This behavior reveals an interesting thing:
Once we autowire by interface, we can't autowire by direct implementation somewhere else. This works vice versa(if we autowire by impl the interface injection will fail).
Please explain why is this happening?

Categories

Resources