Route Arguments

How the files are received by your method is determined by the type of the arguments. Data can be received a chunk at a time or when an upload is completed.

If the route argument name can’t or shouldn’t match the name of the part in the request, simply add the @Part annotation to the argument and specify the name that is expected to be in the request.

Chunk Data Types

PartData is the data type used to represent a chunk of data received in a multipart request. There are methods on the PartData interface to convert the data to a byte[], InputStream, or a ByteBuffer.

Data can only be retrieved from a PartData once. The underlying buffer will be released which causes further attempts to fail.

Route arguments of type Publisher<PartData> will be treated as only intended to receive a single file and each chunk of the received file will be sent downstream. If the generic type is something other than PartData, conversion will be attempted using Micronaut’s conversion service. Conversions to String and byte[] are supported by default.

If requirements dictate you must have knowledge about the metadata of the file being received, a special class called StreamingFileUpload has been created that is a Publisher<PartData>, but also has file information like the content type and file name.

Streaming file upload

  1. import io.micronaut.http.HttpResponse;
  2. import io.micronaut.http.HttpStatus;
  3. import io.micronaut.http.MediaType;
  4. import io.micronaut.http.annotation.Controller;
  5. import io.micronaut.http.annotation.Post;
  6. import io.micronaut.http.multipart.StreamingFileUpload;
  7. import io.reactivex.Single;
  8. import java.io.File;
  9. import org.reactivestreams.Publisher;
  10. import java.io.IOException;
  11. @Controller("/upload")
  12. public class UploadController {
  13. @Post(value = "/", consumes = MediaType.MULTIPART_FORM_DATA, produces = MediaType.TEXT_PLAIN) (1)
  14. public Single<HttpResponse<String>> upload(StreamingFileUpload file) { (2)
  15. File tempFile;
  16. try {
  17. tempFile = File.createTempFile(file.getFilename(), "temp");
  18. } catch (IOException e) {
  19. return Single.error(e);
  20. }
  21. Publisher<Boolean> uploadPublisher = file.transferTo(tempFile); (3)
  22. return Single.fromPublisher(uploadPublisher) (4)
  23. .map(success -> {
  24. if (success) {
  25. return HttpResponse.ok("Uploaded");
  26. } else {
  27. return HttpResponse.<String>status(HttpStatus.CONFLICT)
  28. .body("Upload Failed");
  29. }
  30. });
  31. }
  32. }

Streaming file upload

  1. import io.micronaut.http.HttpResponse
  2. import io.micronaut.http.HttpStatus
  3. import io.micronaut.http.MediaType
  4. import io.micronaut.http.annotation.Controller
  5. import io.micronaut.http.annotation.Post
  6. import io.micronaut.http.multipart.StreamingFileUpload
  7. import io.reactivex.Single
  8. import org.reactivestreams.Publisher
  9. @Controller("/upload")
  10. class UploadController {
  11. @Post(value = "/", consumes = MediaType.MULTIPART_FORM_DATA, produces = MediaType.TEXT_PLAIN) (1)
  12. Single<HttpResponse<String>> upload(StreamingFileUpload file) { (2)
  13. File tempFile = File.createTempFile(file.filename, "temp")
  14. Publisher<Boolean> uploadPublisher = file.transferTo(tempFile) (3)
  15. Single.fromPublisher(uploadPublisher) (4)
  16. .map({ success ->
  17. if (success) {
  18. HttpResponse.ok("Uploaded")
  19. } else {
  20. HttpResponse.<String>status(HttpStatus.CONFLICT)
  21. .body("Upload Failed")
  22. }
  23. })
  24. }
  25. }

Streaming file upload

  1. import io.micronaut.http.HttpResponse
  2. import io.micronaut.http.HttpStatus
  3. import io.micronaut.http.MediaType
  4. import io.micronaut.http.annotation.Controller
  5. import io.micronaut.http.annotation.Post
  6. import io.micronaut.http.multipart.StreamingFileUpload
  7. import io.reactivex.Single
  8. import java.io.File
  9. @Controller("/upload")
  10. class UploadController {
  11. @Post(value = "/", consumes = [MediaType.MULTIPART_FORM_DATA], produces = [MediaType.TEXT_PLAIN]) (1)
  12. fun upload(file: StreamingFileUpload): Single<HttpResponse<String>> { (2)
  13. val tempFile = File.createTempFile(file.filename, "temp")
  14. val uploadPublisher = file.transferTo(tempFile) (3)
  15. return Single.fromPublisher(uploadPublisher) (4)
  16. .map { success ->
  17. if (success) {
  18. HttpResponse.ok("Uploaded")
  19. } else {
  20. HttpResponse.status<String>(HttpStatus.CONFLICT)
  21. .body("Upload Failed")
  22. }
  23. }
  24. }
  25. }
