Skip to content

Commit

Permalink
Polish
Browse files Browse the repository at this point in the history
  • Loading branch information
bclozel committed Nov 25, 2021
1 parent d178eaf commit fab9abd
Show file tree
Hide file tree
Showing 7 changed files with 220 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.spel.CodeFlow;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import org.springframework.util.NumberUtils;
import org.springframework.util.ObjectUtils;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public boolean canCompare(@Nullable Object left, @Nullable Object right) {
return true;
}
if (left instanceof Comparable && right instanceof Comparable) {
Class<?> ancestor = ClassUtils.determineCommonAncestor(left.getClass(), right.getClass());
Class<?> ancestor = ClassUtils.determineCommonAncestor(left.getClass(), right.getClass());
return ancestor != null && Comparable.class.isAssignableFrom(ancestor);
}
return false;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,13 @@
import org.junit.jupiter.api.Test;

import org.springframework.expression.EvaluationException;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.TypeComparator;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.expression.spel.support.StandardTypeComparator;
import org.springframework.lang.Nullable;

import static org.assertj.core.api.Assertions.assertThat;

Expand All @@ -32,7 +37,7 @@
* @author Andy Clement
* @author Giovanni Dall'Oglio Risso
*/
class DefaultComparatorUnitTests {
public class ComparatorTests {

@Test
void testPrimitives() throws EvaluationException {
Expand Down Expand Up @@ -120,4 +125,30 @@ void testCanCompare() throws EvaluationException {
assertThat(comparator.canCompare(String.class,3)).isFalse();
}

@Test
public void customComparatorWorksWithEquality() {
final StandardEvaluationContext ctx = new StandardEvaluationContext();
ctx.setTypeComparator(customComparator);

ExpressionParser parser = new SpelExpressionParser();
Expression expr = parser.parseExpression("'1' == 1");

assertThat(expr.getValue(ctx, Boolean.class)).isTrue();

}

// A silly comparator declaring everything to be equal
private TypeComparator customComparator = new TypeComparator() {
@Override
public boolean canCompare(@Nullable Object firstObject, @Nullable Object secondObject) {
return true;
}

@Override
public int compare(@Nullable Object firstObject, @Nullable Object secondObject) throws EvaluationException {
return 0;
}

};

}
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ void testEqual() {
evaluate("'abc' == new java.lang.StringBuilder('abc')", true, Boolean.class);
evaluate("'abc' == 'def'", false, Boolean.class);
evaluate("'abc' == null", false, Boolean.class);
evaluate("new org.springframework.expression.spel.OperatorTests$SubComparable() == new org.springframework.expression.spel.OperatorTests$OtherSubComparable()", true, Boolean.class);
evaluate("new org.springframework.expression.spel.OperatorTests$SubComparable(0) == new org.springframework.expression.spel.OperatorTests$OtherSubComparable(0)", true, Boolean.class);
evaluate("new org.springframework.expression.spel.OperatorTests$SubComparable(1) < new org.springframework.expression.spel.OperatorTests$OtherSubComparable(2)", true, Boolean.class);
evaluate("new org.springframework.expression.spel.OperatorTests$SubComparable(2) > new org.springframework.expression.spel.OperatorTests$OtherSubComparable(1)", true, Boolean.class);

evaluate("3 eq 5", false, Boolean.class);
evaluate("5 eQ 3", false, Boolean.class);
Expand Down Expand Up @@ -621,18 +623,40 @@ private Operator findOperator(SpelNode node) {

public static class BaseComparable implements Comparable<BaseComparable> {

private int id;

public BaseComparable() {
this.id = 0;
}

public BaseComparable(int id) {
this.id = id;
}

@Override
public int compareTo(BaseComparable other) {
return 0;
return this.id - other.id;
}
}


public static class SubComparable extends BaseComparable {
public SubComparable() {
}

public SubComparable(int id) {
super(id);
}
}


public static class OtherSubComparable extends BaseComparable {
public OtherSubComparable() {
}

public OtherSubComparable(int id) {
super(id);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/*
* Copyright 2002-2021 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
*
* https://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.springframework.expression.spel;

import java.math.BigDecimal;

import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.Test;

import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypeComparator;
import org.springframework.expression.spel.support.StandardTypeComparator;

import static org.assertj.core.api.Assertions.assertThat;

/**
* Unit tests for type comparison
*
* @author Andy Clement
* @author Giovanni Dall'Oglio Risso
*/
public class StandardTypeComparatorTests {

@Test
void testPrimitives() throws EvaluationException {
TypeComparator comparator = new StandardTypeComparator();
// primitive int
assertThat(comparator.compare(1, 2)).isNegative();
assertThat(comparator.compare(1, 1)).isZero();
assertThat(comparator.compare(2, 1)).isPositive();

assertThat(comparator.compare(1.0d, 2)).isNegative();
assertThat(comparator.compare(1.0d, 1)).isZero();
assertThat(comparator.compare(2.0d, 1)).isPositive();

assertThat(comparator.compare(1.0f, 2)).isNegative();
assertThat(comparator.compare(1.0f, 1)).isZero();
assertThat(comparator.compare(2.0f, 1)).isPositive();

assertThat(comparator.compare(1L, 2)).isNegative();
assertThat(comparator.compare(1L, 1)).isZero();
assertThat(comparator.compare(2L, 1)).isPositive();

assertThat(comparator.compare(1, 2L)).isNegative();
assertThat(comparator.compare(1, 1L)).isZero();
assertThat(comparator.compare(2, 1L)).isPositive();

assertThat(comparator.compare(1L, 2L)).isNegative();
assertThat(comparator.compare(1L, 1L)).isZero();
assertThat(comparator.compare(2L, 1L)).isPositive();
}

@Test
void testNonPrimitiveNumbers() throws EvaluationException {
TypeComparator comparator = new StandardTypeComparator();

BigDecimal bdOne = new BigDecimal("1");
BigDecimal bdTwo = new BigDecimal("2");

assertThat(comparator.compare(bdOne, bdTwo)).isNegative();
assertThat(comparator.compare(bdOne, new BigDecimal("1"))).isZero();
assertThat(comparator.compare(bdTwo, bdOne)).isPositive();

assertThat(comparator.compare(1, bdTwo)).isNegative();
assertThat(comparator.compare(1, bdOne)).isZero();
assertThat(comparator.compare(2, bdOne)).isPositive();

assertThat(comparator.compare(1.0d, bdTwo)).isNegative();
assertThat(comparator.compare(1.0d, bdOne)).isZero();
assertThat(comparator.compare(2.0d, bdOne)).isPositive();

assertThat(comparator.compare(1.0f, bdTwo)).isNegative();
assertThat(comparator.compare(1.0f, bdOne)).isZero();
assertThat(comparator.compare(2.0f, bdOne)).isPositive();

assertThat(comparator.compare(1L, bdTwo)).isNegative();
assertThat(comparator.compare(1L, bdOne)).isZero();
assertThat(comparator.compare(2L, bdOne)).isPositive();

}

@Test
void testNulls() throws EvaluationException {
TypeComparator comparator = new StandardTypeComparator();
assertThat(comparator.compare(null, "abc")).isNegative();
assertThat(comparator.compare(null, null)).isZero();
assertThat(comparator.compare("abc", null)).isPositive();
}

@Test
void testObjects() throws EvaluationException {
TypeComparator comparator = new StandardTypeComparator();
assertThat(comparator.compare("a", "a")).isZero();
assertThat(comparator.compare("a", "b")).isNegative();
assertThat(comparator.compare("b", "a")).isPositive();
}

@Test
void testCanCompare() throws EvaluationException {
TypeComparator comparator = new StandardTypeComparator();
assertThat(comparator.canCompare(null, 1)).isTrue();
assertThat(comparator.canCompare(1, null)).isTrue();

assertThat(comparator.canCompare(2, 1)).isTrue();
assertThat(comparator.canCompare("abc", "def")).isTrue();
assertThat(comparator.canCompare("abc", 3)).isFalse();
assertThat(comparator.canCompare(String.class, 3)).isFalse();
}

@Test
public void shouldUseCustomComparator() {
TypeComparator comparator = new StandardTypeComparator();
ComparableType t1 = new ComparableType(1);
ComparableType t2 = new ComparableType(2);

assertThat(comparator.canCompare(t1, 2)).isFalse();
assertThat(comparator.canCompare(t1, t2)).isTrue();
assertThat(comparator.compare(t1, t1)).isZero();
assertThat(comparator.compare(t1, t2)).isNegative();
assertThat(comparator.compare(t2, t1)).isPositive();
}

static class ComparableType implements Comparable<ComparableType> {

private final int id;

public ComparableType(int id) {
this.id = id;
}

@Override
public int compareTo(@NotNull ComparableType other) {
return this.id - other.id;
}

}

}
11 changes: 9 additions & 2 deletions src/docs/asciidoc/core/core-expressions.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1052,8 +1052,9 @@ The Spring Expression Language supports the following kinds of operators:
==== Relational Operators

The relational operators (equal, not equal, less than, less than or equal, greater than,
and greater than or equal) are supported by using standard operator notation. The
following listing shows a few examples of operators:
and greater than or equal) are supported by using standard operator notation.
These operators work on `Number` types as well as types implementing `Comparable`.
The following listing shows a few examples of operators:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
Expand All @@ -1066,6 +1067,9 @@ following listing shows a few examples of operators:
// evaluates to true
boolean trueValue = parser.parseExpression("'black' < 'block'").getValue(Boolean.class);
// uses CustomValue:::compareTo
boolean trueValue = parser.parseExpression("new CustomValue(1) < new CustomValue(2)").getValue(Boolean.class);
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
Expand All @@ -1078,6 +1082,9 @@ following listing shows a few examples of operators:
// evaluates to true
val trueValue = parser.parseExpression("'black' < 'block'").getValue(Boolean::class.java)
// uses CustomValue:::compareTo
val trueValue = parser.parseExpression("new CustomValue(1) < new CustomValue(2)").getValue(Boolean::class.java);
----

[NOTE]
Expand Down

0 comments on commit fab9abd

Please sign in to comment.