2

This is my third personal spring-boot project, I am using 99% of the config I used before, so have no clue why I am getting an error this time around.

The project starts up fine, but once I make a request on the unique @RestController I have, it immediately throws a null pointer exception. This endpoint receives an alpha-2 country code + city name + the desired IP address. If the IP address is not provided, it takes the client IP address which is used as param for the @Service I am getting the null exception from.

After that, the controller should do many other actions before sending the expected output to the client but it never reaches that point since the null exception is thrown.

This is the request I am using:

http://localhost:8080/apiv1/get-distance?country=af&city=Qalat&ip=150.135.184.38

Which outputs:

There was an unexpected error (type=Internal Server Error, status=500).
Cannot invoke "me.givo.distancebetweenus.getdistance.services.CurrentLocationService.getCurrentLocation(String)" because "this.currentLocationService" is null
java.lang.NullPointerException: Cannot invoke "me.givo.distancebetweenus.getdistance.services.CurrentLocationService.getCurrentLocation(String)" because "this.currentLocationService" is null
    at me.givo.distancebetweenus.getdistance.controllers.DistanceController.getDistance(DistanceController.java:53)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:655)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
    at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:96)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1722)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.base/java.lang.Thread.run(Thread.java:833)

This is my controller:

package me.givo.distancebetweenus.getdistance.controllers;

import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;

import me.givo.distancebetweenus.getdistance.dtos.CityDto;
import me.givo.distancebetweenus.getdistance.dtos.CountryDto;
import me.givo.distancebetweenus.getdistance.entities.CityEntity;
import me.givo.distancebetweenus.getdistance.entities.CountryEntity;
import me.givo.distancebetweenus.getdistance.models.ApiCurrentLocationResponse;
import me.givo.distancebetweenus.getdistance.models.Coordinate;
import me.givo.distancebetweenus.getdistance.models.DistanceResponse;
import me.givo.distancebetweenus.getdistance.repositories.ICitiesRepository;
import me.givo.distancebetweenus.getdistance.repositories.ICountriesRepository;
import me.givo.distancebetweenus.getdistance.services.CurrentLocationService;
import org.modelmapper.ModelMapper;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

@RequestMapping("/apiv1")
@Validated
@RestController
public class DistanceController {

    private final CurrentLocationService currentLocationService;
    private final ICitiesRepository citiesRepository;
    private final ICountriesRepository countriesRepository;
    private final ModelMapper modelMapper;

    public DistanceController(CurrentLocationService currentLocationService, ICitiesRepository citiesRepository,
                              ICountriesRepository countryRepository, ModelMapper modelMapper) {
        this.currentLocationService = currentLocationService;
        this.citiesRepository = citiesRepository;
        this.countriesRepository = countryRepository;
        this.modelMapper = modelMapper;
    }

