Skip to content

Commit 1dd55a0

Browse files
committed
HSEARCH-5300 More tests and addressing enum for all (?) scenarios
1 parent 0cfc2db commit 1dd55a0

26 files changed

+909
-116
lines changed

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

+5-1
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,18 @@ public <I2> void bridge(Class<I2> expectedValueType, BeanHolder<? extends Identi
6767
@SuppressWarnings("unchecked") // We check that I2 equals I explicitly using reflection (see above)
6868
Class<I> castedExpectedType = (Class<I>) expectedValueType;
6969

70-
this.partialBinding = new PartialBinding<>( castedBridgeHolder, castedExpectedType );
70+
applyBridge( castedExpectedType, castedBridgeHolder );
7171
}
7272
catch (RuntimeException e) {
7373
abortBridge( new SuppressingCloser( e ), bridgeHolder );
7474
throw e;
7575
}
7676
}
7777

78+
public void applyBridge(Class<I> expectedValueType, BeanHolder<? extends IdentifierBridge<I>> bridgeHolder) {
79+
this.partialBinding = new PartialBinding<>( bridgeHolder, expectedValueType );
80+
}
81+
7882
@Override
7983
public PojoModelValue<I> bridgedElement() {
8084
return bridgedElement;

mapper/pojo-base/src/main/java/org/hibernate/search/mapper/pojo/model/impl/PojoModelValueElement.java

+4
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,8 @@ public boolean isAssignableTo(Class<?> clazz) {
3636
public Class<?> rawType() {
3737
return typeModel.rawType().typeIdentifier().javaClass();
3838
}
39+
40+
public PojoTypeModel<? extends T> typeModel() {
41+
return typeModel;
42+
}
3943
}

metamodel/metamodel-processor/src/main/java/org/hibernate/search/metamodel/processor/HibernateSearchMetamodelProcessor.java

+3-12
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,6 @@
44
*/
55
package org.hibernate.search.metamodel.processor;
66

7-
import java.io.IOException;
8-
import java.io.PrintWriter;
9-
import java.io.StringWriter;
107
import java.util.List;
118
import java.util.Set;
129

@@ -17,8 +14,8 @@
1714
import javax.annotation.processing.SupportedOptions;
1815
import javax.lang.model.SourceVersion;
1916
import javax.lang.model.element.TypeElement;
20-
import javax.tools.Diagnostic;
2117

18+
import org.hibernate.search.metamodel.processor.impl.ExceptionUtils;
2219
import org.hibernate.search.metamodel.processor.impl.HibernateSearchMetamodelProcessorContext;
2320
import org.hibernate.search.metamodel.processor.impl.IndexedEntityMetamodelAnnotationProcessor;
2421
import org.hibernate.search.metamodel.processor.impl.MetamodelAnnotationProcessor;
@@ -59,14 +56,8 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
5956
try {
6057
processor.process( roundEnv );
6158
}
62-
catch (Throwable e) {
63-
try ( var sw = new StringWriter(); var pw = new PrintWriter( sw ) ) {
64-
e.printStackTrace( pw );
65-
context.messager().printMessage( Diagnostic.Kind.ERROR, sw.toString() );
66-
}
67-
catch (IOException ex) {
68-
throw new RuntimeException( ex );
69-
}
59+
catch (Exception e) {
60+
ExceptionUtils.logError( context.messager(), e, "Unable to process Hibernate Search metamodel annotations: " );
7061
}
7162
}
7263
return false;

metamodel/metamodel-processor/src/main/java/org/hibernate/search/metamodel/processor/annotation/processing/impl/AbstractProcessorFieldAnnotationProcessor.java

+15-20
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,8 @@
66

77
import javax.lang.model.element.AnnotationMirror;
88
import javax.lang.model.element.Element;
9-
import javax.lang.model.element.ElementKind;
10-
import javax.lang.model.type.TypeKind;
11-
import javax.lang.model.type.TypeMirror;
129
import javax.tools.Diagnostic;
1310

14-
import org.hibernate.search.mapper.pojo.bridge.ValueBridge;
15-
import org.hibernate.search.mapper.pojo.bridge.runtime.ValueBridgeToIndexedValueContext;
1611
import org.hibernate.search.mapper.pojo.extractor.mapping.programmatic.ContainerExtractorPath;
1712
import org.hibernate.search.mapper.pojo.mapping.definition.programmatic.PropertyMappingFieldOptionsStep;
1813
import org.hibernate.search.mapper.pojo.mapping.definition.programmatic.PropertyMappingStep;
@@ -22,22 +17,25 @@ public abstract class AbstractProcessorFieldAnnotationProcessor extends Abstract
2217
@Override
2318
public final void process(PropertyMappingStep mapping, AnnotationMirror annotation,
2419
Element element, ProcessorAnnotationProcessorContext context) {
25-
String cleanedUpRelativeFieldName = getName( annotation );
26-
PropertyMappingFieldOptionsStep<?> fieldContext =
27-
initFieldMappingContext( mapping, annotation, cleanedUpRelativeFieldName );
28-
20+
// we check for bridges and binders first, to make sure none are defined,
21+
// if any -- we want to stop processing as soon as possible so that field is not added to the index!
2922
AnnotationMirror valueBinder = getValueBinder( annotation );
3023
if ( valueBinder != null ) {
31-
// TODO: do we also inject fields into a value binder ... ?
3224
context.messager().printMessage( Diagnostic.Kind.WARNING, "Defined value binder " + valueBinder + " is ignored ",
3325
element );
26+
return;
3427
}
35-
else if ( element.asType().getKind() == TypeKind.DECLARED
36-
&& context.types().asElement( element.asType() ).getKind() == ElementKind.ENUM ) {
37-
// if it's an enum, we won't get to the built-in bridge so we just use this stub one instead:
38-
fieldContext.valueBridge( new ProcessorEnumValueBridge( element.asType() ) );
28+
AnnotationMirror valueBridge = getValueBridge( annotation );
29+
if ( valueBridge != null ) {
30+
context.messager().printMessage( Diagnostic.Kind.WARNING, "Defined value bridge " + valueBridge + " is ignored ",
31+
element );
32+
return;
3933
}
4034

35+
String cleanedUpRelativeFieldName = getName( annotation );
36+
PropertyMappingFieldOptionsStep<?> fieldContext =
37+
initFieldMappingContext( mapping, annotation, cleanedUpRelativeFieldName );
38+
4139
ContainerExtractorPath extractorPath = toContainerExtractorPath( getExtraction( annotation ), context );
4240
fieldContext.extractors( extractorPath );
4341
}
@@ -57,11 +55,8 @@ private AnnotationMirror getValueBinder(AnnotationMirror annotation) {
5755
return getAnnotationProperty( annotation, "valueBinder" );
5856
}
5957

60-
public record ProcessorEnumValueBridge(TypeMirror valueType) implements ValueBridge<Object, String> {
61-
62-
@Override
63-
public String toIndexedValue(Object value, ValueBridgeToIndexedValueContext context) {
64-
return "";
65-
}
58+
private AnnotationMirror getValueBridge(AnnotationMirror annotation) {
59+
return getAnnotationProperty( annotation, "valueBridge" );
6660
}
61+
6762
}

metamodel/metamodel-processor/src/main/java/org/hibernate/search/metamodel/processor/annotation/processing/impl/ProcessorGeoPointBindingProcessor.java

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
*/
55
package org.hibernate.search.metamodel.processor.annotation.processing.impl;
66

7+
import static org.hibernate.search.metamodel.processor.impl.ProcessorElementUtils.collectExtraTypes;
8+
79
import java.util.Optional;
810

911
import javax.lang.model.element.AnnotationMirror;
@@ -25,6 +27,8 @@ class ProcessorGeoPointBindingProcessor extends AbstractProcessorAnnotationProce
2527
public void process(PropertyMappingStep mapping, AnnotationMirror annotation, Element element,
2628
ProcessorAnnotationProcessorContext context) {
2729
mapping.binder( createBinder( annotation ) );
30+
31+
collectExtraTypes( element.asType(), context );
2832
}
2933

3034
@Override

metamodel/metamodel-processor/src/main/java/org/hibernate/search/metamodel/processor/annotation/processing/impl/ProcessorIndexedEmbeddedProcessor.java

+6-23
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,13 @@
44
*/
55
package org.hibernate.search.metamodel.processor.annotation.processing.impl;
66

7-
import static org.hibernate.search.metamodel.processor.impl.IndexedEntityMetamodelAnnotationProcessor.processTypeAndProperties;
7+
import static org.hibernate.search.metamodel.processor.impl.ProcessorElementUtils.collectExtraTypes;
88

99
import java.util.Optional;
1010

1111
import javax.lang.model.element.AnnotationMirror;
1212
import javax.lang.model.element.AnnotationValue;
1313
import javax.lang.model.element.Element;
14-
import javax.lang.model.element.TypeElement;
15-
import javax.lang.model.type.DeclaredType;
16-
import javax.lang.model.type.TypeKind;
1714
import javax.lang.model.type.TypeMirror;
1815
import javax.tools.Diagnostic;
1916

@@ -38,7 +35,7 @@ public void process(PropertyMappingStep mapping, AnnotationMirror annotation, El
3835
String[] includePathsArray = toStringArray( getAnnotationValue( annotation, "includePaths" ) );
3936
String[] excludePathsArray = toStringArray( getAnnotationValue( annotation, "excludePaths" ) );
4037

41-
ContainerExtractorPath extractorPath = toContainerExtractorPath( annotation, context );
38+
ContainerExtractorPath extractorPath = toContainerExtractorPath( getExtraction( annotation ), context );
4239

4340
if ( getAnnotationValue( annotation, "targetType" ) != null ) {
4441
context.messager().printMessage( Diagnostic.Kind.WARNING,
@@ -68,28 +65,14 @@ public void process(PropertyMappingStep mapping, AnnotationMirror annotation, El
6865
collectExtraTypes( element.asType(), context );
6966
}
7067

71-
private void collectExtraTypes(TypeMirror type, ProcessorAnnotationProcessorContext context) {
72-
if ( type == null || type.getKind() == TypeKind.NONE ) {
73-
return;
74-
}
75-
TypeElement element = (TypeElement) context.types().asElement( type );
76-
processTypeAndProperties(
77-
element,
78-
context.programmaticMapping().type( element.getQualifiedName().toString() ),
79-
context
80-
);
81-
collectExtraTypes( element.getSuperclass(), context );
82-
if ( type instanceof DeclaredType declaredType ) {
83-
for ( TypeMirror typeArgument : declaredType.getTypeArguments() ) {
84-
collectExtraTypes( typeArgument, context );
85-
}
86-
}
87-
}
88-
8968
@Override
9069
protected Optional<IndexFieldTypeFinalStep<?>> configureField(PropertyBindingContext bindingContext,
9170
AnnotationMirror annotation, ProcessorAnnotationProcessorContext context, Element element, TypeMirror fieldType) {
9271
context.messager().printMessage( Diagnostic.Kind.ERROR, "IndexedEmbedded are not allowed within binders.", element );
9372
return Optional.empty();
9473
}
74+
75+
private AnnotationMirror getExtraction(AnnotationMirror annotation) {
76+
return getAnnotationProperty( annotation, "extraction" );
77+
}
9578
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.search.metamodel.processor.impl;
6+
7+
import java.io.IOException;
8+
import java.io.PrintWriter;
9+
import java.io.StringWriter;
10+
11+
import javax.annotation.processing.Messager;
12+
import javax.lang.model.element.Element;
13+
import javax.tools.Diagnostic;
14+
15+
public final class ExceptionUtils {
16+
17+
private ExceptionUtils() {
18+
}
19+
20+
public static void logError(Messager messager, Exception exception, String message) {
21+
logError( messager, exception, message, null );
22+
}
23+
24+
public static void logError(Messager messager, Exception exception, String message, Element element) {
25+
try ( var sw = new StringWriter(); var pw = new PrintWriter( sw ) ) {
26+
exception.printStackTrace( pw );
27+
messager.printMessage( Diagnostic.Kind.ERROR, message + sw, element );
28+
}
29+
catch (IOException ex) {
30+
throw new RuntimeException( ex );
31+
}
32+
}
33+
}

metamodel/metamodel-processor/src/main/java/org/hibernate/search/metamodel/processor/impl/IndexedEntityMetamodelAnnotationProcessor.java

+83-21
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import static org.hibernate.search.metamodel.processor.impl.ProcessorElementUtils.flattenedAnnotations;
88
import static org.hibernate.search.metamodel.processor.impl.ProcessorElementUtils.propertyElements;
9+
import static org.hibernate.search.metamodel.processor.impl.ProcessorElementUtils.propertyName;
910

1011
import java.io.IOException;
1112
import java.io.Writer;
@@ -20,7 +21,14 @@
2021

2122
import org.hibernate.search.engine.backend.metamodel.IndexObjectFieldDescriptor;
2223
import org.hibernate.search.engine.backend.metamodel.IndexValueFieldDescriptor;
24+
import org.hibernate.search.engine.environment.bean.BeanHolder;
2325
import org.hibernate.search.engine.environment.bean.BeanReference;
26+
import org.hibernate.search.mapper.pojo.bridge.IdentifierBridge;
27+
import org.hibernate.search.mapper.pojo.bridge.binding.IdentifierBindingContext;
28+
import org.hibernate.search.mapper.pojo.bridge.binding.impl.DefaultIdentifierBindingContext;
29+
import org.hibernate.search.mapper.pojo.bridge.mapping.programmatic.IdentifierBinder;
30+
import org.hibernate.search.mapper.pojo.bridge.runtime.IdentifierBridgeFromDocumentIdentifierContext;
31+
import org.hibernate.search.mapper.pojo.bridge.runtime.IdentifierBridgeToDocumentIdentifierContext;
2432
import org.hibernate.search.mapper.pojo.mapping.definition.programmatic.ProgrammaticMappingConfigurationContext;
2533
import org.hibernate.search.mapper.pojo.mapping.definition.programmatic.PropertyMappingStep;
2634
import org.hibernate.search.mapper.pojo.mapping.definition.programmatic.TypeMappingStep;
@@ -35,8 +43,10 @@
3543
import org.hibernate.search.metamodel.processor.annotation.processing.impl.ProcessorTypeMappingAnnotationProcessor;
3644
import org.hibernate.search.metamodel.processor.mapping.impl.ProcessorIntrospectorContext;
3745
import org.hibernate.search.metamodel.processor.mapping.impl.ProcessorPojoModelsBootstrapIntrospector;
46+
import org.hibernate.search.metamodel.processor.model.impl.HibernateSearchProcessorEnum;
3847
import org.hibernate.search.metamodel.processor.writer.impl.MetamodelClassWriter;
3948
import org.hibernate.search.metamodel.processor.writer.impl.MetamodelNamesFormatter;
49+
import org.hibernate.search.util.common.annotation.impl.SuppressJQAssistant;
4050

4151
public class IndexedEntityMetamodelAnnotationProcessor implements MetamodelAnnotationProcessor {
4252

@@ -72,6 +82,11 @@ public void process(RoundEnvironment roundEnv) {
7282
.discoverJandexIndexesFromAddedTypes( false )
7383
.buildMissingDiscoveredJandexIndexes( false );
7484

85+
configurationContext.bridges()
86+
.subTypesOf( HibernateSearchProcessorEnum.class )
87+
.valueBinder( HibernateSearchProcessorEnum.BINDER )
88+
.identifierBinder( HibernateSearchProcessorEnum.BINDER );
89+
7590
ProgrammaticMappingConfigurationContext programmaticMapping =
7691
configurationContext.programmaticMapping();
7792

@@ -167,36 +182,83 @@ public static void processTypeAndProperties(TypeElement typeElement, TypeMapping
167182
AtomicReference<PropertyMappingStep> ormId = new AtomicReference<>();
168183
propertyElements( ctx.elements(), typeElement )
169184
.forEach( element -> {
170-
PropertyMappingStep step = typeMappingContext.property( element.getSimpleName().toString() );
185+
PropertyMappingStep step = typeMappingContext.property( propertyName( element ) );
171186

172-
flattenedAnnotations( ctx.types(), element )
173-
.forEach( annotationMirror -> {
174-
if ( ProcessorPropertyMappingAnnotationProcessor.documentId( annotationMirror ) ) {
175-
documentId.set( step );
176-
}
177-
else if ( ProcessorPropertyMappingAnnotationProcessor.ormId( annotationMirror ) ) {
178-
ormId.set( step );
179-
}
180-
else {
181-
ProcessorPropertyMappingAnnotationProcessor.processor( annotationMirror )
182-
.ifPresent( p -> p.process(
183-
step,
184-
annotationMirror,
185-
element,
186-
ctx
187-
) );
188-
}
189-
} );
187+
try {
188+
flattenedAnnotations( ctx.types(), element )
189+
.forEach( annotationMirror -> {
190+
if ( ProcessorPropertyMappingAnnotationProcessor.documentId( annotationMirror ) ) {
191+
documentId.set( step );
192+
}
193+
else if ( ProcessorPropertyMappingAnnotationProcessor.ormId( annotationMirror ) ) {
194+
ormId.set( step );
195+
}
196+
else {
197+
ProcessorPropertyMappingAnnotationProcessor.processor( annotationMirror )
198+
.ifPresent( p -> p.process(
199+
step,
200+
annotationMirror,
201+
element,
202+
ctx
203+
) );
204+
}
205+
} );
206+
}
207+
catch (Exception e) {
208+
ExceptionUtils.logError( ctx.messager(), e,
209+
"Unable to process Hibernate Search metamodel annotations: ", element );
210+
}
190211
} );
212+
PropertyMappingStep docIdStep = null;
191213
if ( documentId.get() != null ) {
192-
documentId.get().documentId();
214+
docIdStep = documentId.get();
193215
}
194216
if ( ormId.get() != null ) {
195-
ormId.get().documentId();
217+
docIdStep = ormId.get();
218+
}
219+
if ( docIdStep != null ) {
220+
// Users can have custom identifier binders/bridges, but we don't care much about their impl
221+
// and since for now we are ignoring these impls we still want users to be able to generate
222+
// a partial model; without an id that wouldn't be possible... hence:
223+
docIdStep.documentId().identifierBinder( ProcessorIdentifierBinder.INSTANCE );
196224
}
197225
}
198226

199227
private ProcessorPojoModelsBootstrapIntrospector wrapIntrospector(PojoBootstrapIntrospector introspector) {
200228
return new ProcessorPojoModelsBootstrapIntrospector( introspectorContext, introspector );
201229
}
230+
231+
@SuppressJQAssistant(reason = "Need to cast to an impl type to get access to not-yet exposed method")
232+
private static class ProcessorIdentifierBinder implements IdentifierBinder {
233+
234+
static ProcessorIdentifierBinder INSTANCE = new ProcessorIdentifierBinder();
235+
236+
@SuppressWarnings({ "rawtypes", "unchecked" })
237+
@Override
238+
public void bind(IdentifierBindingContext<?> context) {
239+
if ( context instanceof DefaultIdentifierBindingContext ctx ) {
240+
ctx.applyBridge( Object.class, BeanHolder.of( ProcessorIdentifierBridge.INSTANCE ) );
241+
}
242+
else {
243+
context.bridge( Object.class, ProcessorIdentifierBridge.INSTANCE );
244+
}
245+
}
246+
247+
private static class ProcessorIdentifierBridge implements IdentifierBridge<Object> {
248+
249+
static ProcessorIdentifierBridge INSTANCE = new ProcessorIdentifierBridge();
250+
251+
@Override
252+
public String toDocumentIdentifier(Object propertyValue, IdentifierBridgeToDocumentIdentifierContext context) {
253+
return "";
254+
}
255+
256+
@Override
257+
public Object fromDocumentIdentifier(String documentIdentifier,
258+
IdentifierBridgeFromDocumentIdentifierContext context) {
259+
return null;
260+
}
261+
}
262+
}
263+
202264
}

0 commit comments

Comments
 (0)