Skip to content

Commit a6d1f74

Browse files
committed
HSEARCH-5235 WIP: draft of injecting field references
1 parent 204633f commit a6d1f74

File tree

49 files changed

+1004
-59
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1004
-59
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.search.documentation.mapper.orm.binding.document.model.dsl.injection;
6+
7+
import jakarta.persistence.Convert;
8+
import jakarta.persistence.Entity;
9+
import jakarta.persistence.GeneratedValue;
10+
import jakarta.persistence.Id;
11+
12+
import org.hibernate.search.documentation.testsupport.data.ISBN;
13+
import org.hibernate.search.documentation.testsupport.data.ISBNAttributeConverter;
14+
import org.hibernate.search.mapper.pojo.bridge.mapping.annotation.PropertyBinderRef;
15+
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.GenericField;
16+
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.Indexed;
17+
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.PropertyBinding;
18+
19+
@Entity
20+
@Indexed
21+
public class Book {
22+
23+
@Id
24+
@GeneratedValue
25+
@GenericField
26+
private Integer id;
27+
28+
@Convert(converter = ISBNAttributeConverter.class)
29+
@PropertyBinding(binder = @PropertyBinderRef(type = ISBNBinder.class))
30+
private ISBN isbn;
31+
32+
public Integer getId() {
33+
return id;
34+
}
35+
36+
public ISBN getIsbn() {
37+
return isbn;
38+
}
39+
40+
public void setIsbn(ISBN isbn) {
41+
this.isbn = isbn;
42+
}
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.search.documentation.mapper.orm.binding.document.model.dsl.injection;
6+
7+
import static org.assertj.core.api.Assertions.assertThat;
8+
import static org.hibernate.search.util.impl.integrationtest.mapper.orm.OrmUtils.with;
9+
10+
import java.util.Arrays;
11+
import java.util.List;
12+
13+
import jakarta.persistence.EntityManagerFactory;
14+
15+
import org.hibernate.search.documentation.testsupport.BackendConfigurations;
16+
import org.hibernate.search.documentation.testsupport.DocumentationSetupHelper;
17+
import org.hibernate.search.documentation.testsupport.data.ISBN;
18+
import org.hibernate.search.mapper.orm.Search;
19+
import org.hibernate.search.mapper.orm.session.SearchSession;
20+
21+
import org.junit.jupiter.api.BeforeEach;
22+
import org.junit.jupiter.api.Test;
23+
import org.junit.jupiter.api.extension.RegisterExtension;
24+
25+
class DocumentModelDslInjectIT {
26+
@RegisterExtension
27+
public DocumentationSetupHelper setupHelper = DocumentationSetupHelper.withSingleBackend( BackendConfigurations.simple() );
28+
29+
private EntityManagerFactory entityManagerFactory;
30+
31+
@BeforeEach
32+
void setup() {
33+
entityManagerFactory = setupHelper.start().setup( Book.class );
34+
}
35+
36+
@Test
37+
void smoke() {
38+
with( entityManagerFactory ).runInTransaction( entityManager -> {
39+
Book book = new Book();
40+
book.setIsbn( ISBN.parse( "978-0-58-600835-5" ) );
41+
entityManager.persist( book );
42+
} );
43+
44+
with( entityManagerFactory ).runInTransaction( entityManager -> {
45+
SearchSession searchSession = Search.session( entityManager );
46+
47+
List<Book> result = searchSession.search( Arrays.asList( Book.class ) )
48+
.where( f -> f.match().field( "isbn" ).matching( "978-0-58-600835-5" ) )
49+
.fetchHits( 20 );
50+
51+
assertThat( result ).hasSize( 1 );
52+
} );
53+
}
54+
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.search.documentation.mapper.orm.binding.document.model.dsl.injection;
6+
7+
import org.hibernate.search.documentation.testsupport.data.ISBN;
8+
import org.hibernate.search.engine.backend.document.DocumentElement;
9+
import org.hibernate.search.engine.backend.document.IndexFieldReference;
10+
import org.hibernate.search.mapper.pojo.bridge.PropertyBridge;
11+
import org.hibernate.search.mapper.pojo.bridge.binding.PropertyBindingContext;
12+
import org.hibernate.search.mapper.pojo.bridge.mapping.programmatic.PropertyBinder;
13+
import org.hibernate.search.mapper.pojo.bridge.runtime.PropertyBridgeWriteContext;
14+
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.KeywordField;
15+
16+
//tag::bind[]
17+
public class ISBNBinder implements PropertyBinder {
18+
19+
@KeywordField(normalizer = "isbn")
20+
IndexFieldReference<String> isbn;
21+
22+
IndexFieldReference<String> isbnNoAnnotation;
23+
24+
@Override
25+
public void bind(PropertyBindingContext context) {
26+
context.dependencies()
27+
.useRootOnly();
28+
29+
context.bridge( // <6>
30+
ISBN.class, // <7>
31+
new ISBNBridge( isbn ) // <8>
32+
);
33+
}
34+
//end::bind[]
35+
36+
//tag::write[]
37+
private static class ISBNBridge implements PropertyBridge<ISBN> {
38+
39+
private final IndexFieldReference<String> fieldReference;
40+
41+
private ISBNBridge(IndexFieldReference<String> fieldReference) {
42+
this.fieldReference = fieldReference;
43+
}
44+
45+
@Override
46+
public void write(DocumentElement target, ISBN bridgedElement, PropertyBridgeWriteContext context) {
47+
String indexedValue = /* ... (extraction of data, not relevant) ... */
48+
//end::write[]
49+
bridgedElement.getStringValue();
50+
//tag::write[]
51+
target.addValue( this.fieldReference, indexedValue ); // <1>
52+
}
53+
}
54+
//end::write[]
55+
//tag::bind[]
56+
}
57+
//end::bind[]

mapper/orm/src/main/java/org/hibernate/search/mapper/orm/model/impl/HibernateOrmBootstrapIntrospector.java

+8-4
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import org.hibernate.models.spi.ClassDetailsRegistry;
2222
import org.hibernate.search.mapper.orm.logging.impl.MappingLog;
2323
import org.hibernate.search.mapper.pojo.model.models.spi.AbstractPojoModelsBootstrapIntrospector;
24-
import org.hibernate.search.mapper.pojo.model.models.spi.PojoModelsGenericContextHelper;
2524
import org.hibernate.search.mapper.pojo.model.spi.AbstractPojoRawTypeModel;
2625
import org.hibernate.search.mapper.pojo.model.spi.GenericContextAwarePojoGenericTypeModel.RawTypeDeclaringContext;
2726
import org.hibernate.search.mapper.pojo.model.spi.PojoBootstrapIntrospector;
@@ -30,6 +29,7 @@
3029
import org.hibernate.search.util.common.reflect.spi.ValueCreateHandle;
3130
import org.hibernate.search.util.common.reflect.spi.ValueHandleFactory;
3231
import org.hibernate.search.util.common.reflect.spi.ValueReadHandle;
32+
import org.hibernate.search.util.common.reflect.spi.ValueReadWriteHandle;
3333

3434
public class HibernateOrmBootstrapIntrospector extends AbstractPojoModelsBootstrapIntrospector
3535
implements PojoBootstrapIntrospector {
@@ -44,7 +44,6 @@ public static HibernateOrmBootstrapIntrospector create(
4444
}
4545

4646
private final HibernateOrmBasicTypeMetadataProvider basicTypeMetadataProvider;
47-
private final PojoModelsGenericContextHelper genericContextHelper;
4847

4948
/*
5049
* Note: the main purpose of these caches is not to improve performance,
@@ -64,11 +63,10 @@ private HibernateOrmBootstrapIntrospector(
6463
ValueHandleFactory valueHandleFactory) {
6564
super( classDetailsRegistry, valueHandleFactory );
6665
this.basicTypeMetadataProvider = basicTypeMetadataProvider;
67-
this.genericContextHelper = new PojoModelsGenericContextHelper( this );
6866
}
6967

7068
@Override
71-
public AbstractPojoRawTypeModel<?, ?> typeModel(String name) {
69+
public AbstractPojoRawTypeModel<?, ?, ?> typeModel(String name) {
7270
HibernateOrmBasicDynamicMapTypeMetadata dynamicMapTypeOrmMetadata =
7371
basicTypeMetadataProvider.getBasicDynamicMapTypeMetadata( name );
7472
if ( dynamicMapTypeOrmMetadata != null ) {
@@ -112,6 +110,12 @@ protected ValueReadHandle<?> createValueReadHandle(Member member) throws Illegal
112110
return super.createValueReadHandle( member );
113111
}
114112

113+
@Override
114+
protected ValueReadWriteHandle<?> createValueReadWriteHandle(Member member) throws IllegalAccessException {
115+
setAccessible( member );
116+
return super.createValueReadWriteHandle( member );
117+
}
118+
115119
ValueReadHandle<?> createValueReadHandle(Class<?> holderClass, Member member,
116120
HibernateOrmBasicClassPropertyMetadata ormPropertyMetadata)
117121
throws IllegalAccessException {

mapper/orm/src/main/java/org/hibernate/search/mapper/orm/model/impl/HibernateOrmClassPropertyModel.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import org.hibernate.search.util.common.reflect.spi.ValueReadHandle;
1313

1414
class HibernateOrmClassPropertyModel<T>
15-
extends AbstractPojoModelsPropertyModel<T, HibernateOrmBootstrapIntrospector> {
15+
extends AbstractPojoModelsPropertyModel<T, HibernateOrmBootstrapIntrospector, ValueReadHandle<T>> {
1616

1717
private final HibernateOrmBasicClassPropertyMetadata ormPropertyMetadata;
1818

mapper/orm/src/main/java/org/hibernate/search/mapper/orm/model/impl/HibernateOrmClassRawTypeModel.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@
1818
import org.hibernate.models.spi.MemberDetails;
1919
import org.hibernate.search.mapper.pojo.model.models.spi.AbstractPojoModelsRawTypeModel;
2020
import org.hibernate.search.mapper.pojo.model.spi.GenericContextAwarePojoGenericTypeModel.RawTypeDeclaringContext;
21+
import org.hibernate.search.mapper.pojo.model.spi.PojoPropertyModel;
2122
import org.hibernate.search.mapper.pojo.model.spi.PojoRawTypeIdentifier;
2223

2324
public class HibernateOrmClassRawTypeModel<T>
24-
extends AbstractPojoModelsRawTypeModel<T, HibernateOrmBootstrapIntrospector> {
25+
extends AbstractPojoModelsRawTypeModel<T, HibernateOrmBootstrapIntrospector, PojoPropertyModel<?>> {
2526

2627
private final HibernateOrmBasicClassTypeMetadata ormTypeMetadata;
2728

mapper/orm/src/main/java/org/hibernate/search/mapper/orm/model/impl/HibernateOrmDynamicMapRawTypeModel.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@
1414
import org.hibernate.search.engine.mapper.model.spi.MappableTypeModel;
1515
import org.hibernate.search.mapper.pojo.model.spi.AbstractPojoRawTypeModel;
1616
import org.hibernate.search.mapper.pojo.model.spi.PojoConstructorModel;
17+
import org.hibernate.search.mapper.pojo.model.spi.PojoPropertyModel;
1718
import org.hibernate.search.mapper.pojo.model.spi.PojoRawTypeIdentifier;
1819
import org.hibernate.search.mapper.pojo.model.spi.PojoRawTypeModel;
1920
import org.hibernate.search.mapper.pojo.model.spi.PojoTypeModel;
2021

2122
@SuppressWarnings("rawtypes")
2223
public class HibernateOrmDynamicMapRawTypeModel
23-
extends AbstractPojoRawTypeModel<Map, HibernateOrmBootstrapIntrospector> {
24+
extends AbstractPojoRawTypeModel<Map, HibernateOrmBootstrapIntrospector, PojoPropertyModel<?>> {
2425

2526
private final HibernateOrmBasicDynamicMapTypeMetadata ormTypeMetadata;
2627

mapper/pojo-base/src/main/java/org/hibernate/search/mapper/pojo/bridge/binding/impl/PropertyBindingContextImpl.java

+17
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@
1414
import org.hibernate.search.engine.mapper.mapping.building.spi.IndexBindingContext;
1515
import org.hibernate.search.mapper.pojo.bridge.PropertyBridge;
1616
import org.hibernate.search.mapper.pojo.bridge.binding.PropertyBindingContext;
17+
import org.hibernate.search.mapper.pojo.bridge.mapping.impl.BeanDelegatingBinder;
1718
import org.hibernate.search.mapper.pojo.bridge.mapping.programmatic.PropertyBinder;
1819
import org.hibernate.search.mapper.pojo.logging.impl.MappingLog;
20+
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.impl.PojoInjectableBinderInjector;
1921
import org.hibernate.search.mapper.pojo.model.PojoModelProperty;
2022
import org.hibernate.search.mapper.pojo.model.dependency.PojoPropertyIndexingDependencyConfigurationContext;
2123
import org.hibernate.search.mapper.pojo.model.dependency.impl.PojoPropertyIndexingDependencyConfigurationContextImpl;
@@ -31,6 +33,7 @@ public class PropertyBindingContextImpl<P> extends AbstractCompositeBindingConte
3133
implements PropertyBindingContext {
3234

3335
private final PojoBootstrapIntrospector introspector;
36+
private final PojoInjectableBinderInjector binderInjector;
3437
private final PojoTypeModel<?> propertyTypeModel;
3538
private final PojoModelPropertyRootElement<P> bridgedElement;
3639
private final PojoPropertyIndexingDependencyConfigurationContextImpl<P> dependencyContext;
@@ -42,13 +45,15 @@ public class PropertyBindingContextImpl<P> extends AbstractCompositeBindingConte
4245

4346
public PropertyBindingContextImpl(BeanResolver beanResolver,
4447
PojoBootstrapIntrospector introspector,
48+
PojoInjectableBinderInjector binderInjector,
4549
PojoTypeModel<P> propertyTypeModel,
4650
IndexBindingContext indexBindingContext,
4751
PojoModelPropertyRootElement<P> bridgedElement,
4852
PojoPropertyIndexingDependencyConfigurationContextImpl<P> dependencyContext,
4953
Map<String, Object> params) {
5054
super( beanResolver, params );
5155
this.introspector = introspector;
56+
this.binderInjector = binderInjector;
5257
this.propertyTypeModel = propertyTypeModel;
5358
this.bridgedElement = bridgedElement;
5459
this.dependencyContext = dependencyContext;
@@ -90,6 +95,11 @@ public IndexSchemaElement indexSchemaElement() {
9095
public Optional<BoundPropertyBridge<P>> applyBinder(PropertyBinder binder) {
9196
try {
9297
// This call should set the partial binding
98+
// TODO: we probably should delay the injection of the binder properties till this point
99+
// here we have access to the index schema element and can create the sub-elements we need.
100+
if ( !BeanDelegatingBinder.class.equals( binder.getClass() ) ) {
101+
injectBinderFields( binder );
102+
}
93103
binder.bind( this );
94104
if ( partialBinding == null ) {
95105
throw MappingLog.INSTANCE.missingBridgeForBinder( binder );
@@ -135,6 +145,13 @@ private <P2> void checkAndBind(BeanHolder<? extends PropertyBridge<P2>> bridgeHo
135145
this.partialBinding = new PartialBinding<>( castedBridgeHolder );
136146
}
137147

148+
// TODO: if users have their delegating binders, those won't get injected with fields ...
149+
// we probably do not care as much about it as in that case we won't get anything out for the static model ...
150+
// but just in case we think of some valid use case then maybe expose this method (or rather whatever it will grow into) through the context to the user.
151+
public void injectBinderFields(PropertyBinder binder) {
152+
binderInjector.injectFields( binder, indexSchemaElement, params() );
153+
}
154+
138155
private static class PartialBinding<P> {
139156
private final BeanHolder<? extends PropertyBridge<? super P>> bridgeHolder;
140157

mapper/pojo-base/src/main/java/org/hibernate/search/mapper/pojo/bridge/mapping/impl/BeanDelegatingBinder.java

+12-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import org.hibernate.search.mapper.pojo.bridge.binding.RoutingBindingContext;
1414
import org.hibernate.search.mapper.pojo.bridge.binding.TypeBindingContext;
1515
import org.hibernate.search.mapper.pojo.bridge.binding.ValueBindingContext;
16+
import org.hibernate.search.mapper.pojo.bridge.binding.impl.PropertyBindingContextImpl;
1617
import org.hibernate.search.mapper.pojo.bridge.mapping.programmatic.IdentifierBinder;
1718
import org.hibernate.search.mapper.pojo.bridge.mapping.programmatic.MarkerBinder;
1819
import org.hibernate.search.mapper.pojo.bridge.mapping.programmatic.PropertyBinder;
@@ -29,9 +30,11 @@ public final class BeanDelegatingBinder
2930
MarkerBinder, IdentifierBinder, ValueBinder {
3031

3132
private final BeanReference<?> delegateReference;
33+
private final Class<?> type;
3234

33-
public BeanDelegatingBinder(BeanReference<?> delegateReference) {
35+
public BeanDelegatingBinder(BeanReference<?> delegateReference, Class<?> type) {
3436
this.delegateReference = delegateReference;
37+
this.type = type;
3538
}
3639

3740
@Override
@@ -51,7 +54,11 @@ public void bind(TypeBindingContext context) {
5154
public void bind(PropertyBindingContext context) {
5255
try ( BeanHolder<? extends PropertyBinder> delegateHolder =
5356
createDelegate( context.beanResolver(), PropertyBinder.class ) ) {
54-
delegateHolder.get().bind( context );
57+
PropertyBinder binder = delegateHolder.get();
58+
// TODO: injecting into this delegating binder itself will make no sense,
59+
// and we need to inject into the delegate itself ...
60+
( (PropertyBindingContextImpl) context ).injectBinderFields( binder );
61+
binder.bind( context );
5562
}
5663
}
5764

@@ -91,4 +98,7 @@ private <B> BeanHolder<? extends B> createDelegate(BeanResolver beanResolver, Cl
9198
return delegateReference.asSubTypeOf( expectedType ).resolve( beanResolver );
9299
}
93100

101+
public Class<?> getDelegateType() {
102+
return type;
103+
}
94104
}

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

+8
Original file line numberDiff line numberDiff line change
@@ -713,4 +713,12 @@ SearchException usingNonDefaultValueConvertAndValueModelNotAllowed(String model,
713713

714714
@Message(id = ID_OFFSET + 170, value = "Property name '%1$s' cannot contain dots.")
715715
IllegalArgumentException propertyNameCannotContainDots(String propertyName);
716+
717+
@Message(id = ID_OFFSET + 179, value = "Unable to retrieve injectable binder model for class '%1$s'.")
718+
SearchException errorRetrievingInjectableBinderModel(@FormatWith(ClassFormatter.class) Class<?> clazz,
719+
@Cause Exception cause);
720+
721+
@LogMessage(level = Logger.Level.DEBUG)
722+
@Message(id = ID_OFFSET + 180, value = "Unable to retrieve injectable binder model for class '%1$s': %2$s")
723+
void cannotLoadClassDetailsButIgnore(@FormatWith(ClassFormatter.class) Class<?> binderType, String message);
716724
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public interface PojoMapperLog
5555
* here to the next value.
5656
*/
5757
@LogMessage(level = TRACE)
58-
@Message(id = ID_OFFSET + 179, value = "")
58+
@Message(id = ID_OFFSET + 181, value = "")
5959
void nextLoggerIdForConvenience();
6060

6161
}

0 commit comments

Comments
 (0)