RestTemplate getForEntity method throws null pointer exception - spring

I am using RestTemplate with Ribbon Client #LoadBalanced. When I am calling my service - time-service(logical identifier) using Discovery Server, which is running on two instances, it is throwing null pointer exception.
My two instances of time-service are running properly. Also, in discovery server both are registered along with this Ribbon client.
Below is the code for same -
#SpringBootApplication
#RestController
#EnableDiscoveryClient
public class RibbonTimeAppApplication {
#Inject
private RestTemplate restTemplate;
public static void main(String[] args) {
SpringApplication.run(RibbonTimeAppApplication.class, args);
}
#Bean
#LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
#GetMapping
public String getTime()
{
String response = "";
try {
response = restTemplate.getForEntity("http://time-service", String.class).getBody();
}
catch(Exception e)
{
e.printStackTrace();
}
return response;
}
}
Here is the stacktrace I am getting when calling this service -
java.lang.NullPointerException
at com.javatechstack.RibbonTimeAppApplication.getTime(RibbonTimeAppApplication.java:37)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at .......
.........................
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Unknown Source)
This is the screenshot of Eureka dashboard -

You can avoid this error by making restTemplate static. Please confirm if it works:
#Bean
#LoadBalanced
public static RestTemplate restTemplate() {
return new RestTemplate();
}

Related

kafkaendpointlistenerregistry.start() throws null pointer exception

I have a requirement where I want to start Kakfa consumer manually.
Code :
class Dummy implements
ConsumerSeekAware
{
#Autowired
KafkaListenerEndpointRegistry registry;
CountDownLatch latch;
#Autowired
ConcurrentKafkaListenerContainerFactory factory;
onIdleEvent(){
latch.countdown()
}
#KafkaListener(id="myContainer",
topics="mytopic",
autoStartup="false")
public void listen() {}
#Scheduled(cron=" some time ")
void do_some_consumption(){
latch = new CountDownLatch(1);
this.registry.getListenerContainer("myContainer").start();
latch.await();
do processing
this.registry.getListenerContainer("myContainer").stop()
}
}
I have made the bean of
ConcurrentKafkaListenerContainerFactory with all props in my other Config class which I am Autowiring here.
However, I get a null pointer exception when I start my container
using this.registry.getListenerContainer("myContainer").start()
java.lang.NullPointerException: null
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:93)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
I just copied your code into a Spring Boot app (which auto configures the factories); and everything works perfectly as expected...
#SpringBootApplication
#EnableScheduling
public class So62412316Application {
public static void main(String[] args) {
SpringApplication.run(So62412316Application.class, args);
}
#Bean
public ApplicationRunner runner(KafkaTemplate<String, String> template) {
return args -> {
template.send("mytopic", "foo");
};
}
#Bean
public NewTopic topic() {
return TopicBuilder.name("mytopic").partitions(1).replicas(1).build();
}
}
#Component
class Dummy implements ConsumerSeekAware {
#Autowired
KafkaListenerEndpointRegistry registry;
CountDownLatch latch;
#Autowired
ConcurrentKafkaListenerContainerFactory factory;
#EventListener
public void onIdleEvent(ListenerContainerIdleEvent event) {
System.out.println(event);
latch.countDown();
}
#KafkaListener(id = "myContainer", topics = "mytopic", autoStartup = "false")
public void listen(String in) {
System.out.println(in);
}
#Scheduled(initialDelay = 5_000, fixedDelay = 60_000)
void do_some_consumption() throws InterruptedException {
latch = new CountDownLatch(1);
this.registry.getListenerContainer("myContainer").start();
latch.await();
this.registry.getListenerContainer("myContainer").stop();
}
}
spring.kafka.consumer.auto-offset-reset=earliest
spring.kafka.listener.idle-event-interval=5000

Infinite loop when authenticating user: Implementation of JWT with Spring Security

