Reputation: 415
I am writing a small app in Quarkus. I am mostly using the quarkus-hibernate-reactive-rest-data-panache extension. One thing is that it doesn't support a partial search for query params. So for example, when searching for the name of a user, it needs the full name instead just the first couple of characters. I'd like to support that.
Now I've written below annotation:
@InterceptorBinding
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PartialSearch {
String value() default "name";
}
And implemented it like this:
@Priority(1)
@Interceptor
@PartialSearch
public class PartialSearchInterceptor {
@Context
UriInfo uriInfo;
@AroundInvoke
public Object intercept(InvocationContext context) throws Exception {
Log.info("Inside of interceptor");
try {
Response originalResponse = (Response) context.proceed();
PartialSearch partialSearch = context.getMethod().getAnnotation(PartialSearch.class);
String searchProperty = partialSearch.value();
String searchTerm = uriInfo.getQueryParameters().getFirst(searchProperty);
if (originalResponse.getEntity() instanceof List<?> originalEntities) {
List<Object> filteredEntities = new ArrayList<>();
for (Object entity : originalEntities) {
if (matchesSearchCriteria(entity, searchProperty, searchTerm)) {
filteredEntities.add(entity);
}
}
return Response.fromResponse(originalResponse)
.entity(filteredEntities)
.build();
}
return originalResponse;
} catch (SearchCriteriaException e) {
Problem problem = new Problem(
"https://example.com/problem/invalid-property",
"INVALID_SEARCH_PROPERTY",
Response.Status.BAD_REQUEST.getStatusCode(),
e.getMessage(),
uriInfo.getAbsolutePath().toString());
return Response.status(Response.Status.BAD_REQUEST).entity(problem).build();
}
}
private boolean matchesSearchCriteria(Object entity, String propertyName, String searchTerm) throws SearchCriteriaException {
try {
Field field = entity.getClass().getDeclaredField(propertyName);
field.setAccessible(true);
Object value = field.get(entity);
Log.debug(value);
Log.debug(searchTerm);
if (value instanceof String) {
return ((String) value).contains(searchTerm);
}
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new SearchCriteriaException("Error accessing property '" + propertyName + "': " + e.getMessage());
}
return false;
}
private static class SearchCriteriaException extends Exception {
public SearchCriteriaException(String message) {
super(message);
}
}
}
And this is the method I am using it one. It's in an interface, because that's how to extension works.
@ResourceProperties(path = "/users")
public interface UserResource extends PanacheEntityResource<User, UUID> {
@PartialSearch("email")
Uni<List<User>> list(Page page, Sort sort);
}
The idea behind the annotation is that it takes the result of the API method, and then does some filtering on the provided property (defaults to 'name').
I added some logging, but when I hit the endpoint I don't see the logs in the Quarkus console and I am getting either an empty response (so the default behaviour of the extension) or a response when I search for the full name.
Does anyone know why the annotation might not be getting executed?
Upvotes: 0
Views: 433
Reputation: 652
You need to add @NonBinding
in front of the attribute value
of your PartialSearch
annotation interface.
In your actual case, the interceptor is only involved when "name" == "default" which is not the case in your UserResource
class which uses @PartialSearch("email")
.
The solution :
@InterceptorBinding
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PartialSearch {
@NonBinding String value() default "name";
}
Now your interceptor will be invoked regardless of the content of the attribute.
If you wonder why, this default mechanism is very useful to have different interceptors based on annotation values without having to deal with "if or switch statements" in your "@AroundInvoke
" method.
See : https://jakarta.ee/specifications/cdi/3.0/apidocs/?jakarta/enterprise/util/Nonbinding.html
Upvotes: 0