O p:graphicImage chama o método duas vezes durante o ciclo de vida, ai você tem que verificar em qual fase do ciclo de vida esta, dependendo da fase você retorna a imagem, que é o que cara fez:
public StreamedContent getStreamedImageById() {
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
// So, we're rendering the view. Return a stub StreamedContent so that it will generate right URL.
return new DefaultStreamedContent();
}
else {
// aqui esta pegando o parametro passado através de f:param, o f:param funciona como um map (chave e valor)
String id = context.getExternalContext().getRequestParameterMap().get("id");
Image image = service.find(Long.valueOf(id));
return new DefaultStreamedContent(new ByteArrayInputStream(image.getBytes()));
}
}
Em f:param ele passou um valor para a requisição e então pegou esse valor no bean.
Esse valor é a própria identificação da imagem (valor único, que no caso é o id)
Você deve ter alguma maneira de especificar qual imagem quer através de um valor, que foi o que ele fez
<p:dataTable id="table-cardapio" var="cardapio" value="#{cardapioBean.cardapios}">
<p:column>
<p:graphicImage id="photo" value="#{registrarPedidoController.streamedImageById}" cache="FALSE">
<f:param name="id" value="#{cardapio.id}" />
</p:graphicImage>
</p:column>
</p:dataTable>
No código acima foi passado um parâmetro com o nome id e o valor é o id do objeto, mas poderia ser qualquer nome e qualquer atributo, mas eu entendo que o id é um valor único, então usei ele.
O value do graphicImage vai chamar um método que retorna um streamedContent, e dentro desse método vai pegar o parâmetro passado e buscar a imagem no banco através desse parâmetro (primeiro código postado)
EDIT: Da uma olhada ai e se não conseguir posta como o seu código esta e o erro