starting to sort out like/matches. Matches is the java regex related one. Like is the SQL related one. But the spring .net 'like' doesn't seem to be the same as the SQL doc I found for like...

git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@78 50f2f4bb-b051-0410-bef5-90022cba6387
This commit is contained in:
Andy Clement 2008-08-17 01:42:06 +00:00
parent c7be5092e1
commit de965b88ea
5 changed files with 30 additions and 17 deletions

View File

@ -23,4 +23,6 @@ Syntax
So 'l'.charAt(0) was required - wonder if we can build in a converter for a single length string to char? So 'l'.charAt(0) was required - wonder if we can build in a converter for a single length string to char?
Can't do that as equals take Object and so we don't know to do a cast in order to pass a char into equals Can't do that as equals take Object and so we don't know to do a cast in order to pass a char into equals
We certainly cannot do a cast (unless casts are added to the syntax). See MethodInvocationTest.testStringClass() We certainly cannot do a cast (unless casts are added to the syntax). See MethodInvocationTest.testStringClass()
- MATCHES is now the thing that takes a java regex. What does 'like' do? right now it is the SQL LIKE that supports
wildcards % and _. It has a poor implementation but I need to know whether to keep it in the language before
fixing that.

View File

@ -106,7 +106,9 @@ public enum SpelMessages {
Kind.ERROR, 1063, "A problem occurred whilst attempting to set the property ''{0}'': ''{1}''"), NOT_AN_INTEGER( Kind.ERROR, 1063, "A problem occurred whilst attempting to set the property ''{0}'': ''{1}''"), NOT_AN_INTEGER(
Kind.ERROR, 1064, "The value ''{0}'' cannot be parsed as an int"), NOT_A_LONG(Kind.ERROR, 1065, Kind.ERROR, 1064, "The value ''{0}'' cannot be parsed as an int"), NOT_A_LONG(Kind.ERROR, 1065,
"The value ''{0}'' cannot be parsed as a long"), PARSE_PROBLEM(Kind.ERROR, 1066, "The value ''{0}'' cannot be parsed as a long"), PARSE_PROBLEM(Kind.ERROR, 1066,
"Error occurred during expression parse: {0}"), ; "Error occurred during expression parse: {0}"), INVALID_FIRST_OPERAND_FOR_MATCHES_OPERATOR(Kind.ERROR,
1067, "First operand to matches operator must be a string. ''{0}'' is not"), INVALID_SECOND_OPERAND_FOR_MATCHES_OPERATOR(
Kind.ERROR, 1068, "Second operand to matches operator must be a string. ''{0}'' is not");
private Kind kind; private Kind kind;
private int code; private int code;

View File

@ -21,13 +21,14 @@ import java.util.regex.PatternSyntaxException;
import org.antlr.runtime.Token; import org.antlr.runtime.Token;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelException; import org.springframework.expression.spel.SpelException;
import org.springframework.expression.spel.SpelMessages; import org.springframework.expression.spel.SpelMessages;
import org.springframework.expression.spel.ExpressionState;
/** /**
* Implements the like operator. The expected operands for like are a string and a pattern (JDK regex). The operator * Implements the like operator. The like operator behaves the same as the SQL LIKE operator. The first operand is
* will return true if the string matches the regex. * compared against the expression supplied as the second operand. This expression supports two wildcards: % meaning any
* string of any length, and _ meaning any single character.
* *
* @author Andy Clement * @author Andy Clement
*/ */
@ -43,10 +44,10 @@ public class OperatorLike extends Operator {
} }
@Override @Override
public Object getValue(ExpressionState state) throws EvaluationException { public Boolean getValue(ExpressionState state) throws EvaluationException {
SpelNode leftOp = getLeftOperand(); SpelNode leftOp = getLeftOperand();
SpelNode rightOp = getRightOperand(); SpelNode rightOp = getRightOperand();
Object left = leftOp.getValue(state); Object left = leftOp.getValue(state, String.class);
Object right = getRightOperand().getValue(state); Object right = getRightOperand().getValue(state);
try { try {
if (!(left instanceof String)) { if (!(left instanceof String)) {
@ -57,12 +58,16 @@ public class OperatorLike extends Operator {
throw new SpelException(rightOp.getCharPositionInLine(), throw new SpelException(rightOp.getCharPositionInLine(),
SpelMessages.INVALID_SECOND_OPERAND_FOR_LIKE_OPERATOR, right); SpelMessages.INVALID_SECOND_OPERAND_FOR_LIKE_OPERATOR, right);
} }
Pattern pattern = Pattern.compile((String) right); // Translate that pattern to a java regex
// not really the best option, what if the right operand already had regex related chars in it?
String likePattern = (String) right;
likePattern = likePattern.replace('_', '.');
likePattern = likePattern.replaceAll("%", ".*");
Pattern pattern = Pattern.compile(likePattern);
Matcher matcher = pattern.matcher((String) left); Matcher matcher = pattern.matcher((String) left);
return matcher.matches(); return matcher.matches();
} catch (PatternSyntaxException pse) { } catch (PatternSyntaxException pse) {
throw new SpelException(rightOp.getCharPositionInLine(), pse, SpelMessages.INVALID_PATTERN, right); throw new SpelException(rightOp.getCharPositionInLine(), pse, SpelMessages.INVALID_PATTERN, right);
} }
} }
} }

