Remove org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder and fix deprecated Specification.where (#2760)
Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
@@ -11,7 +11,6 @@ package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
|
||||
@@ -19,7 +18,6 @@ import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.NoCountSliceRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
@@ -36,15 +34,10 @@ import org.springframework.util.ObjectUtils;
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class JpaManagementHelper {
|
||||
|
||||
public static <T, J extends T> Optional<J> findOneBySpec(
|
||||
final JpaSpecificationExecutor<J> repository, final List<Specification<J>> specList) {
|
||||
return repository.findOne(combineWithAnd(specList));
|
||||
}
|
||||
|
||||
public static <T, J extends T> Page<T> findAllWithCountBySpec(
|
||||
final JpaSpecificationExecutor<J> repository, final List<Specification<J>> specList, final Pageable pageable) {
|
||||
if (CollectionUtils.isEmpty(specList)) {
|
||||
return convertPage(repository.findAll(Specification.where(null), pageable), pageable);
|
||||
return convertPage(repository.findAll(Specification.unrestricted(), pageable), pageable);
|
||||
}
|
||||
|
||||
return convertPage(repository.findAll(combineWithAnd(specList), pageable), pageable);
|
||||
@@ -56,9 +49,16 @@ public final class JpaManagementHelper {
|
||||
|
||||
public static <J> Specification<J> combineWithAnd(final List<Specification<J>> specList) {
|
||||
if (ObjectUtils.isEmpty(specList)) {
|
||||
return Specification.where(null);
|
||||
return Specification.unrestricted();
|
||||
} else if (specList.size() == 1) {
|
||||
return specList.get(0);
|
||||
} else {
|
||||
Specification<J> specs = specList.get(0);
|
||||
for (final Specification<J> specification : specList.subList(1, specList.size())) {
|
||||
specs = specs.and(specification);
|
||||
}
|
||||
return specs;
|
||||
}
|
||||
return specList.size() == 1 ? specList.get(0) : SpecificationsBuilder.combineWithAnd(specList);
|
||||
}
|
||||
|
||||
public static <T, J extends T> Slice<T> findAllWithoutCountBySpec(
|
||||
@@ -76,7 +76,7 @@ public final class JpaManagementHelper {
|
||||
|
||||
public static <J> long countBySpec(final JpaSpecificationExecutor<J> repository, final List<Specification<J>> specList) {
|
||||
if (CollectionUtils.isEmpty(specList)) {
|
||||
return repository.count(Specification.where(null));
|
||||
return repository.count(Specification.unrestricted());
|
||||
}
|
||||
|
||||
return repository.count(combineWithAnd(specList));
|
||||
@@ -92,16 +92,4 @@ public final class JpaManagementHelper {
|
||||
|
||||
return repository.save(result);
|
||||
}
|
||||
|
||||
// the format of filter string is 'name:version'. 'name' and 'version'
|
||||
// fields follow the starts_with semantic, that changes to equal for 'name'
|
||||
// field when the semicolon is present
|
||||
public static String[] getFilterNameAndVersionEntries(final String filterString) {
|
||||
final int semicolonIndex = filterString.indexOf(':');
|
||||
|
||||
final String filterName = semicolonIndex != -1 ? filterString.substring(0, semicolonIndex) : (filterString + "%");
|
||||
final String filterVersion = semicolonIndex != -1 ? (filterString.substring(semicolonIndex + 1) + "%") : "%";
|
||||
|
||||
return new String[] { ObjectUtils.isEmpty(filterName) ? "%" : filterName, filterVersion };
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,6 @@ import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetTagRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetTypeRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.ql.QLSupport;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
@@ -121,7 +120,7 @@ public class JpaTargetManagement
|
||||
TargetSpecifications.hasControllerId(controllerId));
|
||||
|
||||
final Specification<JpaTarget> combinedSpecification = Objects
|
||||
.requireNonNull(SpecificationsBuilder.combineWithAnd(specList));
|
||||
.requireNonNull(JpaManagementHelper.combineWithAnd(specList));
|
||||
return jpaRepository.exists(AccessController.Operation.UPDATE, combinedSpecification);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -21,6 +20,7 @@ import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||
import org.eclipse.hawkbit.repository.RepositoryConstants;
|
||||
import org.eclipse.hawkbit.repository.RepositoryProperties;
|
||||
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
|
||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
|
||||
@@ -31,7 +31,6 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionStatusRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
@@ -79,12 +78,11 @@ class OfflineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
||||
if (isMultiAssignmentsEnabled()) {
|
||||
mapper = ids -> targetRepository.findAll(TargetSpecifications.hasControllerIdIn(ids));
|
||||
} else {
|
||||
mapper = ids -> targetRepository.findAll(SpecificationsBuilder.combineWithAnd(
|
||||
Arrays.asList(TargetSpecifications.hasControllerIdAndAssignedDistributionSetIdNot(ids, setId),
|
||||
TargetSpecifications.notEqualToTargetUpdateStatus(TargetUpdateStatus.PENDING))));
|
||||
mapper = ids -> targetRepository.findAll(JpaManagementHelper.combineWithAnd(List.of(
|
||||
TargetSpecifications.hasControllerIdAndAssignedDistributionSetIdNot(ids, setId),
|
||||
TargetSpecifications.notEqualToTargetUpdateStatus(TargetUpdateStatus.PENDING))));
|
||||
}
|
||||
return ListUtils.partition(controllerIDs, Constants.MAX_ENTRIES_IN_STATEMENT).stream().map(mapper)
|
||||
.flatMap(List::stream).toList();
|
||||
return ListUtils.partition(controllerIDs, Constants.MAX_ENTRIES_IN_STATEMENT).stream().map(mapper).flatMap(List::stream).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -13,7 +13,6 @@ import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetTypeSpecification;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
@@ -27,7 +26,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
public interface TargetTypeRepository extends BaseEntityRepository<JpaTargetType> {
|
||||
|
||||
default List<JpaTargetType> findByDsType(@Param("id") final Long dsTypeId) {
|
||||
return findAll(Specification.where(TargetTypeSpecification.hasDsSetType(dsTypeId)));
|
||||
return findAll(TargetTypeSpecification.hasDsSetType(dsTypeId));
|
||||
}
|
||||
|
||||
@Modifying
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.specifications;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
/**
|
||||
* Helper class to easily combine {@link Specification} instances.
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class SpecificationsBuilder {
|
||||
|
||||
/**
|
||||
* Combine all given specification with and. The first specification is the
|
||||
* where clause.
|
||||
*
|
||||
* @param specList all specification which will combine
|
||||
* @return <null> if the given specification list is empty
|
||||
*/
|
||||
public static <T> Specification<T> combineWithAnd(final List<Specification<T>> specList) {
|
||||
if (specList.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
Specification<T> specs = specList.get(0);
|
||||
for (final Specification<T> specification : specList.subList(1, specList.size())) {
|
||||
specs = specs.and(specification);
|
||||
}
|
||||
return specs;
|
||||
}
|
||||
}
|
||||
@@ -56,6 +56,7 @@ import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetExcepti
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.exception.MultiAssignmentIsNotEnabledException;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction_;
|
||||
@@ -65,7 +66,6 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetSpecification;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate;
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
@@ -1354,9 +1354,9 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
List<? extends DistributionSet> allFoundDS = distributionSetManagement.findAll(PAGE).getContent();
|
||||
assertThat(allFoundDS).as("no ds should be founded").isEmpty();
|
||||
|
||||
assertThat(distributionSetRepository.findAll(SpecificationsBuilder.combineWithAnd(Arrays
|
||||
.asList(DistributionSetSpecification.isDeleted(true), DistributionSetSpecification.isCompleted(true))),
|
||||
PAGE).getContent()).as("wrong size of founded ds").hasSize(noOfDistributionSets);
|
||||
assertThat(distributionSetRepository.findAll(JpaManagementHelper.combineWithAnd(
|
||||
List.of(DistributionSetSpecification.isDeleted(true), DistributionSetSpecification.isCompleted(true))), PAGE).getContent())
|
||||
.as("wrong size of founded ds").hasSize(noOfDistributionSets);
|
||||
|
||||
IntStream.range(0, deploymentResult.getDistributionSets().size()).forEach(i -> testdataFactory.sendUpdateActionStatusToTargets(
|
||||
deploymentResult.getDeployedTargets(), Status.FINISHED, Collections.singletonList("blabla alles gut")));
|
||||
@@ -1367,9 +1367,9 @@ class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
// successfully and no activeAction is referring to created distribution sets
|
||||
allFoundDS = distributionSetManagement.findAll(pageRequest).getContent();
|
||||
assertThat(allFoundDS).as("no ds should be founded").isEmpty();
|
||||
assertThat(distributionSetRepository.findAll(SpecificationsBuilder.combineWithAnd(Arrays
|
||||
.asList(DistributionSetSpecification.isDeleted(true), DistributionSetSpecification.isCompleted(true))),
|
||||
PAGE).getContent()).as("wrong size of founded ds").hasSize(noOfDistributionSets);
|
||||
assertThat(distributionSetRepository.findAll(JpaManagementHelper.combineWithAnd(
|
||||
List.of(DistributionSetSpecification.isDeleted(true), DistributionSetSpecification.isCompleted(true))), PAGE).getContent())
|
||||
.as("wrong size of founded ds").hasSize(noOfDistributionSets);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.specifications;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Expression;
|
||||
import jakarta.persistence.criteria.Path;
|
||||
import jakarta.persistence.criteria.Predicate;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
/**
|
||||
* Feature: Unit Tests - Repository<br/>
|
||||
* Story: Specifications builder
|
||||
*/
|
||||
class SpecificationsBuilderTest {
|
||||
|
||||
/**
|
||||
* Test the combination of specs on an empty list which returns null
|
||||
*/
|
||||
@Test
|
||||
void combineWithAndEmptyList() {
|
||||
final List<Specification<Object>> specList = Collections.emptyList();
|
||||
assertThat(SpecificationsBuilder.combineWithAnd(specList)).isNull();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the combination of specs on an immutable list with one entry
|
||||
*/
|
||||
@Test
|
||||
void combineWithAndSingleImmutableList() {
|
||||
final Specification<Object> spec = (root, query, cb) -> cb.equal(root.get("field1"), "testValue");
|
||||
final List<Specification<Object>> specList = Collections.singletonList(spec);
|
||||
final Specification<Object> specifications = SpecificationsBuilder.combineWithAnd(specList);
|
||||
assertThat(specifications).as("Specifications").isNotNull();
|
||||
|
||||
// mocks to call toPredicate on specifications
|
||||
final CriteriaBuilder criteriaBuilder = mock(CriteriaBuilder.class);
|
||||
final Path field1 = mock(Path.class);
|
||||
final Predicate equalPredicate = mock(Predicate.class);
|
||||
final CriteriaQuery<Object[]> query = mock(CriteriaQuery.class);
|
||||
final Root<Object> root = mock(Root.class);
|
||||
|
||||
when(criteriaBuilder.equal(any(Expression.class), anyString())).thenReturn(equalPredicate);
|
||||
when(root.get("field1")).thenReturn(field1);
|
||||
|
||||
final Predicate predicate = specifications.toPredicate(root, query, criteriaBuilder);
|
||||
|
||||
assertThat(predicate).isEqualTo(equalPredicate);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the combination of specs on a list with multiple entries
|
||||
*/
|
||||
@Test
|
||||
void combineWithAndList() {
|
||||
final Specification<Object> spec1 = (root, query, cb) -> cb.equal(root.get("field1"), "testValue1");
|
||||
final Specification<Object> spec2 = (root, query, cb) -> cb.equal(root.get("field2"), "testValue2");
|
||||
|
||||
final List<Specification<Object>> specList = new ArrayList<>(2);
|
||||
specList.add(spec1);
|
||||
specList.add(spec2);
|
||||
|
||||
final Specification<Object> specifications = SpecificationsBuilder.combineWithAnd(specList);
|
||||
assertThat(specifications).as("Specifications").isNotNull();
|
||||
|
||||
// mocks to call toPredicate on specifications
|
||||
final CriteriaBuilder criteriaBuilder = mock(CriteriaBuilder.class);
|
||||
final Path field1 = mock(Path.class);
|
||||
final Path field2 = mock(Path.class);
|
||||
final Predicate equalPredicate1 = mock(Predicate.class);
|
||||
final Predicate equalPredicate2 = mock(Predicate.class);
|
||||
final Predicate combinedPredicate = mock(Predicate.class);
|
||||
final CriteriaQuery<Object[]> query = mock(CriteriaQuery.class);
|
||||
final Root<Object> root = mock(Root.class);
|
||||
|
||||
when(criteriaBuilder.equal(any(Path.class), eq("testValue1"))).thenReturn(equalPredicate1);
|
||||
when(criteriaBuilder.equal(any(Path.class), eq("testValue2"))).thenReturn(equalPredicate2);
|
||||
when(criteriaBuilder.and(equalPredicate1, equalPredicate2)).thenReturn(combinedPredicate);
|
||||
when(root.get("field1")).thenReturn(field1);
|
||||
when(root.get("field2")).thenReturn(field2);
|
||||
|
||||
final Predicate predicate = specifications.toPredicate(root, query, criteriaBuilder);
|
||||
|
||||
assertThat(predicate).as("Combined predicate").isEqualTo(combinedPredicate);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user