diff --git a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmConfigPersistenceUnit.java b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmConfigPersistenceUnit.java index 7843020debfab..69524ca533d61 100644 --- a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmConfigPersistenceUnit.java +++ b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmConfigPersistenceUnit.java @@ -2,6 +2,7 @@ import java.nio.charset.Charset; import java.time.Duration; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -11,6 +12,7 @@ import org.hibernate.engine.query.spi.QueryPlanCache; +import io.quarkus.runtime.annotations.ConfigDocMapKey; import io.quarkus.runtime.annotations.ConfigDocSection; import io.quarkus.runtime.annotations.ConfigGroup; import io.quarkus.runtime.annotations.ConfigItem; @@ -233,6 +235,10 @@ public class HibernateOrmConfigPersistenceUnit { @ConfigItem(defaultValue = "true") public boolean validateInDevMode; + @ConfigItem(generateDocumentation = false) + @ConfigDocMapKey("full-property-key") + public Map unsupportedProperties = new HashMap<>(); + public boolean isAnyPropertySet() { return datasource.isPresent() || packages.isPresent() || @@ -251,7 +257,8 @@ public boolean isAnyPropertySet() { multitenant.isPresent() || multitenantSchemaDatasource.isPresent() || fetch.isAnyPropertySet() || - discriminator.isAnyPropertySet(); + discriminator.isAnyPropertySet() || + !unsupportedProperties.isEmpty(); } @ConfigGroup @@ -459,4 +466,4 @@ public boolean isAnyPropertySet() { return ignoreExplicitForJoined; } } -} \ No newline at end of file +} diff --git a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java index 36780321fcc9e..832e28ab7950c 100644 --- a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java +++ b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmProcessor.java @@ -405,6 +405,7 @@ public void configurationDescriptorBuilding( .getProperties().getProperty(AvailableSettings.MULTI_TENANT))), null, jpaModel.getXmlMappings(persistenceXmlDescriptorBuildItem.getDescriptor().getName()), + Collections.emptyMap(), false, true)); } @@ -1198,6 +1199,7 @@ private static void producePersistenceUnitDescriptorFromConfig( multiTenancyStrategy, persistenceUnitConfig.multitenantSchemaDatasource.orElse(null), xmlMappings, + persistenceUnitConfig.unsupportedProperties, false, false)); } diff --git a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/PersistenceUnitDescriptorBuildItem.java b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/PersistenceUnitDescriptorBuildItem.java index 3bb65d555d0fb..6a4f4291cd94c 100644 --- a/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/PersistenceUnitDescriptorBuildItem.java +++ b/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/PersistenceUnitDescriptorBuildItem.java @@ -2,6 +2,7 @@ import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Optional; import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor; @@ -26,24 +27,29 @@ public final class PersistenceUnitDescriptorBuildItem extends MultiBuildItem { private final MultiTenancyStrategy multiTenancyStrategy; private final String multiTenancySchemaDataSource; private final List xmlMappings; + private final Map quarkusConfigUnsupportedProperties; private final boolean isReactive; private final boolean fromPersistenceXml; public PersistenceUnitDescriptorBuildItem(ParsedPersistenceXmlDescriptor descriptor, - List xmlMappings, boolean isReactive, boolean fromPersistenceXml) { + List xmlMappings, + Map quarkusConfigUnsupportedProperties, + boolean isReactive, boolean fromPersistenceXml) { this(descriptor, Optional.of(DataSourceUtil.DEFAULT_DATASOURCE_NAME), MultiTenancyStrategy.NONE, null, - xmlMappings, isReactive, fromPersistenceXml); + xmlMappings, quarkusConfigUnsupportedProperties, isReactive, fromPersistenceXml); } public PersistenceUnitDescriptorBuildItem(ParsedPersistenceXmlDescriptor descriptor, Optional dataSource, MultiTenancyStrategy multiTenancyStrategy, String multiTenancySchemaDataSource, List xmlMappings, + Map quarkusConfigUnsupportedProperties, boolean isReactive, boolean fromPersistenceXml) { this.descriptor = descriptor; this.dataSource = dataSource; this.multiTenancyStrategy = multiTenancyStrategy; this.multiTenancySchemaDataSource = multiTenancySchemaDataSource; this.xmlMappings = xmlMappings; + this.quarkusConfigUnsupportedProperties = quarkusConfigUnsupportedProperties; this.isReactive = isReactive; this.fromPersistenceXml = fromPersistenceXml; } @@ -79,6 +85,6 @@ public boolean hasXmlMappings() { public QuarkusPersistenceUnitDefinition asOutputPersistenceUnitDefinition( List integrationStaticDescriptors) { return new QuarkusPersistenceUnitDefinition(descriptor, dataSource, multiTenancyStrategy, xmlMappings, - isReactive, fromPersistenceXml, integrationStaticDescriptors); + quarkusConfigUnsupportedProperties, isReactive, fromPersistenceXml, integrationStaticDescriptors); } } diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/unsupportedproperties/SettingsSpyingIdentifierGenerator.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/unsupportedproperties/SettingsSpyingIdentifierGenerator.java new file mode 100644 index 0000000000000..b92afcae634ff --- /dev/null +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/unsupportedproperties/SettingsSpyingIdentifierGenerator.java @@ -0,0 +1,35 @@ +package io.quarkus.hibernate.orm.config.unsupportedproperties; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.hibernate.HibernateException; +import org.hibernate.MappingException; +import org.hibernate.engine.config.spi.ConfigurationService; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.id.IdentifierGenerator; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.type.Type; + +/** + * This was the only way I found to get our hands on the settings used during metadata building. + * Feel free to use some other solution if you find one. + */ +public class SettingsSpyingIdentifierGenerator implements IdentifierGenerator { + static final List> collectedSettings = new ArrayList<>(); + + @Override + @SuppressWarnings({ "unchecked", "rawtypes" }) + public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException { + collectedSettings.add(new HashMap<>(serviceRegistry.getService(ConfigurationService.class).getSettings())); + } + + @Override + public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException { + throw new IllegalStateException("This should not be called"); + } +} diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/unsupportedproperties/UnsupportedPropertiesTest.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/unsupportedproperties/UnsupportedPropertiesTest.java new file mode 100644 index 0000000000000..057d6dcf9efc6 --- /dev/null +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/unsupportedproperties/UnsupportedPropertiesTest.java @@ -0,0 +1,226 @@ +package io.quarkus.hibernate.orm.config.unsupportedproperties; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.logging.Formatter; +import java.util.logging.Level; + +import javax.inject.Inject; +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; + +import org.hibernate.BaseSessionEventListener; +import org.hibernate.Session; +import org.hibernate.annotations.GenericGenerator; +import org.hibernate.cfg.AvailableSettings; +import org.jboss.logmanager.formatters.PatternFormatter; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.hibernate.orm.runtime.FastBootHibernatePersistenceProvider; +import io.quarkus.narayana.jta.QuarkusTransaction; +import io.quarkus.test.QuarkusUnitTest; + +public class UnsupportedPropertiesTest { + + private static final Formatter LOG_FORMATTER = new PatternFormatter("%s"); + + @RegisterExtension + static QuarkusUnitTest runner = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClass(ParentEntity.class) + .addClass(ChildEntity.class) + .addClass(SpyingIdentifierGeneratorEntity.class) + .addClass(SettingsSpyingIdentifierGenerator.class)) + .withConfigurationResource("application.properties") + .overrideConfigKey("quarkus.hibernate-orm.jdbc.statement-batch-size", "10") + // This should be taken into account by Hibernate ORM + .overrideConfigKey("quarkus.hibernate-orm.unsupported-properties.\"" + AvailableSettings.ORDER_INSERTS + "\"", + "true") + // This is just to test a property set at build time + .overrideConfigKey("quarkus.hibernate-orm.unsupported-properties.\"hibernate.some.unknown.key.static-and-runtime\"", + "some-value-1") + // This is just to test a property set at runtime, which which would not be available during the build + // (or even during static init with native applications). + .overrideRuntimeConfigKey( + "quarkus.hibernate-orm.unsupported-properties.\"hibernate.some.unknown.key.runtime-only\"", + "some-value-2") + // This should be ignored with a warning + .overrideConfigKey( + "quarkus.hibernate-orm.unsupported-properties.\"" + AvailableSettings.HBM2DDL_DATABASE_ACTION + "\"", + "drop-and-create") + // Expect warnings on startup + .setLogRecordPredicate(record -> FastBootHibernatePersistenceProvider.class.getName().equals(record.getLoggerName()) + && record.getLevel().intValue() >= Level.WARNING.intValue()) + .assertLogRecords(records -> { + var assertion = assertThat(records) + .as("Warnings on startup") + .hasSize(2); + assertion.element(0).satisfies(record -> assertThat(LOG_FORMATTER.formatMessage(record)) + .contains("Persistence-unit [] sets unsupported properties", + "These properties may not work correctly", + "may change when upgrading to a newer version of Quarkus (even just a micro/patch version)", + "Consider using a supported configuration property", + "make sure to file a feature request so that a supported configuration property can be added to Quarkus") + .contains(AvailableSettings.ORDER_INSERTS, AvailableSettings.HBM2DDL_DATABASE_ACTION, + "hibernate.some.unknown.key.static-and-runtime", "hibernate.some.unknown.key.runtime-only") + // We should not log property values, that could be a security breach for some properties. + .doesNotContain("some-value")); + assertion.element(1).satisfies(record -> assertThat(LOG_FORMATTER.formatMessage(record)) + .contains( + "Persistence-unit [] sets property '" + AvailableSettings.HBM2DDL_DATABASE_ACTION + + "' to a custom value through 'quarkus.hibernate-orm.unsupported-properties.\"" + + AvailableSettings.HBM2DDL_DATABASE_ACTION + "\"'", + "Quarkus already set that property independently", + "The custom value will be ignored")); + }); + + @Inject + EntityManagerFactory emf; + + @Inject + EntityManager em; + + @Test + public void testPropertiesPropagatedToStaticInit() { + assertThat(SettingsSpyingIdentifierGenerator.collectedSettings).hasSize(1); + Map settings = SettingsSpyingIdentifierGenerator.collectedSettings.get(0); + assertThat(settings) + .containsEntry("hibernate.some.unknown.key.static-and-runtime", "some-value-1") + .doesNotContainKey("hibernate.some.unknown.key.runtime-only"); + } + + @Test + public void testPropertiesPropagatedToRuntimeInit() { + assertThat(emf.getProperties()) + .contains(entry("hibernate.order_inserts", "true"), + // Also test a property that Quarkus cannot possibly know about + entry("hibernate.some.unknown.key.static-and-runtime", "some-value-1"), + entry("hibernate.some.unknown.key.runtime-only", "some-value-2")); + } + + // This tests a particular feature that can (currently) only be enabled with unsupported properties + @Test + public void testInsertsOrdered() { + var listener = new BatchCountSpyingEventListener(); + + QuarkusTransaction.run(() -> { + em.unwrap(Session.class).addEventListeners(listener); + + ParentEntity parent1 = new ParentEntity(1); + parent1.getChildren().add(new ChildEntity(2)); + parent1.getChildren().add(new ChildEntity(3)); + ParentEntity parent2 = new ParentEntity(4); + parent2.getChildren().add(new ChildEntity(5)); + parent2.getChildren().add(new ChildEntity(6)); + em.persist(parent1); + em.persist(parent2); + }); + + // Thanks to insert ordering, we expect only 2 JDBC statement batches + // (instead of 4 if insert ordering was disabled) + assertThat(listener.batchCount).isEqualTo(2); + } + + private static class BatchCountSpyingEventListener extends BaseSessionEventListener { + private long batchCount = 0; + + @Override + public void jdbcExecuteBatchStart() { + ++batchCount; + } + } + + @Entity + public static class ParentEntity { + @Id + private Long id; + + @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL) + private List children = new ArrayList<>(); + + public ParentEntity() { + } + + public ParentEntity(long id) { + this.id = id; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public List getChildren() { + return children; + } + + public void setChildren(List children) { + this.children = children; + } + } + + @Entity + public static class ChildEntity { + @Id + private Long id; + + @ManyToOne + private ParentEntity parent; + + public ChildEntity() { + } + + public ChildEntity(long id) { + this.id = id; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public ParentEntity getParent() { + return parent; + } + + public void setParent(ParentEntity parent) { + this.parent = parent; + } + } + + @Entity + public static class SpyingIdentifierGeneratorEntity { + @Id + @GeneratedValue(generator = "spying-generator") + @GenericGenerator(name = "spying-generator", strategy = "io.quarkus.hibernate.orm.config.unsupportedproperties.SettingsSpyingIdentifierGenerator") + private Long id; + + public SpyingIdentifierGeneratorEntity() { + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + } +} diff --git a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/FastBootHibernatePersistenceProvider.java b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/FastBootHibernatePersistenceProvider.java index 3e7d8a38a58c4..c1b82910f8b7c 100644 --- a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/FastBootHibernatePersistenceProvider.java +++ b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/FastBootHibernatePersistenceProvider.java @@ -202,9 +202,17 @@ private RuntimeSettings buildRuntimeSettings(String persistenceUnitName, Recorde injectDataSource(persistenceUnitName, dataSourceName.get(), runtimeSettingsBuilder); } + HibernateOrmRuntimeConfigPersistenceUnit persistenceUnitConfig; + if (PersistenceUnitUtil.isDefaultPersistenceUnit(persistenceUnitName)) { + persistenceUnitConfig = hibernateOrmRuntimeConfig.defaultPersistenceUnit; + } else { + persistenceUnitConfig = hibernateOrmRuntimeConfig.persistenceUnits.getOrDefault(persistenceUnitName, + new HibernateOrmRuntimeConfigPersistenceUnit()); + } + // Inject runtime configuration if the persistence unit was defined by Quarkus configuration if (!recordedState.isFromPersistenceXml()) { - injectRuntimeConfiguration(persistenceUnitName, hibernateOrmRuntimeConfig, runtimeSettingsBuilder); + injectRuntimeConfiguration(persistenceUnitConfig, runtimeSettingsBuilder); } for (HibernateOrmIntegrationRuntimeDescriptor descriptor : integrationRuntimeDescriptors @@ -218,6 +226,30 @@ private RuntimeSettings buildRuntimeSettings(String persistenceUnitName, Recorde // Allow detection of driver/database capabilities on runtime init (was disabled during static init) runtimeSettingsBuilder.put("hibernate.temp.use_jdbc_metadata_defaults", "true"); + if (!persistenceUnitConfig.unsupportedProperties.isEmpty()) { + log.warnf("Persistence-unit [%s] sets unsupported properties." + + " These properties may not work correctly, and even if they do," + + " that may change when upgrading to a newer version of Quarkus (even just a micro/patch version)." + + " Consider using a supported configuration property before falling back to unsupported ones." + + " If there is no supported equivalent, make sure to file a feature request so that a supported configuration property can be added to Quarkus," + + " and more importantly so that the configuration property is tested regularly." + + " Unsupported properties being set: %s", + persistenceUnitName, + persistenceUnitConfig.unsupportedProperties.keySet()); + } + for (Map.Entry entry : persistenceUnitConfig.unsupportedProperties.entrySet()) { + var key = entry.getKey(); + if (runtimeSettingsBuilder.get(key) != null) { + log.warnf("Persistence-unit [%s] sets property '%s' to a custom value through '%s'," + + " but Quarkus already set that property independently." + + " The custom value will be ignored.", + persistenceUnitName, key, + HibernateOrmRuntimeConfig.puPropertyKey(persistenceUnitName, "unsupported-properties.\"" + key + "\"")); + continue; + } + runtimeSettingsBuilder.put(entry.getKey(), entry.getValue()); + } + RuntimeSettings runtimeSettings = runtimeSettingsBuilder.build(); return runtimeSettings; } @@ -343,16 +375,8 @@ private static void injectDataSource(String persistenceUnitName, String dataSour runtimeSettingsBuilder.put(AvailableSettings.DATASOURCE, ds); } - private static void injectRuntimeConfiguration(String persistenceUnitName, - HibernateOrmRuntimeConfig hibernateOrmRuntimeConfig, Builder runtimeSettingsBuilder) { - HibernateOrmRuntimeConfigPersistenceUnit persistenceUnitConfig; - if (PersistenceUnitUtil.isDefaultPersistenceUnit(persistenceUnitName)) { - persistenceUnitConfig = hibernateOrmRuntimeConfig.defaultPersistenceUnit; - } else { - persistenceUnitConfig = hibernateOrmRuntimeConfig.persistenceUnits.getOrDefault(persistenceUnitName, - new HibernateOrmRuntimeConfigPersistenceUnit()); - } - + private static void injectRuntimeConfiguration(HibernateOrmRuntimeConfigPersistenceUnit persistenceUnitConfig, + Builder runtimeSettingsBuilder) { // Database runtimeSettingsBuilder.put(AvailableSettings.HBM2DDL_DATABASE_ACTION, persistenceUnitConfig.database.generation.generation); diff --git a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/HibernateOrmRuntimeConfigPersistenceUnit.java b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/HibernateOrmRuntimeConfigPersistenceUnit.java index 50e496720d547..341bcf2ebf5bd 100644 --- a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/HibernateOrmRuntimeConfigPersistenceUnit.java +++ b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/HibernateOrmRuntimeConfigPersistenceUnit.java @@ -1,7 +1,10 @@ package io.quarkus.hibernate.orm.runtime; +import java.util.HashMap; +import java.util.Map; import java.util.Optional; +import io.quarkus.runtime.annotations.ConfigDocMapKey; import io.quarkus.runtime.annotations.ConfigDocSection; import io.quarkus.runtime.annotations.ConfigGroup; import io.quarkus.runtime.annotations.ConfigItem; @@ -32,10 +35,35 @@ public class HibernateOrmRuntimeConfigPersistenceUnit { @ConfigDocSection public HibernateOrmConfigPersistenceUnitLog log = new HibernateOrmConfigPersistenceUnitLog(); + /** + * Properties that should be passed on directly to Hibernate ORM. + * Use the full configuration property key here, + * for instance `quarkus.hibernate-orm.unsupported-properties."hibernate.order_inserts" = true`. + * + * [WARNING] + * ==== + * Properties set here are completely unsupported: + * as Quarkus doesn't generally know about these properties and their purpose, + * there is absolutely no guarantee that they will work correctly, + * and even if they do, that may change when upgrading to a newer version of Quarkus + * (even just a micro/patch version). + * ==== + * + * Consider using a supported configuration property before falling back to unsupported ones. + * If none exists, make sure to file a feature request so that a supported configuration property can be added to Quarkus, + * and more importantly so that the configuration property is tested regularly. + * + * @asciidoclet + */ + @ConfigItem + @ConfigDocMapKey("full-property-key") + public Map unsupportedProperties = new HashMap<>(); + public boolean isAnyPropertySet() { return database.isAnyPropertySet() || scripts.isAnyPropertySet() || - log.isAnyPropertySet(); + log.isAnyPropertySet() || + !unsupportedProperties.isEmpty(); } @ConfigGroup diff --git a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/boot/FastBootMetadataBuilder.java b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/boot/FastBootMetadataBuilder.java index b4685c525b117..c92ddee5213b5 100644 --- a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/boot/FastBootMetadataBuilder.java +++ b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/boot/FastBootMetadataBuilder.java @@ -138,6 +138,20 @@ public FastBootMetadataBuilder(final QuarkusPersistenceUnitDefinition puDefiniti // Build the "standard" service registry ssrBuilder.applySettings(buildTimeSettings.getSettings()); + // We don't add unsupported properties to mergedSettings/buildTimeSettings, + // so that we can more easily differentiate between + // properties coming from Quarkus and "unsupported" properties + // on startup (see io.quarkus.hibernate.orm.runtime.FastBootHibernatePersistenceProvider.buildRuntimeSettings) + for (Map.Entry entry : puDefinition.getQuarkusConfigUnsupportedProperties().entrySet()) { + var key = entry.getKey(); + if (buildTimeSettings.get(key) != null) { + // Ignore properties that were already set by Quarkus; + // we'll log a warning about those on startup. + // (see io.quarkus.hibernate.orm.runtime.FastBootHibernatePersistenceProvider.buildRuntimeSettings) + continue; + } + ssrBuilder.applySetting(key, entry.getValue()); + } this.standardServiceRegistry = ssrBuilder.build(); registerIdentifierGenerators(standardServiceRegistry); diff --git a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/boot/QuarkusPersistenceUnitDefinition.java b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/boot/QuarkusPersistenceUnitDefinition.java index 5774438c23ef5..7a0affa72ff8a 100644 --- a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/boot/QuarkusPersistenceUnitDefinition.java +++ b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/boot/QuarkusPersistenceUnitDefinition.java @@ -1,6 +1,7 @@ package io.quarkus.hibernate.orm.runtime.boot; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Properties; @@ -29,9 +30,11 @@ public final class QuarkusPersistenceUnitDefinition { private final boolean isReactive; private final boolean fromPersistenceXml; private final List integrationStaticDescriptors; + private final Map quarkusConfigUnsupportedProperties; public QuarkusPersistenceUnitDefinition(PersistenceUnitDescriptor persistenceUnitDescriptor, Optional dataSource, MultiTenancyStrategy multitenancyStrategy, List xmlMappings, + Map quarkusConfigUnsupportedProperties, boolean isReactive, boolean fromPersistenceXml, List integrationStaticDescriptors) { Objects.requireNonNull(persistenceUnitDescriptor); @@ -40,6 +43,7 @@ public QuarkusPersistenceUnitDefinition(PersistenceUnitDescriptor persistenceUni this.dataSource = dataSource; this.multitenancyStrategy = multitenancyStrategy; this.xmlMappings = xmlMappings; + this.quarkusConfigUnsupportedProperties = quarkusConfigUnsupportedProperties; this.isReactive = isReactive; this.fromPersistenceXml = fromPersistenceXml; this.integrationStaticDescriptors = integrationStaticDescriptors; @@ -52,6 +56,7 @@ private QuarkusPersistenceUnitDefinition(LightPersistenceXmlDescriptor persisten Optional dataSource, MultiTenancyStrategy multitenancyStrategy, List xmlMappings, + Map quarkusConfigUnsupportedProperties, boolean isReactive, boolean fromPersistenceXml, List integrationStaticDescriptors) { @@ -62,6 +67,7 @@ private QuarkusPersistenceUnitDefinition(LightPersistenceXmlDescriptor persisten this.dataSource = dataSource; this.multitenancyStrategy = multitenancyStrategy; this.xmlMappings = xmlMappings; + this.quarkusConfigUnsupportedProperties = quarkusConfigUnsupportedProperties; this.isReactive = isReactive; this.fromPersistenceXml = fromPersistenceXml; this.integrationStaticDescriptors = integrationStaticDescriptors; @@ -83,6 +89,10 @@ public MultiTenancyStrategy getMultitenancyStrategy() { return multitenancyStrategy; } + public List getXmlMappings() { + return xmlMappings; + } + //TODO assert that we match the right type of ORM! public boolean isReactive() { return isReactive; @@ -96,8 +106,8 @@ public List getIntegrationStaticDescrip return integrationStaticDescriptors; } - public List getXmlMappings() { - return xmlMappings; + public Map getQuarkusConfigUnsupportedProperties() { + return quarkusConfigUnsupportedProperties; } /** @@ -120,6 +130,7 @@ public static class Serialized { private List puManagedClassNames; private Properties puProperties; private List integrationStaticDescriptors; + private Map quarkusConfigUnsupportedProperties; //All standard getters and setters generated by IDE: @@ -235,6 +246,14 @@ public void setIntegrationStaticDescriptors( List integrationStaticDescriptors) { this.integrationStaticDescriptors = integrationStaticDescriptors; } + + public Map getQuarkusConfigUnsupportedProperties() { + return quarkusConfigUnsupportedProperties; + } + + public void setQuarkusConfigUnsupportedProperties(Map quarkusConfigUnsupportedProperties) { + this.quarkusConfigUnsupportedProperties = quarkusConfigUnsupportedProperties; + } } public static final class Substitution implements ObjectSubstitution { @@ -255,6 +274,7 @@ public Serialized serialize(final QuarkusPersistenceUnitDefinition obj) { s.setDataSource(obj.getDataSource()); s.setMultitenancyStrategy(obj.getMultitenancyStrategy()); s.setXmlMappingBindings(obj.getXmlMappings()); + s.setQuarkusConfigUnsupportedProperties(obj.getQuarkusConfigUnsupportedProperties()); s.setReactive(obj.isReactive); s.setFromPersistenceXml(obj.isFromPersistenceXml()); s.setIntegrationStaticDescriptors(obj.getIntegrationStaticDescriptors()); @@ -268,7 +288,8 @@ public QuarkusPersistenceUnitDefinition deserialize(Serialized obj) { obj.puValidationMode, obj.puSharedCachemode, obj.puManagedClassNames, obj.puProperties); return new QuarkusPersistenceUnitDefinition(xmlDescriptor, obj.getDataSource(), obj.getMultitenancyStrategy(), - obj.getXmlMappingBindings(), obj.isReactive(), obj.isFromPersistenceXml(), + obj.getXmlMappingBindings(), obj.getQuarkusConfigUnsupportedProperties(), + obj.isReactive(), obj.isFromPersistenceXml(), obj.getIntegrationStaticDescriptors()); } } diff --git a/extensions/hibernate-reactive/deployment/src/main/java/io/quarkus/hibernate/reactive/deployment/HibernateReactiveProcessor.java b/extensions/hibernate-reactive/deployment/src/main/java/io/quarkus/hibernate/reactive/deployment/HibernateReactiveProcessor.java index 0032f5a2cf913..be725d6285adb 100644 --- a/extensions/hibernate-reactive/deployment/src/main/java/io/quarkus/hibernate/reactive/deployment/HibernateReactiveProcessor.java +++ b/extensions/hibernate-reactive/deployment/src/main/java/io/quarkus/hibernate/reactive/deployment/HibernateReactiveProcessor.java @@ -148,8 +148,9 @@ public void buildReactivePersistenceUnit( curateOutcomeBuildItem); if (dbKindOptional.isPresent()) { final String dbKind = dbKindOptional.get(); + HibernateOrmConfigPersistenceUnit persistenceUnitConfig = hibernateOrmConfig.defaultPersistenceUnit; ParsedPersistenceXmlDescriptor reactivePU = generateReactivePersistenceUnit( - hibernateOrmConfig, jpaModel, + hibernateOrmConfig, persistenceUnitConfig, jpaModel, dbKind, applicationArchivesBuildItem, launchMode.getLaunchMode(), systemProperties, nativeImageResources, hotDeploymentWatchedFiles, dbKindDialectBuildItems); @@ -159,6 +160,7 @@ public void buildReactivePersistenceUnit( // - we don't support Hibernate Envers with Hibernate Reactive persistenceUnitDescriptors.produce(new PersistenceUnitDescriptorBuildItem(reactivePU, jpaModel.getXmlMappings(reactivePU.getName()), + persistenceUnitConfig.unsupportedProperties, true, false)); } @@ -197,6 +199,7 @@ PersistenceProviderSetUpBuildItem setUpPersistenceProviderAndWaitForVertxPool(Hi */ private static ParsedPersistenceXmlDescriptor generateReactivePersistenceUnit( HibernateOrmConfig hibernateOrmConfig, + HibernateOrmConfigPersistenceUnit persistenceUnitConfig, JpaModelBuildItem jpaModel, String dbKind, ApplicationArchivesBuildItem applicationArchivesBuildItem, @@ -205,9 +208,6 @@ private static ParsedPersistenceXmlDescriptor generateReactivePersistenceUnit( BuildProducer nativeImageResources, BuildProducer hotDeploymentWatchedFiles, List dbKindDialectBuildItems) { - - HibernateOrmConfigPersistenceUnit persistenceUnitConfig = hibernateOrmConfig.defaultPersistenceUnit; - //we have no persistence.xml so we will create a default one String persistenceUnitConfigName = PersistenceUnitUtil.DEFAULT_PERSISTENCE_UNIT_NAME; diff --git a/test-framework/junit5-internal/src/main/java/io/quarkus/test/QuarkusUnitTest.java b/test-framework/junit5-internal/src/main/java/io/quarkus/test/QuarkusUnitTest.java index a934f6c5a69d6..9ab4fd658eb7e 100644 --- a/test-framework/junit5-internal/src/main/java/io/quarkus/test/QuarkusUnitTest.java +++ b/test-framework/junit5-internal/src/main/java/io/quarkus/test/QuarkusUnitTest.java @@ -19,6 +19,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -112,6 +113,7 @@ public class QuarkusUnitTest private Timer timeoutTimer; private volatile TimerTask timeoutTask; private Properties customApplicationProperties; + private Map customRuntimeApplicationProperties; private Runnable beforeAllCustomizer; private Runnable afterAllCustomizer; private CuratedApplication curatedApplication; @@ -631,7 +633,11 @@ public boolean test(String s) { StartupActionImpl startupAction = new AugmentActionImpl(curatedApplication, customizers, classLoadListeners) .createInitialRuntimeApplication(); - startupAction.overrideConfig(testResourceManager.getConfigProperties()); + Map overriddenConfig = new HashMap<>(testResourceManager.getConfigProperties()); + if (customRuntimeApplicationProperties != null) { + overriddenConfig.putAll(customRuntimeApplicationProperties); + } + startupAction.overrideConfig(overriddenConfig); runningQuarkusApplication = startupAction .run(commandLineParameters); //we restore the CL at the end of the test @@ -815,6 +821,14 @@ public QuarkusUnitTest overrideConfigKey(final String propertyKey, final String return this; } + public QuarkusUnitTest overrideRuntimeConfigKey(final String propertyKey, final String propertyValue) { + if (customRuntimeApplicationProperties == null) { + customRuntimeApplicationProperties = new HashMap<>(); + } + customRuntimeApplicationProperties.put(propertyKey, propertyValue); + return this; + } + @Override public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {