Hybrid ID generation in Hibernate 6.2 is difficult

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;
1 Like