diff --git a/pom.xml b/pom.xml
index f10c1266..ecabc3e6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.springframework.data
spring-data-ldap
- 3.4.0-SNAPSHOT
+ 3.4.0-GH-453-SNAPSHOT
Spring Data LDAP
Spring Data integration for LDAP
@@ -21,6 +21,7 @@
3.2.6
3.4.0-SNAPSHOT
spring.data.ldap
+ 7.0.1
@@ -109,6 +110,20 @@
test
+
+ org.springframework.ldap
+ spring-ldap-test
+ ${spring-ldap}
+ test
+
+
+
+ com.unboundid
+ unboundid-ldapsdk
+ ${unboundid-ldapsdk}
+ test
+
+
diff --git a/src/main/java/org/springframework/data/ldap/repository/query/AbstractLdapRepositoryQuery.java b/src/main/java/org/springframework/data/ldap/repository/query/AbstractLdapRepositoryQuery.java
index 4c4d1f93..d35e6fee 100644
--- a/src/main/java/org/springframework/data/ldap/repository/query/AbstractLdapRepositoryQuery.java
+++ b/src/main/java/org/springframework/data/ldap/repository/query/AbstractLdapRepositoryQuery.java
@@ -26,6 +26,7 @@
import org.springframework.data.repository.query.QueryMethod;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.repository.query.ResultProcessor;
+import org.springframework.data.repository.query.ValueExpressionDelegate;
import org.springframework.ldap.core.LdapOperations;
import org.springframework.ldap.query.LdapQuery;
import org.springframework.util.Assert;
diff --git a/src/main/java/org/springframework/data/ldap/repository/query/AnnotatedLdapRepositoryQuery.java b/src/main/java/org/springframework/data/ldap/repository/query/AnnotatedLdapRepositoryQuery.java
index 49d721b7..11b764a8 100644
--- a/src/main/java/org/springframework/data/ldap/repository/query/AnnotatedLdapRepositoryQuery.java
+++ b/src/main/java/org/springframework/data/ldap/repository/query/AnnotatedLdapRepositoryQuery.java
@@ -17,11 +17,14 @@
import static org.springframework.ldap.query.LdapQueryBuilder.*;
+import org.springframework.data.expression.ValueEvaluationContext;
+import org.springframework.data.expression.ValueEvaluationContextProvider;
import org.springframework.data.ldap.repository.Query;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.EntityInstantiators;
+import org.springframework.data.repository.query.ValueExpressionDelegate;
import org.springframework.ldap.core.LdapOperations;
import org.springframework.ldap.query.LdapQuery;
import org.springframework.util.Assert;
@@ -35,6 +38,8 @@
public class AnnotatedLdapRepositoryQuery extends AbstractLdapRepositoryQuery {
private final Query queryAnnotation;
+ private final ValueExpressionDelegate valueExpressionDelegate;
+ private final StringBasedQuery stringBasedQuery;
/**
* Construct a new instance.
@@ -44,26 +49,58 @@ public class AnnotatedLdapRepositoryQuery extends AbstractLdapRepositoryQuery {
* @param ldapOperations the LdapOperations instance to use.
* @param mappingContext must not be {@literal null}.
* @param instantiators must not be {@literal null}.
+ * @deprecated use the constructor with {@link ValueExpressionDelegate}
*/
+ @Deprecated(since = "3.4")
public AnnotatedLdapRepositoryQuery(LdapQueryMethod queryMethod, Class> entityType, LdapOperations ldapOperations,
MappingContext extends PersistentEntity, ?>, ? extends PersistentProperty>> mappingContext,
EntityInstantiators instantiators) {
+ this(queryMethod, entityType, ldapOperations, mappingContext, instantiators, ValueExpressionDelegate.create());
+ }
+
+ /**
+ * Construct a new instance.
+ *
+ * @param queryMethod the QueryMethod.
+ * @param entityType the managed class.
+ * @param ldapOperations the LdapOperations instance to use.
+ * @param mappingContext must not be {@literal null}.
+ * @param instantiators must not be {@literal null}.
+ * @param valueExpressionDelegate must not be {@literal null}
+ * @since 3.4
+ */
+ public AnnotatedLdapRepositoryQuery(LdapQueryMethod queryMethod, Class> entityType, LdapOperations ldapOperations,
+ MappingContext extends PersistentEntity, ?>, ? extends PersistentProperty>> mappingContext,
+ EntityInstantiators instantiators, ValueExpressionDelegate valueExpressionDelegate) {
+
super(queryMethod, entityType, ldapOperations, mappingContext, instantiators);
Assert.notNull(queryMethod.getQueryAnnotation(), "Annotation must be present");
Assert.hasLength(queryMethod.getQueryAnnotation().value(), "Query filter must be specified");
queryAnnotation = queryMethod.getRequiredQueryAnnotation();
+ String queryValue = queryAnnotation.value();
+ this.valueExpressionDelegate = valueExpressionDelegate;
+ stringBasedQuery = new StringBasedQuery(queryValue, queryMethod.getParameters(), valueExpressionDelegate);
}
@Override
protected LdapQuery createQuery(LdapParameterAccessor parameters) {
+ ValueEvaluationContextProvider valueContextProvider = valueExpressionDelegate
+ .createValueContextProvider(getQueryMethod().getParameters());
+
+ ValueEvaluationContext evaluationContext = valueContextProvider
+ .getEvaluationContext(parameters.getBindableParameterValues(), stringBasedQuery.getExpressionDependencies());
+
+ String boundQuery = stringBasedQuery.bindQuery(parameters,
+ new ContextualValueExpressionEvaluator(valueExpressionDelegate, evaluationContext));
+
return query().base(queryAnnotation.base()) //
.searchScope(queryAnnotation.searchScope()) //
.countLimit(queryAnnotation.countLimit()) //
.timeLimit(queryAnnotation.timeLimit()) //
- .filter(queryAnnotation.value(), parameters.getBindableParameterValues());
+ .filter(boundQuery);
}
}
diff --git a/src/main/java/org/springframework/data/ldap/repository/query/BindingContext.java b/src/main/java/org/springframework/data/ldap/repository/query/BindingContext.java
new file mode 100644
index 00000000..50299e60
--- /dev/null
+++ b/src/main/java/org/springframework/data/ldap/repository/query/BindingContext.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2020-2024 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.ldap.repository.query;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.springframework.data.mapping.model.ValueExpressionEvaluator;
+import org.springframework.data.repository.query.Parameter;
+import org.springframework.data.repository.query.ParameterAccessor;
+import org.springframework.lang.Nullable;
+import org.springframework.util.Assert;
+
+/**
+ * Value object capturing the binding context to provide {@link #getBindingValues() binding values} for queries.
+ *
+ * @author Mark Paluch
+ * @since 3.4
+ */
+class BindingContext {
+
+ private final LdapParameters parameters;
+
+ private final ParameterAccessor parameterAccessor;
+
+ private final List bindings;
+
+ private final ValueExpressionEvaluator evaluator;
+
+ /**
+ * Create new {@link BindingContext}.
+ */
+ BindingContext(LdapParameters parameters, ParameterAccessor parameterAccessor,
+ List bindings, ValueExpressionEvaluator evaluator) {
+
+ this.parameters = parameters;
+ this.parameterAccessor = parameterAccessor;
+ this.bindings = bindings;
+ this.evaluator = evaluator;
+ }
+
+ /**
+ * @return {@literal true} when list of bindings is not empty.
+ */
+ private boolean hasBindings() {
+ return !bindings.isEmpty();
+ }
+
+ /**
+ * Bind values provided by {@link LdapParameterAccessor} to placeholders in {@link BindingContext} while
+ * considering potential conversions and parameter types.
+ *
+ * @return {@literal null} if given {@code raw} value is empty.
+ */
+ public List