2

I am trying to upload a file in chunks in Java.
My chunk upload function:

@Async
private Future<String> sendChunk(byte[] chunk, int start, int end, int numberOfChunks, String name, String sessionId) throws IOException {

    LinkedMultiValueMap<String, Object> requestParams = new LinkedMultiValueMap<>();
    requestParams.add("data", new String(java.util.Base64.getEncoder().encode(chunk), "UTF-8"));
    requestParams.add("start", start);
    requestParams.add("end", end);
    requestParams.add("numberOfChunks", numberOfChunks);
    requestParams.add("fileName", name);
    requestParams.add("session", sessionId);

    HttpEntity<LinkedMultiValueMap<String, Object>> requestEntity = new HttpEntity<>(requestParams);
    UploadResponse uploadResponse = restTemplate.exchange(fileServiceUrl, HttpMethod.POST, requestEntity, new ParameterizedTypeReference<UploadResponse>(){}).getBody();
    return new AsyncResult<>(uploadResponse.getSessionId());
}

This is how the File-Service-API looks like:

@RequestMapping(value = "/simpleUploader", method = RequestMethod.POST, produces = "application/json")
public ResponseEntity<UploadResponse> simpleUploader(
    @RequestParam("data") String data,
    @RequestParam("session") String sessionId,
    @RequestParam("start") int start,
    @RequestParam("end") int end,
    @RequestParam("numberOfChunks") int numberOfChunks,
    @RequestParam("fileName") String fileName) throws IOException {
    ....
}

Now, if I try to upload a Chunk the File-Service responds with a 400 - Bad Request.
Stack-Trace:

org.springframework.web.client.HttpClientErrorException: 400 null at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91) at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:667) at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:620) at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:580) at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:526)

It will be rejected from Spring even before it gets to the API-Function.
I am already uploading the same way, but in Javascript. From Javascript everything is working as it should.
What am I missing?

B. Kemmer
  • 1,517
  • 1
  • 14
  • 32

2 Answers2

0

The only problem I had with my code was, that "sessionId" will be null the first time I am calling the File-Service API.
When I set a value of a Map Entry to null, the whole Entry doesn't get passed. I didnt knew that.
My fix was to add a defaultValue to @RequestParam("session") String sessionId so that the method declaration looks like that:

@RequestMapping(value = "/simpleUploader", method = RequestMethod.POST, produces = "application/json")
public ResponseEntity<UploadResponse> simpleUploader(
    ...
    @RequestParam(value = "session", defaultValue = "") String sessionId,
    ... ) throws IOException {
    ....
}
B. Kemmer
  • 1,517
  • 1
  • 14
  • 32
  • Well if it works, it works. But I would rather have a mechanism in place that ensures a session exists before any logic is invoked that relies on there being a session. – Gimby Apr 13 '17 at 09:39
  • initially there is no session available. the first chunk is the "handshake" between client and server. when the first chunk gets uploaded, the server will create a session for the rest of the file chunks. – B. Kemmer Apr 24 '17 at 07:42
0

The @Async has two limitations.

  • it must be applied to public methods only.
  • self-invocation – calling the async method from within the same class – won’t work

http://www.baeldung.com/spring-async

Try changing private to public

@Async public Future<String> sendChunk(byte[] chunk, int start, int end, int numberOfChunks, String name, String sessionId) throws IOException {