Context is getting passed as null, hence getting NullPointerException in context.getBean("abcRestTemplate", RestTemplate.class). What can be the issue for context to be null.
AuthnConfig.java
#Getter
#ConfigurationProperties(prefix = "authn")
#Configuration
public class AuthnConfig {
#Value("${endpoint}")
private String endpoint;
#Value("${client-svc.name}")
private String serviceClientId;
}
RestTemplateConfig.java
#Configuration
public class RestTemplateConfig {
private final AuthnConfig authnConfig;
#Autowired
public RestTemplateConfig(final AuthnConfig authnConfig) {
this.authnConfig = authnConfig;
}
#Bean(name = "abcRestTemplate"){
public RestTemplate abcRestTemplate() {
//authConfig.getEndpoint() etc....
}
}
}
RestTemplateConfigTest.java
#RunWith(SpringRunner.class)
#SpringBootTest
#ActiveProfiles("test")
public class RestTemplateConfigTest {
#Autowired
private RestTemplateConfig restTemplateConfig;
#Autowired
private ApplicationContext context;
#Mock
private AuthnConfig authnConfig;
#Before
public void initializeConfig() {
Mockito.when(authnConfig.getEndpoint()).thenReturn("https://localhost");
}
#Test
public void testForBeanCreation() {
RestTemplate abcRestTemplate = context.getBean("abcRestTemplate", RestTemplate.class);
assertNotNull(abcRestTemplate);
}
}
Errors If #RunWith(MockitoJUnitRunner.class) is used in RestTemplateConfigTest.class:
java.lang.NullPointerException, context is getting passed as NULL in context.getBean("abcRestTemplate", RestTemplate.class);
Errors If #RunWith(SpringRunner.class) is used in RestTemplateConfigTest.class
[ERROR] testForBeanCreation Time elapsed: 0.028 s <<< ERROR!
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'authnConfig': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'endpoint' in value "${endpoint}"
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'endpoint' in value "${endpoint}"
You need to add the your SpringBooltApplication.class to this #SpringBootTest Annotation, just like this: #SpringBootTest(classes = SpringBootApplicationDemo.class)
Related
I am trying to mock my batis mapper.
#SpringBootTest(classes = ApiApplication.class, webEnvironment = WebEnvironment.DEFINED_PORT)
#AutoConfigureMockMvc
#TestPropertySource("classpath:test-application.properties")
public class SpringGlue {
#TestConfiguration
public static class TestConfig {
#Bean
#Primary
ProductMapper productMapper(){
ProductMapper productMapper = mock(ProductMapper.class);
doAnswer(i -> {
String id = i.getArgument(0);
return Product.builder().id(id).name(id + "hello").build();
}).when(productMapper).getProductById(any());
return productMapper;
}
}
}
But this is not getting mocked
nsatisfied dependency expressed through field 'productMapper'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'productMapper'
Caused by: java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required
at org.springframework.util.Assert.notNull(Assert.java:201)
at org.mybatis.spring.support.SqlSessionDaoSupport.checkDaoConfig(SqlSessionDaoSupport.java:122)
at org.mybatis.spring.mapper.MapperFactoryBean.checkDaoConfig(MapperFactoryBean.java:73)
at org.springframework.dao.support.DaoSupport.afterPropertiesSet(DaoSupport.java:44)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1863)
My test class looks like:
#WebFluxTest(controllers = IndexContoller.class)
#Import(UserServiceImpl.class)
class IndexContollerTest {
private static final String PATH = "/";
private static final String ADD_USER = "/signup";
#MockBean
private UserRepo userRepo;
#Autowired
private WebTestClient webClient;
#Autowired
private ReactiveUserDetailsService userService;
#Test
void saveUser() throws Exception {
Mockito.when(userRepo.save(any())).thenReturn(Mono.just(new User()));
webClient.post()
.uri(ADD_USER)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromObject(new User()))
.exchange()
.expectStatus()
.is2xxSuccessful();}
}
and after i ran it it falls with
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'skillGroupRepository' defined in
com.gmail.qwertygoog.roadmap.repository.SkillGroupRepository defined
in #EnableR2dbcRepositories declared on RoadmapApplication: Cannot
resolve reference to bean 'r2dbcEntityTemplate' while setting bean
property 'entityOperations'; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
bean named 'r2dbcEntityTemplate' available
Basically it searches for different service bean's dependency and falls after cant instantiate it.I also tried to add #SpringExtension withought any difference in output. Any suggestions?
I am using embedded Redis in our Webflux testcases using the following dependency in pom.xml file
<dependency>
<groupId>com.github.kstyrc</groupId>
<artifactId>embedded-redis</artifactId>
<version>0.6</version>
</dependency>
And using below annotations for controllertest classes
#RunWith(SpringRunner.class)
#AutoConfigureWebTestClient(timeout = "36000000")
#WithMockUser
#TestPropertySource(locations = "classpath:application-test.properties")
#SpringBootTest(classes = Application.class)
#DirtiesContext
When I run individual controllertest class, all the controllertest are passing.
When I start both the controllertest classes, one controllertest class is failing with following error:
Application run failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'embededRedis': Invocation of init method failed; nested exception is java.lang.RuntimeException: Can't start redis server. Check logs for details.
Below is the embedded Redis class I am using in my JUnit test
#Component
public class EmbededRedis {
#Value("${spring.redis.port}")
private int redisPort;
private RedisServer redisServer;
#PostConstruct
public void startRedis() throws IOException {
if(redisServer==null||!redisServer.isActive()) {
redisServer = new RedisServer(redisPort);
redisServer.start();
}
}
#PreDestroy
public void stopRedis() {
if(redisServer!=null) {
redisServer.stop();
}
}
}
Check if Redis port is available or not. if not, try to assign a different port
#Component
public class EmbededRedis {
#Value("${spring.redis.port:9999}")
private int redisPort;
private RedisServer redisServer;
#PostConstruct
public void startRedis() throws IOException {
if(redisServer==null||!redisServer.isActive()) {
redisServer = new RedisServer(redisPort);
redisServer.start();
}
}
#PreDestroy
public void stopRedis() {
if(redisServer!=null) {
redisServer.stop();
}
}
}
This issue got resolved after restarting the system
I can run my springboot project in IDEA nicely but when packed it to a jar and run with the java command, just got the java.lang.NullPointerException when getting a bean from spring context.
the first class which just got errors:
#Service
public class MdspiImpl extends CThostFtdcMdSpi {
public MdspiImpl(CThostFtdcMdApi mdapi) {
m_mdapi = mdapi;
logger.info("MdspiImpl is creating...");
***mdr = SpringContextUtil.getBean("marketDataRobot");//this is the error code***
}
}
the second class:
#Service
public class MarketDataRobot {
}
the SpringContextUtil class:
#Component("SpringContextUtil")
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public static <T> T getBean(String name) {
return (T) applicationContext.getBean(name);
}
}
the gradle file:
jar {
baseName = 'programmingTrading'
version = '0.1.0'
manifest {
attributes 'Main-Class': 'com.blackHole.programmingTrading'
}
}
the running exception:
WARN main[AbstractApplicationContext.java:557 Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mdspiImpl' defined in URL [jar:file:/E:/workspace/simuPrd/programmingTrading-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/blackHole/programmingTrading/infrastructure/MdspiImpl.class]: Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.blackHole.programmingTrading.infrastructure.MdspiImpl]: Constructor threw exception; nested exception is java.lang.NullPointerException]
[com.blackHole.programmingTrading.infrastructure.MdspiImpl]: Constructor threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:184)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:117)
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:300)
... 27 common frames omitted
Caused by: java.lang.NullPointerException: null
at com.blackHole.programmingTrading.SpringContextUtil.getBean(SpringContextUtil.java:35)
at com.blackHole.programmingTrading.infrastructure.MdspiImpl.<init>(MdspiImpl.java:46)
It also stem from another problem: #Autowired annotation doesn't work...
when using like this:
#Component
public class Scu{
}
in another class:
#Autowired
private Scu scu;
logger.info(String.format("MdspiImpl is creating...[%s]", scu.toString()));
will get a java.lang.NullPointerException: null
spring-boot configuration like this:
#SpringBootApplication
public class ProgrammingTrading {
public static void main(String[] args) {
SpringApplication.run(ProgrammingTrading.class, args);
}
}
that is part of reasons of using SpringContextUtil to get the bean...
thanks a lot!
SpringContextUtil shouldn't be a accessed statically like you are doing... Since you define it as a #Component do the following;
#Service
public class MdspiImpl extends CThostFtdcMdSpi {
#Autowired
private SpringContextUtil springContextUtil;
public MdspiImpl(CThostFtdcMdApi mdapi) {
m_mdapi = mdapi;
logger.info("MdspiImpl is creating...");
***mdr = springContextUtil.getBean("marketDataRobot");
}
}
Due to SpringContextUtil not being injected via Spring, but simply accessed statically, the applicationContext inside of it is ignored and is null in your case.
Also remove the static modifier;
#Component
public class SpringContextUtil implements ApplicationContextAware {
private ApplicationContext applicationContext;
// include getter/setter for applicationContext as well
public <T> T getBean(String name) {
return (T) applicationContext.getBean(name);
}
}
edit
The trouble from the latest example project;
#Service
public class ExampleService {
#Autowired
private Logger logger;
public ExampleService() {
this.logger=logger;
logger.info("Im working");
}
}
Here the Logger will be null, when the ExampleService constructor is triggered, since the constructor is called before the injection starts, but you can merge this behaviour if you incorporate the injection through the said constructor as follows;
#Service
public class ExampleService {
private final Logger logger;
public ExampleService(Logger logger) {
this.logger = logger;
logger.info("Im working");
}
}
Works perfectly without any trouble...
You should never be accessing beans programmatically like you did with this SpringContextUtil, just inject MarketDataRobot in the constructor of MdspiImpl and you’re good to go (since it’s annotated with #Service). The preferred way is to use constructor injection instead of field injection, which will make it easier for you to write unit tests. You can also get rid of #Autowired if you have only one constructor.
I have two #Configuration classes. I need a bean from one configuration class to another. I have autowired the configuration 1 into 2. All works fine. When executing the unit testing, am getting the below exception.
setUpContext(com.trafigura.titan.framework.services.messaging.loader.SpringLoadTest)
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.xxx.MessagingServicesConfig': Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.xxx.EMSJMSConfig com.xxx.MessagingServicesConfig.emsJmsConfig;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type[com.xxx.EMSJMSConfig] 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)}
Is there anything I need to do additionally to make this working?
Below is the setup for testing.
#Configuration
#Import({MessagingServicesConfig.class,...,EMSJMSConfig.class
})
public class MessagingConfig {}
#Profile("EMS-MESSAGING")
#Configuration
public class EMSJMSConfig {
#Bean
public javax.jms.ConnectionFactory jmsSubscriberConnectionFactory() throws JMSException {
SingleConnectionFactory singleConnectionFactory = new SingleConnectionFactory(tibjmsConnectionFactory());
return singleConnectionFactory;
}
}
#Configuration
public class MessagingServicesConfig {
#Autowired
private EMSJMSConfig emsJmsConfig;
#Bean(destroyMethod = "shutdown")
public MessagingService messagingService() throws JMSException {
...
ConnectionFactory cf=emsJmsConfig.jmsSubscriberConnectionFactory(); // Getting NPE at this line.
}
}
and finally the test class,
public class MessagingServicesConfigTest {
private MessagingServicesConfig config;
private EMSJMSConfig emsJmsConfig;
#BeforeMethod
public void setUp() throws Exception {
config = new MessagingServicesConfig();
... //what needs to be done here to have the EMSJMSConfig
}
#Test
public void testBuildsCorrectService() throws JMSException {
MessagingService service = config.messagingService();
...
}
}
By calling new you're creating object yourself, Spring doesn't know anything about it.
Moreover, you should have a test configuration which will be aware of your beans.
Use an appropriate Runner to load SpringContext.
#ContextConfiguration(classes = TestConfig.class)
#RunWith(SpringRunner.class)
class Tests {
#Autowired // if needed
private MessagingServicesConfig config;
}
While in TestConfig you can create beans or import configuration from the Application:
#Configuration
#Import({MessagingServicesConfig.class})
public class TestConfig {}
#Configuration
#Import({EMSJMSConfig.class})
public class MessagingServicesConfig {}
Or you can refer to your config classes directly:
#ContextConfiguration(classes = {MessagingServicesConfig.class, EMSJMSConfig.class})