This tutorial shows you how to map byte array (byte[]) or Binary Large Object (java.sql.Blob) of Java type to database type using Hibernate ORM framework. Byte array or Blob can be used to store large binary data such as files and images. According to Hibernate Types:

  • A primitive byte[] is mapped to a JDBC VARBINARY.
  • A java.sql.Blob is mapped to a JDBC BLOB.
Let’s understand how to do binary types mapping by exploring the below sample application. We cover both mapping of byte[] and java.sql.Blob with some slightly differences.

 

1. Database Setup

We are going to code an example program that works with a MySQL database. Therefore, execute the following script to create a database called person_db and a table called person:

CREATE DATABASE `person_db`;

CREATE TABLE `person` (
  `person_id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(45) NOT NULL,
  `photo` longblob,
  PRIMARY KEY (`person_id`)
)
 Here, the column photo is declared as of type longblob in MySQL which can hold approximately up to 232 bytes of data (about 4GB).

 

2. Model Class

Model Class with a primitive byte[] type:

Here’s the model class (Person.java) that uses JPA annotations for mapping:

package net.codejava.hibernate;

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


@Entity
@Table(name = "PERSON")
public class Person {
	private int id;
	private String name;
	private byte[] photo;

	public Person() {
	}

	public Person(String name) {
		this.name = name;
	}

	@Id
	@Column(name = "PERSON_ID")
	@GeneratedValue
	public int getId() {
		return id;
	}

	public byte[] getPhoto() {
		return photo;
	}

	public void setPhoto(byte[] photo) {
		this.photo = photo;
	}

	// other getters and setters
}
 

Model Class with a java.sql.Blob type:

Here’s another version of the model class in case the java.sql.Blob type is used:

package net.codejava.hibernate;

import java.sql.Blob;

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


@Entity
@Table(name = "PERSON")
public class Person {
	private int id;
	private String name;
	private Blob photo;

	public Person() {
	}

	public Person(String name) {
		this.name = name;
	}

	@Id
	@Column(name = "PERSON_ID")
	@GeneratedValue
	public int getId() {
		return id;
	}

	public Blob getPhoto() {
		return photo;
	}

	public void setPhoto(Blob photo) {
		this.photo = photo;
	}

	// other getters and setters
}


 

XML Mapping

In both cases, we can use XML mapping as in the following file (Person.hbm.xml):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="net.codejava.hibernate">
	<class name="Person" table="PERSON_PHOTO">
		<id name="id" column="PERSON_ID">
			<generator class="native"/>
		</id>
		<property name="name" column="NAME" />
		<property name="photo" column="PHOTO" />
	</class>
</hibernate-mapping>
 

Hibernate can infer the actual type of the photo attribute by parsing the Person class. In case we want more verbose, add type attribute as following:

  • For primitive byte[] array:
    <property name="photo" column="PHOTO" type="binary" />
  • For java.sql.Blob:
    <property name="photo" column="PHOTO" type="blob" />
It’s better to let Hibernate decides the appropriate mapping type.

 

3. Hibernate Blob Mapping Test Programs

Here is code of a test program for the case in which a primitive byte[] array is used:

package net.codejava.hibernate;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;

/**
 * Test Hibernate binary data mapping with primitive byte[] array.
 * @author www.codejava.net
 *
 */
public class PersonPhotoTest {
	private static ServiceRegistry serviceRegistry;
	private static Session session;
	
	public static void main(String[] args) throws IOException {
		initSession();
		
		String photoFilePathToRead = "e:/Test/Photo/Puppy.jpg";
		savePersonWithPhoto(photoFilePathToRead);
		
		int personId = 1;
		String photoFilePathToSave = "e:/Test/Photo/MyPuppy.jpg";
		readPhotoOfPerson(personId, photoFilePathToSave);
		
		endSession();
	}
	
	private static void savePersonWithPhoto(String photoFilePath) throws IOException {
		Person person = new Person("Tom");
		byte[] photoBytes = readBytesFromFile(photoFilePath);
		person.setPhoto(photoBytes);
		session.save(person);
	}
	
	private static void readPhotoOfPerson(int personId, String photoFilePath) throws IOException {
		Person person = (Person) session.get(Person.class, personId);
		byte[] photoBytes = person.getPhoto();
		saveBytesToFile(photoFilePath, photoBytes);
	}
	
	private static byte[] readBytesFromFile(String filePath) throws IOException {
		File inputFile = new File(filePath);
		FileInputStream inputStream = new FileInputStream(inputFile);
		
		byte[] fileBytes = new byte[(int) inputFile.length()];
		inputStream.read(fileBytes);
		inputStream.close();
		
		return fileBytes;
	}
	
	private static void saveBytesToFile(String filePath, byte[] fileBytes) throws IOException {
		FileOutputStream outputStream = new FileOutputStream(filePath);
		outputStream.write(fileBytes);
		outputStream.close();
	}
	
	
	private static void initSession() {
		Configuration configuration = new Configuration().configure();
		serviceRegistry	= new StandardServiceRegistryBuilder()
				.applySettings(configuration.getProperties()).build();
		
		SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
		
		session = sessionFactory.openSession();
		session.beginTransaction();
	}
	
	private static void endSession() {
		session.getTransaction().commit();
		session.close();
		
		StandardServiceRegistryBuilder.destroy(serviceRegistry);		
	}

}
And the following program’s code is for the case in which a java.sql.Blob is used:

package net.codejava.hibernate;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.Blob;
import java.sql.SQLException;

import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;

/**
 * Test Hibernate binary data mapping with java.sql.Blob type.
 * @author www.codejava.net
 *
 */
public class PersonPhotoTest {
	private static ServiceRegistry serviceRegistry;
	private static Session session;
	
	public static void main(String[] args) throws IOException, SQLException {
		initSession();
		
		String photoFilePathToRead = "e:/Test/Photo/Rex10.jpg";
		savePersonWithPhoto(photoFilePathToRead);
		
		endSession();
		
		initSession();
		
		int personId = 1;
		String photoFilePathToSave = "e:/Test/Photo/MyPuppy.jpg";
		readPhotoOfPerson(personId, photoFilePathToSave);
		
		endSession();
	}
	
	private static void savePersonWithPhoto(String photoFilePath) throws IOException, SQLException {
		Person person = new Person("Peter");
		File file = new File(photoFilePath);
		FileInputStream inputStream = new FileInputStream(file);
		Blob blob = Hibernate.getLobCreator(session)
							.createBlob(inputStream, file.length());
		person.setPhoto(blob);
		session.save(person);
		blob.free();
	}
	
	private static void readPhotoOfPerson(int personId, String photoFilePath) throws IOException, SQLException {
		Person person = (Person) session.get(Person.class, personId);
		Blob blob = person.getPhoto();
		byte[] blobBytes = blob.getBytes(1, (int) blob.length());
		saveBytesToFile(photoFilePath, blobBytes);
		blob.free();
	}
	
	private static void saveBytesToFile(String filePath, byte[] fileBytes) throws IOException {
		FileOutputStream outputStream = new FileOutputStream(filePath);
		outputStream.write(fileBytes);
		outputStream.close();
	}
	
	private static void initSession() {
		Configuration configuration = new Configuration().configure();
		serviceRegistry	= new StandardServiceRegistryBuilder()
				.applySettings(configuration.getProperties()).build();
		
		SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
		
		session = sessionFactory.openSession();
		session.beginTransaction();
	}
	
	private static void endSession() {
		session.getTransaction().commit();
		session.close();
		
		StandardServiceRegistryBuilder.destroy(serviceRegistry);		
	}

}
Both of these test programs insert a person with a photo (specified by its file path) to the database, and then they read the person back, extract the photo data and save as an image file. For your convenience, download both projects in the attachments section below.

 

Other Hibernate Tutorials:


About the Author:

is certified Java programmer (SCJP and SCWCD). He began programming with Java back in the days of Java 1.4 and has been passionate about it ever since. You can connect with him on Facebook and watch his Java videos on YouTube.



Attachments:
Download this file (HibernateBinaryDataExample.zip)HibernateBinaryDataExample.zip[Sample project for mapping primitive byte array]15 kB
Download this file (HibernateBlobExample.zip)HibernateBlobExample.zip[Sample project for mapping Blob type]14 kB

Add comment

   


Comments 

#8Nam2019-12-25 22:51
Quoting Dinesh:
Hi,
which is the best way ,if the size of file is large.2+ GB approx.

Use longblob type which supports up to 4GB.
Quote
#7Dinesh2019-12-20 06:49
Hi,
which is the best way ,if the size of file is large.2+ GB approx.
Quote
#6Ravi2017-03-19 01:42
We want controller code. Here you have written test cases. Test cases we dont want. we want actual implementation right from controller, service, persistence and dao layers.
Quote
#5Javier Monge2015-12-31 11:54
About your post from MARCH 23, 2011
JAXB, Web Services, and Binary Data

In my case Im working in an webservice app where I have a field "logo" in a table client. Where I need to store the client's logo image. I used Netbenas MySQL and Hibernate. And I generate POJOS and hbm.xml with the Netbeans wizard.

But Jaxb gives me this error message:

Dec 31, 2015 11:06:10 AM com.sun.xml.bind.v2.runtime.reflect.opt.Injector inject
WARNING: duplicate class definition bug occured? Please report this : com/model/pojos/Organizacion$JaxbAccessorM_getLogo_setLogo_[B
java.lang.ClassFormatError: Illegal class name
where logo Hibernate has mapped it like this:

-In the class:
private byte[] logo;
setter and getter

-In the hbm file:



Please Blaise Help!
Quote
#4Binh Nguyen Thanh2015-10-15 01:38
Thanks, nice post
Quote