EDIT: I am now getting a 403 forbidden, access denied on all requests besides register and login
I am testing out my endpoints for an application after having implemented JWT authentication and spring security based on this article: https://medium.com/#hantsy/protect-rest-apis-with-spring-security-and-jwt-5fbc90305cc5
Similarly, my other sources of inspiration include: https://www.youtube.com/watch?v=X80nJ5T7YpE
Registration and login of a user are functional, but when I perform subsequent requests requiring the JWT in the header, I get an infinite loop/recursion and a stack overflow error. However, when I input a non-existing JWT on purpose, it throws back the appropriate error message and works well. So the problem is with successfully authenticating a valid JWT. After looking online at different stack overflow answers such as:
Infinite loop in custom Spring Security application
Infinite loop in custom Spring Security application
In Spring Security 3.2.5, what is causing an infinite loop inside the AuthenticationManager implementation?
They all seem to say the same thing which is that the ProviderManager class is looking through the list of auth providers to find one that can authenticate the given authentication and it is not finding one , which causes this error, and they suggest to implement your own authentication provider. Below is my code for the different relevant classes. Note that I do not use a userDetailsService class; instead I have my own UserService class which has basically the functionality of userDetailsService traditionally and also application-specific code. I also did not implement my own authentication provider, following the code examples I mentioned above, so I would like to avoid implementing the authentication providers since the code samples mentioned work and are simpler.
JwtProvider class
#Component
public class JwtProvider {
#Value("${security.jwt.token.secret-key:secret}")
private String secretKey = "secret";
#Value("${security.jwt.token.expire-length:3600000}")
private long validityInMilliseconds = 3600000; // 1h
#Autowired
private AppUserService appUserService;
// encoding the secret used to create the signature for the JWT
#PostConstruct
protected void init() {
secretKey = Base64.getEncoder().encodeToString(secretKey.getBytes());
}
public String createToken(String userEmail) {
Claims claims = Jwts.claims().setSubject(userEmail); // subject is the person who is being authenticated
Date now = new Date();
Date validity = new Date(now.getTime() + validityInMilliseconds);
return Jwts.builder()//
.setClaims(claims)//
.setIssuedAt(now)//
.setExpiration(validity)//
.signWith(SignatureAlgorithm.HS256, secretKey)//
.compact();
}
public Authentication getAuthentication(String token) {
AppUser user = this.appUserService.getAppUserByEmail(getUserEmail(token));
return new UsernamePasswordAuthenticationToken(user, "");
}
// get userEmail in the jwt token that we receive
public String getUserEmail(String token) {
return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody().getSubject();
}
// validate a token that we have: not expired, and matches the userEmail
public boolean validateToken(String token) {
try {
Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);
if (claims.getBody().getExpiration().before(new Date())) {
return false;
}
return true;
} catch (JwtException | IllegalArgumentException e) {
return false;
}
}
}
JwtConfigurer class
package ca.mcgill.ecse321.petadoption.controller;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
// configures how we filter http requests
// specifies order of applying filters
public class JwtConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
private JwtProvider jwtProvider;
public JwtConfigurer(JwtProvider jwtProvider) {
this.jwtProvider = jwtProvider;
}
#Override
public void configure(HttpSecurity http) throws Exception {
JwtFilter customFilter = new JwtFilter(jwtProvider);
http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
}
}
JwtFilter class
// Job: intercept a request and look at the header to get the JWT
public class JwtFilter extends GenericFilterBean {
private JwtProvider jwtProvider;
public JwtFilter(JwtProvider jwtProvider) {
this.jwtProvider = jwtProvider;
}
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain)
throws IOException, ServletException {
String token = resolveToken((HttpServletRequest) req);
if (token != null && jwtProvider.validateToken(token)) { // if token is not null and it isn't expired and it is valid
Authentication auth = jwtProvider.getAuthentication(token); // returning the UsernamePasswordAuthenticationToken
SecurityContextHolder.getContext().setAuthentication(auth);
}
filterChain.doFilter(req, res);
}
public String resolveToken(HttpServletRequest req) {
String bearerToken = req.getHeader("Authorization");
if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7, bearerToken.length());
}
return null;
}
}
SecurityConfigurer class
#Configuration
#EnableWebSecurity
public class SecurityConfigurer extends WebSecurityConfigurerAdapter {
#Autowired
JwtProvider jwtProvider;
#Autowired
AppUserService appUserService;
// this is because we cannot perform #autowired authManager anymore cuz its only compatible w/ older Spring Boot
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic().disable()
.csrf().disable() // this disables cross-site request forgery where an attacker manages to get an authenticated user to perform a malicious request to his liking using diff links and such
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // tell it to use the filterChain that intercepts requests and checks the authorization header for a jwt
.and()
.authorizeRequests()
.antMatchers("/login").permitAll()
.antMatchers("/login/").permitAll()
.antMatchers("/register").permitAll()
.antMatchers("/register/").permitAll()
.anyRequest().authenticated()
.and()
.apply(new JwtConfigurer(jwtProvider)); // this specifies to add our custom filter before the usernamepasswordauthenticationfilter
}
}
Here is the error I get:
2020-03-14 12:14:27.183 ERROR 784 --- [nio-8081-exec-4] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Filter execution threw an exception] with root cause
java.lang.StackOverflowError: null
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.2.3.RELEASE.jar:5.2.3.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:205) ~[spring-aop-5.2.3.RELEASE.jar:5.2.3.RELEASE]
at com.sun.proxy.$Proxy120.authenticate(Unknown Source) ~[na:na]
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:195) ~[spring-security-core-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:501) ~[spring-security-config-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at sun.reflect.GeneratedMethodAccessor107.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_181]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.2.3.RELEASE.jar:5.2.3.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:205) ~[spring-aop-5.2.3.RELEASE.jar:5.2.3.RELEASE]
at com.sun.proxy.$Proxy120.authenticate(Unknown Source) ~[na:na]
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:195) ~[spring-security-core-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:501) ~[spring-security-config-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at sun.reflect.GeneratedMethodAccessor107.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_181]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.2.3.RELEASE.jar:5.2.3.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:205) ~[spring-aop-5.2.3.RELEASE.jar:5.2.3.RELEASE]
at com.sun.proxy.$Proxy120.authenticate(Unknown Source) ~[na:na]
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:195) ~[spring-security-core-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:501) ~[spring-security-config-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at sun.reflect.GeneratedMethodAccessor107.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_181]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.2.3.RELEASE.jar:5.2.3.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:205) ~[spring-aop-5.2.3.RELEASE.jar:5.2.3.RELEASE]
at com.sun.proxy.$Proxy120.authenticate(Unknown Source) ~[na:na]
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:195) ~[spring-security-core-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:501) ~[spring-security-config-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at sun.reflect.GeneratedMethodAccessor107.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_181]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181]
I am relatively new to Spring and Spring Boot so any help is appreciated thank you

