|
22 | 22 | import java.util.List;
|
23 | 23 | import java.util.Map;
|
24 | 24 | import java.util.Optional;
|
| 25 | +import java.util.concurrent.TimeUnit; |
| 26 | +import java.util.stream.Collectors; |
25 | 27 |
|
| 28 | +import com.mongodb.Tag; |
| 29 | +import com.mongodb.TagSet; |
26 | 30 | import org.springframework.core.annotation.AnnotatedElementUtils;
|
27 | 31 | import org.springframework.data.geo.GeoPage;
|
28 | 32 | import org.springframework.data.geo.GeoResult;
|
|
36 | 40 | import org.springframework.data.mongodb.repository.Hint;
|
37 | 41 | import org.springframework.data.mongodb.repository.Meta;
|
38 | 42 | import org.springframework.data.mongodb.repository.Query;
|
| 43 | +import org.springframework.data.mongodb.repository.ReadPreference; |
39 | 44 | import org.springframework.data.mongodb.repository.Tailable;
|
40 | 45 | import org.springframework.data.mongodb.repository.Update;
|
41 | 46 | import org.springframework.data.projection.ProjectionFactory;
|
|
57 | 62 | * @author Oliver Gierke
|
58 | 63 | * @author Christoph Strobl
|
59 | 64 | * @author Mark Paluch
|
| 65 | + * @author Jorge Rodríguez |
60 | 66 | */
|
61 | 67 | public class MongoQueryMethod extends QueryMethod {
|
62 | 68 |
|
@@ -314,6 +320,58 @@ public String getAnnotatedSort() {
|
314 | 320 | "Expected to find @Query annotation but did not; Make sure to check hasAnnotatedSort() before."));
|
315 | 321 | }
|
316 | 322 |
|
| 323 | + |
| 324 | + /** |
| 325 | + * Check if the query method is decorated with an non empty {@link Query#collation()}. |
| 326 | + * |
| 327 | + * @return true if method annotated with {@link Query} or {@link Aggregation} having a non-empty collation attribute. |
| 328 | + * @since 4.2 |
| 329 | + */ |
| 330 | + public boolean hasAnnotatedReadPreference() { |
| 331 | + return doFindReadPreferenceAnnotation().map(ReadPreference::value).filter(StringUtils::hasText).isPresent(); |
| 332 | + } |
| 333 | + |
| 334 | + /** |
| 335 | + * Get the {@link com.mongodb.ReadPreference} extracted from the {@link ReadPreference} annotation. |
| 336 | + * |
| 337 | + * @return the {@link ReadPreference()}. |
| 338 | + * @throws IllegalStateException if method not annotated with {@link Query}. Make sure to check |
| 339 | + * {@link #hasAnnotatedQuery()} first. |
| 340 | + * @since 4.2 |
| 341 | + */ |
| 342 | + public com.mongodb.ReadPreference getAnnotatedReadPreference() { |
| 343 | + |
| 344 | + return doFindReadPreferenceAnnotation().map(annotationReadPreference -> { |
| 345 | + |
| 346 | + com.mongodb.ReadPreference readPreference = com.mongodb.ReadPreference.valueOf(annotationReadPreference.value()); |
| 347 | + |
| 348 | + if (annotationReadPreference.tags().length > 0) { |
| 349 | + List<Tag> tags = Arrays.stream(annotationReadPreference.tags()) |
| 350 | + .map(tag -> new Tag(tag.name(), tag.value())) |
| 351 | + .collect(Collectors.toList()); |
| 352 | + readPreference = readPreference.withTagSet(new TagSet(tags)); |
| 353 | + } |
| 354 | + |
| 355 | + if (annotationReadPreference.maxStalenessSeconds() > 0) { |
| 356 | + readPreference = readPreference.withMaxStalenessMS(annotationReadPreference.maxStalenessSeconds(), TimeUnit.SECONDS); |
| 357 | + } |
| 358 | + |
| 359 | + return readPreference; |
| 360 | + }).orElseThrow(() -> new IllegalStateException( |
| 361 | + "Expected to find @ReadPreference annotation but did not; Make sure to check hasAnnotatedReadPreference() before.")); |
| 362 | + } |
| 363 | + |
| 364 | + /** |
| 365 | + * Get {@link com.mongodb.ReadPreference} from query. First check if the method is annotated. If not, check if the class is annotated. |
| 366 | + * So if the method and the class are annotated with @ReadPreference, the method annotation takes precedence. |
| 367 | + * @return the {@link com.mongodb.ReadPreference} |
| 368 | + * @since 4.2 |
| 369 | + */ |
| 370 | + private Optional<ReadPreference> doFindReadPreferenceAnnotation() { |
| 371 | + return doFindAnnotation(ReadPreference.class).or(() -> doFindAnnotationInClass(ReadPreference.class)); |
| 372 | + } |
| 373 | + |
| 374 | + |
317 | 375 | /**
|
318 | 376 | * Check if the query method is decorated with an non empty {@link Query#collation()} or or
|
319 | 377 | * {@link Aggregation#collation()}.
|
@@ -400,11 +458,21 @@ Optional<Update> lookupUpdateAnnotation() {
|
400 | 458 |
|
401 | 459 | @SuppressWarnings("unchecked")
|
402 | 460 | private <A extends Annotation> Optional<A> doFindAnnotation(Class<A> annotationType) {
|
| 461 | + |
403 | 462 |
|
404 | 463 | return (Optional<A>) this.annotationCache.computeIfAbsent(annotationType,
|
405 | 464 | it -> Optional.ofNullable(AnnotatedElementUtils.findMergedAnnotation(method, it)));
|
406 | 465 | }
|
407 | 466 |
|
| 467 | + @SuppressWarnings("unchecked") |
| 468 | + private <A extends Annotation> Optional<A> doFindAnnotationInClass(Class<A> annotationType) { |
| 469 | + |
| 470 | + Optional<Annotation> mergedAnnotation = Optional.ofNullable(AnnotatedElementUtils.findMergedAnnotation(method.getDeclaringClass(), annotationType)); |
| 471 | + annotationCache.put(annotationType, mergedAnnotation); |
| 472 | + |
| 473 | + return (Optional<A>) mergedAnnotation; |
| 474 | + } |
| 475 | + |
408 | 476 | @Override
|
409 | 477 | public boolean isModifyingQuery() {
|
410 | 478 | return isModifying.get();
|
|
0 commit comments