Skip to content

Commit 0d8cca6

Browse files
committed
HSEARCH-4577 Update the documentation
1 parent 918d260 commit 0d8cca6

File tree

9 files changed

+97
-35
lines changed

9 files changed

+97
-35
lines changed

documentation/src/main/asciidoc/migration/index.adoc

+3
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ interfaces are removed in this version. They have their alternatives in a `org.h
9999
Instead, we are introducing the `org.hibernate.search.mapper.pojo.massindexing.MassIndexingTypeGroupMonitor`
100100
that can be obtained through `org.hibernate.search.mapper.pojo.massindexing.MassIndexingMonitor#typeGroupMonitor(..)`.
101101
This new type group monitor has more flexibility and also allows implementors to skip total count computations if needed.
102+
- `multi()` methods exposed in various projection DSL steps are deprecated in favour of an `accumulator(ProjectionAccumulator.Provider)`.
103+
Check the `ProjectionAccumulator` factory methods to see the list of built-in accumulators that provide support for nullable/optional single-valued projections
104+
and for multivalued ones such as lists, sets arrays and more.
102105

103106
[[spi]]
104107
== SPI

documentation/src/main/asciidoc/public/reference/_binding-projection.adoc

+20-13
Original file line numberDiff line numberDiff line change
@@ -87,26 +87,32 @@ include::{sourcedir}/org/hibernate/search/documentation/mapper/orm/binding/proje
8787

8888
include::../components/_incubating-warning.adoc[]
8989

90-
You can call `.multi()` on the context passed to the projection binder
91-
in order to discover whether the constructor parameter being bound is multi-valued
92-
(according to the same rules as <<mapping-projection-inner-inference-type,implicit inner projection inference>>),
93-
and to bind a multi-valued projection.
90+
You can call `.containerElement()` on the context passed to the projection binder
91+
in order to discover whether the constructor parameter being bound is some sort of container wrapping the value/values
92+
(according to the same rules as <<mapping-projection-inner-inference-type,implicit inner projection inference>>).
93+
If the returned value is a non-empty optional, then the `.constructorParameter()` will provide access to the container type in use.
94+
Additionally, the same context has access to a factory (`.projectionAccumulatorProviderFactory()`)
95+
from which a projection accumulator can be obtained based on a container and element types
96+
(if the container type is `null` the `nullable()` single-valued accumulator is returned).
9497

9598
.Implementing and using a `ProjectionBinder` supporting multi-valued projections
9699
====
97100
[source, JAVA, indent=0, subs="+callouts"]
98101
----
99102
include::{sourcedir}/org/hibernate/search/documentation/mapper/orm/binding/projectionbinder/multi/MyFieldProjectionBinder.java[tags=include]
100103
----
101-
<1> `multi()` returns an optional that contains a context
102-
if and only if the constructor parameter is considered multi-valued.
103-
<2> Call `multi.definition(...)` to define the projection to use.
104-
<3> Here we're failing for single-valued constructor parameters,
105-
but we could theoreticall fall back to a single-valued projection.
106-
<4> The projection definition, being multi-valued,
107-
must implement `ProjectionDefinition<List<T>>`,
108-
where `T` is the exepected type of projected values,
104+
<1> `containerElement()` returns an optional that contains a type of the container elements
105+
if and only if the constructor parameter is considered as such that is wrapped in a container, e.g. a multivalued collection.
106+
<2> Call `context.definition(...)` to define the projection to use.
107+
<3> Here we're failing for single-valued (nullable) constructor parameters,
108+
but we could theoretically fall back to a single-valued projection using the `ProjectionAccumulator.nullable()`.
109+
<4> The projection definition, being multivalued,
110+
must implement `ProjectionDefinition<SomeCollection<T>>`,
111+
where `T` is the expected type of projected values,
112+
`SomeCollection` is one of the supported collection types available in `ProjectionAccumulator`,
109113
and must configure returned projections accordingly.
114+
If the required collection type is not present in the `ProjectionAccumulator`,
115+
then a custom projection accumulator provider can be supplied.
110116
111117
[source, JAVA, indent=0, subs="+callouts"]
112118
----
@@ -138,7 +144,8 @@ or by delegating to it in a custom projection definition.
138144

