I have a person model class that needs to be immutable and singleton. I need to autowire from my service class but getting an error.
So is there any way to create a singleton immutable class in spring boot? where i can set values in person (via autowire) and use the same in the entire application.
I have just started learning spring-boot. I searched on google and found the solution with Lombok but somehow it didn't work for me.
My person model :
#Value
#Builder
#AllArgsConstructor(access = AccessLevel.PRIVATE)
#Component
public final class Person {
private final String firstName;
private final String lastName;
}
//My service class
#Component
public class ArgumentReadingService {
#Autowired
Person person;
public void readArguments() {
person = Person.builder().firstName("Hello").build();
System.out.println("name : "+person.getFirstName());
}
Error :
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2021-03-10 17:52:29.197 ERROR 8824 --- [ main] o.s.boot.SpringApplication : Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'person' defined in file [C:\Users\User\Desktop\WorkSpace\Orion.Strat1.bidAsk_Stp\target\classes\orion\model\Person.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [orion.model.Person]: No default constructor found; nested exception is java.lang.NoSuchMethodException: orion.model.Person.<init>()
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1316) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1214) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:917) ~[spring-context-5.3.4.jar:5.3.4]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:582) ~[spring-context-5.3.4.jar:5.3.4]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:767) [spring-boot-2.4.3.jar:2.4.3]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:759) [spring-boot-2.4.3.jar:2.4.3]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:426) [spring-boot-2.4.3.jar:2.4.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:326) [spring-boot-2.4.3.jar:2.4.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1311) [spring-boot-2.4.3.jar:2.4.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1300) [spring-boot-2.4.3.jar:2.4.3]
at com.orion.Application.main(Application.java:20) [classes/:na]
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [orion.model.Person]: No default constructor found; nested exception is java.lang.NoSuchMethodException: orion.model.Person.<init>()
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:83) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1308) ~[spring-beans-5.3.4.jar:5.3.4]
... 17 common frames omitted
Caused by: java.lang.NoSuchMethodException: orion.model.Person.<init>()
at java.lang.Class.getConstructor0(Class.java:3082) ~[na:1.8.0_191]
at java.lang.Class.getDeclaredConstructor(Class.java:2178) ~[na:1.8.0_191]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:78) ~[spring-beans-5.3.4.jar:5.3.4]
... 18 common frames omitted
This configuration class and that annotation will provide you always with that Person Bean
#Configuration
public class ServerConfig
{
#Bean
private Person getPerson(){
return new Person("name", "lastName");
}
Now it will be available everywhere for autowiring.
As the comments note however, it seems strange to use a model class as a Singleton.
Adding some more info for the readers,
Look at this question for more clarity
SpringBoot - #Configuration creates a singleton bean
Related
I am implementing Spring Boot application and when it's run from Intellij everythinks works fine, but when the artifact is built and run, gets the next error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'resourceHandlerMapping' defined in class path resource [org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.web.servlet.HandlerMapping]: Factory method 'resourceHandlerMapping' threw exception; nested exception is java.lang.IllegalStateException: No ServletContext set
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:658)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:638)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1352)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1195)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:953)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:734)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:308)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295)
at com.backend.core.CoreApplication.main(CoreApplication.java:20)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.web.servlet.HandlerMapping]: Factory method 'resourceHandlerMapping' threw exception; nested exception is java.lang.IllegalStateException: No ServletContext set
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653)
... 18 common frames omitted
Caused by: java.lang.IllegalStateException: No ServletContext set
at org.springframework.util.Assert.state(Assert.java:76)
at org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.resourceHandlerMapping(WebMvcConfigurationSupport.java:591)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
... 19 common frames omitted
See here full log.
I'm using spring-boot-starter-web package which includes Tomcat as a default implementation of a servlet. Seems that exception is thrown because the bean which extends WebMvcConfigurationSupport is created earlier than expected and before the ServletContext is available.
I was trying to change or remove some annotations on WebConfig.java, SecurityConfig.java and CoreApplication.java but always the result is the same.
As a test, if #EnableAutoConfiguration(exclude = { WebMvcAutoConfiguration.class }) is implemented on CoreApplication.java, the exported jar is runned as standalone application without any issue.
So how can I configure WebMvcAutoConfiguration.class in order to run the application waiting for incoming http requests? How can I do in order to build later the bean which extends WebMvcConfigurationSupport and after the ServletContext is available?
Here my repo where there is pom.xml, application.properties, config classes, controllers, main application, models and repositories.
Thanks
There was some problem when build jar from Build -> Build Artifacts -> Rebuild. Seems that tomcat is not embeeded with this configuration.
If I build jar from maven menu into Intellij, the exception dissapear.
I use this kafka configuration with spring cloud and spring boot 2.6.6:
#Configuration
#RefreshScope
public class KafkaProducerConfig {
#Bean(name = "nativeProducerFactory")
#Primary
#RefreshScope
public ProducerFactory<String, String> nativeProducerFactory() {
final Map<String, Object> properties = new HashMap<>();
properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
return new DefaultKafkaProducerFactory<>(properties);
}
#Bean(name = "nativeKafkaTemplate")
public KafkaTemplate<String, String> nativeKafkaTemplate(
#Autowired final ProducerFactory<String, String> factory) {
return new KafkaTemplate<>(factory);
}
But when I start the project I get this error:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.kafka.core.ProducerFactory<java.lang.Object, java.lang.Object>' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1799)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1355)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1309)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:541)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1352)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1195)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1389)
at org.springframework.beans.factory.support.DefaultListableBeanFactory$DependencyObjectProvider.getIfUnique(DefaultListableBeanFactory.java:2072)
at org.springframework.boot.autoconfigure.kafka.KafkaAnnotationDrivenConfiguration.<init>(KafkaAnnotationDrivenConfiguration.java:93)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:211)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:117)
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:311)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:296)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1372)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1222)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:953)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:740)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:415)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1312)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301)
at com.atlas.psp.AtlasRouterApplication.main(AtlasRouterApplication.java:48)
21:45:59.271 [main] ERROR LoggingFailureAnalysisReporter[report:40] -
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of method kafkaTemplate in org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration required a bean of type 'org.springframework.kafka.core.ProducerFactory' that could not be found.
The following candidates were found but could not be injected:
- User-defined bean method 'nativeProducerFactory' in 'KafkaProducerConfig'
Action:
Consider revisiting the entries above or defining a bean of type 'org.springframework.kafka.core.ProducerFactory' in your configuration.
Do you know how I can fix this issue?
When I remove #RefreshScope from the bean it's working fine. Do you know how I can fix this issue?
P.S Looks like adding #RefreshScope also like this solves the error:
#Bean(name = "nativeKafkaTemplate")
#RefreshScope
public KafkaTemplate<String, String> nativeKafkaTemplate(
#Autowired final ProducerFactory<String, String> factory) {
return new KafkaTemplate<>(factory);
}
But I think that is incorrect. Any idea what should be the correct way to fix this?
The issue is related to the #RefreshScope on the #Configuration class. Better define #RefreshScope for the specific #Bean.
Accrding to Spring Cloud Context - Refresh Scope
#RefreshScope works (technically) on an #Configuration class, but it
might lead to surprising behavior. For example, it does not mean that
all the #Beans defined in that class are themselves in #RefreshScope.
Specifically, anything that depends on those beans cannot rely on them
being updated when a refresh is initiated, unless it is itself in
#RefreshScope. In that case, it is rebuilt on a refresh and its
dependencies are re-injected. At that point, they are re-initialized
from the refreshed #Configuration)
Tha's why it's working when you move it to the #Bean.
I am unable to test my controller class by mocking UserService.save() method to return a dummy User object.
Keep getting the following exception
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'webSecurityConfig': Unsatisfied dependency expressed through field 'userDetailsService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.security.core.userdetails.UserDetailsService' 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.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:659) ~[spring-beans-5.3.13.jar:5.3.13]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:639) ~[spring-beans-5.3.13.jar:5.3.13]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119) ~[spring-beans-5.3.13.jar:5.3.13]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399) ~[spring-beans-5.3.13.jar:5.3.13]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1431) ~[spring-beans-5.3.13.jar:5.3.13]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:619) ~[spring-beans-5.3.13.jar:5.3.13]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.13.jar:5.3.13]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.13.jar:5.3.13]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.13.jar:5.3.13]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.13.jar:5.3.13]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.13.jar:5.3.13]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944) ~[spring-beans-5.3.13.jar:5.3.13]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) ~[spring-context-5.3.13.jar:5.3.13]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.13.jar:5.3.13]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730) ~[spring-boot-2.6.1.jar:2.6.1]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:412) ~[spring-boot-2.6.1.jar:2.6.1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:302) ~[spring-boot-2.6.1.jar:2.6.1]
at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:121) ~[spring-boot-test-2.6.1.jar:2.6.1]
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99) ~[spring-test-5.3.13.jar:5.3.13]
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124) ~[spring-test-5.3.13.jar:5.3.13]
... 67 common frames omitted
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.security.core.userdetails.UserDetailsService' 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:1790) ~[spring-beans-5.3.13.jar:5.3.13]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1346) ~[spring-beans-5.3.13.jar:5.3.13]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1300) ~[spring-beans-5.3.13.jar:5.3.13]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:656) ~[spring-beans-5.3.13.jar:5.3.13]
... 86 common frames omitted
I checked my service class but all seems fine there. Moreover the code runs perfectly fine when I run it as a spring boot application.
Can someone help me understand why Spring IOC is unable to register the bean when running the junit test.
#SpringBootTest
public class TestUserController {
#Autowired
private MockMvc mockMvc;
#MockBean
UserService userService;
#Autowired
private UserController controller;
#Test
public void contextLoads() throws Exception {
assertThat(controller).isNotNull();
}
#Test
public void checkUserRegistrationEndpoint() throws Exception {
ObjectMapper mapper = new ObjectMapper();
UserDto userDto = new UserDto();
User user = new User();
Mockito.when(userService.save(userDto)).thenReturn(user);......
#Service
public interface UserService {
User save(UserDto user);
List<User> findAll();
User findOne(String username);
AuthToken refreshToken(String refreshToken);
}
#Service
public class UserServiceImpl implements UserDetailsService, UserService {
protected final Log logger = LogFactory.getLog(getClass());......
NOTE: I have configured this application for JWT based authentication.
You are autowiring MockMvc, so you need to provide the #AutoConfigureMockMvc annotation on your test class, which will tell Spring to inject this class for you (as stated in the docs):
#SpringBootTest
#AutoConfigureMockMvc
public class TestUserController {
....
}
The same annotation includes registration of various Spring auto-configuration classes as stated in this answer, among others the MockMvcSecurityAutoConfiguration, which offers auto-configuration for Spring Security for tests (as stated in the docs).
If this does not solve your problem with the missing bean dependency, you can try to inject it with #MockBean too:
#MockBean
UserDetailsService userDetailsService;
I am trying to execute couple of test cases which were earlier working fine. I recently added a Configuration class which is below :
#Configuration
public class DBConfig {
#Value("${spring.datasource.username:}")
private String username;
#Value("${spring.datasource.url:}")
private String url;
#Bean
#DependsOn("passwordProvider")
public DataSource datasource(PasswordProvider passwordProvider) {
return DataSourceBuilder
.create()
.url(url)
.username(username)
.password(new String(passwordProvider.getKeyByName("DB_PASSWORD").getKey()))
.build();
}
}
Now, all my SpringbootTests fail with the below exception:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.cloud.autoconfigure.RefreshAutoConfiguration$JpaInvokerConfiguration': Invocation of init method failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.jdbc.DataSourceInitializerInvoker': Invocation of init method failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'datasource' defined in class path resource [com/example/configuration/DBConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.sql.DataSource]: Factory method 'datasource' threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:160)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:422)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1778)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:602)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1154)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:908)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:769)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:761)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:426)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:326)
at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:123)
Any idea how to get it fixed ? I dont want to provide passwordProvider configuration in test.properties.
just mention in the spring boot test and it will load yours configuration class:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {DBConfig.class})
public class SpringBootIntegrationTest {
// ...
}
I have updated the following spring dependencies in my project pom.xml
From:
<spring.version>5.3.6</spring.version>
<spring.security.version>5.4.4</spring.security.version>
<spring.boot.version>2.3.10.RELEASE</spring.boot.version>
To:
<spring.version>5.3.8</spring.version>
<spring.security.version>5.5.1</spring.security.version
<spring.boot.version>2.5.2</spring.boot.version>
I was able to build my project successfully whereas, when I tried to start my application, I see the following error and my application fails to start at all.
Can any one help me with the resolution.
Caused by: org.aspectj.weaver.reflect.ReflectionWorld$ReflectionWorldException: warning can't determine superclass of missing type org.springframework.boot.validation.beanvalidation.MethodValidationExcludeFilter$$Lambda$819.0x000000080096f440
[Xlint:cantFindType]
at org.aspectj.weaver.reflect.ReflectionWorld$ExceptionBasedMessageHandler.handleMessage(ReflectionWorld.java:217) ~[aspectjweaver-1.9.7.jar!/:?]
at org.aspectj.weaver.Lint$Kind.signal(Lint.java:339) ~[aspectjweaver-1.9.7.jar!/:1.9.7]
at org.aspectj.weaver.MissingResolvedTypeWithKnownSignature.raiseCantFindType(MissingResolvedTypeWithKnownSignature.java:237) ~[aspectjweaver-1.9.7.jar!/:1.9.7]
at org.aspectj.weaver.MissingResolvedTypeWithKnownSignature.getSuperclass(MissingResolvedTypeWithKnownSignature.java:98) ~[aspectjweaver-1.9.7.jar!/:1.9.7]
at org.aspectj.weaver.JoinPointSignatureIterator.addSignaturesUpToFirstDefiningMember(JoinPointSignatureIterator.java:95) ~[aspectjweaver-1.9.7.jar!/:1.9.7]
at org.aspectj.weaver.JoinPointSignatureIterator.<init>(JoinPointSignatureIterator.java:49) ~[aspectjweaver-1.9.7.jar!/:1.9.7]
at org.aspectj.weaver.MemberImpl.getJoinPointSignatures(MemberImpl.java:515) ~[aspectjweaver-1.9.7.jar!/:1.9.7]
at org.aspectj.weaver.patterns.SignaturePattern.matches(SignaturePattern.java:316) ~[aspectjweaver-1.9.7.jar!/:?]
at org.aspectj.weaver.patterns.KindedPointcut.matchInternal(KindedPointcut.java:202) ~[aspectjweaver-1.9.7.jar!/:?]
at org.aspectj.weaver.patterns.Pointcut.match(Pointcut.java:137) ~[aspectjweaver-1.9.7.jar!/:?]
at org.aspectj.weaver.internal.tools.PointcutExpressionImpl.getShadowMatch(PointcutExpressionImpl.java:319) ~[aspectjweaver-1.9.7.jar!/:?]
at org.aspectj.weaver.internal.tools.PointcutExpressionImpl.matchesExecution(PointcutExpressionImpl.java:129) ~[aspectjweaver-1.9.7.jar!/:?]
at org.aspectj.weaver.internal.tools.PointcutExpressionImpl.matchesMethodExecution(PointcutExpressionImpl.java:110) ~[aspectjweaver-1.9.7.jar!/:?]
at org.springframework.security.config.method.ProtectPointcutPostProcessor.attemptMatch(ProtectPointcutPostProcessor.java:148) ~[spring-security-config-5.5.1.jar!/:5.5.1]
at org.springframework.security.config.method.ProtectPointcutPostProcessor.postProcessBeforeInitialization(ProtectPointcutPostProcessor.java:125) ~[spring-security-config-5.5.1.jar!/:5.5.1]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:422) ~[spring-beans-5.3.8.jar!/:5.3.8]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1778) ~[spring-beans-5.3.8.jar!/:5.3.8]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:602) ~[spring-beans-5.3.8.jar!/:5.3.8]
... 23 more
Warning!
This is not Production Grade solution but this may be considered as starting point for further investigation.
Background
We have quite legacy (~10yo) application and we currently run into same issue during Spring Boot upgrade from 2.3.9 to 2.4.0 (Full stack below).
It seems to me that problem is related to three issues:
ProtectPointcutPostProcessor - from spring security
MethodValidationPostProcessor - which lack of disables the error
change in Spring Boot 2.4.0 - which is described below
Possible cause description
In Spring Boot 2.4.0 new Bean has been introduced in EnableConfigurationPropertiesRegistrar:
static void registerMethodValidationExcludeFilter(BeanDefinitionRegistry registry) {
if (!registry.containsBeanDefinition(METHOD_VALIDATION_EXCLUDE_FILTER_BEAN_NAME)) {
BeanDefinition definition = BeanDefinitionBuilder
.genericBeanDefinition(MethodValidationExcludeFilter.class,
() -> MethodValidationExcludeFilter.byAnnotation(ConfigurationProperties.class))
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE).getBeanDefinition();
registry.registerBeanDefinition(METHOD_VALIDATION_EXCLUDE_FILTER_BEAN_NAME, definition);
}
}
This bean is generated with MethodValidationExcludeFilter.byAnnotation as Lambda:
static MethodValidationExcludeFilter byAnnotation(Class<? extends Annotation> annotationType,
SearchStrategy searchStrategy) {
return (type) -> MergedAnnotations.from(type, SearchStrategy.SUPERCLASS).isPresent(annotationType);
}
Because of being Lambda it has no parent class and fails miserably on bean creation post processing.
(Very) hacky solution
Luckily EnableConfigurationPropertiesRegistrar.registerMethodValidationExcludeFilter contains if statement which checks if bean has not been created. So we may create this bean manually instead:
#Bean("org.springframework.boot.context.properties.EnableConfigurationPropertiesRegistrar.methodValidationExcludeFilter")
public MethodValidationExcludeFilter mockMethodValidationExcludeFilter() {
return new MethodValidationExcludeFilter() {
#Override
public boolean isExcluded( Class< ? > type ) {
return MethodValidationExcludeFilter.byAnnotation( ConfigurationProperties.class).isExcluded( type );
}
};
}
Or even as:
#Bean("org.springframework.boot.context.properties.EnableConfigurationPropertiesRegistrar.methodValidationExcludeFilter")
public String mockMethodValidationExcludeFilter() {
return "mockMethodValidationExcludeFilter";
}
But this seems to me as very dirty hack and not suitable for production usage.
Theoretically disabling linting error cantFindType could also save the day as doing it on debug has allowed application to run but
we have not achieved proper configuration to disable it
this seems as dirty hack as well and should be considered as last resort and not proper solution
Logs
Full error stack trace:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.context.properties.EnableConfigurationPropertiesRegistrar.methodValidationExcludeFilter' defined in class path resource [com/source/etf/common/aop/AopConfig.class]: Initialization of bean failed; nested exception is org.aspectj.weaver.reflect.ReflectionWorld$ReflectionWorldException: warning can't determine superclass of missing type com.source.etf.common.aop.AopConfig$$Lambda$751.0x00000008008fec40
[Xlint:cantFindType]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:617) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:531) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:925) ~[spring-context-5.3.1.jar:5.3.1]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:588) ~[spring-context-5.3.1.jar:5.3.1]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:144) ~[spring-boot-2.4.0.jar:2.4.0]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:767) ~[spring-boot-2.4.0.jar:2.4.0]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:759) ~[spring-boot-2.4.0.jar:2.4.0]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:426) ~[spring-boot-2.4.0.jar:2.4.0]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:326) ~[spring-boot-2.4.0.jar:2.4.0]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1309) ~[spring-boot-2.4.0.jar:2.4.0]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1298) ~[spring-boot-2.4.0.jar:2.4.0]
at com.source.etf.EtfmApplication.main(EtfmApplication.java:56) ~[main/:na]
Caused by: org.aspectj.weaver.reflect.ReflectionWorld$ReflectionWorldException: warning can't determine superclass of missing type com.source.etf.common.aop.AopConfig$$Lambda$751.0x00000008008fec40
[Xlint:cantFindType]
at org.aspectj.weaver.reflect.ReflectionWorld$ExceptionBasedMessageHandler.handleMessage(ReflectionWorld.java:219) ~[aspectjweaver-1.9.6.jar:na]
at org.aspectj.weaver.Lint$Kind.signal(Lint.java:340) ~[aspectjweaver-1.9.6.jar:1.9.6]
at org.aspectj.weaver.MissingResolvedTypeWithKnownSignature.raiseCantFindType(MissingResolvedTypeWithKnownSignature.java:237) ~[aspectjweaver-1.9.6.jar:1.9.6]
at org.aspectj.weaver.MissingResolvedTypeWithKnownSignature.getSuperclass(MissingResolvedTypeWithKnownSignature.java:98) ~[aspectjweaver-1.9.6.jar:1.9.6]
at org.aspectj.weaver.JoinPointSignatureIterator.addSignaturesUpToFirstDefiningMember(JoinPointSignatureIterator.java:95) ~[aspectjweaver-1.9.6.jar:1.9.6]
at org.aspectj.weaver.JoinPointSignatureIterator.<init>(JoinPointSignatureIterator.java:49) ~[aspectjweaver-1.9.6.jar:1.9.6]
at org.aspectj.weaver.MemberImpl.getJoinPointSignatures(MemberImpl.java:515) ~[aspectjweaver-1.9.6.jar:1.9.6]
at org.aspectj.weaver.patterns.SignaturePattern.matches(SignaturePattern.java:319) ~[aspectjweaver-1.9.6.jar:na]
at org.aspectj.weaver.patterns.KindedPointcut.matchInternal(KindedPointcut.java:202) ~[aspectjweaver-1.9.6.jar:na]
at org.aspectj.weaver.patterns.Pointcut.match(Pointcut.java:137) ~[aspectjweaver-1.9.6.jar:na]
at org.aspectj.weaver.internal.tools.PointcutExpressionImpl.getShadowMatch(PointcutExpressionImpl.java:319) ~[aspectjweaver-1.9.6.jar:na]
at org.aspectj.weaver.internal.tools.PointcutExpressionImpl.matchesExecution(PointcutExpressionImpl.java:129) ~[aspectjweaver-1.9.6.jar:na]
at org.aspectj.weaver.internal.tools.PointcutExpressionImpl.matchesMethodExecution(PointcutExpressionImpl.java:110) ~[aspectjweaver-1.9.6.jar:na]
at org.springframework.security.config.method.ProtectPointcutPostProcessor.attemptMatch(ProtectPointcutPostProcessor.java:148) ~[spring-security-config-5.4.5.jar:5.4.5]
at org.springframework.security.config.method.ProtectPointcutPostProcessor.postProcessBeforeInitialization(ProtectPointcutPostProcessor.java:125) ~[spring-security-config-5.4.5.jar:5.4.5]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:429) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1780) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:609) ~[spring-beans-5.3.1.jar:5.3.1]
... 16 common frames omitted
Process finished with exit code 1