Is this object to table mapping possible?

I want to be able to store any Serializable object in a database against a unique ID. So I created a Java object that has a constructor taking those 2 values. The constructor converts the Serializable into bytes and then splits these into chunks of 4096 characters. These bytes are stored in a List in the object. So the object looks like:

public class MyObj {
    private String id;
    private List<byte[]> serData;

    public MyObj(String id, Serializable value) {
        this.id = id;
        this.serData = convertSerializableToByteArray(value);
    }
}

I want to store this into a database table but I want the database table to have 3 columns:

  • ID
  • line_no
  • serialized_data (4096 bytes max)

The primary key of the table should be the ID and line_no combined. As an example, to store an object of ID ‘foo’ to a 10,000 character string, I would expect the database to have the following entries:

ID   line_no   serialized_data
--   -------   ----------------
foo  0         <first 4096 bytes>           
foo  1         <4096  - 8192 bytes>
foo  2         <remaining 808 bytes>

I am having a lot of trouble creating either an hbm file for this or using Annotations. Can anyone help me out? Is this approach even possible? This is the hbm file I have so far (I am aware that this doesn’t work):

<?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>
    <class name="com.foo.MyObject" table="settings_ser">

    <list name="serializedData" cascade="all">
            <key column="id" />
            <index column="line_number"/>
            <element type="binary" column="ser_data" length="4096" />
        </list>
    </class>
</hibernate-mapping>

Thanks

The best way to serialize this object type is to use JSON. Check out the hibernate-types project for more details.

Let us assume that the Java Object and the database table must remain exactly as they are (they are part of a much bigger project). Can a hibernate mapping be created which would perform the mapping I want ?

Yes, of course it can. Just make sure that the entity id is a composite key of that id column and line number, if you want to use a child entity.

Or, you can use an embeddable collection too. That’s going to be easier.

I fear that I am not explaining myself properly. As you can see from my example there is no line-number in the Java code. I simply have 2 Java objects and wish to map these to 3 columns, using the index of the List as one of the columns.

The mappings I have tried do not work - the example I provided isn’t accepted and I don’t know how to express what I want in either an hbm form or Annotation form. That is what I am looking for.

As long as you ttansform the incoming data to match the database table structure, it will work just fine.

The Hibernate User Guide provides plenty of examples of hpw to map a collection of embeddable. Use that as a reference.

I abandoned using an hbm file and added Annotations to the class. I added the annotation @ ElementCollection to the List and got it to refer to the same table as the class (is this recommended???) :

@Table(name="myobj_ser")
public class MyObj  {
@Id
@Column(name="id", nullable=false)
private String id;

@ElementCollection
@CollectionTable(name="myobj_ser")
private List<byte[]> serData = new ArrayList<>();

This resulted in a table with 3 columns:

  • id
  • MyObj_id
  • serData

Can you advise as to how I can annotate to get the correct columns?

Yes, that’s a good idea.

Can you advise as to how I can annotate to get the correct columns?

The entity should look like this:

Can you advise as to how I can annotate to get the correct columns?

Can you advise as to how I can annotate to get the correct columns?

@Entity
@Table(name="myobj_ser")
public class MyObj  {
	@Id
	@Column(name="id")
	private String id;

	@ElementCollection
	@CollectionTable(name="myobj_ser")
	private List<SerData> serData = new ArrayList<>();
}

And SerData:

@Embeddable
public class SerData  {
	@Id
	@Column(name="ID")
	private String id;
	
	@Column(name="line_no")
	private Integer lineNumber;

	@Column(name="serialized_data")
	private byte[] serializedData;
}

It sort-of worked. Your example created a table with 4 columns which were:

  • id
  • myobj_id
  • line_no
  • serialized_data

I tried to work round this and put a joinColumns of "@ JoinColumn(name = “id”)) ". This meant that only 3 columns were created. However when my application started it threw a Foreign Key exception (although it still created the table). I was unable to work around this.

Ultimately I have abandoned my initial approach. The Object “MyObj” has no annotations and simply wrappers the “SerData” object, as you supplied. This is then persisted to the database and I have to ensure that updates, deletions, etc. work on the appropriate object.

Thanks for your help.

You need the myobj_id FK column, as otherwise, the JOIN will not work between the parent and child tables.