Skip to content

Commit e5a206e

Browse files
committed
HSEARCH-5021 Include annotation attributes in the params map for value binders
1 parent ce6e483 commit e5a206e

File tree

5 files changed

+115
-1
lines changed

5 files changed

+115
-1
lines changed

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -920,4 +920,15 @@ SearchException invalidFieldEncodingForVectorFieldMapping(IndexFieldTypeOptionsS
920920
+ "i.e. extraction must be set to DEFAULT and a nonempty array of container value extractor names provided, "
921921
+ "e.g. @ContainerExtraction(extract = ContainerExtract.DEFAULT, value = { ... }).")
922922
SearchException vectorFieldMustUseExplicitExtractorPath();
923+
924+
@Message(id = ID_OFFSET + 147, value = "Unable to obtain annotation attributes from '%1$s': %2$s")
925+
SearchException unexpectedExceptionWhenObtainingAnnotationAttributes(@FormatWith(ClassFormatter.class) Class<?> annotation,
926+
String message, @Cause Exception e);
927+
928+
@LogMessage(level = Logger.Level.WARN)
929+
@Message(id = ID_OFFSET + 148,
930+
value = "The attribute value '%3$s' of '%1$s annotation got overridden with a @org.hibernate.search.mapper.pojo.common.annotation.Param(name = \"%2$s\", value=%4$s). "
931+
+ "If access to the annotation attribute is required, consider using a different parameter name for this @Param.")
932+
void annotationAttributeOverriddenWithParameter(@FormatWith(ClassFormatter.class) Class<?> annotation, String parameterName,
933+
Object overriddenValue, Object parameterValue);
923934
}

mapper/pojo-base/src/main/java/org/hibernate/search/mapper/pojo/mapping/definition/annotation/processing/MappingAnnotationProcessorContext.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77
package org.hibernate.search.mapper.pojo.mapping.definition.annotation.processing;
88

9+
import java.lang.annotation.Annotation;
910
import java.util.Map;
1011
import java.util.Objects;
1112
import java.util.Optional;
@@ -104,6 +105,28 @@ default Map<String, Object> toMap(Param[] params) {
104105
return MappingAnnotationProcessorUtils.toMap( params );
105106
}
106107

108+
/**
109+
* @param annotation The original annotation.
110+
* @return A {@link Map map} containing annotation attributes.
111+
* Use {@link #annotationAttributeMapKey(Class, String)} to build a map key for a corresponding annotation attribute.
112+
* @param <A> The type of the annotation.
113+
* @see #annotationAttributeMapKey(Class, String)
114+
*/
115+
default <A extends Annotation> Map<String, Object> toMap(A annotation) {
116+
return MappingAnnotationProcessorUtils.toMap( annotation );
117+
}
118+
119+
/**
120+
* @param annotation Tha annotation for which the map key should be created.
121+
* @param attribute The name of an annotation attribute.
122+
* @return The map key to retrieve annotation attributes from the parameters map.
123+
* @param <A> The type of the annotation.
124+
* @see #toMap(Annotation)
125+
*/
126+
default <A extends Annotation> String annotationAttributeMapKey(Class<A> annotation, String attribute) {
127+
return MappingAnnotationProcessorUtils.annotationAttributeMapKey( annotation, attribute );
128+
}
129+
107130
/**
108131
* @param value A value extracted from an annotation attribute.
109132
* @param defaultValue A default value for that annotation attribute.

mapper/pojo-base/src/main/java/org/hibernate/search/mapper/pojo/mapping/definition/annotation/processing/impl/AbstractFieldAnnotationProcessor.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,15 @@ public final void process(PropertyMappingStep mappingContext, A annotation,
4646
valueBinder,
4747
context
4848
);
49+
Map<String, Object> params = context.toMap( annotation );
50+
for ( Map.Entry<String, Object> entry : context.toMap( valueBinder.params() ).entrySet() ) {
51+
Object overriddenValue = params.put( entry.getKey(), entry.getValue() );
52+
if ( overriddenValue != null ) {
53+
log.annotationAttributeOverriddenWithParameter( annotation.annotationType(), entry.getKey(), overriddenValue,
54+
entry.getValue() );
55+
}
56+
}
4957

50-
Map<String, Object> params = context.toMap( valueBinder.params() );
5158
fieldContext.valueBinder( binder, params );
5259

5360
ContainerExtractorPath extractorPath = context.toContainerExtractorPath( getExtraction( annotation ) );

mapper/pojo-base/src/main/java/org/hibernate/search/mapper/pojo/mapping/definition/annotation/processing/impl/MappingAnnotationProcessorUtils.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,13 @@
66
*/
77
package org.hibernate.search.mapper.pojo.mapping.definition.annotation.processing.impl;
88

