ParameterBindingContext.java
/*
* Copyright 2019-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.util.json;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;
import org.jspecify.annotations.Nullable;
import org.springframework.data.mapping.model.ValueExpressionEvaluator;
import org.springframework.data.spel.ExpressionDependencies;
import org.springframework.data.util.Lazy;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParseException;
import org.springframework.expression.ParserContext;
/**
* Reusable context for binding parameters to a placeholder or a SpEL expression within a JSON structure. <br />
* To be used along with {@link ParameterBindingDocumentCodec#decode(String, ParameterBindingContext)}.
*
* @author Christoph Strobl
* @author Mark Paluch
* @since 2.2
*/
public class ParameterBindingContext {
private final ValueProvider valueProvider;
private final ValueExpressionEvaluator expressionEvaluator;
/**
* @param valueProvider
* @param expressionParser
* @param evaluationContext a {@link Supplier} for {@link Lazy} context retrieval.
* @since 2.2.3
*/
public ParameterBindingContext(ValueProvider valueProvider, ExpressionParser expressionParser,
Supplier<EvaluationContext> evaluationContext) {
this(valueProvider, new EvaluationContextExpressionEvaluator(valueProvider, unwrap(expressionParser)) {
@Override
public EvaluationContext getEvaluationContext(String expressionString) {
return evaluationContext.get();
}
});
}
private static ExpressionParser unwrap(ExpressionParser expressionParser) {
return new ExpressionParser() {
@Override
public Expression parseExpression(String expressionString) throws ParseException {
return expressionParser.parseExpression(unwrap(expressionString));
}
@Override
public Expression parseExpression(String expressionString, ParserContext context) throws ParseException {
return expressionParser.parseExpression(unwrap(expressionString), context);
}
};
}
private static String unwrap(String expressionString) {
return expressionString.startsWith("#{") && expressionString.endsWith("}")
? expressionString.substring(2, expressionString.length() - 1).trim()
: expressionString;
}
/**
* @param valueProvider
* @param expressionEvaluator
* @since 4.4.0
*/
public ParameterBindingContext(ValueProvider valueProvider, ValueExpressionEvaluator expressionEvaluator) {
this.valueProvider = valueProvider;
this.expressionEvaluator = expressionEvaluator;
}
/**
* Create a new {@link ParameterBindingContext} that is capable of expression parsing and can provide a
* {@link EvaluationContext} based on {@link ExpressionDependencies}.
*
* @param valueProvider
* @param expressionParser
* @param contextFunction
* @return
* @since 3.1
*/
public static ParameterBindingContext forExpressions(ValueProvider valueProvider, ExpressionParser expressionParser,
Function<ExpressionDependencies, EvaluationContext> contextFunction) {
return new ParameterBindingContext(valueProvider,
new EvaluationContextExpressionEvaluator(valueProvider, expressionParser) {
@Override
public EvaluationContext getEvaluationContext(String expressionString) {
Expression expression = getParsedExpression(expressionString);
ExpressionDependencies dependencies = ExpressionDependencies.discover(expression);
return contextFunction.apply(dependencies);
}
});
}
/**
* Create a new {@link ParameterBindingContext} that is capable of expression parsing.
*
* @param valueProvider
* @param expressionEvaluator
* @return
* @since 4.4.0
*/
public static ParameterBindingContext forExpressions(ValueProvider valueProvider,
ValueExpressionEvaluator expressionEvaluator) {
return new ParameterBindingContext(valueProvider, expressionEvaluator);
}
public @Nullable Object bindableValueForIndex(int index) {
return valueProvider.getBindableValue(index);
}
public @Nullable Object evaluateExpression(String expressionString) {
return expressionEvaluator.evaluate(expressionString);
}
public @Nullable Object evaluateExpression(String expressionString, Map<String, Object> variables) {
if (expressionEvaluator instanceof EvaluationContextExpressionEvaluator expressionEvaluator) {
return expressionEvaluator.evaluateExpression(expressionString, variables);
}
return expressionEvaluator.evaluate(expressionString);
}
public ValueProvider getValueProvider() {
return valueProvider;
}
}