I’m migrating a legacy system over to use Hibernate 3. It currently generates its own identifiers. To keep with what the system currently does before I try and move it over to something a little better, how would I go about specifying (using annotations) my own class that will return the custom generated identifiers when an insert occurs?
Something like:
@Id
@CustomIdGenerator(Foo.class) // obviously this is not a real annotation
public String getId() { ... }
Where the Foo class has one method that generates the identifier.
Currently I’m just calling the setId(String id) method manually but was hoping for a better way to deal with this situation.
I don’t think there is out-of-box support for generating custom Ids using custom annotations using pure JPA-2 API. But if you want to use provider specific API, then the job is pretty simple. Sample Example
To be provider independent try any of following tricks….
IdGeneratorHolder
General IdGenerator interface
Specific IdGenerator – Product Id Generator
Now set the generated id either in no-arg constructor OR in @PrePersist method.
Product.java
In above example all the ids are of the same type i.e.
java.lang.String. If the persistent entities have ids of different types…..IdGenerator.java
CustomId.java
Item.java
You can also use your custom annotation…
CustomIdGenerator.java
IdStrategy.java
IdGeneratorHolder.java
One more thing…. If we set id in @PrePersist method, the equals() method cannot rely on id field (i.e. surrogate key), we have to use business/natural key to implement equals() method. But if we set id field to some unique value (uuid or “app-uid” unique within application) in no-arg constructor, it helps us to implement the equals() method.
If we or someone else call (intentionally or by mistake) the @PrePersist annotated method more than one times, the “unique id will be changed!!!” So setting id in no-arg constructor is preferable. OR to address this issue put a not null check…
UPDATE
Yeah you are right, I missed that part. 🙁 Actually, I wanted to tell you that:- in my application every Entity object is associated with an Organization Entity; so I’ve created an abstract super class with two constructors, and every Entity (except Organization) extends this class.
The no-arg constructor is for JPA provider, we never invoke no-arg constructor, but the other organization based constructor. As you can see. id is assigned in Organization based constructor. (I really missed this point while writing the answer, sorry for that).
See if you can implement this or similar strategy in your application.
Ideally, JPA provider should invoke @PrePersist methods (one declared in class and also all the other methods that are declared in super-classes) before persisting the entity object. Can’t tell you what is wrong, unless you show some code and console.