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:
Avgustin Marinov
2025-10-16 16:01:29 +03:00
committed by GitHub
parent 8da851a75a
commit 4b3c3cc870
7 changed files with 25 additions and 193 deletions

View File

@@ -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 };
}
}

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}
}