001/* 002 * Copyright 2002-2016 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.core; 018 019import java.util.Arrays; 020import java.util.Collections; 021import java.util.Comparator; 022import java.util.List; 023 024import org.springframework.util.ObjectUtils; 025 026/** 027 * {@link Comparator} implementation for {@link Ordered} objects, sorting 028 * by order value ascending, respectively by priority descending. 029 * 030 * <h3>Same Order Objects</h3> 031 * <p>Objects that have the same order value will be sorted with arbitrary 032 * ordering with respect to other objects with the same order value. 033 * 034 * <h3>Non-ordered Objects</h3> 035 * <p>Any object that does not provide its own order value is implicitly 036 * assigned a value of {@link Ordered#LOWEST_PRECEDENCE}, thus ending up 037 * at the end of a sorted collection in arbitrary order with respect to 038 * other objects with the same order value. 039 * 040 * @author Juergen Hoeller 041 * @author Sam Brannen 042 * @since 07.04.2003 043 * @see Ordered 044 * @see org.springframework.core.annotation.AnnotationAwareOrderComparator 045 * @see java.util.Collections#sort(java.util.List, java.util.Comparator) 046 * @see java.util.Arrays#sort(Object[], java.util.Comparator) 047 */ 048public class OrderComparator implements Comparator<Object> { 049 050 /** 051 * Shared default instance of {@code OrderComparator}. 052 */ 053 public static final OrderComparator INSTANCE = new OrderComparator(); 054 055 056 /** 057 * Build an adapted order comparator with the given source provider. 058 * @param sourceProvider the order source provider to use 059 * @return the adapted comparator 060 * @since 4.1 061 */ 062 public Comparator<Object> withSourceProvider(final OrderSourceProvider sourceProvider) { 063 return new Comparator<Object>() { 064 @Override 065 public int compare(Object o1, Object o2) { 066 return doCompare(o1, o2, sourceProvider); 067 } 068 }; 069 } 070 071 @Override 072 public int compare(Object o1, Object o2) { 073 return doCompare(o1, o2, null); 074 } 075 076 private int doCompare(Object o1, Object o2, OrderSourceProvider sourceProvider) { 077 boolean p1 = (o1 instanceof PriorityOrdered); 078 boolean p2 = (o2 instanceof PriorityOrdered); 079 if (p1 && !p2) { 080 return -1; 081 } 082 else if (p2 && !p1) { 083 return 1; 084 } 085 086 // Direct evaluation instead of Integer.compareTo to avoid unnecessary object creation. 087 int i1 = getOrder(o1, sourceProvider); 088 int i2 = getOrder(o2, sourceProvider); 089 return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0; 090 } 091 092 /** 093 * Determine the order value for the given object. 094 * <p>The default implementation checks against the given {@link OrderSourceProvider} 095 * using {@link #findOrder} and falls back to a regular {@link #getOrder(Object)} call. 096 * @param obj the object to check 097 * @return the order value, or {@code Ordered.LOWEST_PRECEDENCE} as fallback 098 */ 099 private int getOrder(Object obj, OrderSourceProvider sourceProvider) { 100 Integer order = null; 101 if (sourceProvider != null) { 102 Object orderSource = sourceProvider.getOrderSource(obj); 103 if (orderSource != null && orderSource.getClass().isArray()) { 104 Object[] sources = ObjectUtils.toObjectArray(orderSource); 105 for (Object source : sources) { 106 order = findOrder(source); 107 if (order != null) { 108 break; 109 } 110 } 111 } 112 else { 113 order = findOrder(orderSource); 114 } 115 } 116 return (order != null ? order : getOrder(obj)); 117 } 118 119 /** 120 * Determine the order value for the given object. 121 * <p>The default implementation checks against the {@link Ordered} interface 122 * through delegating to {@link #findOrder}. Can be overridden in subclasses. 123 * @param obj the object to check 124 * @return the order value, or {@code Ordered.LOWEST_PRECEDENCE} as fallback 125 */ 126 protected int getOrder(Object obj) { 127 Integer order = findOrder(obj); 128 return (order != null ? order : Ordered.LOWEST_PRECEDENCE); 129 } 130 131 /** 132 * Find an order value indicated by the given object. 133 * <p>The default implementation checks against the {@link Ordered} interface. 134 * Can be overridden in subclasses. 135 * @param obj the object to check 136 * @return the order value, or {@code null} if none found 137 */ 138 protected Integer findOrder(Object obj) { 139 return (obj instanceof Ordered ? ((Ordered) obj).getOrder() : null); 140 } 141 142 /** 143 * Determine a priority value for the given object, if any. 144 * <p>The default implementation always returns {@code null}. 145 * Subclasses may override this to give specific kinds of values a 146 * 'priority' characteristic, in addition to their 'order' semantics. 147 * A priority indicates that it may be used for selecting one object over 148 * another, in addition to serving for ordering purposes in a list/array. 149 * @param obj the object to check 150 * @return the priority value, or {@code null} if none 151 * @since 4.1 152 */ 153 public Integer getPriority(Object obj) { 154 return null; 155 } 156 157 158 /** 159 * Sort the given List with a default OrderComparator. 160 * <p>Optimized to skip sorting for lists with size 0 or 1, 161 * in order to avoid unnecessary array extraction. 162 * @param list the List to sort 163 * @see java.util.Collections#sort(java.util.List, java.util.Comparator) 164 */ 165 public static void sort(List<?> list) { 166 if (list.size() > 1) { 167 Collections.sort(list, INSTANCE); 168 } 169 } 170 171 /** 172 * Sort the given array with a default OrderComparator. 173 * <p>Optimized to skip sorting for lists with size 0 or 1, 174 * in order to avoid unnecessary array extraction. 175 * @param array the array to sort 176 * @see java.util.Arrays#sort(Object[], java.util.Comparator) 177 */ 178 public static void sort(Object[] array) { 179 if (array.length > 1) { 180 Arrays.sort(array, INSTANCE); 181 } 182 } 183 184 /** 185 * Sort the given array or List with a default OrderComparator, 186 * if necessary. Simply skips sorting when given any other value. 187 * <p>Optimized to skip sorting for lists with size 0 or 1, 188 * in order to avoid unnecessary array extraction. 189 * @param value the array or List to sort 190 * @see java.util.Arrays#sort(Object[], java.util.Comparator) 191 */ 192 public static void sortIfNecessary(Object value) { 193 if (value instanceof Object[]) { 194 sort((Object[]) value); 195 } 196 else if (value instanceof List) { 197 sort((List<?>) value); 198 } 199 } 200 201 202 /** 203 * Strategy interface to provide an order source for a given object. 204 * @since 4.1 205 */ 206 public interface OrderSourceProvider { 207 208 /** 209 * Return an order source for the specified object, i.e. an object that 210 * should be checked for an order value as a replacement to the given object. 211 * <p>Can also be an array of order source objects. 212 * <p>If the returned object does not indicate any order, the comparator 213 * will fall back to checking the original object. 214 * @param obj the object to find an order source for 215 * @return the order source for that object, or {@code null} if none found 216 */ 217 Object getOrderSource(Object obj); 218 } 219 220}