Hibernate Books

All times are UTC - 5 hours [ DST ]



Post new topic Reply to topic  [ 6 posts ] 
Author Message
 Post subject: Retrieving binary data
PostPosted: Fri Mar 19, 2010 11:55 am 
Newbie

Joined: Fri Mar 19, 2010 11:47 am
Posts: 1
Hello,

I've searched for a long time and couldn't find an answer.

Is there a way to have Hibernate return the InputStream instead of blob or byte[], so the data can be streamed to the web client?

Can a custom data type achieve this?

Thanks very much for your help!

Bing


Top
 Profile  
 
 Post subject: Re: Retrieving binary data
PostPosted: Fri Mar 19, 2010 10:55 pm 
Senior
Senior

Joined: Wed Sep 19, 2007 9:31 pm
Posts: 191
Location: Khuntien (Indonesia)
I think from the byte[] you can convert manually to Input Stream using ByteArrayInputStream


Top
 Profile  
 
 Post subject: Re: Retrieving binary data with a stream
PostPosted: Thu Feb 02, 2012 4:32 am 
Beginner
Beginner

Joined: Tue Nov 02, 2010 4:29 am
Posts: 21
I know this is an old post, but I feel the question still stands. I've made the subject a little more descriptive too.

I'm not convinced that getting the byte array and merely running it through a ByteArrayInputStream is really the desired approach.

I want to be able to stream data out of a binary object or array stored in the database and process it (parse XML in this case) without having to load the whole object or array into memory - something I think the previously suggested approach may do. There is very little documentation on binary objects in the reference documentation (perhaps someone can point me to something else?). I've found mention of hibernate.jdbc.use_streams_for_binary but I don't know what annotations to use on the fields and what types to put on the fields and accessor methods (byte[], blob, lob, inputstream, outputstream, etc).

Any ideas?


Top
 Profile  
 
 Post subject: Re: Retrieving binary data
PostPosted: Fri Feb 10, 2012 11:42 am 
Newbie

Joined: Fri Feb 10, 2012 11:29 am
Posts: 1
I thought I'd piggy back on this topic since I have the same problem - I have a Blob that the entire contents are getting read into memory so it throws OutOfMemory exception.

Hibernate version: 3.6.9
Java: 1.6.0_21
Oracle Database: 11.2.0.2.0
Oracle Drivers: 11.2.0.2.0

Hibernate config property:
Code:
       <property name="hibernate.jdbc.use_streams_for_binary">true</property>


Here is my object's property mapping:
Code:
     <property name="contents" column="CONTENTS" type="blob"/>


Java property:
Code:
   private java.sql.Blob contents;


Creation code:
Code:
InputStream contents = ... // i'm getting these from a file
Blob b = Hibernate.createBlob(contents, contents.available())


Now when I save the Blob b, when there is a flush, it executes code that apparently is trying to convert the Blob into a byte[], so I get an OutOfMemoryError. Here:

java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2786)
at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:94)
at org.hibernate.type.descriptor.java.DataHelper.extractBytes(DataHelper.java:170)
at org.hibernate.type.descriptor.java.BlobTypeDescriptor.unwrap(BlobTypeDescriptor.java:123)
at org.hibernate.type.descriptor.java.BlobTypeDescriptor.unwrap(BlobTypeDescriptor.java:47)
at org.hibernate.type.descriptor.sql.BlobTypeDescriptor$4$1.doBind(BlobTypeDescriptor.java:101)
at org.hibernate.type.descriptor.sql.BasicBinder.bind(BasicBinder.java:91)
at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:283)
at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:278)
at org.hibernate.type.AbstractSingleColumnStandardBasicType.nullSafeSet(AbstractSingleColumnStandardBasicType.java:89)
at org.hibernate.persister.entity.AbstractEntityPersister.dehydrate(AbstractEntityPersister.java:2184)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2430)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2874)
at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:79)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:265)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
at uiowa.hawkirb.biz.AuditableHibernateSession.flush(AuditableHibernateSession.java:48)
at uiowa.hawkirb.biz.Persistent.save(Persistent.java:120)
at uiowa.hawkirb.site.attachment.ViewAttachmentsAction.createNewAttachment(ViewAttachmentsAction.java:522)
at uiowa.hawkirb.site.attachment.ViewAttachmentsAction.execute(ViewAttachmentsAction.java:198)
at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:425)
at uiowa.hawkirb.site.RequestProcessor.processActionPerform(RequestProcessor.java:41)
at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:228)
at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1913)
at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:462)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)


