java.lang.IllegalStateException: InputStream has already been read - do not use InputStreamResource if a stream needs to be read multiple times

Spring JIRA | Greg Adams | 1 year ago
  1. 0

    I've been trying to send a multipart post via restTemplate and have been unable to get it to work with anything but FileSystemResource. In my use case (a weird file-forwarding use case) this forces me to copy a MultiPartFile InputStream into a temp file in order be able to create a FileSystemResource, which seems undesirable. Here's a testing version of the file-receiving controller (from another project, running in another servlet container): {code} @RestController public class FileReceiveController { private Log log = LogFactory.getLog(FileReceiveController.class); @RequestMapping(method = RequestMethod.POST) public void uploadFile(@RequestParam("customerId") int customerId, @RequestPart("file") MultipartFile multipartFile) { log.info("customerId: " + customerId); log.info("Received multipart file - original filename: " + multipartFile.getOriginalFilename()); log.info("content-type: " + multipartFile.getContentType()); log.info("size: " + multipartFile.getSize()); } } {code} Here's the file-forwarding controller: {code} @RestController public class FileForwardController { private RestTemplate restTemplate; public FileForwardController() { SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); requestFactory.setBufferRequestBody(false); this.restTemplate = new RestTemplate(requestFactory); } @RequestMapping(method = RequestMethod.POST) public void uploadFile(@RequestParam("customerId") int customerId, @RequestPart("file") MultipartFile multipartFile) { MultiValueMap<String,Object> parts = new LinkedMultiValueMap<>(); parts.add("customerId", customerId); try { // copy to temp file and use FileSystemResource // File tempFile = File.createTempFile("xyz", ""); // FileCopyUtils.copy(multipartFile.getInputStream(), new FileOutputStream(tempFile)); // parts.add("file", new FileSystemResource(tempFile)); // OR use InputStreamResource (broken) parts.add("file", new InputStreamResource(multipartFile.getInputStream())); // OR use ByteArrayResource (broken) // parts.add("file", new ByteArrayResource(multipartFile.getBytes())); } catch (IOException e) { throw new RuntimeException(e); } HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.MULTIPART_FORM_DATA); HttpEntity<MultiValueMap<String,Object>> request = new HttpEntity<>(parts, headers); restTemplate.exchange("http://localhost:8080", HttpMethod.POST, request, Void.class); } } {code} In this form, the restTemplate.exchange call throws {code} org.springframework.web.client.HttpClientErrorException: 400 Bad Request at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91) at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:614) at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:570) {code} The ByteArrayResource form does the same thing. Only the FileSystemResource form works.

    Spring JIRA | 1 year ago | Greg Adams
    java.lang.IllegalStateException: InputStream has already been read - do not use InputStreamResource if a stream needs to be read multiple times
  2. 0

    I've been trying to send a multipart post via restTemplate and have been unable to get it to work with anything but FileSystemResource. In my use case (a weird file-forwarding use case) this forces me to copy a MultiPartFile InputStream into a temp file in order be able to create a FileSystemResource, which seems undesirable. Here's a testing version of the file-receiving controller (from another project, running in another servlet container): {code} @RestController public class FileReceiveController { private Log log = LogFactory.getLog(FileReceiveController.class); @RequestMapping(method = RequestMethod.POST) public void uploadFile(@RequestParam("customerId") int customerId, @RequestPart("file") MultipartFile multipartFile) { log.info("customerId: " + customerId); log.info("Received multipart file - original filename: " + multipartFile.getOriginalFilename()); log.info("content-type: " + multipartFile.getContentType()); log.info("size: " + multipartFile.getSize()); } } {code} Here's the file-forwarding controller: {code} @RestController public class FileForwardController { private RestTemplate restTemplate; public FileForwardController() { SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); requestFactory.setBufferRequestBody(false); this.restTemplate = new RestTemplate(requestFactory); } @RequestMapping(method = RequestMethod.POST) public void uploadFile(@RequestParam("customerId") int customerId, @RequestPart("file") MultipartFile multipartFile) { MultiValueMap<String,Object> parts = new LinkedMultiValueMap<>(); parts.add("customerId", customerId); try { // copy to temp file and use FileSystemResource // File tempFile = File.createTempFile("xyz", ""); // FileCopyUtils.copy(multipartFile.getInputStream(), new FileOutputStream(tempFile)); // parts.add("file", new FileSystemResource(tempFile)); // OR use InputStreamResource (broken) parts.add("file", new InputStreamResource(multipartFile.getInputStream())); // OR use ByteArrayResource (broken) // parts.add("file", new ByteArrayResource(multipartFile.getBytes())); } catch (IOException e) { throw new RuntimeException(e); } HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.MULTIPART_FORM_DATA); HttpEntity<MultiValueMap<String,Object>> request = new HttpEntity<>(parts, headers); restTemplate.exchange("http://localhost:8080", HttpMethod.POST, request, Void.class); } } {code} In this form, the restTemplate.exchange call throws {code} org.springframework.web.client.HttpClientErrorException: 400 Bad Request at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91) at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:614) at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:570) {code} The ByteArrayResource form does the same thing. Only the FileSystemResource form works.

    Spring JIRA | 1 year ago | Greg Adams
    java.lang.IllegalStateException: InputStream has already been read - do not use InputStreamResource if a stream needs to be read multiple times
  3. 0

    When using an InputStreamResource to create the XmlBeanFactory, an illegal state exception is thrown. java.lang.IllegalStateException: InputStream has already been read - do not use InputStreamResource if a stream needs to be read multiple times at org.springframework.core.io.InputStreamResource.getInputStream(InputStreamResource.java:91) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.detectValidationMode(XmlBeanDefinitionReader.java:425) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.getValidationModeForResource(XmlBeanDefinitionReader.java:412) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.createDocumentBuilderFactory(XmlBeanDefinitionReader.java:385) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:352) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:308) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:283) at org.springframework.beans.factory.xml.XmlBeanFactory.<init>(XmlBeanFactory.java:73) at org.springframework.beans.factory.xml.XmlBeanFactory.<init>(XmlBeanFactory.java:61) at ResourceReadErrorTest.testDoubleRead(ResourceReadErrorTest.java:23) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at com.intellij.rt.execution.junit2.JUnitStarter.main(JUnitStarter.java:32) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:90)

    Spring JIRA | 1 decade ago | Hal Hildebrand
    java.lang.IllegalStateException: InputStream has already been read - do not use InputStreamResource if a stream needs to be read multiple times
  4. Speed up your debug routine!

    Automated exception search integrated into your IDE

  5. 0

    When using an InputStreamResource to create the XmlBeanFactory, an illegal state exception is thrown. java.lang.IllegalStateException: InputStream has already been read - do not use InputStreamResource if a stream needs to be read multiple times at org.springframework.core.io.InputStreamResource.getInputStream(InputStreamResource.java:91) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.detectValidationMode(XmlBeanDefinitionReader.java:425) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.getValidationModeForResource(XmlBeanDefinitionReader.java:412) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.createDocumentBuilderFactory(XmlBeanDefinitionReader.java:385) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:352) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:308) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:283) at org.springframework.beans.factory.xml.XmlBeanFactory.<init>(XmlBeanFactory.java:73) at org.springframework.beans.factory.xml.XmlBeanFactory.<init>(XmlBeanFactory.java:61) at ResourceReadErrorTest.testDoubleRead(ResourceReadErrorTest.java:23) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at com.intellij.rt.execution.junit2.JUnitStarter.main(JUnitStarter.java:32) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:90)

    Spring JIRA | 1 decade ago | Hal Hildebrand
    java.lang.IllegalStateException: InputStream has already been read - do not use InputStreamResource if a stream needs to be read multiple times
  6. 0

    Handling multi-part forms from a blocking handler?

    Google Groups | 3 months ago | Deven Phillips
    java.lang.IllegalStateException: Request has already been read

    Not finding the right solution?
    Take a tour to get the most out of Samebug.

    Tired of useless tips?

    Automated exception search integrated into your IDE

    Root Cause Analysis

    1. java.lang.IllegalStateException

      InputStream has already been read - do not use InputStreamResource if a stream needs to be read multiple times

      at org.springframework.core.io.InputStreamResource.getInputStream()
    2. Spring Core
      InputStreamResource.getInputStream
      1. org.springframework.core.io.InputStreamResource.getInputStream(InputStreamResource.java:96)[spring-core-4.2.4.RELEASE.jar:4.2.4.RELEASE]
      1 frame
    3. Spring
      RestTemplate$HttpEntityRequestCallback.doWithRequest
      1. org.springframework.http.converter.ResourceHttpMessageConverter.writeInternal(ResourceHttpMessageConverter.java:100)[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
      2. org.springframework.http.converter.ResourceHttpMessageConverter.writeInternal(ResourceHttpMessageConverter.java:47)[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
      3. org.springframework.http.converter.AbstractHttpMessageConverter.write(AbstractHttpMessageConverter.java:195)[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
      4. org.springframework.http.converter.FormHttpMessageConverter.writePart(FormHttpMessageConverter.java:349)[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
      5. org.springframework.http.converter.FormHttpMessageConverter.writeParts(FormHttpMessageConverter.java:329)[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
      6. org.springframework.http.converter.FormHttpMessageConverter.writeMultipart(FormHttpMessageConverter.java:318)[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
      7. org.springframework.http.converter.FormHttpMessageConverter.write(FormHttpMessageConverter.java:233)[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
      8. org.springframework.http.converter.FormHttpMessageConverter.write(FormHttpMessageConverter.java:88)[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
      9. org.springframework.web.client.RestTemplate$HttpEntityRequestCallback.doWithRequest(RestTemplate.java:800)[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
      9 frames