16

I need to convert iTextPDF Document file to byte[] after it's created in memory. I have already tested that I've no problem with creating PDF properly. The problem is how to convert it to byte array to store in DB.

Here's my code:

Document generatedDocument = reportService.generateRequestForm(scdUser, jsonObject, 0, null);
reportService.generateRequestForm(scdUser, jsonObject, 0, null);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfWriter pdfWriter = PdfWriter.getInstance(generatedDocument, baos);
generatedDocument.open();
document.setDocument(baos.toByteArray()); // stores as blob

I got value of null at database blob column.

Here's my Document domain object:

Document Domain Object

@Entity
@Table(name = "document")
public class Document implements java.io.Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "document_id", nullable = false)
    private int documentId;
    @Column(name = "document_name", nullable = false, length = 65535)
    private String documentName;
    @Column(name = "document_type", nullable = false)
    private int documentType;
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "upload_date", nullable = false, length = 19)
    private Date uploadDate = new Date();
    @Column(name = "document", nullable = false)
    private byte[] document;    // BLOB COLUMN
    @Column(name = "document_size", nullable = false)
    private long documentSize;
    @Column(name = "title", nullable = true, insertable = true, updatable = true, length = 65535, precision = 0)
    private String title;
    @Column(name = "tag", nullable = true, insertable = true, updatable = true, length = 65535, precision = 0)
    private String tag;
    @Column(name = "description", nullable = true, insertable = true, updatable = true, length = 65535, precision = 0)
    private String description;
    @Column(name = "shared", nullable = false, insertable = true, updatable = true, length = 1, precision = 0)
    private boolean shared = false;
    @Column(name = "status", nullable = false)
    private int status = DocumentStatus.READY.getStatus();


    public int getDocumentId() {
        return this.documentId;
    }

    public void setDocumentId(int documentId) {
        this.documentId = documentId;
    }

    public String getDocumentName() {
        return this.documentName;
    }

    public void setDocumentName(String documentName) {
        this.documentName = documentName;
    }

    public int getDocumentType() {
        return this.documentType;
    }

    public void setDocumentType(int documentType) {
        this.documentType = documentType;
    }

    public Date getUploadDate() {
        return this.uploadDate;
    }

    public void setUploadDate(Date uploadDate) {
        this.uploadDate = uploadDate;
    }

    public byte[] getDocument() {
        return this.document;
    }

    public void setDocument(byte[] document) {
        this.document = document;
    }

    public long getDocumentSize() {
        return this.documentSize;
    }

    public void setDocumentSize(long documentSize) {
        this.documentSize = documentSize;
    }

    public String getTag() {
        return tag;
    }

    public void setTag(String tag) {
        this.tag = tag;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public boolean getShared() {
        return shared;
    }

    public void setShared(boolean shared) {
        this.shared = shared;
    }


    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }


}
talha06
  • 6,206
  • 21
  • 92
  • 147
  • look at the question, then look at your last sentence.. – Eugene Aug 10 '12 at 07:40
  • looks like the document will not be generated at first in cause of that database error. – Marvin Emil Brach Aug 10 '12 at 07:51
  • @Eugene it's same; I'm persisting byte[] to blob column. – talha06 Aug 10 '12 at 08:03
  • @MarvinEmilBrach yeah the document is generated at runtime. – talha06 Aug 10 '12 at 08:04
  • @talha06 I am still confused, can you confirm that my understanding is right? You create a PDF document dynamically at runtime, then store it in the DB as byte array? If true, then what is your question exactly? You get a null value when inserting in the DB? – Eugene Aug 10 '12 at 08:32
  • @Eugene yeah exactly I need to convert iTextPDF Document to byte[] properly. As I mentioned in code snippet above, the variable **`generatedDocument`** holds PDF document that is just generated. Then I need to convert it to byte array to persist db. Thanks for your care. – talha06 Aug 10 '12 at 08:36
  • @talha06 I will try this myself in about 1 hour and get back to you – Eugene Aug 10 '12 at 08:36
  • 1
    are you sure that the generation was successful? seems like the outputstream doesn't receive any data at all... I'm really curious what Eugene will tell in an our :) – Marvin Emil Brach Aug 10 '12 at 08:44
  • @MarvinEmilBrach yeah generation is successful, I tested it with sending generated PDF to client. Thanks again Eugene for your care & time.. – talha06 Aug 10 '12 at 09:16
  • @MarvinEmilBrach true :) was doing three things at once.. – Eugene Aug 10 '12 at 09:37
  • @Eugene I create PDF file just for testing. Normally I'll create it at runtime, then I'll persist it to DB. I have already post code snippet that is associated with it.. – talha06 Aug 10 '12 at 11:02

