I am trying to use an #Autowired variable in an #Configuration class, where a bean is created using #Bean in a method. However the component I need to create the bean with is null.
#Autowired
private JDAListener listener;
#Bean
public ShardManager shardManager() throws LoginException, IllegalArgumentException {
DefaultShardManagerBuilder builder = DefaultShardManagerBuilder.createDefault(this.botToken)
.enableIntents(GatewayIntent.GUILD_MEMBERS)
.setStatus(OnlineStatus.IDLE)
.setShardsTotal(this.totalShards)
.addEventListeners(Arrays.asList(this.listener)); //throws Exception
return builder.build();
}
The Exception I get is as follows:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'config':
Unsatisfied dependency expressed through field 'shardManager'; nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'shardManager' defined in class path resource [dev/teamnight/nightbot/Config.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException:
Failed to instantiate [net.dv8tion.jda.api.sharding.ShardManager]: Circular reference involving containing bean 'config' - consider declaring the factory method as static for independence from its containing instance. Factory method 'shardManager' threw exception;
nested exception is java.lang.IllegalArgumentException: listeners may not be null
I assume the code snippet is a part of some kind of configuration (Something annotated with #Configuration or maybe even #SpringBootApplication).
In this case:
Make JDAListener be managed by Spring container as well.
Inject the instance of JDAListener bean into the shard manager by passing the parameter to the shardManager method
You will end up with the code that looks like this:
#Configuration
public class MyConfiguration {
#Bean // now jda listener is managed by spring!
public JDAListener jdaListener() {
return new JDAListener();
}
#Bean // note the parameter to the method
public ShardManager shardManager(JDAListener jdaListener) throws LoginException, IllegalArgumentException {
DefaultShardManagerBuilder builder =
DefaultShardManagerBuilder.createDefault(this.botToken)
.enableIntents(GatewayIntent.GUILD_MEMBERS)
.setStatus(OnlineStatus.IDLE)
.setShardsTotal(this.totalShards)
.addEventListeners(Arrays.asList(jdaListener)); //throws Exception
return builder.build();
}
}
I think that you're facing this issue because Spring attempted to dependency inject the bean before it injected the listener. How about you try declare JdaListener as a bean as well?
Is JDAListener is marked as #Component/ #Service or something which tells the framework that it is suppose to be treated as a bean? Also, quickly check your component scan configuration.
Related
I have a central library for certain functions and now I have trouble integrating that library.
The library is written in spring boot and contains a class: com.common.Security.
It is defined like this:
package com.common;
....
#Service
#EnableConfigurationProperties(SecurityProperties.class)
#Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class Security {
....
}
I try to use this in another class:
package org.special;
import com.common.Security;
#Configuration
public class WebServiceConfig {
#Autowired
private Security security;
....
}
But I get some errors:
Error creating bean with name 'myController': Unsatisfied dependency expressed through field 'WebServiceclient';
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'webserviceClient':
Unsatisfied dependency expressed through field 'template'; nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'webServiceTemplate' defined in class path resource [org/special/WebServiceConfig.class]:
Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException:
Failed to instantiate [org.springframework.ws.client.core.WebServiceTemplate]: Factory method 'webServiceTemplate' threw exception;
nested exception is org.springframework.beans.factory.BeanCreationException:
nested exception is org.springframework.beans.factory.support.ScopeNotActiveException: Error creating bean with name 'scopedTarget.Security': Scope 'request' is not active for the current thread;
consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found:
What can I do to fix this?
Removing the Scope was quite helpfull.
I tried this before but some of my tests failed after that. I didn't see, that this was because of missing settings in application.yaml for the tests.
They were not neccessary when scope is request.
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/
I have a method bean that reads a file and returns a NullPointerException when the file doesn't exist. When I am running tests, I don't expect that file to exist so I want to mock that method bean to return a dummy response. It doesn't seem to be working however, and I'm getting an error like this:
"class":"o.s.b.w.s.c.AnnotationConfigServletWebServerApplicationContext"
,"rest":"Exception encountered during context initialization -
cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'someName' defined in class path resource
[../../Someconfiguration.class]: Bean instantiation via factory method failed;
nested exception is org.springframework.beans.BeanInstantiationException:
Failed to instantiate [className]: Factory method 'someName' threw exception;
nested exception is java.lang.NullPointerException"}
The method looks like this:
#Bean
#Qualifier(SOME_QUALIFIER)
public className someName() {
// read file and return null exception if it doesn't exist
}
Would appreciate any ideas on fixing this.
This seems like a use case for Spring profiles.
Mark this method with a positive profile that is only active in production, or a negative profile that is only active in test:
#Bean #Profile("production")
#Qualifier(SOME_QUALIFIER)
public className someName() {
or
#Bean #Profile("!test")
#Qualifier(SOME_QUALIFIER)
public className someName() {
of course you will have to substitute a test configuration that is active for the test profile.
I have some #Component and #Resource in my SpringBoot application.
I have the right JDBC datasource, and also I have some REST services, by Jersey.
I want to test one of the services, but it will fail, it says:
Injection of autowired dependencies failed
But it does not use any component.
This is a simple test for testing db, and it is working:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = MyApplication.class)
public class CommonRepositoryTest {
#Autowired
private MyRepository myRepository;
#Test
public void testDatabaseChangeLogsSize() {
int resultSize = myRepository.getTableRowSize(MyTable.TABLE_NAME);
System.out.println("MyTable result list size: "+resultSize);
assertTrue("MyTable table should has at least one row!", resultSize>0);
}
}
But this REST tester is not working:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = MyApplication.class)
public class SampleResourceTest extends JerseyTest {
#Override
protected Application configure() {
ApplicationContext context = new AnnotationConfigApplicationContext(MyApplication.class);
return new ResourceConfig(SampleResource.class).property("contextConfig", context);
}
#Test
public void testSampleGet() throws Exception {
long id = 1;
String name = "name";
SampleDomainModel sampleDomainModel = new SampleDomainModel();
sampleDomainModel.setId(id);
sampleDomainModel.setName(name);
Response response = target("/sampleresource/samplepath/" + id).queryParam(name).request().get(Response.class);
SampleDomainModel responseSampleDomainModel = response.readEntity(SampleDomainModel.class);
assertEquals(sampleDomainModel.getId(), responseSampleDomainModel.getId());
}
}
As you see, it must override the configure() method from JerseyTest.
I think the problam is, that the AnnotationConfigApplicationContext cannot load anything maybe (?).
The #SpringApplicationConfiguration(classes = MyApplication.class) annotation loads the context, but the new AnnotationConfigApplicationContext(MyApplication.class) code maybe do the failure, it does not have the full context.
If I replace the code with mocking, it works (but it is not a nice way):
#Override
protected Application configure() {
ApplicationContext mockContext = Mockito.mock(ApplicationContext.class);
return new ResourceConfig(SampleResource.class).property("contextConfig", mockContext);
}
The fail message is:
2016-05-13 13:25:39.617 WARN 9832 --- [ main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myRepositoryImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.jdbc.core.JdbcTemplate com.repository.impl.myRepositoryImpl.jdbcTemplate; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration$JdbcTemplateConfiguration': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private javax.sql.DataSource org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration$JdbcTemplateConfiguration.dataSource; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfiguration$NonEmbeddedConfiguration.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 org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Cannot determine embedded database driver class for database type NONE. If you want an embedded database please put a supported one on the classpath. If you have database settings to be loaded from a particular profile you may need to active it (no profiles are currently active).
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.422 sec <<< FAILURE! - in com.ws.server.SampleResourceTest
testSampleGetWithCorrectParameters(com.ws.server.SampleResourceTest) Time elapsed: 0.015 sec <<< ERROR!
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myRepositoryImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.jdbc.core.JdbcTemplate com.repository.impl.MyRepositoryImpl.jdbcTemplate; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration$JdbcTemplateConfiguration': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private javax.sql.DataSource org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration$JdbcTemplateConfiguration.dataSource; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfiguration$NonEmbeddedConfiguration.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 org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Cannot determine embedded database driver class for database type NONE. If you want an embedded database please put a supported one on the classpath. If you have database settings to be loaded from a particular profile you may need to active it (no profiles are currently active).
at org.springframework.boot.autoconfigure.jdbc.DataSourceProperties.getDriverClassName(DataSourceProperties.java:180)
at org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration$NonEmbeddedConfiguration.dataSource(DataSourceAutoConfiguration.java:121)
How to use the SpringBoot context for this jersey test?
SImply put, you can't use both Spring's TestContext and Jersey Test Framework together. They will operate on two different ApplicationContexts. Even if you try to inject the ApplicationContext (created be the TestContext) into the test class and pass it to the ResourceConfig in the configure method, it's too late, as the injection doesn't occur until after construction, but the `configure method is called during contruction.
Forget JerseyTest and just use #WebIntegrationTest. See the sample from the spring boot project.
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(SampleJerseyApplication.class)
#WebIntegrationTest(randomPort = true)
public class SampleJerseyApplicationTests {
#Value("${local.server.port}")
private int port;
In a Jersey/Boot environment, Jersey needs to run in a web app environment, and that's what the #WebIntegrationTest does.
For the client, instead of just calling target on the JerseyTest, you will just need to create the client
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://localhost:" + this.port);
Response response = target.path("/sampleresource/samplepath/" + id).request().get();
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 {
// ...
}