1The method is set to consume MULTIPART_FORM_DATA
2The method parameters match form attribute names. In this case the file will match for example an <input type=”file” name=”file”>
3The StreamingFileUpload.transferTo(java.lang.String) method is used to transfer the file to the server. The method returns a Publisher
4The returned Single subscribes to the Publisher and outputs a response once the upload is complete, without blocking.

Whole Data Types

Route arguments that are not publishers will cause the route execution to be delayed until the upload has finished. The received data will attempt to be converted to the requested type. Conversions to a String or byte[] are supported by default. In addition, the file can be converted to a POJO if a media type codec has been registered that supports the media type of the file. A media type codec is included by default that allows conversion of JSON files to POJOs.

Receiving a byte array

  1. import io.micronaut.http.HttpResponse;
  2. import io.micronaut.http.MediaType;
  3. import io.micronaut.http.annotation.Controller;
  4. import io.micronaut.http.annotation.Post;
  5. import java.io.File;
  6. import java.io.IOException;
  7. import java.nio.file.Files;
  8. import java.nio.file.Path;
  9. import java.nio.file.Paths;
  10. @Controller("/upload")
  11. public class BytesUploadController {
  12. @Post(value = "/bytes",
  13. consumes = MediaType.MULTIPART_FORM_DATA,
  14. produces = MediaType.TEXT_PLAIN) (1)
  15. public HttpResponse<String> uploadBytes(byte[] file, String fileName) { (2)
  16. try {
  17. File tempFile = File.createTempFile(fileName, "temp");
  18. Path path = Paths.get(tempFile.getAbsolutePath());
  19. Files.write(path, file); (3)
  20. return HttpResponse.ok("Uploaded");
  21. } catch (IOException exception) {
  22. return HttpResponse.badRequest("Upload Failed");
  23. }
  24. }
  25. }

Receiving a byte array

  1. import io.micronaut.http.HttpResponse
  2. import io.micronaut.http.MediaType
  3. import io.micronaut.http.annotation.Controller
  4. import io.micronaut.http.annotation.Post
  5. import java.nio.file.Files
  6. import java.nio.file.Path
  7. import java.nio.file.Paths
  8. @Controller("/upload")
  9. class BytesUploadController {
  10. @Post(value = "/bytes",
  11. consumes = MediaType.MULTIPART_FORM_DATA,
  12. produces = MediaType.TEXT_PLAIN) (1)
  13. HttpResponse<String> uploadBytes(byte[] file, String fileName) { (2)
  14. try {
  15. File tempFile = File.createTempFile(fileName, "temp")
  16. Path path = Paths.get(tempFile.absolutePath)
  17. Files.write(path, file) (3)
  18. HttpResponse.ok("Uploaded")
  19. } catch (IOException exception) {
  20. HttpResponse.badRequest("Upload Failed")
  21. }
  22. }
  23. }

Receiving a byte array

  1. import io.micronaut.http.HttpResponse
  2. import io.micronaut.http.MediaType
  3. import io.micronaut.http.annotation.Controller
  4. import io.micronaut.http.annotation.Post
  5. import java.io.File
  6. import java.io.IOException
  7. import java.nio.file.Files
  8. import java.nio.file.Path
  9. import java.nio.file.Paths
  10. @Controller("/upload")
  11. class BytesUploadController {
  12. @Post(value = "/bytes",
  13. consumes = [MediaType.MULTIPART_FORM_DATA],
  14. produces = [MediaType.TEXT_PLAIN]) (1)
  15. fun uploadBytes(file: ByteArray, fileName: String): HttpResponse<String> { (2)
  16. return try {
  17. val tempFile = File.createTempFile(fileName, "temp")
  18. val path = Paths.get(tempFile.absolutePath)
  19. Files.write(path, file) (3)
  20. HttpResponse.ok("Uploaded")
  21. } catch (exception: IOException) {
  22. HttpResponse.badRequest("Upload Failed")
  23. }
  24. }
  25. }

