Can not resolve NullPointerException in WebClient Builder | Spring Boot

Viewed 2470

I am getting a Nullpointer Exception when calling a service with the help of WebClient.

Service

@Service
public class DummyWebclient  {

  @Autowired
  private WebClient getWebClient;

  public DummyWebclient() {}

  Response client3 = getWebClient.get().
            uri(uriBuilder -> uriBuilder
                .queryParam("param1", "value1")
                .queryParam("param2", "value2")
                .build() )
            .retrieve()
            .bodyToMono(Response.class)
            .block();

  public Response getClient3() {
        return client3;
    }
}

Template Webservice

@Component
public class GetWebClient {

    @Bean
    public WebClient GetWebclient() {
       return WebClient
               .builder()
               .baseUrl(MainURL.getMAINURL())
               .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
               .build()
                ;
    }
}

And a simple test to reveive the response throws NullPointer Exception, Caused by: java.lang.NullPointerException at (DummyWebclient.java:19)

Line Response client3 = getWebClient.get().

@ExtendWith(SpringExtension.class)
@SpringBootTest
class DummyWebclientTest{

    @Autowired
    private DummyWebclient dummyWebclient;

    @Test
    public void GetResponse2() {
        Response response2 = dummyWebclient.getClient3();
        System.out.println(response2);
    }

}

My question is: why does Spring does not create a Bean and insert to Service?

2 Answers

You got the order of initialization wrong:

@Service
public class DummyWebclient  {

  @Autowired
  private WebClient getWebClient;

  public DummyWebclient() {}

  Response client3 = getWebClient.get().
            uri(uriBuilder -> uriBuilder
                .queryParam("param1", "value1")
                .queryParam("param2", "value2")
                .build() )
            .retrieve()
            .bodyToMono(Response.class)
            .block();

  public Response getClient3() {
        return client3;
    }
}

With your current code:

  • new instance of DummyWebClient is created
  • all fields are initialized to their default values
    • getWebClient to null
    • client3 initialization attempt: BOOM
  • only after that Spring will attempt fields injection

You have 2 options to fix this:

Option1

Use constructor injection:

    private WebClient getWebClient;

    @Autowired
    public DummyWebClient(WebClient getWebClient) {
        this.getWebClient = getWebClient;
    }

this is good idea anyway

Option 2

You make a blocking HTTP call in field initialization. Why not get Response on demand, in getClient3() call?

IMHO, you should apply both changes.

Welcome to Stackoverflow

class GetWebClient should have @Configuration annotation instead of @Component

Related