139145
Other methods exposed on the binding context work similarly:
140146

141-
* `.createObjectDefinitionMulti(...)` returns a <<binding-projection-multi,multi-valued>> object projection definition.
147+
* `.createObjectDefinition(..., ProjectionAccumulator.Provider)` returns an object projection definition with the provided accumulator applied
148+
and can be used for <<binding-projection-multi,multivalued>> object projections or object projections wrapped in some other containers.
142149
* `.createCompositeDefinition(...)` returns a (single-valued)
143150
<<search-dsl-projection-composite,composite projection>> definition
144151
(which, on contrary to an <<search-dsl-projection-object,object projection>>, is not bound to an object field in the index).

documentation/src/main/asciidoc/public/reference/_mapping-projection.adoc

+15-6
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ See <<mapping-projection-inner-inference>> for more information on how construct
3939
+
4040
Alternatively, the field projection can be configured explicitly with <<search-dsl-projection-field-mapping,`@FieldProjection`>>.
4141
<4> To project on an object field, add a constructor parameter named after that field and with its own custom projection type.
42-
Multivalued projections <<mapping-projection-inner-inference-type,must be modeled as a `List<...>`>> or supertype.
42+
Multivalued projections <<mapping-projection-inner-inference-type,must be modeled as one of the multivalued containers available in `ProjectionAccumulator`>> or their supertype.
4343
+
4444
Alternatively, the object projection can be configured explicitly with <<search-dsl-projection-object-mapping,`@ObjectProjection`>>.
4545
<5> Annotate any custom projection type used for object fields with `@ProjectionConstructor` as well.
@@ -106,18 +106,27 @@ for the target field, which in general is the type of the property annotated wit
106106
(generally mapped using <<mapping-indexedembedded,`@IndexedEmbedded`>>),
107107
set the parameter type to another custom type annotated with `@ProjectionConstructor`,
108108
whose constructor will define which fields to extract from that object field.
109-
* For a multivalued projection, follow the rules above then wrap the type with `Iterable`, `Collection` or `List`,
110-
e.g. `Iterable<SomeType>`, `Collection<SomeType>` or `List<SomeType>`.
109+
* For projections where values are wrapped in some container, be it a multivalued projection represented by some collection or array,
110+
or a single-valued projection wrapped in an optional,
111+
follow the rules above for the elements inside the container and then wrap the type with one of the containers
112+
available in `ProjectionAccumulator` (`Iterable`, `Collection`, `List`, etc.),
113+
e.g. `Iterable<SomeType>`, `Collection<SomeType>`, `List<SomeType>`, etc.
111114

112115
[IMPORTANT]
113116
====
114117
Constructor parameters meant to represent a multivalued projection
115-
can **only** have the type `Iterable<...>`, `Collection<...>` or `List<...>`.
118+
**must** have the type of one of the supported multivalued containers.
119+
====
116120

117-
Other container types such as `Map` or `Optional` are not supported
118-
https://hibernate.atlassian.net/browse/HSEARCH-4577[at the moment].
121+
[NOTE]
122+
====
123+
In case the `ProjectionAccumulator` does not provide a suitable accumulator for a container/collection
124+
needed for a constructor parameter mapping, <<binding-projection-multi,a custom projection binding>> can be implemented
125+
and a user-implemented projection accumulator applied.
119126
====
120127

128+
129+
121130
[[mapping-projection-inner-inference-fieldpath]]
122131
=== [[mapper-orm-mapping-projection-inner-inference-fieldpath]] Inner projection and field path
123132

documentation/src/main/asciidoc/public/reference/_search-dsl-projection.adoc

