How to address Schema Migration for Dummies

  1. Be very clear in what your PersistentEntity (an entity that directly corresponds to a db table) is and separate it from your Business related entities that may or may not have one to one relationship with the tables. Ideally, Business Entities should be defined on a need basis, however PersistentEntities should be defined as soon as your schema / data model design is ready for the first iteration of development.
  2. Once you create entities, you will annotate these entities, and I haved shared an example of such entities. These annotations should follow JPA annotations standard and not Hibernate annotations, because that way you will avoid vendor lockin, and be following a standard. JPA is a standard developed by Java Community and has JSR (Java Specification Request) which is implemented by Hibernate, J2EE, TopLink or any other middle-tier OR implementation.
  3. Add Hibernate Synchronizer plugin to Eclipse (you can also use the schem exporter command line utility, which you will find docs on RedHat Hibernate website). I highly recommend using Eclipse plugin because it makes the process visual and easy to follow.
  4. Use Hibernate Sychronizer to Export the Schema based on the PersistentEntities, this will require you to configure your persistence.xml file, which is usually placed in the class path, inside a jar or directly under the class path  i can share some examples for demonstration.
  5. The schema exporter works by pointing to your data base instance and generating all the tables that you have defined as PersistentEntities, taking care of all the constraint definitions, indexes etc. Will share a sample of that too.
  6. What you now have is the v1 of your db. This is ready to be used in your application by defining DAO or Data Access Layer, which abstracts out the operations performed on PersistentEntities. Note: As long as you have a good abstraction around DAO, your persistent entities will mostly remain unchanged until you decide to add more columns or tables to your schema.
  7. Now for v2, if you are adding more tables and columns, you will start with modifying the PersistentEntities directly and adding news ones where required. Reminder: All the entity relationships are also defined using Annotations, as you already are aware, and hence adding new tables only requires some new relationship annotations to be added to exisinting entities if they are going to have a new relationship with the newly added entity.
  8. After you are happy with your v2 db schema design and PersistentEntities created thereof, you will point to your Development DB server and generated the new schema based db instance.
  9. In this step you will need to have a tool that can compare db instance v1 with db instance v2 and generate a migration script for the DDL part. For data that needs to be migrated, you will have to write your own migration scripts. Note: If you are using MySQL then you are lucky because MySQL Workbench has great tools for schema comparison and migration DDL auto generation.

PersistentEntity

package com.rishik.hibernate.entity;

import java.io.Serializable;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

import org.hibernate.annotations.Generated;
import org.hibernate.annotations.GenerationTime;

/**
* This is an object that contains data related to the file table.
*
*
* table="file"
*/

@Entity
@Table(name="file")
@SuppressWarnings("serial")
public class FileEntity implements Serializable {

public static String REF = "FileEntity";
public static String PROP_TYPE = "type";
public static String PROP_ID = "id";
public static String PROP_USER = "user";
public static String PROP_CONTENT = "content";
public static String PROP_WORKSPACE = "workspace";
public static String PROP_CREATED_DATE = "createdDate";
public static String PROP_LAST_EDITED_DATE = "lastModifiedDate";
public static String PROP_LAST_EDITED_BY = "lastModifiedBy";

// constructors
public FileEntity () {
initialize();
}

/**
* Constructor for primary key
*/
public FileEntity (java.lang.Long id) {
this.setId(id);
initialize();
}

/**
* Constructor for required fields
*/
public FileEntity (
java.lang.Long id,
java.lang.Long userId,
java.lang.Long workspaceId) {

this.setId(id);
this.setUser(user);
this.setWorkspace(workspace);
initialize();
}

protected void initialize () {}

private int hashCode = Integer.MIN_VALUE;

// primary key
private java.lang.Long id = 0L;

// fields
private UserEntity user;
private WorkspaceEntity workspace;
private java.lang.String content;
private java.lang.String type;
private java.util.Date createdDate;
private java.util.Date lastModifiedDate;
private UserEntity lastModifiedBy;

/**
* Return the unique identifier of this class
* @hibernate.id
* generator-class="native"
* column="file_id"
*/
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Generated(GenerationTime.INSERT)
@Column(name="file_id",insertable=true,updatable=false)
public java.lang.Long getId () {
return id;
}

/**
* Set the unique identifier of this class
* @param id the new ID
*/
public void setId (java.lang.Long id) {
this.id = id;
this.hashCode = Integer.MIN_VALUE;
}

/**
* Return the value associated with the column: user_id
*/
@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name="user_id")
public UserEntity getUser () {
return user;
}

/**
* Set the value related to the column: user_id
* @param user the user_id value
*/
public void setUser (UserEntity user) {
this.user = user;
}

/**
* @return
*/
@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name="workspace_id")
public WorkspaceEntity getWorkspace() {
return workspace;
}

/**
* @param workspace
*/
public void setWorkspace(WorkspaceEntity workspace) {
this.workspace = workspace;
}

/**
* Return the value associated with the column: content
*/
@Column(name="content")
@Lob
public java.lang.String getContent () {
return content;
}

