@@ -20,7 +20,7 @@ import javax.naming.Name;
|
|||||||
|
|
||||||
import org.springframework.data.repository.core.support.AbstractEntityInformation;
|
import org.springframework.data.repository.core.support.AbstractEntityInformation;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.ldap.odm.core.impl.DefaultObjectDirectoryMapper;
|
import org.springframework.ldap.odm.core.ObjectDirectoryMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ODM-based {@link org.springframework.data.repository.core.EntityInformation} for LDAP entities.
|
* ODM-based {@link org.springframework.data.repository.core.EntityInformation} for LDAP entities.
|
||||||
@@ -32,16 +32,17 @@ import org.springframework.ldap.odm.core.impl.DefaultObjectDirectoryMapper;
|
|||||||
*/
|
*/
|
||||||
class LdapEntityInformation<T> extends AbstractEntityInformation<T, Name> {
|
class LdapEntityInformation<T> extends AbstractEntityInformation<T, Name> {
|
||||||
|
|
||||||
private final DefaultObjectDirectoryMapper MAPPER = new DefaultObjectDirectoryMapper();
|
private final ObjectDirectoryMapper odm;
|
||||||
|
|
||||||
public LdapEntityInformation(Class<T> domainClass) {
|
public LdapEntityInformation(Class<T> domainClass, ObjectDirectoryMapper odm) {
|
||||||
super(domainClass);
|
super(domainClass);
|
||||||
|
this.odm = odm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Name getId(T entity) {
|
public Name getId(T entity) {
|
||||||
return MAPPER.getId(entity);
|
return odm.getId(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -16,11 +16,13 @@
|
|||||||
package org.springframework.data.ldap.repository.support;
|
package org.springframework.data.ldap.repository.support;
|
||||||
|
|
||||||
import static org.springframework.data.querydsl.QuerydslUtils.*;
|
import static org.springframework.data.querydsl.QuerydslUtils.*;
|
||||||
|
import static org.springframework.data.repository.core.support.RepositoryComposition.*;
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||||
import org.springframework.data.ldap.core.mapping.LdapMappingContext;
|
import org.springframework.data.ldap.core.mapping.LdapMappingContext;
|
||||||
import org.springframework.data.ldap.repository.query.AnnotatedLdapRepositoryQuery;
|
import org.springframework.data.ldap.repository.query.AnnotatedLdapRepositoryQuery;
|
||||||
import org.springframework.data.ldap.repository.query.LdapQueryMethod;
|
import org.springframework.data.ldap.repository.query.LdapQueryMethod;
|
||||||
@@ -94,9 +96,9 @@ public class LdapRepositoryFactory extends RepositoryFactorySupport {
|
|||||||
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getEntityInformation(java.lang.Class)
|
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getEntityInformation(java.lang.Class)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
public <T, ID> EntityInformation<T, ID> getEntityInformation(Class<T> domainClass) {
|
public <T, ID> EntityInformation<T, ID> getEntityInformation(Class<T> domainClass) {
|
||||||
return new LdapEntityInformation(domainClass);
|
return new LdapEntityInformation(domainClass, ldapOperations.getObjectDirectoryMapper());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -105,11 +107,46 @@ public class LdapRepositoryFactory extends RepositoryFactorySupport {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
|
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
|
||||||
|
return SimpleLdapRepository.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getRepositoryFragments(org.springframework.data.repository.core.RepositoryMetadata)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected RepositoryFragments getRepositoryFragments(RepositoryMetadata metadata) {
|
||||||
|
return getRepositoryFragments(metadata, this.ldapOperations);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates {@link RepositoryFragments} based on {@link RepositoryMetadata} to add LDAP-specific extensions. Typically,
|
||||||
|
* adds a {@link QuerydslLdapPredicateExecutor} if the repository interface uses Querydsl.
|
||||||
|
* <p>
|
||||||
|
* Can be overridden by subclasses to customize {@link RepositoryFragments}.
|
||||||
|
*
|
||||||
|
* @param metadata repository metadata.
|
||||||
|
* @param operations the LDAP operations manager.
|
||||||
|
* @return
|
||||||
|
* @since 2.6
|
||||||
|
*/
|
||||||
|
protected RepositoryFragments getRepositoryFragments(RepositoryMetadata metadata, LdapOperations operations) {
|
||||||
|
|
||||||
boolean isQueryDslRepository = QUERY_DSL_PRESENT
|
boolean isQueryDslRepository = QUERY_DSL_PRESENT
|
||||||
&& QuerydslPredicateExecutor.class.isAssignableFrom(metadata.getRepositoryInterface());
|
&& QuerydslPredicateExecutor.class.isAssignableFrom(metadata.getRepositoryInterface());
|
||||||
|
|
||||||
return isQueryDslRepository ? QuerydslLdapRepository.class : SimpleLdapRepository.class;
|
if (isQueryDslRepository) {
|
||||||
|
|
||||||
|
if (metadata.isReactiveRepository()) {
|
||||||
|
throw new InvalidDataAccessApiUsageException(
|
||||||
|
"Cannot combine Querydsl and reactive repository support in a single interface");
|
||||||
|
}
|
||||||
|
|
||||||
|
return RepositoryFragments.just(new QuerydslLdapPredicateExecutor<>(
|
||||||
|
getEntityInformation(metadata.getDomainType()), getProjectionFactory(), operations, mappingContext));
|
||||||
|
}
|
||||||
|
|
||||||
|
return RepositoryFragments.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -0,0 +1,460 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016-2021 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.support;
|
||||||
|
|
||||||
|
import java.beans.FeatureDescriptor;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||||
|
import org.springframework.data.domain.Example;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.domain.Sort;
|
||||||
|
import org.springframework.data.ldap.repository.query.DtoInstantiatingConverter;
|
||||||
|
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.projection.ProjectionFactory;
|
||||||
|
import org.springframework.data.projection.ProjectionInformation;
|
||||||
|
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
|
||||||
|
import org.springframework.data.repository.core.EntityInformation;
|
||||||
|
import org.springframework.data.repository.query.FluentQuery;
|
||||||
|
import org.springframework.data.support.PageableExecutionUtils;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
import org.springframework.ldap.core.LdapOperations;
|
||||||
|
import org.springframework.ldap.query.LdapQueryBuilder;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import com.querydsl.core.types.OrderSpecifier;
|
||||||
|
import com.querydsl.core.types.Predicate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LDAP-specific {@link QuerydslPredicateExecutor}.
|
||||||
|
*
|
||||||
|
* @author Mark Paluch
|
||||||
|
* @since 2.6
|
||||||
|
*/
|
||||||
|
public class QuerydslLdapPredicateExecutor<T> implements QuerydslPredicateExecutor<T> {
|
||||||
|
|
||||||
|
private final EntityInformation<T, ?> entityInformation;
|
||||||
|
private final ProjectionFactory projectionFactory;
|
||||||
|
private final LdapOperations ldapOperations;
|
||||||
|
private final MappingContext<? extends PersistentEntity<?, ?>, ? extends PersistentProperty<?>> mappingContext;
|
||||||
|
private final EntityInstantiators entityInstantiators = new EntityInstantiators();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link QuerydslLdapPredicateExecutor}.
|
||||||
|
*
|
||||||
|
* @param entityInformation must not be {@literal null}.
|
||||||
|
* @param projectionFactory must not be {@literal null}.
|
||||||
|
* @param ldapOperations must not be {@literal null}.
|
||||||
|
* @param mappingContext must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public QuerydslLdapPredicateExecutor(Class<T> entityType, ProjectionFactory projectionFactory,
|
||||||
|
LdapOperations ldapOperations,
|
||||||
|
MappingContext<? extends PersistentEntity<?, ?>, ? extends PersistentProperty<?>> mappingContext) {
|
||||||
|
|
||||||
|
Assert.notNull(entityType, "Entity type must not be null!");
|
||||||
|
Assert.notNull(projectionFactory, "ProjectionFactory must not be null!");
|
||||||
|
Assert.notNull(ldapOperations, "LdapOperations must not be null!");
|
||||||
|
Assert.notNull(mappingContext, "MappingContext must not be null!");
|
||||||
|
|
||||||
|
this.entityInformation = new LdapEntityInformation<>(entityType, ldapOperations.getObjectDirectoryMapper());
|
||||||
|
this.ldapOperations = ldapOperations;
|
||||||
|
this.projectionFactory = projectionFactory;
|
||||||
|
this.mappingContext = mappingContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link QuerydslLdapPredicateExecutor}.
|
||||||
|
*
|
||||||
|
* @param entityInformation must not be {@literal null}.
|
||||||
|
* @param projectionFactory must not be {@literal null}.
|
||||||
|
* @param ldapOperations must not be {@literal null}.
|
||||||
|
* @param mappingContext must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public QuerydslLdapPredicateExecutor(EntityInformation<T, ?> entityInformation, ProjectionFactory projectionFactory,
|
||||||
|
LdapOperations ldapOperations,
|
||||||
|
MappingContext<? extends PersistentEntity<?, ?>, ? extends PersistentProperty<?>> mappingContext) {
|
||||||
|
|
||||||
|
Assert.notNull(entityInformation, "EntityInformation must not be null!");
|
||||||
|
Assert.notNull(projectionFactory, "ProjectionFactory must not be null!");
|
||||||
|
Assert.notNull(ldapOperations, "LdapOperations must not be null!");
|
||||||
|
Assert.notNull(mappingContext, "MappingContext must not be null!");
|
||||||
|
|
||||||
|
this.entityInformation = entityInformation;
|
||||||
|
this.ldapOperations = ldapOperations;
|
||||||
|
this.projectionFactory = projectionFactory;
|
||||||
|
this.mappingContext = mappingContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findOne(com.querydsl.core.types.Predicate)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Optional<T> findOne(Predicate predicate) {
|
||||||
|
return findBy(predicate, Function.identity()).one();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findAll(com.querydsl.core.types.Predicate)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<T> findAll(Predicate predicate) {
|
||||||
|
return queryFor(predicate).list();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#count(com.querydsl.core.types.Predicate)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public long count(Predicate predicate) {
|
||||||
|
return findBy(predicate, FluentQuery.FetchableFluentQuery::count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#exists(com.querydsl.core.types.Predicate)
|
||||||
|
*/
|
||||||
|
public boolean exists(Predicate predicate) {
|
||||||
|
return findBy(predicate, FluentQuery.FetchableFluentQuery::exists);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findAll(com.querydsl.core.types.Predicate, org.springframework.data.domain.Sort)
|
||||||
|
*/
|
||||||
|
public Iterable<T> findAll(Predicate predicate, Sort sort) {
|
||||||
|
|
||||||
|
Assert.notNull(sort, "Pageable must not be null!");
|
||||||
|
|
||||||
|
if (sort.isUnsorted()) {
|
||||||
|
return findAll(predicate);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new UnsupportedOperationException("Sorting is not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findAll(com.querydsl.core.types.OrderSpecifier[])
|
||||||
|
*/
|
||||||
|
public Iterable<T> findAll(OrderSpecifier<?>... orders) {
|
||||||
|
|
||||||
|
if (orders.length == 0) {
|
||||||
|
return findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new UnsupportedOperationException("Sorting is not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findAll(com.querydsl.core.types.Predicate, com.querydsl.core.types.OrderSpecifier[])
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Iterable<T> findAll(Predicate predicate, OrderSpecifier<?>... orders) {
|
||||||
|
|
||||||
|
if (orders.length == 0) {
|
||||||
|
return findAll(predicate);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new UnsupportedOperationException("Sorting is not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findAll(com.querydsl.core.types.Predicate, org.springframework.data.domain.Pageable)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Page<T> findAll(Predicate predicate, Pageable pageable) {
|
||||||
|
|
||||||
|
Assert.notNull(pageable, "Pageable must not be null!");
|
||||||
|
|
||||||
|
if (pageable.isUnpaged()) {
|
||||||
|
return PageableExecutionUtils.getPage(findAll(predicate), pageable, () -> count(predicate));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pageable.getSort().isUnsorted() && pageable.getPageNumber() == 0) {
|
||||||
|
|
||||||
|
return PageableExecutionUtils.getPage(queryFor(predicate, q -> q.countLimit(pageable.getPageSize())).list(),
|
||||||
|
pageable, () -> count(predicate));
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new UnsupportedOperationException("Pagination and Sorting is not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.querydsl.QuerydslPredicateExecutor#findBy(com.querydsl.core.types.Predicate, java.util.function.Function)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <S extends T, R> R findBy(Predicate predicate,
|
||||||
|
Function<FluentQuery.FetchableFluentQuery<S>, R> queryFunction) {
|
||||||
|
|
||||||
|
Assert.notNull(queryFunction, "Query function must not be null!");
|
||||||
|
|
||||||
|
return queryFunction.apply(new FluentQuerydsl<>(predicate, (Class<S>) entityInformation.getJavaType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private QuerydslLdapQuery<T> queryFor(Predicate predicate) {
|
||||||
|
return queryFor(predicate, it -> {
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private QuerydslLdapQuery<T> queryFor(Predicate predicate, Consumer<LdapQueryBuilder> queryBuilderConsumer) {
|
||||||
|
|
||||||
|
Assert.notNull(predicate, "Predicate must not be null!");
|
||||||
|
|
||||||
|
return new QuerydslLdapQuery<>(ldapOperations, entityInformation.getJavaType(), queryBuilderConsumer)
|
||||||
|
.where(predicate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link FetchableFluentQuery} using {@link Example}.
|
||||||
|
*
|
||||||
|
* @author Mark Paluch
|
||||||
|
* @since 2.6
|
||||||
|
*/
|
||||||
|
class FluentQuerydsl<R> implements FluentQuery.FetchableFluentQuery<R> {
|
||||||
|
|
||||||
|
private final Predicate predicate;
|
||||||
|
private final Sort sort;
|
||||||
|
private final Class<R> resultType;
|
||||||
|
private final List<String> projection;
|
||||||
|
|
||||||
|
FluentQuerydsl(Predicate predicate, Class<R> resultType) {
|
||||||
|
this(predicate, Sort.unsorted(), resultType, Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
FluentQuerydsl(Predicate predicate, Sort sort, Class<R> resultType, List<String> projection) {
|
||||||
|
this.predicate = predicate;
|
||||||
|
this.sort = sort;
|
||||||
|
this.resultType = resultType;
|
||||||
|
this.projection = projection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#sortBy(org.springframework.data.domain.Sort)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public FetchableFluentQuery<R> sortBy(Sort sort) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#as(java.lang.Class)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <R1> FetchableFluentQuery<R1> as(Class<R1> resultType) {
|
||||||
|
|
||||||
|
Assert.notNull(projection, "Projection target type must not be null!");
|
||||||
|
|
||||||
|
return new FluentQuerydsl<>(predicate, sort, resultType, projection);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#project(java.util.Collection)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public FetchableFluentQuery<R> project(Collection<String> properties) {
|
||||||
|
|
||||||
|
Assert.notNull(properties, "Projection properties must not be null!");
|
||||||
|
|
||||||
|
return new FluentQuerydsl<>(predicate, sort, resultType, new ArrayList<>(properties));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#oneValue()
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public R oneValue() {
|
||||||
|
|
||||||
|
List<T> results = findTop(2);
|
||||||
|
|
||||||
|
if (results.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (results.size() > 1) {
|
||||||
|
throw new IncorrectResultSizeDataAccessException(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
T one = results.get(0);
|
||||||
|
return getConversionFunction().apply(one);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#firstValue()
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public R firstValue() {
|
||||||
|
|
||||||
|
List<T> results = findTop(2);
|
||||||
|
|
||||||
|
if (results.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
T one = results.get(0);
|
||||||
|
return getConversionFunction().apply(one);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#all()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<R> all() {
|
||||||
|
return stream().collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#page(org.springframework.data.domain.Pageable)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Page<R> page(Pageable pageable) {
|
||||||
|
|
||||||
|
Assert.notNull(pageable, "Pageable must not be null!");
|
||||||
|
|
||||||
|
if (pageable.isUnpaged()) {
|
||||||
|
return PageableExecutionUtils.getPage(all(), pageable, this::count);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pageable.getSort().isUnsorted() && pageable.getPageNumber() == 0) {
|
||||||
|
|
||||||
|
Function<Object, R> conversionFunction = getConversionFunction();
|
||||||
|
|
||||||
|
return PageableExecutionUtils.getPage(
|
||||||
|
findTop(pageable.getPageSize()).stream().map(conversionFunction).collect(Collectors.toList()), pageable,
|
||||||
|
this::count);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new UnsupportedOperationException("Pagination and Sorting is not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#stream()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Stream<R> stream() {
|
||||||
|
|
||||||
|
Function<Object, R> conversionFunction = getConversionFunction();
|
||||||
|
|
||||||
|
return search(null, QuerydslLdapQuery::list).stream().map(conversionFunction);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#count()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public long count() {
|
||||||
|
return search(null, q -> q.search(it -> true)).size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#exists()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean exists() {
|
||||||
|
return !search(1, q -> q.search(it -> true)).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<T> findTop(int limit) {
|
||||||
|
return search(limit, QuerydslLdapQuery::list);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <S> S search(@Nullable Integer limit, Function<QuerydslLdapQuery<T>, S> searchFunction) {
|
||||||
|
|
||||||
|
QuerydslLdapQuery<T> q = queryFor(predicate, query -> {
|
||||||
|
|
||||||
|
List<String> projection = getProjection();
|
||||||
|
|
||||||
|
if (!projection.isEmpty()) {
|
||||||
|
query.attributes(projection.toArray(new String[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (limit != null) {
|
||||||
|
query.countLimit(limit);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return searchFunction.apply(q);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private <P> Function<Object, P> getConversionFunction(Class<?> inputType, Class<P> targetType) {
|
||||||
|
|
||||||
|
if (targetType.isAssignableFrom(inputType)) {
|
||||||
|
return (Function<Object, P>) Function.identity();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetType.isInterface()) {
|
||||||
|
return o -> projectionFactory.createProjection(targetType, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
DtoInstantiatingConverter converter = new DtoInstantiatingConverter(targetType, mappingContext,
|
||||||
|
entityInstantiators);
|
||||||
|
|
||||||
|
return o -> (P) converter.convert(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Function<Object, R> getConversionFunction() {
|
||||||
|
return getConversionFunction(entityInformation.getJavaType(), resultType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> getProjection() {
|
||||||
|
|
||||||
|
if (projection.isEmpty()) {
|
||||||
|
|
||||||
|
if (resultType.isAssignableFrom(entityInformation.getJavaType())) {
|
||||||
|
return projection;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resultType.isInterface()) {
|
||||||
|
ProjectionInformation projectionInformation = projectionFactory.getProjectionInformation(resultType);
|
||||||
|
|
||||||
|
if (projectionInformation.isClosed()) {
|
||||||
|
return projectionInformation.getInputProperties().stream().map(FeatureDescriptor::getName)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return projection;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -15,42 +15,22 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.ldap.repository.support;
|
package org.springframework.data.ldap.repository.support;
|
||||||
|
|
||||||
import java.beans.FeatureDescriptor;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import org.springframework.beans.BeansException;
|
|
||||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
|
||||||
import org.springframework.beans.factory.BeanFactory;
|
|
||||||
import org.springframework.beans.factory.BeanFactoryAware;
|
|
||||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
|
||||||
import org.springframework.data.domain.Example;
|
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.data.ldap.core.mapping.LdapMappingContext;
|
import org.springframework.data.ldap.core.mapping.LdapMappingContext;
|
||||||
import org.springframework.data.ldap.repository.query.DtoInstantiatingConverter;
|
|
||||||
import org.springframework.data.mapping.PersistentEntity;
|
import org.springframework.data.mapping.PersistentEntity;
|
||||||
import org.springframework.data.mapping.PersistentProperty;
|
import org.springframework.data.mapping.PersistentProperty;
|
||||||
import org.springframework.data.mapping.context.MappingContext;
|
import org.springframework.data.mapping.context.MappingContext;
|
||||||
import org.springframework.data.mapping.model.EntityInstantiators;
|
|
||||||
import org.springframework.data.projection.ProjectionInformation;
|
|
||||||
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
|
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
|
||||||
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
|
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
|
||||||
import org.springframework.data.repository.query.FluentQuery;
|
import org.springframework.data.repository.query.FluentQuery;
|
||||||
import org.springframework.data.support.PageableExecutionUtils;
|
|
||||||
import org.springframework.lang.Nullable;
|
|
||||||
import org.springframework.ldap.core.LdapOperations;
|
import org.springframework.ldap.core.LdapOperations;
|
||||||
import org.springframework.ldap.odm.core.ObjectDirectoryMapper;
|
import org.springframework.ldap.odm.core.ObjectDirectoryMapper;
|
||||||
import org.springframework.ldap.query.LdapQueryBuilder;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
import com.querydsl.core.types.OrderSpecifier;
|
import com.querydsl.core.types.OrderSpecifier;
|
||||||
import com.querydsl.core.types.Predicate;
|
import com.querydsl.core.types.Predicate;
|
||||||
@@ -61,15 +41,12 @@ import com.querydsl.core.types.Predicate;
|
|||||||
* @author Mattias Hellborg Arthursson
|
* @author Mattias Hellborg Arthursson
|
||||||
* @author Eddu Melendez
|
* @author Eddu Melendez
|
||||||
* @author Mark Paluch
|
* @author Mark Paluch
|
||||||
|
* @deprecated since 2.6, use {@link QuerydslLdapPredicateExecutor} instead.
|
||||||
*/
|
*/
|
||||||
public class QuerydslLdapRepository<T> extends SimpleLdapRepository<T>
|
@Deprecated
|
||||||
implements QuerydslPredicateExecutor<T>, BeanFactoryAware, BeanClassLoaderAware {
|
public class QuerydslLdapRepository<T> extends SimpleLdapRepository<T> implements QuerydslPredicateExecutor<T> {
|
||||||
|
|
||||||
private final LdapOperations ldapOperations;
|
private final QuerydslLdapPredicateExecutor<T> executor;
|
||||||
private final MappingContext<? extends PersistentEntity<?, ?>, ? extends PersistentProperty<?>> context;
|
|
||||||
private final Class<T> entityType;
|
|
||||||
private final SpelAwareProxyProjectionFactory projectionFactory = new SpelAwareProxyProjectionFactory();
|
|
||||||
private final EntityInstantiators entityInstantiators = new EntityInstantiators();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link QuerydslLdapRepository}.
|
* Creates a new {@link QuerydslLdapRepository}.
|
||||||
@@ -82,9 +59,8 @@ public class QuerydslLdapRepository<T> extends SimpleLdapRepository<T>
|
|||||||
|
|
||||||
super(ldapOperations, odm, entityType);
|
super(ldapOperations, odm, entityType);
|
||||||
|
|
||||||
this.ldapOperations = ldapOperations;
|
this.executor = new QuerydslLdapPredicateExecutor<>(entityType, new SpelAwareProxyProjectionFactory(),
|
||||||
this.entityType = entityType;
|
ldapOperations, new LdapMappingContext());
|
||||||
this.context = new LdapMappingContext();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -102,19 +78,8 @@ public class QuerydslLdapRepository<T> extends SimpleLdapRepository<T>
|
|||||||
|
|
||||||
super(ldapOperations, context, odm, entityType);
|
super(ldapOperations, context, odm, entityType);
|
||||||
|
|
||||||
this.ldapOperations = ldapOperations;
|
this.executor = new QuerydslLdapPredicateExecutor<>(entityType, new SpelAwareProxyProjectionFactory(),
|
||||||
this.context = context;
|
ldapOperations, new LdapMappingContext());
|
||||||
this.entityType = entityType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
|
||||||
projectionFactory.setBeanClassLoader(classLoader);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
|
||||||
projectionFactory.setBeanFactory(beanFactory);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -123,7 +88,7 @@ public class QuerydslLdapRepository<T> extends SimpleLdapRepository<T>
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Optional<T> findOne(Predicate predicate) {
|
public Optional<T> findOne(Predicate predicate) {
|
||||||
return findBy(predicate, Function.identity()).one();
|
return executor.findOne(predicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
@@ -131,7 +96,7 @@ public class QuerydslLdapRepository<T> extends SimpleLdapRepository<T>
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<T> findAll(Predicate predicate) {
|
public List<T> findAll(Predicate predicate) {
|
||||||
return queryFor(predicate).list();
|
return executor.findAll(predicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
@@ -139,40 +104,28 @@ public class QuerydslLdapRepository<T> extends SimpleLdapRepository<T>
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public long count(Predicate predicate) {
|
public long count(Predicate predicate) {
|
||||||
return findBy(predicate, FluentQuery.FetchableFluentQuery::count);
|
return executor.count(predicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#exists(com.querydsl.core.types.Predicate)
|
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#exists(com.querydsl.core.types.Predicate)
|
||||||
*/
|
*/
|
||||||
public boolean exists(Predicate predicate) {
|
public boolean exists(Predicate predicate) {
|
||||||
return findBy(predicate, FluentQuery.FetchableFluentQuery::exists);
|
return executor.exists(predicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findAll(com.querydsl.core.types.Predicate, org.springframework.data.domain.Sort)
|
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findAll(com.querydsl.core.types.Predicate, org.springframework.data.domain.Sort)
|
||||||
*/
|
*/
|
||||||
public Iterable<T> findAll(Predicate predicate, Sort sort) {
|
public Iterable<T> findAll(Predicate predicate, Sort sort) {
|
||||||
|
return executor.findAll(predicate, sort);
|
||||||
Assert.notNull(sort, "Pageable must not be null!");
|
|
||||||
|
|
||||||
if (sort.isUnsorted()) {
|
|
||||||
return findAll(predicate);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new UnsupportedOperationException("Sorting is not supported");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findAll(com.querydsl.core.types.OrderSpecifier[])
|
* @see org.springframework.data.querydsl.QueryDslPredicateExecutor#findAll(com.querydsl.core.types.OrderSpecifier[])
|
||||||
*/
|
*/
|
||||||
public Iterable<T> findAll(OrderSpecifier<?>... orders) {
|
public Iterable<T> findAll(OrderSpecifier<?>... orders) {
|
||||||
|
return executor.findAll(orders);
|
||||||
if (orders.length == 0) {
|
|
||||||
return findAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new UnsupportedOperationException("Sorting is not supported");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
@@ -180,12 +133,7 @@ public class QuerydslLdapRepository<T> extends SimpleLdapRepository<T>
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Iterable<T> findAll(Predicate predicate, OrderSpecifier<?>... orders) {
|
public Iterable<T> findAll(Predicate predicate, OrderSpecifier<?>... orders) {
|
||||||
|
return executor.findAll(predicate, orders);
|
||||||
if (orders.length == 0) {
|
|
||||||
return findAll(predicate);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new UnsupportedOperationException("Sorting is not supported");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
@@ -193,20 +141,7 @@ public class QuerydslLdapRepository<T> extends SimpleLdapRepository<T>
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Page<T> findAll(Predicate predicate, Pageable pageable) {
|
public Page<T> findAll(Predicate predicate, Pageable pageable) {
|
||||||
|
return executor.findAll(predicate, pageable);
|
||||||
Assert.notNull(pageable, "Pageable must not be null!");
|
|
||||||
|
|
||||||
if (pageable.isUnpaged()) {
|
|
||||||
return PageableExecutionUtils.getPage(findAll(predicate), pageable, () -> count(predicate));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pageable.getSort().isUnsorted() && pageable.getPageNumber() == 0) {
|
|
||||||
|
|
||||||
return PageableExecutionUtils.getPage(queryFor(predicate, q -> q.countLimit(pageable.getPageSize())).list(),
|
|
||||||
pageable, () -> count(predicate));
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new UnsupportedOperationException("Pagination and Sorting is not supported");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -217,250 +152,7 @@ public class QuerydslLdapRepository<T> extends SimpleLdapRepository<T>
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <S extends T, R> R findBy(Predicate predicate,
|
public <S extends T, R> R findBy(Predicate predicate,
|
||||||
Function<FluentQuery.FetchableFluentQuery<S>, R> queryFunction) {
|
Function<FluentQuery.FetchableFluentQuery<S>, R> queryFunction) {
|
||||||
|
return executor.findBy(predicate, queryFunction);
|
||||||
Assert.notNull(queryFunction, "Query function must not be null!");
|
|
||||||
|
|
||||||
return queryFunction.apply(new FluentQuerydsl<>(predicate, (Class<S>) entityType));
|
|
||||||
}
|
|
||||||
|
|
||||||
private QuerydslLdapQuery<T> queryFor(Predicate predicate) {
|
|
||||||
return queryFor(predicate, it -> {
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private QuerydslLdapQuery<T> queryFor(Predicate predicate, Consumer<LdapQueryBuilder> queryBuilderConsumer) {
|
|
||||||
|
|
||||||
Assert.notNull(predicate, "Predicate must not be null!");
|
|
||||||
|
|
||||||
return new QuerydslLdapQuery<>(ldapOperations, entityType, queryBuilderConsumer).where(predicate);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery} using {@link Example}.
|
|
||||||
*
|
|
||||||
* @author Mark Paluch
|
|
||||||
* @since 2.6
|
|
||||||
*/
|
|
||||||
class FluentQuerydsl<R> implements FluentQuery.FetchableFluentQuery<R> {
|
|
||||||
|
|
||||||
private final Predicate predicate;
|
|
||||||
private final Sort sort;
|
|
||||||
private final Class<R> resultType;
|
|
||||||
private final List<String> projection;
|
|
||||||
|
|
||||||
FluentQuerydsl(Predicate predicate, Class<R> resultType) {
|
|
||||||
this(predicate, Sort.unsorted(), resultType, Collections.emptyList());
|
|
||||||
}
|
|
||||||
|
|
||||||
FluentQuerydsl(Predicate predicate, Sort sort, Class<R> resultType, List<String> projection) {
|
|
||||||
this.predicate = predicate;
|
|
||||||
this.sort = sort;
|
|
||||||
this.resultType = resultType;
|
|
||||||
this.projection = projection;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#sortBy(org.springframework.data.domain.Sort)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public FetchableFluentQuery<R> sortBy(Sort sort) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#as(java.lang.Class)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public <R1> FetchableFluentQuery<R1> as(Class<R1> resultType) {
|
|
||||||
|
|
||||||
Assert.notNull(projection, "Projection target type must not be null!");
|
|
||||||
|
|
||||||
return new FluentQuerydsl<>(predicate, sort, resultType, projection);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#project(java.util.Collection)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public FetchableFluentQuery<R> project(Collection<String> properties) {
|
|
||||||
|
|
||||||
Assert.notNull(properties, "Projection properties must not be null!");
|
|
||||||
|
|
||||||
return new FluentQuerydsl<>(predicate, sort, resultType, new ArrayList<>(properties));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#oneValue()
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public R oneValue() {
|
|
||||||
|
|
||||||
List<T> results = findTop(2);
|
|
||||||
|
|
||||||
if (results.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (results.size() > 1) {
|
|
||||||
throw new IncorrectResultSizeDataAccessException(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
T one = results.get(0);
|
|
||||||
return getConversionFunction().apply(one);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#firstValue()
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public R firstValue() {
|
|
||||||
|
|
||||||
List<T> results = findTop(2);
|
|
||||||
|
|
||||||
if (results.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
T one = results.get(0);
|
|
||||||
return getConversionFunction().apply(one);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#all()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public List<R> all() {
|
|
||||||
return stream().collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#page(org.springframework.data.domain.Pageable)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Page<R> page(Pageable pageable) {
|
|
||||||
|
|
||||||
Assert.notNull(pageable, "Pageable must not be null!");
|
|
||||||
|
|
||||||
if (pageable.isUnpaged()) {
|
|
||||||
return PageableExecutionUtils.getPage(all(), pageable, this::count);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pageable.getSort().isUnsorted() && pageable.getPageNumber() == 0) {
|
|
||||||
|
|
||||||
Function<Object, R> conversionFunction = getConversionFunction();
|
|
||||||
|
|
||||||
return PageableExecutionUtils.getPage(
|
|
||||||
findTop(pageable.getPageSize()).stream().map(conversionFunction).collect(Collectors.toList()), pageable,
|
|
||||||
this::count);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new UnsupportedOperationException("Pagination and Sorting is not supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#stream()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Stream<R> stream() {
|
|
||||||
|
|
||||||
Function<Object, R> conversionFunction = getConversionFunction();
|
|
||||||
|
|
||||||
return search(null, QuerydslLdapQuery::list).stream().map(conversionFunction);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#count()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public long count() {
|
|
||||||
return search(null, q -> q.search(it -> true)).size();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#exists()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean exists() {
|
|
||||||
return !search(1, q -> q.search(it -> true)).isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<T> findTop(int limit) {
|
|
||||||
return search(limit, QuerydslLdapQuery::list);
|
|
||||||
}
|
|
||||||
|
|
||||||
private <S> S search(@Nullable Integer limit, Function<QuerydslLdapQuery<T>, S> searchFunction) {
|
|
||||||
|
|
||||||
QuerydslLdapQuery<T> q = queryFor(predicate, query -> {
|
|
||||||
|
|
||||||
List<String> projection = getProjection();
|
|
||||||
|
|
||||||
if (!projection.isEmpty()) {
|
|
||||||
query.attributes(projection.toArray(new String[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (limit != null) {
|
|
||||||
query.countLimit(limit);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return searchFunction.apply(q);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private <P> Function<Object, P> getConversionFunction(Class<?> inputType, Class<P> targetType) {
|
|
||||||
|
|
||||||
if (targetType.isAssignableFrom(inputType)) {
|
|
||||||
return (Function<Object, P>) Function.identity();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (targetType.isInterface()) {
|
|
||||||
return o -> projectionFactory.createProjection(targetType, o);
|
|
||||||
}
|
|
||||||
|
|
||||||
DtoInstantiatingConverter converter = new DtoInstantiatingConverter(targetType, context, entityInstantiators);
|
|
||||||
|
|
||||||
return o -> (P) converter.convert(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Function<Object, R> getConversionFunction() {
|
|
||||||
return getConversionFunction(entityType, resultType);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> getProjection() {
|
|
||||||
|
|
||||||
if (projection.isEmpty()) {
|
|
||||||
|
|
||||||
if (resultType.isAssignableFrom(entityType)) {
|
|
||||||
return projection;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resultType.isInterface()) {
|
|
||||||
ProjectionInformation projectionInformation = projectionFactory.getProjectionInformation(resultType);
|
|
||||||
|
|
||||||
if (projectionInformation.isClosed()) {
|
|
||||||
return projectionInformation.getInputProperties().stream().map(FeatureDescriptor::getName)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return projection;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
|||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.PageRequest;
|
import org.springframework.data.domain.PageRequest;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
|
import org.springframework.data.ldap.core.mapping.LdapMappingContext;
|
||||||
|
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
|
||||||
import org.springframework.data.repository.query.FluentQuery;
|
import org.springframework.data.repository.query.FluentQuery;
|
||||||
import org.springframework.ldap.core.ContextMapper;
|
import org.springframework.ldap.core.ContextMapper;
|
||||||
import org.springframework.ldap.core.LdapOperations;
|
import org.springframework.ldap.core.LdapOperations;
|
||||||
@@ -45,24 +47,24 @@ import org.springframework.ldap.odm.core.impl.DefaultObjectDirectoryMapper;
|
|||||||
import org.springframework.ldap.query.LdapQuery;
|
import org.springframework.ldap.query.LdapQuery;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link QuerydslLdapRepository}.
|
* Unit tests for {@link QuerydslLdapPredicateExecutor}.
|
||||||
*
|
*
|
||||||
* @author Mark Paluch
|
* @author Mark Paluch
|
||||||
*/
|
*/
|
||||||
@MockitoSettings
|
@MockitoSettings
|
||||||
class QuerydslLdapRepositoryUnitTests {
|
class QuerydslLdapPredicateExecutorUnitTests {
|
||||||
|
|
||||||
@Mock LdapOperations ldapOperations;
|
@Mock LdapOperations ldapOperations;
|
||||||
|
|
||||||
UnitTestPerson walter, hank;
|
UnitTestPerson walter, hank;
|
||||||
|
|
||||||
QuerydslLdapRepository<UnitTestPerson> repository;
|
QuerydslLdapPredicateExecutor<UnitTestPerson> repository;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void before() throws Exception {
|
void before() throws Exception {
|
||||||
when(ldapOperations.getObjectDirectoryMapper()).thenReturn(new DefaultObjectDirectoryMapper());
|
when(ldapOperations.getObjectDirectoryMapper()).thenReturn(new DefaultObjectDirectoryMapper());
|
||||||
repository = new QuerydslLdapRepository<>(ldapOperations, ldapOperations.getObjectDirectoryMapper(),
|
repository = new QuerydslLdapPredicateExecutor<>(UnitTestPerson.class, new SpelAwareProxyProjectionFactory(),
|
||||||
UnitTestPerson.class);
|
ldapOperations, new LdapMappingContext());
|
||||||
|
|
||||||
walter = new UnitTestPerson(new LdapName("cn=walter"), "Walter", "White", Collections.emptyList(), "US",
|
walter = new UnitTestPerson(new LdapName("cn=walter"), "Walter", "White", Collections.emptyList(), "US",
|
||||||
"Heisenberg", "000");
|
"Heisenberg", "000");
|
||||||
Reference in New Issue
Block a user