View File

@ -58,11 +58,11 @@ public class OperatorMatches extends Operator {
try { try {
if (!(left instanceof String)) { if (!(left instanceof String)) {
throw new SpelException(leftOp.getCharPositionInLine(), throw new SpelException(leftOp.getCharPositionInLine(),
SpelMessages.INVALID_FIRST_OPERAND_FOR_LIKE_OPERATOR, left); SpelMessages.INVALID_FIRST_OPERAND_FOR_MATCHES_OPERATOR, left);
} }
if (!(right instanceof String)) { if (!(right instanceof String)) {
throw new SpelException(rightOp.getCharPositionInLine(), throw new SpelException(rightOp.getCharPositionInLine(),
SpelMessages.INVALID_SECOND_OPERAND_FOR_LIKE_OPERATOR, right); SpelMessages.INVALID_SECOND_OPERAND_FOR_MATCHES_OPERATOR, right);
} }
Pattern pattern = Pattern.compile((String) right); Pattern pattern = Pattern.compile((String) right);
Matcher matcher = pattern.matcher((String) left); Matcher matcher = pattern.matcher((String) left);

View File

@ -58,21 +58,25 @@ public class EvaluationTests extends ExpressionTestCase {
} }
public void testRelOperatorsLike01() { public void testRelOperatorsLike01() {
evaluate("'Abc' like '[A-Z]b.*'", "true", Boolean.class); evaluate("'Abc' like 'A%_'", "true", Boolean.class);
} // not the same as CSharp thing which matched '[A-Z]b*' }
public void testRelOperatorsLike02() { public void testRelOperatorsLike02() {
evaluate("'Abc' like '..'", "false", Boolean.class); evaluate("'Abc' like '..'", "false", Boolean.class);
} // was '?' }
public void testRelOperatorsLike03() { public void testRelOperatorsLike03() {
evaluateAndCheckError("7 like '.'", SpelMessages.INVALID_FIRST_OPERAND_FOR_LIKE_OPERATOR); evaluateAndCheckError("null like '.'", SpelMessages.INVALID_FIRST_OPERAND_FOR_LIKE_OPERATOR);
} }
public void testRelOperatorsLike04() { public void testRelOperatorsLike04() {
evaluateAndCheckError("'abc' like 2.0", SpelMessages.INVALID_SECOND_OPERAND_FOR_LIKE_OPERATOR); evaluateAndCheckError("'abc' like 2.0", SpelMessages.INVALID_SECOND_OPERAND_FOR_LIKE_OPERATOR);
} }
public void testRelOperatorsLike05() {
evaluate("27 like '__'", "true", Boolean.class); // conversion int>string
}
public void testRelOperatorsBetween01() { public void testRelOperatorsBetween01() {
evaluate("1 between {1, 5}", "true", Boolean.class); evaluate("1 between {1, 5}", "true", Boolean.class);
} }
@ -122,11 +126,11 @@ public class EvaluationTests extends ExpressionTestCase {
} }
public void testRelOperatorsMatches03() { public void testRelOperatorsMatches03() {
evaluateAndCheckError("null matches '^.*$'", SpelMessages.INVALID_FIRST_OPERAND_FOR_LIKE_OPERATOR, 0, null); evaluateAndCheckError("null matches '^.*$'", SpelMessages.INVALID_FIRST_OPERAND_FOR_MATCHES_OPERATOR, 0, null);
} }
public void testRelOperatorsMatches04() { public void testRelOperatorsMatches04() {
evaluateAndCheckError("'abc' matches null", SpelMessages.INVALID_SECOND_OPERAND_FOR_LIKE_OPERATOR, 14, null); evaluateAndCheckError("'abc' matches null", SpelMessages.INVALID_SECOND_OPERAND_FOR_MATCHES_OPERATOR, 14, null);
} }
public void testRelOperatorsMatches05() { public void testRelOperatorsMatches05() {