Important Note: This issue has been fixed since PrimeFaces 5.2 final (community release) was released on April 8, 2015. That way, if you accidentally use this version or newer, you wonβt have to bother with a temporary workaround.
The earlier example can now be safely modified as follows.
public StreamedContent getImage() throws IOException { FacesContext context = FacesContext.getCurrentInstance(); if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) { return new DefaultStreamedContent(); } else { String id = context.getExternalContext().getRequestParameterMap().get("id"); byte[] bytes = Utils.isNumber(id) ? service.findImageById(Long.parseLong(id)) : null; return bytes == null ? null : new DefaultStreamedContent(new ByteArrayInputStream(bytes)); } }
I moved the images to the database (MySQL) as a BLOB ( LONGBLOB ) after I got tired of manipulating / managing the images stored in the disk file system.
Accordingly, I show the images in <p:dataTable> as follows (explicitly copied from here :)).
<p:column headerText="Header"> <p:graphicImage value="#{bannerBean.image}" height="200" width="200"> <f:param name="id" value="#{row.bannerId}"/> </p:graphicImage> <p:column>
The bean that retrieves the images is as follows.
@ManagedBean @ApplicationScoped public final class BannerBean { @EJB private final BannerBeanLocal service=null; public BannerBean() {} public StreamedContent getImage() throws IOException { FacesContext context = FacesContext.getCurrentInstance(); if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) { return new DefaultStreamedContent(); } else { String id = context.getExternalContext().getRequestParameterMap().get("id"); byte[] bytes = service.findImageById(Long.parseLong(id)); return bytes==null? new DefaultStreamedContent():new DefaultStreamedContent(new ByteArrayInputStream(bytes)); } } }
This works fine as long as there are images in each row of the database table.
A column of type BLOB in the database, however, is optional in some cases and, therefore, it may contain null values.
If this column is null on any / s line in the database, the following exception is thrown.
SEVERE: Error in streaming dynamic resource. null WARNING: StandardWrapperValve[Faces Servlet]: Servlet.service() for servlet Faces Servlet threw exception java.lang.NullPointerException at org.primefaces.application.PrimeResourceHandler.handleResourceRequest(PrimeResourceHandler.java:127) at javax.faces.application.ResourceHandlerWrapper.handleResourceRequest(ResourceHandlerWrapper.java:153) at javax.faces.webapp.FacesServlet.service(FacesServlet.java:643) at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1682) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:344) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214) at org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:70) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:316) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160) at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:734) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673) at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174) at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:357) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:260) at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:188) at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:191) at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:168) at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:189) at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119) at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:288) at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:206) at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:136) at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:114) at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77) at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:838) at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:113) at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115) at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55) at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135) at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:564) at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:544) at java.lang.Thread.run(Thread.java:722)
So how do you manage a null BLOB to throw this exception?
new DefaultStreamedContent(new ByteArrayInputStream(new byte[0])) returning new DefaultStreamedContent(new ByteArrayInputStream(new byte[0])) , if the byte array in the managed bean is null, it will suppress the exception, but this should not be the solution. Is this a desirable solution?
An EJB method that returns an array of bytes, although in this case it is completely unnecessary.
public byte[] findImageById(Long id) { CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); CriteriaQuery<byte[]>criteriaQuery=criteriaBuilder.createQuery(byte[].class); Root<BannerImages> root = criteriaQuery.from(BannerImages.class); criteriaQuery.multiselect(root.get(BannerImages_.bannerImage)); ParameterExpression<Long>parameterExpression=criteriaBuilder.parameter(Long.class); criteriaQuery.where(criteriaBuilder.equal(root.get(BannerImages_.bannerId), parameterExpression)); List<byte[]> list = entityManager.createQuery(criteriaQuery).setParameter(parameterExpression, id).getResultList(); return list!=null&&!list.isEmpty()?list.get(0):null; }