views:

78

answers:

2

I am having some trouble properly retrieving blob data from my database using java in my JSF 2.0 application. The first problem I am having is on my getter method for the Blob named "file" I get an error saying that "Basic attributes can only be of the following types..." basically saying that I can not return a Blob object. My code looks like what is below. Even with the error my code compiles. I have created a test method (the last bit of code below) and tried to test but it gives me runtime errors.

Controller Bean

import java.sql.Blob;

@Entity
@Table(named = "files")
@NamedQueries( {
    @NamedQuery(name = "MyBlob.getBlob",
    query = from MyBlob WHERE fileId =: fileId")
})
public class MyBlob implements Serializable {

     private Integer fileId;
     private Blob file;
     ...

     public Integer getFileId() {
         return fileId;
     }

     public void setFileId() {
         this.fileId = fileId;
     }

     public Blob getFile() {
         return file;
     }

     public void setFile(Blob file) {
         this.file = file;
     }

     ....

}

BlobDao.java File method to get blob

public MyBlob getBlob(Integer fileId) throws HibernateException {
    Session session = getSessionFactory().openSession();
    try { 
      MyBlob blob = (MyBlob)session.getNamedQuery("MyBlob.getBlob").setInteger("fileId", fileId).uniqueResult();
      return blob;
    } catch(HibernateException e) {
         throw new HibernateException(e);
    } finally {
        session.close();
    }
}

TestDao.java

@Test
public void testBlob() {

    MyBlob test = blobdao.getBlob(1);  // 1 is a fileId that exists in the DB with a blob image file.
    Blob blob = test.getFile();
    try {
        System.out.println(blob.length));   //this prints a number but I dont think the right one. 
        if(blob.length > 0 ) {
             System.out.println(blob.toString() ); //errors out here
        }
    } catch(SQLException e) {
          return System.out.println("Failed");
    }
}

I am not sure that I am doing this right at all. Any help would be great. Thanks.

A: 

I am guessing the Blob object is your Entity. It might help if you print that as well.

Make sure your Blob returns byte[]

@Basic(fetch = FetchType.LAZY)
@Lob             
@Column(length = 104857600, nullable = false)
private byte[] data;
Shervin
I don't understand when you say make sure your Blob returns byte[]. Can you possibly elaborate on that? Thanks.
NewTOJSF
+1  A: 

on my getter method for the Blob named "file" I get an error saying that "Basic attributes can only be of the following types..." basically saying that I can not return a Blob object.

Indeed, a java.sql.Blob is not a persistent field or property that can be mapped by Hibernate/JPA. The JPA specification puts is like this:

2.1.1 Persistent Fields and Properties

...

The persistent fields or properties of an entity may be of the following types: Java primitive types; java.lang.String; other Java serializable types (including wrappers of the primitive types, java.math.BigInteger, java.math.BigDecimal, java.util.Date, java.util.Calendar, java.sql.Date, java.sql.Time, java.sql.Timestamp, user-defined serializable types, byte[], Byte[], char[], and Character[]); enums; entity types and/or collections of entity types; and embeddable classes (see section 2.1.5).

You should probably use the Lob annotation and change your attribute type. From the specification:

9.1.19 Lob Annotation

A Lob annotation specifies that a persistent property or field should be persisted as a large object to a database-supported large object type. Portable applications should use the Lob annotation when mapping to a database Lob type. The Lob annotation may be used in conjunction with the Basic annotation. A Lob may be either a binary or character type. The Lob type is inferred from the type of the persistent field or property, and except for string and character-based types defaults to Blob.

...

Example 1:

@Lob @Basic(fetch=EAGER)
@Column(name="REPORT")
protected String report;

Example 2:

@Lob @Basic(fetch=LAZY)
@Column(name="EMP_PIC", columnDefinition="BLOB NOT NULL")
protected byte[] pic;

References

  • JPA 1.0 specification
    • Section 2.1.1 "Persistent Fields and Properties"
    • Section 9.1.19 "Lob Annotation"

Well my exact requirements are to retrieve the Blob from the database either as a Blob or a byte[], whatever works, and then somehow convert that into a valid InputStream object.

What about ByteArrayInputStream(byte[])?

Pascal Thivent
So if I did this how would I retrieve the data? I need to get the data as a Blob object so I can call the getInputStream method on it. if I change it to a byte[] I can not call this method anymore.
NewTOJSF
@NewTOJSF `So if I did this how would I retrieve the data?` By using the getter? `I need to get the data as a Blob object so I can call the getInputStream method on it.` And why do you need this? Where did you mention that in your question? What are your **exact** requirements?
Pascal Thivent
Well my exact requiredments are to retrieve the Blob from the database either as a Blob or a byte[], whatever works, and then somehow convert that into a valid InputStream object. I am using primefaces so I am trying to use their Dyna Image feature which will serve the images for me. In order to get the InputStream object I am under the assumption I need to call the getBinaryStream() method on the blob object. I have searched how to convert a byte[] array to an InputStream but I have not found anything that looks promising. Again I am very new to this so I am sorry for any confusion.
NewTOJSF
@NewTOJSF: No problem, it's just that readers can't guess what you're trying to achieve if you don't tell them :) I'll update my answer.
Pascal Thivent
Thank you, sorry for the confusion.
NewTOJSF
Thanks so much this worked.
NewTOJSF