Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HttpHeaders cause NPE in use with RestTemplate #22871

Closed
membersound opened this issue May 2, 2019 · 3 comments
Closed

HttpHeaders cause NPE in use with RestTemplate #22871

membersound opened this issue May 2, 2019 · 3 comments
Labels
status: duplicate A duplicate of another issue

Comments

@membersound
Copy link

membersound commented May 2, 2019

Occasionally I'm getting NPEs wehn using RestTemplate.postForObject(). I could not manually reproduce the issues, as I don't know the case when the headers "seem" to be null.

All I know is that the ClientHttpResponse is not null in those cases and correctly filled with header+body data. The next request with the exact same parameters then works again.

Maybe this has to do with #22821, because new HttpHeaders() is initialized with LinkedCaseInsensitiveMap?

Anyways I think adding (or getting) the HttpHeaders should never result in an NPE, this should be caught somewhere down the stack.

java.util.concurrent.CompletionException: java.lang.NullPointerException
	at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:314) ~[?:?]
	at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:319) ~[?:?]
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1702) ~[?:?]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[?:?]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[?:?]
	at java.lang.Thread.run(Thread.java:834) [?:?]
Caused by: java.lang.NullPointerException
	at org.springframework.util.CollectionUtils$MultiValueMapAdapter.add(CollectionUtils.java:460) ~[spring-core-5.1.6.RELEASE.jar:5.1.6.RELEASE]
	at org.springframework.http.HttpHeaders.add(HttpHeaders.java:1565) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
	at org.springframework.http.client.HttpComponentsClientHttpResponse.getHeaders(HttpComponentsClientHttpResponse.java:71) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
	at org.springframework.http.client.BufferingClientHttpResponseWrapper.getHeaders(BufferingClientHttpResponseWrapper.java:65) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
	at org.springframework.web.client.MessageBodyClientHttpResponseWrapper.getHeaders(MessageBodyClientHttpResponseWrapper.java:115) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
	at org.springframework.web.client.MessageBodyClientHttpResponseWrapper.hasMessageBody(MessageBodyClientHttpResponseWrapper.java:66) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
	at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:87) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
	at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:737) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
	at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:670) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
	at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:414) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1700) ~[?:?]
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label May 2, 2019
@rstoyanchev
Copy link
Contributor

Yes it should not result in an NPE but the cause is likely a bug that should be addressed. What is the header data in such a case? Maybe that can help to reproduce it. Also any chance you could retry with 5.2.0.BULID-SNAPSHOT to confirm if it is related to #22821.

@membersound
Copy link
Author

membersound commented May 9, 2019

The problem is: it only happens every other day, by chance. So if I'd be using the snapshot (which is not that easy as I'm totally inheriting from spring-boot release), I still can't be sure if it is fixed.

Unfortunately I did not find a way to reproduce the issue at will.
The headers in those cases are nothing special:
Headers: [X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY", Content-Type:"application/json;charset=UTF-8", Content-Length:"1430", Date:"Wed, 08 May 2019 11:55:22 GMT"]

Maybe it has to do with the fact the I'm sending and processing my requests in an async future?

@Autowired
private ThreadPoolExecutor executor;

List<Request> requests;

//the basic idea is to prepare all requests required, then dispatch all req async and collect the responses also async. then wait until all responses have been received.
List<CompletableFuture<Response>> futures = requests
		.stream()
		.map(req -> CompletableFuture.supplyAsync(
			() -> restTemplate.postForEntity(URL, req, Response.class).getBody(), executor)
		.collect(Collectors.toList());

List<Response> responses = futures.stream().map(CompletableFuture::join).collect(Collectors.toList());

I also found another log entry, that interestingly throws the NPE also inside an async process.
It comes from the following code:

@Service
@Async
public class MyHeaderInterceptor() {
    public void traceHeaders(ClientHttpResponse rsp) {
        LOGGER.info(message.getHeaders().toString());
    }
}

Same issue: occasionally getting NPEs like:

java.lang.NullPointerException: null
	at org.springframework.util.CollectionUtils$MultiValueMapAdapter.add(CollectionUtils.java:460) ~[spring-core-5.1.6.RELEASE.jar:5.1.6.RELEASE]
	at org.springframework.http.HttpHeaders.add(HttpHeaders.java:1565) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
	at org.springframework.http.client.HttpComponentsClientHttpResponse.getHeaders(HttpComponentsClientHttpResponse.java:71) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
	at org.springframework.http.client.BufferingClientHttpResponseWrapper.getHeaders(BufferingClientHttpResponseWrapper.java:65) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at my.logging.MyHeaderInterceptor.traceHeaders(MyHeaderInterceptor.java:116) ~[classes/:?]
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.1.6.RELEASE.jar:5.1.6.RELEASE]
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749) ~[spring-aop-5.1.6.RELEASE.jar:5.1.6.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.1.6.RELEASE.jar:5.1.6.RELEASE]
	at org.springframework.aop.interceptor.AsyncExecutionInterceptor.lambda$invoke$0(AsyncExecutionInterceptor.java:115) ~[spring-aop-5.1.6.RELEASE.jar:5.1.6.RELEASE]
	at java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[?:?]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[?:?]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[?:?]
	at java.lang.Thread.run(Thread.java:834) [?:?]

To be complete, my RestTemplate is build with apache HttpClient as follows:

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
	HttpClient httpClient = HttpClientBuilder.create()
			.setMaxConnTotal(200)
			.setMaxConnPerRoute(100)
			.build();

	HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
	factory.setConnectTimeout(2000);
	factory.setReadTimeout(10000);

	return builder.requestFactory(() -> new BufferingClientHttpRequestFactory(factory)).build();
}

@bclozel bclozel added status: invalid An issue that we don't feel is valid and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Apr 1, 2020
@bclozel
Copy link
Member

bclozel commented Apr 1, 2020

We didn't get any new reports for this, I'm assuming this has been fixed with #22821.

@bclozel bclozel closed this as completed Apr 1, 2020
@bclozel bclozel added status: duplicate A duplicate of another issue and removed status: invalid An issue that we don't feel is valid labels Apr 1, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: duplicate A duplicate of another issue
Projects
None yet
Development

No branches or pull requests

4 participants