/**
* Set the value related to the column: content
* @param content the content value
*/
public void setContent (java.lang.String content) {
this.content = content;
}

/**
* Return the value associated with the column: type
*/
@Column(name="type")
public java.lang.String getType () {
return type;
}

/**
* Set the value related to the column: type
* @param type the type value
*/
public void setType (java.lang.String type) {
this.type = type;
}

/**
* @return the createdDate
*/
@Column(name="created_date")
public java.util.Date getCreatedDate() {
return createdDate;
}

/**
* @param createdDate the createdDate to set
*/
public void setCreatedDate(java.util.Date createdDate) {
this.createdDate = createdDate;
}

/**
* @return the lastModifiedDate
*/
@Column(name="last_modified_date")
public java.util.Date getLastModifiedDate() {
return lastModifiedDate;
}

/**
* @param lastModifiedDate the lastModifiedDate to set
*/
public void setLastModifiedDate(java.util.Date lastModifiedDate) {
this.lastModifiedDate = lastModifiedDate;
}

/**
* @return the lastModifiedBy
*/
@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name="last_modified_by")
public UserEntity getLastModifiedBy() {
return lastModifiedBy;
}

/**
* @param lastModifiedBy the lastModifiedBy to set
*/
public void setLastModifiedBy(UserEntity lastModifiedBy) {
this.lastModifiedBy = lastModifiedBy;
}

public boolean equals (Object obj) {
if (null == obj) return false;
if (!(obj instanceof FileEntity)) return false;
else {
FileEntity pOFile = (FileEntity) obj;
if (null == this.getId() || null == pOFile.getId()) return false;
else return (this.getId().equals(pOFile.getId()));
}
}

public int hashCode () {
if (Integer.MIN_VALUE == this.hashCode) {
if (null == this.getId()) return super.hashCode();
else {
String hashStr = this.getClass().getName() + ":" + this.getId().hashCode();
this.hashCode = hashStr.hashCode();
}
}
return this.hashCode;
}

public String toString () {
return super.toString();
}

}

Calendar getDisplayName() JDK 6.0 vs JDK 1.5.0

If you have somehow used jdk6.0 while developing your application that uses Calendar API of java.util.Calendar, and have used getDisplayName method to extract the display names for fields of the calendar, specific to your desired style and locale, and then had to compile your application with jdk1.5.0 only to realize that compiler spits swear words at you…Here is quick fix for you!

This is what you did in jdk6.0:

//get your application locale
Locale userLocale = getContext().getLocale();

//define a calendar
Calendar calendarInstance = Calendar.getInstance();

//Extract the month name in SHORT format (viz. "Jan","Feb" etc.) for the context locale.
calendarInstance.getDisplayName(calendarInstance.get(Calendar.MONTH),Calendar.SHORT,userLocale);

Here is what you can do to achieve the same getDisplayName functionality in jdk 5.0:

//import the following class
import java.text.DateFormatSymbols;

//declare variable.
DateFormatSymbols dateFormatSymbols = new DateFormatSymbols();

//Get the short names for months in a Calendar
String[] months = dateFormatSymbols.getShortMonths();

//Use the month field of Calendar to fetch the short name of month for cell label.
months[calendarInstance.get(Calendar.MONTH)];

Once you acquire the SHORT name for the field, you can use it for your labels, or column headers etc. based on where you require it.

Ideally, you shouldn’t have to fall back on the previous version of jdk, yet sometimes the project requirements can’t be altered even for better things in life.

Hope this tip helps!

Hello World – I am here!

There can’t be a more apt way of entering the Java world than “Hello World!”. Those magical words can transform about the most ordinary lives. At least for me they did.

I am relatively an infant in the Java world, but I am a precocious infant so I will say whatever I think is right and you have only two options, you agree with me or you die.

Java technology stack has grown from strength to strength in last decade and today it has reached a level of maturity that inspires confidence that the world could indeed depend on software. That intangible, quirky stuff some nerds keep punching in on their keyboards and that can do some wonderful stuff only we don’t know how it does that.

My ride through the software world allowed me to witness the prehistoric programmig languages like Fortran-77 and Pascal but as I moved ahead it has only gotten better with time.

In the life of a programmer, the real transformation occurs when one moves from straightforward procedural languages to the world of Object Oriented Programming, which kinda adds a realistic paradigm to the world of software. The complexity of objects in the real world and their relationships are translated verbatim in the OOPS world and that is when things start getting better. It’s like a boy turning into a man. Both the programmer and his code enter a new level of maturity and capability.

So, who am I? My name Rishik, and I would like to think it is a unique name, however it is no more. I have worked as a programmer for last 6 years now and worked on different sets of technologies. Currently, I am having an affair with Java Technology Stack. And I can’t express how rewarding this relationship has been right from its inception. I work with Pramati Technologies, and I have recently added another role to my portfolio, which is “Relationship Manager”. Apart from being a developer I am now into business development for half of my time. And I started this blog to bring out the lighter side of Java.

Let’s see what comes first, the chicken or the egg!