First, I cosidered possibility of different configuring of primary key generation straegy for different platforms, using master entity superclass and confguring with XML descriptors (actually combining XML descriptors and annotations).
The, I tried to find some solution that enables us to somehow make EclipseLink use some alternative method of primary key generation. Fortunately, it did not take long.
On EclipseLink wiki there is an example of custom sequencing using UUID. Now, UUID generation is something we came across while using Hibernate, who has some issues using HashMaps and identifying objects, so generating UUID used in isEqual methods for objects is very recommender. Using UUID as primary key sounded interesting, but, frankly, I did not feel like modifying database schema...
So I wondered, why not making my own, concurrency safe version of table sequencing? After all, it is very nice solution, takes my mind of thinking whether I use MS, Oracle or whatever DB and I dont bother worrying over whether identity columns will do just as good job as Oracle sequences...
Let's look into customizing sequencing.
You can extend Eclipselink classes Sequence and StandardSequence. You also have to implenent SessionCustomizer interface.
public class UUIDSequence extends Sequence implements SessionCustomizer{
Now, look into the class. For us important methods are
public Object getGeneratedValue(Accessor accessor,and
AbstractSession writeSession, String seqName) {
return UUID.randomUUID().toString().toUpperCase();
}
public void customize(Session session) throws Exception {getGeneratedValue method, well, returns the generated sequence value in whatever way we want. In the example UUID is used, so simply radnom generated uuid value is returned from the method.
UUIDSequence sequence = new UUIDSequence("system-uuid");
session.getLogin().addSequence(sequence);
}
But, how do we make Eclipselink use our sequence generator? customize method is used for this. As you can see, a new instance of our sequence class is created with our specific name given to constructor, and our sequence is added to session. To tell eclipselink that we are using our custom generator we add a property in the persistence unit
name="eclipselink.session.customizer"
value="eclipselink.example.UUIDSequence"/>
And that is it. I'm not really sure how this works, but persistence unit sees that it has customizable class, method customize is called and our sequence is set. When you want to use sequence in your JPA entities, you siply specify name you passed to constructor
@Id
@GeneratedValue(generator="system-uuid"/>
@Column(name="PROJ_ID")
private int id;
In the next post we will make similar class which will use our own table generated sequence. And yes, it is quite simple :)
Wow, not bad post after 10 days of flu...