+6-6
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ See <<mapping-projection-inner-inference>> for more information on how construct
7272
+
7373
Alternatively, the field projection can be configured explicitly with <<search-dsl-projection-field-mapping,`@FieldProjection`>>.
7474
<4> To project on an object field, add a constructor parameter named after that field and with its own custom projection type.
75-
Multivalued projections <<mapping-projection-inner-inference-type,must be modeled as a `List<...>`>> or supertype.
75+
Multivalued projections <<mapping-projection-inner-inference-type,must be modeled as one of the multivalued containers available in `ProjectionAccumulator`>> or their supertype.
7676
+
7777
Alternatively, the object projection can be configured explicitly with <<search-dsl-projection-object-mapping,`@ObjectProjection`>>.
7878
<5> Annotate any custom projection type used for object fields with `@ProjectionConstructor` as well.
@@ -403,8 +403,8 @@ include::{sourcedir}/org/hibernate/search/documentation/search/projection/Projec
403403
[[search-dsl-projection-field-multivalued]]
404404
=== Multivalued fields
405405

406-
To return multiple values, and thus allow projection on multivalued fields, use `.multi()`.
407-
This will change the return type of the projection to `List<T>` where `T` is what the single-valued projection
406+
To return multiple values, and thus allow projection on multivalued fields, use `.accumulator(..)`.
407+
This will change the return type of the projection to `SomeContainer<T>` where `T` is what the single-valued projection
408408
would have returned.
409409

410410
.Returning field values from matched documents, for multivalued fields
@@ -610,8 +610,8 @@ include::{sourcedir}/org/hibernate/search/documentation/search/projection/Projec
610610
[[search-dsl-projection-distance-multivalued]]
611611
=== Multivalued fields
612612

613-
To return multiple values, and thus allow projection on multivalued fields, use `.multi()`.
614-
This will change the return type of the projection to `List<Double>`.
613+
To return multiple values, and thus allow projection on multivalued fields, use `.accumulator(..)`.
614+
This will change the return type of the projection to `SomeContainer<Double>`.
615615

616616
.Returning the distance to a point, for multivalued fields
617617
====
@@ -834,7 +834,7 @@ See <<mapping-projection-inner-inference>> for more information on how construct
834834
+
835835
Alternatively, the field projection can be configured explicitly with <<search-dsl-projection-field-mapping,`@FieldProjection`>>.
836836
<4> To project on an object field, add a constructor parameter named after that field and with its own custom projection type.
837-
Multivalued projections <<mapping-projection-inner-inference-type,must be modeled as a `List<...>`>> or supertype.
837+
Multivalued projections <<mapping-projection-inner-inference-type,must be modeled as one of the multivalued containers available in `ProjectionAccumulator`>> or their supertype.
838838
+
839839
Alternatively, the object projection can be configured explicitly with <<search-dsl-projection-object-mapping,`@ObjectProjection`>>.
840840
<5> Annotate any custom projection type used for object fields with `@ProjectionConstructor` as well.

engine/src/main/java/org/hibernate/search/engine/search/projection/ProjectionAccumulator.java