    @GetMapping("/get-distance")
    @ResponseBody
    private ResponseEntity<Object> getDistance(
            @RequestParam(required = true, name = "country") @Min(2) @Max(2) String country,
            @RequestParam(required = true, name = "city") String city,
            @RequestParam(required = false, name = "ip") @Min(7) @Max(15) String ip,
            HttpServletRequest request) {

        ApiCurrentLocationResponse currentLocation;
        if (ip == null || ip.isEmpty()) {
            String requestIP = request.getRemoteAddr();
            System.out.println(requestIP);
            try {
                currentLocation = currentLocationService.getCurrentLocation(requestIP);
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        } else {
            try {
                currentLocation = currentLocationService.getCurrentLocation(ip);
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }

        CountryEntity countryEntity = countriesRepository.getById(country);
        CityEntity cityEntity = citiesRepository.getByNameAndCode(city, country);

        CountryDto countryDto = convertToCountryDto(countryEntity);
        CityDto cityDto = convertToCityDto(cityEntity);

        Coordinate currentLocationCoordinate = new Coordinate(currentLocation);
        Coordinate destinationCoordinate = new Coordinate(cityDto);

        Double distance = currentLocationCoordinate.distanceBetweenUsKm(destinationCoordinate);

        DistanceResponse response = new DistanceResponse(countryDto, cityDto, distance);

        return ResponseEntity.status(HttpStatus.OK).body(response);
    }

    private CityDto convertToCityDto(CityEntity cityEntity) {
        return modelMapper.map(cityEntity, CityDto.class);
    }

    private CountryDto convertToCountryDto(CountryEntity countryEntity) {
        return modelMapper.map(countryEntity, CountryDto.class);
    }
}

This is the "null" @Service:

package me.givo.distancebetweenus.getdistance.services;

import me.givo.distancebetweenus.getdistance.models.ApiCurrentLocationResponse;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;

@Service
public class CurrentLocationService {

    private final WebClient.Builder webClient;

    private final String key = "fakekey347834834892923fake";

    public CurrentLocationService(WebClient.Builder webClient) {
        this.webClient = webClient;
    }

    public ApiCurrentLocationResponse getCurrentLocation(String requestIP) {

        String url = "https://api.fakeapi.app/json/";
        return webClient.baseUrl(url).build().get()
                .uri(uriBuilder -> uriBuilder
                        .path(requestIP)
                        .queryParam("apikey", key)
                        .build())
                .retrieve()
                .bodyToMono(ApiCurrentLocationResponse.class)
                .block();
    }
}

Edit

shivam's comment gave me the idea of tagging my injections with @Autowired so I did it and I am not getting the null pointer exception in the @Service anymore, as it now happens in the ICountriesRepository which is just the next line of code in my @RestController. These are the changes I made:

public class DistanceController {

    private final CurrentLocationService currentLocationService;
    private final ICitiesRepository citiesRepository;
    private final ICountriesRepository countriesRepository;
    private final ModelMapper modelMapper;

    @Autowired
    public DistanceController(CurrentLocationService currentLocationService, ICitiesRepository citiesRepository,
                              ICountriesRepository countriesRepository, ModelMapper modelMapper) {
        this.currentLocationService = currentLocationService;
        this.citiesRepository = citiesRepository;
        this.countriesRepository = countriesRepository;
        this.modelMapper = modelMapper;
    }

This is the "new" error log:

There was an unexpected error (type=Internal Server Error, status=500).
Cannot invoke "me.givo.distancebetweenus.getdistance.repositories.ICountriesRepository.getById(Object)" because "this.countriesRepository" is null
java.lang.NullPointerException: Cannot invoke "me.givo.distancebetweenus.getdistance.repositories.ICountriesRepository.getById(Object)" because "this.countriesRepository" is null
    at me.givo.distancebetweenus.getdistance.controllers.DistanceController.getDistance(DistanceController.java:72)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:655)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
    at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:96)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1722)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.base/java.lang.Thread.run(Thread.java:833)

There is the code of the ICountriesRepository:

package me.givo.distancebetweenus.getdistance.repositories;


import me.givo.distancebetweenus.getdistance.entities.CountryEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;


@Repository
public interface ICountriesRepository extends JpaRepository<CountryEntity, String> {

}

Also, here is the code of a @Configuration I made for the ModelMapper:

package me.givo.distancebetweenus.getdistance.config;

import org.modelmapper.ModelMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class Config {

    @Bean
    public ModelMapper modelMapper() {
        return new ModelMapper();
    }

}
7
  • did you autowired the CurrentLocationService into DistanceController ? Commented Nov 28, 2021 at 11:50
  • Hello, shivam. I didnt, since I was injecting in the controller constructor but I made the try of adding the Autowired as well and now I am getting the same null error this time in the next Repository the Controller uses. I will update the initial question. Thanks. Commented Nov 28, 2021 at 12:07
  • The dependency injection happens when you start the application. Are you getting any exception at that point? Commented Nov 28, 2021 at 12:09
  • Try to annotate the consturctor with @Autowired. Spring(since 4.3) autowires the ONLY constructor by default, is there a construtor you didn't show us? Commented Nov 28, 2021 at 12:13
  • 1
    Now you've created a mess there, please leave the @Autowire just on the constructor. Please show use this class/interface ICountriesRepository. Commented Nov 28, 2021 at 12:41

1 Answer 1

5

I found that the only @GetMapping method my controller has was private. I just made it public and all run as expected already.

Sign up to request clarification or add additional context in comments.

1 Comment

This has been very helpful to me, I've been asking AI and haven't had a correct answer for such an easy solution like this. Thank you

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.