\

Overriding the Default JPA Sequence

I had a situation where certain IDs needed to be skipped when inserting records. The details of my situation are not important; the general approach has more applications.

In the majority of cases, the default method for generating a sequence in JPA is the best method. When you have a case where you need to generate a custom sequence, the stock JPA approach will not do right out of the box. Imagine a contrived case where you have to generate only even sequence numbers, or skip a range of sequence numbers, to visualize the reason to insert your own method to create a sequence.

Using the stock approach, the Java code would look like this (leaving out a lot of detail):

package com.mycompany.package;

...

@Entity
@Table(name = "MyTable")
// blah, blah, blah...
public class MyClass
{
	@Id
	@GeneratedValue(strategy = "GenerationType.AUTO", generator = "id_gen")
	@SequenceGenerator(name = "id_gen", sequenceName = "MY_SEQ")
	private int myId;

	// lots more code...
}

				

Which is all fine and dandy, but then the situation comes up that you have to have a different sequence generation method. Thankfully, JPA provides a way to override the default behavior and insert your own approach. The trick is to substitute the @SequenceGenerator annotation with the @GenericGenerator annotation.

Change the above code to look like this:

package com.mycompany.package;

...

@Entity
@Table(name = "MyTable")
// blah, blah, blah...
public class MyClass
{
	@Id
	@GeneratedValue(strategy = "GenerationType.AUTO", generator = "id_gen")
	@GenericGenerator(name = "id_gen", 
		strategy = "com.mycompany.package.MyGenerator")
	private int myId;

	// lots more code...
}
				

The @GenericGenerator annotation along with the strategy tag is the hook to get your code into the mix and generate a sequence in the desired form. That's part of the solution, but you have to supply the class designated by the strategy tag. Note that it is a fully qualified name to your class that will implement the code to provide your own sequence.

The class to provide the custom sequence looks like this:

package  com.mycompany.package;

import java.io.Serializable;
import org.hibernate.id.SequenceGenerator;

public class MyGenerator
	extends SequenceGenerator
{
	@Override
	public Serializable generate(SessionImplementor session, Object obj)
	{
		// generate your custom sequence here
		return ... // In this example, return an int
	}
}
				

Note that the SessionImplementor has a public method to retrieve the current Connection by invoking session.connection() that you can use to issue SQL statements if necessary. That is the form of all the code necessary to implement your own custom sequence.