Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.micronaut.data.runtime.intercept.criteria.AbstractSpecificationInterceptor Maven / Gradle / Ivy
/*
* Copyright 2017-2021 original 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 io.micronaut.data.runtime.intercept.criteria;
import io.micronaut.aop.MethodInvocationContext;
import io.micronaut.core.annotation.AnnotationMetadata;
import io.micronaut.core.annotation.Internal;
import io.micronaut.core.annotation.NonNull;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.core.beans.BeanIntrospection;
import io.micronaut.core.type.Argument;
import io.micronaut.core.util.CollectionUtils;
import io.micronaut.core.util.StringUtils;
import io.micronaut.data.annotation.RepositoryConfiguration;
import io.micronaut.data.intercept.RepositoryMethodKey;
import io.micronaut.data.model.AssociationUtils;
import io.micronaut.data.model.Pageable;
import io.micronaut.data.model.Pageable.Mode;
import io.micronaut.data.model.Sort;
import io.micronaut.data.model.jpa.criteria.PersistentEntityFrom;
import io.micronaut.data.model.jpa.criteria.impl.QueryResultPersistentEntityCriteriaQuery;
import io.micronaut.data.model.query.JoinPath;
import io.micronaut.data.model.query.QueryModel;
import io.micronaut.data.model.query.builder.QueryBuilder;
import io.micronaut.data.model.query.builder.QueryResult;
import io.micronaut.data.model.runtime.PreparedQuery;
import io.micronaut.data.model.runtime.StoredQuery;
import io.micronaut.data.operations.BlockingCriteriaCapableRepository;
import io.micronaut.data.operations.CriteriaRepositoryOperations;
import io.micronaut.data.operations.RepositoryOperations;
import io.micronaut.data.repository.jpa.criteria.CriteriaDeleteBuilder;
import io.micronaut.data.repository.jpa.criteria.CriteriaQueryBuilder;
import io.micronaut.data.repository.jpa.criteria.CriteriaUpdateBuilder;
import io.micronaut.data.repository.jpa.criteria.DeleteSpecification;
import io.micronaut.data.repository.jpa.criteria.PredicateSpecification;
import io.micronaut.data.repository.jpa.criteria.QuerySpecification;
import io.micronaut.data.repository.jpa.criteria.UpdateSpecification;
import io.micronaut.data.runtime.criteria.RuntimeCriteriaBuilder;
import io.micronaut.data.runtime.intercept.AbstractQueryInterceptor;
import io.micronaut.data.runtime.query.MethodContextAwareStoredQueryDecorator;
import io.micronaut.data.runtime.query.PreparedQueryDecorator;
import io.micronaut.data.runtime.query.StoredQueryDecorator;
import io.micronaut.data.runtime.query.internal.QueryResultStoredQuery;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaDelete;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.CriteriaUpdate;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.Order;
import jakarta.persistence.criteria.Path;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;
import static io.micronaut.data.model.runtime.StoredQuery.OperationType;
/**
* Abstract specification interceptor.
*
* @param The declaring type
* @param The return type
* @author Denis Stepanov
* @since 3.2
*/
@Internal
public abstract class AbstractSpecificationInterceptor extends AbstractQueryInterceptor {
protected final CriteriaRepositoryOperations criteriaRepositoryOperations;
private final Map sqlQueryBuilderForRepositories = new ConcurrentHashMap<>();
private final Map> methodsJoinPaths = new ConcurrentHashMap<>();
private final CriteriaBuilder criteriaBuilder;
private final MethodContextAwareStoredQueryDecorator storedQueryDecorator;
private final PreparedQueryDecorator preparedQueryDecorator;
/**
* Default constructor.
*
* @param operations The operations
*/
protected AbstractSpecificationInterceptor(RepositoryOperations operations) {
super(operations);
if (operations instanceof CriteriaRepositoryOperations criteriaOps) {
criteriaRepositoryOperations = criteriaOps;
criteriaBuilder = criteriaRepositoryOperations.getCriteriaBuilder();
} else if (operations instanceof BlockingCriteriaCapableRepository repository) {
criteriaRepositoryOperations = repository.blocking();
criteriaBuilder = criteriaRepositoryOperations.getCriteriaBuilder();
} else {
criteriaRepositoryOperations = null;
criteriaBuilder = operations.getApplicationContext().getBean(RuntimeCriteriaBuilder.class);
}
if (operations instanceof MethodContextAwareStoredQueryDecorator) {
storedQueryDecorator = (MethodContextAwareStoredQueryDecorator) operations;
} else if (operations instanceof StoredQueryDecorator decorator) {
storedQueryDecorator = new MethodContextAwareStoredQueryDecorator() {
@Override
public StoredQuery decorate(MethodInvocationContext, ?> context, StoredQuery storedQuery) {
return decorator.decorate(storedQuery);
}
};
} else {
storedQueryDecorator = new MethodContextAwareStoredQueryDecorator() {
@Override
public StoredQuery decorate(MethodInvocationContext, ?> context, StoredQuery storedQuery) {
return storedQuery;
}
};
}
preparedQueryDecorator = operations instanceof PreparedQueryDecorator decorator ? decorator : new PreparedQueryDecorator() {
@Override
public PreparedQuery decorate(PreparedQuery preparedQuery) {
return preparedQuery;
}
};
}
@NonNull
protected final Iterable> findAll(RepositoryMethodKey methodKey, MethodInvocationContext context, Type type) {
Set methodJoinPaths = getMethodJoinPaths(methodKey, context);
if (criteriaRepositoryOperations != null) {
CriteriaQuery query = buildQuery(context, type, methodJoinPaths);
Pageable pageable = getPageable(context);
if (pageable != null) {
if (pageable.getMode() != Mode.OFFSET) {
throw new UnsupportedOperationException("Pageable mode " + pageable.getMode() + " is not supported with specifications");
}
return criteriaRepositoryOperations.findAll(query, (int) pageable.getOffset(), pageable.getSize());
}
return criteriaRepositoryOperations.findAll(query);
}
return operations.findAll(preparedQueryForCriteria(methodKey, context, type, methodJoinPaths));
}
@NonNull
protected final Object findOne(RepositoryMethodKey methodKey, MethodInvocationContext context, Type type) {
Set methodJoinPaths = getMethodJoinPaths(methodKey, context);
if (criteriaRepositoryOperations != null) {
return criteriaRepositoryOperations.findOne(buildQuery(context, type, methodJoinPaths));
}
return operations.findOne(preparedQueryForCriteria(methodKey, context, type, methodJoinPaths));
}
protected final Set getMethodJoinPaths(RepositoryMethodKey methodKey, MethodInvocationContext context) {
return methodsJoinPaths.computeIfAbsent(methodKey, repositoryMethodKey ->
AssociationUtils.getJoinFetchPaths(context));
}
@NonNull
protected final Long count(RepositoryMethodKey methodKey, MethodInvocationContext context) {
Set methodJoinPaths = getMethodJoinPaths(methodKey, context);
Long count;
if (criteriaRepositoryOperations != null) {
count = criteriaRepositoryOperations.findOne(buildCountQuery(context));
} else {
count = operations.findOne(preparedQueryForCriteria(methodKey, context, Type.COUNT, methodJoinPaths));
}
return count == null ? 0 : count;
}
protected final boolean exists(RepositoryMethodKey methodKey, MethodInvocationContext context) {
Set methodJoinPaths = getMethodJoinPaths(methodKey, context);
if (criteriaRepositoryOperations != null) {
return criteriaRepositoryOperations.findOne(buildExistsQuery(context, methodJoinPaths));
}
Object one = operations.findOne(preparedQueryForCriteria(methodKey, context, Type.EXISTS, methodJoinPaths));
return one instanceof Boolean aBoolean ? aBoolean : one != null;
}
protected final Optional deleteAll(RepositoryMethodKey methodKey, MethodInvocationContext context) {
Set methodJoinPaths = getMethodJoinPaths(methodKey, context);
if (criteriaRepositoryOperations != null) {
return criteriaRepositoryOperations.deleteAll(buildDeleteQuery(context));
}
return operations.executeDelete(preparedQueryForCriteria(methodKey, context, Type.DELETE_ALL, methodJoinPaths));
}
protected final Optional updateAll(RepositoryMethodKey methodKey, MethodInvocationContext context) {
Set methodJoinPaths = getMethodJoinPaths(methodKey, context);
if (criteriaRepositoryOperations != null) {
return criteriaRepositoryOperations.updateAll(buildUpdateQuery(context));
}
return operations.executeUpdate(preparedQueryForCriteria(methodKey, context, Type.UPDATE_ALL, methodJoinPaths));
}
@NonNull
protected final PreparedQuery preparedQueryForCriteria(RepositoryMethodKey methodKey,
MethodInvocationContext context,
Type type,
Set methodJoinPaths) {
Pageable pageable = findPageable(context);
QueryBuilder sqlQueryBuilder = getQueryBuilder(methodKey, context);
StoredQuery storedQuery;
if (type == Type.FIND_ALL || type == Type.FIND_ONE || type == Type.FIND_PAGE) {
storedQuery = buildFind(methodKey, context, type, methodJoinPaths);
} else if (type == Type.COUNT) {
storedQuery = buildCount(methodKey, context);
} else if (type == Type.DELETE_ALL) {
storedQuery = buildDeleteAll(context, sqlQueryBuilder);
} else if (type == Type.UPDATE_ALL) {
storedQuery = buildUpdateAll(context, sqlQueryBuilder);
} else if (type == Type.EXISTS) {
storedQuery = buildExists(context, sqlQueryBuilder, methodJoinPaths);
} else {
throw new IllegalStateException("Unknown criteria type: " + type);
}
storedQuery = storedQueryDecorator.decorate(context, storedQuery);
PreparedQuery preparedQuery = (PreparedQuery) preparedQueryResolver.resolveQuery(context, storedQuery, pageable);
return preparedQueryDecorator.decorate(preparedQuery);
}
@NonNull
private Pageable findPageable(MethodInvocationContext context) {
Pageable pageable = Pageable.UNPAGED;
for (Object param : context.getParameterValues()) {
if (param instanceof Pageable pageableParam) {
pageable = pageableParam;
break;
}
}
return pageable;
}
@NonNull
private QueryBuilder getQueryBuilder(RepositoryMethodKey methodKey, MethodInvocationContext context) {
return sqlQueryBuilderForRepositories.computeIfAbsent(methodKey, repositoryMethodKey -> {
Class builder = context.getAnnotationMetadata().classValue(RepositoryConfiguration.class, "queryBuilder")
.orElseThrow(() -> new IllegalStateException("Cannot determine QueryBuilder"));
BeanIntrospection introspection = BeanIntrospection.getIntrospection(builder);
if (introspection.getConstructorArguments().length == 1
&& introspection.getConstructorArguments()[0].getType() == AnnotationMetadata.class) {
return introspection.instantiate(context.getAnnotationMetadata());
}
return introspection.instantiate();
}
);
}
private StoredQuery buildExists(MethodInvocationContext context, QueryBuilder sqlQueryBuilder, Set annotationJoinPaths) {
CriteriaQuery criteriaQuery = buildExistsQuery(context, annotationJoinPaths);
QueryResult queryResult = ((QueryResultPersistentEntityCriteriaQuery) criteriaQuery).buildQuery(sqlQueryBuilder);
return QueryResultStoredQuery.single(OperationType.EXISTS, context.getName(), context.getAnnotationMetadata(),
queryResult, getRequiredRootEntity(context));
}
protected final CriteriaQuery buildExistsQuery(MethodInvocationContext context, Set annotationJoinPaths) {
return this.getCriteriaQueryBuilder(context, annotationJoinPaths).build(criteriaBuilder);
}
private StoredQuery buildUpdateAll(MethodInvocationContext context, QueryBuilder sqlQueryBuilder) {
CriteriaUpdate criteriaUpdate = buildUpdateQuery(context);
QueryResult queryResult = ((QueryResultPersistentEntityCriteriaQuery) criteriaUpdate).buildQuery(sqlQueryBuilder);
return QueryResultStoredQuery.single(OperationType.UPDATE, context.getName(),
context.getAnnotationMetadata(), queryResult, (Class) criteriaUpdate.getRoot().getJavaType());
}
protected final CriteriaUpdate buildUpdateQuery(MethodInvocationContext context) {
return this.getCriteriaUpdateBuilder(context).build(criteriaBuilder);
}
private StoredQuery buildDeleteAll(MethodInvocationContext context, QueryBuilder sqlQueryBuilder) {
CriteriaDelete criteriaDelete = buildDeleteQuery(context);
QueryResult queryResult = ((QueryResultPersistentEntityCriteriaQuery) criteriaDelete).buildQuery(sqlQueryBuilder);
return QueryResultStoredQuery.single(OperationType.DELETE, context.getName(),
context.getAnnotationMetadata(), queryResult, (Class) criteriaDelete.getRoot().getJavaType());
}
protected final CriteriaDelete buildDeleteQuery(MethodInvocationContext context) {
return this.getCriteriaDeleteBuilder(context).build(criteriaBuilder);
}
private StoredQuery buildCount(RepositoryMethodKey methodKey,
MethodInvocationContext context) {
CriteriaQuery criteriaQuery = buildCountQuery(context);
QueryBuilder sqlQueryBuilder = getQueryBuilder(methodKey, context);
QueryResult queryResult = ((QueryResultPersistentEntityCriteriaQuery) criteriaQuery).buildQuery(sqlQueryBuilder);
return QueryResultStoredQuery.count(context.getName(), context.getAnnotationMetadata(), queryResult, getRequiredRootEntity(context));
}
@NonNull
protected final CriteriaQuery buildCountQuery(MethodInvocationContext context) {
Class rootEntity = getRequiredRootEntity(context);
QuerySpecification specification = getQuerySpecification(context);
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Long.class);
Root root = criteriaQuery.from(rootEntity);
if (specification != null) {
Predicate predicate = specification.toPredicate(root, criteriaQuery, criteriaBuilder);
if (predicate != null) {
criteriaQuery.where(predicate);
}
}
if (criteriaQuery.isDistinct()) {
return criteriaQuery.select(criteriaBuilder.countDistinct(root));
} else {
return criteriaQuery.select(criteriaBuilder.count(root));
}
}
private StoredQuery buildFind(RepositoryMethodKey methodKey,
MethodInvocationContext context,
Type type,
Set methodJoinPaths) {
CriteriaQuery criteriaQuery = buildInternalQuery(context, type, methodJoinPaths);
QueryBuilder sqlQueryBuilder = getQueryBuilder(methodKey, context);
QueryResultPersistentEntityCriteriaQuery queryModelCriteriaQuery = (QueryResultPersistentEntityCriteriaQuery) criteriaQuery;
QueryModel queryModel = queryModelCriteriaQuery.getQueryModel();
Collection queryJoinPaths = queryModel.getJoinPaths();
QueryResult queryResult = sqlQueryBuilder.buildQuery(AnnotationMetadata.EMPTY_METADATA, queryModel);
Set joinPaths = mergeJoinPaths(methodJoinPaths, queryJoinPaths);
Class rootEntity = getRequiredRootEntity(context);
if (type == Type.FIND_ONE) {
return QueryResultStoredQuery.single(OperationType.QUERY, context.getName(), context.getAnnotationMetadata(),
queryResult, rootEntity, criteriaQuery.getResultType(), joinPaths);
}
Pageable pageable = findPageable(context);
return QueryResultStoredQuery.many(context.getName(), context.getAnnotationMetadata(), queryResult, rootEntity,
criteriaQuery.getResultType(), !pageable.isUnpaged(), joinPaths);
}
private CriteriaQuery buildInternalQuery(MethodInvocationContext context, Type type, Set methodJoinPaths) {
CriteriaQueryBuilder builder = getCriteriaQueryBuilder(context, methodJoinPaths);
CriteriaQuery criteriaQuery = builder.build(criteriaBuilder);
if (type == Type.FIND_ALL) {
Pageable pageable = findPageable(context);
for (Object param : context.getParameterValues()) {
if (param instanceof Sort sort && param != pageable) {
if (sort.isSorted()) {
Root> root = criteriaQuery.getRoots().stream().findFirst().orElseThrow(() -> new IllegalStateException("The root not found!"));
criteriaQuery.orderBy(getOrders(sort, root, criteriaBuilder));
break;
}
}
}
}
return criteriaQuery;
}
protected final CriteriaQuery buildQuery(MethodInvocationContext context, Type type, Set methodJoinPaths) {
CriteriaQueryBuilder builder = getCriteriaQueryBuilder(context, methodJoinPaths);
CriteriaQuery criteriaQuery = builder.build(criteriaBuilder);
for (Object param : context.getParameterValues()) {
if (param instanceof Sort sort) {
if (sort.isSorted()) {
Root> root = criteriaQuery.getRoots().stream().findFirst().orElseThrow(() -> new IllegalStateException("The root not found!"));
criteriaQuery.orderBy(getOrders(sort, root, criteriaBuilder));
break;
}
}
}
return criteriaQuery;
}
/**
* Find {@link io.micronaut.data.repository.jpa.criteria.QuerySpecification} in context.
*
* @param context The context
* @param the specification entity root type
* @return found specification
*/
@Nullable
protected QuerySpecification getQuerySpecification(MethodInvocationContext, ?> context) {
final Object parameterValue = context.getParameterValues()[0];
if (parameterValue instanceof QuerySpecification querySpecification) {
return querySpecification;
}
if (parameterValue instanceof PredicateSpecification predicateSpecification) {
return QuerySpecification.where(predicateSpecification);
}
Argument> parameterArgument = context.getArguments()[0];
if (parameterArgument.isAssignableFrom(QuerySpecification.class) || parameterArgument.isAssignableFrom(PredicateSpecification.class)) {
return null;
}
throw new IllegalArgumentException("Argument must be an instance of: " + QuerySpecification.class + " or " + PredicateSpecification.class);
}
/**
* Find {@link io.micronaut.data.repository.jpa.criteria.CriteriaQueryBuilder}
* or {@link io.micronaut.data.repository.jpa.criteria.QuerySpecification} in context.
*
* @param context The context
* @param joinPaths The join fetch paths
* @param the result type
* @return found specification
*/
@NonNull
protected CriteriaQueryBuilder getCriteriaQueryBuilder(MethodInvocationContext, ?> context, Set joinPaths) {
final Object parameterValue = context.getParameterValues()[0];
if (parameterValue instanceof CriteriaQueryBuilder criteriaQueryBuilder) {
return criteriaQueryBuilder;
}
return criteriaBuilder -> {
Class rootEntity = getRequiredRootEntity(context);
QuerySpecification specification = getQuerySpecification(context);
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(rootEntity);
Root root = criteriaQuery.from(rootEntity);
if (specification != null) {
Predicate predicate = specification.toPredicate(root, criteriaQuery, criteriaBuilder);
if (predicate != null) {
criteriaQuery.where(predicate);
}
}
if (CollectionUtils.isNotEmpty(joinPaths)) {
for (JoinPath joinPath : joinPaths) {
join(root, joinPath);
}
}
return criteriaQuery;
};
}
private void join(Root> root, JoinPath joinPath) {
if (root instanceof PersistentEntityFrom, ?> persistentEntityFrom) {
Optional optAlias = joinPath.getAlias();
if (optAlias.isPresent()) {
persistentEntityFrom.join(joinPath.getPath(), joinPath.getJoinType(), optAlias.get());
} else {
persistentEntityFrom.join(joinPath.getPath(), joinPath.getJoinType());
}
}
}
private Set mergeJoinPaths(Collection joinPaths, Collection additionalJoinPaths) {
Set resultPaths = CollectionUtils.newHashSet(joinPaths.size() + additionalJoinPaths.size());
if (CollectionUtils.isNotEmpty(joinPaths)) {
resultPaths.addAll(joinPaths);
}
if (CollectionUtils.isNotEmpty(additionalJoinPaths)) {
Map existingPathsByPath = resultPaths.stream().collect(Collectors.toMap(JoinPath::getPath, Function.identity()));
resultPaths.addAll(additionalJoinPaths.stream().filter(jp -> !existingPathsByPath.containsKey(jp.getPath())).collect(Collectors.toSet()));
}
return resultPaths;
}
/**
* Find {@link io.micronaut.data.repository.jpa.criteria.DeleteSpecification} in context.
*
* @param context The context
* @param the specification entity root type
* @return found specification
*/
@Nullable
protected DeleteSpecification getDeleteSpecification(MethodInvocationContext, ?> context) {
final Object parameterValue = context.getParameterValues()[0];
if (parameterValue instanceof DeleteSpecification deleteSpecification) {
return deleteSpecification;
}
if (parameterValue instanceof PredicateSpecification predicateSpecification) {
return DeleteSpecification.where(predicateSpecification);
}
Argument> parameterArgument = context.getArguments()[0];
if (parameterArgument.isAssignableFrom(DeleteSpecification.class) || parameterArgument.isAssignableFrom(PredicateSpecification.class)) {
return null;
}
throw new IllegalArgumentException("Argument must be an instance of: " + DeleteSpecification.class + " or " + PredicateSpecification.class);
}
/**
* Find {@link io.micronaut.data.repository.jpa.criteria.CriteriaDeleteBuilder}
* or {@link io.micronaut.data.repository.jpa.criteria.QuerySpecification} in context.
*
* @param context The context
* @param the result type
* @return found specification
*/
@NonNull
protected CriteriaDeleteBuilder getCriteriaDeleteBuilder(MethodInvocationContext, ?> context) {
final Object parameterValue = context.getParameterValues()[0];
if (parameterValue instanceof CriteriaDeleteBuilder criteriaDeleteBuilder) {
return criteriaDeleteBuilder;
}
return criteriaBuilder -> {
Class rootEntity = getRequiredRootEntity(context);
DeleteSpecification specification = getDeleteSpecification(context);
CriteriaDelete criteriaDelete = criteriaBuilder.createCriteriaDelete(rootEntity);
Root root = criteriaDelete.from(rootEntity);
if (specification != null) {
Predicate predicate = specification.toPredicate(root, criteriaDelete, criteriaBuilder);
if (predicate != null) {
criteriaDelete.where(predicate);
}
}
return criteriaDelete;
};
}
/**
* Find {@link io.micronaut.data.repository.jpa.criteria.UpdateSpecification} in context.
*
* @param context The context
* @param the specification entity root type
* @return found specification
*/
@Nullable
protected UpdateSpecification getUpdateSpecification(MethodInvocationContext, ?> context) {
final Object parameterValue = context.getParameterValues()[0];
if (parameterValue instanceof UpdateSpecification updateSpecification) {
return updateSpecification;
}
Argument> parameterArgument = context.getArguments()[0];
if (parameterArgument.isAssignableFrom(UpdateSpecification.class) || parameterArgument.isAssignableFrom(PredicateSpecification.class)) {
return null;
}
throw new IllegalArgumentException("Argument must be an instance of: " + UpdateSpecification.class);
}
/**
* Find {@link io.micronaut.data.repository.jpa.criteria.CriteriaUpdateBuilder}
* or {@link io.micronaut.data.repository.jpa.criteria.QuerySpecification} in context.
*
* @param context The context
* @param the result type
* @return found specification
*/
@NonNull
protected CriteriaUpdateBuilder getCriteriaUpdateBuilder(MethodInvocationContext, ?> context) {
final Object parameterValue = context.getParameterValues()[0];
if (parameterValue instanceof CriteriaUpdateBuilder criteriaUpdateBuilder) {
return criteriaUpdateBuilder;
}
return criteriaBuilder -> {
Class rootEntity = getRequiredRootEntity(context);
UpdateSpecification specification = getUpdateSpecification(context);
CriteriaUpdate criteriaUpdate = criteriaBuilder.createCriteriaUpdate(rootEntity);
Root root = criteriaUpdate.from(rootEntity);
if (specification != null) {
Predicate predicate = specification.toPredicate(root, criteriaUpdate, criteriaBuilder);
if (predicate != null) {
criteriaUpdate.where(predicate);
}
}
return criteriaUpdate;
};
}
private List getOrders(Sort sort, Root> root, CriteriaBuilder cb) {
List orders = new ArrayList<>();
for (Sort.Order order : sort.getOrderBy()) {
Path> path = root;
for (String property : StringUtils.splitOmitEmptyStrings(order.getProperty(), '.')) {
path = path.get(property);
}
Expression> expression = order.isIgnoreCase() ? cb.lower(path.type().as(String.class)) : path;
orders.add(order.isAscending() ? cb.asc(expression) : cb.desc(expression));
}
return orders;
}
protected enum Type {
COUNT, FIND_ONE, FIND_PAGE, FIND_ALL, DELETE_ALL, UPDATE_ALL, EXISTS
}
}