001
002 /*
003 * Copyright (C) 2011 Archie L. Cobbs. All rights reserved.
004 *
005 * $Id: SortedValidator.java 144 2011-10-13 22:31:52Z archie.cobbs $
006 */
007
008 package org.dellroad.stuff.validation;
009
010 import java.util.Arrays;
011 import java.util.Collection;
012 import java.util.Comparator;
013 import java.util.Map;
014
015 import javax.validation.ConstraintValidatorContext;
016
017 /**
018 * Validator for the @{@link Sorted} constraint.
019 *
020 * @see Sorted
021 */
022 public class SortedValidator extends AbstractValidator<Sorted, Object> {
023
024 @Override
025 @SuppressWarnings("unchecked")
026 public boolean isValid(Object value, ConstraintValidatorContext context) {
027
028 // Ignore null values
029 if (value == null)
030 return true;
031
032 // Value must be an array, collection or map
033 Iterable<?> iterable;
034 if (value instanceof Object[])
035 iterable = Arrays.asList((Object[])value);
036 else if (value instanceof Collection)
037 iterable = (Collection<?>)value;
038 else if (value instanceof Map)
039 iterable = ((Map<?, ?>)value).keySet();
040 else {
041 this.setViolation(context, "@Sorted constraint only applies to non-primitive arrays, collections and maps");
042 return false;
043 }
044
045 // Get comparator
046 Comparator comparator;
047 if (this.annotation.comparator() == Comparator.class) {
048 comparator = new Comparator() {
049 @Override
050 public int compare(Object x, Object y) {
051 return ((Comparable)x).compareTo(y);
052 }
053 };
054 } else {
055 try {
056 comparator = this.annotation.comparator().newInstance();
057 } catch (Exception e) {
058 this.setViolation(context, "Cannot instantiate comparator for @Sorted constraint: " + e);
059 return false;
060 }
061 }
062
063 // Check sorted-ness
064 Object prev = null;
065 int index = -1;
066 for (Object next : iterable) {
067 index++;
068 if (prev == null) {
069 prev = next;
070 continue;
071 }
072 if (next == null)
073 continue;
074 int diff;
075 try {
076 diff = comparator.compare(prev, next);
077 } catch (ClassCastException e) {
078 this.setViolation(context, "@Sorted constraint only applies to Comparable elements: " + e);
079 return false;
080 }
081 if (diff > 0 || (this.annotation.strict() && diff == 0)) {
082 this.setViolation(context, "elements are not properly sorted (mis-ordered at index " + index + ")");
083 return false;
084 }
085 }
086
087 // Done
088 return true;
089 }
090 }
091