title: How to create a generic entity model class that supports generic id including auto generated ids?
body: <p>I have three <em>kinds</em> of primary keys for tables:</p>
  
  <ul>
  <li><code>INT</code> auto generated primary key which use <code>AUTO_INCREMENT</code> capacity from database vendor (MySQL)</li>
  <li><code>CHAR(X)</code> primary key to store a user readable value as key (where X is a number and 50 &lt;= X &lt;= 60)</li>
  <li>Complex primary keys, composed by 2 or 3 fields of the table.</li>
  </ul>
  
  <p>Also, there are some group of fields that may be present (or not):</p>
  
  <ul>
  <li>version, <code>INT</code> field.</li>
  <li>createdBy, <code>VARCHAR(60)</code> field, and lastUpdatedBy, <code>VARCHAR(60)</code> field (there are more fields but these covers a basic example).</li>
  </ul>
  
  <p>Some examples of above:</p>
  
  <ul>
  <li>Table1
  <ul>
  <li>id int primary key auto_increment</li>
  <li>version int</li>
  <li>value char(10)</li>
  <li>createdBy varchar(60)</li>
  <li>lastUpdatedBy varchar(60)</li>
  </ul></li>
  <li>Table2
  <ul>
  <li>id char(60) primary key</li>
  <li>shortDescription varchar(20)</li>
  <li>longDescription varchar(100)</li>
  </ul></li>
  <li>Table3
  <ul>
  <li>field1 int primary key</li>
  <li>field2 int primary key</li>
  <li>amount decimal(10, 5)</li>
  <li>version int</li>
  </ul></li>
  </ul>
  
  <p>With all this in mind, I need to create a generic set of classes that supports these requirements and allows CRUD operations using Hibernate 4.3 and JPA 2.1.</p>
  
  <p>Here's my current model (getters/setters avoided to shorten the code sample):</p>
  
  <pre><code>@MappedSuperclass
  public abstract class BaseEntity&lt;T&gt; implements Serializable {
      @Id
      @GeneratedValue(strategy=GenerationType.IDENTITY)
      protected T id;
  }
  
  @MappedSuperclass
  public abstract class VersionedEntity&lt;T&gt; extends BaseEntity&lt;T&gt; {
      @Version
      protected int version;
  }
  
  @MappedSuperclass
  public abstract class MaintainedEntity&lt;T&gt; extends VersionedEntity&lt;T&gt; {
      @Column
      protected String createdBy;
      @Column
      protected String lastUpdatedBy;
  }
  
  @Entity
  public class Table1 extends MaintainedEntity&lt;Long&gt; {
      @Column
      private String value;
  }
  
  @Entity
  public class Table2 extends BaseEntity&lt;String&gt; {
      @Column
      private String shortDescription;
      @Column
      private String longDescription;
  }
  </code></pre>
  
  <p>I'm currently testing save instances of <code>Table1</code> and <code>Table2</code>. I have the following code:</p>
  
  <pre><code>SessionFactory sf = HibernateUtils.getSessionFactory();
  Session session = sf.getCurrentSession();
  session.beginTransaction();
  
  Table1 newTable1 = new Table1();
  newTable1.setValue("foo");
  session.save(newTable1); //works
  
  Table2 newTable2 = new Table2();
  //here I want to set the ID manually
  newTable2.setId("foo_id");
  newTable2.setShortDescription("short desc");
  newTable2.setLongDescription("long description");
  session.save(newTable2); //fails
  
  session.getTransaction().commit();
  sf.close();
  </code></pre>
  
  <p>It fails when trying to save <code>Table2</code> and I get the following error:</p>
  
  <pre><code>Caused by: java.sql.SQLException: Field 'id' doesn't have a default value
  at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:996)
  at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3887)
  </code></pre>
  
  <p>The error message is obvious because a <code>CHAR(X)</code> field doesn't have a default value and won't have it (AFAIK). I tried changing the generation strategy to <code>GenerationType.AUTO</code> and got the same error message.</p>
  
  <p>How can I remodel these classes in order to support these requirements? Or even better, how could I provide a generation strategy that depends on the key of the entity I'm saving, which could be auto generated or provided by me?</p>
  
  <p>Involved technologies:</p>
  
  <ul>
  <li>Java SDK 8</li>
  <li>Hibernate 4.3.6</li>
  <li>JPA 2.1</li>
  <li>MySQL and Postgres databases</li>
  <li>OS: Windows 7 Professional</li>
  </ul>
  
  <p>Note: the above may (and probably will) change in order to be supported for other implementations of JPA 2.1 like EclipseLink.</p>