3 Answers3

31

I had a similar problem... I'd create the Document and inside the class where I created it, I could save it to File, and it worked great. However, when I tried to return it as a Stream I would get a null value.

The problem was that once the Document was closed (document.close()), it would close the Stream also.

The work-around was to create a ByteArrayOutputStream when I created the Document and have the PdfWriter output to it. I could then do whatever I wanted with the PDF bytes... in my case I converted them to a StreamedContent to send to the user.

Create a variable to hold the bytes:

  private ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

Have the PdfWriter output the data to the byte[] as it creates the document:

  Document document = new Document(PageSize.LETTER, 0.75F, 0.75F, 0.75F, 0.75F);
  PdfWriter.getInstance(document, byteArrayOutputStream);  // Do this BEFORE document.open()

  document.open();
  createPDF(document);  // Whatever function that you use to create your PDF
  document.close();

Once you're done generating the PDF, just get the Bytes and do with them as you will.

  byte[] pdfBytes = byteArrayOutputStream.toByteArray();

I don't know what your reportService class looks like, but this may be a good place to put it.

Hope this helps.

AceFunk
  • 684
  • 1
  • 8
  • 14
9

Just updating the answer for the iText 7 version.

private static byte[] createPDF() {
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    PdfWriter writer = new PdfWriter(byteArrayOutputStream);
    PdfDocument pdfDocument = new PdfDocument(writer);
    Document document = new Document(pdfDocument);

    //Write the file content

    document.close();
    return byteArrayOutputStream.toByteArray();
}
2

From the comments it appears that it has nothing to do the way PDF is generated at runtime, but instead the way it is stored in the DB. You need to provide that code also.

Here is what I have actually (my test):

The Holder:

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;



@Entity
public class PDFHolder implements Serializable {

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private long id;

@Column(columnDefinition = "LONGBLOB")
private byte[] documentPDF;

public byte[] getDocumentPDF() {
    return documentPDF;
}

public void setDocumentPDF(byte[] documentPDF) {
    this.documentPDF = documentPDF;
}

public long getId() {
    return id;
}

public void setId(long id) {
    this.id = id;
}
}

The Repository, which does the save:

@Repository
public interface PDFHolderRepository extends JpaRepository<PDFHolder, Long> {}

And the actual insert:

private void generateDatabaseRows() {

    try{
        String urlPDF = "http://cetatenie.just.ro/LinkClick.aspx?fileticket=K13DZkoIE2o%3d&tabid=57&mid=593";
        URL url = new URL(urlPDF);

        ByteBuffer byteBufferResponse = this.getAsByteArray(url.openConnection());
        byte [] responseArray = byteBufferResponse.array();
        System.out.println("Size of the PDF : " + responseArray.length);

        // Save it to DB
        PDFHolder pdfHolder = new PDFHolder();
        pdfHolder.setDocumentPDF(responseArray);

        pdfHolderRepository.save(pdfHolder);

    } catch(Exception e){
        e.printStackTrace();
    }
}


private ByteBuffer getAsByteArray(final URLConnection urlConnection) throws IOException {
    final ByteArrayOutputStream tmpOut = new ByteArrayOutputStream();
    final InputStream inputStream = urlConnection.getInputStream();
    final byte[] buf = new byte[1024];
    int len;
    while (true) {
        len = inputStream.read(buf);
        if (len == -1) {
            break;
        }
        tmpOut.write(buf, 0, len);
    }
    tmpOut.close();
    return ByteBuffer.wrap(tmpOut.toByteArray(), 0, tmpOut.size());
}

Of course I have an @Autowired repository in this class:

@Autowired
PDFHolderRepository pdfHolderRepository;

MySQL stores the byte array

Eugene
  • 117,005
  • 15
  • 201
  • 306
  • I get null when I retrieve document from DB. (Also I see null when at GUI - MySQL Workbench) I persist PDF to DB using Hibernate. When I debug the code, I see the document is generated successfully. So I want to learn how can I successfully convert iTextPDF Document to byte array in order to persist properly. – talha06 Aug 10 '12 at 11:18
  • @talha06 see my updated answer - I've tested this and it works. Also you might want to have a look at this: http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work – Eugene Aug 10 '12 at 12:38