in endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/ComparisonFilter.java [238:342]
private boolean evaluate(Object left, Object right) {
/*
* For numbers, the apply(…) method inherited from parent class will delegate to specialized methods like
* applyAsDouble(…). All implementations of those specialized methods in ComparisonFilter return integer,
* so call to intValue() will not cause information lost.
*/
if (left instanceof Number && right instanceof Number) {
final Number r = apply((Number) left, (Number) right);
if (r != null) return r.intValue() != 0;
}
/*
* For legacy java.util.Date, the compareTo(…) method is consistent only for dates of the same class.
* Otherwise A.compareTo(B) and B.compareTo(A) are inconsistent if one object is a java.util.Date and
* the other object is a java.sql.Timestamp. In such case, we compare the dates as java.time objects.
*/
if (left instanceof Date && right instanceof Date) {
if (left.getClass() == right.getClass()) {
return fromCompareTo(((Date) left).compareTo((Date) right));
}
left = fromLegacy((Date) left);
right = fromLegacy((Date) right);
}
/*
* Temporal objects have complex conversion rules. We take Instant as the most accurate and unambiguous type.
* So if at least one value is an Instant, try to unconditionally promote the other value to an Instant too.
* This conversion will fail if the other object has some undefined fields; for example java.sql.Date has no
* time fields (we do not assume that the values of those fields are zero).
*
* OffsetTime and OffsetDateTime are final classes that do not implement a java.time.chrono interface.
* Note that OffsetDateTime is convertible into OffsetTime by dropping the date fields, but we do not
* (for now) perform comparisons that would ignore the date fields of an operand.
*/
if (left instanceof Temporal || right instanceof Temporal) { // Use || because an operand may be Date.
if (left instanceof Instant) {
final Instant t = toInstant(right);
if (t != null) return fromCompareTo(((Instant) left).compareTo(t));
} else if (right instanceof Instant) {
final Instant t = toInstant(left);
if (t != null) return fromCompareTo(t.compareTo((Instant) right));
} else if (left instanceof OffsetDateTime) {
final OffsetDateTime t = toOffsetDateTime(right);
if (t != null) return compare((OffsetDateTime) left, t);
} else if (right instanceof OffsetDateTime) {
final OffsetDateTime t = toOffsetDateTime(left);
if (t != null) return compare(t, (OffsetDateTime) right);
} else if (left instanceof OffsetTime && right instanceof OffsetTime) {
return compare((OffsetTime) left, (OffsetTime) right);
}
/*
* Comparisons of temporal objects implementing java.time.chrono interfaces. We need to check the most
* complete types first. If the type are different, we reduce to the type of the less smallest operand.
* For example if an operand is a date+time and the other operand is only a date, then the time fields
* will be ignored and a warning will be reported.
*/
if (left instanceof ChronoLocalDateTime<?>) {
final ChronoLocalDateTime<?> t = toLocalDateTime(right);
if (t != null) return compare((ChronoLocalDateTime<?>) left, t);
} else if (right instanceof ChronoLocalDateTime<?>) {
final ChronoLocalDateTime<?> t = toLocalDateTime(left);
if (t != null) return compare(t, (ChronoLocalDateTime<?>) right);
}
if (left instanceof ChronoLocalDate) {
final ChronoLocalDate t = toLocalDate(right);
if (t != null) return compare((ChronoLocalDate) left, t);
} else if (right instanceof ChronoLocalDate) {
final ChronoLocalDate t = toLocalDate(left);
if (t != null) return compare(t, (ChronoLocalDate) right);
}
if (left instanceof LocalTime) {
final LocalTime t = toLocalTime(right);
if (t != null) return fromCompareTo(((LocalTime) left).compareTo(t));
} else if (right instanceof LocalTime) {
final LocalTime t = toLocalTime(left);
if (t != null) return fromCompareTo(t.compareTo((LocalTime) right));
}
}
/*
* Test character strings only after all specialized types have been tested. The intent is that if an
* object implements both CharSequence and a specialized interface, they have been compared as value
* objects before to be compared as strings.
*/
if (left instanceof CharSequence || right instanceof CharSequence) { // Really ||, not &&.
final String s1 = left.toString();
final String s2 = right.toString();
final int result;
if (isMatchingCase) {
result = s1.compareTo(s2);
} else {
result = s1.compareToIgnoreCase(s2); // TODO: use Collator for taking locale in account.
}
return fromCompareTo(result);
}
/*
* Comparison using `compareTo` method should be last because it does not take in account
* the `isMatchingCase` flag and because the semantic is different than < or > comparator
* for numbers and dates.
*/
if (left.getClass() == right.getClass() && (left instanceof Comparable<?>)) {
@SuppressWarnings("unchecked")
final int result = ((Comparable) left).compareTo(right);
return fromCompareTo(result);
}
// TODO: report a warning for non-comparable objects.
return false;
}