Null after #InjectMocks in Mockito Junit

I am having some troubles passing a dependancy while unit testing with JUnit.
Consider these pieces of code:
This is the dependacy injecton into the class which i want to test, lets call it Service.
error log trace
java.lang.NullPointerException
at com.example.demo.service.ServiceClass.getCustomerById(ServiceClass.java:50)
at com.example.demo.service.ServiceClassTest.getCustomerByIdTest(ServiceClassTest.java:46)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
ServiceClass
#Service
public class ServiceClass {
public static final String CRM_JPA_URI = "http://localhost:9000/api/tickets/";
#Autowired
RestTemplate restTemplate;
public Customer getCustomerById(int customerId) {
ResponseEntity<Customer> entity = restTemplate.getForEntity(CRM_JPA_URI +"ticket/{customerId}",
Customer.class, customerId);
return entity.getBody();
}
}
ServiceClassTest
#RunWith(MockitoJUnitRunner.class)
public class ServiceClassTest {
#Mock
RestTemplate mockRestTemplate;
#InjectMocks
ServiceClass serviceClass;
/**
* getCustomerByIdTest
*/
#Test
public void getCustomerByIdTest(){
Customer customer = new Customer();
customer.setPassengerName("Ramesh");
customer.setBookingDate("09/09/2019");
customer.setDestStation("pamur");
customer.setEmail("r#gmail.com");
customer.setSourceStation("ongole");
Mockito.lenient().when(mockRestTemplate.getForEntity("http://localhost:9000/api/tickets/ticket/1", Customer.class)).
thenReturn(new ResponseEntity<Customer>(customer,HttpStatus.OK));
System.out.println("object is--->"+serviceClass.getCustomerById(1));
assertEquals(customer, serviceClass.getCustomerById(1));
}
}
Try calling
MockitoAnnotations.initMocks(this);
in your test method or #Before setup() method