If requirements dictate you must have knowledge about the metadata of the file being received, a special class called CompletedFileUpload has been created that has methods to retrieve the data of the file, but also has file information like the content type and file name.

File upload with metadata

  1. import io.micronaut.http.HttpResponse;
  2. import io.micronaut.http.MediaType;
  3. import io.micronaut.http.annotation.Controller;
  4. import io.micronaut.http.annotation.Post;
  5. import io.micronaut.http.multipart.CompletedFileUpload;
  6. import java.io.File;
  7. import java.io.IOException;
  8. import java.nio.file.Files;
  9. import java.nio.file.Path;
  10. import java.nio.file.Paths;
  11. @Controller("/upload")
  12. public class CompletedUploadController {
  13. @Post(value = "/completed",
  14. consumes = MediaType.MULTIPART_FORM_DATA,
  15. produces = MediaType.TEXT_PLAIN) (1)
  16. public HttpResponse<String> uploadCompleted(CompletedFileUpload file) { (2)
  17. try {
  18. File tempFile = File.createTempFile(file.getFilename(), "temp"); (3)
  19. Path path = Paths.get(tempFile.getAbsolutePath());
  20. Files.write(path, file.getBytes()); (3)
  21. return HttpResponse.ok("Uploaded");
  22. } catch (IOException exception) {
  23. return HttpResponse.badRequest("Upload Failed");
  24. }
  25. }
  26. }

File upload with metadata

  1. import io.micronaut.http.HttpResponse
  2. import io.micronaut.http.MediaType
  3. import io.micronaut.http.annotation.Controller
  4. import io.micronaut.http.annotation.Post
  5. import io.micronaut.http.multipart.CompletedFileUpload
  6. import java.nio.file.Files
  7. import java.nio.file.Path
  8. import java.nio.file.Paths
  9. @Controller("/upload")
  10. class CompletedUploadController {
  11. @Post(value = "/completed",
  12. consumes = MediaType.MULTIPART_FORM_DATA,
  13. produces = MediaType.TEXT_PLAIN) (1)
  14. HttpResponse<String> uploadCompleted(CompletedFileUpload file) { (2)
  15. try {
  16. File tempFile = File.createTempFile(file.filename, "temp") (3)
  17. Path path = Paths.get(tempFile.absolutePath)
  18. Files.write(path, file.bytes) (3)
  19. HttpResponse.ok("Uploaded")
  20. } catch (IOException exception) {
  21. HttpResponse.badRequest("Upload Failed")
  22. }
  23. }
  24. }

File upload with metadata

  1. import io.micronaut.http.HttpResponse
  2. import io.micronaut.http.MediaType
  3. import io.micronaut.http.annotation.Controller
  4. import io.micronaut.http.annotation.Post
  5. import io.micronaut.http.multipart.CompletedFileUpload
  6. import java.io.File
  7. import java.io.IOException
  8. import java.nio.file.Files
  9. import java.nio.file.Path
  10. import java.nio.file.Paths
  11. @Controller("/upload")
  12. class CompletedUploadController {
  13. @Post(value = "/completed",
  14. consumes = [MediaType.MULTIPART_FORM_DATA],
  15. produces = [MediaType.TEXT_PLAIN]) (1)
  16. fun uploadCompleted(file: CompletedFileUpload): HttpResponse<String> { (2)
  17. return try {
  18. val tempFile = File.createTempFile(file.filename, "temp") (3)
  19. val path = Paths.get(tempFile.absolutePath)
  20. Files.write(path, file.bytes) (3)
  21. HttpResponse.ok("Uploaded")
  22. } catch (exception: IOException) {
  23. HttpResponse.badRequest("Upload Failed")
  24. }
  25. }
  26. }
1The method is set to consume MULTIPART_FORM_DATA
2The method parameters match form attribute names. In this case the file will match for example an <input type=”file” name=”file”>
3The CompletedFileUpload instance gives access to metadata about the upload as well as access to the file’s contents.