ComparatorBuilder.java
/*
* Copyright 2019-2022 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
*
* http://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.bremersee.comparator;
import java.util.Collection;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import org.bremersee.comparator.model.SortOrder;
import org.bremersee.comparator.model.SortOrders;
/**
* The comparator builder.
*
* @author Christian Bremer
*/
public interface ComparatorBuilder {
/**
* Creates a new comparator builder.
*
* @return the new comparator builder
*/
static ComparatorBuilder newInstance() {
return new DefaultComparatorBuilder();
}
/**
* Adds the given comparator to this builder.
*
* @param comparator the comparator (can be {@code null} - then no comparator is added)
* @return the comparator builder
*/
ComparatorBuilder add(Comparator<?> comparator);
/**
* Adds a default comparator for the given field (the value of the field must be comparable).
*
* @param field the field
* @return the comparator builder
*/
default ComparatorBuilder add(String field) {
return add(field, true, true, false);
}
/**
* Adds the given comparator for the given field name or path to this builder.
*
* @param field the field name or path (can be {@code null})
* @param comparator the comparator (can be {@code null} - then no comparator is added)
* @return the comparator builder
*/
default ComparatorBuilder add(String field, Comparator<?> comparator) {
return add(field, null, comparator);
}
/**
* Adds the given comparator for the given field name or path to this builder. A custom value
* extractor can be specified.
*
* @param field the field name or path (can be {@code null})
* @param valueExtractor the value extractor (can be {@code null})
* @param comparator the comparator (can be {@code null} - then no comparator is added)
* @return the comparator builder
*/
default ComparatorBuilder add(
String field,
ValueExtractor valueExtractor,
Comparator<?> comparator) {
return Optional.ofNullable(comparator)
.map(c -> add(new DelegatingComparator(field, valueExtractor, c)))
.orElse(this);
}
/**
* Creates and adds a value comparator for the given field name or path to this builder.
*
* @param field the field name or path (can be {@code null})
* @param asc {@code true} for an ascending order, {@code false} for a descending order
* @param ignoreCase {@code true} for a case-insensitive order, {@code false} for a
* case-sensitive order
* @param nullIsFirst specifies the order of {@code null} values
* @return the comparator builder
*/
default ComparatorBuilder add(
String field,
boolean asc,
boolean ignoreCase,
boolean nullIsFirst) {
return add(field, asc, ignoreCase, nullIsFirst, null);
}
/**
* Creates and adds a value comparator for the given field name or path to this builder. A custom
* value extractor can be specified.
*
* @param field the field name or path (can be {@code null})
* @param asc {@code true} for an ascending order, {@code false} for a descending order
* @param ignoreCase {@code true} for a case insensitive order, {@code false} for a case
* sensitive order
* @param nullIsFirst specifies the order of {@code null} values
* @param valueExtractor the value extractor (can be {@code null})
* @return the comparator builder
*/
default ComparatorBuilder add(
String field,
boolean asc,
boolean ignoreCase,
boolean nullIsFirst,
ValueExtractor valueExtractor) {
return add(new ValueComparator(field, asc, ignoreCase, nullIsFirst, valueExtractor));
}
/**
* Creates and adds a value comparator for the given field ordering description.
*
* @param field the field ordering description (can be {@code null})
* @return the comparator builder
*/
default ComparatorBuilder add(SortOrder field) {
return add(field, null);
}
/**
* Creates and adds a value comparator for the given field ordering description. A custom value
* extractor can be specified.
*
* @param field the field ordering description (can be {@code null})
* @param valueExtractor the value extractor (can be {@code null})
* @return the comparator builder
*/
default ComparatorBuilder add(SortOrder field, ValueExtractor valueExtractor) {
return Optional.ofNullable(field)
.map(sortOrder -> add(
sortOrder.getField(),
sortOrder.isAsc(),
sortOrder.isIgnoreCase(),
sortOrder.isNullIsFirst(),
valueExtractor))
.orElse(this);
}
/**
* Creates and adds value comparators for the given field ordering descriptions.
*
* @param sortOrders the ordering descriptions (can be {@code null} - no comparator will be
* added)
* @return the comparator builder
*/
default ComparatorBuilder addAll(Collection<? extends SortOrder> sortOrders) {
return addAll(sortOrders, (ValueExtractor) null);
}
/**
* Creates and adds value comparators for the given field ordering descriptions. A custom value
* extractor can be specified.
*
* @param sortOrders the ordering descriptions (can be {@code null} - no comparator will be
* added)
* @param valueExtractor the value extractor (can be {@code null})
* @return the comparator builder
*/
default ComparatorBuilder addAll(
Collection<? extends SortOrder> sortOrders,
ValueExtractor valueExtractor) {
Optional.ofNullable(sortOrders)
.ifPresent(orders -> orders.stream()
.filter(Objects::nonNull)
.forEach(sortOrder -> add(sortOrder, valueExtractor)));
return this;
}
/**
* Adds comparators for the given sortOrders ordering descriptions.
*
* @param sortOrders the ordering descriptions (can be {@code null} - no comparator will be
* added)
* @param comparatorFunction the comparator function
* @return the comparator builder
*/
default ComparatorBuilder addAll(
Collection<? extends SortOrder> sortOrders,
Function<SortOrder, Comparator<?>> comparatorFunction) {
Optional.ofNullable(sortOrders)
.ifPresent(orders -> orders.stream()
.filter(Objects::nonNull)
.forEach(sortOrder -> add(comparatorFunction.apply(sortOrder))));
return this;
}
/**
* Creates and adds value comparators for the given field ordering descriptions.
*
* @param sortOrders the ordering descriptions (can be {@code null} - no comparator will
* be added)
* @return the comparator builder
*/
default ComparatorBuilder addAll(SortOrders sortOrders) {
return Optional.ofNullable(sortOrders)
.map(orders -> addAll(orders.getSortOrders()))
.orElse(this);
}
/**
* Creates and adds value comparators for the given field ordering descriptions. A custom value
* extractor can be specified.
*
* @param sortOrders the ordering descriptions (can be {@code null} - no comparator will
* be added)
* @param valueExtractor the value extractor (can be {@code null})
* @return the comparator builder
*/
default ComparatorBuilder addAll(
SortOrders sortOrders,
ValueExtractor valueExtractor) {
return Optional.ofNullable(sortOrders)
.map(orders -> addAll(orders.getSortOrders(), valueExtractor))
.orElse(this);
}
/**
* Add all comparator builder.
*
* @param sortOrders the sort orders
* @param comparatorFunction the comparator function
* @return the comparator builder
*/
default ComparatorBuilder addAll(
SortOrders sortOrders,
Function<SortOrder, Comparator<?>> comparatorFunction) {
return Optional.ofNullable(sortOrders)
.map(orders -> addAll(orders.getSortOrders(), comparatorFunction))
.orElse(this);
}
/**
* Build comparator.
*
* @param <T> the type parameter
* @return the comparator
*/
<T> Comparator<T> build();
/**
* The default comparator builder.
*/
class DefaultComparatorBuilder implements ComparatorBuilder {
@SuppressWarnings("rawtypes")
private final List<Comparator> comparatorChain = new LinkedList<>();
@Override
public ComparatorBuilder add(Comparator<?> comparator) {
Optional.ofNullable(comparator)
.ifPresent(comparatorChain::add);
return this;
}
@Override
public <T> Comparator<T> build() {
//noinspection unchecked
return (Comparator<T>) new ComparatorChain(comparatorChain);
}
}
}