From ae220809d8d93b0fc7388cc31c4965f26f096cb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Wed, 21 Jun 2023 16:02:39 +0200 Subject: [PATCH 1/6] Upgrade to Hibernate Search 6.2.0.CR1 --- bom/application/pom.xml | 40 +++++++- .../hibernate-search-orm-elasticsearch.adoc | 14 +-- ...HibernateSearchElasticsearchProcessor.java | 3 +- ...tion-multiple-persistence-units.properties | 6 +- .../src/test/resources/application.properties | 2 +- .../HibernateSearchElasticsearchRecorder.java | 16 +++- ...ticsearchRuntimeConfigPersistenceUnit.java | 93 +++++++++++++++---- .../graal/Substitute_JandexBehavior.java | 20 ++++ ...usHibernateOrmSearchMappingConfigurer.java | 15 +++ .../src/main/resources/application.properties | 2 +- .../analysis/AnalysisTestResource.java | 4 +- .../search/HibernateSearchTestResource.java | 3 +- .../src/main/resources/application.properties | 2 +- .../search/HibernateSearchTestResource.java | 3 +- .../src/main/resources/application.properties | 2 +- 15 files changed, 184 insertions(+), 41 deletions(-) create mode 100644 extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/graal/Substitute_JandexBehavior.java create mode 100644 extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/mapping/QuarkusHibernateOrmSearchMappingConfigurer.java diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 298dea4478b0d..327d075439792 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -102,7 +102,7 @@ 6.0.6.Final 2.0.1.Final 8.0.1.Final - 6.1.7.Final + 6.2.0.CR1 6.0.1.Final 2.1 8.0.0.Final @@ -5615,22 +5615,60 @@ org.hibernate.common hibernate-commons-annotations + + + io.smallrye + jandex + org.hibernate.search hibernate-search-engine ${hibernate-search.version} + + + + org.jboss + jandex + + + io.smallrye + jandex + + org.hibernate.search hibernate-search-mapper-pojo-base ${hibernate-search.version} + + + + org.jboss + jandex + + + io.smallrye + jandex + + org.hibernate.search hibernate-search-util-common ${hibernate-search.version} + + + + org.jboss + jandex + + + io.smallrye + jandex + + org.postgresql diff --git a/docs/src/main/asciidoc/hibernate-search-orm-elasticsearch.adoc b/docs/src/main/asciidoc/hibernate-search-orm-elasticsearch.adoc index 8efaba28138cf..ccb9141b1c407 100644 --- a/docs/src/main/asciidoc/hibernate-search-orm-elasticsearch.adoc +++ b/docs/src/main/asciidoc/hibernate-search-orm-elasticsearch.adoc @@ -4,7 +4,7 @@ and pull requests should be submitted there: https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc //// = Hibernate Search guide -:hibernate-search-doc-prefix: https://docs.jboss.org/hibernate/search/6.1/reference/en-US/html_single/ +:hibernate-search-doc-prefix: https://docs.jboss.org/hibernate/search/6.2/reference/en-US/html_single/ include::_attributes.adoc[] :categories: data :summary: Hibernate Search allows you to index your entities in an Elasticsearch cluster and easily offer full text search in all your Hibernate ORM-based applications. @@ -566,7 +566,7 @@ quarkus.datasource.db-kind=postgresql <2> quarkus.hibernate-orm.sql-load-script=import.sql <3> quarkus.hibernate-search-orm.elasticsearch.version=7 <4> -quarkus.hibernate-search-orm.automatic-indexing.synchronization.strategy=sync <5> +quarkus.hibernate-search-orm.indexing.plan.synchronization.strategy=sync <5> %prod.quarkus.datasource.jdbc.url=jdbc:postgresql://localhost/quarkus_test <6> %prod.quarkus.datasource.username=quarkus_test @@ -701,7 +701,7 @@ quarkus.hibernate-search-orm.elasticsearch.version=opensearch:1.2 All other configuration options and APIs are exactly the same as with Elasticsearch. You can find more information about compatible distributions and versions of Elasticsearch in -link:{hibernate-search-doc-prefix}#getting-started-compatibility[this section of Hibernate Search's reference documentation]. +link:{hibernate-search-doc-prefix}#compatibility[this section of Hibernate Search's reference documentation]. [[multiple-persistence-units]] == Multiple persistence units @@ -849,7 +849,7 @@ If you disable automatic schema creation by setting `quarkus.hibernate-search-or you will have to create the schema manually at some point before your application starts persisting/updating entities and executing search requests. -See link:{hibernate-search-doc-prefix}#mapper-orm-schema-management-manager[this section of the reference documentation] +See link:{hibernate-search-doc-prefix}#schema-management-manager[this section of the reference documentation] for more information. ==== @@ -876,7 +876,7 @@ These limitations are the result of Hibernate Search not coordinating between th In order to get rid of these limitations, you can link:{hibernate-search-doc-prefix}#architecture-examples-outbox-polling-elasticsearch[use the `outbox-polling` coordination strategy]. This strategy creates an outbox table in the database to push entity change events to, -and relies on a background processor to consume these events and perform automatic indexing. +and relies on a background processor to consume these events and perform indexing. To enable the `outbox-polling` coordination strategy, an additional extension is required: @@ -910,7 +910,7 @@ However, there is one key difference: index updates are necessarily asynchronous they are guaranteed to happen _eventually_, but not immediately. This means in particular that the configuration property -link:#quarkus-hibernate-search-orm-elasticsearch_quarkus.hibernate-search-orm.automatic-indexing.synchronization.strategy[`quarkus.hibernate-search-orm.automatic-indexing.synchronization.strategy`] +link:#quarkus-hibernate-search-orm-elasticsearch_quarkus.hibernate-search-orm.indexing.plan.synchronization.strategy[`quarkus.hibernate-search-orm.indexing.plan.synchronization.strategy`] cannot be set when using the `outbox-polling` coordination strategy: Hibernate Search will always behave as if this property was set to `write-sync` (the default). @@ -976,7 +976,7 @@ For example `class:com.mycompany.MyClass`. * An arbitrary string referencing a built-in implementation. Available values are detailed in the documentation of each configuration property, such as `async`/`read-sync`/`write-sync`/`sync` for -<>. +<>. Other formats are also accepted, but are only useful for advanced use cases. See link:{hibernate-search-doc-prefix}#configuration-bean-reference-parsing[this section of Hibernate Search's reference documentation] diff --git a/extensions/hibernate-search-orm-elasticsearch/deployment/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/deployment/HibernateSearchElasticsearchProcessor.java b/extensions/hibernate-search-orm-elasticsearch/deployment/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/deployment/HibernateSearchElasticsearchProcessor.java index e667ce91a8571..5d6ec81dca53a 100644 --- a/extensions/hibernate-search-orm-elasticsearch/deployment/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/deployment/HibernateSearchElasticsearchProcessor.java +++ b/extensions/hibernate-search-orm-elasticsearch/deployment/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/deployment/HibernateSearchElasticsearchProcessor.java @@ -26,6 +26,7 @@ import org.hibernate.search.backend.elasticsearch.index.layout.IndexLayoutStrategy; import org.hibernate.search.engine.reporting.FailureHandler; import org.hibernate.search.mapper.orm.automaticindexing.session.AutomaticIndexingSynchronizationStrategy; +import org.hibernate.search.mapper.pojo.work.IndexingPlanSynchronizationStrategy; import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.AnnotationValue; import org.jboss.jandex.IndexView; @@ -167,7 +168,7 @@ void registerBeans(List propertyCollecto buildTimeConfig == null ? Optional.empty() : buildTimeConfig.backgroundFailureHandler(), FailureHandler.class, persistenceUnitName, null, null)); + addConfig(propertyCollector, + HibernateOrmMapperSettings.MAPPING_CONFIGURER, + new QuarkusHibernateOrmSearchMappingConfigurer()); + addConfig(propertyCollector, HibernateOrmMapperSettings.COORDINATION_STRATEGY, HibernateSearchBeanUtil.singleExtensionBeanReferenceFor( @@ -227,7 +233,7 @@ public void onMetadataInitialized(Metadata metadata, BootstrapContext bootstrapC BiConsumer propertyCollector) { HibernateOrmIntegrationBooter booter = HibernateOrmIntegrationBooter.builder(metadata, bootstrapContext) // MethodHandles don't work at all in GraalVM 20 and below, and seem unreliable on GraalVM 21 - .valueReadHandleFactory(ValueReadHandleFactory.usingJavaLangReflect()) + .valueReadHandleFactory(ValueHandleFactory.usingJavaLangReflect()) .build(); booter.preBoot(propertyCollector); @@ -352,6 +358,12 @@ public void contributeRuntimeProperties(BiConsumer propertyColle runtimeConfig.multiTenancy().tenantIds()); } + addConfig(propertyCollector, + HibernateOrmMapperSettings.INDEXING_PLAN_SYNCHRONIZATION_STRATEGY, + HibernateSearchBeanUtil.singleExtensionBeanReferenceFor( + runtimeConfig == null ? Optional.empty() + : runtimeConfig.indexing().plan().synchronization().strategy(), + IndexingPlanSynchronizationStrategy.class, persistenceUnitName, null, null)); addConfig(propertyCollector, HibernateOrmMapperSettings.AUTOMATIC_INDEXING_SYNCHRONIZATION_STRATEGY, HibernateSearchBeanUtil.singleExtensionBeanReferenceFor( diff --git a/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/HibernateSearchElasticsearchRuntimeConfigPersistenceUnit.java b/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/HibernateSearchElasticsearchRuntimeConfigPersistenceUnit.java index a0c0744352bd7..6732df9ed16a9 100644 --- a/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/HibernateSearchElasticsearchRuntimeConfigPersistenceUnit.java +++ b/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/HibernateSearchElasticsearchRuntimeConfigPersistenceUnit.java @@ -67,8 +67,16 @@ public interface HibernateSearchElasticsearchRuntimeConfigPersistenceUnit { SearchQueryLoadingConfig queryLoading(); /** - * Configuration for the automatic indexing. + * Configuration for indexing. */ + IndexingConfig indexing(); + + /** + * Configuration for automatic indexing. + * + * @deprecated Use {@link #indexing()} instead. + */ + @Deprecated AutomaticIndexingConfig automaticIndexing(); /** @@ -256,31 +264,41 @@ public interface DiscoveryConfig { } @ConfigGroup - public interface AutomaticIndexingConfig { + interface IndexingConfig { /** - * Configuration for synchronization with the index when indexing automatically. + * Configuration for indexing plans. */ - AutomaticIndexingSynchronizationConfig synchronization(); + IndexingPlanConfig plan(); + + } + + // Having a dedicated config group class feels a bit unnecessary + // because we could just use @WithName("plan.synchronization.strategy") + // but that leads to bugs + // see https://github.com/quarkusio/quarkus/pull/34251#issuecomment-1611273375 + @ConfigGroup + interface IndexingPlanConfig { /** - * Whether to check if dirty properties are relevant to indexing before actually reindexing an entity. - * - * When enabled, re-indexing of an entity is skipped if the only changes are on properties that are not used when - * indexing. - * - * @asciidoclet + * Configuration for indexing plan synchronization. */ - @WithDefault("true") - boolean enableDirtyCheck(); + IndexingPlanSynchronizationConfig synchronization(); + } + // Having a dedicated config group class feels a bit unnecessary + // because we could just use @WithName("plan.synchronization.strategy") + // but that leads to bugs + // see https://github.com/quarkusio/quarkus/pull/34251#issuecomment-1611273375 @ConfigGroup - public interface AutomaticIndexingSynchronizationConfig { + interface IndexingPlanSynchronizationConfig { // @formatter:off /** - * The synchronization strategy to use when indexing automatically. + * How to synchronize between application threads and indexing, + * in particular when relying on (implicit) listener-triggered indexing on entity change, + * but also when using a `SearchIndexingPlan` explicitly. * * Defines how complete indexing should be before resuming the application thread * after a database transaction is committed. @@ -332,16 +350,16 @@ public interface AutomaticIndexingSynchronizationConfig { * !=== * * This property also accepts a xref:hibernate-search-orm-elasticsearch.adoc#bean-reference-note-anchor[bean reference] - * to a custom implementations of `AutomaticIndexingSynchronizationStrategy`. + * to a custom implementations of `IndexingPlanSynchronizationStrategy`. * * See - * link:{hibernate-search-doc-prefix}#mapper-orm-indexing-automatic-synchronization[this section of the reference documentation] + * link:{hibernate-search-doc-prefix}#indexing-plan-synchronization[this section of the reference documentation] * for more information. * * [NOTE] * ==== * Instead of setting this configuration property, - * you can simply annotate your custom `AutomaticIndexingSynchronizationStrategy` implementation with `@SearchExtension` + * you can simply annotate your custom `IndexingPlanSynchronizationStrategy` implementation with `@SearchExtension` * and leave the configuration property unset: Hibernate Search will use the annotated implementation automatically. * If this configuration property is set, it takes precedence over any `@SearchExtension` annotation. * ==== @@ -351,6 +369,47 @@ public interface AutomaticIndexingSynchronizationConfig { // @formatter:on @ConfigDocDefault("write-sync") Optional strategy(); + + } + + @ConfigGroup + @Deprecated + public interface AutomaticIndexingConfig { + + /** + * Configuration for synchronization with the index when indexing automatically. + * + * @deprecated Use {@code quarkus.hibernate-search-orm.indexing.plan.synchronization.strategy} instead. + */ + AutomaticIndexingSynchronizationConfig synchronization(); + + /** + * Whether to check if dirty properties are relevant to indexing before actually reindexing an entity. + *