+42-4
Original file line numberDiff line numberDiff line change
@@ -39,34 +39,72 @@
3939
*/
4040
public interface ProjectionAccumulator<E, V, A, R> {
4141

42+
/**
43+
* @return The projection accumulator capable of accumulating single-valued projections in an as-is form,
44+
* i.e. the value is returned without any extra transformations.
45+
* @param <V> The type of values to accumulate.
46+
*/
4247
static <V> ProjectionAccumulator.Provider<V, V> nullable() {
4348
return BuiltInProjectionAccumulators.nullable();
4449
}
4550

46-
static <V> Provider<V, List<V>> list() {
47-
return BuiltInProjectionAccumulators.list();
51+
/**
52+
* @return The projection accumulator capable of accumulating single-valued projections and wrapping the values in an {@link Optional}.
53+
* @param <V> The type of values to accumulate.
54+
*/
55+
static <V> Provider<V, Optional<V>> optional() {
56+
return BuiltInProjectionAccumulators.optional();
4857
}
4958

59+
/**
60+
* @param converter The function that defines how to convert a list of collected values to the final collection.
61+
* @return An accumulator based on a list as a temporary storage.
62+
* @param <V> The type of values to accumulate.
63+
* @param <C> The type of the resulting collection.
64+
*/
5065
static <V, C> Provider<V, C> simple(Function<List<V>, C> converter) {
5166
return BuiltInProjectionAccumulators.simple( converter );
5267
}
5368

54-
static <V> Provider<V, Optional<V>> optional() {
55-
return BuiltInProjectionAccumulators.optional();
69+
/**
70+
* @return The projection accumulator capable of accumulating multivalued projections as a {@link List}.
71+
* @param <V> The type of values to accumulate.
72+
*/
73+
static <V> Provider<V, List<V>> list() {
74+
return BuiltInProjectionAccumulators.list();
5675
}
5776

77+
/**
78+
* @return The projection accumulator capable of accumulating multivalued projections as a {@link Set}.
79+
* @param <V> The type of values to accumulate.
80+
*/
5881
static <V> Provider<V, Set<V>> set() {
5982
return BuiltInProjectionAccumulators.set();
6083
}
6184

85+
/**
86+
* @return The projection accumulator capable of accumulating multivalued projections as a {@link SortedSet}.
87+
* @param <V> The type of values to accumulate.
88+
*/
6289
static <V> Provider<V, SortedSet<V>> sortedSet() {
6390
return BuiltInProjectionAccumulators.sortedSet();
6491
}
6592

93+
/**
94+
* @return The projection accumulator capable of accumulating multivalued projections as a {@link SortedSet}
95+
* using a custom comparator.
96+
* @param comparator The comparator which should be used by the sorted set.
97+
* @param <V> The type of values to accumulate.
98+
*/
6699
static <V> Provider<V, SortedSet<V>> sortedSet(Comparator<? super V> comparator) {
67100
return BuiltInProjectionAccumulators.sortedSet( comparator );
68101
}
69102

103+
/**
104+
* @return The projection accumulator capable of accumulating multivalued projections as an array.
105+
* @param componentType The type of the array elements.
106+
* @param <V> The type of values to accumulate.
107+
*/
70108
static <V> Provider<V, V[]> array(Class<? super V> componentType) {
71109
return BuiltInProjectionAccumulators.array( componentType );
72110
}
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@
22
* SPDX-License-Identifier: Apache-2.0
33
* Copyright Red Hat Inc. and Hibernate Authors
44
*/
5-
package org.hibernate.search.engine.search.projection.dsl;
5+
package org.hibernate.search.engine.search.projection;
66

7-
import org.hibernate.search.engine.search.projection.ProjectionAccumulator;
87
import org.hibernate.search.util.common.annotation.Incubating;
98

109
/**
@@ -16,6 +15,8 @@ public interface ProjectionAccumulatorProviderFactory {
1615
/**
1716
*
1817
* @param containerType The type of the expected container.
18+
* Passing a {@code null} value as a container type will result in {@link ProjectionAccumulator#nullable() a nullable accumulator}
19+
* being returned, i.e. an accumulator that does not wrap the value in any sort of container.
1920
* @param containerElementType The type of the container elements
2021
* @return The projection accumulator provider for a requested container/element types.
2122
* @param <U> The type of values to accumulate after being transformed.

mapper/pojo-base/src/main/java/org/hibernate/search/mapper/pojo/logging/impl/Log.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -1050,8 +1050,7 @@ void indexingProgressWithRemainingTime(float estimatePercentileComplete, long do
10501050

10511051
@Message(id = ID_OFFSET + 170,
10521052
value = "Implicit binding of a java.util.SortedSet<%1$s> constructor parameter is not possible since %1$s is not implementing java.lang.Comparable."
1053-
+ " Either make %1$s implement java.lang.Comparable or use a programmatic mapping and provide"
1054-
+ " a custom ProjectionAccumulatorProviderFactory that, for example, utilizes a ProjectionAccumulator.sortedSet(comparator) accumulator provider.")
1053+
+ " Either make %1$s implement java.lang.Comparable or create a custom @ProjectionBinding and use the ProjectionAccumulator.sortedSet(comparator) accumulator provider in it.")
10551054
SearchException cannotBindSortedSetWithNonComparableElements(@FormatWith(ClassFormatter.class) Class<?> elementType,
10561055
@Param EventContext eventContext);
10571056
}

mapper/pojo-base/src/main/java/org/hibernate/search/mapper/pojo/search/definition/binding/ProjectionBindingContext.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
import org.hibernate.search.engine.environment.bean.BeanReference;
1414
import org.hibernate.search.engine.environment.bean.BeanResolver;
1515
import org.hibernate.search.engine.search.projection.ProjectionAccumulator;
16+
import org.hibernate.search.engine.search.projection.ProjectionAccumulatorProviderFactory;
1617
import org.hibernate.search.engine.search.projection.definition.ProjectionDefinition;
17-
import org.hibernate.search.engine.search.projection.dsl.ProjectionAccumulatorProviderFactory;
1818
import org.hibernate.search.engine.search.projection.dsl.SearchProjectionFactory;
1919
import org.hibernate.search.mapper.pojo.bridge.mapping.annotation.PropertyBinderRef;
2020
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.ObjectProjection;
@@ -219,6 +219,10 @@ <C, T> BeanHolder<? extends ProjectionDefinition<C>> createObjectDefinition(Stri
219219
*/
220220
boolean isIncluded(String fieldPath);
221221

222+
/**
223+
* @return An instance of a projection accumulator provider factory capable of supplying an accumulator provider
224+
* based on a container and component types.
225+
*/
222226
@Incubating
223227
ProjectionAccumulatorProviderFactory projectionAccumulatorProviderFactory();
224228

mapper/pojo-base/src/main/java/org/hibernate/search/mapper/pojo/search/definition/binding/impl/ProjectionBindingContextImpl.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@
2121
import org.hibernate.search.engine.environment.bean.BeanResolver;
2222
import org.hibernate.search.engine.mapper.model.spi.MappingElement;
2323
import org.hibernate.search.engine.search.projection.ProjectionAccumulator;
24+
import org.hibernate.search.engine.search.projection.ProjectionAccumulatorProviderFactory;
2425
import org.hibernate.search.engine.search.projection.definition.ProjectionDefinition;
2526
import org.hibernate.search.engine.search.projection.definition.spi.CompositeProjectionDefinition;
2627
import org.hibernate.search.engine.search.projection.definition.spi.ConstantProjectionDefinition;
2728
import org.hibernate.search.engine.search.projection.definition.spi.ObjectProjectionDefinition;
28-
import org.hibernate.search.engine.search.projection.dsl.ProjectionAccumulatorProviderFactory;
2929
import org.hibernate.search.mapper.pojo.extractor.builtin.BuiltinContainerExtractors;
3030
import org.hibernate.search.mapper.pojo.extractor.impl.BoundContainerExtractorPath;
3131
import org.hibernate.search.mapper.pojo.extractor.mapping.programmatic.ContainerExtractorPath;
@@ -359,6 +359,7 @@ BeanHolder<? extends ProjectionDefinition<? extends P>> complete() {
359359
}
360360
}
361361

362+
@Deprecated(since = "8.0")
362363
public class MultiContextImpl<PV> implements ProjectionBindingMultiContext {
363364
public final PojoTypeModel<PV> parameterContainerElementTypeModel;
364365
private final PojoModelValue<PV> parameterContainerElementRootElement;

0 commit comments

Comments
 (0)