When my Java application was running on Spring Boot 2.6.2, the entities for which Export/Import features applied were using the following custom id generator:
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.IdentityGenerator;
import java.io.Serializable;
public class CustomIdGenerator extends IdentityGenerator {
@Override
public Serializable generate(SharedSessionContractImplementor session, Object entity) {
Serializable id = session.getEntityPersister(null, entity)
.getClassMetadata().getIdentifier(entity, session);
return id != null ? id : super.generate(session, entity);
}
}
so that, when an Id was provided in the CSV file, the import was producing the very same entity in the database, with the very same Id.
In particular, I was able to save and restore the whole table by doing these actions in the following order:
Now that I have migrated my application to Spring Boot 3.3.1, this doesn't work anymore. I was forced to dispose of CustomIdGenerator because this implementation is no more compatible with Spring Boot 3.3.1 (because of its Hibernate dependency). I tried to obtain a similar CustomIdGenerator the new way, but in vain after several attempts and a couple of evenings trying to achieve that...
To summarize: I need the Ids of my entity to be auto-generated (like with GenerationType.IDENTITY) when they are provided without Id, but I need the Ids to be strictly identical to those provided in the CSV file in case of an import action.
Any known way to do that with success?
--
For example, I tried to implement a CustomIdGenerator this way (Spring Boot 3.3.1):
public class NewCustomIdGenerator implements IdentifierGenerator {
@Override
public Object generate (SharedSessionContractImplementor session, Object entity) {
var id = session.getEntityPersister(entity.getClass().toString(), entity).getIdentifier(entity, session);
if (id != null) {
return id;
}
//var res = super.generate(session, entity); // doesn't work
var res = 0L; // doesn't work (here I'd like the auto-generation to take over)
return res;
}
I also tried to extend IncrementGenerator or TableGenerator... in vain.
Any idea that works?
I finally found this solution based upon hybrid ID generation:
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.generator.BeforeExecutionGenerator;
import org.hibernate.generator.EventType;
import org.hibernate.id.IdentityGenerator;
import static java.util.Objects.isNull;
public class CustomIdGenerator extends IdentityGenerator implements BeforeExecutionGenerator {
@Override
public Object generate(SharedSessionContractImplementor session, Object entity, Object currentValue, EventType eventType) {
return getId(entity, session);
}
private static Object getId(Object entity, SharedSessionContractImplementor session) {
return session.getEntityPersister(null, entity)
.getIdentifier(entity, session);
}
/**
* The generate() method above is called if no ID is provided!
*/
@Override
public boolean generatedOnExecution(Object entity, SharedSessionContractImplementor session) {
Object id = getId(entity, session);
return isNull(id);
}
@Override
public boolean generatedOnExecution() {
return true;
}
}
The following post helped me a great deal:
https://discourse.hibernate.org/t/hybrid-id-generation-in-hibernate-6-2-is-difficult/7666/7