Introducing Spring Batch fails Dao-Test

I am using Spring Batch in a Spring Boot application as below. Spring Batch and the application seem to work fine with that configuration.
However, with that configuration for a simple Dao-Test (not for Spring Batch) I get the following exception. Without the Spring Batch configuration the test is running fine. Update: The problem appears if I configure to use an own JobRepository with a transaction manager (below in class MyBatchConfigurer).
I tried to provide another transaction manager for Spring Batch but I am running from exception to exception.
org.springframework.dao.InvalidDataAccessApiUsageException: no transaction is in progress; nested exception is javax.persistence.TransactionRequiredException: no transaction is in progress
Caused by: javax.persistence.TransactionRequiredException: no transaction is in progress
at org.hibernate.internal.SessionImpl.checkTransactionNeeded(SessionImpl.java:3505)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1427)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1423)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:350)
at com.sun.proxy.$Proxy165.flush(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:305)
at com.sun.proxy.$Proxy165.flush(Unknown Source)
at com.foo.dao.GenericDao.save(GenericDao.java:60)
at com.foo.dao.GenericDao$$FastClassBySpringCGLIB$$71a0996b.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:746)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
... 37 more
Test Setup
#SpringBootTest
#RunWith(SpringRunner.class)
#EntityScan(basePackages = "com.foo.entity")
#DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
#TestPropertySource("/mytest.properties")
#Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = "classpath:/testdata.sql")
public class MyTest {
#Inject
private OrderDao sut;
#Test
public void test_findByAnotherFieldId() {
final Order order = // build an order ...
sut.save(order);
final Order result = sut.findByAnotherFieldId("valueOfOtherField");
assertThat(result).isEqualTo(order);
}
}
Spring Batch Job configuration
#Configuration
#EnableBatchProcessing
#Import(OracleDatabaseConfig.class)
#ComponentScan(basePackageClasses = MyBatchConfigurer.class)
public class BatchJobConfig {
// Injects...
#Qualifier("analyseOrdersJob")
#Bean
public Job analyseOrdersJob() {
return jobBuilderFactory.get("analyseOrdersJob").start(analyseOrdersStep()).build();
}
#Bean
public Step analyseOrdersStep() {
return stepBuilderFactory.get("analyseOrdersStep").<Order, String>chunk(4)
.reader(orderItemReader) //
.processor(orderItemProcessor) //
.writer(orderItemWriter) //
.build();
}
}
Spring Batch configuration
#Component
public class MyBatchConfigurer extends DefaultBatchConfigurer {
#Inject
private DataSource dataSource;
#Override
public JobRepository getJobRepository() {
try {
return extractJobRepository();
} catch (final Exception e) {
throw new BatchConfigurationException(e);
}
}
private JobRepository extractJobRepository() throws Exception {
final JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
factory.setDataSource(dataSource);
factory.setTransactionManager(getTransactionManager());
factory.afterPropertiesSet();
return factory.getObject();
}
}
ItemReader
#Component
#StepScope
public class OrderItemReader implements ItemReader<Order> {
#Inject
private OrderDao orderdao;
private int nextOrderIndex;
private List<Order> orders;
#PostConstruct
public void postConstruct() {
orders = orderdao.findAll();
}
#Override
public Order read() {
if (nextOrderIndex < orders.size()) {
final Order order = orders.get(nextOrderIndex);
nextOrderIndex++;
return order;
}
return null;
}
}
ItemWriter and ItemProcessor are similarly configured.

