Skip to content

Commit

Permalink
HHH-15789 allow any InMemoryGenerator to generate ids
Browse files Browse the repository at this point in the history
  • Loading branch information
gavinking committed Nov 30, 2022
1 parent 7f72696 commit 26e7393
Show file tree
Hide file tree
Showing 47 changed files with 761 additions and 558 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/
package org.hibernate.annotations;

import org.hibernate.id.IdentifierGenerator;
import org.hibernate.tuple.InMemoryGenerator;

import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
Expand Down Expand Up @@ -74,12 +74,11 @@
*/
String name();
/**
* The type of identifier generator, a class implementing
* {@link org.hibernate.id.IdentifierGenerator}.
* The type of identifier generator, a class implementing {@link InMemoryGenerator}.
*
* @since 6.2
*/
Class<? extends IdentifierGenerator> type() default IdentifierGenerator.class;
Class<? extends InMemoryGenerator> type() default InMemoryGenerator.class;
/**
* The type of identifier generator, the name of either:
* <ul>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.lang.annotation.Target;

import org.hibernate.id.IdentifierGenerator;
import org.hibernate.tuple.InMemoryGenerator;

import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
Expand Down Expand Up @@ -63,8 +64,8 @@
@Retention(RUNTIME)
public @interface IdGeneratorType {
/**
* A class that implements {@link IdentifierGenerator} and has a
* constructor with the signature:
* A class that implements {@link InMemoryGenerator} and has a constructor
* with the signature:
* <pre>{@code
* public GeneratorType(AnnotationType config, Member idMember,
* CustomIdGeneratorCreationContext creationContext)
Expand All @@ -73,5 +74,5 @@
* {@code IdentifierGenerator}, and {@code AnnotationType} is the
* annotation type to which this annotation was applied.
*/
Class<? extends IdentifierGenerator> value();
Class<? extends InMemoryGenerator> value();
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import org.hibernate.boot.model.naming.ImplicitUniqueKeyNameSource;
import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject;
import org.hibernate.boot.model.relational.Database;
import org.hibernate.boot.model.relational.ExportableProducer;
import org.hibernate.boot.model.relational.Namespace;
import org.hibernate.boot.model.relational.QualifiedTableName;
import org.hibernate.boot.model.source.internal.ImplicitColumnNamingSecondPass;
Expand Down Expand Up @@ -102,6 +103,7 @@
import org.hibernate.metamodel.spi.EmbeddableInstantiator;
import org.hibernate.query.named.NamedObjectRepository;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.tuple.InMemoryGenerator;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.spi.TypeConfiguration;
Expand Down Expand Up @@ -2314,13 +2316,15 @@ private void handleIdentifierValueBinding(
// It was done this way in the old code too, so no "regression" here; but
// it could be done better
try {
final IdentifierGenerator ig = identifierValueBinding.createIdentifierGenerator(
final InMemoryGenerator generator = identifierValueBinding.createIdentifierGenerator(
bootstrapContext.getIdentifierGeneratorFactory(),
dialect,
entityBinding
);

ig.registerExportables( getDatabase() );
if ( generator instanceof ExportableProducer ) {
( (ExportableProducer) generator ).registerExportables( getDatabase() );
}
}
catch (MappingException e) {
// ignore this for now. The reasoning being "non-reflective" binding as needed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,20 @@
package org.hibernate.boot.model;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import jakarta.persistence.GenerationType;
import jakarta.persistence.Index;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.TableGenerator;
import jakarta.persistence.UniqueConstraint;
import org.hibernate.AssertionFailure;
import org.hibernate.Internal;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.internal.util.collections.CollectionHelper;

import static java.util.Collections.emptyMap;
Expand Down Expand Up @@ -74,6 +84,171 @@ public Map<String, String> getParameters() {
return parameters;
}

@Internal
public static IdentifierGeneratorDefinition createImplicit(
String name,
Class<?> idType,
String generatorName,
IdGeneratorStrategyInterpreter generationInterpreter,
GenerationType generationType) {
// If we were unable to locate an actual matching named generator assume
// a sequence/table of the given name, make one based on GenerationType.

if ( generationType == null) {
return buildSequenceGeneratorDefinition( name, generationInterpreter );
}

final String strategyName;
switch ( generationType ) {
case SEQUENCE:
return buildSequenceGeneratorDefinition( name, generationInterpreter );
case TABLE:
return buildTableGeneratorDefinition( name, generationInterpreter );
// really AUTO and IDENTITY work the same in this respect, aside from the actual strategy name
case IDENTITY:
strategyName = "identity";
break;
case AUTO:
strategyName = generationInterpreter.determineGeneratorName(
generationType,
new IdGeneratorStrategyInterpreter.GeneratorNameDeterminationContext() {
@Override
public Class<?> getIdType() {
return idType;
}
@Override
public String getGeneratedValueGeneratorName() {
return generatorName;
}
}
);
break;
default:
throw new AssertionFailure( "unknown generator type: " + generationType );
}

return new IdentifierGeneratorDefinition(
name,
strategyName,
Collections.singletonMap( IdentifierGenerator.GENERATOR_NAME, name )
);
}

private static IdentifierGeneratorDefinition buildTableGeneratorDefinition(String name, IdGeneratorStrategyInterpreter generationInterpreter) {
final Builder builder = new Builder();
generationInterpreter.interpretTableGenerator(
new TableGenerator() {
@Override
public String name() {
return name;
}

@Override
public String table() {
return "";
}

@Override
public int initialValue() {
return 0;
}

@Override
public int allocationSize() {
return 50;
}

@Override
public String catalog() {
return "";
}

@Override
public String schema() {
return "";
}

@Override
public String pkColumnName() {
return "";
}

@Override
public String valueColumnName() {
return "";
}

@Override
public String pkColumnValue() {
return "";
}

@Override
public UniqueConstraint[] uniqueConstraints() {
return new UniqueConstraint[0];
}

@Override
public Index[] indexes() {
return new Index[0];
}

@Override
public Class<? extends Annotation> annotationType() {
return TableGenerator.class;
}
},
builder
);

return builder.build();
}

private static IdentifierGeneratorDefinition buildSequenceGeneratorDefinition(String name, IdGeneratorStrategyInterpreter generationInterpreter) {
final Builder builder = new Builder();
generationInterpreter.interpretSequenceGenerator(
new SequenceGenerator() {
@Override
public String name() {
return name;
}

@Override
public String sequenceName() {
return "";
}

@Override
public String catalog() {
return "";
}

@Override
public String schema() {
return "";
}

@Override
public int initialValue() {
return 1;
}

@Override
public int allocationSize() {
return 50;
}

@Override
public Class<? extends Annotation> annotationType() {
return SequenceGenerator.class;
}
},
builder
);

return builder.build();
}

@Override
public boolean equals(Object o) {
if ( this == o ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
import org.hibernate.annotations.Parameter;
import org.hibernate.annotations.Parent;
import org.hibernate.annotations.TimeZoneStorage;
import org.hibernate.annotations.ValueGenerationType;
import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.annotations.common.reflection.XAnnotatedElement;
import org.hibernate.annotations.common.reflection.XClass;
Expand Down Expand Up @@ -91,6 +92,7 @@
import org.hibernate.property.access.spi.PropertyAccessStrategy;
import org.hibernate.resource.beans.spi.ManagedBean;
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
import org.hibernate.tuple.InMemoryGenerator;
import org.hibernate.type.BasicType;
import org.hibernate.type.CustomType;
import org.hibernate.type.descriptor.java.BasicJavaType;
Expand Down Expand Up @@ -152,6 +154,7 @@
import static org.hibernate.cfg.InheritanceState.getSuperclassInheritanceState;
import static org.hibernate.cfg.PropertyHolderBuilder.buildPropertyHolder;
import static org.hibernate.cfg.annotations.HCANNHelper.findContainingAnnotation;
import static org.hibernate.cfg.annotations.PropertyBinder.generatorCreator;
import static org.hibernate.cfg.annotations.PropertyBinder.identifierGeneratorCreator;
import static org.hibernate.internal.CoreLogging.messageLogger;
import static org.hibernate.mapping.Constraint.hashedName;
Expand Down Expand Up @@ -477,10 +480,10 @@ else if ( generatorAnnotation instanceof SequenceGenerator ) {
else if ( generatorAnnotation instanceof GenericGenerator ) {
final GenericGenerator genericGenerator = (GenericGenerator) generatorAnnotation;
definitionBuilder.setName( genericGenerator.name() );
final String strategy = genericGenerator.type().equals(IdentifierGenerator.class)
final String strategy = genericGenerator.type().equals(InMemoryGenerator.class)
? genericGenerator.strategy()
: genericGenerator.type().getName();
definitionBuilder.setStrategy(strategy);
definitionBuilder.setStrategy( strategy );
for ( Parameter parameter : genericGenerator.parameters() ) {
definitionBuilder.addParam( parameter.name(), parameter.value() );
}
Expand Down Expand Up @@ -1806,9 +1809,14 @@ private static void processId(
+ "' belongs to an '@IdClass' and may not be annotated '@Id' or '@EmbeddedId'" );
}
final XProperty idProperty = inferredData.getProperty();
final Annotation generatorAnnotation = findContainingAnnotation( idProperty, IdGeneratorType.class );
if ( generatorAnnotation != null ) {
idValue.setCustomIdGeneratorCreator( identifierGeneratorCreator( idProperty, generatorAnnotation ) );
final Annotation idGeneratorAnnotation = findContainingAnnotation( idProperty, IdGeneratorType.class );
final Annotation generatorAnnotation = findContainingAnnotation( idProperty, ValueGenerationType.class );
//TODO: validate that we don't have too many generator annotations and throw
if ( idGeneratorAnnotation != null ) {
idValue.setCustomIdGeneratorCreator( identifierGeneratorCreator( idProperty, idGeneratorAnnotation ) );
}
else if ( generatorAnnotation != null ) {
idValue.setCustomGeneratorCreator( generatorCreator( idProperty, generatorAnnotation ) );
}
else {
final XClass entityClass = inferredData.getClassOrElement();
Expand Down
Loading

0 comments on commit 26e7393

Please sign in to comment.