SortOrders.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.model;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlElementRef;
import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlTransient;
import jakarta.xml.bind.annotation.XmlType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.StringTokenizer;
import java.util.stream.Collectors;
import lombok.EqualsAndHashCode;
/**
* The list of sort orders.
*
* @author Christian Bremer
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "sortOrders")
@XmlType(name = "sortOrdersType")
@JsonIgnoreProperties(ignoreUnknown = true)
@Schema(description = "A list of sort orders.")
@EqualsAndHashCode
public class SortOrders {
@Schema(description = "The list of sort orders.")
@XmlElementRef
private final List<SortOrder> sortOrders = new ArrayList<>();
/**
* Instantiates an empty list of sort orders.
*/
protected SortOrders() {
}
/**
* Instantiates a new unmodifiable list of sort orders.
*
* @param sortOrders the sort orders
*/
@JsonCreator
public SortOrders(@JsonProperty("sortOrders") Collection<? extends SortOrder> sortOrders) {
if (sortOrders != null) {
this.sortOrders.addAll(sortOrders);
}
}
/**
* Gets the unmodifiable list of sort orders.
*
* @return the list of sort orders
*/
public List<SortOrder> getSortOrders() {
return Collections.unmodifiableList(sortOrders);
}
/**
* Checks whether the list of sort orders is empty or not.
*
* @return {@code true} if the list of sort orders is empty, otherwise {@code false}
*/
@XmlTransient
@JsonIgnore
public boolean isEmpty() {
return sortOrders.isEmpty();
}
/**
* Checks whether this sort orders contains any entries. If there are entries, this is sorted,
* otherwise it is unsorted.
*
* @return {@code true} if the list of sort orders is not empty (aka sorted), otherwise
* {@code false}
*/
@XmlTransient
@JsonIgnore
public boolean isSorted() {
return !isEmpty();
}
/**
* Checks whether this sort orders contains any entries. If there are no entries, this is
* unsorted, otherwise it is sorted.
*
* @return {@code true} if the list of sort orders is empty (aka unsorted), otherwise
* {@code false}
*/
@XmlTransient
@JsonIgnore
public boolean isUnsorted() {
return !isSorted();
}
/**
* Creates the sort orders text of this ordering descriptions.
*
* <p>The syntax of the ordering description is
* <pre>
* fieldNameOrPath0,asc,ignoreCase,nullIsFirst;fieldNameOrPath1,asc,ignoreCase,nullIsFirst
* </pre>
*
* <p>For example
* <pre>
* room.number,asc,true,false;person.lastName,asc,true,false;person.firstName,asc,true,false
* </pre>
*
* @return the sort orders text
*/
@JsonIgnore
@XmlTransient
public String getSortOrdersText() {
return getSortOrdersText(null);
}
/**
* Creates the sort orders text of this ordering descriptions.
*
* <p>The syntax of the ordering description is
* <pre>
* fieldNameOrPath0,asc,ignoreCase,nullIsFirst;fieldNameOrPath1,asc,ignoreCase,nullIsFirst
* </pre>
*
* <p>For example
* <pre>
* room.number,asc,true,false;person.lastName,asc,true,false;person.firstName,asc,true,false
* </pre>
*
* @return the sort orders text
* @deprecated Use {@link #getSortOrdersText()} instead.
*/
@Deprecated
public String toSortOrdersText() {
return getSortOrdersText();
}
/**
* Creates the sort orders text of this ordering descriptions.
*
* <p>The syntax of the ordering description is
* <pre>
* fieldNameOrPath0,asc,ignoreCase,nullIsFirst;fieldNameOrPath1,asc,ignoreCase,nullIsFirst
* </pre>
*
* <p>The separators (',') and (';') and the values of {@code direction}, {@code case-handling}
* and {@code null-handling} depend on the given {@link SortOrdersTextProperties}.
*
* <p>For example with default properties:
* <pre>
* room.number,asc,true,false;person.lastName,asc,true,false;person.firstName,asc,true,false
* </pre>
*
* @param properties the properties
* @return the sort orders text
*/
public String getSortOrdersText(SortOrdersTextProperties properties) {
SortOrdersTextProperties props = Objects.requireNonNullElse(properties,
SortOrdersTextProperties.defaults());
return sortOrders.stream()
.map(sortOrder -> sortOrder.getSortOrderText(props))
.collect(Collectors.joining(props.getSortOrderSeparator()));
}
/**
* Creates the sort orders text of this ordering descriptions.
*
* <p>The syntax of the ordering description is
* <pre>
* fieldNameOrPath0,asc,ignoreCase,nullIsFirst;fieldNameOrPath1,asc,ignoreCase,nullIsFirst
* </pre>
*
* <p>The separators (',') and (';') and the values of {@code direction}, {@code case-handling}
* and {@code null-handling} depend on the given {@link SortOrdersTextProperties}.
*
* <p>For example with default properties:
* <pre>
* room.number,asc,true,false;person.lastName,asc,true,false;person.firstName,asc,true,false
* </pre>
*
* @param properties the properties
* @return the sort orders text
* @deprecated Use {@link #getSortOrdersText(SortOrdersTextProperties)} instead.
*/
@Deprecated
public String toSortOrdersText(SortOrdersTextProperties properties) {
return getSortOrdersText(properties);
}
@Override
public String toString() {
return getSortOrdersText();
}
/**
* From sort orders text.
*
* @param source the sort orders text
* @return the sort orders
*/
public static SortOrders fromSortOrdersText(String source) {
return fromSortOrdersText(source, SortOrdersTextProperties.defaults());
}
/**
* From sort orders text.
*
* @param source the sort orders text
* @param properties the properties
* @return the sort orders
*/
public static SortOrders fromSortOrdersText(String source, SortOrdersTextProperties properties) {
return Optional.ofNullable(source)
.map(text -> {
SortOrdersTextProperties props = Objects
.requireNonNullElse(properties, SortOrdersTextProperties.defaults());
List<SortOrder> sortOrders = new ArrayList<>();
StringTokenizer tokenizer = new StringTokenizer(text, props.getSortOrderSeparator());
while (tokenizer.hasMoreTokens()) {
sortOrders.add(SortOrder.fromSortOrderText(tokenizer.nextToken(), props));
}
return new SortOrders(sortOrders);
})
.orElseGet(SortOrders::new);
}
/**
* Creates new sort orders with the given orders.
*
* @param sortOrders the sort orders
* @return the sort orders
*/
public static SortOrders by(SortOrder... sortOrders) {
return Optional.ofNullable(sortOrders)
.map(so -> new SortOrders(Arrays.asList(so)))
.orElseGet(SortOrders::new);
}
}