I had a "similar" problem with OP, and I landed here (and in many other BalusC answers).
The BalusC explanation is perfect, as usual, but how do you solve the problem if, like me and the OP, you are in tight limits? In my case: the bean was supposed to be ViewScope, the bytes of the images stored in the bean are immediately updated with "ajaxely" after loading the bytes, you cannot get the image again based on an attribute (for example, identifier, and get it from the database). In general, every time you have a one-time generated image (captcha?) Or images included in ajaxely (uploaded image? Custom image?).
I know that for such ajax-rich applications, JSF / PrimeFaces is not the best structure, but the application is completely written in PrimeFaces, so ... maybe you want to stick with PF and see if a solution is possible.
You can do this using a combination of ajax components and creativity, namely remoteCommand, a bit of JS and a bunch of StackOverflow answers that I'm going to link.
First, you need to call remoteCommand. I do this in the onupload event of the fileUploader file (similar to this answer ), and also when the document is ready (for the generated image):
<p:fileUpload fileUploadListener="#{bean.handleFileUpload}" oncomplete="displayImageBegin();"
displayImageBegin just calls in remoteCommand:
function displayImageBegin() { if (typeof(getImage) == "function") getImage(); }
and
<p:remoteCommand name="getImage" action="#{bean.getImage()}" oncomplete="displayImageEnd(xhr, status, args);" style="display: none;" />
On the bean side, the getImage function simply returns the bytes of the image. You have two options: either use inline, base64 for img src (see this answer , and this one ), or just return and blow the stream and put it in canvas . The second option is more flexible and works with large images (mine are small and the size is controlled, so base64 encoding was great):
You need to completely control the format of the XHR response, as in this answer (BTW, I agree that this is an abuse of JSF as a REST service, treat this code as an interesting experiment):
public void getImage() throws IOException { FacesContext facesContext = FacesContext.getCurrentInstance(); ExternalContext externalContext = facesContext.getExternalContext(); externalContext.setResponseContentType("application/text"); externalContext.setResponseCharacterEncoding("UTF-8"); if (getCurrentImagePresent()) { String base64Image = Base64.getEncoder().encodeToString(yourByteArray); externalContext.getResponseOutputWriter().write(base64Image); } else { externalContext.setResponseStatus(404); } facesContext.responseComplete(); }
The remoteCommand oncomplete passes the data returned from this bean function to our JS, as in this answer :
function displayImageEnd(xhr, status, args) { if (xhr.status == 200) { $('#previewCurrentImage').attr("src", "data:image/png;base64," + xhr.responseText); } }
(of course you need the correct img tag in xhtml)
Why does it work? The answer is here :
A @ViewScoped bean lives exactly as long as a JSF view. [...]
A @ViewScoped bean is therefore particularly useful in rich Ajax-enabled views, which should remember the state of a (modified) view through Ajax requests.
An byte array for the image is generated as part of the creation of the bean and / or as a response to the ajax action on the page; it is then retrieved by any other ajax action on the page, as it falls into the same ViewScoped bean.
This is the solution that worked in my case; I do not recommend it at all, but if your limitations are very similar, you can do something .. it seems! :)
I just wanted to share it, as this may be well suited to the OP question (or people looking for a similar problem), and this is a good collage of good SO answers.