Search code examples
hibernatesessionblobtransactional

Hibernate + Resteasy + Blobstream


i'm using resteasy and saving blobs with hibernate

i've configured the open session in view

my rest-handler is non-transactional, my service which retrieves the java.sql.blobs is transactional.

The problem: after retrieving the blob in the service the jdbc-connection is closed by the HibernateTransactionManager:doCleanupAfterCompletion (the hibernate session is not closed)

so rest can't read the blob stream later, because it works only if the same jdbc-connection is still open

how can i hibernate teach not to close the jdbc-connection after the transactional service-function?

It should close it when the session is closed


Solution

  • i solved it by creating a Provider for Blob, adopded from InputSTream-Provider

    @Provider
    @Produces("*/*")
    public class BlobProvider implements MessageBodyWriter<Blob> {
    
        public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
            return Blob.class.isAssignableFrom(type);
        }
    
        public long getSize(Blob blob, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
            return -1;
        }
    
        public void writeTo(Blob blob, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException {
            SessionFactory sessionFactory = (SessionFactory) Utils.getBean("sessionFactory");
            sessionFactory.getCurrentSession().beginTransaction();
            InputStream inputStream = null;
            try {
                inputStream = blob.getBinaryStream();
                int c = inputStream.read();
                if (c == -1) {
                    httpHeaders.putSingle(HttpHeaderNames.CONTENT_LENGTH, Integer.toString(0));
                    entityStream.write(new byte[0]); // fix RESTEASY-204
                    return;
                } else
                    entityStream.write(c);
                ProviderHelper.writeTo(inputStream, entityStream);
            } catch (SQLException e) {
                Utils.logError(e);
            } finally {
                if (inputStream != null)
                    inputStream.close();
            }
            sessionFactory.getCurrentSession().getTransaction().commit();
        }
    }