Replacement of @GenericGenerator "native"

Hi,
I have upgraded to hibernate 6.6 from 6.2 and found, that @GenericGenerator is deprecated. I am using native strategy, so some databases are using sequences and others identity. I need this for backward compatibility.

    @Id
    @GeneratedValue(generator = "native")
    @GenericGenerator(name = "native", strategy = "native")
    private Long id;

GenerationType.IDENTITY is always generating identity and disabling identity in dialect throws, GenerationType.AUTO is selecting sequences for SQL Server. Is there option to alter behaviour of AUTO strategy in dialect or some supported way to use native generator?

The supported way to specify a custom generator is using @IdGeneratorType meta-annotation, see the user guide for more details and examples on how to rework your mappings.

Only way is to create custom generator? I was thinking about that, but this is complicated - delegate either to identity or sequence generator - how should I know current dialect?

Dialect has nothing to do with this. If you wish to use identity or sequence generators, just annotated either @GeneratedValue( strategy = IDENTITY ) or @GeneratedValue( strategy = SEQUENCE ).

I need different generator for SQL Server (identity) and for Oracle/PostgreSQL (sequence) - so I need to differentiate this with dialect.

I’m afraid that’s not possible with native Hibernate functionality, you’re just going to need to create a custom generator that implements your specific business logic.

Hi I also have the same problem with @GenericGenerator(name = “native_generator”, strategy = “native”), I need to support PostgesSql and Ms SQL together but as hibernate 6.5 deprecated GenericGenerator annotation, which annotation could be replacement of GenericGenerator with strategy = “native”? PostgesSql need ID with sequence and Ms SQL needs Auto increment ID.
@jezbera Have you found solution for it?

Unfortunately custom GenerationTypeStrategyRegistration was not working.

import jakarta.persistence.GenerationType;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.id.factory.internal.IdentityGenerationTypeStrategy;
import org.hibernate.id.factory.internal.SequenceGenerationTypeStrategy;
import org.hibernate.id.factory.spi.GenerationTypeStrategy;
import org.hibernate.id.factory.spi.GenerationTypeStrategyRegistration;
import org.hibernate.service.ServiceRegistry;

import java.util.function.BiConsumer;

public class CustomIdentifierGeneratorStrategyRegistration implements GenerationTypeStrategyRegistration {
    @Override
    public void registerStrategies(BiConsumer<GenerationType, GenerationTypeStrategy> registry, ServiceRegistry serviceRegistry) {
        Dialect dialect = serviceRegistry.requireService(JdbcEnvironment.class).getDialect();
        registry.accept(GenerationType.AUTO, dialect.getNativeIdentifierGeneratorStrategy().equals("identity") ? IdentityGenerationTypeStrategy.INSTANCE :  SequenceGenerationTypeStrategy.INSTANCE);
    }
}

I have used dirty way - custom IdentifierGeneratorFactory, that replaces sequences with identity based on dialect (it will break with future hibernate):

import jakarta.persistence.GenerationType;
import org.hibernate.MappingException;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.generator.Generator;
import org.hibernate.id.Assigned;
import org.hibernate.id.Configurable;
import org.hibernate.id.ForeignGenerator;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.IdentityGenerator;
import org.hibernate.id.factory.IdentifierGeneratorFactory;
import org.hibernate.id.factory.spi.GeneratorDefinitionResolver;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.type.Type;
import org.hibernate.type.descriptor.java.JavaType;

import java.util.Optional;
import java.util.Properties;

public class CustomIdentifierGeneratorFactory implements IdentifierGeneratorFactory {
    private final ServiceRegistry serviceRegistry;

    private Dialect dialect;

    public CustomIdentifierGeneratorFactory(ServiceRegistryImplementor serviceRegistry) {
        this.serviceRegistry = serviceRegistry;
    }

    @Override
    public Generator createIdentifierGenerator(GenerationType generationType, String generatedValueGeneratorName, String generatorName, JavaType<?> javaType, Properties config, GeneratorDefinitionResolver definitionResolver) {
        throw new UnsupportedOperationException("Not implemented yet");
    }

    @Override
    @Deprecated(since = "6.0")
    public Generator createIdentifierGenerator(String strategy, Type type, Properties parameters) {
        try {
            final Class<? extends Generator> clazz = generatorClassForName(strategy);
            final Generator identifierGenerator = clazz.newInstance();
            if (identifierGenerator instanceof Configurable configurable) {
                configurable.configure(type, parameters, serviceRegistry);
            }
            return identifierGenerator;
        } catch (Exception e) {
            final String entityName = parameters.getProperty(IdentifierGenerator.ENTITY_NAME);
            throw new MappingException(String.format("Could not instantiate id generator [entity-name=%s]", entityName), e);
        }
    }

    private Dialect getDialect() {
        if (dialect == null) {
            dialect = serviceRegistry.requireService(JdbcEnvironment.class).getDialect();
        }
        return dialect;
    }

    private Class<? extends Generator> generatorClassForName(String strategy) {
        if (strategy.equals("org.hibernate.id.enhanced.SequenceStyleGenerator") && getDialect().getNativeIdentifierGeneratorStrategy().equals("identity")) {
            return IdentityGenerator.class;
        }
        try {
            return getLegacyGenerator(strategy).orElseGet(() -> serviceRegistry.requireService(ClassLoaderService.class).classForName(strategy));
        } catch (ClassLoadingException e) {
            throw new MappingException(String.format("Could not interpret id generator strategy [%s]", strategy));
        }
    }

    private static Optional<Class<? extends Generator>> getLegacyGenerator(String name) {
        return switch (name) {
            case "assigned" -> Optional.of(Assigned.class);
            case "foreign" -> Optional.of(ForeignGenerator.class);
            default -> Optional.empty();
        };
    }
}