9+
import java.lang.annotation.Annotation;
910
import java.lang.invoke.MethodHandles;
11+
import java.lang.reflect.InvocationTargetException;
12+
import java.lang.reflect.Method;
1013
import java.util.Arrays;
1114
import java.util.Collections;
15+
import java.util.HashMap;
1216
import java.util.HashSet;
1317
import java.util.LinkedHashMap;
1418
import java.util.Map;
@@ -112,4 +116,28 @@ public static Set<String> cleanUpPaths(String[] pathsArray) {
112116
}
113117
return paths;
114118
}
119+
120+
public static <A extends Annotation> Map<String, Object> toMap(A annotation) {
121+
if ( annotation == null ) {
122+
return Collections.emptyMap();
123+
}
124+
Map<String, Object> attributes = new HashMap<>();
125+
Class<? extends Annotation> annotationType = annotation.annotationType();
126+
for ( Method method : annotationType.getDeclaredMethods() ) {
127+
try {
128+
attributes.put( annotationAttributeMapKey( annotationType, method.getName() ), method.invoke( annotation ) );
129+
}
130+
catch (InvocationTargetException | IllegalAccessException e) {
131+
throw log.unexpectedExceptionWhenObtainingAnnotationAttributes( annotationType, e.getMessage(), e );
132+
}
133+
}
134+
135+
return attributes;
136+
}
137+
138+
public static <A extends Annotation> String annotationAttributeMapKey(Class<A> annotation, String attribute) {
139+
Contracts.assertNotNull( annotation, "annotation" );
140+
Contracts.assertNotNullNorEmpty( attribute, "attribute" );
141+
return annotation.getName() + "#" + attribute;
142+
}
115143
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Hibernate Search, full-text search for your domain model
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
5+
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
6+
*/
7+
package org.hibernate.search.mapper.pojo.mapping.definition.annotation.processing.impl;
8+
9+
import static org.assertj.core.api.Assertions.assertThat;
10+
import static org.hibernate.search.mapper.pojo.mapping.definition.annotation.processing.impl.MappingAnnotationProcessorUtils.annotationAttributeMapKey;
11+
12+
import java.lang.annotation.ElementType;
13+
import java.lang.annotation.Retention;
14+
import java.lang.annotation.RetentionPolicy;
15+
import java.lang.annotation.Target;
16+
17+
import org.junit.jupiter.api.Test;
18+
19+
class MappingAnnotationProcessorUtilsTest {
20+
21+
@Test
22+
void toMap() {
23+
MyAnnotation annotation = Annotated.class.getAnnotation( MyAnnotation.class );
24+
25+
assertThat( MappingAnnotationProcessorUtils.toMap( annotation ) )
26+
.containsEntry( annotationAttributeMapKey( MyAnnotation.class, "string" ), "" )
27+
.containsEntry( annotationAttributeMapKey( MyAnnotation.class, "integer" ), 100 )
28+
.containsEntry( annotationAttributeMapKey( MyAnnotation.class, "type" ), Annotated.class );
29+
}
30+
31+
@Target(ElementType.TYPE)
32+
@Retention(RetentionPolicy.RUNTIME)
33+
@interface MyAnnotation {
34+
String string() default "";
35+
36+
int integer();
37+
38+
Class<?> type() default Object.class;
39+
40+
}
41+
42+
@MyAnnotation(integer = 100, type = Annotated.class)
43+
private static class Annotated {
44+
}
45+
}

0 commit comments

Comments
 (0)