javaresthttpmicronautmicronaut-client

Cannot create the generated HTTP client's required return type, since no TypeConverter from ByteBuffer to class java.io.File : Micronaut


Below is the server side code for sending file to client as rest response using micronaut.

@Get(value = "/downloadFile", produces = MediaType.APPLICATION_OCTET_STREAM )
public HttpResponse<File> downloadDocument() throws IOException {

    File sampleDocumentFile = new File(getClass().getClassLoader().getResource("SampleDocument.pdf").getFile());

    return HttpResponse.ok(sampleDocumentFile).header("Content-Disposition", "attachment; filename=\"" + sampleDocumentFile.getName() + "\"" );
}

Below is the client for calling the above endpoint.

@Client(value = "/client")
public interface DownloadDocumentClient {

@Get(value = "/downloadDocument", processes = MediaType.APPLICATION_OCTET_STREAM)
public Flowable<File> downloadDocument();

}

Tried to retreive file as below :-

Flowable<File> fileFlowable = downloadDocumentClient.downloadDocument();
    Maybe<File> fileMaybe = fileFlowable.firstElement();
    return fileMaybe.blockingGet();

Getting exception as

io.micronaut.context.exceptions.ConfigurationException: Cannot create the generated HTTP client's required return type, since no TypeConverter from ByteBuffer to class java.io.File is registered


Solution

  • You cannot send file data using File instance because it contains only path and not file content. You can send file content using byte array.

    Update the controller in this way:

    @Get(value = "/download", produces = MediaType.APPLICATION_OCTET_STREAM)
    public HttpResponse<byte[]> downloadDocument() throws IOException, URISyntaxException {
        String documentName = "SampleDocument.pdf";
        byte[] content = Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource(documentName).toURI()));
        return HttpResponse.ok(content).header("Content-Disposition", "attachment; filename=\"" + documentName + "\"");
    }
    

    Client will be then like this:

    @Get(value = "/download", processes = MediaType.APPLICATION_OCTET_STREAM)
    Flowable<byte[]> downloadDocument();
    

    And finally client call:

    Flowable<byte[]> fileFlowable = downloadDocumentClient.downloadDocument();
    Maybe<byte[]> fileMaybe = fileFlowable.firstElement();
    byte[] content = fileMaybe.blockingGet();
    

    Update: If you need to save received bytes (file content) into the file on a client machine (container) then you can do that for example like this:

    Path targetPath = Files.write(Paths.get("target.pdf"), fileMaybe.blockingGet());
    

    And if you really need instance of File instead of Path for further processing then simply:

    File file = targetPath.toFile();