diff --git a/src/main/java/com/mongodb/hibernate/dialect/MongoDialect.java b/src/main/java/com/mongodb/hibernate/dialect/MongoDialect.java index 6d8d98f8..8161b607 100644 --- a/src/main/java/com/mongodb/hibernate/dialect/MongoDialect.java +++ b/src/main/java/com/mongodb/hibernate/dialect/MongoDialect.java @@ -151,6 +151,8 @@ *

For the documentation on the supported HQL * functions see {@link #initializeFunctionRegistry(FunctionContributions)}. + * + *

Thread-safe, immutable, as per the documentation of {@link Dialect}. */ @Sealed public class MongoDialect extends Dialect { @@ -196,7 +198,7 @@ protected void checkVersion() { @Override public SqlAstTranslatorFactory getSqlAstTranslatorFactory() { - return new MongoTranslatorFactory(); + return MongoTranslatorFactory.INSTANCE; } @Override @@ -350,6 +352,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio functionRegistry.register("array_includes_nullable", new MongoArrayIncludesFunction(true, typeConfiguration)); } + /** The {@link MutationOperation} returned from this method does not have to be thread-safe. */ @Override public MutationOperation createOptionalTableUpdateOperation( EntityMutationTarget mutationTarget, @@ -372,6 +375,7 @@ public void appendDatetimeFormat(SqlAppender appender, String format) { throw new FeatureNotSupportedException("TODO-HIBERNATE-88 https://jira.mongodb.org/browse/HIBERNATE-88"); } + /** The {@link SQLExceptionConversionDelegate} returned from this method must be thread-safe. */ @Override public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() { return (sqlException, exceptionMessage, mql) -> new JDBCException(exceptionMessage, sqlException, mql); diff --git a/src/main/java/com/mongodb/hibernate/internal/extension/MongoAdditionalMappingContributor.java b/src/main/java/com/mongodb/hibernate/internal/extension/MongoAdditionalMappingContributor.java index 1d475b6b..6fb4f835 100644 --- a/src/main/java/com/mongodb/hibernate/internal/extension/MongoAdditionalMappingContributor.java +++ b/src/main/java/com/mongodb/hibernate/internal/extension/MongoAdditionalMappingContributor.java @@ -38,7 +38,10 @@ import java.util.Set; import java.util.StringJoiner; import org.hibernate.annotations.Struct; +import org.hibernate.boot.Metadata; +import org.hibernate.boot.MetadataSources; import org.hibernate.boot.ResourceStreamLocator; +import org.hibernate.boot.registry.BootstrapServiceRegistry; import org.hibernate.boot.spi.AdditionalMappingContributions; import org.hibernate.boot.spi.AdditionalMappingContributor; import org.hibernate.boot.spi.InFlightMetadataCollector; @@ -50,6 +53,10 @@ import org.hibernate.type.BasicPluralType; import org.hibernate.type.ComponentType; +/** + * The instance methods of {@link AdditionalMappingContributor} are called multiple times if multiple {@link Metadata} + * instances are {@linkplain MetadataSources#buildMetadata() built} using the same {@link BootstrapServiceRegistry}. + */ public final class MongoAdditionalMappingContributor implements AdditionalMappingContributor { /** * We do not support these characters because BSON fields with names containing them must be handled specially as diff --git a/src/main/java/com/mongodb/hibernate/internal/extension/service/StandardServiceRegistryScopedState.java b/src/main/java/com/mongodb/hibernate/internal/extension/service/StandardServiceRegistryScopedState.java index 01d0adf0..7174b093 100644 --- a/src/main/java/com/mongodb/hibernate/internal/extension/service/StandardServiceRegistryScopedState.java +++ b/src/main/java/com/mongodb/hibernate/internal/extension/service/StandardServiceRegistryScopedState.java @@ -33,13 +33,16 @@ import java.util.Map; import java.util.Set; import org.hibernate.HibernateException; +import org.hibernate.boot.registry.BootstrapServiceRegistry; import org.hibernate.boot.registry.StandardServiceInitiator; +import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.service.Service; import org.hibernate.service.UnknownServiceException; import org.hibernate.service.spi.ServiceRegistryImplementor; import org.jspecify.annotations.Nullable; +/** Thread-safe. */ public final class StandardServiceRegistryScopedState implements Service { @Serial private static final long serialVersionUID = 1L; @@ -61,17 +64,27 @@ private void writeObject(ObjectOutputStream out) throws IOException { "This class is not designed to be serialized despite it having to implement `Serializable`"); } + /** + * The instance methods of {@link org.hibernate.service.spi.ServiceContributor} are called multiple times if + * multiple {@link StandardServiceRegistry} instances are {@linkplain StandardServiceRegistryBuilder#build() built} + * using the same {@link BootstrapServiceRegistry}. + */ public static final class ServiceContributor implements org.hibernate.service.spi.ServiceContributor { public ServiceContributor() {} @Override public void contribute(StandardServiceRegistryBuilder serviceRegistryBuilder) { serviceRegistryBuilder.addInitiator(new StandardServiceInitiator() { + /** + * This method may be called multiple times when {@linkplain StandardServiceRegistryBuilder#build() + * building} a single {@link StandardServiceRegistry} instance. + */ @Override public Class getServiceInitiated() { return StandardServiceRegistryScopedState.class; } + /** This method is called not more than once per instance of {@link StandardServiceInitiator}. */ @Override public StandardServiceRegistryScopedState initiateService( Map configurationValues, ServiceRegistryImplementor serviceRegistry) { diff --git a/src/main/java/com/mongodb/hibernate/internal/id/objectid/ObjectIdGenerator.java b/src/main/java/com/mongodb/hibernate/internal/id/objectid/ObjectIdGenerator.java index f56d63e1..6121f338 100644 --- a/src/main/java/com/mongodb/hibernate/internal/id/objectid/ObjectIdGenerator.java +++ b/src/main/java/com/mongodb/hibernate/internal/id/objectid/ObjectIdGenerator.java @@ -24,6 +24,7 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.generator.BeforeExecutionGenerator; import org.hibernate.generator.EventType; +import org.hibernate.generator.Generator; import org.hibernate.generator.GeneratorCreationContext; import org.hibernate.id.factory.spi.CustomIdGeneratorCreationContext; import org.jspecify.annotations.Nullable; @@ -39,25 +40,17 @@ public final class ObjectIdGenerator implements BeforeExecutionGenerator { private static final org.bson.codecs.ObjectIdGenerator GENERATOR = new org.bson.codecs.ObjectIdGenerator(); - private final boolean forIdentifier; - + /** @see Generator */ public ObjectIdGenerator( com.mongodb.hibernate.annotations.ObjectIdGenerator config, Member annotatedMember, - CustomIdGeneratorCreationContext context) { - this(true); - } + CustomIdGeneratorCreationContext context) {} + /** @see Generator */ public ObjectIdGenerator( com.mongodb.hibernate.annotations.ObjectIdGenerator config, Member annotatedMember, - GeneratorCreationContext context) { - this(false); - } - - private ObjectIdGenerator(boolean forIdentifier) { - this.forIdentifier = forIdentifier; - } + GeneratorCreationContext context) {} @Override public Object generate( @@ -67,13 +60,6 @@ public Object generate( EventType eventType) { if (currentValue != null) { return currentValue; - } else if (forIdentifier) { - // Hibernate ORM provides `null` as `currentValue` when generating an entity identifier value. - // To work around that behavior we have to read the value explicitly. - var currentId = session.getEntityPersister(null, owner).getIdentifier(owner, session); - if (currentId != null) { - return currentId; - } } return GENERATOR.generate(); } diff --git a/src/main/java/com/mongodb/hibernate/internal/translate/MongoTranslatorFactory.java b/src/main/java/com/mongodb/hibernate/internal/translate/MongoTranslatorFactory.java index e596b89e..7dc7f151 100644 --- a/src/main/java/com/mongodb/hibernate/internal/translate/MongoTranslatorFactory.java +++ b/src/main/java/com/mongodb/hibernate/internal/translate/MongoTranslatorFactory.java @@ -26,7 +26,12 @@ import org.hibernate.sql.model.ast.TableMutation; import org.hibernate.sql.model.jdbc.JdbcMutationOperation; +/** Tread-safe. */ public final class MongoTranslatorFactory implements SqlAstTranslatorFactory { + public static MongoTranslatorFactory INSTANCE = new MongoTranslatorFactory(); + + private MongoTranslatorFactory() {} + @Override public SqlAstTranslator buildSelectTranslator( SessionFactoryImplementor sessionFactoryImplementor, SelectStatement selectStatement) {