I found a solution.
With
<properties>
<hibernate.version>6.4.4.Final</hibernate.version>
</properties>
I can use
public class CustomIdentityGenerator 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);
}
/**
* @implNote Method {@link #generate(SharedSessionContractImplementor, Object, Object, EventType)}
* is called if this method returns false
*/
@Override
public boolean generatedOnExecution(Object entity, SharedSessionContractImplementor session) {
Object id = getId(entity, session);
return isNull(id);
}
@Override
public boolean generatedOnExecution() {
// This method is called to configure a context (using this Generator) without knowledge of a specific Entity.
// The choice for the real Entity must be made in the this.generatedOnExecution(entity, session) method.
// For example, find out comment "support mixed-timing generators" in IdentifierGeneratorUtil.class (hibernate-core):
// true is required, if ID sometimes should be generated by RDBMS (for example by AUTO_INCREMENT)
return true;
}
}
This class completly replaces old CustomIdentityGenerator
above, the rest of the code can remain the same. This class works for AUTO_INCREMENT / IDENTITY
db columns.
If you want use TABLE
, SEQUENCE
, UUID
id generation types you can use general class I’ve described here. Then you can wrap required “before” and “on” sql statement execution id generator implementations
class AssignedOrIdentityGenerator extends BeforeOrOnExecutionGenerator {
public AssignedOrIdentityGenerator() {
super(new Assigned(), new IdentityGenerator());
}
}
With hibernate 6.4.4 you can also create simple annotation
@Retention(RUNTIME)
@Target({METHOD, FIELD})
@IdGeneratorType(AssignedOrIdentityGenerator.class)
public @interface AssignedOrGeneratedValue {
}
So you can replace this code snippet
@Id
@GeneratedValue(generator = "assigned-or-generated")
@GenericGenerator(name = "assigned-or-generated", type = AssignedOrIdentityGenerator.class)
@Column(name = "id")
private Integer id;
with a simpler one
@Id
@AssignedOrGeneratedValue
@Column(name = "id")
private Integer id;