diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQuery.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQuery.java index f887c58aa..1a63a997a 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQuery.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQuery.java @@ -29,9 +29,6 @@ import org.springframework.core.convert.converter.Converter; import org.springframework.data.jdbc.core.convert.JdbcColumnTypes; import org.springframework.data.jdbc.core.convert.JdbcConverter; import org.springframework.data.jdbc.core.mapping.JdbcValue; -import org.springframework.data.jdbc.repository.query.parameter.ParameterBindingParser; -import org.springframework.data.jdbc.repository.query.parameter.ParameterBindings.Metadata; -import org.springframework.data.jdbc.repository.query.parameter.ParameterBindings.ParameterBinding; import org.springframework.data.jdbc.support.JdbcUtil; import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.relational.repository.query.RelationalParameterAccessor; @@ -41,16 +38,12 @@ import org.springframework.data.repository.query.Parameter; import org.springframework.data.repository.query.Parameters; import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider; import org.springframework.data.repository.query.ResultProcessor; +import org.springframework.data.repository.query.SpelEvaluator; import org.springframework.data.repository.query.SpelQueryContext; -import org.springframework.expression.EvaluationContext; -import org.springframework.expression.Expression; -import org.springframework.expression.ExpressionParser; -import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; -import org.springframework.jdbc.core.namedparam.SqlParameterSource; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -130,16 +123,6 @@ public class StringBasedJdbcQuery extends AbstractJdbcQuery { @Override public Object execute(Object[] objects) { -// List parameterBindings = new ArrayList<>(); -// SpelQueryContext queryContext = SpelQueryContext.of((counter, expression) -> { -// -// String parameterName = String.format("__synthetic_%d__", counter); -// parameterBindings.add(new ParameterBinding(parameterName, expression)); -// return parameterName; -// }, String::concat); -// -// SpelQueryContext.SpelExtractor parsed = queryContext.parse(query); - RelationalParameterAccessor accessor = new RelationalParametersParameterAccessor(getQueryMethod(), objects); ResultProcessor processor = getQueryMethod().getResultProcessor().withDynamicProjection(accessor); ResultProcessingConverter converter = new ResultProcessingConverter(processor, this.converter.getMappingContext(), @@ -153,51 +136,28 @@ public class StringBasedJdbcQuery extends AbstractJdbcQuery { determineResultSetExtractor(rowMapper), // rowMapper); - Metadata queryMeta = new Metadata(); + MapSqlParameterSource parameterMap = this.bindParameters(accessor); String query = determineQuery(); if (ObjectUtils.isEmpty(query)) { throw new IllegalStateException(String.format("No query specified on %s", queryMethod.getName())); } - List bindings = new ArrayList<>(); - - query = ParameterBindingParser.INSTANCE.parseParameterBindingsOfQueryIntoBindingsAndReturnCleanedQuery(query, - bindings, queryMeta); - SqlParameterSource parameterMap = this.bindParameters(accessor); - extendParametersFromSpELEvaluation((MapSqlParameterSource) parameterMap, bindings, objects); - return queryExecution.execute(query, parameterMap); + return queryExecution.execute(processSpelExpressions(objects, parameterMap, query), parameterMap); } - /** - * Extend the {@link MapSqlParameterSource} by evaluating each detected SpEL parameter in the original query. This is - * basically a simple variant of Spring Data JPA's SPeL implementation. - * - * @param parameterMap - * @param bindings - * @param values - */ - void extendParametersFromSpELEvaluation(MapSqlParameterSource parameterMap, List bindings, - Object[] values) { - - if (bindings.size() == 0) { - return; - } + private String processSpelExpressions(Object[] objects, MapSqlParameterSource parameterMap, String query) { - ExpressionParser parser = new SpelExpressionParser(); + SpelQueryContext.EvaluatingSpelQueryContext queryContext = SpelQueryContext + .of((counter, expression) -> String.format("__$synthetic$__%d", counter + 1), String::concat) + .withEvaluationContextProvider(evaluationContextProvider); - bindings.forEach(binding -> { - if (!binding.isExpression()) { - return; - } + SpelEvaluator spelEvaluator = queryContext.parse(query, queryMethod.getParameters()); - Expression expression = parser.parseExpression(binding.getExpression()); - EvaluationContext context = evaluationContextProvider.getEvaluationContext(this.queryMethod.getParameters(), - values); + spelEvaluator.evaluate(objects).forEach(parameterMap::addValue); - parameterMap.addValue(binding.getName(), expression.getValue(context, Object.class)); - }); + return spelEvaluator.getQueryString(); } @Override diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/parameter/ParameterBindingParser.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/parameter/ParameterBindingParser.java deleted file mode 100755 index a96eaa520..000000000 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/parameter/ParameterBindingParser.java +++ /dev/null @@ -1,295 +0,0 @@ -package org.springframework.data.jdbc.repository.query.parameter; - -import static java.util.regex.Pattern.CASE_INSENSITIVE; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.BiFunction; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.springframework.data.jdbc.repository.query.parameter.ParameterBindings.InParameterBinding; -import org.springframework.data.jdbc.repository.query.parameter.ParameterBindings.LikeParameterBinding; -import org.springframework.data.jdbc.repository.query.parameter.ParameterBindings.Metadata; -import org.springframework.data.jdbc.repository.query.parameter.ParameterBindings.ParameterBinding; -import org.springframework.data.repository.query.SpelQueryContext; -import org.springframework.data.repository.query.SpelQueryContext.SpelExtractor; -import org.springframework.data.repository.query.parser.Part.Type; -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; - -/** - * A parser that extracts the parameter bindings from a given query string. - * - * TODO This class comes from Spring Data JPA org.springframework.data.jpa.repository.query.StringQuery and should be probably moved to Spring Data Commons. - * - * @author Thomas Darimont - * @author Christopher Klein - */ -public enum ParameterBindingParser { - - INSTANCE; - - private static final String EXPRESSION_PARAMETER_PREFIX = "__$synthetic$__"; - public static final String POSITIONAL_OR_INDEXED_PARAMETER = "\\?(\\d*+(?![#\\w]))"; - // .....................................................................^ not followed by a hash or a letter. - // .................................................................^ zero or more digits. - // .............................................................^ start with a question mark. - private static final Pattern PARAMETER_BINDING_BY_INDEX = Pattern.compile(POSITIONAL_OR_INDEXED_PARAMETER); - private static final Pattern PARAMETER_BINDING_PATTERN; - private static final String MESSAGE = "Already found parameter binding with same index / parameter name but differing binding type! " - + "Already have: %s, found %s! If you bind a parameter multiple times make sure they use the same binding."; - private static final int INDEXED_PARAMETER_GROUP = 4; - private static final int NAMED_PARAMETER_GROUP = 6; - private static final int COMPARISION_TYPE_GROUP = 1; - - public static final String IDENTIFIER = "[._$[\\P{Z}&&\\P{Cc}&&\\P{Cf}&&\\P{Punct}]]+"; - public static final String COLON_NO_DOUBLE_COLON = "(? keywords = new ArrayList<>(); - - for (ParameterBindingType type : ParameterBindingType.values()) { - if (type.getKeyword() != null) { - keywords.add(type.getKeyword()); - } - } - - StringBuilder builder = new StringBuilder(); - builder.append("("); - builder.append(StringUtils.collectionToDelimitedString(keywords, "|")); // keywords - builder.append(")?"); - builder.append("(?: )?"); // some whitespace - builder.append("\\(?"); // optional braces around parameters - builder.append("("); - builder.append("%?(" + POSITIONAL_OR_INDEXED_PARAMETER + ")%?"); // position parameter and parameter index - builder.append("|"); // or - - // named parameter and the parameter name - builder.append("%?(" + COLON_NO_DOUBLE_COLON + IDENTIFIER_GROUP + ")%?"); - - builder.append(")"); - builder.append("\\)?"); // optional braces around parameters - - PARAMETER_BINDING_PATTERN = Pattern.compile(builder.toString(), CASE_INSENSITIVE); - } - - /** - * Parses {@link ParameterBinding} instances from the given query and adds them to the registered bindings. Returns - * the cleaned up query. - */ - public String parseParameterBindingsOfQueryIntoBindingsAndReturnCleanedQuery(String query, - List bindings, Metadata queryMeta) { - - int greatestParameterIndex = tryFindGreatestParameterIndexIn(query); - boolean parametersShouldBeAccessedByIndex = greatestParameterIndex != -1; - - /* - * Prefer indexed access over named parameters if only SpEL Expression parameters are present. - */ - if (!parametersShouldBeAccessedByIndex && query.contains("?#{")) { - parametersShouldBeAccessedByIndex = true; - greatestParameterIndex = 0; - } - - SpelExtractor spelExtractor = createSpelExtractor(query, parametersShouldBeAccessedByIndex, - greatestParameterIndex); - - String resultingQuery = spelExtractor.getQueryString(); - Matcher matcher = PARAMETER_BINDING_PATTERN.matcher(resultingQuery); - - int expressionParameterIndex = parametersShouldBeAccessedByIndex ? greatestParameterIndex : 0; - - boolean usesJpaStyleParameters = false; - while (matcher.find()) { - - if (spelExtractor.isQuoted(matcher.start())) { - continue; - } - - String parameterIndexString = matcher.group(INDEXED_PARAMETER_GROUP); - String parameterName = parameterIndexString != null ? null : matcher.group(NAMED_PARAMETER_GROUP); - Integer parameterIndex = getParameterIndex(parameterIndexString); - - String typeSource = matcher.group(COMPARISION_TYPE_GROUP); - String expression = spelExtractor.getParameter(parameterName == null ? parameterIndexString : parameterName); - String replacement = null; - - Assert.isTrue(parameterIndexString != null || parameterName != null, () -> String.format("We need either a name or an index! Offending query string: %s", query)); - - expressionParameterIndex++; - if ("".equals(parameterIndexString)) { - - queryMeta.setUsesJdbcStyleParameters(true); - parameterIndex = expressionParameterIndex; - } else { - usesJpaStyleParameters = true; - } - - if (usesJpaStyleParameters && queryMeta.isUsesJdbcStyleParameters()) { - throw new IllegalArgumentException("Mixing of ? parameters and other forms like ?1 is not supported!"); - } - - switch (ParameterBindingType.of(typeSource)) { - - case LIKE: - - Type likeType = LikeParameterBinding.getLikeTypeFrom(matcher.group(2)); - replacement = matcher.group(3); - - if (parameterIndex != null) { - checkAndRegister(new LikeParameterBinding(parameterIndex, likeType, expression), bindings); - } else { - checkAndRegister(new LikeParameterBinding(parameterName, likeType, expression), bindings); - - replacement = expression != null ? ":" + parameterName : matcher.group(5); - } - - break; - - case IN: - - if (parameterIndex != null) { - checkAndRegister(new InParameterBinding(parameterIndex, expression), bindings); - } else { - checkAndRegister(new InParameterBinding(parameterName, expression), bindings); - } - - break; - - case AS_IS: // fall-through we don't need a special parameter binding for the given parameter. - default: - - bindings.add(parameterIndex != null ? new ParameterBinding(null, parameterIndex, expression) - : new ParameterBinding(parameterName, null, expression)); - } - - if (replacement != null) { - resultingQuery = replaceFirst(resultingQuery, matcher.group(2), replacement); - } - - } - - return resultingQuery; - } - - private static SpelExtractor createSpelExtractor(String queryWithSpel, boolean parametersShouldBeAccessedByIndex, - int greatestParameterIndex) { - - /* - * If parameters need to be bound by index, we bind the synthetic expression parameters starting from position of the greatest discovered index parameter in order to - * not mix-up with the actual parameter indices. - */ - int expressionParameterIndex = parametersShouldBeAccessedByIndex ? greatestParameterIndex : 0; - - BiFunction indexToParameterName = parametersShouldBeAccessedByIndex - ? (index, expression) -> String.valueOf(index + expressionParameterIndex + 1) - : (index, expression) -> EXPRESSION_PARAMETER_PREFIX + (index + 1); - - String fixedPrefix = parametersShouldBeAccessedByIndex ? "?" : ":"; - - BiFunction parameterNameToReplacement = (prefix, name) -> fixedPrefix + name; - - return SpelQueryContext.of(indexToParameterName, parameterNameToReplacement).parse(queryWithSpel); - } - - private static String replaceFirst(String text, String substring, String replacement) { - - int index = text.indexOf(substring); - if (index < 0) { - return text; - } - - return text.substring(0, index) + replacement + text.substring(index + substring.length()); - } - - @Nullable - private static Integer getParameterIndex(@Nullable String parameterIndexString) { - - if (parameterIndexString == null || parameterIndexString.isEmpty()) { - return null; - } - return Integer.valueOf(parameterIndexString); - } - - private static int tryFindGreatestParameterIndexIn(String query) { - - Matcher parameterIndexMatcher = PARAMETER_BINDING_BY_INDEX.matcher(query); - - int greatestParameterIndex = -1; - while (parameterIndexMatcher.find()) { - - String parameterIndexString = parameterIndexMatcher.group(1); - Integer parameterIndex = getParameterIndex(parameterIndexString); - if (parameterIndex != null) { - greatestParameterIndex = Math.max(greatestParameterIndex, parameterIndex); - } - } - - return greatestParameterIndex; - } - - private static void checkAndRegister(ParameterBinding binding, List bindings) { - - bindings.stream() // - .filter(it -> it.hasName(binding.getName()) || it.hasPosition(binding.getPosition())) // - .forEach(it -> Assert.isTrue(it.equals(binding), String.format(MESSAGE, it, binding))); - - if (!bindings.contains(binding)) { - bindings.add(binding); - } - } - - /** - * An enum for the different types of bindings. - * - * @author Thomas Darimont - * @author Oliver Gierke - */ - private enum ParameterBindingType { - - // Trailing whitespace is intentional to reflect that the keywords must be used with at least one whitespace - // character, while = does not. - LIKE("like "), IN("in "), AS_IS(null); - - private final @Nullable String keyword; - - ParameterBindingType(@Nullable String keyword) { - this.keyword = keyword; - } - - /** - * Returns the keyword that will trigger the binding type or {@literal null} if the type is not triggered by a - * keyword. - * - * @return the keyword - */ - @Nullable - public String getKeyword() { - return keyword; - } - - /** - * Return the appropriate {@link ParameterBindingType} for the given {@link String}. Returns {@literal #AS_IS} in - * case no other {@link ParameterBindingType} could be found. - */ - static ParameterBindingType of(String typeSource) { - - if (!StringUtils.hasText(typeSource)) { - return AS_IS; - } - - for (ParameterBindingType type : values()) { - if (type.name().equalsIgnoreCase(typeSource.trim())) { - return type; - } - } - - throw new IllegalArgumentException(String.format("Unsupported parameter binding type %s!", typeSource)); - } - } -} diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/parameter/ParameterBindings.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/parameter/ParameterBindings.java deleted file mode 100755 index 07e58db5b..000000000 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/parameter/ParameterBindings.java +++ /dev/null @@ -1,442 +0,0 @@ -package org.springframework.data.jdbc.repository.query.parameter; - -import static org.springframework.util.ObjectUtils.nullSafeEquals; -import static org.springframework.util.ObjectUtils.nullSafeHashCode; - -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; - -import org.springframework.data.repository.query.parser.Part.Type; -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; -import org.springframework.util.ObjectUtils; -import org.springframework.util.StringUtils; - -/** - * TODO This class comes from Spring Data JPA org.springframework.data.jpa.repository.query.StringQuery and should be probably moved to Spring Data Commons. - * @author Christopher Klein - */ -public class ParameterBindings { - - /** - * A generic parameter binding with name or position information. - * - * @author Thomas Darimont - */ - public static class ParameterBinding { - - private final @Nullable String name; - private final @Nullable String expression; - private final @Nullable Integer position; - - /** - * Creates a new {@link ParameterBinding} for the parameter with the given - * position. - * - * @param position must not be {@literal null}. - */ - ParameterBinding(Integer position) { - this(null, position, null); - } - - /** - * Creates a new {@link ParameterBinding} for the parameter with the given name, - * position and expression information. Either {@literal name} or - * {@literal position} must be not {@literal null}. - * - * @param name of the parameter may be {@literal null}. - * @param position of the parameter may be {@literal null}. - * @param expression the expression to apply to any value for this parameter. - */ - ParameterBinding(@Nullable String name, @Nullable Integer position, @Nullable String expression) { - - if (name == null) { - Assert.notNull(position, "Position must not be null!"); - } - - if (position == null) { - Assert.notNull(name, "Name must not be null!"); - } - - this.name = name; - this.position = position; - this.expression = expression; - } - - /** - * Returns whether the binding has the given name. Will always be - * {@literal false} in case the {@link ParameterBinding} has been set up from a - * position. - */ - boolean hasName(@Nullable String name) { - return this.position == null && this.name != null && this.name.equals(name); - } - - /** - * Returns whether the binding has the given position. Will always be - * {@literal false} in case the {@link ParameterBinding} has been set up from a - * name. - */ - boolean hasPosition(@Nullable Integer position) { - return position != null && this.name == null && position.equals(this.position); - } - - /** - * @return the name - */ - @Nullable - public String getName() { - return name; - } - - /** - * @return the name - * @throws IllegalStateException if the name is not available. - * @since 2.0 - */ - String getRequiredName() throws IllegalStateException { - - String name = getName(); - - if (name != null) { - return name; - } - - throw new IllegalStateException(String.format("Required name for %s not available!", this)); - } - - /** - * @return the position - */ - @Nullable - Integer getPosition() { - return position; - } - - /** - * @return the position - * @throws IllegalStateException if the position is not available. - * @since 2.0 - */ - int getRequiredPosition() throws IllegalStateException { - - Integer position = getPosition(); - - if (position != null) { - return position; - } - - throw new IllegalStateException(String.format("Required position for %s not available!", this)); - } - - /** - * @return {@literal true} if this parameter binding is a synthetic SpEL - * expression. - */ - public boolean isExpression() { - return this.expression != null; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - - int result = 17; - - result += nullSafeHashCode(this.name); - result += nullSafeHashCode(this.position); - result += nullSafeHashCode(this.expression); - - return result; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(Object obj) { - - if (!(obj instanceof ParameterBinding)) { - return false; - } - - ParameterBinding that = (ParameterBinding) obj; - - return nullSafeEquals(this.name, that.name) && nullSafeEquals(this.position, that.position) - && nullSafeEquals(this.expression, that.expression); - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - return String.format("ParameterBinding [name: %s, position: %d, expression: %s]", getName(), getPosition(), - getExpression()); - } - - /** - * @param valueToBind value to prepare - */ - @Nullable - public Object prepare(@Nullable Object valueToBind) { - return valueToBind; - } - - @Nullable - public String getExpression() { - return expression; - } - } - - /** - * Represents a {@link ParameterBinding} in a JPQL query augmented with - * instructions of how to apply a parameter as an {@code IN} parameter. - * - * @author Thomas Darimont - */ - public static class InParameterBinding extends ParameterBinding { - - /** - * Creates a new {@link InParameterBinding} for the parameter with the given - * name. - */ - InParameterBinding(String name, @Nullable String expression) { - super(name, null, expression); - } - - /** - * Creates a new {@link InParameterBinding} for the parameter with the given - * position. - */ - InParameterBinding(int position, @Nullable String expression) { - super(null, position, expression); - } - - /* - * (non-Javadoc) - * - * @see - * org.springframework.data.jpa.repository.query.StringQuery.ParameterBinding# - * prepare(java.lang.Object) - */ - @Override - public Object prepare(@Nullable Object value) { - - if (!ObjectUtils.isArray(value)) { - return value; - } - - int length = Array.getLength(value); - Collection result = new ArrayList<>(length); - - for (int i = 0; i < length; i++) { - result.add(Array.get(value, i)); - } - - return result; - } - } - - /** - * Represents a parameter binding in a JPQL query augmented with instructions of - * how to apply a parameter as LIKE parameter. This allows expressions like - * {@code …like %?1} in the JPQL query, which is not allowed by plain JPA. - * - * @author Oliver Gierke - * @author Thomas Darimont - */ - public static class LikeParameterBinding extends ParameterBinding { - - private static final List SUPPORTED_TYPES = Arrays.asList(Type.CONTAINING, Type.STARTING_WITH, - Type.ENDING_WITH, Type.LIKE); - - private final Type type; - - /** - * Creates a new {@link LikeParameterBinding} for the parameter with the given - * name and {@link Type}. - * - * @param name must not be {@literal null} or empty. - * @param type must not be {@literal null}. - */ - LikeParameterBinding(String name, Type type) { - this(name, type, null); - } - - /** - * Creates a new {@link LikeParameterBinding} for the parameter with the given - * name and {@link Type} and parameter binding input. - * - * @param name must not be {@literal null} or empty. - * @param type must not be {@literal null}. - * @param expression may be {@literal null}. - */ - LikeParameterBinding(String name, Type type, @Nullable String expression) { - - super(name, null, expression); - - Assert.hasText(name, "Name must not be null or empty!"); - Assert.notNull(type, "Type must not be null!"); - - Assert.isTrue(SUPPORTED_TYPES.contains(type), String.format("Type must be one of %s!", - StringUtils.collectionToCommaDelimitedString(SUPPORTED_TYPES))); - - this.type = type; - } - - /** - * Creates a new {@link LikeParameterBinding} for the parameter with the given - * position and {@link Type}. - * - * @param position position of the parameter in the query. - * @param type must not be {@literal null}. - */ - LikeParameterBinding(int position, Type type) { - this(position, type, null); - } - - /** - * Creates a new {@link LikeParameterBinding} for the parameter with the given - * position and {@link Type}. - * - * @param position position of the parameter in the query. - * @param type must not be {@literal null}. - * @param expression may be {@literal null}. - */ - LikeParameterBinding(int position, Type type, @Nullable String expression) { - - super(null, position, expression); - - Assert.isTrue(position > 0, "Position must be greater than zero!"); - Assert.notNull(type, "Type must not be null!"); - - Assert.isTrue(SUPPORTED_TYPES.contains(type), String.format("Type must be one of %s!", - StringUtils.collectionToCommaDelimitedString(SUPPORTED_TYPES))); - - this.type = type; - } - - /** - * Returns the {@link Type} of the binding. - * - * @return the type - */ - public Type getType() { - return type; - } - - /** - * Prepares the given raw keyword according to the like type. - */ - @Nullable - @Override - public Object prepare(@Nullable Object value) { - - if (value == null) { - return null; - } - - switch (type) { - case STARTING_WITH: - return String.format("%s%%", value.toString()); - case ENDING_WITH: - return String.format("%%%s", value.toString()); - case CONTAINING: - return String.format("%%%s%%", value.toString()); - case LIKE: - default: - return value; - } - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(Object obj) { - - if (!(obj instanceof LikeParameterBinding)) { - return false; - } - - LikeParameterBinding that = (LikeParameterBinding) obj; - - return super.equals(obj) && this.type.equals(that.type); - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - - int result = super.hashCode(); - - result += nullSafeHashCode(this.type); - - return result; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - return String.format("LikeBinding [name: %s, position: %d, type: %s]", getName(), getPosition(), type); - } - - /** - * Extracts the like {@link Type} from the given JPA like expression. - * - * @param expression must not be {@literal null} or empty. - */ - static Type getLikeTypeFrom(String expression) { - - Assert.hasText(expression, "Expression must not be null or empty!"); - - if (expression.matches("%.*%")) { - return Type.CONTAINING; - } - - if (expression.startsWith("%")) { - return Type.ENDING_WITH; - } - - if (expression.endsWith("%")) { - return Type.STARTING_WITH; - } - - return Type.LIKE; - } - } - - public static class Metadata { - private boolean usesJdbcStyleParameters = false; - - public boolean isUsesJdbcStyleParameters() { - return usesJdbcStyleParameters; - } - - public void setUsesJdbcStyleParameters(boolean usesJdbcStyleParameters) { - this.usesJdbcStyleParameters = usesJdbcStyleParameters; - } - } -}