Here is the method unwrap in BlobTypeDescriptor where the exception is getting thrown:
Code:
   @SuppressWarnings({ "unchecked" })
   public <X> X unwrap(Blob value, Class<X> type, WrapperOptions options) {
      if ( ! ( Blob.class.isAssignableFrom( type ) || BinaryStream.class.isAssignableFrom( type ) ) ) {
         throw unknownUnwrap( type );
      }

      if ( value == null ) {
         return null;
      }

      if ( BinaryStream.class.isAssignableFrom( type ) ) {
         try {
            return (X) new BinaryStreamImpl( DataHelper.extractBytes( value.getBinaryStream() ) );
         }
         catch ( SQLException e ) {
            throw new HibernateException( "Unable to access blob stream", e );
         }
      }

      final Blob blob =  WrappedBlob.class.isInstance( value )
            ? ( (WrappedBlob) value ).getWrappedBlob()
            : value;
      return (X) blob;
   }


This is the line throwing the exception:
Code:
return (X) new BinaryStreamImpl( DataHelper.extractBytes( value.getBinaryStream() ) );


It is trying to change everything into a byte[], and then back into BinaryStreamImpl?

Is there a way I can somehow tell hibernate not to put everything into a byte[] like this?


Top
 Profile  
 
 Post subject: Re: Retrieving binary data
PostPosted: Thu May 03, 2012 6:19 am 
Newbie

Joined: Sat Apr 28, 2012 2:48 pm
Posts: 6
Thanks for all share your knowledge.

_________________
designer sunglasses


Top
 Profile  
 
 Post subject: Re: Retrieving binary data
PostPosted: Sat Oct 27, 2012 4:16 am 
Newbie

Joined: Sat Oct 27, 2012 4:03 am
Posts: 1
I ran into the same issue (OOM), and fixed it by replacing the BlobTypeDescriptor:

Code:
        @SuppressWarnings("unchecked")
        @Override
        public <X> X unwrap(Blob value, Class<X> type, WrapperOptions options) {
            if ( value == null ) {
                return null;
            }

            if ( BinaryStream.class.isAssignableFrom( type ) ) {
                return (X) new BinaryStreamWrapper(value);
            }

            try {
                final Blob blob =  WrappedBlob.class.isInstance( value ) ? ((WrappedBlob) value ).getWrappedBlob() : value;
                final Blob rv = options.getLobCreator().createBlob(blob.getBinaryStream(),-1);
                return (X)rv;
            }
            catch (SQLException e) {
                throw new HibernateException(e);
            }
        }

(BinaryStreamWrapper implements BinaryStream and wraps around a Blob without using byte-arrays)

You can register this new BlobType using an Integrator:
Code:
public class BlobIntegrator implements Integrator {
    @Override
    public void integrate(Configuration configuration, SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
        BlobUserType blobUserType = new BlobUserType();
        configuration.registerTypeOverride(blobUserType);
    }
}


Another alternative is to register a UserType which overrides the nullSafeGet and nullSafeSet, but remember that you will need to handle the gory details of creating a Blob (e.g. Oracle requires oracle.sql.BLOB, so you need to use a LobCreator). Also you would need to specify the UserType for each property:
Quote:
@Lob
@Type(type = "BobUserType")
private Blob contents;


Barry


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 6 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.