Using Spring Scheduler to return rows from DB throws Null pointer Exception

I am using Spring scheduling to schedule a task that performs some DB operation every hour. This throws a NullPointerException every time I try to call a function that triggers DB specific operations.
Configuration File :
#Configuration
#EnableWebMvc
#ComponentScan(basePackages="com.bt.rtddashboard")
/*#EnableJpaRepositories(basePackages = {
"com.bt.rtddashboard"
})*/
#EnableScheduling
#PropertySource("classpath:jdbc.properties")
public class RTDDashboardConfiguration extends WebMvcConfigurerAdapter {
#Resource
private Environment env;
#Bean(name = "dataSource", destroyMethod="close")
public DataSource getDataSource() {
//DB code
}
private Properties getHibernateProperties() {
//Hibernate code
}
#Bean(name = "sessionFactory")
#Scope("singleton")
public LocalSessionFactoryBean getSessionFactory() {
}
#Autowired
#Bean(name = "transactionManager")
public HibernateTransactionManager getHibernateTransactionManager(SessionFactory factory) {
;
}
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("/").setCachePeriod(31556926);
}
#Scheduled(fixedRate=1000)
public void work() {
// task execution logic
System.out.println("Scheduled Task");
DashboardController controller=new DashboardController();
controller.performTask();
}
}
Dashboard Controller :
#RestController
public class DashboardController {
#Autowired
private InlineService service;
#RequestMapping(value="/rtd/getAllServers", method=RequestMethod.GET)
public ResponseEntity<List<ServerMonitor>> getAllServers(){
List<ServerMonitor> ilsList=new ArrayList<ServerMonitor>();
ResponseEntity<List<ServerMonitor>> response=null;
try{
ilsList=service.getAllServers();
response=new ResponseEntity<List<ServerMonitor>>(ilsList,HttpStatus.OK);
System.out.println("Scheduled Time");
}catch(Exception e){
}
return response;
}
public void performTask(){
System.out.println("Scheduled Task Starts in Contrroller");
List<IlsStats> ilsStats =new ArrayList<IlsStats>();
List<IlsStatsHistory> ilsStatsHisList=new ArrayList<IlsStatsHistory>();
try{
//get All the ILS Stats
ilsStats=service.getAllInlineStats();
System.out.println("No of rows to Copy : " + ilsStats.size());
ilsStatsHisList=formILSHistoryList(ilsStats);
int flag=service.insertInIlsStatsHistory(ilsStatsHisList);
//List<ServerMonitor> ilsList=service.getAllServers();
}catch(Exception e){
e.printStackTrace();
}
}
Here, ilsStats=service.getAllInlineStats(); throws NullPointerException.
Even though the rest webservice created on top of it is working fine.
Stack Trace :
Scheduled Task
Scheduled Task Starts in Contrroller
java.lang.NullPointerException
at com.bt.rtddashboard.controller.DashboardController.performTask(DashboardController.java:226)
at com.bt.rtddashboard.configuration.RTDDashboardConfiguration.work(RTDDashboardConfiguration.java:137)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:304)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
The same stack trace comes up every 1 sec now.
Creating an #Scheduled method in a configuration class is a very bad idea (imho). Next to that I also think that having a scheduler calling a controller method (a method tied to a web related component!) is generally a bad idea/design.
Nonetheless the problem is that you do new DashboardController(). That will obviously create a bean outside the scope of spring and will never be dependency injected. Instead inject the into the class and use that instance.
#Autowired
private DashboardController controller;
#Scheduled(fixedRate=1000)
public void work() {
controller.performTask();
}
Or even better just remove that method all together and simply place #Scheduled(fixedRate=1000) on the performTask method instead.

Resources