+ * When enabled, re-indexing of an entity is skipped if the only changes are on properties that are not used when + * indexing. + * + * @deprecated This property is deprecated with no alternative to replace it. + * In the future, a dirty check will always be performed when considering whether to trigger reindexing. + */ + @WithDefault("true") + @Deprecated + boolean enableDirtyCheck(); + } + + @ConfigGroup + @Deprecated + public interface AutomaticIndexingSynchronizationConfig { + + // @formatter:off + /** + * The synchronization strategy to use when indexing automatically. + * + * @deprecated Use {@code quarkus.hibernate-search-orm.indexing.plan.synchronization.strategy} instead. + */ + // @formatter:on + @ConfigDocDefault("write-sync") + Optional strategy(); } @ConfigGroup diff --git a/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/graal/Substitute_JandexBehavior.java b/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/graal/Substitute_JandexBehavior.java new file mode 100644 index 0000000000000..18bfe47e63283 --- /dev/null +++ b/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/graal/Substitute_JandexBehavior.java @@ -0,0 +1,20 @@ +package io.quarkus.hibernate.search.orm.elasticsearch.runtime.graal; + +import org.hibernate.search.util.common.jar.spi.JandexBehavior; + +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.annotate.TargetClass; + +/** + * Disallow the use of Jandex so that relevant code can be DCEd + * (otherwise compilation would fail as Jandex is not available at runtime). + */ +@TargetClass(className = "org.hibernate.search.util.common.jar.spi.JandexBehavior") +final class Substitute_JandexBehavior { + + @Substitute + public static T doWithJandex(JandexBehavior.JandexOperation operation) { + throw new IllegalStateException("Jandex should not be used at runtime."); + } + +} diff --git a/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/mapping/QuarkusHibernateOrmSearchMappingConfigurer.java b/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/mapping/QuarkusHibernateOrmSearchMappingConfigurer.java new file mode 100644 index 0000000000000..9e507ee5cde3b --- /dev/null +++ b/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/mapping/QuarkusHibernateOrmSearchMappingConfigurer.java @@ -0,0 +1,15 @@ +package io.quarkus.hibernate.search.orm.elasticsearch.runtime.mapping; + +import org.hibernate.search.mapper.orm.mapping.HibernateOrmMappingConfigurationContext; +import org.hibernate.search.mapper.orm.mapping.HibernateOrmSearchMappingConfigurer; + +public class QuarkusHibernateOrmSearchMappingConfigurer implements HibernateOrmSearchMappingConfigurer { + @Override + public void configure(HibernateOrmMappingConfigurationContext context) { + // Jandex is not available at runtime in Quarkus, + // so Hibernate Search cannot perform classpath scanning on startup. + context.annotationMapping() + .discoverJandexIndexesFromAddedTypes(false) + .buildMissingDiscoveredJandexIndexes(false); + } +} diff --git a/integration-tests/hibernate-search-orm-elasticsearch-tenancy/src/main/resources/application.properties b/integration-tests/hibernate-search-orm-elasticsearch-tenancy/src/main/resources/application.properties index 5d65ebe36f89a..5e1f036cd0987 100644 --- a/integration-tests/hibernate-search-orm-elasticsearch-tenancy/src/main/resources/application.properties +++ b/integration-tests/hibernate-search-orm-elasticsearch-tenancy/src/main/resources/application.properties @@ -10,4 +10,4 @@ quarkus.hibernate-search-orm.elasticsearch.version=7 quarkus.hibernate-search-orm.elasticsearch.hosts=${elasticsearch.hosts:localhost:9200} quarkus.hibernate-search-orm.elasticsearch.protocol=${elasticsearch.protocol:http} quarkus.hibernate-search-orm.schema-management.strategy=drop-and-create-and-drop -quarkus.hibernate-search-orm.automatic-indexing.synchronization.strategy=sync +quarkus.hibernate-search-orm.indexing.plan.synchronization.strategy=sync diff --git a/integration-tests/hibernate-search-orm-elasticsearch/src/main/java/io/quarkus/it/hibernate/search/orm/elasticsearch/analysis/AnalysisTestResource.java b/integration-tests/hibernate-search-orm-elasticsearch/src/main/java/io/quarkus/it/hibernate/search/orm/elasticsearch/analysis/AnalysisTestResource.java index 8860b69cf88e3..2932dc8e44c6e 100644 --- a/integration-tests/hibernate-search-orm-elasticsearch/src/main/java/io/quarkus/it/hibernate/search/orm/elasticsearch/analysis/AnalysisTestResource.java +++ b/integration-tests/hibernate-search-orm-elasticsearch/src/main/java/io/quarkus/it/hibernate/search/orm/elasticsearch/analysis/AnalysisTestResource.java @@ -13,8 +13,8 @@ import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; +import org.hibernate.search.engine.common.EntityReference; import org.hibernate.search.mapper.orm.Search; -import org.hibernate.search.mapper.orm.common.EntityReference; import org.hibernate.search.mapper.orm.session.SearchSession; import org.jboss.resteasy.annotations.jaxrs.QueryParam; @@ -65,7 +65,7 @@ public String testAnalysisConfigured() { public List> findTypesMatching(@QueryParam String field, @QueryParam String term) { SearchSession searchSession = Search.session(entityManager); return searchSession.search(AnalysisTestingEntityBase.class) - .> select(f -> f.composite(EntityReference::type, f.entityReference())) + .> select(f -> f.composite().from(f.entityReference()).as(EntityReference::type)) .where(f -> f.match().field(field).matching(term).skipAnalysis()) .fetchAllHits(); } diff --git a/integration-tests/hibernate-search-orm-elasticsearch/src/main/java/io/quarkus/it/hibernate/search/orm/elasticsearch/search/HibernateSearchTestResource.java b/integration-tests/hibernate-search-orm-elasticsearch/src/main/java/io/quarkus/it/hibernate/search/orm/elasticsearch/search/HibernateSearchTestResource.java index a0b0d5c4b1fe7..1fe629fa7c868 100644 --- a/integration-tests/hibernate-search-orm-elasticsearch/src/main/java/io/quarkus/it/hibernate/search/orm/elasticsearch/search/HibernateSearchTestResource.java +++ b/integration-tests/hibernate-search-orm-elasticsearch/src/main/java/io/quarkus/it/hibernate/search/orm/elasticsearch/search/HibernateSearchTestResource.java @@ -54,8 +54,7 @@ public String testSearch() { assertEquals("John Irving", person.get(1).getName()); person = searchSession.search(Person.class) - .where(f -> f.nested().objectField("address").nest( - f.match().field("address.city").matching("london"))) + .where(f -> f.match().field("address.city").matching("london")) .sort(f -> f.field("name_sort")) .fetchHits(20); diff --git a/integration-tests/hibernate-search-orm-elasticsearch/src/main/resources/application.properties b/integration-tests/hibernate-search-orm-elasticsearch/src/main/resources/application.properties index 79f8ce7b2739d..5d6c5b394c047 100644 --- a/integration-tests/hibernate-search-orm-elasticsearch/src/main/resources/application.properties +++ b/integration-tests/hibernate-search-orm-elasticsearch/src/main/resources/application.properties @@ -12,7 +12,7 @@ quarkus.hibernate-search-orm.elasticsearch.indexes.Analysis2TestingEntity.analys quarkus.hibernate-search-orm.elasticsearch.indexes.Analysis3TestingEntity.analysis.configurer=io.quarkus.it.hibernate.search.orm.elasticsearch.analysis.IndexAnalysis3Configurer quarkus.hibernate-search-orm.elasticsearch.indexes.Analysis4TestingEntity.analysis.configurer=index-analysis-4 quarkus.hibernate-search-orm.elasticsearch.indexes.Analysis5TestingEntity.analysis.configurer=io.quarkus.it.hibernate.search.orm.elasticsearch.analysis.IndexAnalysis5Configurer -quarkus.hibernate-search-orm.automatic-indexing.synchronization.strategy=sync +quarkus.hibernate-search-orm.indexing.plan.synchronization.strategy=sync # Use drop-and-create instead of drop-and-create-and-drop # so we can differentiate between the value we set here diff --git a/integration-tests/hibernate-search-orm-opensearch/src/main/java/io/quarkus/it/hibernate/search/orm/opensearch/search/HibernateSearchTestResource.java b/integration-tests/hibernate-search-orm-opensearch/src/main/java/io/quarkus/it/hibernate/search/orm/opensearch/search/HibernateSearchTestResource.java index f1efb48a0e17c..f4d47b755ca56 100644 --- a/integration-tests/hibernate-search-orm-opensearch/src/main/java/io/quarkus/it/hibernate/search/orm/opensearch/search/HibernateSearchTestResource.java +++ b/integration-tests/hibernate-search-orm-opensearch/src/main/java/io/quarkus/it/hibernate/search/orm/opensearch/search/HibernateSearchTestResource.java @@ -54,8 +54,7 @@ public String testSearch() { assertEquals("John Irving", person.get(1).getName()); person = searchSession.search(Person.class) - .where(f -> f.nested().objectField("address").nest( - f.match().field("address.city").matching("london"))) + .where(f -> f.match().field("address.city").matching("london")) .sort(f -> f.field("name_sort")) .fetchHits(20); diff --git a/integration-tests/hibernate-search-orm-opensearch/src/main/resources/application.properties b/integration-tests/hibernate-search-orm-opensearch/src/main/resources/application.properties index f5c18a350c7e6..94c13ed99e2e1 100644 --- a/integration-tests/hibernate-search-orm-opensearch/src/main/resources/application.properties +++ b/integration-tests/hibernate-search-orm-opensearch/src/main/resources/application.properties @@ -11,4 +11,4 @@ quarkus.hibernate-search-orm.elasticsearch.hosts=${opensearch.hosts:localhost:92 quarkus.hibernate-search-orm.elasticsearch.protocol=${opensearch.protocol:http} quarkus.hibernate-search-orm.elasticsearch.analysis.configurer=bean:backend-analysis quarkus.hibernate-search-orm.schema-management.strategy=drop-and-create-and-drop -quarkus.hibernate-search-orm.automatic-indexing.synchronization.strategy=sync +quarkus.hibernate-search-orm.indexing.plan.synchronization.strategy=sync From 4e4c49f8efcee0e3253913f1ff452254ac7326d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Thu, 22 Jun 2023 11:01:55 +0200 Subject: [PATCH 2/6] Hibernate Search: Allow multiple Elasticsearch analysis configurers in settings As Hibernate Search now allows it. --- ...csearchBuildTimeConfigPersistenceUnit.java | 13 +++++---- .../HibernateSearchElasticsearchRecorder.java | 2 +- .../runtime/bean/ArcBeanReference.java | 13 +++++---- .../runtime/bean/HibernateSearchBeanUtil.java | 28 ++++++++++++++++++- 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/HibernateSearchElasticsearchBuildTimeConfigPersistenceUnit.java b/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/HibernateSearchElasticsearchBuildTimeConfigPersistenceUnit.java index 5dabad2197f33..b1924c7844759 100644 --- a/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/HibernateSearchElasticsearchBuildTimeConfigPersistenceUnit.java +++ b/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/HibernateSearchElasticsearchBuildTimeConfigPersistenceUnit.java @@ -1,6 +1,7 @@ package io.quarkus.hibernate.search.orm.elasticsearch.runtime; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.Optional; @@ -165,12 +166,12 @@ public interface SchemaManagementConfig { } @ConfigGroup - public interface AnalysisConfig { + interface AnalysisConfig { /** - * A xref:hibernate-search-orm-elasticsearch.adoc#bean-reference-note-anchor[bean reference] to the component - * used to configure full text analysis (e.g. analyzers, normalizers). + * One or more xref:hibernate-search-orm-elasticsearch.adoc#bean-reference-note-anchor[bean references] + * to the component(s) used to configure full text analysis (e.g. analyzers, normalizers). * - * The referenced bean must implement `ElasticsearchAnalysisConfigurer`. + * The referenced beans must implement `ElasticsearchAnalysisConfigurer`. * * See xref:hibernate-search-orm-elasticsearch.adoc#analysis-configurer[Setting up the analyzers] for more * information. @@ -178,14 +179,14 @@ public interface AnalysisConfig { * [NOTE] * ==== * Instead of setting this configuration property, - * you can simply annotate your custom `ElasticsearchAnalysisConfigurer` implementation with `@SearchExtension` + * you can simply annotate your custom `ElasticsearchAnalysisConfigurer` implementations with `@SearchExtension` * and leave the configuration property unset: Hibernate Search will use the annotated implementation automatically. * If this configuration property is set, it takes precedence over any `@SearchExtension` annotation. * ==== * * @asciidoclet */ - Optional configurer(); + Optional> configurer(); } @ConfigGroup diff --git a/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/HibernateSearchElasticsearchRecorder.java b/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/HibernateSearchElasticsearchRecorder.java index 92ac85f478d5d..0585b18a60650 100644 --- a/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/HibernateSearchElasticsearchRecorder.java +++ b/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/HibernateSearchElasticsearchRecorder.java @@ -286,7 +286,7 @@ private void contributeBackendIndexBuildTimeProperties(BiConsumer implements BeanReference { - private final InjectableInstance delegate; + private final InjectableBean bean; - public ArcBeanReference(InjectableInstance delegate) { - this.delegate = delegate; + public ArcBeanReference(InjectableBean bean) { + this.bean = bean; } @Override public String toString() { - return getClass().getSimpleName() + "[" + delegate.toString() + "]"; + return getClass().getSimpleName() + "[" + bean.toString() + "]"; } @Override public BeanHolder resolve(BeanResolver beanResolver) { - return new ArcBeanHolder<>(delegate.getHandle()); + return new ArcBeanHolder<>(Arc.container().instance(bean)); } } diff --git a/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/bean/HibernateSearchBeanUtil.java b/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/bean/HibernateSearchBeanUtil.java index 5590316d3d07d..734a4ce827772 100644 --- a/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/bean/HibernateSearchBeanUtil.java +++ b/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/bean/HibernateSearchBeanUtil.java @@ -1,12 +1,16 @@ package io.quarkus.hibernate.search.orm.elasticsearch.runtime.bean; +import java.util.ArrayList; +import java.util.List; import java.util.Locale; import java.util.Optional; +import java.util.stream.Collectors; import org.hibernate.search.engine.environment.bean.BeanReference; import io.quarkus.arc.Arc; import io.quarkus.arc.InjectableInstance; +import io.quarkus.arc.InstanceHandle; import io.quarkus.hibernate.search.orm.elasticsearch.SearchExtension; public final class HibernateSearchBeanUtil { @@ -41,7 +45,29 @@ private static Optional> singleExtensionBeanReferenceFor(Cl beanType.getSimpleName(), persistenceUnitName)); } } - return instance.isResolvable() ? Optional.of(new ArcBeanReference<>(instance)) : Optional.empty(); + return instance.isResolvable() ? Optional.of(new ArcBeanReference<>(instance.getHandle().getBean())) : Optional.empty(); + } + + public static Optional>> multiExtensionBeanReferencesFor(Optional> override, + Class beanType, + String persistenceUnitName, String backendName, String indexName) { + return override.map(strings -> strings.stream() + .map(string -> BeanReference.parse(beanType, string)) + .collect(Collectors.toList())) + .or(() -> multiExtensionBeanReferencesFor(beanType, persistenceUnitName, backendName, indexName)); + } + + private static Optional>> multiExtensionBeanReferencesFor(Class beanType, + String persistenceUnitName, String backendName, String indexName) { + InjectableInstance instance = extensionInstanceFor(beanType, persistenceUnitName, backendName, indexName); + if (!instance.isResolvable()) { + return Optional.empty(); + } + List> references = new ArrayList<>(); + for (InstanceHandle handle : instance.handles()) { + references.add(new ArcBeanReference<>(handle.getBean())); + } + return Optional.of(references); } public static InjectableInstance extensionInstanceFor(Class beanType, String persistenceUnitName, From 87704762430e413fb25454e6cb56e11749ce5cc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Thu, 22 Jun 2023 14:33:58 +0200 Subject: [PATCH 3/6] Hibernate Search: Add support for projection constructors --- .../elasticsearch/deployment/ClassNames.java | 5 +++ ...HibernateSearchElasticsearchProcessor.java | 34 +++++++++++++++++++ .../HibernateSearchElasticsearchRecorder.java | 18 ++++++++-- ...usHibernateOrmSearchMappingConfigurer.java | 12 +++++++ .../orm/elasticsearch/search/AddressDTO.java | 20 +++++++++++ .../search/HibernateSearchTestResource.java | 20 +++++++++++ .../orm/elasticsearch/search/PersonDTO.java | 27 +++++++++++++++ .../elasticsearch/HibernateSearchTest.java | 6 +++- 8 files changed, 139 insertions(+), 3 deletions(-) create mode 100644 integration-tests/hibernate-search-orm-elasticsearch/src/main/java/io/quarkus/it/hibernate/search/orm/elasticsearch/search/AddressDTO.java create mode 100644 integration-tests/hibernate-search-orm-elasticsearch/src/main/java/io/quarkus/it/hibernate/search/orm/elasticsearch/search/PersonDTO.java diff --git a/extensions/hibernate-search-orm-elasticsearch/deployment/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/deployment/ClassNames.java b/extensions/hibernate-search-orm-elasticsearch/deployment/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/deployment/ClassNames.java index 535a46c65a1d2..84551e8d6f797 100644 --- a/extensions/hibernate-search-orm-elasticsearch/deployment/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/deployment/ClassNames.java +++ b/extensions/hibernate-search-orm-elasticsearch/deployment/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/deployment/ClassNames.java @@ -9,4 +9,9 @@ class ClassNames { static final DotName INDEXED = DotName .createSimple("org.hibernate.search.mapper.pojo.mapping.definition.annotation.Indexed"); + static final DotName ROOT_MAPPING = DotName + .createSimple("org.hibernate.search.mapper.pojo.mapping.definition.annotation.processing.RootMapping"); + static final DotName PROJECTION_CONSTRUCTOR = DotName + .createSimple("org.hibernate.search.mapper.pojo.mapping.definition.annotation.ProjectionConstructor"); + } diff --git a/extensions/hibernate-search-orm-elasticsearch/deployment/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/deployment/HibernateSearchElasticsearchProcessor.java b/extensions/hibernate-search-orm-elasticsearch/deployment/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/deployment/HibernateSearchElasticsearchProcessor.java index 5d6ec81dca53a..04812d7882e1e 100644 --- a/extensions/hibernate-search-orm-elasticsearch/deployment/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/deployment/HibernateSearchElasticsearchProcessor.java +++ b/extensions/hibernate-search-orm-elasticsearch/deployment/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/deployment/HibernateSearchElasticsearchProcessor.java @@ -1,6 +1,8 @@ package io.quarkus.hibernate.search.orm.elasticsearch.deployment; import static io.quarkus.hibernate.search.orm.elasticsearch.deployment.ClassNames.INDEXED; +import static io.quarkus.hibernate.search.orm.elasticsearch.deployment.ClassNames.PROJECTION_CONSTRUCTOR; +import static io.quarkus.hibernate.search.orm.elasticsearch.deployment.ClassNames.ROOT_MAPPING; import static io.quarkus.hibernate.search.orm.elasticsearch.runtime.HibernateSearchElasticsearchRuntimeConfig.backendPropertyKey; import static io.quarkus.hibernate.search.orm.elasticsearch.runtime.HibernateSearchElasticsearchRuntimeConfig.defaultBackendPropertyKeys; import static io.quarkus.hibernate.search.orm.elasticsearch.runtime.HibernateSearchElasticsearchRuntimeConfig.elasticsearchVersionPropertyKey; @@ -29,6 +31,7 @@ import org.hibernate.search.mapper.pojo.work.IndexingPlanSynchronizationStrategy; import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.AnnotationValue; +import org.jboss.jandex.DotName; import org.jboss.jandex.IndexView; import org.jboss.logging.Logger; @@ -46,6 +49,7 @@ import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem; import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; import io.quarkus.deployment.recording.RecorderContext; +import io.quarkus.deployment.util.JandexUtil; import io.quarkus.elasticsearch.restclient.common.deployment.DevservicesElasticsearchBuildItem; import io.quarkus.hibernate.orm.deployment.PersistenceUnitDescriptorBuildItem; import io.quarkus.hibernate.orm.deployment.integration.HibernateOrmIntegrationRuntimeConfiguredBuildItem; @@ -175,6 +179,7 @@ void registerBeans(List integrationStaticConfigBuildItems, List configuredPersistenceUnits, HibernateSearchElasticsearchBuildTimeConfig buildTimeConfig, @@ -183,6 +188,9 @@ void setStaticConfig(RecorderContext recorderContext, HibernateSearchElasticsear recorderContext.registerSubstitution(ElasticsearchVersion.class, String.class, ElasticsearchVersionSubstitution.class); + IndexView index = combinedIndexBuildItem.getIndex(); + Set rootAnnotationMappedClassNames = collectRootAnnotationMappedClassNames(index); + for (HibernateSearchElasticsearchPersistenceUnitConfiguredBuildItem configuredPersistenceUnit : configuredPersistenceUnits) { String puName = configuredPersistenceUnit.getPersistenceUnitName(); List integrationStaticInitListeners = new ArrayList<>(); @@ -204,11 +212,37 @@ void setStaticConfig(RecorderContext recorderContext, HibernateSearchElasticsear // we cannot pass a config group to a recorder so passing the whole config recorder.createStaticInitListener(puName, buildTimeConfig, configuredPersistenceUnit.getBackendAndIndexNamesForSearchExtensions(), + rootAnnotationMappedClassNames, integrationStaticInitListeners)) .setXmlMappingRequired(xmlMappingRequired)); } } + private static Set collectRootAnnotationMappedClassNames(IndexView index) { + // Look for classes annotated with annotations meta-annotated with @RootMapping: + // those classes will have their annotations processed on every persistence unit. + // At the moment only @ProjectionConstructor is meta-annotated with @RootMapping. + Set rootMappingAnnotationNames = new LinkedHashSet<>(); + // This is built into Hibernate Search, which may not be part of the index. + rootMappingAnnotationNames.add(PROJECTION_CONSTRUCTOR); + // Users can theoretically declare their own root mapping annotations + // (replacements for @ProjectionConstructor, for example), + // so we need to consider those as well. + for (AnnotationInstance rootMappingAnnotationInstance : index.getAnnotations(ROOT_MAPPING)) { + rootMappingAnnotationNames.add(rootMappingAnnotationInstance.target().asClass().name()); + } + + // We'll collect all classes annotated with "root mapping" annotations + // anywhere (type level, constructor, ...) + Set rootAnnotationMappedClassNames = new LinkedHashSet<>(); + for (DotName rootMappingAnnotationName : rootMappingAnnotationNames) { + for (AnnotationInstance annotation : index.getAnnotations(rootMappingAnnotationName)) { + rootAnnotationMappedClassNames.add(JandexUtil.getEnclosingClass(annotation).name().toString()); + } + } + return rootAnnotationMappedClassNames; + } + @BuildStep @Record(ExecutionTime.RUNTIME_INIT) void setRuntimeConfig(HibernateSearchElasticsearchRecorder recorder, diff --git a/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/HibernateSearchElasticsearchRecorder.java b/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/HibernateSearchElasticsearchRecorder.java index 0585b18a60650..c2ae0148cd63d 100644 --- a/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/HibernateSearchElasticsearchRecorder.java +++ b/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/HibernateSearchElasticsearchRecorder.java @@ -58,10 +58,21 @@ public class HibernateSearchElasticsearchRecorder { public HibernateOrmIntegrationStaticInitListener createStaticInitListener( String persistenceUnitName, HibernateSearchElasticsearchBuildTimeConfig buildTimeConfig, Map> backendAndIndexNamesForSearchExtensions, + Set rootAnnotationMappedClassNames, List integrationStaticInitListeners) { + Set> rootAnnotationMappedClasses = new LinkedHashSet<>(); + ClassLoader tccl = Thread.currentThread().getContextClassLoader(); + for (String className : rootAnnotationMappedClassNames) { + try { + rootAnnotationMappedClasses.add(Class.forName(className, true, tccl)); + } catch (Exception e) { + throw new IllegalStateException("Could not initialize mapped class " + className, e); + } + } return new HibernateSearchIntegrationStaticInitListener(persistenceUnitName, buildTimeConfig.getPersistenceUnitConfig(persistenceUnitName), - backendAndIndexNamesForSearchExtensions, integrationStaticInitListeners); + backendAndIndexNamesForSearchExtensions, rootAnnotationMappedClasses, + integrationStaticInitListeners); } public HibernateOrmIntegrationStaticInitListener createStaticInitInactiveListener() { @@ -173,15 +184,18 @@ private static final class HibernateSearchIntegrationStaticInitListener private final String persistenceUnitName; private final HibernateSearchElasticsearchBuildTimeConfigPersistenceUnit buildTimeConfig; private final Map> backendAndIndexNamesForSearchExtensions; + private final Set> rootAnnotationMappedClasses; private final List integrationStaticInitListeners; private HibernateSearchIntegrationStaticInitListener(String persistenceUnitName, HibernateSearchElasticsearchBuildTimeConfigPersistenceUnit buildTimeConfig, Map> backendAndIndexNamesForSearchExtensions, + Set> rootAnnotationMappedClasses, List integrationStaticInitListeners) { this.persistenceUnitName = persistenceUnitName; this.buildTimeConfig = buildTimeConfig; this.backendAndIndexNamesForSearchExtensions = backendAndIndexNamesForSearchExtensions; + this.rootAnnotationMappedClasses = rootAnnotationMappedClasses; this.integrationStaticInitListeners = integrationStaticInitListeners; } @@ -195,7 +209,7 @@ public void contributeBootProperties(BiConsumer propertyCollecto addConfig(propertyCollector, HibernateOrmMapperSettings.MAPPING_CONFIGURER, - new QuarkusHibernateOrmSearchMappingConfigurer()); + new QuarkusHibernateOrmSearchMappingConfigurer(rootAnnotationMappedClasses)); addConfig(propertyCollector, HibernateOrmMapperSettings.COORDINATION_STRATEGY, diff --git a/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/mapping/QuarkusHibernateOrmSearchMappingConfigurer.java b/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/mapping/QuarkusHibernateOrmSearchMappingConfigurer.java index 9e507ee5cde3b..709ea0ec29d1d 100644 --- a/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/mapping/QuarkusHibernateOrmSearchMappingConfigurer.java +++ b/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/mapping/QuarkusHibernateOrmSearchMappingConfigurer.java @@ -1,9 +1,17 @@ package io.quarkus.hibernate.search.orm.elasticsearch.runtime.mapping; +import java.util.Set; + import org.hibernate.search.mapper.orm.mapping.HibernateOrmMappingConfigurationContext; import org.hibernate.search.mapper.orm.mapping.HibernateOrmSearchMappingConfigurer; public class QuarkusHibernateOrmSearchMappingConfigurer implements HibernateOrmSearchMappingConfigurer { + private final Set> rootAnnotationMappedClasses; + + public QuarkusHibernateOrmSearchMappingConfigurer(Set> rootAnnotationMappedClasses) { + this.rootAnnotationMappedClasses = rootAnnotationMappedClasses; + } + @Override public void configure(HibernateOrmMappingConfigurationContext context) { // Jandex is not available at runtime in Quarkus, @@ -11,5 +19,9 @@ public void configure(HibernateOrmMappingConfigurationContext context) { context.annotationMapping() .discoverJandexIndexesFromAddedTypes(false) .buildMissingDiscoveredJandexIndexes(false); + + // ... but we do better: we perform classpath scanning during the build, + // and propagate the result here. + context.annotationMapping().add(rootAnnotationMappedClasses); } } diff --git a/integration-tests/hibernate-search-orm-elasticsearch/src/main/java/io/quarkus/it/hibernate/search/orm/elasticsearch/search/AddressDTO.java b/integration-tests/hibernate-search-orm-elasticsearch/src/main/java/io/quarkus/it/hibernate/search/orm/elasticsearch/search/AddressDTO.java new file mode 100644 index 0000000000000..91d343dd06567 --- /dev/null +++ b/integration-tests/hibernate-search-orm-elasticsearch/src/main/java/io/quarkus/it/hibernate/search/orm/elasticsearch/search/AddressDTO.java @@ -0,0 +1,20 @@ +package io.quarkus.it.hibernate.search.orm.elasticsearch.search; + +import org.hibernate.search.mapper.pojo.mapping.definition.annotation.ProjectionConstructor; + +// Ideally we'd use records, but Quarkus still has to compile with JDK 11 at the moment. +public class AddressDTO { + public final String city; + + @ProjectionConstructor + public AddressDTO(String city) { + this.city = city; + } + + @Override + public String toString() { + return "AddressDTO{" + + "city='" + city + '\'' + + '}'; + } +} diff --git a/integration-tests/hibernate-search-orm-elasticsearch/src/main/java/io/quarkus/it/hibernate/search/orm/elasticsearch/search/HibernateSearchTestResource.java b/integration-tests/hibernate-search-orm-elasticsearch/src/main/java/io/quarkus/it/hibernate/search/orm/elasticsearch/search/HibernateSearchTestResource.java index 1fe629fa7c868..a8207985b043b 100644 --- a/integration-tests/hibernate-search-orm-elasticsearch/src/main/java/io/quarkus/it/hibernate/search/orm/elasticsearch/search/HibernateSearchTestResource.java +++ b/integration-tests/hibernate-search-orm-elasticsearch/src/main/java/io/quarkus/it/hibernate/search/orm/elasticsearch/search/HibernateSearchTestResource.java @@ -1,5 +1,6 @@ package io.quarkus.it.hibernate.search.orm.elasticsearch.search; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.List; @@ -68,6 +69,25 @@ public String testSearch() { return "OK"; } + @GET + @Path("/search-projection") + @Produces(MediaType.TEXT_PLAIN) + public String testSearchWithProjection() { + SearchSession searchSession = Search.session(entityManager); + + assertThat(searchSession.search(Person.class) + .select(PersonDTO.class) + .where(f -> f.match().field("name").matching("john")) + .sort(f -> f.field("name_sort")) + .fetchHits(20)) + .usingRecursiveFieldByFieldElementComparator() + .containsExactly( + new PersonDTO(4, "John Grisham", new AddressDTO("Oxford")), + new PersonDTO(1, "John Irving", new AddressDTO("Burlington"))); + + return "OK"; + } + @PUT @Path("/purge") @Produces(MediaType.TEXT_PLAIN) diff --git a/integration-tests/hibernate-search-orm-elasticsearch/src/main/java/io/quarkus/it/hibernate/search/orm/elasticsearch/search/PersonDTO.java b/integration-tests/hibernate-search-orm-elasticsearch/src/main/java/io/quarkus/it/hibernate/search/orm/elasticsearch/search/PersonDTO.java new file mode 100644 index 0000000000000..2dc75d37feb5a --- /dev/null +++ b/integration-tests/hibernate-search-orm-elasticsearch/src/main/java/io/quarkus/it/hibernate/search/orm/elasticsearch/search/PersonDTO.java @@ -0,0 +1,27 @@ +package io.quarkus.it.hibernate.search.orm.elasticsearch.search; + +import org.hibernate.search.mapper.pojo.mapping.definition.annotation.IdProjection; +import org.hibernate.search.mapper.pojo.mapping.definition.annotation.ProjectionConstructor; + +// Ideally we'd use records, but Quarkus still has to compile with JDK 11 at the moment. +public class PersonDTO { + public final long id; + public final String name; + public final AddressDTO address; + + @ProjectionConstructor + public PersonDTO(@IdProjection long id, String name, AddressDTO address) { + this.id = id; + this.name = name; + this.address = address; + } + + @Override + public String toString() { + return "PersonDTO{" + + "id=" + id + + ", name='" + name + '\'' + + ", address=" + address + + '}'; + } +} diff --git a/integration-tests/hibernate-search-orm-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/orm/elasticsearch/HibernateSearchTest.java b/integration-tests/hibernate-search-orm-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/orm/elasticsearch/HibernateSearchTest.java index 54a2774a88645..8eb64b277ba5d 100644 --- a/integration-tests/hibernate-search-orm-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/orm/elasticsearch/HibernateSearchTest.java +++ b/integration-tests/hibernate-search-orm-elasticsearch/src/test/java/io/quarkus/it/hibernate/search/orm/elasticsearch/HibernateSearchTest.java @@ -11,7 +11,7 @@ public class HibernateSearchTest { @Test - public void testSearch() throws Exception { + public void testSearch() { RestAssured.when().put("/test/hibernate-search/init-data").then() .statusCode(204); @@ -19,6 +19,10 @@ public void testSearch() throws Exception { .statusCode(200) .body(is("OK")); + RestAssured.when().get("/test/hibernate-search/search-projection").then() + .statusCode(200) + .body(is("OK")); + RestAssured.when().put("/test/hibernate-search/purge").then() .statusCode(200) .body(is("OK")); From 6dcd7de53e8066fa5ee60a984f17ba5571c019e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Thu, 22 Jun 2023 17:19:20 +0200 Subject: [PATCH 4/6] Hibernate Search: Add support for new outbox-polling properties in 6.2 --- .../hibernate-search-orm-elasticsearch.adoc | 19 ++ ...HibernateSearchOutboxPollingProcessor.java | 5 +- .../configuration/ConfigPropertiesTest.java | 75 ++++++++ ...ateSearchOutboxPollingBuildTimeConfig.java | 30 ++++ ...PollingBuildTimeConfigPersistenceUnit.java | 163 ++++++++++++++++++ ...ibernateSearchOutboxPollingConfigUtil.java | 10 ++ .../HibernateSearchOutboxPollingRecorder.java | 73 ++++++++ 7 files changed, 374 insertions(+), 1 deletion(-) create mode 100644 extensions/hibernate-search-orm-coordination-outbox-polling/runtime/src/main/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/runtime/HibernateSearchOutboxPollingBuildTimeConfig.java create mode 100644 extensions/hibernate-search-orm-coordination-outbox-polling/runtime/src/main/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/runtime/HibernateSearchOutboxPollingBuildTimeConfigPersistenceUnit.java diff --git a/docs/src/main/asciidoc/hibernate-search-orm-elasticsearch.adoc b/docs/src/main/asciidoc/hibernate-search-orm-elasticsearch.adoc index ccb9141b1c407..08cc336e7db9e 100644 --- a/docs/src/main/asciidoc/hibernate-search-orm-elasticsearch.adoc +++ b/docs/src/main/asciidoc/hibernate-search-orm-elasticsearch.adoc @@ -5,6 +5,7 @@ https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc //// = Hibernate Search guide :hibernate-search-doc-prefix: https://docs.jboss.org/hibernate/search/6.2/reference/en-US/html_single/ +:hibernate-orm-doc-prefix: https://docs.jboss.org/hibernate/orm/6.2/userguide/html_single/Hibernate_User_Guide.html include::_attributes.adoc[] :categories: data :summary: Hibernate Search allows you to index your entities in an Elasticsearch cluster and easily offer full text search in all your Hibernate ORM-based applications. @@ -896,6 +897,24 @@ then no worries: the entities required by Hibernate Search will be included in t * Otherwise, you must link:{hibernate-search-doc-prefix}#coordination-outbox-polling-schema[manually alter your schema to add the necessary tables/sequences]. +[NOTE] +==== +The database schema Hibernate Search will expect for outbox-polling coordination +may be customized through the following configuration properties: + +* link:#quarkus-hibernate-search-orm-coordination-outboxpolling_quarkus.hibernate-search-orm.coordination.entity.mapping.agent.catalog[`quarkus.hibernate-search-orm.coordination.entity.mapping.agent.catalog`] +* link:#quarkus-hibernate-search-orm-coordination-outboxpolling_quarkus.hibernate-search-orm.coordination.entity.mapping.agent.schema[`quarkus.hibernate-search-orm.coordination.entity.mapping.agent.schema`] +* link:#quarkus-hibernate-search-orm-coordination-outboxpolling_quarkus.hibernate-search-orm.coordination.entity.mapping.agent.table[`quarkus.hibernate-search-orm.coordination.entity.mapping.agent.table`] +* link:#quarkus-hibernate-search-orm-coordination-outboxpolling_quarkus.hibernate-search-orm.coordination.entity.mapping.agent.uuid-gen-strategy[`quarkus.hibernate-search-orm.coordination.entity.mapping.agent.uuid-gen-strategy`] +* link:#quarkus-hibernate-search-orm-coordination-outboxpolling_quarkus.hibernate-search-orm.coordination.entity.mapping.agent.uuid-type[`quarkus.hibernate-search-orm.coordination.entity.mapping.agent.uuid-type`] +* link:#quarkus-hibernate-search-orm-coordination-outboxpolling_quarkus.hibernate-search-orm.coordination.entity.mapping.outbox-event.catalog[`quarkus.hibernate-search-orm.coordination.entity.mapping.outbox-event.catalog`] +* link:#quarkus-hibernate-search-orm-coordination-outboxpolling_quarkus.hibernate-search-orm.coordination.entity.mapping.outbox-event.schema[`quarkus.hibernate-search-orm.coordination.entity.mapping.outbox-event.schema`] +* link:#quarkus-hibernate-search-orm-coordination-outboxpolling_quarkus.hibernate-search-orm.coordination.entity.mapping.outbox-event.table[`quarkus.hibernate-search-orm.coordination.entity.mapping.outbox-event.table`] +* link:#quarkus-hibernate-search-orm-coordination-outboxpolling_quarkus.hibernate-search-orm.coordination.entity.mapping.outbox-event.uuid-gen-strategy[`quarkus.hibernate-search-orm.coordination.entity.mapping.outbox-event.uuid-gen-strategy`] +* link:#quarkus-hibernate-search-orm-coordination-outboxpolling_quarkus.hibernate-search-orm.coordination.entity.mapping.outbox-event.uuid-type[`quarkus.hibernate-search-orm.coordination.entity.mapping.outbox-event.uuid-type`] + +==== + Once you are done with the above, you're ready to use Hibernate Search with an outbox. Don't change any code, and just start your application: it will automatically detect when multiple applications are connected to the same database, diff --git a/extensions/hibernate-search-orm-coordination-outbox-polling/deployment/src/main/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/deployment/HibernateSearchOutboxPollingProcessor.java b/extensions/hibernate-search-orm-coordination-outbox-polling/deployment/src/main/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/deployment/HibernateSearchOutboxPollingProcessor.java index a8c05bc51719c..700e9eba79097 100644 --- a/extensions/hibernate-search-orm-coordination-outbox-polling/deployment/src/main/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/deployment/HibernateSearchOutboxPollingProcessor.java +++ b/extensions/hibernate-search-orm-coordination-outbox-polling/deployment/src/main/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/deployment/HibernateSearchOutboxPollingProcessor.java @@ -14,6 +14,7 @@ import io.quarkus.deployment.builditem.AdditionalIndexedClassesBuildItem; import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; import io.quarkus.hibernate.orm.deployment.spi.AdditionalJpaModelBuildItem; +import io.quarkus.hibernate.search.orm.coordination.outboxpolling.runtime.HibernateSearchOutboxPollingBuildTimeConfig; import io.quarkus.hibernate.search.orm.coordination.outboxpolling.runtime.HibernateSearchOutboxPollingRecorder; import io.quarkus.hibernate.search.orm.coordination.outboxpolling.runtime.HibernateSearchOutboxPollingRuntimeConfig; import io.quarkus.hibernate.search.orm.elasticsearch.deployment.HibernateSearchElasticsearchPersistenceUnitConfiguredBuildItem; @@ -43,6 +44,7 @@ void registerInternalModel(BuildProducer addi @BuildStep @Record(ExecutionTime.STATIC_INIT) void setStaticConfig(HibernateSearchOutboxPollingRecorder recorder, + HibernateSearchOutboxPollingBuildTimeConfig buildTimeConfig, List configuredPersistenceUnits, BuildProducer staticConfigured) { for (HibernateSearchElasticsearchPersistenceUnitConfiguredBuildItem configuredPersistenceUnit : configuredPersistenceUnits) { @@ -51,7 +53,8 @@ void setStaticConfig(HibernateSearchOutboxPollingRecorder recorder, } String puName = configuredPersistenceUnit.getPersistenceUnitName(); staticConfigured.produce(new HibernateSearchIntegrationStaticConfiguredBuildItem( - HIBERNATE_SEARCH_ORM_COORDINATION_OUTBOX_POLLING, puName, null) + HIBERNATE_SEARCH_ORM_COORDINATION_OUTBOX_POLLING, puName, + recorder.createStaticInitListener(buildTimeConfig, puName)) // Additional entities such as Agent and OutboxEvent are defined through XML // (because there's no other way). .setXmlMappingRequired(true)); diff --git a/extensions/hibernate-search-orm-coordination-outbox-polling/deployment/src/test/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/test/configuration/ConfigPropertiesTest.java b/extensions/hibernate-search-orm-coordination-outbox-polling/deployment/src/test/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/test/configuration/ConfigPropertiesTest.java index 69bc445beff93..303c91a68fd85 100644 --- a/extensions/hibernate-search-orm-coordination-outbox-polling/deployment/src/test/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/test/configuration/ConfigPropertiesTest.java +++ b/extensions/hibernate-search-orm-coordination-outbox-polling/deployment/src/test/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/test/configuration/ConfigPropertiesTest.java @@ -9,6 +9,7 @@ import org.hibernate.SessionFactory; import org.hibernate.search.mapper.orm.coordination.outboxpolling.cfg.HibernateOrmMapperOutboxPollingSettings; +import org.hibernate.search.mapper.orm.coordination.outboxpolling.cfg.UuidGenerationStrategy; import org.jboss.shrinkwrap.api.ShrinkWrap; import org.jboss.shrinkwrap.api.spec.JavaArchive; import org.junit.jupiter.api.Test; @@ -32,6 +33,20 @@ public class ConfigPropertiesTest { .addPackage(IndexedEntity.class.getPackage()) .addPackage(IndexedEntityForPU1.class.getPackage())) .withConfigurationResource("application-multiple-persistence-units.properties") + .overrideConfigKey("quarkus.hibernate-search-orm.coordination.entity-mapping.agent.catalog", "myagentcatalog") + .overrideConfigKey("quarkus.hibernate-search-orm.coordination.entity-mapping.agent.schema", "myagentschema") + .overrideConfigKey("quarkus.hibernate-search-orm.coordination.entity-mapping.agent.table", "myagenttable") + .overrideConfigKey("quarkus.hibernate-search-orm.coordination.entity-mapping.agent.uuid-gen-strategy", "random") + .overrideConfigKey("quarkus.hibernate-search-orm.coordination.entity-mapping.agent.uuid-type", "uuid-char") + .overrideConfigKey("quarkus.hibernate-search-orm.coordination.entity-mapping.outbox-event.catalog", + "myoutboxeventcatalog") + .overrideConfigKey("quarkus.hibernate-search-orm.coordination.entity-mapping.outbox-event.schema", + "myoutboxeventschema") + .overrideConfigKey("quarkus.hibernate-search-orm.coordination.entity-mapping.outbox-event.table", + "myoutboxeventtable") + .overrideConfigKey("quarkus.hibernate-search-orm.coordination.entity-mapping.outbox-event.uuid-gen-strategy", + "time") + .overrideConfigKey("quarkus.hibernate-search-orm.coordination.entity-mapping.outbox-event.uuid-type", "uuid-binary") .overrideConfigKey("quarkus.hibernate-search-orm.coordination.event-processor.enabled", "false") .overrideConfigKey("quarkus.hibernate-search-orm.coordination.event-processor.shards.total-count", "10") .overrideConfigKey("quarkus.hibernate-search-orm.coordination.event-processor.shards.assigned", "1,2") @@ -44,6 +59,28 @@ public class ConfigPropertiesTest { .overrideConfigKey("quarkus.hibernate-search-orm.coordination.mass-indexer.polling-interval", "0.048S") .overrideConfigKey("quarkus.hibernate-search-orm.coordination.mass-indexer.pulse-interval", "0.049S") .overrideConfigKey("quarkus.hibernate-search-orm.coordination.mass-indexer.pulse-expiration", "50S") + .overrideConfigKey("quarkus.hibernate-search-orm.coordination.mass-indexer.pulse-interval", "0.049S") + .overrideConfigKey("quarkus.hibernate-search-orm.coordination.mass-indexer.pulse-expiration", "50S") + .overrideConfigKey("quarkus.hibernate-search-orm.\"pu1\".coordination.entity-mapping.agent.catalog", + "myagentcatalogpu1") + .overrideConfigKey("quarkus.hibernate-search-orm.\"pu1\".coordination.entity-mapping.agent.schema", + "myagentschemapu1") + .overrideConfigKey("quarkus.hibernate-search-orm.\"pu1\".coordination.entity-mapping.agent.table", + "myagenttablepu1") + .overrideConfigKey("quarkus.hibernate-search-orm.\"pu1\".coordination.entity-mapping.agent.uuid-gen-strategy", + "time") + .overrideConfigKey("quarkus.hibernate-search-orm.\"pu1\".coordination.entity-mapping.agent.uuid-type", + "uuid-binary") + .overrideConfigKey("quarkus.hibernate-search-orm.\"pu1\".coordination.entity-mapping.outbox-event.catalog", + "myoutboxeventcatalogpu1") + .overrideConfigKey("quarkus.hibernate-search-orm.\"pu1\".coordination.entity-mapping.outbox-event.schema", + "myoutboxeventschemapu1") + .overrideConfigKey("quarkus.hibernate-search-orm.\"pu1\".coordination.entity-mapping.outbox-event.table", + "myoutboxeventtablepu1") + .overrideConfigKey( + "quarkus.hibernate-search-orm.\"pu1\".coordination.entity-mapping.outbox-event.uuid-gen-strategy", "random") + .overrideConfigKey("quarkus.hibernate-search-orm.\"pu1\".coordination.entity-mapping.outbox-event.uuid-type", + "uuid-char") .overrideConfigKey("quarkus.hibernate-search-orm.\"pu1\".coordination.event-processor.enabled", "false") .overrideConfigKey("quarkus.hibernate-search-orm.\"pu1\".coordination.event-processor.shards.total-count", "110") .overrideConfigKey("quarkus.hibernate-search-orm.\"pu1\".coordination.event-processor.shards.assigned", "11,12") @@ -100,6 +137,24 @@ public class ConfigPropertiesTest { public void root() { assertThat(sessionFactory.getProperties()) .contains( + entry(HibernateOrmMapperOutboxPollingSettings.COORDINATION_ENTITY_MAPPING_AGENT_CATALOG, + "myagentcatalog"), + entry(HibernateOrmMapperOutboxPollingSettings.COORDINATION_ENTITY_MAPPING_AGENT_SCHEMA, + "myagentschema"), + entry(HibernateOrmMapperOutboxPollingSettings.COORDINATION_ENTITY_MAPPING_AGENT_TABLE, "myagenttable"), + entry(HibernateOrmMapperOutboxPollingSettings.COORDINATION_ENTITY_MAPPING_AGENT_UUID_GEN_STRATEGY, + UuidGenerationStrategy.RANDOM), + entry(HibernateOrmMapperOutboxPollingSettings.COORDINATION_ENTITY_MAPPING_AGENT_UUID_TYPE, "uuid-char"), + entry(HibernateOrmMapperOutboxPollingSettings.COORDINATION_ENTITY_MAPPING_OUTBOXEVENT_CATALOG, + "myoutboxeventcatalog"), + entry(HibernateOrmMapperOutboxPollingSettings.COORDINATION_ENTITY_MAPPING_OUTBOXEVENT_SCHEMA, + "myoutboxeventschema"), + entry(HibernateOrmMapperOutboxPollingSettings.COORDINATION_ENTITY_MAPPING_OUTBOXEVENT_TABLE, + "myoutboxeventtable"), + entry(HibernateOrmMapperOutboxPollingSettings.COORDINATION_ENTITY_MAPPING_OUTBOXEVENT_UUID_GEN_STRATEGY, + UuidGenerationStrategy.TIME), + entry(HibernateOrmMapperOutboxPollingSettings.COORDINATION_ENTITY_MAPPING_OUTBOXEVENT_UUID_TYPE, + "uuid-binary"), entry(HibernateOrmMapperOutboxPollingSettings.COORDINATION_EVENT_PROCESSOR_ENABLED, false), entry(HibernateOrmMapperOutboxPollingSettings.COORDINATION_EVENT_PROCESSOR_SHARDS_TOTAL_COUNT, 10), entry(HibernateOrmMapperOutboxPollingSettings.COORDINATION_EVENT_PROCESSOR_SHARDS_ASSIGNED, @@ -119,6 +174,26 @@ public void root() { public void perNamedPersistenceUnit() { assertThat(sessionFactoryForNamedPU1.getProperties()) .contains( + entry(HibernateOrmMapperOutboxPollingSettings.COORDINATION_ENTITY_MAPPING_AGENT_CATALOG, + "myagentcatalogpu1"), + entry(HibernateOrmMapperOutboxPollingSettings.COORDINATION_ENTITY_MAPPING_AGENT_SCHEMA, + "myagentschemapu1"), + entry(HibernateOrmMapperOutboxPollingSettings.COORDINATION_ENTITY_MAPPING_AGENT_TABLE, + "myagenttablepu1"), + entry(HibernateOrmMapperOutboxPollingSettings.COORDINATION_ENTITY_MAPPING_AGENT_UUID_GEN_STRATEGY, + UuidGenerationStrategy.TIME), + entry(HibernateOrmMapperOutboxPollingSettings.COORDINATION_ENTITY_MAPPING_AGENT_UUID_TYPE, + "uuid-binary"), + entry(HibernateOrmMapperOutboxPollingSettings.COORDINATION_ENTITY_MAPPING_OUTBOXEVENT_CATALOG, + "myoutboxeventcatalogpu1"), + entry(HibernateOrmMapperOutboxPollingSettings.COORDINATION_ENTITY_MAPPING_OUTBOXEVENT_SCHEMA, + "myoutboxeventschemapu1"), + entry(HibernateOrmMapperOutboxPollingSettings.COORDINATION_ENTITY_MAPPING_OUTBOXEVENT_TABLE, + "myoutboxeventtablepu1"), + entry(HibernateOrmMapperOutboxPollingSettings.COORDINATION_ENTITY_MAPPING_OUTBOXEVENT_UUID_GEN_STRATEGY, + UuidGenerationStrategy.RANDOM), + entry(HibernateOrmMapperOutboxPollingSettings.COORDINATION_ENTITY_MAPPING_OUTBOXEVENT_UUID_TYPE, + "uuid-char"), entry(HibernateOrmMapperOutboxPollingSettings.COORDINATION_EVENT_PROCESSOR_ENABLED, false), entry(HibernateOrmMapperOutboxPollingSettings.COORDINATION_EVENT_PROCESSOR_SHARDS_TOTAL_COUNT, 110), entry(HibernateOrmMapperOutboxPollingSettings.COORDINATION_EVENT_PROCESSOR_SHARDS_ASSIGNED, diff --git a/extensions/hibernate-search-orm-coordination-outbox-polling/runtime/src/main/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/runtime/HibernateSearchOutboxPollingBuildTimeConfig.java b/extensions/hibernate-search-orm-coordination-outbox-polling/runtime/src/main/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/runtime/HibernateSearchOutboxPollingBuildTimeConfig.java new file mode 100644 index 0000000000000..3df1613cce9bc --- /dev/null +++ b/extensions/hibernate-search-orm-coordination-outbox-polling/runtime/src/main/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/runtime/HibernateSearchOutboxPollingBuildTimeConfig.java @@ -0,0 +1,30 @@ +package io.quarkus.hibernate.search.orm.coordination.outboxpolling.runtime; + +import java.util.Map; + +import io.quarkus.runtime.annotations.ConfigDocMapKey; +import io.quarkus.runtime.annotations.ConfigDocSection; +import io.quarkus.runtime.annotations.ConfigPhase; +import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithParentName; + +@ConfigMapping(prefix = "quarkus.hibernate-search-orm") +@ConfigRoot(phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED) +public interface HibernateSearchOutboxPollingBuildTimeConfig { + + /** + * Configuration for the default persistence unit. + */ + @WithParentName + HibernateSearchOutboxPollingBuildTimeConfigPersistenceUnit defaultPersistenceUnit(); + + /** + * Configuration for additional named persistence units. + */ + @ConfigDocSection + @ConfigDocMapKey("persistence-unit-name") + @WithParentName + Map persistenceUnits(); + +} diff --git a/extensions/hibernate-search-orm-coordination-outbox-polling/runtime/src/main/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/runtime/HibernateSearchOutboxPollingBuildTimeConfigPersistenceUnit.java b/extensions/hibernate-search-orm-coordination-outbox-polling/runtime/src/main/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/runtime/HibernateSearchOutboxPollingBuildTimeConfigPersistenceUnit.java new file mode 100644 index 0000000000000..67c9d637fa47a --- /dev/null +++ b/extensions/hibernate-search-orm-coordination-outbox-polling/runtime/src/main/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/runtime/HibernateSearchOutboxPollingBuildTimeConfigPersistenceUnit.java @@ -0,0 +1,163 @@ +package io.quarkus.hibernate.search.orm.coordination.outboxpolling.runtime; + +import java.util.Optional; + +import org.hibernate.search.mapper.orm.coordination.outboxpolling.cfg.UuidGenerationStrategy; + +import io.quarkus.runtime.annotations.ConfigDocDefault; +import io.quarkus.runtime.annotations.ConfigDocSection; +import io.quarkus.runtime.annotations.ConfigGroup; + +@ConfigGroup +public interface HibernateSearchOutboxPollingBuildTimeConfigPersistenceUnit { + + /** + * Configuration for coordination between threads or application instances. + */ + CoordinationConfig coordination(); + + @ConfigGroup + interface CoordinationConfig { + + /** + * Configuration for the mapping of entities used for outbox-polling coordination. + */ + @ConfigDocSection + EntityMappingConfig entityMapping(); + + } + + @ConfigGroup + interface EntityMappingConfig { + + /** + * Configuration for the "agent" entity mapping. + */ + EntityMappingAgentConfig agent(); + + /** + * Configuration for the "outbox event" entity mapping. + */ + EntityMappingOutboxEventConfig outboxEvent(); + + } + + @ConfigGroup + interface EntityMappingAgentConfig { + + /** + * The database catalog to use for the agent table. + * + * @asciidoclet + */ + @ConfigDocDefault("Default catalog configured in Hibernate ORM") + Optional catalog(); + + /** + * The schema catalog to use for the agent table. + * + * @asciidoclet + */ + @ConfigDocDefault("Default catalog configured in Hibernate ORM") + Optional schema(); + + /** + * The name of the agent table. + * + * @asciidoclet + */ + @ConfigDocDefault("HSEARCH_AGENT") + Optional table(); + + /** + * The UUID generator strategy used for the agent table. + * + * Available strategies: + * + * * `auto` (the default) is the same as `random` which uses `UUID#randomUUID()`. + * * `time` is an IP based strategy consistent with IETF RFC 4122. + * + * @asciidoclet + */ + @ConfigDocDefault("auto") + Optional uuidGenStrategy(); + + /** + * The name of the Hibernate ORM basic type used for representing an UUID in the agent table. + * + * Refer to + * link:{hibernate-orm-doc-prefix}#basic-legacy-provided[this section of the Hibernate ORM documentation] + * to see the list of available UUID representations provided by Hibernate ORM. + * + * A user defined type can also be supplied. + * + * Defaults to the special value `default`, which will result into one of `uuid`/`uuid-binary`/`uuid-char` + * depending on the database kind. + * + * @asciidoclet + */ + @ConfigDocDefault("uuid/uuid-binary/uuid-char depending on the database kind") + Optional uuidType(); + + } + + @ConfigGroup + interface EntityMappingOutboxEventConfig { + + /** + * The database catalog to use for the outbox event table. + * + * @asciidoclet + */ + @ConfigDocDefault("Default catalog configured in Hibernate ORM") + Optional catalog(); + + /** + * The schema catalog to use for the outbox event table. + * + * @asciidoclet + */ + @ConfigDocDefault("Default schema configured in Hibernate ORM") + Optional schema(); + + /** + * The name of the outbox event table. + * + * @asciidoclet + */ + @ConfigDocDefault("HSEARCH_OUTBOX_EVENT") + Optional table(); + + /** + * The UUID generator strategy used for the outbox event table. + * + * Available strategies: + * + * * `auto` (the default) is the same as `random` which uses `UUID#randomUUID()`. + * * `time` is an IP based strategy consistent with IETF RFC 4122. + * + * @asciidoclet + */ + @ConfigDocDefault("auto") + Optional uuidGenStrategy(); + + /** + * The name of the Hibernate ORM basic type used for representing an UUID in the outbox event table. + * + * Refer to + * link:{hibernate-orm-doc-prefix}#basic-legacy-provided[this section of the Hibernate ORM documentation] + * to see the list of available UUID representations provided by Hibernate ORM. + * + * A user defined type can also be supplied. + * + * Defaults to the special value `default`, which will result into one of `uuid`/`uuid-binary`/`uuid-char` + * depending on the database kind. + * + * @asciidoclet + */ + @ConfigDocDefault("uuid/uuid-binary/uuid-char depending on the database kind") + Optional uuidType(); + + } + +} diff --git a/extensions/hibernate-search-orm-coordination-outbox-polling/runtime/src/main/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/runtime/HibernateSearchOutboxPollingConfigUtil.java b/extensions/hibernate-search-orm-coordination-outbox-polling/runtime/src/main/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/runtime/HibernateSearchOutboxPollingConfigUtil.java index b1eb98900b199..db1557c01f90b 100644 --- a/extensions/hibernate-search-orm-coordination-outbox-polling/runtime/src/main/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/runtime/HibernateSearchOutboxPollingConfigUtil.java +++ b/extensions/hibernate-search-orm-coordination-outbox-polling/runtime/src/main/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/runtime/HibernateSearchOutboxPollingConfigUtil.java @@ -12,6 +12,16 @@ public final class HibernateSearchOutboxPollingConfigUtil { private HibernateSearchOutboxPollingConfigUtil() { } + public static void addCoordinationConfig(BiConsumer propertyCollector, + String configPath, T value) { + addCoordinationConfig(propertyCollector, null, configPath, value); + } + + public static void addCoordinationConfig(BiConsumer propertyCollector, String configPath, + Optional value) { + addCoordinationConfig(propertyCollector, null, configPath, value); + } + public static void addCoordinationConfig(BiConsumer propertyCollector, String tenantId, String configPath, T value) { String key = HibernateOrmMapperOutboxPollingSettings.coordinationKey(tenantId, configPath); diff --git a/extensions/hibernate-search-orm-coordination-outbox-polling/runtime/src/main/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/runtime/HibernateSearchOutboxPollingRecorder.java b/extensions/hibernate-search-orm-coordination-outbox-polling/runtime/src/main/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/runtime/HibernateSearchOutboxPollingRecorder.java index c65a8566d72e5..4bc734b9be338 100644 --- a/extensions/hibernate-search-orm-coordination-outbox-polling/runtime/src/main/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/runtime/HibernateSearchOutboxPollingRecorder.java +++ b/extensions/hibernate-search-orm-coordination-outbox-polling/runtime/src/main/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/runtime/HibernateSearchOutboxPollingRecorder.java @@ -6,16 +6,28 @@ import java.util.Optional; import java.util.function.BiConsumer; +import org.hibernate.boot.Metadata; +import org.hibernate.boot.spi.BootstrapContext; import org.hibernate.search.mapper.orm.coordination.outboxpolling.cfg.HibernateOrmMapperOutboxPollingSettings; import io.quarkus.hibernate.orm.runtime.PersistenceUnitUtil; import io.quarkus.hibernate.orm.runtime.integration.HibernateOrmIntegrationRuntimeInitListener; +import io.quarkus.hibernate.orm.runtime.integration.HibernateOrmIntegrationStaticInitListener; import io.quarkus.hibernate.search.orm.coordination.outboxpolling.runtime.HibernateSearchOutboxPollingRuntimeConfigPersistenceUnit.AgentsConfig; import io.quarkus.runtime.annotations.Recorder; @Recorder public class HibernateSearchOutboxPollingRecorder { + public HibernateOrmIntegrationStaticInitListener createStaticInitListener( + HibernateSearchOutboxPollingBuildTimeConfig buildTimeConfig, String persistenceUnitName) { + HibernateSearchOutboxPollingBuildTimeConfigPersistenceUnit puConfig = PersistenceUnitUtil + .isDefaultPersistenceUnit(persistenceUnitName) + ? buildTimeConfig.defaultPersistenceUnit() + : buildTimeConfig.persistenceUnits().get(persistenceUnitName); + return new StaticInitListener(puConfig); + } + public HibernateOrmIntegrationRuntimeInitListener createRuntimeInitListener( HibernateSearchOutboxPollingRuntimeConfig runtimeConfig, String persistenceUnitName) { HibernateSearchOutboxPollingRuntimeConfigPersistenceUnit puConfig = PersistenceUnitUtil @@ -25,6 +37,67 @@ public HibernateOrmIntegrationRuntimeInitListener createRuntimeInitListener( return new RuntimeInitListener(puConfig); } + private static final class StaticInitListener + implements HibernateOrmIntegrationStaticInitListener { + + private final HibernateSearchOutboxPollingBuildTimeConfigPersistenceUnit buildTimeConfig; + + private StaticInitListener(HibernateSearchOutboxPollingBuildTimeConfigPersistenceUnit buildTimeConfig) { + this.buildTimeConfig = buildTimeConfig; + } + + @Override + public void onMetadataInitialized(Metadata metadata, BootstrapContext bootstrapContext, + BiConsumer propertyCollector) { + // Nothing to do + } + + @Override + public void contributeBootProperties(BiConsumer propertyCollector) { + if (buildTimeConfig == null) { + return; + } + + contributeCoordinationBuildTimeProperties(propertyCollector, buildTimeConfig.coordination()); + } + + private void contributeCoordinationBuildTimeProperties(BiConsumer propertyCollector, + HibernateSearchOutboxPollingBuildTimeConfigPersistenceUnit.CoordinationConfig config) { + addCoordinationConfig(propertyCollector, + HibernateOrmMapperOutboxPollingSettings.CoordinationRadicals.ENTITY_MAPPING_AGENT_CATALOG, + config.entityMapping().agent().catalog()); + addCoordinationConfig(propertyCollector, + HibernateOrmMapperOutboxPollingSettings.CoordinationRadicals.ENTITY_MAPPING_AGENT_SCHEMA, + config.entityMapping().agent().schema()); + addCoordinationConfig(propertyCollector, + HibernateOrmMapperOutboxPollingSettings.CoordinationRadicals.ENTITY_MAPPING_AGENT_TABLE, + config.entityMapping().agent().table()); + addCoordinationConfig(propertyCollector, + HibernateOrmMapperOutboxPollingSettings.CoordinationRadicals.ENTITY_MAPPING_AGENT_UUID_GEN_STRATEGY, + config.entityMapping().agent().uuidGenStrategy()); + addCoordinationConfig(propertyCollector, + HibernateOrmMapperOutboxPollingSettings.CoordinationRadicals.ENTITY_MAPPING_AGENT_UUID_TYPE, + config.entityMapping().agent().uuidType()); + + addCoordinationConfig(propertyCollector, + HibernateOrmMapperOutboxPollingSettings.CoordinationRadicals.ENTITY_MAPPING_OUTBOXEVENT_CATALOG, + config.entityMapping().outboxEvent().catalog()); + addCoordinationConfig(propertyCollector, + HibernateOrmMapperOutboxPollingSettings.CoordinationRadicals.ENTITY_MAPPING_OUTBOXEVENT_SCHEMA, + config.entityMapping().outboxEvent().schema()); + addCoordinationConfig(propertyCollector, + HibernateOrmMapperOutboxPollingSettings.CoordinationRadicals.ENTITY_MAPPING_OUTBOXEVENT_TABLE, + config.entityMapping().outboxEvent().table()); + addCoordinationConfig(propertyCollector, + HibernateOrmMapperOutboxPollingSettings.CoordinationRadicals.ENTITY_MAPPING_OUTBOXEVENT_UUID_GEN_STRATEGY, + config.entityMapping().outboxEvent().uuidGenStrategy()); + addCoordinationConfig(propertyCollector, + HibernateOrmMapperOutboxPollingSettings.CoordinationRadicals.ENTITY_MAPPING_OUTBOXEVENT_UUID_TYPE, + config.entityMapping().outboxEvent().uuidType()); + } + + } + private static final class RuntimeInitListener implements HibernateOrmIntegrationRuntimeInitListener { From d92ec3c8fcd2f37c902974f556e9a0ba1f1646a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 23 Jun 2023 09:37:50 +0200 Subject: [PATCH 5/6] Fix outdated Hibernate documentation URLs and use a common Asciidoc attribute --- bom/application/pom.xml | 5 +++- docs/pom.xml | 4 ++++ docs/src/main/asciidoc/_attributes.adoc | 5 ++++ .../main/asciidoc/hibernate-orm-panache.adoc | 4 ++-- docs/src/main/asciidoc/hibernate-orm.adoc | 13 +++++----- .../asciidoc/hibernate-reactive-panache.adoc | 4 ++-- .../hibernate-search-orm-elasticsearch.adoc | 22 ++++++++--------- docs/src/main/asciidoc/mongodb-panache.adoc | 2 +- ...PollingBuildTimeConfigPersistenceUnit.java | 4 ++-- ...oxPollingRuntimeConfigPersistenceUnit.java | 24 +++++++++---------- ...csearchBuildTimeConfigPersistenceUnit.java | 2 +- ...ticsearchRuntimeConfigPersistenceUnit.java | 2 +- 12 files changed, 50 insertions(+), 41 deletions(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 327d075439792..bb8bc87b387ee 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -97,11 +97,14 @@ 3.12.0 1.16.0 1.5.1 - 6.2.5.Final + + 6.2.5.Final 1.12.18 6.0.6.Final 2.0.1.Final 8.0.1.Final + 6.2.0.CR1 6.0.1.Final 2.1 diff --git a/docs/pom.xml b/docs/pom.xml index 94f59c856cd95..8db3183286bf4 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -35,6 +35,10 @@ ${project.basedir}/../target/asciidoc/generated ${generated-dir}/examples docker.io/jdkato/vale:v2.15.5 + + + 6.2 + 6.2 Quarkus - Documentation diff --git a/docs/src/main/asciidoc/_attributes.adoc b/docs/src/main/asciidoc/_attributes.adoc index 102641c4cdfbd..610ab5295bd07 100644 --- a/docs/src/main/asciidoc/_attributes.adoc +++ b/docs/src/main/asciidoc/_attributes.adoc @@ -24,6 +24,8 @@ :grpc-version: ${grpc.version} :protoc-version: ${protoc.version} :gcf-invoker-version: ${gcf-invoker.version} +:hibernate-orm-version: ${hibernate-orm.version-for-documentation} +:hibernate-search-version: ${hibernate-search.version-for-documentation} // . :quarkus-home-url: ${quarkus-home-url} :quarkus-org-url: https://github.com/quarkusio @@ -46,6 +48,9 @@ :quickstarts-blob-url: ${quickstarts-base-url}/blob/main :quickstarts-tree-url: ${quickstarts-base-url}/tree/main // . +:hibernate-orm-docs-url: https://docs.jboss.org/hibernate/orm/{hibernate-orm-version}/userguide/html_single/Hibernate_User_Guide.html +:hibernate-search-docs-url: https://docs.jboss.org/hibernate/search/{hibernate-search-version}/reference/en-US/html_single/ +// . :amazon-services-guide: https://quarkiverse.github.io/quarkiverse-docs/quarkus-amazon-services/dev/index.html :config-consul-guide: https://quarkiverse.github.io/quarkiverse-docs/quarkus-config-extensions/dev/consul.html :hibernate-search-orm-elasticsearch-aws-guide: https://quarkiverse.github.io/quarkiverse-docs/quarkus-hibernate-search-extras/dev/index.html diff --git a/docs/src/main/asciidoc/hibernate-orm-panache.adoc b/docs/src/main/asciidoc/hibernate-orm-panache.adoc index 8c45a0d98572d..7d3ed4fcb70b2 100644 --- a/docs/src/main/asciidoc/hibernate-orm-panache.adoc +++ b/docs/src/main/asciidoc/hibernate-orm-panache.adoc @@ -763,7 +763,7 @@ If your delete query does not start with `delete`, we support the following addi - `` will expand to `delete from EntityName where ` NOTE: You can also write your queries in plain -link:https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#hql[HQL]: +link:{hibernate-orm-docs-url}#hql[HQL]: [source,java] ---- @@ -869,7 +869,7 @@ You can use it to restrict which fields will be returned by the database. Hibernate will use **DTO projection** and generate a SELECT clause with the attributes from the projection class. This is also called **dynamic instantiation** or **constructor expression**, more info can be found on the Hibernate guide: -link:https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#hql-select-clause[hql select clause] +link:{hibernate-orm-docs-url}#hql-select-clause[hql select clause] The projection class needs to have a constructor that contains all its attributes, this constructor will be used to instantiate the projection DTO instead of using the entity class. This class must have a matching constructor with all the class attributes as parameters. diff --git a/docs/src/main/asciidoc/hibernate-orm.adoc b/docs/src/main/asciidoc/hibernate-orm.adoc index 8958a25296d43..6cbb3a8a923cf 100644 --- a/docs/src/main/asciidoc/hibernate-orm.adoc +++ b/docs/src/main/asciidoc/hibernate-orm.adoc @@ -8,7 +8,6 @@ include::_attributes.adoc[] :categories: data :summary: Hibernate ORM is the de facto Jakarta Persistence implementation and offers you the full breath of an Object Relational Mapper. It works beautifully in Quarkus. :config-file: application.properties -:orm-doc-url-prefix: https://docs.jboss.org/hibernate/orm/6.2/userguide/html_single/Hibernate_User_Guide.html Hibernate ORM is the de facto standard Jakarta Persistence (formerly known as JPA) implementation and offers you the full breadth of an Object Relational Mapper. It works beautifully in Quarkus. @@ -173,7 +172,7 @@ so at your application entry point boundaries like your REST endpoint controller ==== Supported databases For xref:datasource.adoc#default-datasource[supported databases], -the link:{orm-doc-url-prefix}##database-dialect[Hibernate ORM dialect] +the link:{hibernate-orm-docs-url}#database-dialect[Hibernate ORM dialect] does not need to be set explicitly: it is selected automatically based on the datasource. @@ -215,7 +214,7 @@ If the database cannot be reached, a warning will be logged but startup will pro If xref:datasource.adoc#other-databases[your database does not have a corresponding Quarkus extension], or if the defaults do not match your needs for some reason, -you will need to set the link:{orm-doc-url-prefix}##database-dialect[Hibernate ORM dialect] explicitly: +you will need to set the link:{hibernate-orm-docs-url}#database-dialect[Hibernate ORM dialect] explicitly: [source,properties] .`{config-file}` with an explicit `dialect` @@ -524,7 +523,7 @@ difference is that you would specify your Hibernate ORM configuration in `META-I ---- When using the `persistence.xml` configuration you are configuring Hibernate ORM directly, -so in this case the appropriate reference is the link:{orm-doc-url-prefix}#configurations[documentation on hibernate.org]. +so in this case the appropriate reference is the link:{hibernate-orm-docs-url}#configurations[documentation on hibernate.org]. Please remember these are not the same property names as the ones used in the Quarkus `{config-file}`, nor will the same defaults be applied. @@ -914,9 +913,9 @@ Jump over to xref:datasource.adoc[Quarkus - Datasources] for all details. [[multitenancy]] == Multitenancy -"The term multitenancy, in general, is applied to software development to indicate an architecture in which a single running instance of an application simultaneously serves multiple clients (tenants). This is highly common in SaaS solutions. Isolating information (data, customizations, etc.) pertaining to the various tenants is a particular challenge in these systems. This includes the data owned by each tenant stored in the database" (link:{orm-doc-url-prefix}#multitenacy[Hibernate User Guide]). +"The term multitenancy, in general, is applied to software development to indicate an architecture in which a single running instance of an application simultaneously serves multiple clients (tenants). This is highly common in SaaS solutions. Isolating information (data, customizations, etc.) pertaining to the various tenants is a particular challenge in these systems. This includes the data owned by each tenant stored in the database" (link:{hibernate-orm-docs-url}#multitenacy[Hibernate User Guide]). -Quarkus currently supports the link:{orm-doc-url-prefix}#multitenacy-separate-database[separate database] approach, the link:{orm-doc-url-prefix}#multitenacy-separate-schema[separate schema] approach and the link:{orm-doc-url-prefix}#multitenacy-discriminator[discriminator] approach. +Quarkus currently supports the link:{hibernate-orm-docs-url}#multitenacy-separate-database[separate database] approach, the link:{hibernate-orm-docs-url}#multitenacy-separate-schema[separate schema] approach and the link:{hibernate-orm-docs-url}#multitenacy-discriminator[discriminator] approach. To see multitenancy in action, you can check out the {quickstarts-tree-url}/hibernate-orm-multi-tenancy-quickstart[hibernate-orm-multi-tenancy-quickstart] quickstart. @@ -1179,7 +1178,7 @@ Your custom connection resolver would allow for example to read tenant informati [[interceptors]] == Interceptors -You can assign an link:{orm-doc-url-prefix}#events-interceptors[`org.hibernate.Interceptor`] +You can assign an link:{hibernate-orm-docs-url}#events-interceptors[`org.hibernate.Interceptor`] to your `SessionFactory` by simply defining a CDI bean with the appropriate qualifier: [source,java] diff --git a/docs/src/main/asciidoc/hibernate-reactive-panache.adoc b/docs/src/main/asciidoc/hibernate-reactive-panache.adoc index e2088abc4c868..d245eb3c4d598 100644 --- a/docs/src/main/asciidoc/hibernate-reactive-panache.adoc +++ b/docs/src/main/asciidoc/hibernate-reactive-panache.adoc @@ -525,7 +525,7 @@ If your delete query does not start with `delete`, we support the following addi - `` will expand to `delete from EntityName where ` NOTE: You can also write your queries in plain -link:https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#hql[HQL]: +link:{hibernate-orm-docs-url}#hql[HQL]: [source,java] ---- @@ -617,7 +617,7 @@ You can use it to restrict which fields will be returned by the database. Hibernate will use **DTO projection** and generate a SELECT clause with the attributes from the projection class. This is also called **dynamic instantiation** or **constructor expression**, more info can be found on the Hibernate guide: -link:https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#hql-select-clause[hql select clause] +link:{hibernate-orm-docs-url}#hql-select-clause[hql select clause] The projection class needs to be a valid Java Bean and have a constructor that contains all its attributes, this constructor will be used to instantiate the projection DTO instead of using the entity class. This must be the only constructor of the class. diff --git a/docs/src/main/asciidoc/hibernate-search-orm-elasticsearch.adoc b/docs/src/main/asciidoc/hibernate-search-orm-elasticsearch.adoc index 08cc336e7db9e..79a3301902d70 100644 --- a/docs/src/main/asciidoc/hibernate-search-orm-elasticsearch.adoc +++ b/docs/src/main/asciidoc/hibernate-search-orm-elasticsearch.adoc @@ -4,8 +4,6 @@ and pull requests should be submitted there: https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc //// = Hibernate Search guide -:hibernate-search-doc-prefix: https://docs.jboss.org/hibernate/search/6.2/reference/en-US/html_single/ -:hibernate-orm-doc-prefix: https://docs.jboss.org/hibernate/orm/6.2/userguide/html_single/Hibernate_User_Guide.html include::_attributes.adoc[] :categories: data :summary: Hibernate Search allows you to index your entities in an Elasticsearch cluster and easily offer full text search in all your Hibernate ORM-based applications. @@ -549,7 +547,7 @@ The Hibernate Search DSL supports a significant subset of the Elasticsearch pred Feel free to explore the DSL using autocompletion. When that's not enough, you can always fall back to -link:{hibernate-search-doc-prefix}#search-dsl-predicate-extensions-elasticsearch-from-json[defining a predicate using JSON directly]. +link:{hibernate-search-docs-url}#search-dsl-predicate-extensions-elasticsearch-from-json[defining a predicate using JSON directly]. ==== == Configuring the application @@ -691,7 +689,7 @@ and https://www.opensearch.org/[OpenSearch], but it assumes it is working with an Elasticsearch cluster by default. To have Hibernate Search work with an OpenSearch cluster instead, -link:{hibernate-search-doc-prefix}#backend-elasticsearch-configuration-version[prefix the configured version with `opensearch:`], +link:{hibernate-search-docs-url}#backend-elasticsearch-configuration-version[prefix the configured version with `opensearch:`], as shown below. [source,properties] @@ -702,7 +700,7 @@ quarkus.hibernate-search-orm.elasticsearch.version=opensearch:1.2 All other configuration options and APIs are exactly the same as with Elasticsearch. You can find more information about compatible distributions and versions of Elasticsearch in -link:{hibernate-search-doc-prefix}#compatibility[this section of Hibernate Search's reference documentation]. +link:{hibernate-search-docs-url}#compatibility[this section of Hibernate Search's reference documentation]. [[multiple-persistence-units]] == Multiple persistence units @@ -850,7 +848,7 @@ If you disable automatic schema creation by setting `quarkus.hibernate-search-or you will have to create the schema manually at some point before your application starts persisting/updating entities and executing search requests. -See link:{hibernate-search-doc-prefix}#schema-management-manager[this section of the reference documentation] +See link:{hibernate-search-docs-url}#schema-management-manager[this section of the reference documentation] for more information. ==== @@ -870,12 +868,12 @@ or as issues in our https://github.com/quarkusio/quarkus/issues[GitHub issue tra While it’s technically possible to use Hibernate Search and Elasticsearch in distributed applications, by default they suffer from -link:{hibernate-search-doc-prefix}#architecture-examples-no-coordination-elasticsearch-pros-and-cons[a few limitations]. +link:{hibernate-search-docs-url}#architecture-examples-no-coordination-elasticsearch-pros-and-cons[a few limitations]. These limitations are the result of Hibernate Search not coordinating between threads or application nodes by default. In order to get rid of these limitations, you can -link:{hibernate-search-doc-prefix}#architecture-examples-outbox-polling-elasticsearch[use the `outbox-polling` coordination strategy]. +link:{hibernate-search-docs-url}#architecture-examples-outbox-polling-elasticsearch[use the `outbox-polling` coordination strategy]. This strategy creates an outbox table in the database to push entity change events to, and relies on a background processor to consume these events and perform indexing. @@ -895,7 +893,7 @@ Finally, you will need to make sure that the Hibernate ORM entities added by Hib and intend to xref:hibernate-orm.adoc#dev-mode[let Hibernate ORM generate your database schema], then no worries: the entities required by Hibernate Search will be included in the generated schema. * Otherwise, you must -link:{hibernate-search-doc-prefix}#coordination-outbox-polling-schema[manually alter your schema to add the necessary tables/sequences]. +link:{hibernate-search-docs-url}#coordination-outbox-polling-schema[manually alter your schema to add the necessary tables/sequences]. [NOTE] ==== @@ -939,7 +937,7 @@ and the recommended way of using Hibernate Search even when coordination is disa ==== For more information about coordination in Hibernate Search, -see link:{hibernate-search-doc-prefix}#coordination[this section of the reference documentation]. +see link:{hibernate-search-docs-url}#coordination[this section of the reference documentation]. For more information about configuration options related to coordination, see <>. @@ -958,7 +956,7 @@ for more information. == Further reading If you are interested in learning more about Hibernate Search 6, -the Hibernate team publishes link:{hibernate-search-doc-prefix}[an extensive reference documentation]. +the Hibernate team publishes link:{hibernate-search-docs-url}[an extensive reference documentation]. == FAQ @@ -998,7 +996,7 @@ such as `async`/`read-sync`/`write-sync`/`sync` for <>. Other formats are also accepted, but are only useful for advanced use cases. -See link:{hibernate-search-doc-prefix}#configuration-bean-reference-parsing[this section of Hibernate Search's reference documentation] +See link:{hibernate-search-docs-url}#configuration-bean-reference-parsing[this section of Hibernate Search's reference documentation] for more information. ==== diff --git a/docs/src/main/asciidoc/mongodb-panache.adoc b/docs/src/main/asciidoc/mongodb-panache.adoc index ee08c8145e56e..4003e3efb8ca9 100644 --- a/docs/src/main/asciidoc/mongodb-panache.adoc +++ b/docs/src/main/asciidoc/mongodb-panache.adoc @@ -587,7 +587,7 @@ The `Sort` class has plenty of methods for adding columns and specifying sort di Normally, MongoDB queries are of this form: `{'firstname': 'John', 'lastname':'Doe'}`, this is what we call MongoDB native queries. -You can use them if you want, but we also support what we call **PanacheQL** that can be seen as a subset of link:https://docs.oracle.com/javaee/7/tutorial/persistence-querylanguage.htm#BNBTG[JPQL] (or link:https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#hql[HQL]) and allows you to easily express a query. +You can use them if you want, but we also support what we call **PanacheQL** that can be seen as a subset of link:https://docs.oracle.com/javaee/7/tutorial/persistence-querylanguage.htm#BNBTG[JPQL] (or link:{hibernate-orm-docs-url}#hql[HQL]) and allows you to easily express a query. MongoDB with Panache will then map it to a MongoDB native query. If your query does not start with `{`, we will consider it a PanacheQL query: diff --git a/extensions/hibernate-search-orm-coordination-outbox-polling/runtime/src/main/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/runtime/HibernateSearchOutboxPollingBuildTimeConfigPersistenceUnit.java b/extensions/hibernate-search-orm-coordination-outbox-polling/runtime/src/main/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/runtime/HibernateSearchOutboxPollingBuildTimeConfigPersistenceUnit.java index 67c9d637fa47a..b3f17f275e111 100644 --- a/extensions/hibernate-search-orm-coordination-outbox-polling/runtime/src/main/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/runtime/HibernateSearchOutboxPollingBuildTimeConfigPersistenceUnit.java +++ b/extensions/hibernate-search-orm-coordination-outbox-polling/runtime/src/main/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/runtime/HibernateSearchOutboxPollingBuildTimeConfigPersistenceUnit.java @@ -86,7 +86,7 @@ interface EntityMappingAgentConfig { * The name of the Hibernate ORM basic type used for representing an UUID in the agent table. * * Refer to - * link:{hibernate-orm-doc-prefix}#basic-legacy-provided[this section of the Hibernate ORM documentation] + * link:{hibernate-orm-docs-url}#basic-legacy-provided[this section of the Hibernate ORM documentation] * to see the list of available UUID representations provided by Hibernate ORM. * * A user defined type can also be supplied. @@ -145,7 +145,7 @@ interface EntityMappingOutboxEventConfig { * The name of the Hibernate ORM basic type used for representing an UUID in the outbox event table. * * Refer to - * link:{hibernate-orm-doc-prefix}#basic-legacy-provided[this section of the Hibernate ORM documentation] + * link:{hibernate-orm-docs-url}#basic-legacy-provided[this section of the Hibernate ORM documentation] * to see the list of available UUID representations provided by Hibernate ORM. * * A user defined type can also be supplied. diff --git a/extensions/hibernate-search-orm-coordination-outbox-polling/runtime/src/main/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/runtime/HibernateSearchOutboxPollingRuntimeConfigPersistenceUnit.java b/extensions/hibernate-search-orm-coordination-outbox-polling/runtime/src/main/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/runtime/HibernateSearchOutboxPollingRuntimeConfigPersistenceUnit.java index 413c1e8834c08..a7b4b8d7e5a73 100644 --- a/extensions/hibernate-search-orm-coordination-outbox-polling/runtime/src/main/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/runtime/HibernateSearchOutboxPollingRuntimeConfigPersistenceUnit.java +++ b/extensions/hibernate-search-orm-coordination-outbox-polling/runtime/src/main/java/io/quarkus/hibernate/search/orm/coordination/outboxpolling/runtime/HibernateSearchOutboxPollingRuntimeConfigPersistenceUnit.java @@ -66,7 +66,7 @@ public interface EventProcessorConfig { * for example to dedicate some nodes to HTTP request processing and other nodes to event processing. * * See - * link:{hibernate-search-doc-prefix}#coordination-outbox-polling-event-processor[this section of the reference documentation] + * link:{hibernate-search-docs-url}#coordination-outbox-polling-event-processor[this section of the reference documentation] * for more information. * * @asciidoclet @@ -88,7 +88,7 @@ public interface EventProcessorConfig { * but will increase the stress on the database when there are no new events. * * See - * link:{hibernate-search-doc-prefix}#coordination-outbox-polling-event-processor[this section of the reference documentation] + * link:{hibernate-search-docs-url}#coordination-outbox-polling-event-processor[this section of the reference documentation] * for more information. * * @asciidoclet @@ -118,7 +118,7 @@ public interface EventProcessorConfig { * but less stress on the database because of less frequent checks of the list of agents. * * See - * link:{hibernate-search-doc-prefix}#coordination-outbox-polling-event-processor[this section of the reference documentation] + * link:{hibernate-search-docs-url}#coordination-outbox-polling-event-processor[this section of the reference documentation] * for more information. * * @asciidoclet @@ -145,7 +145,7 @@ public interface EventProcessorConfig { * because an event processor is incorrectly considered disconnected. * * See - * link:{hibernate-search-doc-prefix}#coordination-outbox-polling-event-processor[this section of the reference documentation] + * link:{hibernate-search-docs-url}#coordination-outbox-polling-event-processor[this section of the reference documentation] * for more information. * * @asciidoclet @@ -163,7 +163,7 @@ public interface EventProcessorConfig { * but will increase memory usage and in extreme cases may lead to ``OutOfMemoryError``s. * * See - * link:{hibernate-search-doc-prefix}#coordination-outbox-polling-event-processor[this section of the reference documentation] + * link:{hibernate-search-docs-url}#coordination-outbox-polling-event-processor[this section of the reference documentation] * for more information. * * @asciidoclet @@ -182,7 +182,7 @@ public interface EventProcessorConfig { * If this happens, set a higher transaction timeout for event processing using this property. * * See - * link:{hibernate-search-doc-prefix}#coordination-outbox-polling-event-processor[this section of the reference documentation] + * link:{hibernate-search-docs-url}#coordination-outbox-polling-event-processor[this section of the reference documentation] * for more information. * * @asciidoclet @@ -197,7 +197,7 @@ public interface EventProcessorConfig { * Use the value `0S` to reprocess failed events as soon as possible, with no delay. * * See - * link:{hibernate-search-doc-prefix}#coordination-outbox-polling-event-processor[this section of the reference documentation] + * link:{hibernate-search-docs-url}#coordination-outbox-polling-event-processor[this section of the reference documentation] * for more information. * * @asciidoclet @@ -222,7 +222,7 @@ public interface EventProcessorShardsConfig { * is necessary. * * See - * link:{hibernate-search-doc-prefix}#coordination-outbox-polling-event-processor-sharding[this section of the reference documentation] + * link:{hibernate-search-docs-url}#coordination-outbox-polling-event-processor-sharding[this section of the reference documentation] * for more information about event processor sharding. * * @asciidoclet @@ -246,7 +246,7 @@ public interface EventProcessorShardsConfig { * by setting `shards.assigned` to a comma-separated list, e.g. `0,3`. * * See - * link:{hibernate-search-doc-prefix}#coordination-outbox-polling-event-processor-sharding[this section of the reference documentation] + * link:{hibernate-search-docs-url}#coordination-outbox-polling-event-processor-sharding[this section of the reference documentation] * for more information about event processor sharding. * * @asciidoclet @@ -273,7 +273,7 @@ public interface MassIndexerConfig { * but will reduce the stress on the database while the mass indexer agent is actively waiting. * * See - * link:{hibernate-search-doc-prefix}#coordination-outbox-polling-mass-indexer[this section of the reference documentation] + * link:{hibernate-search-docs-url}#coordination-outbox-polling-mass-indexer[this section of the reference documentation] * for more information. * * @asciidoclet @@ -301,7 +301,7 @@ public interface MassIndexerConfig { * but less stress on the database because of less frequent updates of the mass indexer agent's entry in the agent table. * * See - * link:{hibernate-search-doc-prefix}#coordination-outbox-polling-mass-indexer[this section of the reference documentation] + * link:{hibernate-search-docs-url}#coordination-outbox-polling-mass-indexer[this section of the reference documentation] * for more information. * * @asciidoclet @@ -328,7 +328,7 @@ public interface MassIndexerConfig { * because a mass indexer agent is incorrectly considered disconnected. * * See - * link:{hibernate-search-doc-prefix}#coordination-outbox-polling-mass-indexer[this section of the reference documentation] + * link:{hibernate-search-docs-url}#coordination-outbox-polling-mass-indexer[this section of the reference documentation] * for more information. * * @asciidoclet diff --git a/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/HibernateSearchElasticsearchBuildTimeConfigPersistenceUnit.java b/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/HibernateSearchElasticsearchBuildTimeConfigPersistenceUnit.java index b1924c7844759..1eecddafc2b5a 100644 --- a/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/HibernateSearchElasticsearchBuildTimeConfigPersistenceUnit.java +++ b/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/HibernateSearchElasticsearchBuildTimeConfigPersistenceUnit.java @@ -209,7 +209,7 @@ public interface LayoutConfig { * this strategy will create an index named `myindex`, and will not use any alias. * * See - * link:{hibernate-search-doc-prefix}#backend-elasticsearch-indexlayout[this section of the reference documentation] + * link:{hibernate-search-docs-url}#backend-elasticsearch-indexlayout[this section of the reference documentation] * for more information. * * [NOTE] diff --git a/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/HibernateSearchElasticsearchRuntimeConfigPersistenceUnit.java b/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/HibernateSearchElasticsearchRuntimeConfigPersistenceUnit.java index 6732df9ed16a9..e8ae2b3762dbd 100644 --- a/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/HibernateSearchElasticsearchRuntimeConfigPersistenceUnit.java +++ b/extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/HibernateSearchElasticsearchRuntimeConfigPersistenceUnit.java @@ -353,7 +353,7 @@ interface IndexingPlanSynchronizationConfig { * to a custom implementations of `IndexingPlanSynchronizationStrategy`. * * See - * link:{hibernate-search-doc-prefix}#indexing-plan-synchronization[this section of the reference documentation] + * link:{hibernate-search-docs-url}#indexing-plan-synchronization[this section of the reference documentation] * for more information. * * [NOTE] From be15a3a5da8fd2d1d60859c777eb364d0d3af896 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 23 Jun 2023 10:39:51 +0200 Subject: [PATCH 6/6] Fix dead link in Hibernate ORM extension docs --- docs/src/main/asciidoc/hibernate-orm.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/main/asciidoc/hibernate-orm.adoc b/docs/src/main/asciidoc/hibernate-orm.adoc index 6cbb3a8a923cf..079a228afd050 100644 --- a/docs/src/main/asciidoc/hibernate-orm.adoc +++ b/docs/src/main/asciidoc/hibernate-orm.adoc @@ -171,7 +171,7 @@ so at your application entry point boundaries like your REST endpoint controller [[hibernate-dialect-supported-databases]] ==== Supported databases -For xref:datasource.adoc#default-datasource[supported databases], +For xref:datasource.adoc#extensions-and-database-drivers-reference[supported databases], the link:{hibernate-orm-docs-url}#database-dialect[Hibernate ORM dialect] does not need to be set explicitly: it is selected automatically based on the datasource.