StreamResource used to set Image Src

Hi, i am evaluating how to change the code below in order to be prepeared for future versions (StreamResource is deprecated)

I could not found a low code option to replace this. Does anyone has an idea?

 ImageItem currentItem = imageItems.get(currentIndex);
        StreamResource resource = new StreamResource(currentItem.getFileName(),
                () -> new ByteArrayInputStream(currentItem.getContent()));
        imageDisplay.setSrc(resource);

The ImageItems gets filled with data out of a database where the images are saved as blob


@Data
@AllArgsConstructor
public class ImageItem {
    String fileName;
    byte [] content;

    public InputStream getInputStream() {
        return new ByteArrayInputStream(content);
    }

    public String getFileName() {
        return fileName;
    }

}

Base64 would be an option but then the images might be bigger.

Lokking forward to some ideas

What speaks against DownloadHandler.fromInputStream?

Ah image takes a DownloadHandler as a parameter :D nice have overseen this.

The name “DownloadHandler” is in this case a little bit confusing, because i font wont to download something, but when i think more about it, i download indeed something to the client. Anyway, it works ;) Thanks a lot

Any hint for optimization? The mime typ can be any image format, thats why i set it dynamic and not static

        ImageItem currentItem = imageItems.get(currentIndex);
        String mimeType = URLConnection.guessContentTypeFromName(currentItem.getFileName());
        DownloadHandler downloadHandler = DownloadHandler.fromInputStream(
                event -> new DownloadResponse(
                        new ByteArrayInputStream(currentItem.getContent()),
                        currentItem.getFileName(),
                        mimeType,
                        currentItem.getContent().length
                )
        );
        imageDisplay.setSrc(downloadHandler);
       ...
   

I would personally inline the whole thing like so and configure inline()


    image.setSrc(DownloadHandler.fromInputStream(event -> {
      ImageItem currentItem = imageItems.get(currentIndex);
      return new DownloadResponse(
        new ByteArrayInputStream(currentItem.getContent()),
        currentItem.getFileName(),
        URLConnection.guessContentTypeFromName(currentItem.getFileName()),
        currentItem.getContent().length
      );
    }).inline());

Thanks, its a good hint but in this case i will attach this downloadhandler to another element as well

But whats if want to open a PDF in Browser. The DownloadHandler triggers always a Download

 private void openFile(int arrayPositionAsOffset, boolean customerFiles) {
        FileBlobEntity fileBlobEntity = ....

        DownloadHandler downloadHandler = DownloadHandler.fromInputStream(
                event -> new DownloadResponse(new ByteArrayInputStream(
                        fileBlobEntity.content()), fileBlobEntity.filename(),
                        URLConnection.guessContentTypeFromName(fileBlobEntity.filename()),
                        fileBlobEntity.content().length
                )
        );

        String resourceUrl = VaadinSession.getCurrent().getResourceRegistry().registerResource(downloadHandler).getResourceUri().toString();
        UI.getCurrent().getPage().open(resourceUrl, "_blank");
    }

The old version using StreamResource works.

That’s when .inline() comes into play

1 Like

:partying_face: thanks! Works like a charm

I would like to claim that pretty much always it is better to use the “lower level API”, where one writes to the outputstream instead. This is not just “how it really works” and keeping it analog to other frameworks, but also one gets rid of that helper method, things are slightly more efficient (no BAIS over the content needed) and it is easier for the developer when you move to the most optimal solution (you generate the PDF on the fly instead of pull a cached version from the database). In case of the ImageItem it would be something like:

        ImageItem currentItem = imageItems.get(currentIndex);
        imageDisplay.setSrc(download -> {
            download.setFileName(currentItem.getFileName());
            // mime type & content lenght in the same way if needed
            download.getOutputStream().write(currentItem.getContent());
        });

Totally without relation to this thread I was preparing and example for my good friend @Sami that scrathes the same topic: addon-demos/src/main/java/org/example/otherexamples/NewDownloadAPI.java at main · parttio/addon-demos · GitHub

Although in above some of the examples are technically more in LOC, they are effectively the same, and thus I think using the same API for both dynamically generated content and somehow cached stuff would be easier for Vaadin users. Currently I only see people getting confused what happens with the new helpers, but please educate if I’m missing something why these “helpers” are relevant.

1 Like