Skip to content

Commit fdef3b5

Browse files
committed
HHH-18411 - Add ability to specify a custom UuidGenerator.ValueGenerator
1 parent 55108d0 commit fdef3b5

File tree

9 files changed

+295
-16
lines changed

9 files changed

+295
-16
lines changed

hibernate-core/src/main/java/org/hibernate/annotations/UuidGenerator.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
import java.lang.annotation.Target;
1212
import java.util.UUID;
1313

14+
import org.hibernate.Incubating;
15+
import org.hibernate.id.uuid.UuidValueGenerator;
16+
1417
import static java.lang.annotation.ElementType.FIELD;
1518
import static java.lang.annotation.ElementType.METHOD;
1619
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@@ -21,9 +24,10 @@
2124
* <p>
2225
* The type of the identifier attribute may be {@link UUID} or {@link String}.
2326
*
24-
* @author Steve Ebersole
25-
*
27+
* @see org.hibernate.id.uuid.UuidGenerator
2628
* @since 6.0
29+
*
30+
* @author Steve Ebersole
2731
*/
2832
@IdGeneratorType(org.hibernate.id.uuid.UuidGenerator.class)
2933
@ValueGenerationType(generatedBy = org.hibernate.id.uuid.UuidGenerator.class)
@@ -58,4 +62,13 @@ enum Style {
5862
* Specifies which {@linkplain Style style} of UUID generation should be used.
5963
*/
6064
Style style() default Style.AUTO;
65+
66+
/**
67+
* Allows to provide a specific, generally custom, value generation implementation.
68+
*
69+
* @apiNote If algorithm is specified, it is expected that {@linkplain #style()} be
70+
* {@linkplain Style#AUTO}.
71+
*/
72+
@Incubating
73+
Class<? extends UuidValueGenerator> algorithm() default UuidValueGenerator.class;
6174
}

