/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/CollationUtils.java

https://github.com/spring-projects/spring-data-mongodb · Java · 112 lines · 61 code · 17 blank · 34 comment · 9 complexity · 3ac74968bd1235edf66af1dad67623a2 MD5 · raw file

  1. /*
  2. * Copyright 2019-2022 the original author or authors.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * https://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.springframework.data.mongodb.repository.query;
  17. import java.util.Locale;
  18. import java.util.regex.Matcher;
  19. import java.util.regex.Pattern;
  20. import org.bson.Document;
  21. import org.springframework.data.mongodb.core.query.Collation;
  22. import org.springframework.data.mongodb.util.json.ParameterBindingContext;
  23. import org.springframework.data.mongodb.util.json.ParameterBindingDocumentCodec;
  24. import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
  25. import org.springframework.expression.ExpressionParser;
  26. import org.springframework.expression.spel.standard.SpelExpressionParser;
  27. import org.springframework.lang.Nullable;
  28. import org.springframework.util.NumberUtils;
  29. import org.springframework.util.ObjectUtils;
  30. import org.springframework.util.StringUtils;
  31. /**
  32. * Internal utility class to help avoid duplicate code required in both the reactive and the sync {@link Collation}
  33. * support offered by repositories.
  34. *
  35. * @author Christoph Strobl
  36. * @since 2.2
  37. */
  38. abstract class CollationUtils {
  39. private static final ParameterBindingDocumentCodec CODEC = new ParameterBindingDocumentCodec();
  40. private static final Pattern PARAMETER_BINDING_PATTERN = Pattern.compile("\\?(\\d+)");
  41. private CollationUtils() {
  42. }
  43. /**
  44. * Compute the {@link Collation} by inspecting the {@link ConvertingParameterAccessor#getCollation() parameter
  45. * accessor} or parsing a potentially given {@literal collationExpression}.
  46. *
  47. * @param collationExpression
  48. * @param accessor
  49. * @param parameters
  50. * @param expressionParser
  51. * @param evaluationContextProvider
  52. * @return can be {@literal null} if neither {@link ConvertingParameterAccessor#getCollation()} nor
  53. * {@literal collationExpression} are present.
  54. */
  55. @Nullable
  56. static Collation computeCollation(@Nullable String collationExpression, ConvertingParameterAccessor accessor,
  57. MongoParameters parameters, ExpressionParser expressionParser,
  58. QueryMethodEvaluationContextProvider evaluationContextProvider) {
  59. if (accessor.getCollation() != null) {
  60. return accessor.getCollation();
  61. }
  62. if (!StringUtils.hasText(collationExpression)) {
  63. return null;
  64. }
  65. if (collationExpression.stripLeading().startsWith("{")) {
  66. ParameterBindingContext bindingContext = ParameterBindingContext.forExpressions(accessor::getBindableValue,
  67. expressionParser, dependencies -> evaluationContextProvider.getEvaluationContext(parameters,
  68. accessor.getValues(), dependencies));
  69. return Collation.from(CODEC.decode(collationExpression, bindingContext));
  70. }
  71. Matcher matcher = PARAMETER_BINDING_PATTERN.matcher(collationExpression);
  72. if (!matcher.find()) {
  73. return Collation.parse(collationExpression);
  74. }
  75. String placeholder = matcher.group();
  76. Object placeholderValue = accessor.getBindableValue(computeParameterIndex(placeholder));
  77. if (collationExpression.startsWith("?")) {
  78. if (placeholderValue instanceof String) {
  79. return Collation.parse(placeholderValue.toString());
  80. }
  81. if (placeholderValue instanceof Locale) {
  82. return Collation.of((Locale) placeholderValue);
  83. }
  84. if (placeholderValue instanceof Document) {
  85. return Collation.from((Document) placeholderValue);
  86. }
  87. throw new IllegalArgumentException(String.format("Collation must be a String, Locale or Document but was %s",
  88. ObjectUtils.nullSafeClassName(placeholderValue)));
  89. }
  90. return Collation.parse(collationExpression.replace(placeholder, placeholderValue.toString()));
  91. }
  92. private static int computeParameterIndex(String parameter) {
  93. return NumberUtils.parseNumber(parameter.replace("?", ""), Integer.class);
  94. }
  95. }