hibernate-core/src/main/java/org/hibernate/id/uuid/CustomVersionOneStrategy.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
*
2424
* @author Steve Ebersole
2525
*/
26-
public class CustomVersionOneStrategy implements UUIDGenerationStrategy, UuidGenerator.ValueGenerator {
26+
public class CustomVersionOneStrategy implements UUIDGenerationStrategy, UuidValueGenerator {
2727
@Override
2828
public int getGeneratedVersion() {
2929
return 1;

hibernate-core/src/main/java/org/hibernate/id/uuid/StandardRandomStrategy.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
*
1717
* @author Steve Ebersole
1818
*/
19-
public class StandardRandomStrategy implements UUIDGenerationStrategy, UuidGenerator.ValueGenerator {
19+
public class StandardRandomStrategy implements UUIDGenerationStrategy, UuidValueGenerator {
2020
public static final StandardRandomStrategy INSTANCE = new StandardRandomStrategy();
2121

2222
/**

hibernate-core/src/main/java/org/hibernate/id/uuid/UuidGenerator.java

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,39 +8,56 @@
88

99
import java.lang.reflect.Member;
1010
import java.util.EnumSet;
11+
import java.util.Locale;
1112
import java.util.UUID;
1213

1314
import org.hibernate.HibernateException;
15+
import org.hibernate.Internal;
16+
import org.hibernate.MappingException;
1417
import org.hibernate.engine.spi.SharedSessionContractImplementor;
18+
import org.hibernate.generator.BeforeExecutionGenerator;
1519
import org.hibernate.generator.EventType;
1620
import org.hibernate.generator.EventTypeSets;
1721
import org.hibernate.generator.GeneratorCreationContext;
1822
import org.hibernate.id.factory.spi.CustomIdGeneratorCreationContext;
19-
import org.hibernate.generator.BeforeExecutionGenerator;
2023
import org.hibernate.type.descriptor.java.UUIDJavaType;
2124
import org.hibernate.type.descriptor.java.UUIDJavaType.ValueTransformer;
2225

26+
import static org.hibernate.annotations.UuidGenerator.Style.AUTO;
2327
import static org.hibernate.annotations.UuidGenerator.Style.TIME;
2428
import static org.hibernate.generator.EventTypeSets.INSERT_ONLY;
2529
import static org.hibernate.internal.util.ReflectHelper.getPropertyType;
2630

2731
/**
28-
* Generates {@link UUID}s.
32+
* {@linkplain org.hibernate.generator.Generator} for producing {@link UUID} values.
33+
* <p/>
34+
* Uses a {@linkplain UuidValueGenerator} and {@linkplain ValueTransformer} to
35+
* generate the values.
2936
*
3037
* @see org.hibernate.annotations.UuidGenerator
3138
*/
3239
public class UuidGenerator implements BeforeExecutionGenerator {
33-
interface ValueGenerator {
34-
UUID generateUuid(SharedSessionContractImplementor session);
35-
}
36-
37-
private final ValueGenerator generator;
40+
private final UuidValueGenerator generator;
3841
private final ValueTransformer valueTransformer;
3942

4043
private UuidGenerator(
4144
org.hibernate.annotations.UuidGenerator config,
4245
Member idMember) {
43-
if ( config.style() == TIME ) {
46+
if ( config.algorithm() != UuidValueGenerator.class ) {
47+
if ( config.style() != AUTO ) {
48+
throw new MappingException(
49+
String.format(
50+
Locale.ROOT,
51+
"Style [%s] should not be specified with custom UUID value generator : %s.%s",
52+
config.style().name(),
53+
idMember.getDeclaringClass().getName(),
54+
idMember.getName()
55+
)
56+
);
57+
}
58+
generator = instantiateCustomGenerator( config.algorithm() );
59+
}
60+
else if ( config.style() == TIME ) {
4461
generator = new CustomVersionOneStrategy();
4562
}
4663
else {
@@ -63,6 +80,15 @@ else if ( byte[].class.isAssignableFrom( propertyType ) ) {
6380
}
6481
}
6582

83+
private static UuidValueGenerator instantiateCustomGenerator(Class<? extends UuidValueGenerator> algorithmClass) {
84+
try {
85+
return algorithmClass.getDeclaredConstructor().newInstance();
86+
}
87+
catch (Exception e) {
88+
throw new HibernateException( "Unable to instantiate " + algorithmClass.getName(), e );
89+
}
90+
}
91+
6692
public UuidGenerator(
6793
org.hibernate.annotations.UuidGenerator config,
6894
Member idMember,
@@ -89,4 +115,14 @@ public EnumSet<EventType> getEventTypes() {
89115
public Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue, EventType eventType) {
90116
return valueTransformer.transform( generator.generateUuid( session ) );
91117
}
118+
119+
@Internal
120+
public UuidValueGenerator getValueGenerator() {
121+
return generator;
122+
}
123+
124+
@Internal
125+
public ValueTransformer getValueTransformer() {
126+
return valueTransformer;
127+
}
92128
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
6+
*/
7+
package org.hibernate.id.uuid;
8+
9+
import java.util.UUID;
10+
11+
import org.hibernate.engine.spi.SharedSessionContractImplementor;
12+
13+
/**
14+
* Represents a specific algorithm for producing UUID values. Used in
15+
* conjunction with {@linkplain UuidGenerator} and
16+
*
17+
* @author Steve Ebersole
18+
*/
19+
public interface UuidValueGenerator {
20+
/**
21+
* Generate the UUID value
22+
*/
23+
UUID generateUuid(SharedSessionContractImplementor session);
24+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
6+
*/
7+
package org.hibernate.orm.test.id.uuid.annotation;
8+
9+
import java.util.UUID;
10+
11+
import org.hibernate.annotations.UuidGenerator;
12+
13+
import jakarta.persistence.Entity;
14+
import jakarta.persistence.GeneratedValue;
15+
import jakarta.persistence.Id;
16+
import jakarta.persistence.Basic;
17+
18+
/**
19+
* @author Steve Ebersole
20+
*/
21+
@Entity
22+
public class AnotherEntity {
23+
@Id
24+
@GeneratedValue
25+
@UuidGenerator( algorithm = CustomUuidValueGenerator.class )
26+
private UUID id;
27+
@Basic
28+
private String name;
29+
30+
protected AnotherEntity() {
31+
// for Hibernate use
32+
}
33+
34+
public AnotherEntity(String name) {
35+
this.name = name;
36+
}
37+
38+
public UUID getId() {
39+
return id;
40+
}
41+
42+
public String getName() {
43+
return name;
44+
}
45+
46+
public void setName(String name) {
47+
this.name = name;
48+
}
49+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
6+
*/
7+
package org.hibernate.orm.test.id.uuid.annotation;
8+
9+
import java.util.UUID;
10+
11+
import org.hibernate.engine.spi.SharedSessionContractImplementor;
12+
import org.hibernate.id.uuid.UuidValueGenerator;
13+
14+
/**
15+
* @author Steve Ebersole
16+
*/
17+
public class CustomUuidValueGenerator implements UuidValueGenerator {
18+
private long counter = 0;
19+
20+
@Override
21+
public UUID generateUuid(SharedSessionContractImplementor session) {
22+
final UUID sessionIdentifier = session.getSessionIdentifier();
23+
return new UUID( sessionIdentifier.getMostSignificantBits(), ++counter );
24+
}
25+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
6+
*/
7+
package org.hibernate.orm.test.id.uuid.annotation;
8+
9+
import org.hibernate.boot.model.relational.Database;
10+
import org.hibernate.boot.spi.MetadataImplementor;
11+
import org.hibernate.id.factory.IdentifierGeneratorFactory;
12+
import org.hibernate.id.factory.spi.CustomIdGeneratorCreationContext;
13+
import org.hibernate.mapping.PersistentClass;
14+
import org.hibernate.mapping.Property;
15+
import org.hibernate.mapping.RootClass;
16+
import org.hibernate.service.ServiceRegistry;
17+
18+
/**
19+
* @author Steve Ebersole
20+
*/
21+
public class IdGeneratorCreationContext implements CustomIdGeneratorCreationContext {
22+
private final MetadataImplementor domainModel;
23+
private final RootClass entityMapping;
24+
25+
public IdGeneratorCreationContext(MetadataImplementor domainModel, RootClass entityMapping) {
26+
this.domainModel = domainModel;
27+
this.entityMapping = entityMapping;
28+
29+
assert entityMapping.getIdentifierProperty() != null;
30+
}
31+
32+
@Override
33+
public IdentifierGeneratorFactory getIdentifierGeneratorFactory() {
34+
return domainModel.getMetadataBuildingOptions().getIdentifierGeneratorFactory();
35+
}
36+
37+
@Override
38+
public RootClass getRootClass() {
39+
return entityMapping;
40+
}
41+
42+
@Override
43+
public Database getDatabase() {
44+
return domainModel.getDatabase();
45+
}
46+
47+
@Override
48+
public ServiceRegistry getServiceRegistry() {
49+
return domainModel.getMetadataBuildingOptions().getServiceRegistry();
50+
}
51+
52+
@Override
53+
public String getDefaultCatalog() {
54+
return "";
55+
}
56+
57+
@Override
58+
public String getDefaultSchema() {
59+
return "";
60+
}
61+
62+
@Override
63+
public PersistentClass getPersistentClass() {
64+
return entityMapping;
65+
}
66+
67+
@Override
68+
public Property getProperty() {
69+
return entityMapping.getIdentifierProperty();
70+
}
71+
}

0 commit comments

Comments
 (0)