/* * Copyright 2002-2017 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 * * http://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.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import org.junit.Test; import org.springframework.asm.MethodVisitor; import org.springframework.expression.AccessException; import org.springframework.expression.EvaluationContext; import org.springframework.expression.Expression; import org.springframework.expression.TypedValue; import org.springframework.expression.spel.ast.CompoundExpression; import org.springframework.expression.spel.ast.OpLT; import org.springframework.expression.spel.ast.SpelNodeImpl; import org.springframework.expression.spel.ast.Ternary; import org.springframework.expression.spel.standard.SpelCompiler; import org.springframework.expression.spel.standard.SpelExpression; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.expression.spel.testdata.PersonInOtherPackage; import static org.junit.Assert.*; /** * Checks the behaviour of the SpelCompiler. * This should cover compilation all compiled node types. * * @author Andy Clement * @since 4.1 */ public class SpelCompilationCoverageTests extends AbstractExpressionTests { /* * Further TODOs for compilation: * * - OpMinus with a single literal operand could be treated as a negative literal. Will save a * pointless loading of 0 and then a subtract instruction in code gen. * - allow other accessors/resolvers to participate in compilation and create their own code * - A TypeReference followed by (what ends up as) a static method invocation can really skip * code gen for the TypeReference since once that is used to locate the method it is not * used again. * - The opEq implementation is quite basic. It will compare numbers of the same type (allowing * them to be their boxed or unboxed variants) or compare object references. It does not * compile expressions where numbers are of different types or when objects implement * Comparable. * * Compiled nodes: * * TypeReference * OperatorInstanceOf * StringLiteral * NullLiteral * RealLiteral * IntLiteral * LongLiteral * BooleanLiteral * FloatLiteral * OpOr * OpAnd * OperatorNot * Ternary * Elvis * VariableReference * OpLt * OpLe * OpGt * OpGe * OpEq * OpNe * OpPlus * OpMinus * OpMultiply * OpDivide * MethodReference * PropertyOrFieldReference * Indexer * CompoundExpression * ConstructorReference * FunctionReference * InlineList * OpModulus * * Not yet compiled (some may never need to be): * Assign * BeanReference * Identifier * OpDec * OpBetween * OpMatches * OpPower * OpInc * Projection * QualifiedId * Selection */ private Expression expression; private SpelNodeImpl ast; @Test public void typeReference() throws Exception { expression = parse("T(String)"); assertEquals(String.class, expression.getValue()); assertCanCompile(expression); assertEquals(String.class, expression.getValue()); expression = parse("T(java.io.IOException)"); assertEquals(IOException.class, expression.getValue()); assertCanCompile(expression); assertEquals(IOException.class, expression.getValue()); expression = parse("T(java.io.IOException[])"); assertEquals(IOException[].class, expression.getValue()); assertCanCompile(expression); assertEquals(IOException[].class, expression.getValue()); expression = parse("T(int[][])"); assertEquals(int[][].class, expression.getValue()); assertCanCompile(expression); assertEquals(int[][].class, expression.getValue()); expression = parse("T(int)"); assertEquals(Integer.TYPE, expression.getValue()); assertCanCompile(expression); assertEquals(Integer.TYPE, expression.getValue()); expression = parse("T(byte)"); assertEquals(Byte.TYPE, expression.getValue()); assertCanCompile(expression); assertEquals(Byte.TYPE, expression.getValue()); expression = parse("T(char)"); assertEquals(Character.TYPE, expression.getValue()); assertCanCompile(expression); assertEquals(Character.TYPE, expression.getValue()); expression = parse("T(short)"); assertEquals(Short.TYPE, expression.getValue()); assertCanCompile(expression); assertEquals(Short.TYPE, expression.getValue()); expression = parse("T(long)"); assertEquals(Long.TYPE, expression.getValue()); assertCanCompile(expression); assertEquals(Long.TYPE, expression.getValue()); expression = parse("T(float)"); assertEquals(Float.TYPE, expression.getValue()); assertCanCompile(expression); assertEquals(Float.TYPE, expression.getValue()); expression = parse("T(double)"); assertEquals(Double.TYPE, expression.getValue()); assertCanCompile(expression); assertEquals(Double.TYPE, expression.getValue()); expression = parse("T(boolean)"); assertEquals(Boolean.TYPE, expression.getValue()); assertCanCompile(expression); assertEquals(Boolean.TYPE, expression.getValue()); expression = parse("T(Missing)"); assertGetValueFail(expression); assertCantCompile(expression); } @SuppressWarnings("unchecked") @Test public void operatorInstanceOf() throws Exception { expression = parse("'xyz' instanceof T(String)"); assertEquals(true, expression.getValue()); assertCanCompile(expression); assertEquals(true, expression.getValue()); expression = parse("'xyz' instanceof T(Integer)"); assertEquals(false, expression.getValue()); assertCanCompile(expression); assertEquals(false, expression.getValue()); List<String> list = new ArrayList<>(); expression = parse("#root instanceof T(java.util.List)"); assertEquals(true, expression.getValue(list)); assertCanCompile(expression); assertEquals(true, expression.getValue(list)); List<String>[] arrayOfLists = new List[] {new ArrayList<String>()}; expression = parse("#root instanceof T(java.util.List[])"); assertEquals(true, expression.getValue(arrayOfLists)); assertCanCompile(expression); assertEquals(true, expression.getValue(arrayOfLists)); int[] intArray = new int[] {1,2,3}; expression = parse("#root instanceof T(int[])"); assertEquals(true, expression.getValue(intArray)); assertCanCompile(expression); assertEquals(true, expression.getValue(intArray)); String root = null; expression = parse("#root instanceof T(Integer)"); assertEquals(false, expression.getValue(root)); assertCanCompile(expression); assertEquals(false, expression.getValue(root)); // root still null expression = parse("#root instanceof T(java.lang.Object)"); assertEquals(false, expression.getValue(root)); assertCanCompile(expression); assertEquals(false, expression.getValue(root)); root = "howdy!"; expression = parse("#root instanceof T(java.lang.Object)"); assertEquals(true, expression.getValue(root)); assertCanCompile(expression); assertEquals(true, expression.getValue(root)); } @Test public void operatorInstanceOf_SPR14250() throws Exception { // primitive left operand - should get boxed, return true expression = parse("3 instanceof T(Integer)"); assertEquals(true, expression.getValue()); assertCanCompile(expression); assertEquals(true, expression.getValue()); // primitive left operand - should get boxed, return false expression = parse("3 instanceof T(String)"); assertEquals(false, expression.getValue()); assertCanCompile(expression); assertEquals(false, expression.getValue()); // double slot left operand - should get boxed, return false expression = parse("3.0d instanceof T(Integer)"); assertEquals(false, expression.getValue()); assertCanCompile(expression); assertEquals(false, expression.getValue()); // double slot left operand - should get boxed, return true expression = parse("3.0d instanceof T(Double)"); assertEquals(true, expression.getValue()); assertCanCompile(expression); assertEquals(true, expression.getValue()); // Only when the right hand operand is a direct type reference // will it be compilable. StandardEvaluationContext ctx = new StandardEvaluationContext(); ctx.setVariable("foo", String.class); expression = parse("3 instanceof #foo"); assertEquals(false, expression.getValue(ctx)); assertCantCompile(expression); // use of primitive as type for instanceof check - compilable // but always false expression = parse("3 instanceof T(int)"); assertEquals(false, expression.getValue()); assertCanCompile(expression); assertEquals(false, expression.getValue()); expression = parse("3 instanceof T(long)"); assertEquals(false, expression.getValue()); assertCanCompile(expression); assertEquals(false, expression.getValue()); } @Test public void stringLiteral() throws Exception { expression = parser.parseExpression("'abcde'"); assertEquals("abcde", expression.getValue(new TestClass1(), String.class)); assertCanCompile(expression); String resultC = expression.getValue(new TestClass1(), String.class); assertEquals("abcde", resultC); assertEquals("abcde", expression.getValue(String.class)); assertEquals("abcde", expression.getValue()); assertEquals("abcde", expression.getValue(new StandardEvaluationContext())); expression = parser.parseExpression("\"abcde\""); assertCanCompile(expression); assertEquals("abcde", expression.getValue(String.class)); } @Test public void nullLiteral() throws Exception { expression = parser.parseExpression("null"); Object resultI = expression.getValue(new TestClass1(), Object.class); assertCanCompile(expression); Object resultC = expression.getValue(new TestClass1(), Object.class); assertEquals(null, resultI); assertEquals(null, resultC); assertEquals(null, resultC); } @Test public void realLiteral() throws Exception { expression = parser.parseExpression("3.4d"); double resultI = expression.getValue(new TestClass1(), Double.TYPE); assertCanCompile(expression); double resultC = expression.getValue(new TestClass1(), Double.TYPE); assertEquals(3.4d, resultI,0.1d); assertEquals(3.4d, resultC,0.1d); assertEquals(3.4d, expression.getValue()); } @Test public void repeatedCompilation() throws Exception { // Verifying that after a number of compilations, the classloaders // used to load the compiled expressions are discarded/replaced. // See SpelCompiler.loadClass() Field f = SpelExpression.class.getDeclaredField("compiledAst"); Set<Object> classloadersUsed = new HashSet<>(); for (int i=0;i<1500;i++) { // 1500 is greater than SpelCompiler.CLASSES_DEFINED_LIMIT expression = parser.parseExpression("4 + 5"); assertEquals(9, (int)expression.getValue(Integer.class)); assertCanCompile(expression); f.setAccessible(true); CompiledExpression cEx = (CompiledExpression)f.get(expression); classloadersUsed.add(cEx.getClass().getClassLoader()); assertEquals(9, (int)expression.getValue(Integer.class)); } assertTrue(classloadersUsed.size() > 1); } @SuppressWarnings("rawtypes") @Test public void inlineList() throws Exception { expression = parser.parseExpression("'abcde'.substring({1,3,4}[0])"); Object o = expression.getValue(); assertEquals("bcde",o); assertCanCompile(expression); o = expression.getValue(); assertEquals("bcde", o); expression = parser.parseExpression("{'abc','def'}"); List<?> l = (List) expression.getValue(); assertEquals("[abc, def]", l.toString()); assertCanCompile(expression); l = (List) expression.getValue(); assertEquals("[abc, def]", l.toString()); expression = parser.parseExpression("{'abc','def'}[0]"); o = expression.getValue(); assertEquals("abc",o); assertCanCompile(expression); o = expression.getValue(); assertEquals("abc", o); expression = parser.parseExpression("{'abcde','ijklm'}[0].substring({1,3,4}[0])"); o = expression.getValue(); assertEquals("bcde",o); assertCanCompile(expression); o = expression.getValue(); assertEquals("bcde", o); expression = parser.parseExpression("{'abcde','ijklm'}[0].substring({1,3,4}[0],{1,3,4}[1])"); o = expression.getValue(); assertEquals("bc",o); assertCanCompile(expression); o = expression.getValue(); assertEquals("bc", o); } @SuppressWarnings("rawtypes") @Test public void nestedInlineLists() throws Exception { Object o = null; expression = parser.parseExpression("{{1,2,3},{4,5,6},{7,8,9}}"); o = expression.getValue(); assertEquals("[[1, 2, 3], [4, 5, 6], [7, 8, 9]]",o.toString()); assertCanCompile(expression); o = expression.getValue(); assertEquals("[[1, 2, 3], [4, 5, 6], [7, 8, 9]]",o.toString()); expression = parser.parseExpression("{{1,2,3},{4,5,6},{7,8,9}}.toString()"); o = expression.getValue(); assertEquals("[[1, 2, 3], [4, 5, 6], [7, 8, 9]]",o); assertCanCompile(expression); o = expression.getValue(); assertEquals("[[1, 2, 3], [4, 5, 6], [7, 8, 9]]",o); expression = parser.parseExpression("{{1,2,3},{4,5,6},{7,8,9}}[1][0]"); o = expression.getValue(); assertEquals(4,o); assertCanCompile(expression); o = expression.getValue(); assertEquals(4,o); expression = parser.parseExpression("{{1,2,3},'abc',{7,8,9}}[1]"); o = expression.getValue(); assertEquals("abc",o); assertCanCompile(expression); o = expression.getValue(); assertEquals("abc",o); expression = parser.parseExpression("'abcde'.substring({{1,3},1,3,4}[0][1])"); o = expression.getValue(); assertEquals("de",o); assertCanCompile(expression); o = expression.getValue(); assertEquals("de", o); expression = parser.parseExpression("'abcde'.substring({{1,3},1,3,4}[1])"); o = expression.getValue(); assertEquals("bcde",o); assertCanCompile(expression); o = expression.getValue(); assertEquals("bcde", o); expression = parser.parseExpression("{'abc',{'def','ghi'}}"); List<?> l = (List) expression.getValue(); assertEquals("[abc, [def, ghi]]", l.toString()); assertCanCompile(expression); l = (List) expression.getValue(); assertEquals("[abc, [def, ghi]]", l.toString()); expression = parser.parseExpression("{'abcde',{'ijklm','nopqr'}}[0].substring({1,3,4}[0])"); o = expression.getValue(); assertEquals("bcde",o); assertCanCompile(expression); o = expression.getValue(); assertEquals("bcde", o); expression = parser.parseExpression("{'abcde',{'ijklm','nopqr'}}[1][0].substring({1,3,4}[0])"); o = expression.getValue(); assertEquals("jklm",o); assertCanCompile(expression); o = expression.getValue(); assertEquals("jklm", o); expression = parser.parseExpression("{'abcde',{'ijklm','nopqr'}}[1][1].substring({1,3,4}[0],{1,3,4}[1])"); o = expression.getValue(); assertEquals("op",o); assertCanCompile(expression); o = expression.getValue(); assertEquals("op", o); } @Test public void intLiteral() throws Exception { expression = parser.parseExpression("42"); int resultI = expression.getValue(new TestClass1(), Integer.TYPE); assertCanCompile(expression); int resultC = expression.getValue(new TestClass1(), Integer.TYPE); assertEquals(42, resultI); assertEquals(42, resultC); expression = parser.parseExpression("T(Integer).valueOf(42)"); expression.getValue(Integer.class); assertCanCompile(expression); assertEquals(new Integer(42), expression.getValue(null, Integer.class)); // Code gen is different for -1 .. 6 because there are bytecode instructions specifically for those // values // Not an int literal but an opminus with one operand: // expression = parser.parseExpression("-1"); // assertCanCompile(expression); // assertEquals(-1, expression.getValue()); expression = parser.parseExpression("0"); assertCanCompile(expression); assertEquals(0, expression.getValue()); expression = parser.parseExpression("2"); assertCanCompile(expression); assertEquals(2, expression.getValue()); expression = parser.parseExpression("7"); assertCanCompile(expression); assertEquals(7, expression.getValue()); } @Test public void longLiteral() throws Exception { expression = parser.parseExpression("99L"); long resultI = expression.getValue(new TestClass1(), Long.TYPE); assertCanCompile(expression); long resultC = expression.getValue(new TestClass1(), Long.TYPE); assertEquals(99L, resultI); assertEquals(99L, resultC); } @Test public void booleanLiteral() throws Exception { expression = parser.parseExpression("true"); boolean resultI = expression.getValue(1, Boolean.TYPE); assertEquals(true, resultI); assertTrue(SpelCompiler.compile(expression)); boolean resultC = expression.getValue(1, Boolean.TYPE); assertEquals(true, resultC); expression = parser.parseExpression("false"); resultI = expression.getValue(1, Boolean.TYPE); assertEquals(false, resultI); assertTrue(SpelCompiler.compile(expression)); resultC = expression.getValue(1, Boolean.TYPE); assertEquals(false, resultC); } @Test public void floatLiteral() throws Exception { expression = parser.parseExpression("3.4f"); float resultI = expression.getValue(new TestClass1(), Float.TYPE); assertCanCompile(expression); float resultC = expression.getValue(new TestClass1(), Float.TYPE); assertEquals(3.4f, resultI,0.1f); assertEquals(3.4f, resultC,0.1f); assertEquals(3.4f, expression.getValue()); } @Test public void opOr() throws Exception { Expression expression = parser.parseExpression("false or false"); boolean resultI = expression.getValue(1, Boolean.TYPE); SpelCompiler.compile(expression); boolean resultC = expression.getValue(1, Boolean.TYPE); assertEquals(false, resultI); assertEquals(false, resultC); expression = parser.parseExpression("false or true"); resultI = expression.getValue(1, Boolean.TYPE); assertCanCompile(expression); resultC = expression.getValue(1, Boolean.TYPE); assertEquals(true, resultI); assertEquals(true, resultC); expression = parser.parseExpression("true or false"); resultI = expression.getValue(1, Boolean.TYPE); assertCanCompile(expression); resultC = expression.getValue(1, Boolean.TYPE); assertEquals(true, resultI); assertEquals(true, resultC); expression = parser.parseExpression("true or true"); resultI = expression.getValue(1, Boolean.TYPE); assertCanCompile(expression); resultC = expression.getValue(1, Boolean.TYPE); assertEquals(true, resultI); assertEquals(true, resultC); TestClass4 tc = new TestClass4(); expression = parser.parseExpression("getfalse() or gettrue()"); resultI = expression.getValue(tc, Boolean.TYPE); assertCanCompile(expression); resultC = expression.getValue(tc, Boolean.TYPE); assertEquals(true, resultI); assertEquals(true, resultC); // Can't compile this as we aren't going down the getfalse() branch in our evaluation expression = parser.parseExpression("gettrue() or getfalse()"); resultI = expression.getValue(tc, Boolean.TYPE); assertCantCompile(expression); expression = parser.parseExpression("getA() or getB()"); tc.a = true; tc.b = true; resultI = expression.getValue(tc, Boolean.TYPE); assertCantCompile(expression); // Haven't yet been into second branch tc.a = false; tc.b = true; resultI = expression.getValue(tc, Boolean.TYPE); assertCanCompile(expression); // Now been down both assertTrue(resultI); boolean b = false; expression = parse("#root or #root"); Object resultI2 = expression.getValue(b); assertCanCompile(expression); assertFalse((Boolean) resultI2); assertFalse((Boolean) expression.getValue(b)); } @Test public void opAnd() throws Exception { Expression expression = parser.parseExpression("false and false"); boolean resultI = expression.getValue(1, Boolean.TYPE); SpelCompiler.compile(expression); boolean resultC = expression.getValue(1, Boolean.TYPE); assertEquals(false, resultI); assertEquals(false, resultC); expression = parser.parseExpression("false and true"); resultI = expression.getValue(1, Boolean.TYPE); SpelCompiler.compile(expression); resultC = expression.getValue(1, Boolean.TYPE); assertEquals(false, resultI); assertEquals(false, resultC); expression = parser.parseExpression("true and false"); resultI = expression.getValue(1, Boolean.TYPE); SpelCompiler.compile(expression); resultC = expression.getValue(1, Boolean.TYPE); assertEquals(false, resultI); assertEquals(false, resultC); expression = parser.parseExpression("true and true"); resultI = expression.getValue(1, Boolean.TYPE); SpelCompiler.compile(expression); resultC = expression.getValue(1, Boolean.TYPE); assertEquals(true, resultI); assertEquals(true, resultC); TestClass4 tc = new TestClass4(); // Can't compile this as we aren't going down the gettrue() branch in our evaluation expression = parser.parseExpression("getfalse() and gettrue()"); resultI = expression.getValue(tc, Boolean.TYPE); assertCantCompile(expression); expression = parser.parseExpression("getA() and getB()"); tc.a = false; tc.b = false; resultI = expression.getValue(tc, Boolean.TYPE); assertCantCompile(expression); // Haven't yet been into second branch tc.a = true; tc.b = false; resultI = expression.getValue(tc, Boolean.TYPE); assertCanCompile(expression); // Now been down both assertFalse(resultI); tc.a = true; tc.b = true; resultI = expression.getValue(tc, Boolean.TYPE); assertTrue(resultI); boolean b = true; expression = parse("#root and #root"); Object resultI2 = expression.getValue(b); assertCanCompile(expression); assertTrue((Boolean) resultI2); assertTrue((Boolean) expression.getValue(b)); } @Test public void operatorNot() throws Exception { expression = parse("!true"); assertEquals(false, expression.getValue()); assertCanCompile(expression); assertEquals(false, expression.getValue()); expression = parse("!false"); assertEquals(true, expression.getValue()); assertCanCompile(expression); assertEquals(true, expression.getValue()); boolean b = true; expression = parse("!#root"); assertEquals(false, expression.getValue(b)); assertCanCompile(expression); assertEquals(false, expression.getValue(b)); b = false; expression = parse("!#root"); assertEquals(true, expression.getValue(b)); assertCanCompile(expression); assertEquals(true, expression.getValue(b)); } @Test public void ternary() throws Exception { Expression expression = parser.parseExpression("true?'a':'b'"); String resultI = expression.getValue(String.class); assertCanCompile(expression); String resultC = expression.getValue(String.class); assertEquals("a", resultI); assertEquals("a", resultC); expression = parser.parseExpression("false?'a':'b'"); resultI = expression.getValue(String.class); assertCanCompile(expression); resultC = expression.getValue(String.class); assertEquals("b", resultI); assertEquals("b", resultC); expression = parser.parseExpression("false?1:'b'"); // All literals so we can do this straight away assertCanCompile(expression); assertEquals("b", expression.getValue()); boolean root = true; expression = parser.parseExpression("(#root and true)?T(Integer).valueOf(1):T(Long).valueOf(3L)"); assertEquals(1, expression.getValue(root)); assertCantCompile(expression); // Have not gone down false branch root = false; assertEquals(3L, expression.getValue(root)); assertCanCompile(expression); assertEquals(3L, expression.getValue(root)); root = true; assertEquals(1, expression.getValue(root)); } @Test public void ternaryWithBooleanReturn() { // SPR-12271 expression = parser.parseExpression("T(Boolean).TRUE?'abc':'def'"); assertEquals("abc", expression.getValue()); assertCanCompile(expression); assertEquals("abc", expression.getValue()); expression = parser.parseExpression("T(Boolean).FALSE?'abc':'def'"); assertEquals("def", expression.getValue()); assertCanCompile(expression); assertEquals("def", expression.getValue()); } @Test public void elvis() throws Exception { Expression expression = parser.parseExpression("'a'?:'b'"); String resultI = expression.getValue(String.class); assertCanCompile(expression); String resultC = expression.getValue(String.class); assertEquals("a", resultI); assertEquals("a", resultC); expression = parser.parseExpression("null?:'a'"); resultI = expression.getValue(String.class); assertCanCompile(expression); resultC = expression.getValue(String.class); assertEquals("a", resultI); assertEquals("a", resultC); String s = "abc"; expression = parser.parseExpression("#root?:'b'"); assertCantCompile(expression); resultI = expression.getValue(s, String.class); assertEquals("abc", resultI); assertCanCompile(expression); } @Test public void variableReference_root() throws Exception { String s = "hello"; Expression expression = parser.parseExpression("#root"); String resultI = expression.getValue(s, String.class); assertCanCompile(expression); String resultC = expression.getValue(s, String.class); assertEquals(s, resultI); assertEquals(s, resultC); expression = parser.parseExpression("#root"); int i = (Integer) expression.getValue(42); assertEquals(42,i); assertCanCompile(expression); i = (Integer) expression.getValue(42); assertEquals(42,i); } public static String concat(String a, String b) { return a+b; } public static String join(String...strings) { StringBuilder buf = new StringBuilder(); for (String string: strings) { buf.append(string); } return buf.toString(); } @Test public void compiledExpressionShouldWorkWhenUsingCustomFunctionWithVarargs() throws Exception { StandardEvaluationContext context = null; // Here the target method takes Object... and we are passing a string expression = parser.parseExpression("#doFormat('hey %s', 'there')"); context = new StandardEvaluationContext(); context.registerFunction("doFormat", DelegatingStringFormat.class.getDeclaredMethod("format", String.class, Object[].class)); ((SpelExpression) expression).setEvaluationContext(context); assertEquals("hey there", expression.getValue(String.class)); assertTrue(((SpelNodeImpl) ((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals("hey there", expression.getValue(String.class)); expression = parser.parseExpression("#doFormat([0], 'there')"); context = new StandardEvaluationContext(new Object[] {"hey %s"}); context.registerFunction("doFormat", DelegatingStringFormat.class.getDeclaredMethod("format", String.class, Object[].class)); ((SpelExpression) expression).setEvaluationContext(context); assertEquals("hey there", expression.getValue(String.class)); assertTrue(((SpelNodeImpl) ((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals("hey there", expression.getValue(String.class)); expression = parser.parseExpression("#doFormat([0], #arg)"); context = new StandardEvaluationContext(new Object[] {"hey %s"}); context.registerFunction("doFormat", DelegatingStringFormat.class.getDeclaredMethod("format", String.class, Object[].class)); context.setVariable("arg", "there"); ((SpelExpression) expression).setEvaluationContext(context); assertEquals("hey there", expression.getValue(String.class)); assertTrue(((SpelNodeImpl) ((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals("hey there", expression.getValue(String.class)); } @Test public void functionReference() throws Exception { EvaluationContext ctx = new StandardEvaluationContext(); Method m = getClass().getDeclaredMethod("concat", String.class, String.class); ctx.setVariable("concat",m); expression = parser.parseExpression("#concat('a','b')"); assertEquals("ab", expression.getValue(ctx)); assertCanCompile(expression); assertEquals("ab", expression.getValue(ctx)); expression = parser.parseExpression("#concat(#concat('a','b'),'c').charAt(1)"); assertEquals('b', expression.getValue(ctx)); assertCanCompile(expression); assertEquals('b', expression.getValue(ctx)); expression = parser.parseExpression("#concat(#a,#b)"); ctx.setVariable("a", "foo"); ctx.setVariable("b", "bar"); assertEquals("foobar", expression.getValue(ctx)); assertCanCompile(expression); assertEquals("foobar", expression.getValue(ctx)); ctx.setVariable("b", "boo"); assertEquals("fooboo", expression.getValue(ctx)); m = Math.class.getDeclaredMethod("pow", Double.TYPE, Double.TYPE); ctx.setVariable("kapow",m); expression = parser.parseExpression("#kapow(2.0d,2.0d)"); assertEquals("4.0", expression.getValue(ctx).toString()); assertCanCompile(expression); assertEquals("4.0", expression.getValue(ctx).toString()); } // Confirms visibility of what is being called. @Test public void functionReferenceVisibility_SPR12359() throws Exception { StandardEvaluationContext context = new StandardEvaluationContext(new Object[] {"1"}); context.registerFunction("doCompare", SomeCompareMethod.class.getDeclaredMethod( "compare", Object.class, Object.class)); context.setVariable("arg", "2"); // type nor method are public expression = parser.parseExpression("#doCompare([0],#arg)"); assertEquals("-1", expression.getValue(context, Integer.class).toString()); assertCantCompile(expression); // type not public but method is context = new StandardEvaluationContext(new Object[] {"1"}); context.registerFunction("doCompare", SomeCompareMethod.class.getDeclaredMethod( "compare2", Object.class, Object.class)); context.setVariable("arg", "2"); expression = parser.parseExpression("#doCompare([0],#arg)"); assertEquals("-1", expression.getValue(context, Integer.class).toString()); assertCantCompile(expression); } @Test public void functionReferenceNonCompilableArguments_SPR12359() throws Exception { StandardEvaluationContext context = new StandardEvaluationContext(new Object[] {"1"}); context.registerFunction("negate", SomeCompareMethod2.class.getDeclaredMethod( "negate", Integer.TYPE)); context.setVariable("arg", "2"); int[] ints = new int[] {1,2,3}; context.setVariable("ints",ints); expression = parser.parseExpression("#negate(#ints.?[#this<2][0])"); assertEquals("-1", expression.getValue(context, Integer.class).toString()); // Selection isn't compilable. assertFalse(((SpelNodeImpl)((SpelExpression) expression).getAST()).isCompilable()); } @Test public void functionReferenceVarargs_SPR12359() throws Exception { StandardEvaluationContext context = new StandardEvaluationContext(); context.registerFunction("append", SomeCompareMethod2.class.getDeclaredMethod("append", String[].class)); context.registerFunction("append2", SomeCompareMethod2.class.getDeclaredMethod("append2", Object[].class)); context.registerFunction("append3", SomeCompareMethod2.class.getDeclaredMethod("append3", String[].class)); context.registerFunction("append4", SomeCompareMethod2.class.getDeclaredMethod("append4", String.class, String[].class)); context.registerFunction("appendChar", SomeCompareMethod2.class.getDeclaredMethod("appendChar", char[].class)); context.registerFunction("sum", SomeCompareMethod2.class.getDeclaredMethod("sum", int[].class)); context.registerFunction("sumDouble", SomeCompareMethod2.class.getDeclaredMethod("sumDouble", double[].class)); context.registerFunction("sumFloat", SomeCompareMethod2.class.getDeclaredMethod("sumFloat", float[].class)); context.setVariable("stringArray", new String[] {"x","y","z"}); context.setVariable("intArray", new int[] {5,6,9}); context.setVariable("doubleArray", new double[] {5.0d,6.0d,9.0d}); context.setVariable("floatArray", new float[] {5.0f,6.0f,9.0f}); expression = parser.parseExpression("#append('a','b','c')"); assertEquals("abc", expression.getValue(context).toString()); assertTrue(((SpelNodeImpl)((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals("abc", expression.getValue(context).toString()); expression = parser.parseExpression("#append('a')"); assertEquals("a", expression.getValue(context).toString()); assertTrue(((SpelNodeImpl)((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals("a", expression.getValue(context).toString()); expression = parser.parseExpression("#append()"); assertEquals("", expression.getValue(context).toString()); assertTrue(((SpelNodeImpl)((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals("", expression.getValue(context).toString()); expression = parser.parseExpression("#append(#stringArray)"); assertEquals("xyz", expression.getValue(context).toString()); assertTrue(((SpelNodeImpl)((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals("xyz", expression.getValue(context).toString()); // This is a methodreference invocation, to compare with functionreference expression = parser.parseExpression("append(#stringArray)"); assertEquals("xyz", expression.getValue(context,new SomeCompareMethod2()).toString()); assertTrue(((SpelNodeImpl)((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals("xyz", expression.getValue(context,new SomeCompareMethod2()).toString()); expression = parser.parseExpression("#append2('a','b','c')"); assertEquals("abc", expression.getValue(context).toString()); assertTrue(((SpelNodeImpl)((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals("abc", expression.getValue(context).toString()); expression = parser.parseExpression("append2('a','b')"); assertEquals("ab", expression.getValue(context, new SomeCompareMethod2()).toString()); assertTrue(((SpelNodeImpl)((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals("ab", expression.getValue(context, new SomeCompareMethod2()).toString()); expression = parser.parseExpression("#append2('a','b')"); assertEquals("ab", expression.getValue(context).toString()); assertTrue(((SpelNodeImpl)((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals("ab", expression.getValue(context).toString()); expression = parser.parseExpression("#append2()"); assertEquals("", expression.getValue(context).toString()); assertTrue(((SpelNodeImpl)((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals("", expression.getValue(context).toString()); expression = parser.parseExpression("#append3(#stringArray)"); assertEquals("xyz", expression.getValue(context, new SomeCompareMethod2()).toString()); assertTrue(((SpelNodeImpl)((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals("xyz", expression.getValue(context, new SomeCompareMethod2()).toString()); // TODO fails due to conversionservice handling of String[] to Object... // expression = parser.parseExpression("#append2(#stringArray)"); // assertEquals("xyz", expression.getValue(context).toString()); // assertTrue(((SpelNodeImpl)((SpelExpression) expression).getAST()).isCompilable()); // assertCanCompile(expression); // assertEquals("xyz", expression.getValue(context).toString()); expression = parser.parseExpression("#sum(1,2,3)"); assertEquals(6, expression.getValue(context)); assertTrue(((SpelNodeImpl)((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals(6, expression.getValue(context)); expression = parser.parseExpression("#sum(2)"); assertEquals(2, expression.getValue(context)); assertTrue(((SpelNodeImpl)((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals(2, expression.getValue(context)); expression = parser.parseExpression("#sum()"); assertEquals(0, expression.getValue(context)); assertTrue(((SpelNodeImpl)((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals(0, expression.getValue(context)); expression = parser.parseExpression("#sum(#intArray)"); assertEquals(20, expression.getValue(context)); assertTrue(((SpelNodeImpl)((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals(20, expression.getValue(context)); expression = parser.parseExpression("#sumDouble(1.0d,2.0d,3.0d)"); assertEquals(6, expression.getValue(context)); assertTrue(((SpelNodeImpl)((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals(6, expression.getValue(context)); expression = parser.parseExpression("#sumDouble(2.0d)"); assertEquals(2, expression.getValue(context)); assertTrue(((SpelNodeImpl)((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals(2, expression.getValue(context)); expression = parser.parseExpression("#sumDouble()"); assertEquals(0, expression.getValue(context)); assertTrue(((SpelNodeImpl)((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals(0, expression.getValue(context)); expression = parser.parseExpression("#sumDouble(#doubleArray)"); assertEquals(20, expression.getValue(context)); assertTrue(((SpelNodeImpl)((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals(20, expression.getValue(context)); expression = parser.parseExpression("#sumFloat(1.0f,2.0f,3.0f)"); assertEquals(6, expression.getValue(context)); assertTrue(((SpelNodeImpl)((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals(6, expression.getValue(context)); expression = parser.parseExpression("#sumFloat(2.0f)"); assertEquals(2, expression.getValue(context)); assertTrue(((SpelNodeImpl)((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals(2, expression.getValue(context)); expression = parser.parseExpression("#sumFloat()"); assertEquals(0, expression.getValue(context)); assertTrue(((SpelNodeImpl)((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals(0, expression.getValue(context)); expression = parser.parseExpression("#sumFloat(#floatArray)"); assertEquals(20, expression.getValue(context)); assertTrue(((SpelNodeImpl)((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals(20, expression.getValue(context)); expression = parser.parseExpression("#appendChar('abc'.charAt(0),'abc'.charAt(1))"); assertEquals("ab", expression.getValue(context)); assertTrue(((SpelNodeImpl)((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals("ab", expression.getValue(context)); expression = parser.parseExpression("#append4('a','b','c')"); assertEquals("a::bc", expression.getValue(context).toString()); assertTrue(((SpelNodeImpl)((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals("a::bc", expression.getValue(context).toString()); expression = parser.parseExpression("#append4('a','b')"); assertEquals("a::b", expression.getValue(context).toString()); assertTrue(((SpelNodeImpl)((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals("a::b", expression.getValue(context).toString()); expression = parser.parseExpression("#append4('a')"); assertEquals("a::", expression.getValue(context).toString()); assertTrue(((SpelNodeImpl)((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals("a::", expression.getValue(context).toString()); expression = parser.parseExpression("#append4('a',#stringArray)"); assertEquals("a::xyz", expression.getValue(context).toString()); assertTrue(((SpelNodeImpl)((SpelExpression) expression).getAST()).isCompilable()); assertCanCompile(expression); assertEquals("a::xyz", expression.getValue(context).toString()); } @Test public void functionReferenceVarargs() throws Exception { EvaluationContext ctx = new StandardEvaluationContext(); Method m = getClass().getDeclaredMethod("join", String[].class); ctx.setVariable("join", m); expression = parser.parseExpression("#join('a','b','c')"); assertEquals("abc", expression.getValue(ctx)); assertCanCompile(expression); assertEquals("abc", expression.getValue(ctx)); } @Test public void variableReference_userDefined() throws Exception { EvaluationContext ctx = new StandardEvaluationContext(); ctx.setVariable("target", "abc"); expression = parser.parseExpression("#target"); assertEquals("abc", expression.getValue(ctx)); assertCanCompile(expression); assertEquals("abc", expression.getValue(ctx)); ctx.setVariable("target", "123"); assertEquals("123", expression.getValue(ctx)); ctx.setVariable("target", 42); try { assertEquals(42, expression.getValue(ctx)); fail(); } catch (SpelEvaluationException see) { assertTrue(see.getCause() instanceof ClassCastException); } ctx.setVariable("target", "abc"); expression = parser.parseExpression("#target.charAt(0)"); assertEquals('a', expression.getValue(ctx)); assertCanCompile(expression); assertEquals('a', expression.getValue(ctx)); ctx.setVariable("target", "1"); assertEquals('1', expression.getValue(ctx)); ctx.setVariable("target", 42); try { assertEquals('4', expression.getValue(ctx)); fail(); } catch (SpelEvaluationException see) { assertTrue(see.getCause() instanceof ClassCastException); } } @Test public void opLt() throws Exception { expression = parse("3.0d < 4.0d"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("3446.0d < 1123.0d"); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("3 < 1"); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("2 < 4"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("3.0f < 1.0f"); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("1.0f < 5.0f"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("30L < 30L"); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("15L < 20L"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); // Differing types of number, not yet supported expression = parse("1 < 3.0d"); assertCantCompile(expression); expression = parse("T(Integer).valueOf(3) < 4"); assertTrue((Boolean) expression.getValue()); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("T(Integer).valueOf(3) < T(Integer).valueOf(3)"); assertFalse((Boolean) expression.getValue()); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("5 < T(Integer).valueOf(3)"); assertFalse((Boolean) expression.getValue()); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); } @Test public void opLe() throws Exception { expression = parse("3.0d <= 4.0d"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("3446.0d <= 1123.0d"); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("3446.0d <= 3446.0d"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("3 <= 1"); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("2 <= 4"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("3 <= 3"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("3.0f <= 1.0f"); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("1.0f <= 5.0f"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("2.0f <= 2.0f"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("30L <= 30L"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("15L <= 20L"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); // Differing types of number, not yet supported expression = parse("1 <= 3.0d"); assertCantCompile(expression); expression = parse("T(Integer).valueOf(3) <= 4"); assertTrue((Boolean) expression.getValue()); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("T(Integer).valueOf(3) <= T(Integer).valueOf(3)"); assertTrue((Boolean) expression.getValue()); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("5 <= T(Integer).valueOf(3)"); assertFalse((Boolean) expression.getValue()); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); } @Test public void opGt() throws Exception { expression = parse("3.0d > 4.0d"); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("3446.0d > 1123.0d"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("3 > 1"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("2 > 4"); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("3.0f > 1.0f"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("1.0f > 5.0f"); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("30L > 30L"); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("15L > 20L"); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); // Differing types of number, not yet supported expression = parse("1 > 3.0d"); assertCantCompile(expression); expression = parse("T(Integer).valueOf(3) > 4"); assertFalse((Boolean) expression.getValue()); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("T(Integer).valueOf(3) > T(Integer).valueOf(3)"); assertFalse((Boolean) expression.getValue()); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("5 > T(Integer).valueOf(3)"); assertTrue((Boolean) expression.getValue()); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); } @Test public void opGe() throws Exception { expression = parse("3.0d >= 4.0d"); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("3446.0d >= 1123.0d"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("3446.0d >= 3446.0d"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("3 >= 1"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("2 >= 4"); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("3 >= 3"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("3.0f >= 1.0f"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("1.0f >= 5.0f"); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("3.0f >= 3.0f"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("40L >= 30L"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("15L >= 20L"); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("30L >= 30L"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); // Differing types of number, not yet supported expression = parse("1 >= 3.0d"); assertCantCompile(expression); expression = parse("T(Integer).valueOf(3) >= 4"); assertFalse((Boolean) expression.getValue()); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("T(Integer).valueOf(3) >= T(Integer).valueOf(3)"); assertTrue((Boolean) expression.getValue()); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("5 >= T(Integer).valueOf(3)"); assertTrue((Boolean) expression.getValue()); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); } @Test public void opEq() throws Exception { String tvar = "35"; expression = parse("#root == 35"); assertFalse((Boolean) expression.getValue(tvar)); assertCanCompile(expression); assertFalse((Boolean) expression.getValue(tvar)); expression = parse("35 == #root"); expression.getValue(tvar); assertFalse((Boolean) expression.getValue(tvar)); assertCanCompile(expression); assertFalse((Boolean) expression.getValue(tvar)); TestClass7 tc7 = new TestClass7(); expression = parse("property == 'UK'"); assertTrue((Boolean) expression.getValue(tc7)); TestClass7.property = null; assertFalse((Boolean) expression.getValue(tc7)); assertCanCompile(expression); TestClass7.reset(); assertTrue((Boolean) expression.getValue(tc7)); TestClass7.property = "UK"; assertTrue((Boolean) expression.getValue(tc7)); TestClass7.reset(); TestClass7.property = null; assertFalse((Boolean) expression.getValue(tc7)); expression = parse("property == null"); assertTrue((Boolean) expression.getValue(tc7)); assertCanCompile(expression); assertTrue((Boolean) expression.getValue(tc7)); expression = parse("3.0d == 4.0d"); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("3446.0d == 3446.0d"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("3 == 1"); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("3 == 3"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("3.0f == 1.0f"); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("2.0f == 2.0f"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("30L == 30L"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("15L == 20L"); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); // number types are not the same expression = parse("1 == 3.0d"); assertCantCompile(expression); Double d = 3.0d; expression = parse("#root==3.0d"); assertTrue((Boolean) expression.getValue(d)); assertCanCompile(expression); assertTrue((Boolean) expression.getValue(d)); Integer i = 3; expression = parse("#root==3"); assertTrue((Boolean) expression.getValue(i)); assertCanCompile(expression); assertTrue((Boolean) expression.getValue(i)); Float f = 3.0f; expression = parse("#root==3.0f"); assertTrue((Boolean) expression.getValue(f)); assertCanCompile(expression); assertTrue((Boolean) expression.getValue(f)); long l = 300l; expression = parse("#root==300l"); assertTrue((Boolean) expression.getValue(l)); assertCanCompile(expression); assertTrue((Boolean) expression.getValue(l)); boolean b = true; expression = parse("#root==true"); assertTrue((Boolean) expression.getValue(b)); assertCanCompile(expression); assertTrue((Boolean) expression.getValue(b)); expression = parse("T(Integer).valueOf(3) == 4"); assertFalse((Boolean) expression.getValue()); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("T(Integer).valueOf(3) == T(Integer).valueOf(3)"); assertTrue((Boolean) expression.getValue()); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("5 == T(Integer).valueOf(3)"); assertFalse((Boolean) expression.getValue()); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("T(Float).valueOf(3.0f) == 4.0f"); assertFalse((Boolean) expression.getValue()); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("T(Float).valueOf(3.0f) == T(Float).valueOf(3.0f)"); assertTrue((Boolean) expression.getValue()); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("5.0f == T(Float).valueOf(3.0f)"); assertFalse((Boolean) expression.getValue()); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("T(Long).valueOf(3L) == 4L"); assertFalse((Boolean) expression.getValue()); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("T(Long).valueOf(3L) == T(Long).valueOf(3L)"); assertTrue((Boolean) expression.getValue()); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("5L == T(Long).valueOf(3L)"); assertFalse((Boolean) expression.getValue()); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("T(Double).valueOf(3.0d) == 4.0d"); assertFalse((Boolean) expression.getValue()); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("T(Double).valueOf(3.0d) == T(Double).valueOf(3.0d)"); assertTrue((Boolean) expression.getValue()); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("5.0d == T(Double).valueOf(3.0d)"); assertFalse((Boolean) expression.getValue()); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("false == true"); assertFalse((Boolean) expression.getValue()); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("T(Boolean).valueOf('true') == T(Boolean).valueOf('true')"); assertTrue((Boolean) expression.getValue()); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("T(Boolean).valueOf('true') == true"); assertTrue((Boolean) expression.getValue()); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("false == T(Boolean).valueOf('false')"); assertTrue((Boolean) expression.getValue()); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); } @Test public void opNe() throws Exception { expression = parse("3.0d != 4.0d"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("3446.0d != 3446.0d"); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("3 != 1"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("3 != 3"); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("3.0f != 1.0f"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("2.0f != 2.0f"); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("30L != 30L"); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("15L != 20L"); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); // not compatible number types expression = parse("1 != 3.0d"); assertCantCompile(expression); expression = parse("T(Integer).valueOf(3) != 4"); assertTrue((Boolean) expression.getValue()); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("T(Integer).valueOf(3) != T(Integer).valueOf(3)"); assertFalse((Boolean) expression.getValue()); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("5 != T(Integer).valueOf(3)"); assertTrue((Boolean) expression.getValue()); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("T(Float).valueOf(3.0f) != 4.0f"); assertTrue((Boolean) expression.getValue()); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("T(Float).valueOf(3.0f) != T(Float).valueOf(3.0f)"); assertFalse((Boolean) expression.getValue()); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("5.0f != T(Float).valueOf(3.0f)"); assertTrue((Boolean) expression.getValue()); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("T(Long).valueOf(3L) != 4L"); assertTrue((Boolean) expression.getValue()); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("T(Long).valueOf(3L) != T(Long).valueOf(3L)"); assertFalse((Boolean) expression.getValue()); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("5L != T(Long).valueOf(3L)"); assertTrue((Boolean) expression.getValue()); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("T(Double).valueOf(3.0d) == 4.0d"); assertFalse((Boolean) expression.getValue()); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("T(Double).valueOf(3.0d) == T(Double).valueOf(3.0d)"); assertTrue((Boolean) expression.getValue()); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("5.0d == T(Double).valueOf(3.0d)"); assertFalse((Boolean) expression.getValue()); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("false == true"); assertFalse((Boolean) expression.getValue()); assertCanCompile(expression); assertFalse((Boolean) expression.getValue()); expression = parse("T(Boolean).valueOf('true') == T(Boolean).valueOf('true')"); assertTrue((Boolean) expression.getValue()); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("T(Boolean).valueOf('true') == true"); assertTrue((Boolean) expression.getValue()); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); expression = parse("false == T(Boolean).valueOf('false')"); assertTrue((Boolean) expression.getValue()); assertCanCompile(expression); assertTrue((Boolean) expression.getValue()); } @Test public void opNe_SPR14863() throws Exception { SpelParserConfiguration configuration = new SpelParserConfiguration(SpelCompilerMode.MIXED, ClassLoader.getSystemClassLoader()); SpelExpressionParser parser = new SpelExpressionParser(configuration); Expression expression = parser.parseExpression("data['my-key'] != 'my-value'"); Map<String, String> data = new HashMap<>(); data.put("my-key", new String("my-value")); StandardEvaluationContext context = new StandardEvaluationContext(new MyContext(data)); assertFalse(expression.getValue(context, Boolean.class)); assertCanCompile(expression); ((SpelExpression) expression).compileExpression(); assertFalse(expression.getValue(context, Boolean.class)); List<String> ls = new ArrayList<String>(); ls.add(new String("foo")); context = new StandardEvaluationContext(ls); expression = parse("get(0) != 'foo'"); assertFalse(expression.getValue(context, Boolean.class)); assertCanCompile(expression); assertFalse(expression.getValue(context, Boolean.class)); ls.remove(0); ls.add("goo"); assertTrue(expression.getValue(context, Boolean.class)); } @Test public void opEq_SPR14863() throws Exception { // Exercise the comparator invocation code that runs in // equalityCheck() (called from interpreted and compiled code) expression = parser.parseExpression("#aa==#bb"); StandardEvaluationContext sec = new StandardEvaluationContext(); Apple aa = new Apple(1); Apple bb = new Apple(2); sec.setVariable("aa",aa); sec.setVariable("bb",bb); boolean b = expression.getValue(sec, Boolean.class); // Verify what the expression caused aa to be compared to assertEquals(bb,aa.gotComparedTo); assertFalse(b); bb.setValue(1); b = expression.getValue(sec, Boolean.class); assertEquals(bb,aa.gotComparedTo); assertTrue(b); assertCanCompile(expression); // Similar test with compiled expression aa = new Apple(99); bb = new Apple(100); sec.setVariable("aa",aa); sec.setVariable("bb",bb); b = expression.getValue(sec, Boolean.class); assertFalse(b); assertEquals(bb,aa.gotComparedTo); bb.setValue(99); b = expression.getValue(sec, Boolean.class); assertTrue(b); assertEquals(bb,aa.gotComparedTo); List<String> ls = new ArrayList<String>(); ls.add(new String("foo")); StandardEvaluationContext context = new StandardEvaluationContext(ls); expression = parse("get(0) == 'foo'"); assertTrue(expression.getValue(context, Boolean.class)); assertCanCompile(expression); assertTrue(expression.getValue(context, Boolean.class)); ls.remove(0); ls.add("goo"); assertFalse(expression.getValue(context, Boolean.class)); } @Test public void opPlus() throws Exception { expression = parse("2+2"); expression.getValue(); assertCanCompile(expression); assertEquals(4, expression.getValue()); expression = parse("2L+2L"); expression.getValue(); assertCanCompile(expression); assertEquals(4L, expression.getValue()); expression = parse("2.0f+2.0f"); expression.getValue(); assertCanCompile(expression); assertEquals(4.0f, expression.getValue()); expression = parse("3.0d+4.0d"); expression.getValue(); assertCanCompile(expression); assertEquals(7.0d, expression.getValue()); expression = parse("+1"); expression.getValue(); assertCanCompile(expression); assertEquals(1, expression.getValue()); expression = parse("+1L"); expression.getValue(); assertCanCompile(expression); assertEquals(1L, expression.getValue()); expression = parse("+1.5f"); expression.getValue(); assertCanCompile(expression); assertEquals(1.5f, expression.getValue()); expression = parse("+2.5d"); expression.getValue(); assertCanCompile(expression); assertEquals(2.5d, expression.getValue()); expression = parse("+T(Double).valueOf(2.5d)"); expression.getValue(); assertCanCompile(expression); assertEquals(2.5d, expression.getValue()); expression = parse("T(Integer).valueOf(2)+6"); assertEquals(8, expression.getValue()); assertCanCompile(expression); assertEquals(8, expression.getValue()); expression = parse("T(Integer).valueOf(1)+T(Integer).valueOf(3)"); assertEquals(4, expression.getValue()); assertCanCompile(expression); assertEquals(4, expression.getValue()); expression = parse("1+T(Integer).valueOf(3)"); assertEquals(4, expression.getValue()); assertCanCompile(expression); assertEquals(4, expression.getValue()); expression = parse("T(Float).valueOf(2.0f)+6"); assertEquals(8.0f, expression.getValue()); assertCanCompile(expression); assertEquals(8.0f, expression.getValue()); expression = parse("T(Float).valueOf(2.0f)+T(Float).valueOf(3.0f)"); assertEquals(5.0f, expression.getValue()); assertCanCompile(expression); assertEquals(5.0f, expression.getValue()); expression = parse("3L+T(Long).valueOf(4L)"); assertEquals(7L, expression.getValue()); assertCanCompile(expression); assertEquals(7L, expression.getValue()); expression = parse("T(Long).valueOf(2L)+6"); assertEquals(8L, expression.getValue()); assertCanCompile(expression); assertEquals(8L, expression.getValue()); expression = parse("T(Long).valueOf(2L)+T(Long).valueOf(3L)"); assertEquals(5L, expression.getValue()); assertCanCompile(expression); assertEquals(5L, expression.getValue()); expression = parse("1L+T(Long).valueOf(2L)"); assertEquals(3L, expression.getValue()); assertCanCompile(expression); assertEquals(3L, expression.getValue()); } @Test public void opDivide_mixedNumberTypes() throws Exception { PayloadX p = new PayloadX(); // This is what you had to do before the changes in order for it to compile: // expression = parse("(T(java.lang.Double).parseDouble(payload.valueI.toString()))/60D"); // right is a double checkCalc(p,"payload.valueSB/60D",2d); checkCalc(p,"payload.valueBB/60D",2d); checkCalc(p,"payload.valueFB/60D",2d); checkCalc(p,"payload.valueDB/60D",2d); checkCalc(p,"payload.valueJB/60D",2d); checkCalc(p,"payload.valueIB/60D",2d); checkCalc(p,"payload.valueS/60D",2d); checkCalc(p,"payload.valueB/60D",2d); checkCalc(p,"payload.valueF/60D",2d); checkCalc(p,"payload.valueD/60D",2d); checkCalc(p,"payload.valueJ/60D",2d); checkCalc(p,"payload.valueI/60D",2d); checkCalc(p,"payload.valueSB/payload.valueDB60",2d); checkCalc(p,"payload.valueBB/payload.valueDB60",2d); checkCalc(p,"payload.valueFB/payload.valueDB60",2d); checkCalc(p,"payload.valueDB/payload.valueDB60",2d); checkCalc(p,"payload.valueJB/payload.valueDB60",2d); checkCalc(p,"payload.valueIB/payload.valueDB60",2d); checkCalc(p,"payload.valueS/payload.valueDB60",2d); checkCalc(p,"payload.valueB/payload.valueDB60",2d); checkCalc(p,"payload.valueF/payload.valueDB60",2d); checkCalc(p,"payload.valueD/payload.valueDB60",2d); checkCalc(p,"payload.valueJ/payload.valueDB60",2d); checkCalc(p,"payload.valueI/payload.valueDB60",2d); // right is a float checkCalc(p,"payload.valueSB/60F",2F); checkCalc(p,"payload.valueBB/60F",2F); checkCalc(p,"payload.valueFB/60F",2f); checkCalc(p,"payload.valueDB/60F",2d); checkCalc(p,"payload.valueJB/60F",2F); checkCalc(p,"payload.valueIB/60F",2F); checkCalc(p,"payload.valueS/60F",2F); checkCalc(p,"payload.valueB/60F",2F); checkCalc(p,"payload.valueF/60F",2f); checkCalc(p,"payload.valueD/60F",2d); checkCalc(p,"payload.valueJ/60F",2F); checkCalc(p,"payload.valueI/60F",2F); checkCalc(p,"payload.valueSB/payload.valueFB60",2F); checkCalc(p,"payload.valueBB/payload.valueFB60",2F); checkCalc(p,"payload.valueFB/payload.valueFB60",2f); checkCalc(p,"payload.valueDB/payload.valueFB60",2d); checkCalc(p,"payload.valueJB/payload.valueFB60",2F); checkCalc(p,"payload.valueIB/payload.valueFB60",2F); checkCalc(p,"payload.valueS/payload.valueFB60",2F); checkCalc(p,"payload.valueB/payload.valueFB60",2F); checkCalc(p,"payload.valueF/payload.valueFB60",2f); checkCalc(p,"payload.valueD/payload.valueFB60",2d); checkCalc(p,"payload.valueJ/payload.valueFB60",2F); checkCalc(p,"payload.valueI/payload.valueFB60",2F); // right is a long checkCalc(p,"payload.valueSB/60L",2L); checkCalc(p,"payload.valueBB/60L",2L); checkCalc(p,"payload.valueFB/60L",2f); checkCalc(p,"payload.valueDB/60L",2d); checkCalc(p,"payload.valueJB/60L",2L); checkCalc(p,"payload.valueIB/60L",2L); checkCalc(p,"payload.valueS/60L",2L); checkCalc(p,"payload.valueB/60L",2L); checkCalc(p,"payload.valueF/60L",2f); checkCalc(p,"payload.valueD/60L",2d); checkCalc(p,"payload.valueJ/60L",2L); checkCalc(p,"payload.valueI/60L",2L); checkCalc(p,"payload.valueSB/payload.valueJB60",2L); checkCalc(p,"payload.valueBB/payload.valueJB60",2L); checkCalc(p,"payload.valueFB/payload.valueJB60",2f); checkCalc(p,"payload.valueDB/payload.valueJB60",2d); checkCalc(p,"payload.valueJB/payload.valueJB60",2L); checkCalc(p,"payload.valueIB/payload.valueJB60",2L); checkCalc(p,"payload.valueS/payload.valueJB60",2L); checkCalc(p,"payload.valueB/payload.valueJB60",2L); checkCalc(p,"payload.valueF/payload.valueJB60",2f); checkCalc(p,"payload.valueD/payload.valueJB60",2d); checkCalc(p,"payload.valueJ/payload.valueJB60",2L); checkCalc(p,"payload.valueI/payload.valueJB60",2L); // right is an int checkCalc(p,"payload.valueSB/60",2); checkCalc(p,"payload.valueBB/60",2); checkCalc(p,"payload.valueFB/60",2f); checkCalc(p,"payload.valueDB/60",2d); checkCalc(p,"payload.valueJB/60",2L); checkCalc(p,"payload.valueIB/60",2); checkCalc(p,"payload.valueS/60",2); checkCalc(p,"payload.valueB/60",2); checkCalc(p,"payload.valueF/60",2f); checkCalc(p,"payload.valueD/60",2d); checkCalc(p,"payload.valueJ/60",2L); checkCalc(p,"payload.valueI/60",2); checkCalc(p,"payload.valueSB/payload.valueIB60",2); checkCalc(p,"payload.valueBB/payload.valueIB60",2); checkCalc(p,"payload.valueFB/payload.valueIB60",2f); checkCalc(p,"payload.valueDB/payload.valueIB60",2d); checkCalc(p,"payload.valueJB/payload.valueIB60",2L); checkCalc(p,"payload.valueIB/payload.valueIB60",2); checkCalc(p,"payload.valueS/payload.valueIB60",2); checkCalc(p,"payload.valueB/payload.valueIB60",2); checkCalc(p,"payload.valueF/payload.valueIB60",2f); checkCalc(p,"payload.valueD/payload.valueIB60",2d); checkCalc(p,"payload.valueJ/payload.valueIB60",2L); checkCalc(p,"payload.valueI/payload.valueIB60",2); // right is a short checkCalc(p,"payload.valueSB/payload.valueS",1); checkCalc(p,"payload.valueBB/payload.valueS",1); checkCalc(p,"payload.valueFB/payload.valueS",1f); checkCalc(p,"payload.valueDB/payload.valueS",1d); checkCalc(p,"payload.valueJB/payload.valueS",1L); checkCalc(p,"payload.valueIB/payload.valueS",1); checkCalc(p,"payload.valueS/payload.valueS",1); checkCalc(p,"payload.valueB/payload.valueS",1); checkCalc(p,"payload.valueF/payload.valueS",1f); checkCalc(p,"payload.valueD/payload.valueS",1d); checkCalc(p,"payload.valueJ/payload.valueS",1L); checkCalc(p,"payload.valueI/payload.valueS",1); checkCalc(p,"payload.valueSB/payload.valueSB",1); checkCalc(p,"payload.valueBB/payload.valueSB",1); checkCalc(p,"payload.valueFB/payload.valueSB",1f); checkCalc(p,"payload.valueDB/payload.valueSB",1d); checkCalc(p,"payload.valueJB/payload.valueSB",1L); checkCalc(p,"payload.valueIB/payload.valueSB",1); checkCalc(p,"payload.valueS/payload.valueSB",1); checkCalc(p,"payload.valueB/payload.valueSB",1); checkCalc(p,"payload.valueF/payload.valueSB",1f); checkCalc(p,"payload.valueD/payload.valueSB",1d); checkCalc(p,"payload.valueJ/payload.valueSB",1L); checkCalc(p,"payload.valueI/payload.valueSB",1); // right is a byte checkCalc(p,"payload.valueSB/payload.valueB",1); checkCalc(p,"payload.valueBB/payload.valueB",1); checkCalc(p,"payload.valueFB/payload.valueB",1f); checkCalc(p,"payload.valueDB/payload.valueB",1d); checkCalc(p,"payload.valueJB/payload.valueB",1L); checkCalc(p,"payload.valueIB/payload.valueB",1); checkCalc(p,"payload.valueS/payload.valueB",1); checkCalc(p,"payload.valueB/payload.valueB",1); checkCalc(p,"payload.valueF/payload.valueB",1f); checkCalc(p,"payload.valueD/payload.valueB",1d); checkCalc(p,"payload.valueJ/payload.valueB",1L); checkCalc(p,"payload.valueI/payload.valueB",1); checkCalc(p,"payload.valueSB/payload.valueBB",1); checkCalc(p,"payload.valueBB/payload.valueBB",1); checkCalc(p,"payload.valueFB/payload.valueBB",1f); checkCalc(p,"payload.valueDB/payload.valueBB",1d); checkCalc(p,"payload.valueJB/payload.valueBB",1L); checkCalc(p,"payload.valueIB/payload.valueBB",1); checkCalc(p,"payload.valueS/payload.valueBB",1); checkCalc(p,"payload.valueB/payload.valueBB",1); checkCalc(p,"payload.valueF/payload.valueBB",1f); checkCalc(p,"payload.valueD/payload.valueBB",1d); checkCalc(p,"payload.valueJ/payload.valueBB",1L); checkCalc(p,"payload.valueI/payload.valueBB",1); } @Test public void opPlus_mixedNumberTypes() throws Exception { PayloadX p = new PayloadX(); // This is what you had to do before the changes in order for it to compile: // expression = parse("(T(java.lang.Double).parseDouble(payload.valueI.toString()))/60D"); // right is a double checkCalc(p,"payload.valueSB+60D",180d); checkCalc(p,"payload.valueBB+60D",180d); checkCalc(p,"payload.valueFB+60D",180d); checkCalc(p,"payload.valueDB+60D",180d); checkCalc(p,"payload.valueJB+60D",180d); checkCalc(p,"payload.valueIB+60D",180d); checkCalc(p,"payload.valueS+60D",180d); checkCalc(p,"payload.valueB+60D",180d); checkCalc(p,"payload.valueF+60D",180d); checkCalc(p,"payload.valueD+60D",180d); checkCalc(p,"payload.valueJ+60D",180d); checkCalc(p,"payload.valueI+60D",180d); checkCalc(p,"payload.valueSB+payload.valueDB60",180d); checkCalc(p,"payload.valueBB+payload.valueDB60",180d); checkCalc(p,"payload.valueFB+payload.valueDB60",180d); checkCalc(p,"payload.valueDB+payload.valueDB60",180d); checkCalc(p,"payload.valueJB+payload.valueDB60",180d); checkCalc(p,"payload.valueIB+payload.valueDB60",180d); checkCalc(p,"payload.valueS+payload.valueDB60",180d); checkCalc(p,"payload.valueB+payload.valueDB60",180d); checkCalc(p,"payload.valueF+payload.valueDB60",180d); checkCalc(p,"payload.valueD+payload.valueDB60",180d); checkCalc(p,"payload.valueJ+payload.valueDB60",180d); checkCalc(p,"payload.valueI+payload.valueDB60",180d); // right is a float checkCalc(p,"payload.valueSB+60F",180F); checkCalc(p,"payload.valueBB+60F",180F); checkCalc(p,"payload.valueFB+60F",180f); checkCalc(p,"payload.valueDB+60F",180d); checkCalc(p,"payload.valueJB+60F",180F); checkCalc(p,"payload.valueIB+60F",180F); checkCalc(p,"payload.valueS+60F",180F); checkCalc(p,"payload.valueB+60F",180F); checkCalc(p,"payload.valueF+60F",180f); checkCalc(p,"payload.valueD+60F",180d); checkCalc(p,"payload.valueJ+60F",180F); checkCalc(p,"payload.valueI+60F",180F); checkCalc(p,"payload.valueSB+payload.valueFB60",180F); checkCalc(p,"payload.valueBB+payload.valueFB60",180F); checkCalc(p,"payload.valueFB+payload.valueFB60",180f); checkCalc(p,"payload.valueDB+payload.valueFB60",180d); checkCalc(p,"payload.valueJB+payload.valueFB60",180F); checkCalc(p,"payload.valueIB+payload.valueFB60",180F); checkCalc(p,"payload.valueS+payload.valueFB60",180F); checkCalc(p,"payload.valueB+payload.valueFB60",180F); checkCalc(p,"payload.valueF+payload.valueFB60",180f); checkCalc(p,"payload.valueD+payload.valueFB60",180d); checkCalc(p,"payload.valueJ+payload.valueFB60",180F); checkCalc(p,"payload.valueI+payload.valueFB60",180F); // right is a long checkCalc(p,"payload.valueSB+60L",180L); checkCalc(p,"payload.valueBB+60L",180L); checkCalc(p,"payload.valueFB+60L",180f); checkCalc(p,"payload.valueDB+60L",180d); checkCalc(p,"payload.valueJB+60L",180L); checkCalc(p,"payload.valueIB+60L",180L); checkCalc(p,"payload.valueS+60L",180L); checkCalc(p,"payload.valueB+60L",180L); checkCalc(p,"payload.valueF+60L",180f); checkCalc(p,"payload.valueD+60L",180d); checkCalc(p,"payload.valueJ+60L",180L); checkCalc(p,"payload.valueI+60L",180L); checkCalc(p,"payload.valueSB+payload.valueJB60",180L); checkCalc(p,"payload.valueBB+payload.valueJB60",180L); checkCalc(p,"payload.valueFB+payload.valueJB60",180f); checkCalc(p,"payload.valueDB+payload.valueJB60",180d); checkCalc(p,"payload.valueJB+payload.valueJB60",180L); checkCalc(p,"payload.valueIB+payload.valueJB60",180L); checkCalc(p,"payload.valueS+payload.valueJB60",180L); checkCalc(p,"payload.valueB+payload.valueJB60",180L); checkCalc(p,"payload.valueF+payload.valueJB60",180f); checkCalc(p,"payload.valueD+payload.valueJB60",180d); checkCalc(p,"payload.valueJ+payload.valueJB60",180L); checkCalc(p,"payload.valueI+payload.valueJB60",180L); // right is an int checkCalc(p,"payload.valueSB+60",180); checkCalc(p,"payload.valueBB+60",180); checkCalc(p,"payload.valueFB+60",180f); checkCalc(p,"payload.valueDB+60",180d); checkCalc(p,"payload.valueJB+60",180L); checkCalc(p,"payload.valueIB+60",180); checkCalc(p,"payload.valueS+60",180); checkCalc(p,"payload.valueB+60",180); checkCalc(p,"payload.valueF+60",180f); checkCalc(p,"payload.valueD+60",180d); checkCalc(p,"payload.valueJ+60",180L); checkCalc(p,"payload.valueI+60",180); checkCalc(p,"payload.valueSB+payload.valueIB60",180); checkCalc(p,"payload.valueBB+payload.valueIB60",180); checkCalc(p,"payload.valueFB+payload.valueIB60",180f); checkCalc(p,"payload.valueDB+payload.valueIB60",180d); checkCalc(p,"payload.valueJB+payload.valueIB60",180L); checkCalc(p,"payload.valueIB+payload.valueIB60",180); checkCalc(p,"payload.valueS+payload.valueIB60",180); checkCalc(p,"payload.valueB+payload.valueIB60",180); checkCalc(p,"payload.valueF+payload.valueIB60",180f); checkCalc(p,"payload.valueD+payload.valueIB60",180d); checkCalc(p,"payload.valueJ+payload.valueIB60",180L); checkCalc(p,"payload.valueI+payload.valueIB60",180); // right is a short checkCalc(p,"payload.valueSB+payload.valueS",240); checkCalc(p,"payload.valueBB+payload.valueS",240); checkCalc(p,"payload.valueFB+payload.valueS",240f); checkCalc(p,"payload.valueDB+payload.valueS",240d); checkCalc(p,"payload.valueJB+payload.valueS",240L); checkCalc(p,"payload.valueIB+payload.valueS",240); checkCalc(p,"payload.valueS+payload.valueS",240); checkCalc(p,"payload.valueB+payload.valueS",240); checkCalc(p,"payload.valueF+payload.valueS",240f); checkCalc(p,"payload.valueD+payload.valueS",240d); checkCalc(p,"payload.valueJ+payload.valueS",240L); checkCalc(p,"payload.valueI+payload.valueS",240); checkCalc(p,"payload.valueSB+payload.valueSB",240); checkCalc(p,"payload.valueBB+payload.valueSB",240); checkCalc(p,"payload.valueFB+payload.valueSB",240f); checkCalc(p,"payload.valueDB+payload.valueSB",240d); checkCalc(p,"payload.valueJB+payload.valueSB",240L); checkCalc(p,"payload.valueIB+payload.valueSB",240); checkCalc(p,"payload.valueS+payload.valueSB",240); checkCalc(p,"payload.valueB+payload.valueSB",240); checkCalc(p,"payload.valueF+payload.valueSB",240f); checkCalc(p,"payload.valueD+payload.valueSB",240d); checkCalc(p,"payload.valueJ+payload.valueSB",240L); checkCalc(p,"payload.valueI+payload.valueSB",240); // right is a byte checkCalc(p,"payload.valueSB+payload.valueB",240); checkCalc(p,"payload.valueBB+payload.valueB",240); checkCalc(p,"payload.valueFB+payload.valueB",240f); checkCalc(p,"payload.valueDB+payload.valueB",240d); checkCalc(p,"payload.valueJB+payload.valueB",240L); checkCalc(p,"payload.valueIB+payload.valueB",240); checkCalc(p,"payload.valueS+payload.valueB",240); checkCalc(p,"payload.valueB+payload.valueB",240); checkCalc(p,"payload.valueF+payload.valueB",240f); checkCalc(p,"payload.valueD+payload.valueB",240d); checkCalc(p,"payload.valueJ+payload.valueB",240L); checkCalc(p,"payload.valueI+payload.valueB",240); checkCalc(p,"payload.valueSB+payload.valueBB",240); checkCalc(p,"payload.valueBB+payload.valueBB",240); checkCalc(p,"payload.valueFB+payload.valueBB",240f); checkCalc(p,"payload.valueDB+payload.valueBB",240d); checkCalc(p,"payload.valueJB+payload.valueBB",240L); checkCalc(p,"payload.valueIB+payload.valueBB",240); checkCalc(p,"payload.valueS+payload.valueBB",240); checkCalc(p,"payload.valueB+payload.valueBB",240); checkCalc(p,"payload.valueF+payload.valueBB",240f); checkCalc(p,"payload.valueD+payload.valueBB",240d); checkCalc(p,"payload.valueJ+payload.valueBB",240L); checkCalc(p,"payload.valueI+payload.valueBB",240); } private void checkCalc(PayloadX p, String expression, int expectedResult) { Expression expr = parse(expression); assertEquals(expectedResult, expr.getValue(p)); assertCanCompile(expr); assertEquals(expectedResult, expr.getValue(p)); } private void checkCalc(PayloadX p, String expression, float expectedResult) { Expression expr = parse(expression); assertEquals(expectedResult, expr.getValue(p)); assertCanCompile(expr); assertEquals(expectedResult, expr.getValue(p)); } private void checkCalc(PayloadX p, String expression, long expectedResult) { Expression expr = parse(expression); assertEquals(expectedResult, expr.getValue(p)); assertCanCompile(expr); assertEquals(expectedResult, expr.getValue(p)); } private void checkCalc(PayloadX p, String expression, double expectedResult) { Expression expr = parse(expression); assertEquals(expectedResult, expr.getValue(p)); assertCanCompile(expr); assertEquals(expectedResult, expr.getValue(p)); } @Test public void opPlusString() throws Exception { expression = parse("'hello' + 'world'"); assertEquals("helloworld", expression.getValue()); assertCanCompile(expression); assertEquals("helloworld", expression.getValue()); // Method with string return expression = parse("'hello' + getWorld()"); assertEquals("helloworld", expression.getValue(new Greeter())); assertCanCompile(expression); assertEquals("helloworld", expression.getValue(new Greeter())); // Method with string return expression = parse("getWorld() + 'hello'"); assertEquals("worldhello", expression.getValue(new Greeter())); assertCanCompile(expression); assertEquals("worldhello", expression.getValue(new Greeter())); // Three strings, optimal bytecode would only use one StringBuilder expression = parse("'hello' + getWorld() + ' spring'"); assertEquals("helloworld spring", expression.getValue(new Greeter())); assertCanCompile(expression); assertEquals("helloworld spring", expression.getValue(new Greeter())); // Three strings, optimal bytecode would only use one StringBuilder expression = parse("'hello' + 3 + ' spring'"); assertEquals("hello3 spring", expression.getValue(new Greeter())); assertCantCompile(expression); expression = parse("object + 'a'"); assertEquals("objecta", expression.getValue(new Greeter())); assertCanCompile(expression); assertEquals("objecta", expression.getValue(new Greeter())); expression = parse("'a'+object"); assertEquals("aobject", expression.getValue(new Greeter())); assertCanCompile(expression); assertEquals("aobject", expression.getValue(new Greeter())); expression = parse("'a'+object+'a'"); assertEquals("aobjecta", expression.getValue(new Greeter())); assertCanCompile(expression); assertEquals("aobjecta", expression.getValue(new Greeter())); expression = parse("object+'a'+object"); assertEquals("objectaobject", expression.getValue(new Greeter())); assertCanCompile(expression); assertEquals("objectaobject", expression.getValue(new Greeter())); expression = parse("object+object"); assertEquals("objectobject", expression.getValue(new Greeter())); assertCanCompile(expression); assertEquals("objectobject", expression.getValue(new Greeter())); } @Test public void opMinus() throws Exception { expression = parse("2-2"); expression.getValue(); assertCanCompile(expression); assertEquals(0, expression.getValue()); expression = parse("4L-2L"); expression.getValue(); assertCanCompile(expression); assertEquals(2L, expression.getValue()); expression = parse("4.0f-2.0f"); expression.getValue(); assertCanCompile(expression); assertEquals(2.0f, expression.getValue()); expression = parse("3.0d-4.0d"); expression.getValue(); assertCanCompile(expression); assertEquals(-1.0d, expression.getValue()); expression = parse("-1"); expression.getValue(); assertCanCompile(expression); assertEquals(-1, expression.getValue()); expression = parse("-1L"); expression.getValue(); assertCanCompile(expression); assertEquals(-1L, expression.getValue()); expression = parse("-1.5f"); expression.getValue(); assertCanCompile(expression); assertEquals(-1.5f, expression.getValue()); expression = parse("-2.5d"); expression.getValue(); assertCanCompile(expression); assertEquals(-2.5d, expression.getValue()); expression = parse("T(Integer).valueOf(2)-6"); assertEquals(-4, expression.getValue()); assertCanCompile(expression); assertEquals(-4, expression.getValue()); expression = parse("T(Integer).valueOf(1)-T(Integer).valueOf(3)"); assertEquals(-2, expression.getValue()); assertCanCompile(expression); assertEquals(-2, expression.getValue()); expression = parse("4-T(Integer).valueOf(3)"); assertEquals(1, expression.getValue()); assertCanCompile(expression); assertEquals(1, expression.getValue()); expression = parse("T(Float).valueOf(2.0f)-6"); assertEquals(-4.0f, expression.getValue()); assertCanCompile(expression); assertEquals(-4.0f, expression.getValue()); expression = parse("T(Float).valueOf(8.0f)-T(Float).valueOf(3.0f)"); assertEquals(5.0f, expression.getValue()); assertCanCompile(expression); assertEquals(5.0f, expression.getValue()); expression = parse("11L-T(Long).valueOf(4L)"); assertEquals(7L, expression.getValue()); assertCanCompile(expression); assertEquals(7L, expression.getValue()); expression = parse("T(Long).valueOf(9L)-6"); assertEquals(3L, expression.getValue()); assertCanCompile(expression); assertEquals(3L, expression.getValue()); expression = parse("T(Long).valueOf(4L)-T(Long).valueOf(3L)"); assertEquals(1L, expression.getValue()); assertCanCompile(expression); assertEquals(1L, expression.getValue()); expression = parse("8L-T(Long).valueOf(2L)"); assertEquals(6L, expression.getValue()); assertCanCompile(expression); assertEquals(6L, expression.getValue()); } @Test public void opMinus_mixedNumberTypes() throws Exception { PayloadX p = new PayloadX(); // This is what you had to do before the changes in order for it to compile: // expression = parse("(T(java.lang.Double).parseDouble(payload.valueI.toString()))/60D"); // right is a double checkCalc(p,"payload.valueSB-60D",60d); checkCalc(p,"payload.valueBB-60D",60d); checkCalc(p,"payload.valueFB-60D",60d); checkCalc(p,"payload.valueDB-60D",60d); checkCalc(p,"payload.valueJB-60D",60d); checkCalc(p,"payload.valueIB-60D",60d); checkCalc(p,"payload.valueS-60D",60d); checkCalc(p,"payload.valueB-60D",60d); checkCalc(p,"payload.valueF-60D",60d); checkCalc(p,"payload.valueD-60D",60d); checkCalc(p,"payload.valueJ-60D",60d); checkCalc(p,"payload.valueI-60D",60d); checkCalc(p,"payload.valueSB-payload.valueDB60",60d); checkCalc(p,"payload.valueBB-payload.valueDB60",60d); checkCalc(p,"payload.valueFB-payload.valueDB60",60d); checkCalc(p,"payload.valueDB-payload.valueDB60",60d); checkCalc(p,"payload.valueJB-payload.valueDB60",60d); checkCalc(p,"payload.valueIB-payload.valueDB60",60d); checkCalc(p,"payload.valueS-payload.valueDB60",60d); checkCalc(p,"payload.valueB-payload.valueDB60",60d); checkCalc(p,"payload.valueF-payload.valueDB60",60d); checkCalc(p,"payload.valueD-payload.valueDB60",60d); checkCalc(p,"payload.valueJ-payload.valueDB60",60d); checkCalc(p,"payload.valueI-payload.valueDB60",60d); // right is a float checkCalc(p,"payload.valueSB-60F",60F); checkCalc(p,"payload.valueBB-60F",60F); checkCalc(p,"payload.valueFB-60F",60f); checkCalc(p,"payload.valueDB-60F",60d); checkCalc(p,"payload.valueJB-60F",60F); checkCalc(p,"payload.valueIB-60F",60F); checkCalc(p,"payload.valueS-60F",60F); checkCalc(p,"payload.valueB-60F",60F); checkCalc(p,"payload.valueF-60F",60f); checkCalc(p,"payload.valueD-60F",60d); checkCalc(p,"payload.valueJ-60F",60F); checkCalc(p,"payload.valueI-60F",60F); checkCalc(p,"payload.valueSB-payload.valueFB60",60F); checkCalc(p,"payload.valueBB-payload.valueFB60",60F); checkCalc(p,"payload.valueFB-payload.valueFB60",60f); checkCalc(p,"payload.valueDB-payload.valueFB60",60d); checkCalc(p,"payload.valueJB-payload.valueFB60",60F); checkCalc(p,"payload.valueIB-payload.valueFB60",60F); checkCalc(p,"payload.valueS-payload.valueFB60",60F); checkCalc(p,"payload.valueB-payload.valueFB60",60F); checkCalc(p,"payload.valueF-payload.valueFB60",60f); checkCalc(p,"payload.valueD-payload.valueFB60",60d); checkCalc(p,"payload.valueJ-payload.valueFB60",60F); checkCalc(p,"payload.valueI-payload.valueFB60",60F); // right is a long checkCalc(p,"payload.valueSB-60L",60L); checkCalc(p,"payload.valueBB-60L",60L); checkCalc(p,"payload.valueFB-60L",60f); checkCalc(p,"payload.valueDB-60L",60d); checkCalc(p,"payload.valueJB-60L",60L); checkCalc(p,"payload.valueIB-60L",60L); checkCalc(p,"payload.valueS-60L",60L); checkCalc(p,"payload.valueB-60L",60L); checkCalc(p,"payload.valueF-60L",60f); checkCalc(p,"payload.valueD-60L",60d); checkCalc(p,"payload.valueJ-60L",60L); checkCalc(p,"payload.valueI-60L",60L); checkCalc(p,"payload.valueSB-payload.valueJB60",60L); checkCalc(p,"payload.valueBB-payload.valueJB60",60L); checkCalc(p,"payload.valueFB-payload.valueJB60",60f); checkCalc(p,"payload.valueDB-payload.valueJB60",60d); checkCalc(p,"payload.valueJB-payload.valueJB60",60L); checkCalc(p,"payload.valueIB-payload.valueJB60",60L); checkCalc(p,"payload.valueS-payload.valueJB60",60L); checkCalc(p,"payload.valueB-payload.valueJB60",60L); checkCalc(p,"payload.valueF-payload.valueJB60",60f); checkCalc(p,"payload.valueD-payload.valueJB60",60d); checkCalc(p,"payload.valueJ-payload.valueJB60",60L); checkCalc(p,"payload.valueI-payload.valueJB60",60L); // right is an int checkCalc(p,"payload.valueSB-60",60); checkCalc(p,"payload.valueBB-60",60); checkCalc(p,"payload.valueFB-60",60f); checkCalc(p,"payload.valueDB-60",60d); checkCalc(p,"payload.valueJB-60",60L); checkCalc(p,"payload.valueIB-60",60); checkCalc(p,"payload.valueS-60",60); checkCalc(p,"payload.valueB-60",60); checkCalc(p,"payload.valueF-60",60f); checkCalc(p,"payload.valueD-60",60d); checkCalc(p,"payload.valueJ-60",60L); checkCalc(p,"payload.valueI-60",60); checkCalc(p,"payload.valueSB-payload.valueIB60",60); checkCalc(p,"payload.valueBB-payload.valueIB60",60); checkCalc(p,"payload.valueFB-payload.valueIB60",60f); checkCalc(p,"payload.valueDB-payload.valueIB60",60d); checkCalc(p,"payload.valueJB-payload.valueIB60",60L); checkCalc(p,"payload.valueIB-payload.valueIB60",60); checkCalc(p,"payload.valueS-payload.valueIB60",60); checkCalc(p,"payload.valueB-payload.valueIB60",60); checkCalc(p,"payload.valueF-payload.valueIB60",60f); checkCalc(p,"payload.valueD-payload.valueIB60",60d); checkCalc(p,"payload.valueJ-payload.valueIB60",60L); checkCalc(p,"payload.valueI-payload.valueIB60",60); // right is a short checkCalc(p,"payload.valueSB-payload.valueS20",100); checkCalc(p,"payload.valueBB-payload.valueS20",100); checkCalc(p,"payload.valueFB-payload.valueS20",100f); checkCalc(p,"payload.valueDB-payload.valueS20",100d); checkCalc(p,"payload.valueJB-payload.valueS20",100L); checkCalc(p,"payload.valueIB-payload.valueS20",100); checkCalc(p,"payload.valueS-payload.valueS20",100); checkCalc(p,"payload.valueB-payload.valueS20",100); checkCalc(p,"payload.valueF-payload.valueS20",100f); checkCalc(p,"payload.valueD-payload.valueS20",100d); checkCalc(p,"payload.valueJ-payload.valueS20",100L); checkCalc(p,"payload.valueI-payload.valueS20",100); checkCalc(p,"payload.valueSB-payload.valueSB20",100); checkCalc(p,"payload.valueBB-payload.valueSB20",100); checkCalc(p,"payload.valueFB-payload.valueSB20",100f); checkCalc(p,"payload.valueDB-payload.valueSB20",100d); checkCalc(p,"payload.valueJB-payload.valueSB20",100L); checkCalc(p,"payload.valueIB-payload.valueSB20",100); checkCalc(p,"payload.valueS-payload.valueSB20",100); checkCalc(p,"payload.valueB-payload.valueSB20",100); checkCalc(p,"payload.valueF-payload.valueSB20",100f); checkCalc(p,"payload.valueD-payload.valueSB20",100d); checkCalc(p,"payload.valueJ-payload.valueSB20",100L); checkCalc(p,"payload.valueI-payload.valueSB20",100); // right is a byte checkCalc(p,"payload.valueSB-payload.valueB20",100); checkCalc(p,"payload.valueBB-payload.valueB20",100); checkCalc(p,"payload.valueFB-payload.valueB20",100f); checkCalc(p,"payload.valueDB-payload.valueB20",100d); checkCalc(p,"payload.valueJB-payload.valueB20",100L); checkCalc(p,"payload.valueIB-payload.valueB20",100); checkCalc(p,"payload.valueS-payload.valueB20",100); checkCalc(p,"payload.valueB-payload.valueB20",100); checkCalc(p,"payload.valueF-payload.valueB20",100f); checkCalc(p,"payload.valueD-payload.valueB20",100d); checkCalc(p,"payload.valueJ-payload.valueB20",100L); checkCalc(p,"payload.valueI-payload.valueB20",100); checkCalc(p,"payload.valueSB-payload.valueBB20",100); checkCalc(p,"payload.valueBB-payload.valueBB20",100); checkCalc(p,"payload.valueFB-payload.valueBB20",100f); checkCalc(p,"payload.valueDB-payload.valueBB20",100d); checkCalc(p,"payload.valueJB-payload.valueBB20",100L); checkCalc(p,"payload.valueIB-payload.valueBB20",100); checkCalc(p,"payload.valueS-payload.valueBB20",100); checkCalc(p,"payload.valueB-payload.valueBB20",100); checkCalc(p,"payload.valueF-payload.valueBB20",100f); checkCalc(p,"payload.valueD-payload.valueBB20",100d); checkCalc(p,"payload.valueJ-payload.valueBB20",100L); checkCalc(p,"payload.valueI-payload.valueBB20",100); } @Test public void opMultiply_mixedNumberTypes() throws Exception { PayloadX p = new PayloadX(); // This is what you had to do before the changes in order for it to compile: // expression = parse("(T(java.lang.Double).parseDouble(payload.valueI.toString()))/60D"); // right is a double checkCalc(p,"payload.valueSB*60D",7200d); checkCalc(p,"payload.valueBB*60D",7200d); checkCalc(p,"payload.valueFB*60D",7200d); checkCalc(p,"payload.valueDB*60D",7200d); checkCalc(p,"payload.valueJB*60D",7200d); checkCalc(p,"payload.valueIB*60D",7200d); checkCalc(p,"payload.valueS*60D",7200d); checkCalc(p,"payload.valueB*60D",7200d); checkCalc(p,"payload.valueF*60D",7200d); checkCalc(p,"payload.valueD*60D",7200d); checkCalc(p,"payload.valueJ*60D",7200d); checkCalc(p,"payload.valueI*60D",7200d); checkCalc(p,"payload.valueSB*payload.valueDB60",7200d); checkCalc(p,"payload.valueBB*payload.valueDB60",7200d); checkCalc(p,"payload.valueFB*payload.valueDB60",7200d); checkCalc(p,"payload.valueDB*payload.valueDB60",7200d); checkCalc(p,"payload.valueJB*payload.valueDB60",7200d); checkCalc(p,"payload.valueIB*payload.valueDB60",7200d); checkCalc(p,"payload.valueS*payload.valueDB60",7200d); checkCalc(p,"payload.valueB*payload.valueDB60",7200d); checkCalc(p,"payload.valueF*payload.valueDB60",7200d); checkCalc(p,"payload.valueD*payload.valueDB60",7200d); checkCalc(p,"payload.valueJ*payload.valueDB60",7200d); checkCalc(p,"payload.valueI*payload.valueDB60",7200d); // right is a float checkCalc(p,"payload.valueSB*60F",7200F); checkCalc(p,"payload.valueBB*60F",7200F); checkCalc(p,"payload.valueFB*60F",7200f); checkCalc(p,"payload.valueDB*60F",7200d); checkCalc(p,"payload.valueJB*60F",7200F); checkCalc(p,"payload.valueIB*60F",7200F); checkCalc(p,"payload.valueS*60F",7200F); checkCalc(p,"payload.valueB*60F",7200F); checkCalc(p,"payload.valueF*60F",7200f); checkCalc(p,"payload.valueD*60F",7200d); checkCalc(p,"payload.valueJ*60F",7200F); checkCalc(p,"payload.valueI*60F",7200F); checkCalc(p,"payload.valueSB*payload.valueFB60",7200F); checkCalc(p,"payload.valueBB*payload.valueFB60",7200F); checkCalc(p,"payload.valueFB*payload.valueFB60",7200f); checkCalc(p,"payload.valueDB*payload.valueFB60",7200d); checkCalc(p,"payload.valueJB*payload.valueFB60",7200F); checkCalc(p,"payload.valueIB*payload.valueFB60",7200F); checkCalc(p,"payload.valueS*payload.valueFB60",7200F); checkCalc(p,"payload.valueB*payload.valueFB60",7200F); checkCalc(p,"payload.valueF*payload.valueFB60",7200f); checkCalc(p,"payload.valueD*payload.valueFB60",7200d); checkCalc(p,"payload.valueJ*payload.valueFB60",7200F); checkCalc(p,"payload.valueI*payload.valueFB60",7200F); // right is a long checkCalc(p,"payload.valueSB*60L",7200L); checkCalc(p,"payload.valueBB*60L",7200L); checkCalc(p,"payload.valueFB*60L",7200f); checkCalc(p,"payload.valueDB*60L",7200d); checkCalc(p,"payload.valueJB*60L",7200L); checkCalc(p,"payload.valueIB*60L",7200L); checkCalc(p,"payload.valueS*60L",7200L); checkCalc(p,"payload.valueB*60L",7200L); checkCalc(p,"payload.valueF*60L",7200f); checkCalc(p,"payload.valueD*60L",7200d); checkCalc(p,"payload.valueJ*60L",7200L); checkCalc(p,"payload.valueI*60L",7200L); checkCalc(p,"payload.valueSB*payload.valueJB60",7200L); checkCalc(p,"payload.valueBB*payload.valueJB60",7200L); checkCalc(p,"payload.valueFB*payload.valueJB60",7200f); checkCalc(p,"payload.valueDB*payload.valueJB60",7200d); checkCalc(p,"payload.valueJB*payload.valueJB60",7200L); checkCalc(p,"payload.valueIB*payload.valueJB60",7200L); checkCalc(p,"payload.valueS*payload.valueJB60",7200L); checkCalc(p,"payload.valueB*payload.valueJB60",7200L); checkCalc(p,"payload.valueF*payload.valueJB60",7200f); checkCalc(p,"payload.valueD*payload.valueJB60",7200d); checkCalc(p,"payload.valueJ*payload.valueJB60",7200L); checkCalc(p,"payload.valueI*payload.valueJB60",7200L); // right is an int checkCalc(p,"payload.valueSB*60",7200); checkCalc(p,"payload.valueBB*60",7200); checkCalc(p,"payload.valueFB*60",7200f); checkCalc(p,"payload.valueDB*60",7200d); checkCalc(p,"payload.valueJB*60",7200L); checkCalc(p,"payload.valueIB*60",7200); checkCalc(p,"payload.valueS*60",7200); checkCalc(p,"payload.valueB*60",7200); checkCalc(p,"payload.valueF*60",7200f); checkCalc(p,"payload.valueD*60",7200d); checkCalc(p,"payload.valueJ*60",7200L); checkCalc(p,"payload.valueI*60",7200); checkCalc(p,"payload.valueSB*payload.valueIB60",7200); checkCalc(p,"payload.valueBB*payload.valueIB60",7200); checkCalc(p,"payload.valueFB*payload.valueIB60",7200f); checkCalc(p,"payload.valueDB*payload.valueIB60",7200d); checkCalc(p,"payload.valueJB*payload.valueIB60",7200L); checkCalc(p,"payload.valueIB*payload.valueIB60",7200); checkCalc(p,"payload.valueS*payload.valueIB60",7200); checkCalc(p,"payload.valueB*payload.valueIB60",7200); checkCalc(p,"payload.valueF*payload.valueIB60",7200f); checkCalc(p,"payload.valueD*payload.valueIB60",7200d); checkCalc(p,"payload.valueJ*payload.valueIB60",7200L); checkCalc(p,"payload.valueI*payload.valueIB60",7200); // right is a short checkCalc(p,"payload.valueSB*payload.valueS20",2400); checkCalc(p,"payload.valueBB*payload.valueS20",2400); checkCalc(p,"payload.valueFB*payload.valueS20",2400f); checkCalc(p,"payload.valueDB*payload.valueS20",2400d); checkCalc(p,"payload.valueJB*payload.valueS20",2400L); checkCalc(p,"payload.valueIB*payload.valueS20",2400); checkCalc(p,"payload.valueS*payload.valueS20",2400); checkCalc(p,"payload.valueB*payload.valueS20",2400); checkCalc(p,"payload.valueF*payload.valueS20",2400f); checkCalc(p,"payload.valueD*payload.valueS20",2400d); checkCalc(p,"payload.valueJ*payload.valueS20",2400L); checkCalc(p,"payload.valueI*payload.valueS20",2400); checkCalc(p,"payload.valueSB*payload.valueSB20",2400); checkCalc(p,"payload.valueBB*payload.valueSB20",2400); checkCalc(p,"payload.valueFB*payload.valueSB20",2400f); checkCalc(p,"payload.valueDB*payload.valueSB20",2400d); checkCalc(p,"payload.valueJB*payload.valueSB20",2400L); checkCalc(p,"payload.valueIB*payload.valueSB20",2400); checkCalc(p,"payload.valueS*payload.valueSB20",2400); checkCalc(p,"payload.valueB*payload.valueSB20",2400); checkCalc(p,"payload.valueF*payload.valueSB20",2400f); checkCalc(p,"payload.valueD*payload.valueSB20",2400d); checkCalc(p,"payload.valueJ*payload.valueSB20",2400L); checkCalc(p,"payload.valueI*payload.valueSB20",2400); // right is a byte checkCalc(p,"payload.valueSB*payload.valueB20",2400); checkCalc(p,"payload.valueBB*payload.valueB20",2400); checkCalc(p,"payload.valueFB*payload.valueB20",2400f); checkCalc(p,"payload.valueDB*payload.valueB20",2400d); checkCalc(p,"payload.valueJB*payload.valueB20",2400L); checkCalc(p,"payload.valueIB*payload.valueB20",2400); checkCalc(p,"payload.valueS*payload.valueB20",2400); checkCalc(p,"payload.valueB*payload.valueB20",2400); checkCalc(p,"payload.valueF*payload.valueB20",2400f); checkCalc(p,"payload.valueD*payload.valueB20",2400d); checkCalc(p,"payload.valueJ*payload.valueB20",2400L); checkCalc(p,"payload.valueI*payload.valueB20",2400); checkCalc(p,"payload.valueSB*payload.valueBB20",2400); checkCalc(p,"payload.valueBB*payload.valueBB20",2400); checkCalc(p,"payload.valueFB*payload.valueBB20",2400f); checkCalc(p,"payload.valueDB*payload.valueBB20",2400d); checkCalc(p,"payload.valueJB*payload.valueBB20",2400L); checkCalc(p,"payload.valueIB*payload.valueBB20",2400); checkCalc(p,"payload.valueS*payload.valueBB20",2400); checkCalc(p,"payload.valueB*payload.valueBB20",2400); checkCalc(p,"payload.valueF*payload.valueBB20",2400f); checkCalc(p,"payload.valueD*payload.valueBB20",2400d); checkCalc(p,"payload.valueJ*payload.valueBB20",2400L); checkCalc(p,"payload.valueI*payload.valueBB20",2400); } @Test public void opModulus_mixedNumberTypes() throws Exception { PayloadX p = new PayloadX(); // This is what you had to do before the changes in order for it to compile: // expression = parse("(T(java.lang.Double).parseDouble(payload.valueI.toString()))/60D"); // right is a double checkCalc(p,"payload.valueSB%58D",4d); checkCalc(p,"payload.valueBB%58D",4d); checkCalc(p,"payload.valueFB%58D",4d); checkCalc(p,"payload.valueDB%58D",4d); checkCalc(p,"payload.valueJB%58D",4d); checkCalc(p,"payload.valueIB%58D",4d); checkCalc(p,"payload.valueS%58D",4d); checkCalc(p,"payload.valueB%58D",4d); checkCalc(p,"payload.valueF%58D",4d); checkCalc(p,"payload.valueD%58D",4d); checkCalc(p,"payload.valueJ%58D",4d); checkCalc(p,"payload.valueI%58D",4d); checkCalc(p,"payload.valueSB%payload.valueDB58",4d); checkCalc(p,"payload.valueBB%payload.valueDB58",4d); checkCalc(p,"payload.valueFB%payload.valueDB58",4d); checkCalc(p,"payload.valueDB%payload.valueDB58",4d); checkCalc(p,"payload.valueJB%payload.valueDB58",4d); checkCalc(p,"payload.valueIB%payload.valueDB58",4d); checkCalc(p,"payload.valueS%payload.valueDB58",4d); checkCalc(p,"payload.valueB%payload.valueDB58",4d); checkCalc(p,"payload.valueF%payload.valueDB58",4d); checkCalc(p,"payload.valueD%payload.valueDB58",4d); checkCalc(p,"payload.valueJ%payload.valueDB58",4d); checkCalc(p,"payload.valueI%payload.valueDB58",4d); // right is a float checkCalc(p,"payload.valueSB%58F",4F); checkCalc(p,"payload.valueBB%58F",4F); checkCalc(p,"payload.valueFB%58F",4f); checkCalc(p,"payload.valueDB%58F",4d); checkCalc(p,"payload.valueJB%58F",4F); checkCalc(p,"payload.valueIB%58F",4F); checkCalc(p,"payload.valueS%58F",4F); checkCalc(p,"payload.valueB%58F",4F); checkCalc(p,"payload.valueF%58F",4f); checkCalc(p,"payload.valueD%58F",4d); checkCalc(p,"payload.valueJ%58F",4F); checkCalc(p,"payload.valueI%58F",4F); checkCalc(p,"payload.valueSB%payload.valueFB58",4F); checkCalc(p,"payload.valueBB%payload.valueFB58",4F); checkCalc(p,"payload.valueFB%payload.valueFB58",4f); checkCalc(p,"payload.valueDB%payload.valueFB58",4d); checkCalc(p,"payload.valueJB%payload.valueFB58",4F); checkCalc(p,"payload.valueIB%payload.valueFB58",4F); checkCalc(p,"payload.valueS%payload.valueFB58",4F); checkCalc(p,"payload.valueB%payload.valueFB58",4F); checkCalc(p,"payload.valueF%payload.valueFB58",4f); checkCalc(p,"payload.valueD%payload.valueFB58",4d); checkCalc(p,"payload.valueJ%payload.valueFB58",4F); checkCalc(p,"payload.valueI%payload.valueFB58",4F); // right is a long checkCalc(p,"payload.valueSB%58L",4L); checkCalc(p,"payload.valueBB%58L",4L); checkCalc(p,"payload.valueFB%58L",4f); checkCalc(p,"payload.valueDB%58L",4d); checkCalc(p,"payload.valueJB%58L",4L); checkCalc(p,"payload.valueIB%58L",4L); checkCalc(p,"payload.valueS%58L",4L); checkCalc(p,"payload.valueB%58L",4L); checkCalc(p,"payload.valueF%58L",4f); checkCalc(p,"payload.valueD%58L",4d); checkCalc(p,"payload.valueJ%58L",4L); checkCalc(p,"payload.valueI%58L",4L); checkCalc(p,"payload.valueSB%payload.valueJB58",4L); checkCalc(p,"payload.valueBB%payload.valueJB58",4L); checkCalc(p,"payload.valueFB%payload.valueJB58",4f); checkCalc(p,"payload.valueDB%payload.valueJB58",4d); checkCalc(p,"payload.valueJB%payload.valueJB58",4L); checkCalc(p,"payload.valueIB%payload.valueJB58",4L); checkCalc(p,"payload.valueS%payload.valueJB58",4L); checkCalc(p,"payload.valueB%payload.valueJB58",4L); checkCalc(p,"payload.valueF%payload.valueJB58",4f); checkCalc(p,"payload.valueD%payload.valueJB58",4d); checkCalc(p,"payload.valueJ%payload.valueJB58",4L); checkCalc(p,"payload.valueI%payload.valueJB58",4L); // right is an int checkCalc(p,"payload.valueSB%58",4); checkCalc(p,"payload.valueBB%58",4); checkCalc(p,"payload.valueFB%58",4f); checkCalc(p,"payload.valueDB%58",4d); checkCalc(p,"payload.valueJB%58",4L); checkCalc(p,"payload.valueIB%58",4); checkCalc(p,"payload.valueS%58",4); checkCalc(p,"payload.valueB%58",4); checkCalc(p,"payload.valueF%58",4f); checkCalc(p,"payload.valueD%58",4d); checkCalc(p,"payload.valueJ%58",4L); checkCalc(p,"payload.valueI%58",4); checkCalc(p,"payload.valueSB%payload.valueIB58",4); checkCalc(p,"payload.valueBB%payload.valueIB58",4); checkCalc(p,"payload.valueFB%payload.valueIB58",4f); checkCalc(p,"payload.valueDB%payload.valueIB58",4d); checkCalc(p,"payload.valueJB%payload.valueIB58",4L); checkCalc(p,"payload.valueIB%payload.valueIB58",4); checkCalc(p,"payload.valueS%payload.valueIB58",4); checkCalc(p,"payload.valueB%payload.valueIB58",4); checkCalc(p,"payload.valueF%payload.valueIB58",4f); checkCalc(p,"payload.valueD%payload.valueIB58",4d); checkCalc(p,"payload.valueJ%payload.valueIB58",4L); checkCalc(p,"payload.valueI%payload.valueIB58",4); // right is a short checkCalc(p,"payload.valueSB%payload.valueS18",12); checkCalc(p,"payload.valueBB%payload.valueS18",12); checkCalc(p,"payload.valueFB%payload.valueS18",12f); checkCalc(p,"payload.valueDB%payload.valueS18",12d); checkCalc(p,"payload.valueJB%payload.valueS18",12L); checkCalc(p,"payload.valueIB%payload.valueS18",12); checkCalc(p,"payload.valueS%payload.valueS18",12); checkCalc(p,"payload.valueB%payload.valueS18",12); checkCalc(p,"payload.valueF%payload.valueS18",12f); checkCalc(p,"payload.valueD%payload.valueS18",12d); checkCalc(p,"payload.valueJ%payload.valueS18",12L); checkCalc(p,"payload.valueI%payload.valueS18",12); checkCalc(p,"payload.valueSB%payload.valueSB18",12); checkCalc(p,"payload.valueBB%payload.valueSB18",12); checkCalc(p,"payload.valueFB%payload.valueSB18",12f); checkCalc(p,"payload.valueDB%payload.valueSB18",12d); checkCalc(p,"payload.valueJB%payload.valueSB18",12L); checkCalc(p,"payload.valueIB%payload.valueSB18",12); checkCalc(p,"payload.valueS%payload.valueSB18",12); checkCalc(p,"payload.valueB%payload.valueSB18",12); checkCalc(p,"payload.valueF%payload.valueSB18",12f); checkCalc(p,"payload.valueD%payload.valueSB18",12d); checkCalc(p,"payload.valueJ%payload.valueSB18",12L); checkCalc(p,"payload.valueI%payload.valueSB18",12); // right is a byte checkCalc(p,"payload.valueSB%payload.valueB18",12); checkCalc(p,"payload.valueBB%payload.valueB18",12); checkCalc(p,"payload.valueFB%payload.valueB18",12f); checkCalc(p,"payload.valueDB%payload.valueB18",12d); checkCalc(p,"payload.valueJB%payload.valueB18",12L); checkCalc(p,"payload.valueIB%payload.valueB18",12); checkCalc(p,"payload.valueS%payload.valueB18",12); checkCalc(p,"payload.valueB%payload.valueB18",12); checkCalc(p,"payload.valueF%payload.valueB18",12f); checkCalc(p,"payload.valueD%payload.valueB18",12d); checkCalc(p,"payload.valueJ%payload.valueB18",12L); checkCalc(p,"payload.valueI%payload.valueB18",12); checkCalc(p,"payload.valueSB%payload.valueBB18",12); checkCalc(p,"payload.valueBB%payload.valueBB18",12); checkCalc(p,"payload.valueFB%payload.valueBB18",12f); checkCalc(p,"payload.valueDB%payload.valueBB18",12d); checkCalc(p,"payload.valueJB%payload.valueBB18",12L); checkCalc(p,"payload.valueIB%payload.valueBB18",12); checkCalc(p,"payload.valueS%payload.valueBB18",12); checkCalc(p,"payload.valueB%payload.valueBB18",12); checkCalc(p,"payload.valueF%payload.valueBB18",12f); checkCalc(p,"payload.valueD%payload.valueBB18",12d); checkCalc(p,"payload.valueJ%payload.valueBB18",12L); checkCalc(p,"payload.valueI%payload.valueBB18",12); } @Test public void opMultiply() throws Exception { expression = parse("2*2"); expression.getValue(); assertCanCompile(expression); assertEquals(4, expression.getValue()); expression = parse("2L*2L"); expression.getValue(); assertCanCompile(expression); assertEquals(4L, expression.getValue()); expression = parse("2.0f*2.0f"); expression.getValue(); assertCanCompile(expression); assertEquals(4.0f, expression.getValue()); expression = parse("3.0d*4.0d"); expression.getValue(); assertCanCompile(expression); assertEquals(12.0d, expression.getValue()); expression = parse("T(Float).valueOf(2.0f)*6"); assertEquals(12.0f, expression.getValue()); assertCanCompile(expression); assertEquals(12.0f, expression.getValue()); expression = parse("T(Float).valueOf(8.0f)*T(Float).valueOf(3.0f)"); assertEquals(24.0f, expression.getValue()); assertCanCompile(expression); assertEquals(24.0f, expression.getValue()); expression = parse("11L*T(Long).valueOf(4L)"); assertEquals(44L, expression.getValue()); assertCanCompile(expression); assertEquals(44L, expression.getValue()); expression = parse("T(Long).valueOf(9L)*6"); assertEquals(54L, expression.getValue()); assertCanCompile(expression); assertEquals(54L, expression.getValue()); expression = parse("T(Long).valueOf(4L)*T(Long).valueOf(3L)"); assertEquals(12L, expression.getValue()); assertCanCompile(expression); assertEquals(12L, expression.getValue()); expression = parse("8L*T(Long).valueOf(2L)"); assertEquals(16L, expression.getValue()); assertCanCompile(expression); assertEquals(16L, expression.getValue()); expression = parse("T(Float).valueOf(8.0f)*-T(Float).valueOf(3.0f)"); assertEquals(-24.0f, expression.getValue()); assertCanCompile(expression); assertEquals(-24.0f, expression.getValue()); } @Test public void opDivide() throws Exception { expression = parse("2/2"); expression.getValue(); assertCanCompile(expression); assertEquals(1, expression.getValue()); expression = parse("2L/2L"); expression.getValue(); assertCanCompile(expression); assertEquals(1L, expression.getValue()); expression = parse("2.0f/2.0f"); expression.getValue(); assertCanCompile(expression); assertEquals(1.0f, expression.getValue()); expression = parse("3.0d/4.0d"); expression.getValue(); assertCanCompile(expression); assertEquals(0.75d, expression.getValue()); expression = parse("T(Float).valueOf(6.0f)/2"); assertEquals(3.0f, expression.getValue()); assertCanCompile(expression); assertEquals(3.0f, expression.getValue()); expression = parse("T(Float).valueOf(8.0f)/T(Float).valueOf(2.0f)"); assertEquals(4.0f, expression.getValue()); assertCanCompile(expression); assertEquals(4.0f, expression.getValue()); expression = parse("12L/T(Long).valueOf(4L)"); assertEquals(3L, expression.getValue()); assertCanCompile(expression); assertEquals(3L, expression.getValue()); expression = parse("T(Long).valueOf(44L)/11"); assertEquals(4L, expression.getValue()); assertCanCompile(expression); assertEquals(4L, expression.getValue()); expression = parse("T(Long).valueOf(4L)/T(Long).valueOf(2L)"); assertEquals(2L, expression.getValue()); assertCanCompile(expression); assertEquals(2L, expression.getValue()); expression = parse("8L/T(Long).valueOf(2L)"); assertEquals(4L, expression.getValue()); assertCanCompile(expression); assertEquals(4L, expression.getValue()); expression = parse("T(Float).valueOf(8.0f)/-T(Float).valueOf(4.0f)"); assertEquals(-2.0f, expression.getValue()); assertCanCompile(expression); assertEquals(-2.0f, expression.getValue()); } @Test public void opModulus_12041() throws Exception { expression = parse("2%2"); assertEquals(0, expression.getValue()); assertCanCompile(expression); assertEquals(0, expression.getValue()); expression = parse("payload%2==0"); assertTrue(expression.getValue(new GenericMessageTestHelper<>(4), Boolean.TYPE)); assertFalse(expression.getValue(new GenericMessageTestHelper<>(5), Boolean.TYPE)); assertCanCompile(expression); assertTrue(expression.getValue(new GenericMessageTestHelper<>(4), Boolean.TYPE)); assertFalse(expression.getValue(new GenericMessageTestHelper<>(5), Boolean.TYPE)); expression = parse("8%3"); assertEquals(2, expression.getValue()); assertCanCompile(expression); assertEquals(2, expression.getValue()); expression = parse("17L%5L"); assertEquals(2L, expression.getValue()); assertCanCompile(expression); assertEquals(2L, expression.getValue()); expression = parse("3.0f%2.0f"); assertEquals(1.0f, expression.getValue()); assertCanCompile(expression); assertEquals(1.0f, expression.getValue()); expression = parse("3.0d%4.0d"); assertEquals(3.0d, expression.getValue()); assertCanCompile(expression); assertEquals(3.0d, expression.getValue()); expression = parse("T(Float).valueOf(6.0f)%2"); assertEquals(0.0f, expression.getValue()); assertCanCompile(expression); assertEquals(0.0f, expression.getValue()); expression = parse("T(Float).valueOf(6.0f)%4"); assertEquals(2.0f, expression.getValue()); assertCanCompile(expression); assertEquals(2.0f, expression.getValue()); expression = parse("T(Float).valueOf(8.0f)%T(Float).valueOf(3.0f)"); assertEquals(2.0f, expression.getValue()); assertCanCompile(expression); assertEquals(2.0f, expression.getValue()); expression = parse("13L%T(Long).valueOf(4L)"); assertEquals(1L, expression.getValue()); assertCanCompile(expression); assertEquals(1L, expression.getValue()); expression = parse("T(Long).valueOf(44L)%12"); assertEquals(8L, expression.getValue()); assertCanCompile(expression); assertEquals(8L, expression.getValue()); expression = parse("T(Long).valueOf(9L)%T(Long).valueOf(2L)"); assertEquals(1L, expression.getValue()); assertCanCompile(expression); assertEquals(1L, expression.getValue()); expression = parse("7L%T(Long).valueOf(2L)"); assertEquals(1L, expression.getValue()); assertCanCompile(expression); assertEquals(1L, expression.getValue()); expression = parse("T(Float).valueOf(9.0f)%-T(Float).valueOf(4.0f)"); assertEquals(1.0f, expression.getValue()); assertCanCompile(expression); assertEquals(1.0f, expression.getValue()); } @Test public void failsWhenSettingContextForExpression_SPR12326() { SpelExpressionParser parser = new SpelExpressionParser( new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, getClass().getClassLoader())); Person3 person = new Person3("foo", 1); SpelExpression expression = parser.parseRaw("#it?.age?.equals([0])"); StandardEvaluationContext context = new StandardEvaluationContext(new Object[] { 1 }); context.setVariable("it", person); expression.setEvaluationContext(context); assertTrue(expression.getValue(Boolean.class)); assertTrue(expression.getValue(Boolean.class)); assertCanCompile(expression); assertTrue(expression.getValue(Boolean.class)); } /** * Test variants of using T(...) and static/non-static method/property/field references. */ @Test public void constructorReference_SPR13781() { // Static field access on a T() referenced type expression = parser.parseExpression("T(java.util.Locale).ENGLISH"); assertEquals("en", expression.getValue().toString()); assertCanCompile(expression); assertEquals("en", expression.getValue().toString()); // The actual expression from the bug report. It fails if the ENGLISH reference fails // to pop the type reference for Locale off the stack (if it isn't popped then // toLowerCase() will be called with a Locale parameter). In this situation the // code generation for ENGLISH should notice there is something on the stack that // is not required and pop it off. expression = parser.parseExpression("#userId.toString().toLowerCase(T(java.util.Locale).ENGLISH)"); StandardEvaluationContext context = new StandardEvaluationContext(); context.setVariable("userId", "RoDnEy"); assertEquals("rodney", expression.getValue(context)); assertCanCompile(expression); assertEquals("rodney", expression.getValue(context)); // Property access on a class object expression = parser.parseExpression("T(String).name"); assertEquals("java.lang.String", expression.getValue()); assertCanCompile(expression); assertEquals("java.lang.String", expression.getValue()); // Now the type reference isn't on the stack, and needs loading context = new StandardEvaluationContext(String.class); expression = parser.parseExpression("name"); assertEquals("java.lang.String", expression.getValue(context)); assertCanCompile(expression); assertEquals("java.lang.String", expression.getValue(context)); expression = parser.parseExpression("T(String).getName()"); assertEquals("java.lang.String", expression.getValue()); assertCanCompile(expression); assertEquals("java.lang.String", expression.getValue()); // These tests below verify that the chain of static accesses (either method/property or field) // leave the right thing on top of the stack for processing by any outer consuming code. // Here the consuming code is the String.valueOf() function. If the wrong thing were on // the stack (for example if the compiled code for static methods wasn't popping the // previous thing off the stack) the valueOf() would operate on the wrong value. String shclass = StaticsHelper.class.getName(); // Basic chain: property access then method access expression = parser.parseExpression("T(String).valueOf(T(String).name.valueOf(1))"); assertEquals("1", expression.getValue()); assertCanCompile(expression); assertEquals("1", expression.getValue()); // chain of statics ending with static method expression = parser.parseExpression("T(String).valueOf(T(" + shclass + ").methoda().methoda().methodb())"); assertEquals("mb", expression.getValue()); assertCanCompile(expression); assertEquals("mb", expression.getValue()); // chain of statics ending with static field expression = parser.parseExpression("T(String).valueOf(T(" + shclass + ").fielda.fielda.fieldb)"); assertEquals("fb", expression.getValue()); assertCanCompile(expression); assertEquals("fb", expression.getValue()); // chain of statics ending with static property access expression = parser.parseExpression("T(String).valueOf(T(" + shclass + ").propertya.propertya.propertyb)"); assertEquals("pb", expression.getValue()); assertCanCompile(expression); assertEquals("pb", expression.getValue()); // variety chain expression = parser.parseExpression("T(String).valueOf(T(" + shclass + ").fielda.methoda().propertya.fieldb)"); assertEquals("fb", expression.getValue()); assertCanCompile(expression); assertEquals("fb", expression.getValue()); expression = parser.parseExpression("T(String).valueOf(fielda.fieldb)"); assertEquals("fb", expression.getValue(StaticsHelper.sh)); assertCanCompile(expression); assertEquals("fb", expression.getValue(StaticsHelper.sh)); expression = parser.parseExpression("T(String).valueOf(propertya.propertyb)"); assertEquals("pb", expression.getValue(StaticsHelper.sh)); assertCanCompile(expression); assertEquals("pb", expression.getValue(StaticsHelper.sh)); expression = parser.parseExpression("T(String).valueOf(methoda().methodb())"); assertEquals("mb", expression.getValue(StaticsHelper.sh)); assertCanCompile(expression); assertEquals("mb", expression.getValue(StaticsHelper.sh)); } @Test public void constructorReference_SPR12326() { String type = getClass().getName(); String prefix = "new " + type + ".Obj"; expression = parser.parseExpression(prefix + "([0])"); assertEquals("test", ((Obj) expression.getValue(new Object[] {"test"})).param1); assertCanCompile(expression); assertEquals("test", ((Obj) expression.getValue(new Object[] {"test"})).param1); expression = parser.parseExpression(prefix + "2('foo','bar').output"); assertEquals("foobar", expression.getValue(String.class)); assertCanCompile(expression); assertEquals("foobar", expression.getValue(String.class)); expression = parser.parseExpression(prefix + "2('foo').output"); assertEquals("foo", expression.getValue(String.class)); assertCanCompile(expression); assertEquals("foo", expression.getValue(String.class)); expression = parser.parseExpression(prefix + "2().output"); assertEquals("", expression.getValue(String.class)); assertCanCompile(expression); assertEquals("", expression.getValue(String.class)); expression = parser.parseExpression(prefix + "3(1,2,3).output"); assertEquals("123", expression.getValue(String.class)); assertCanCompile(expression); assertEquals("123", expression.getValue(String.class)); expression = parser.parseExpression(prefix + "3(1).output"); assertEquals("1", expression.getValue(String.class)); assertCanCompile(expression); assertEquals("1", expression.getValue(String.class)); expression = parser.parseExpression(prefix + "3().output"); assertEquals("", expression.getValue(String.class)); assertCanCompile(expression); assertEquals("", expression.getValue(String.class)); expression = parser.parseExpression(prefix + "3('abc',5.0f,1,2,3).output"); assertEquals("abc:5.0:123", expression.getValue(String.class)); assertCanCompile(expression); assertEquals("abc:5.0:123", expression.getValue(String.class)); expression = parser.parseExpression(prefix + "3('abc',5.0f,1).output"); assertEquals("abc:5.0:1", expression.getValue(String.class)); assertCanCompile(expression); assertEquals("abc:5.0:1", expression.getValue(String.class)); expression = parser.parseExpression(prefix + "3('abc',5.0f).output"); assertEquals("abc:5.0:", expression.getValue(String.class)); assertCanCompile(expression); assertEquals("abc:5.0:", expression.getValue(String.class)); expression = parser.parseExpression(prefix + "4(#root).output"); assertEquals("123", expression.getValue(new int[] {1,2,3}, String.class)); assertCanCompile(expression); assertEquals("123", expression.getValue(new int[] {1,2,3}, String.class)); } @Test public void methodReferenceMissingCastAndRootObjectAccessing_SPR12326() { // Need boxing code on the 1 so that toString() can be called expression = parser.parseExpression("1.toString()"); assertEquals("1", expression.getValue()); assertCanCompile(expression); assertEquals("1", expression.getValue()); expression = parser.parseExpression("#it?.age.equals([0])"); Person person = new Person(1); StandardEvaluationContext context = new StandardEvaluationContext(new Object[] { person.getAge() }); context.setVariable("it", person); assertTrue(expression.getValue(context, Boolean.class)); assertCanCompile(expression); assertTrue(expression.getValue(context, Boolean.class)); // Variant of above more like what was in the bug report: SpelExpressionParser parser = new SpelExpressionParser( new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, getClass().getClassLoader())); SpelExpression ex = parser.parseRaw("#it?.age.equals([0])"); context = new StandardEvaluationContext(new Object[] { person.getAge() }); context.setVariable("it", person); assertTrue(ex.getValue(context, Boolean.class)); assertTrue(ex.getValue(context, Boolean.class)); PersonInOtherPackage person2 = new PersonInOtherPackage(1); ex = parser.parseRaw("#it?.age.equals([0])"); context = new StandardEvaluationContext(new Object[] { person2.getAge() }); context.setVariable("it", person2); assertTrue(ex.getValue(context, Boolean.class)); assertTrue(ex.getValue(context, Boolean.class)); ex = parser.parseRaw("#it?.age.equals([0])"); context = new StandardEvaluationContext(new Object[] { person2.getAge() }); context.setVariable("it", person2); assertTrue((Boolean)ex.getValue(context)); assertTrue((Boolean)ex.getValue(context)); } @Test public void constructorReference() throws Exception { // simple ctor expression = parser.parseExpression("new String('123')"); assertEquals("123", expression.getValue()); assertCanCompile(expression); assertEquals("123", expression.getValue()); String testclass8 = "org.springframework.expression.spel.SpelCompilationCoverageTests$TestClass8"; // multi arg ctor that includes primitives expression = parser.parseExpression("new " + testclass8 + "(42,'123',4.0d,true)"); assertEquals(testclass8, expression.getValue().getClass().getName()); assertCanCompile(expression); Object o = expression.getValue(); assertEquals(testclass8,o.getClass().getName()); TestClass8 tc8 = (TestClass8)o; assertEquals(42, tc8.i); assertEquals("123", tc8.s); assertEquals(4.0d, tc8.d,0.5d); assertEquals(true, tc8.z); // no-arg ctor expression = parser.parseExpression("new " + testclass8 + "()"); assertEquals(testclass8, expression.getValue().getClass().getName()); assertCanCompile(expression); o = expression.getValue(); assertEquals(testclass8,o.getClass().getName()); // pass primitive to reference type ctor expression = parser.parseExpression("new " + testclass8 + "(42)"); assertEquals(testclass8, expression.getValue().getClass().getName()); assertCanCompile(expression); o = expression.getValue(); assertEquals(testclass8,o.getClass().getName()); tc8 = (TestClass8) o; assertEquals(42, tc8.i); // private class, can't compile it String testclass9 = "org.springframework.expression.spel.SpelCompilationCoverageTests$TestClass9"; expression = parser.parseExpression("new " + testclass9 + "(42)"); assertEquals(testclass9, expression.getValue().getClass().getName()); assertCantCompile(expression); } @Test public void methodReferenceReflectiveMethodSelectionWithVarargs() throws Exception { TestClass10 tc = new TestClass10(); // Should call the non varargs version of concat // (which causes the '::' prefix in test output) expression = parser.parseExpression("concat('test')"); assertCantCompile(expression); expression.getValue(tc); assertEquals("::test", tc.s); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals("::test", tc.s); tc.reset(); // This will call the varargs concat with an empty array expression = parser.parseExpression("concat()"); assertCantCompile(expression); expression.getValue(tc); assertEquals("", tc.s); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals("", tc.s); tc.reset(); // Should call the non varargs version of concat // (which causes the '::' prefix in test output) expression = parser.parseExpression("concat2('test')"); assertCantCompile(expression); expression.getValue(tc); assertEquals("::test", tc.s); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals("::test", tc.s); tc.reset(); // This will call the varargs concat with an empty array expression = parser.parseExpression("concat2()"); assertCantCompile(expression); expression.getValue(tc); assertEquals("", tc.s); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals("", tc.s); tc.reset(); } @Test public void methodReferenceVarargs() throws Exception { TestClass5 tc = new TestClass5(); // varargs string expression = parser.parseExpression("eleven()"); assertCantCompile(expression); expression.getValue(tc); assertEquals("", tc.s); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals("", tc.s); tc.reset(); // varargs string expression = parser.parseExpression("eleven('aaa')"); assertCantCompile(expression); expression.getValue(tc); assertEquals("aaa", tc.s); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals("aaa", tc.s); tc.reset(); // varargs string expression = parser.parseExpression("eleven(stringArray)"); assertCantCompile(expression); expression.getValue(tc); assertEquals("aaabbbccc", tc.s); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals("aaabbbccc", tc.s); tc.reset(); // varargs string expression = parser.parseExpression("eleven('aaa','bbb','ccc')"); assertCantCompile(expression); expression.getValue(tc); assertEquals("aaabbbccc", tc.s); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals("aaabbbccc", tc.s); tc.reset(); expression = parser.parseExpression("sixteen('aaa','bbb','ccc')"); assertCantCompile(expression); expression.getValue(tc); assertEquals("aaabbbccc", tc.s); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals("aaabbbccc", tc.s); tc.reset(); // TODO Fails related to conversion service converting a String[] to satisfy Object... // expression = parser.parseExpression("sixteen(stringArray)"); // assertCantCompile(expression); // expression.getValue(tc); // assertEquals("aaabbbccc", tc.s); // assertCanCompile(expression); // tc.reset(); // expression.getValue(tc); // assertEquals("aaabbbccc", tc.s); // tc.reset(); // varargs int expression = parser.parseExpression("twelve(1,2,3)"); assertCantCompile(expression); expression.getValue(tc); assertEquals(6, tc.i); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals(6, tc.i); tc.reset(); expression = parser.parseExpression("twelve(1)"); assertCantCompile(expression); expression.getValue(tc); assertEquals(1, tc.i); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals(1, tc.i); tc.reset(); // one string then varargs string expression = parser.parseExpression("thirteen('aaa','bbb','ccc')"); assertCantCompile(expression); expression.getValue(tc); assertEquals("aaa::bbbccc", tc.s); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals("aaa::bbbccc", tc.s); tc.reset(); // nothing passed to varargs parameter expression = parser.parseExpression("thirteen('aaa')"); assertCantCompile(expression); expression.getValue(tc); assertEquals("aaa::", tc.s); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals("aaa::", tc.s); tc.reset(); // nested arrays expression = parser.parseExpression("fourteen('aaa',stringArray,stringArray)"); assertCantCompile(expression); expression.getValue(tc); assertEquals("aaa::{aaabbbccc}{aaabbbccc}", tc.s); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals("aaa::{aaabbbccc}{aaabbbccc}", tc.s); tc.reset(); // nested primitive array expression = parser.parseExpression("fifteen('aaa',intArray,intArray)"); assertCantCompile(expression); expression.getValue(tc); assertEquals("aaa::{112233}{112233}", tc.s); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals("aaa::{112233}{112233}", tc.s); tc.reset(); // varargs boolean expression = parser.parseExpression("arrayz(true,true,false)"); assertCantCompile(expression); expression.getValue(tc); assertEquals("truetruefalse", tc.s); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals("truetruefalse", tc.s); tc.reset(); expression = parser.parseExpression("arrayz(true)"); assertCantCompile(expression); expression.getValue(tc); assertEquals("true", tc.s); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals("true", tc.s); tc.reset(); // varargs short expression = parser.parseExpression("arrays(s1,s2,s3)"); assertCantCompile(expression); expression.getValue(tc); assertEquals("123", tc.s); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals("123", tc.s); tc.reset(); expression = parser.parseExpression("arrays(s1)"); assertCantCompile(expression); expression.getValue(tc); assertEquals("1", tc.s); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals("1", tc.s); tc.reset(); // varargs double expression = parser.parseExpression("arrayd(1.0d,2.0d,3.0d)"); assertCantCompile(expression); expression.getValue(tc); assertEquals("1.02.03.0", tc.s); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals("1.02.03.0", tc.s); tc.reset(); expression = parser.parseExpression("arrayd(1.0d)"); assertCantCompile(expression); expression.getValue(tc); assertEquals("1.0", tc.s); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals("1.0", tc.s); tc.reset(); // varargs long expression = parser.parseExpression("arrayj(l1,l2,l3)"); assertCantCompile(expression); expression.getValue(tc); assertEquals("123", tc.s); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals("123", tc.s); tc.reset(); expression = parser.parseExpression("arrayj(l1)"); assertCantCompile(expression); expression.getValue(tc); assertEquals("1", tc.s); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals("1", tc.s); tc.reset(); // varargs char expression = parser.parseExpression("arrayc(c1,c2,c3)"); assertCantCompile(expression); expression.getValue(tc); assertEquals("abc", tc.s); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals("abc", tc.s); tc.reset(); expression = parser.parseExpression("arrayc(c1)"); assertCantCompile(expression); expression.getValue(tc); assertEquals("a", tc.s); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals("a", tc.s); tc.reset(); // varargs byte expression = parser.parseExpression("arrayb(b1,b2,b3)"); assertCantCompile(expression); expression.getValue(tc); assertEquals("656667", tc.s); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals("656667", tc.s); tc.reset(); expression = parser.parseExpression("arrayb(b1)"); assertCantCompile(expression); expression.getValue(tc); assertEquals("65", tc.s); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals("65", tc.s); tc.reset(); // varargs float expression = parser.parseExpression("arrayf(f1,f2,f3)"); assertCantCompile(expression); expression.getValue(tc); assertEquals("1.02.03.0", tc.s); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals("1.02.03.0", tc.s); tc.reset(); expression = parser.parseExpression("arrayf(f1)"); assertCantCompile(expression); expression.getValue(tc); assertEquals("1.0", tc.s); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals("1.0", tc.s); tc.reset(); } @Test public void methodReference() throws Exception { TestClass5 tc = new TestClass5(); // non-static method, no args, void return expression = parser.parseExpression("one()"); assertCantCompile(expression); expression.getValue(tc); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals(1, tc.i); tc.reset(); // static method, no args, void return expression = parser.parseExpression("two()"); assertCantCompile(expression); expression.getValue(tc); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals(1, TestClass5._i); tc.reset(); // non-static method, reference type return expression = parser.parseExpression("three()"); assertCantCompile(expression); expression.getValue(tc); assertCanCompile(expression); tc.reset(); assertEquals("hello", expression.getValue(tc)); tc.reset(); // non-static method, primitive type return expression = parser.parseExpression("four()"); assertCantCompile(expression); expression.getValue(tc); assertCanCompile(expression); tc.reset(); assertEquals(3277700L, expression.getValue(tc)); tc.reset(); // static method, reference type return expression = parser.parseExpression("five()"); assertCantCompile(expression); expression.getValue(tc); assertCanCompile(expression); tc.reset(); assertEquals("hello", expression.getValue(tc)); tc.reset(); // static method, primitive type return expression = parser.parseExpression("six()"); assertCantCompile(expression); expression.getValue(tc); assertCanCompile(expression); tc.reset(); assertEquals(3277700L, expression.getValue(tc)); tc.reset(); // non-static method, one parameter of reference type expression = parser.parseExpression("seven(\"foo\")"); assertCantCompile(expression); expression.getValue(tc); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals("foo", tc.s); tc.reset(); // static method, one parameter of reference type expression = parser.parseExpression("eight(\"bar\")"); assertCantCompile(expression); expression.getValue(tc); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals("bar", TestClass5._s); tc.reset(); // non-static method, one parameter of primitive type expression = parser.parseExpression("nine(231)"); assertCantCompile(expression); expression.getValue(tc); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals(231, tc.i); tc.reset(); // static method, one parameter of primitive type expression = parser.parseExpression("ten(111)"); assertCantCompile(expression); expression.getValue(tc); assertCanCompile(expression); tc.reset(); expression.getValue(tc); assertEquals(111, TestClass5._i); tc.reset(); // method that gets type converted parameters // Converting from an int to a string expression = parser.parseExpression("seven(123)"); assertCantCompile(expression); expression.getValue(tc); assertEquals("123", tc.s); assertCantCompile(expression); // Uncompilable as argument conversion is occurring Expression expression = parser.parseExpression("'abcd'.substring(index1,index2)"); String resultI = expression.getValue(new TestClass1(), String.class); assertCanCompile(expression); String resultC = expression.getValue(new TestClass1(), String.class); assertEquals("bc", resultI); assertEquals("bc", resultC); // Converting from an int to a Number expression = parser.parseExpression("takeNumber(123)"); assertCantCompile(expression); expression.getValue(tc); assertEquals("123", tc.s); tc.reset(); assertCanCompile(expression); // The generated code should include boxing of the int to a Number expression.getValue(tc); assertEquals("123", tc.s); // Passing a subtype expression = parser.parseExpression("takeNumber(T(Integer).valueOf(42))"); assertCantCompile(expression); expression.getValue(tc); assertEquals("42", tc.s); tc.reset(); assertCanCompile(expression); // The generated code should include boxing of the int to a Number expression.getValue(tc); assertEquals("42", tc.s); // Passing a subtype expression = parser.parseExpression("takeString(T(Integer).valueOf(42))"); assertCantCompile(expression); expression.getValue(tc); assertEquals("42", tc.s); tc.reset(); assertCantCompile(expression); // method takes a string and we are passing an Integer } @Test public void errorHandling() throws Exception { TestClass5 tc = new TestClass5(); // changing target // from primitive array to reference type array int[] is = new int[] {1,2,3}; String[] strings = new String[] {"a","b","c"}; expression = parser.parseExpression("[1]"); assertEquals(2, expression.getValue(is)); assertCanCompile(expression); assertEquals(2, expression.getValue(is)); try { assertEquals(2, expression.getValue(strings)); fail(); } catch (SpelEvaluationException see) { assertTrue(see.getCause() instanceof ClassCastException); } SpelCompiler.revertToInterpreted(expression); assertEquals("b", expression.getValue(strings)); assertCanCompile(expression); assertEquals("b", expression.getValue(strings)); tc.field = "foo"; expression = parser.parseExpression("seven(field)"); assertCantCompile(expression); expression.getValue(tc); assertEquals("foo", tc.s); assertCanCompile(expression); tc.reset(); tc.field="bar"; expression.getValue(tc); // method with changing parameter types (change reference type) tc.obj = "foo"; expression = parser.parseExpression("seven(obj)"); assertCantCompile(expression); expression.getValue(tc); assertEquals("foo", tc.s); assertCanCompile(expression); tc.reset(); tc.obj=new Integer(42); try { expression.getValue(tc); fail(); } catch (SpelEvaluationException see) { assertTrue(see.getCause() instanceof ClassCastException); } // method with changing target expression = parser.parseExpression("#root.charAt(0)"); assertEquals('a', expression.getValue("abc")); assertCanCompile(expression); try { expression.getValue(new Integer(42)); fail(); } catch (SpelEvaluationException see) { // java.lang.Integer cannot be cast to java.lang.String assertTrue(see.getCause() instanceof ClassCastException); } } @Test public void methodReference_staticMethod() throws Exception { Expression expression = parser.parseExpression("T(Integer).valueOf(42)"); int resultI = expression.getValue(new TestClass1(), Integer.TYPE); assertCanCompile(expression); int resultC = expression.getValue(new TestClass1(), Integer.TYPE); assertEquals(42, resultI); assertEquals(42, resultC); } @Test public void methodReference_literalArguments_int() throws Exception { Expression expression = parser.parseExpression("'abcd'.substring(1,3)"); String resultI = expression.getValue(new TestClass1(), String.class); assertCanCompile(expression); String resultC = expression.getValue(new TestClass1(), String.class); assertEquals("bc", resultI); assertEquals("bc", resultC); } @Test public void methodReference_simpleInstanceMethodNoArg() throws Exception { Expression expression = parser.parseExpression("toString()"); String resultI = expression.getValue(42, String.class); assertCanCompile(expression); String resultC = expression.getValue(42, String.class); assertEquals("42", resultI); assertEquals("42", resultC); } @Test public void methodReference_simpleInstanceMethodNoArgReturnPrimitive() throws Exception { expression = parser.parseExpression("intValue()"); int resultI = expression.getValue(new Integer(42), Integer.TYPE); assertEquals(42, resultI); assertCanCompile(expression); int resultC = expression.getValue(new Integer(42), Integer.TYPE); assertEquals(42, resultC); } @Test public void methodReference_simpleInstanceMethodOneArgReturnPrimitive1() throws Exception { Expression expression = parser.parseExpression("indexOf('b')"); int resultI = expression.getValue("abc", Integer.TYPE); assertCanCompile(expression); int resultC = expression.getValue("abc", Integer.TYPE); assertEquals(1, resultI); assertEquals(1, resultC); } @Test public void methodReference_simpleInstanceMethodOneArgReturnPrimitive2() throws Exception { expression = parser.parseExpression("charAt(2)"); char resultI = expression.getValue("abc", Character.TYPE); assertEquals('c', resultI); assertCanCompile(expression); char resultC = expression.getValue("abc", Character.TYPE); assertEquals('c', resultC); } @Test public void compoundExpression() throws Exception { Payload payload = new Payload(); expression = parser.parseExpression("DR[0]"); assertEquals("instanceof Two", expression.getValue(payload).toString()); assertCanCompile(expression); assertEquals("instanceof Two", expression.getValue(payload).toString()); ast = getAst(); assertEquals("Lorg/springframework/expression/spel/SpelCompilationCoverageTests$Two", ast.getExitDescriptor()); expression = parser.parseExpression("holder.three"); assertEquals("org.springframework.expression.spel.SpelCompilationCoverageTests$Three", expression.getValue(payload).getClass().getName()); assertCanCompile(expression); assertEquals("org.springframework.expression.spel.SpelCompilationCoverageTests$Three", expression.getValue(payload).getClass().getName()); ast = getAst(); assertEquals("Lorg/springframework/expression/spel/SpelCompilationCoverageTests$Three", ast.getExitDescriptor()); expression = parser.parseExpression("DR[0]"); assertEquals("org.springframework.expression.spel.SpelCompilationCoverageTests$Two", expression.getValue(payload).getClass().getName()); assertCanCompile(expression); assertEquals("org.springframework.expression.spel.SpelCompilationCoverageTests$Two", expression.getValue(payload).getClass().getName()); assertEquals("Lorg/springframework/expression/spel/SpelCompilationCoverageTests$Two", getAst().getExitDescriptor()); expression = parser.parseExpression("DR[0].three"); assertEquals("org.springframework.expression.spel.SpelCompilationCoverageTests$Three", expression.getValue(payload).getClass().getName()); assertCanCompile(expression); assertEquals("org.springframework.expression.spel.SpelCompilationCoverageTests$Three", expression.getValue(payload).getClass().getName()); ast = getAst(); assertEquals("Lorg/springframework/expression/spel/SpelCompilationCoverageTests$Three", ast.getExitDescriptor()); expression = parser.parseExpression("DR[0].three.four"); assertEquals(0.04d, expression.getValue(payload)); assertCanCompile(expression); assertEquals(0.04d, expression.getValue(payload)); assertEquals("D", getAst().getExitDescriptor()); } @Test public void mixingItUp_indexerOpEqTernary() throws Exception { Map<String, String> m = new HashMap<>(); m.put("andy","778"); expression = parse("['andy']==null?1:2"); assertEquals(2, expression.getValue(m)); assertCanCompile(expression); assertEquals(2, expression.getValue(m)); m.remove("andy"); assertEquals(1, expression.getValue(m)); } @Test public void propertyReference() throws Exception { TestClass6 tc = new TestClass6(); // non static field expression = parser.parseExpression("orange"); assertCantCompile(expression); assertEquals("value1", expression.getValue(tc)); assertCanCompile(expression); assertEquals("value1", expression.getValue(tc)); // static field expression = parser.parseExpression("apple"); assertCantCompile(expression); assertEquals("value2", expression.getValue(tc)); assertCanCompile(expression); assertEquals("value2", expression.getValue(tc)); // non static getter expression = parser.parseExpression("banana"); assertCantCompile(expression); assertEquals("value3", expression.getValue(tc)); assertCanCompile(expression); assertEquals("value3", expression.getValue(tc)); // static getter expression = parser.parseExpression("plum"); assertCantCompile(expression); assertEquals("value4", expression.getValue(tc)); assertCanCompile(expression); assertEquals("value4", expression.getValue(tc)); } @Test public void propertyReferenceVisibility() { // SPR-12771 StandardEvaluationContext ctx = new StandardEvaluationContext(); ctx.setVariable("httpServletRequest", HttpServlet3RequestFactory.getOne()); // Without a fix compilation was inserting a checkcast to a private type expression = parser.parseExpression("#httpServletRequest.servletPath"); assertEquals("wibble", expression.getValue(ctx)); assertCanCompile(expression); assertEquals("wibble", expression.getValue(ctx)); } @SuppressWarnings("unchecked") @Test public void indexer() throws Exception { String[] sss = new String[] {"a","b","c"}; Number[] ns = new Number[] {2,8,9}; int[] is = new int[] {8,9,10}; double[] ds = new double[] {3.0d,4.0d,5.0d}; long[] ls = new long[] {2L,3L,4L}; short[] ss = new short[] {(short)33,(short)44,(short)55}; float[] fs = new float[] {6.0f,7.0f,8.0f}; byte[] bs = new byte[] {(byte)2,(byte)3,(byte)4}; char[] cs = new char[] {'a','b','c'}; // Access String (reference type) array expression = parser.parseExpression("[0]"); assertEquals("a", expression.getValue(sss)); assertCanCompile(expression); assertEquals("a", expression.getValue(sss)); assertEquals("Ljava/lang/String", getAst().getExitDescriptor()); expression = parser.parseExpression("[1]"); assertEquals(8, expression.getValue(ns)); assertCanCompile(expression); assertEquals(8, expression.getValue(ns)); assertEquals("Ljava/lang/Number", getAst().getExitDescriptor()); // Access int array expression = parser.parseExpression("[2]"); assertEquals(10, expression.getValue(is)); assertCanCompile(expression); assertEquals(10, expression.getValue(is)); assertEquals("I", getAst().getExitDescriptor()); // Access double array expression = parser.parseExpression("[1]"); assertEquals(4.0d, expression.getValue(ds)); assertCanCompile(expression); assertEquals(4.0d, expression.getValue(ds)); assertEquals("D", getAst().getExitDescriptor()); // Access long array expression = parser.parseExpression("[0]"); assertEquals(2L, expression.getValue(ls)); assertCanCompile(expression); assertEquals(2L, expression.getValue(ls)); assertEquals("J", getAst().getExitDescriptor()); // Access short array expression = parser.parseExpression("[2]"); assertEquals((short)55, expression.getValue(ss)); assertCanCompile(expression); assertEquals((short)55, expression.getValue(ss)); assertEquals("S", getAst().getExitDescriptor()); // Access float array expression = parser.parseExpression("[0]"); assertEquals(6.0f, expression.getValue(fs)); assertCanCompile(expression); assertEquals(6.0f, expression.getValue(fs)); assertEquals("F", getAst().getExitDescriptor()); // Access byte array expression = parser.parseExpression("[2]"); assertEquals((byte)4, expression.getValue(bs)); assertCanCompile(expression); assertEquals((byte)4, expression.getValue(bs)); assertEquals("B", getAst().getExitDescriptor()); // Access char array expression = parser.parseExpression("[1]"); assertEquals('b', expression.getValue(cs)); assertCanCompile(expression); assertEquals('b', expression.getValue(cs)); assertEquals("C", getAst().getExitDescriptor()); // Collections List<String> strings = new ArrayList<>(); strings.add("aaa"); strings.add("bbb"); strings.add("ccc"); expression = parser.parseExpression("[1]"); assertEquals("bbb", expression.getValue(strings)); assertCanCompile(expression); assertEquals("bbb", expression.getValue(strings)); assertEquals("Ljava/lang/Object", getAst().getExitDescriptor()); List<Integer> ints = new ArrayList<>(); ints.add(123); ints.add(456); ints.add(789); expression = parser.parseExpression("[2]"); assertEquals(789, expression.getValue(ints)); assertCanCompile(expression); assertEquals(789, expression.getValue(ints)); assertEquals("Ljava/lang/Object", getAst().getExitDescriptor()); // Maps Map<String, Integer> map1 = new HashMap<>(); map1.put("aaa", 111); map1.put("bbb", 222); map1.put("ccc", 333); expression = parser.parseExpression("['aaa']"); assertEquals(111, expression.getValue(map1)); assertCanCompile(expression); assertEquals(111, expression.getValue(map1)); assertEquals("Ljava/lang/Object", getAst().getExitDescriptor()); // Object TestClass6 tc = new TestClass6(); expression = parser.parseExpression("['orange']"); assertEquals("value1", expression.getValue(tc)); assertCanCompile(expression); assertEquals("value1", expression.getValue(tc)); assertEquals("Ljava/lang/String", getAst().getExitDescriptor()); expression = parser.parseExpression("['peach']"); assertEquals(34L, expression.getValue(tc)); assertCanCompile(expression); assertEquals(34L, expression.getValue(tc)); assertEquals("J", getAst().getExitDescriptor()); // getter expression = parser.parseExpression("['banana']"); assertEquals("value3", expression.getValue(tc)); assertCanCompile(expression); assertEquals("value3", expression.getValue(tc)); assertEquals("Ljava/lang/String", getAst().getExitDescriptor()); // list of arrays List<String[]> listOfStringArrays = new ArrayList<>(); listOfStringArrays.add(new String[] {"a","b","c"}); listOfStringArrays.add(new String[] {"d","e","f"}); expression = parser.parseExpression("[1]"); assertEquals("d e f", stringify(expression.getValue(listOfStringArrays))); assertCanCompile(expression); assertEquals("d e f", stringify(expression.getValue(listOfStringArrays))); assertEquals("Ljava/lang/Object", getAst().getExitDescriptor()); expression = parser.parseExpression("[1][0]"); assertEquals("d", stringify(expression.getValue(listOfStringArrays))); assertCanCompile(expression); assertEquals("d", stringify(expression.getValue(listOfStringArrays))); assertEquals("Ljava/lang/String", getAst().getExitDescriptor()); List<Integer[]> listOfIntegerArrays = new ArrayList<>(); listOfIntegerArrays.add(new Integer[] {1,2,3}); listOfIntegerArrays.add(new Integer[] {4,5,6}); expression = parser.parseExpression("[0]"); assertEquals("1 2 3", stringify(expression.getValue(listOfIntegerArrays))); assertCanCompile(expression); assertEquals("1 2 3", stringify(expression.getValue(listOfIntegerArrays))); assertEquals("Ljava/lang/Object", getAst().getExitDescriptor()); expression = parser.parseExpression("[0][1]"); assertEquals(2, expression.getValue(listOfIntegerArrays)); assertCanCompile(expression); assertEquals(2, expression.getValue(listOfIntegerArrays)); assertEquals("Ljava/lang/Integer", getAst().getExitDescriptor()); // array of lists List<String>[] stringArrayOfLists = new ArrayList[2]; stringArrayOfLists[0] = new ArrayList<>(); stringArrayOfLists[0].add("a"); stringArrayOfLists[0].add("b"); stringArrayOfLists[0].add("c"); stringArrayOfLists[1] = new ArrayList<>(); stringArrayOfLists[1].add("d"); stringArrayOfLists[1].add("e"); stringArrayOfLists[1].add("f"); expression = parser.parseExpression("[1]"); assertEquals("d e f", stringify(expression.getValue(stringArrayOfLists))); assertCanCompile(expression); assertEquals("d e f", stringify(expression.getValue(stringArrayOfLists))); assertEquals("Ljava/util/ArrayList", getAst().getExitDescriptor()); expression = parser.parseExpression("[1][2]"); assertEquals("f", stringify(expression.getValue(stringArrayOfLists))); assertCanCompile(expression); assertEquals("f", stringify(expression.getValue(stringArrayOfLists))); assertEquals("Ljava/lang/Object", getAst().getExitDescriptor()); // array of arrays String[][] referenceTypeArrayOfArrays = new String[][] {new String[] {"a","b","c"},new String[] {"d","e","f"}}; expression = parser.parseExpression("[1]"); assertEquals("d e f", stringify(expression.getValue(referenceTypeArrayOfArrays))); assertCanCompile(expression); assertEquals("[Ljava/lang/String", getAst().getExitDescriptor()); assertEquals("d e f", stringify(expression.getValue(referenceTypeArrayOfArrays))); assertEquals("[Ljava/lang/String", getAst().getExitDescriptor()); expression = parser.parseExpression("[1][2]"); assertEquals("f", stringify(expression.getValue(referenceTypeArrayOfArrays))); assertCanCompile(expression); assertEquals("f", stringify(expression.getValue(referenceTypeArrayOfArrays))); assertEquals("Ljava/lang/String", getAst().getExitDescriptor()); int[][] primitiveTypeArrayOfArrays = new int[][] {new int[] {1,2,3},new int[] {4,5,6}}; expression = parser.parseExpression("[1]"); assertEquals("4 5 6", stringify(expression.getValue(primitiveTypeArrayOfArrays))); assertCanCompile(expression); assertEquals("4 5 6", stringify(expression.getValue(primitiveTypeArrayOfArrays))); assertEquals("[I", getAst().getExitDescriptor()); expression = parser.parseExpression("[1][2]"); assertEquals("6", stringify(expression.getValue(primitiveTypeArrayOfArrays))); assertCanCompile(expression); assertEquals("6", stringify(expression.getValue(primitiveTypeArrayOfArrays))); assertEquals("I", getAst().getExitDescriptor()); // list of lists of reference types List<List<String>> listOfListOfStrings = new ArrayList<>(); List<String> list = new ArrayList<>(); list.add("a"); list.add("b"); list.add("c"); listOfListOfStrings.add(list); list = new ArrayList<>(); list.add("d"); list.add("e"); list.add("f"); listOfListOfStrings.add(list); expression = parser.parseExpression("[1]"); assertEquals("d e f", stringify(expression.getValue(listOfListOfStrings))); assertCanCompile(expression); assertEquals("Ljava/lang/Object", getAst().getExitDescriptor()); assertEquals("d e f", stringify(expression.getValue(listOfListOfStrings))); assertEquals("Ljava/lang/Object", getAst().getExitDescriptor()); expression = parser.parseExpression("[1][2]"); assertEquals("f", stringify(expression.getValue(listOfListOfStrings))); assertCanCompile(expression); assertEquals("f", stringify(expression.getValue(listOfListOfStrings))); assertEquals("Ljava/lang/Object", getAst().getExitDescriptor()); // Map of lists Map<String,List<String>> mapToLists = new HashMap<>(); list = new ArrayList<>(); list.add("a"); list.add("b"); list.add("c"); mapToLists.put("foo", list); expression = parser.parseExpression("['foo']"); assertEquals("a b c", stringify(expression.getValue(mapToLists))); assertCanCompile(expression); assertEquals("Ljava/lang/Object", getAst().getExitDescriptor()); assertEquals("a b c", stringify(expression.getValue(mapToLists))); assertEquals("Ljava/lang/Object", getAst().getExitDescriptor()); expression = parser.parseExpression("['foo'][2]"); assertEquals("c", stringify(expression.getValue(mapToLists))); assertCanCompile(expression); assertEquals("c", stringify(expression.getValue(mapToLists))); assertEquals("Ljava/lang/Object", getAst().getExitDescriptor()); // Map to array Map<String,int[]> mapToIntArray = new HashMap<>(); StandardEvaluationContext ctx = new StandardEvaluationContext(); ctx.addPropertyAccessor(new CompilableMapAccessor()); mapToIntArray.put("foo",new int[] {1,2,3}); expression = parser.parseExpression("['foo']"); assertEquals("1 2 3", stringify(expression.getValue(mapToIntArray))); assertCanCompile(expression); assertEquals("Ljava/lang/Object", getAst().getExitDescriptor()); assertEquals("1 2 3", stringify(expression.getValue(mapToIntArray))); assertEquals("Ljava/lang/Object", getAst().getExitDescriptor()); expression = parser.parseExpression("['foo'][1]"); assertEquals(2, expression.getValue(mapToIntArray)); assertCanCompile(expression); assertEquals(2, expression.getValue(mapToIntArray)); expression = parser.parseExpression("foo"); assertEquals("1 2 3", stringify(expression.getValue(ctx, mapToIntArray))); assertCanCompile(expression); assertEquals("1 2 3", stringify(expression.getValue(ctx, mapToIntArray))); assertEquals("Ljava/lang/Object", getAst().getExitDescriptor()); expression = parser.parseExpression("foo[1]"); assertEquals(2, expression.getValue(ctx, mapToIntArray)); assertCanCompile(expression); assertEquals(2, expression.getValue(ctx, mapToIntArray)); expression = parser.parseExpression("['foo'][2]"); assertEquals("3", stringify(expression.getValue(ctx, mapToIntArray))); assertCanCompile(expression); assertEquals("3", stringify(expression.getValue(ctx, mapToIntArray))); assertEquals("I", getAst().getExitDescriptor()); // Map array Map<String, String>[] mapArray = new Map[1]; mapArray[0] = new HashMap<>(); mapArray[0].put("key", "value1"); expression = parser.parseExpression("[0]"); assertEquals("{key=value1}", stringify(expression.getValue(mapArray))); assertCanCompile(expression); assertEquals("Ljava/util/Map", getAst().getExitDescriptor()); assertEquals("{key=value1}", stringify(expression.getValue(mapArray))); assertEquals("Ljava/util/Map", getAst().getExitDescriptor()); expression = parser.parseExpression("[0]['key']"); assertEquals("value1", stringify(expression.getValue(mapArray))); assertCanCompile(expression); assertEquals("value1", stringify(expression.getValue(mapArray))); assertEquals("Ljava/lang/Object", getAst().getExitDescriptor()); } @Test public void plusNeedingCheckcast_SPR12426() { expression = parser.parseExpression("object + ' world'"); Object v = expression.getValue(new FooObject()); assertEquals("hello world", v); assertCanCompile(expression); assertEquals("hello world", v); expression = parser.parseExpression("object + ' world'"); v = expression.getValue(new FooString()); assertEquals("hello world", v); assertCanCompile(expression); assertEquals("hello world", v); } @Test public void mixingItUp_propertyAccessIndexerOpLtTernaryRootNull() throws Exception { Payload payload = new Payload(); expression = parser.parseExpression("DR[0].three"); Object v = expression.getValue(payload); assertEquals("Lorg/springframework/expression/spel/SpelCompilationCoverageTests$Three", getAst().getExitDescriptor()); Expression expression = parser.parseExpression("DR[0].three.four lt 0.1d?#root:null"); v = expression.getValue(payload); SpelExpression sExpr = (SpelExpression) expression; Ternary ternary = (Ternary) sExpr.getAST(); OpLT oplt = (OpLT) ternary.getChild(0); CompoundExpression cExpr = (CompoundExpression)oplt.getLeftOperand(); String cExprExitDescriptor = cExpr.getExitDescriptor(); assertEquals("D", cExprExitDescriptor); assertEquals("Z", oplt.getExitDescriptor()); assertCanCompile(expression); Object vc = expression.getValue(payload); assertEquals(payload, v); assertEquals(payload,vc); payload.DR[0].three.four = 0.13d; vc = expression.getValue(payload); assertNull(vc); } @Test public void variantGetter() throws Exception { Payload2Holder holder = new Payload2Holder(); StandardEvaluationContext ctx = new StandardEvaluationContext(); ctx.addPropertyAccessor(new MyAccessor()); expression = parser.parseExpression("payload2.var1"); Object v = expression.getValue(ctx,holder); assertEquals("abc", v); // // time it interpreted // long stime = System.currentTimeMillis(); // for (int i = 0; i < 100000; i++) { // v = expression.getValue(ctx,holder); // } // System.out.println((System.currentTimeMillis() - stime)); assertCanCompile(expression); v = expression.getValue(ctx,holder); assertEquals("abc", v); // // time it compiled // stime = System.currentTimeMillis(); // for (int i = 0; i < 100000; i++) { // v = expression.getValue(ctx,holder); // } // System.out.println((System.currentTimeMillis() - stime)); } @Test public void compilerWithGenerics_12040() { expression = parser.parseExpression("payload!=2"); assertTrue(expression.getValue(new GenericMessageTestHelper<>(4), Boolean.class)); assertCanCompile(expression); assertFalse(expression.getValue(new GenericMessageTestHelper<>(2), Boolean.class)); expression = parser.parseExpression("2!=payload"); assertTrue(expression.getValue(new GenericMessageTestHelper<>(4), Boolean.class)); assertCanCompile(expression); assertFalse(expression.getValue(new GenericMessageTestHelper<>(2), Boolean.class)); expression = parser.parseExpression("payload!=6L"); assertTrue(expression.getValue(new GenericMessageTestHelper<>(4L), Boolean.class)); assertCanCompile(expression); assertFalse(expression.getValue(new GenericMessageTestHelper<>(6L), Boolean.class)); expression = parser.parseExpression("payload==2"); assertFalse(expression.getValue(new GenericMessageTestHelper<>(4), Boolean.class)); assertCanCompile(expression); assertTrue(expression.getValue(new GenericMessageTestHelper<>(2), Boolean.class)); expression = parser.parseExpression("2==payload"); assertFalse(expression.getValue(new GenericMessageTestHelper<>(4), Boolean.class)); assertCanCompile(expression); assertTrue(expression.getValue(new GenericMessageTestHelper<>(2), Boolean.class)); expression = parser.parseExpression("payload==6L"); assertFalse(expression.getValue(new GenericMessageTestHelper<>(4L), Boolean.class)); assertCanCompile(expression); assertTrue(expression.getValue(new GenericMessageTestHelper<>(6L), Boolean.class)); expression = parser.parseExpression("2==payload"); assertFalse(expression.getValue(new GenericMessageTestHelper<>(4), Boolean.class)); assertCanCompile(expression); assertTrue(expression.getValue(new GenericMessageTestHelper<>(2), Boolean.class)); expression = parser.parseExpression("payload/2"); assertEquals(2, expression.getValue(new GenericMessageTestHelper<>(4))); assertCanCompile(expression); assertEquals(3, expression.getValue(new GenericMessageTestHelper<>(6))); expression = parser.parseExpression("100/payload"); assertEquals(25, expression.getValue(new GenericMessageTestHelper<>(4))); assertCanCompile(expression); assertEquals(10, expression.getValue(new GenericMessageTestHelper<>(10))); expression = parser.parseExpression("payload+2"); assertEquals(6, expression.getValue(new GenericMessageTestHelper<>(4))); assertCanCompile(expression); assertEquals(8, expression.getValue(new GenericMessageTestHelper<>(6))); expression = parser.parseExpression("100+payload"); assertEquals(104, expression.getValue(new GenericMessageTestHelper<>(4))); assertCanCompile(expression); assertEquals(110, expression.getValue(new GenericMessageTestHelper<>(10))); expression = parser.parseExpression("payload-2"); assertEquals(2, expression.getValue(new GenericMessageTestHelper<>(4))); assertCanCompile(expression); assertEquals(4, expression.getValue(new GenericMessageTestHelper<>(6))); expression = parser.parseExpression("100-payload"); assertEquals(96, expression.getValue(new GenericMessageTestHelper<>(4))); assertCanCompile(expression); assertEquals(90, expression.getValue(new GenericMessageTestHelper<>(10))); expression = parser.parseExpression("payload*2"); assertEquals(8, expression.getValue(new GenericMessageTestHelper<>(4))); assertCanCompile(expression); assertEquals(12, expression.getValue(new GenericMessageTestHelper<>(6))); expression = parser.parseExpression("100*payload"); assertEquals(400, expression.getValue(new GenericMessageTestHelper<>(4))); assertCanCompile(expression); assertEquals(1000, expression.getValue(new GenericMessageTestHelper<>(10))); expression = parser.parseExpression("payload/2L"); assertEquals(2L, expression.getValue(new GenericMessageTestHelper<>(4L))); assertCanCompile(expression); assertEquals(3L, expression.getValue(new GenericMessageTestHelper<>(6L))); expression = parser.parseExpression("100L/payload"); assertEquals(25L, expression.getValue(new GenericMessageTestHelper<>(4L))); assertCanCompile(expression); assertEquals(10L, expression.getValue(new GenericMessageTestHelper<>(10L))); expression = parser.parseExpression("payload/2f"); assertEquals(2f, expression.getValue(new GenericMessageTestHelper<>(4f))); assertCanCompile(expression); assertEquals(3f, expression.getValue(new GenericMessageTestHelper<>(6f))); expression = parser.parseExpression("100f/payload"); assertEquals(25f, expression.getValue(new GenericMessageTestHelper<>(4f))); assertCanCompile(expression); assertEquals(10f, expression.getValue(new GenericMessageTestHelper<>(10f))); expression = parser.parseExpression("payload/2d"); assertEquals(2d, expression.getValue(new GenericMessageTestHelper<>(4d))); assertCanCompile(expression); assertEquals(3d, expression.getValue(new GenericMessageTestHelper<>(6d))); expression = parser.parseExpression("100d/payload"); assertEquals(25d, expression.getValue(new GenericMessageTestHelper<>(4d))); assertCanCompile(expression); assertEquals(10d, expression.getValue(new GenericMessageTestHelper<>(10d))); } // The new helper class here uses an upper bound on the generic @Test public void compilerWithGenerics_12040_2() { expression = parser.parseExpression("payload/2"); assertEquals(2, expression.getValue(new GenericMessageTestHelper2<>(4))); assertCanCompile(expression); assertEquals(3, expression.getValue(new GenericMessageTestHelper2<>(6))); expression = parser.parseExpression("9/payload"); assertEquals(1, expression.getValue(new GenericMessageTestHelper2<>(9))); assertCanCompile(expression); assertEquals(3, expression.getValue(new GenericMessageTestHelper2<>(3))); expression = parser.parseExpression("payload+2"); assertEquals(6, expression.getValue(new GenericMessageTestHelper2<>(4))); assertCanCompile(expression); assertEquals(8, expression.getValue(new GenericMessageTestHelper2<>(6))); expression = parser.parseExpression("100+payload"); assertEquals(104, expression.getValue(new GenericMessageTestHelper2<>(4))); assertCanCompile(expression); assertEquals(110, expression.getValue(new GenericMessageTestHelper2<>(10))); expression = parser.parseExpression("payload-2"); assertEquals(2, expression.getValue(new GenericMessageTestHelper2<>(4))); assertCanCompile(expression); assertEquals(4, expression.getValue(new GenericMessageTestHelper2<>(6))); expression = parser.parseExpression("100-payload"); assertEquals(96, expression.getValue(new GenericMessageTestHelper2<>(4))); assertCanCompile(expression); assertEquals(90, expression.getValue(new GenericMessageTestHelper2<>(10))); expression = parser.parseExpression("payload*2"); assertEquals(8, expression.getValue(new GenericMessageTestHelper2<>(4))); assertCanCompile(expression); assertEquals(12, expression.getValue(new GenericMessageTestHelper2<>(6))); expression = parser.parseExpression("100*payload"); assertEquals(400, expression.getValue(new GenericMessageTestHelper2<>(4))); assertCanCompile(expression); assertEquals(1000, expression.getValue(new GenericMessageTestHelper2<>(10))); } // The other numeric operators @Test public void compilerWithGenerics_12040_3() { expression = parser.parseExpression("payload >= 2"); assertTrue(expression.getValue(new GenericMessageTestHelper2<>(4), Boolean.TYPE)); assertCanCompile(expression); assertFalse(expression.getValue(new GenericMessageTestHelper2<>(1), Boolean.TYPE)); expression = parser.parseExpression("2 >= payload"); assertFalse(expression.getValue(new GenericMessageTestHelper2<>(5), Boolean.TYPE)); assertCanCompile(expression); assertTrue(expression.getValue(new GenericMessageTestHelper2<>(1), Boolean.TYPE)); expression = parser.parseExpression("payload > 2"); assertTrue(expression.getValue(new GenericMessageTestHelper2<>(4), Boolean.TYPE)); assertCanCompile(expression); assertFalse(expression.getValue(new GenericMessageTestHelper2<>(1), Boolean.TYPE)); expression = parser.parseExpression("2 > payload"); assertFalse(expression.getValue(new GenericMessageTestHelper2<>(5), Boolean.TYPE)); assertCanCompile(expression); assertTrue(expression.getValue(new GenericMessageTestHelper2<>(1), Boolean.TYPE)); expression = parser.parseExpression("payload <=2"); assertTrue(expression.getValue(new GenericMessageTestHelper2<>(1), Boolean.TYPE)); assertCanCompile(expression); assertFalse(expression.getValue(new GenericMessageTestHelper2<>(6), Boolean.TYPE)); expression = parser.parseExpression("2 <= payload"); assertFalse(expression.getValue(new GenericMessageTestHelper2<>(1), Boolean.TYPE)); assertCanCompile(expression); assertTrue(expression.getValue(new GenericMessageTestHelper2<>(6), Boolean.TYPE)); expression = parser.parseExpression("payload < 2"); assertTrue(expression.getValue(new GenericMessageTestHelper2<>(1), Boolean.TYPE)); assertCanCompile(expression); assertFalse(expression.getValue(new GenericMessageTestHelper2<>(6), Boolean.TYPE)); expression = parser.parseExpression("2 < payload"); assertFalse(expression.getValue(new GenericMessageTestHelper2<>(1), Boolean.TYPE)); assertCanCompile(expression); assertTrue(expression.getValue(new GenericMessageTestHelper2<>(6), Boolean.TYPE)); } @Test public void indexerMapAccessor_12045() throws Exception { SpelParserConfiguration spc = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE,getClass().getClassLoader()); SpelExpressionParser sep = new SpelExpressionParser(spc); expression=sep.parseExpression("headers[command]"); MyMessage root = new MyMessage(); assertEquals("wibble", expression.getValue(root)); // This next call was failing because the isCompilable check in Indexer did not check on the key being compilable // (and also generateCode in the Indexer was missing the optimization that it didn't need necessarily need to call // generateCode for that accessor) assertEquals("wibble", expression.getValue(root)); assertCanCompile(expression); // What about a map key that is an expression - ensure the getKey() is evaluated in the right scope expression=sep.parseExpression("headers[getKey()]"); assertEquals("wobble", expression.getValue(root)); assertEquals("wobble", expression.getValue(root)); expression=sep.parseExpression("list[getKey2()]"); assertEquals("wobble", expression.getValue(root)); assertEquals("wobble", expression.getValue(root)); expression = sep.parseExpression("ia[getKey2()]"); assertEquals(3, expression.getValue(root)); assertEquals(3, expression.getValue(root)); } @Test public void elvisOperator_SPR15192() { SpelParserConfiguration configuration = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, null); Expression exp; exp = new SpelExpressionParser(configuration).parseExpression("bar()"); assertEquals("BAR", exp.getValue(new Foo(), String.class)); assertCanCompile(exp); assertEquals("BAR", exp.getValue(new Foo(), String.class)); assertIsCompiled(exp); exp = new SpelExpressionParser(configuration).parseExpression("bar('baz')"); assertEquals("BAZ", exp.getValue(new Foo(), String.class)); assertCanCompile(exp); assertEquals("BAZ", exp.getValue(new Foo(), String.class)); assertIsCompiled(exp); StandardEvaluationContext context = new StandardEvaluationContext(); context.setVariable("map", Collections.singletonMap("foo", "qux")); exp = new SpelExpressionParser(configuration).parseExpression("bar(#map['foo'])"); assertEquals("QUX", exp.getValue(context, new Foo(), String.class)); assertCanCompile(exp); assertEquals("QUX", exp.getValue(context, new Foo(), String.class)); assertIsCompiled(exp); exp = new SpelExpressionParser(configuration).parseExpression("bar(#map['foo'] ?: 'qux')"); assertEquals("QUX", exp.getValue(context, new Foo(), String.class)); assertCanCompile(exp); assertEquals("QUX", exp.getValue(context, new Foo(), String.class)); assertIsCompiled(exp); // When the condition is a primitive exp = new SpelExpressionParser(configuration).parseExpression("3?:'foo'"); assertEquals("3", exp.getValue(context, new Foo(), String.class)); assertCanCompile(exp); assertEquals("3", exp.getValue(context, new Foo(), String.class)); assertIsCompiled(exp); // When the condition is a double slot primitive exp = new SpelExpressionParser(configuration).parseExpression("3L?:'foo'"); assertEquals("3", exp.getValue(context, new Foo(), String.class)); assertCanCompile(exp); assertEquals("3", exp.getValue(context, new Foo(), String.class)); assertIsCompiled(exp); // When the condition is an empty string exp = new SpelExpressionParser(configuration).parseExpression("''?:4L"); assertEquals("4", exp.getValue(context, new Foo(), String.class)); assertCanCompile(exp); assertEquals("4", exp.getValue(context, new Foo(), String.class)); assertIsCompiled(exp); // null condition exp = new SpelExpressionParser(configuration).parseExpression("null?:4L"); assertEquals("4", exp.getValue(context, new Foo(), String.class)); assertCanCompile(exp); assertEquals("4", exp.getValue(context, new Foo(), String.class)); assertIsCompiled(exp); // variable access returning primitive exp = new SpelExpressionParser(configuration).parseExpression("#x?:'foo'"); context.setVariable("x",50); assertEquals("50", exp.getValue(context, new Foo(), String.class)); assertCanCompile(exp); assertEquals("50", exp.getValue(context, new Foo(), String.class)); assertIsCompiled(exp); exp = new SpelExpressionParser(configuration).parseExpression("#x?:'foo'"); context.setVariable("x",null); assertEquals("foo", exp.getValue(context, new Foo(), String.class)); assertCanCompile(exp); assertEquals("foo", exp.getValue(context, new Foo(), String.class)); assertIsCompiled(exp); // variable access returning array exp = new SpelExpressionParser(configuration).parseExpression("#x?:'foo'"); context.setVariable("x",new int[]{1,2,3}); assertEquals("1,2,3", exp.getValue(context, new Foo(), String.class)); assertCanCompile(exp); assertEquals("1,2,3", exp.getValue(context, new Foo(), String.class)); assertIsCompiled(exp); } @Test public void ternaryOperator_SPR15192() { SpelParserConfiguration configuration = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, null); Expression exp; StandardEvaluationContext context = new StandardEvaluationContext(); context.setVariable("map", Collections.singletonMap("foo", "qux")); exp = new SpelExpressionParser(configuration).parseExpression("bar(#map['foo'] != null ? #map['foo'] : 'qux')"); assertEquals("QUX", exp.getValue(context, new Foo(), String.class)); assertCanCompile(exp); assertEquals("QUX", exp.getValue(context, new Foo(), String.class)); assertIsCompiled(exp); exp = new SpelExpressionParser(configuration).parseExpression("3==3?3:'foo'"); assertEquals("3", exp.getValue(context, new Foo(), String.class)); assertCanCompile(exp); assertEquals("3", exp.getValue(context, new Foo(), String.class)); assertIsCompiled(exp); exp = new SpelExpressionParser(configuration).parseExpression("3!=3?3:'foo'"); assertEquals("foo", exp.getValue(context, new Foo(), String.class)); assertCanCompile(exp); assertEquals("foo", exp.getValue(context, new Foo(), String.class)); assertIsCompiled(exp); // When the condition is a double slot primitive exp = new SpelExpressionParser(configuration).parseExpression("3==3?3L:'foo'"); assertEquals("3", exp.getValue(context, new Foo(), String.class)); assertCanCompile(exp); assertEquals("3", exp.getValue(context, new Foo(), String.class)); assertIsCompiled(exp); exp = new SpelExpressionParser(configuration).parseExpression("3!=3?3L:'foo'"); assertEquals("foo", exp.getValue(context, new Foo(), String.class)); assertCanCompile(exp); assertEquals("foo", exp.getValue(context, new Foo(), String.class)); assertIsCompiled(exp); // When the condition is an empty string exp = new SpelExpressionParser(configuration).parseExpression("''==''?'abc':4L"); assertEquals("abc", exp.getValue(context, new Foo(), String.class)); assertCanCompile(exp); assertEquals("abc", exp.getValue(context, new Foo(), String.class)); assertIsCompiled(exp); // null condition exp = new SpelExpressionParser(configuration).parseExpression("3==3?null:4L"); assertEquals(null, exp.getValue(context, new Foo(), String.class)); assertCanCompile(exp); assertEquals(null, exp.getValue(context, new Foo(), String.class)); assertIsCompiled(exp); // variable access returning primitive exp = new SpelExpressionParser(configuration).parseExpression("#x==#x?50:'foo'"); context.setVariable("x",50); assertEquals("50", exp.getValue(context, new Foo(), String.class)); assertCanCompile(exp); assertEquals("50", exp.getValue(context, new Foo(), String.class)); assertIsCompiled(exp); exp = new SpelExpressionParser(configuration).parseExpression("#x!=#x?50:'foo'"); context.setVariable("x",null); assertEquals("foo", exp.getValue(context, new Foo(), String.class)); assertCanCompile(exp); assertEquals("foo", exp.getValue(context, new Foo(), String.class)); assertIsCompiled(exp); // variable access returning array exp = new SpelExpressionParser(configuration).parseExpression("#x==#x?'1,2,3':'foo'"); context.setVariable("x",new int[]{1,2,3}); assertEquals("1,2,3", exp.getValue(context, new Foo(), String.class)); assertCanCompile(exp); assertEquals("1,2,3", exp.getValue(context, new Foo(), String.class)); assertIsCompiled(exp); } // helper methods private SpelNodeImpl getAst() { SpelExpression spelExpression = (SpelExpression) expression; SpelNode ast = spelExpression.getAST(); return (SpelNodeImpl)ast; } private String stringify(Object object) { StringBuilder s = new StringBuilder(); if (object instanceof List) { List<?> ls = (List<?>) object; for (Object l: ls) { s.append(l); s.append(" "); } } else if (object instanceof Object[]) { Object[] os = (Object[]) object; for (Object o: os) { s.append(o); s.append(" "); } } else if (object instanceof int[]) { int[] is = (int[]) object; for (int i: is) { s.append(i); s.append(" "); } } else { s.append(object.toString()); } return s.toString().trim(); } private void assertCanCompile(Expression expression) { assertTrue(SpelCompiler.compile(expression)); } private void assertCantCompile(Expression expression) { assertFalse(SpelCompiler.compile(expression)); } private Expression parse(String expression) { return parser.parseExpression(expression); } private void assertGetValueFail(Expression expression) { try { Object o = expression.getValue(); fail("Calling getValue on the expression should have failed but returned "+o); } catch (Exception ex) { // success! } } private void assertIsCompiled(Expression expression) { try { Field field = SpelExpression.class.getDeclaredField("compiledAst"); field.setAccessible(true); Object object = field.get(expression); assertNotNull(object); } catch (Exception ex) { fail(ex.toString()); } } // nested types public interface Message<T> { MessageHeaders getHeaders(); @SuppressWarnings("rawtypes") List getList(); int[] getIa(); } public static class MyMessage implements Message<String> { public MessageHeaders getHeaders() { MessageHeaders mh = new MessageHeaders(); mh.put("command", "wibble"); mh.put("command2", "wobble"); return mh; } public int[] getIa() { return new int[] {5,3}; } @SuppressWarnings({"rawtypes", "unchecked"}) public List getList() { List l = new ArrayList(); l.add("wibble"); l.add("wobble"); return l; } public String getKey() { return "command2"; } public int getKey2() { return 1; } } @SuppressWarnings("serial") public static class MessageHeaders extends HashMap<String, Object> { } public static class GenericMessageTestHelper<T> { private T payload; GenericMessageTestHelper(T value) { this.payload = value; } public T getPayload() { return payload; } } // This test helper has a bound on the type variable public static class GenericMessageTestHelper2<T extends Number> { private T payload; GenericMessageTestHelper2(T value) { this.payload = value; } public T getPayload() { return payload; } } static class MyAccessor implements CompilablePropertyAccessor { private Method method; public Class<?>[] getSpecificTargetClasses() { return new Class[] {Payload2.class}; } public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { // target is a Payload2 instance return true; } public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { Payload2 payload2 = (Payload2)target; return new TypedValue(payload2.getField(name)); } public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { return false; } public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException { } @Override public boolean isCompilable() { return true; } @Override public Class<?> getPropertyType() { return Object.class; } @Override public void generateCode(String propertyName, MethodVisitor mv,CodeFlow cf) { if (method == null) { try { method = Payload2.class.getDeclaredMethod("getField", String.class); } catch (Exception ex) { } } String descriptor = cf.lastDescriptor(); String memberDeclaringClassSlashedDescriptor = method.getDeclaringClass().getName().replace('.','/'); if (descriptor == null) { cf.loadTarget(mv); } if (descriptor == null || !memberDeclaringClassSlashedDescriptor.equals(descriptor.substring(1))) { mv.visitTypeInsn(CHECKCAST, memberDeclaringClassSlashedDescriptor); } mv.visitLdcInsn(propertyName); mv.visitMethodInsn(INVOKEVIRTUAL, memberDeclaringClassSlashedDescriptor, method.getName(),CodeFlow.createSignatureDescriptor(method),false); } } static class CompilableMapAccessor implements CompilablePropertyAccessor { @Override public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { Map<?,?> map = (Map<?,?>) target; return map.containsKey(name); } @Override public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { Map<?,?> map = (Map<?,?>) target; Object value = map.get(name); if (value == null && !map.containsKey(name)) { throw new MapAccessException(name); } return new TypedValue(value); } @Override public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { return true; } @Override @SuppressWarnings("unchecked") public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException { Map<String, Object> map = (Map<String, Object>) target; map.put(name, newValue); } @Override public Class<?>[] getSpecificTargetClasses() { return new Class[] {Map.class}; } @Override public boolean isCompilable() { return true; } @Override public Class<?> getPropertyType() { return Object.class; } @Override public void generateCode(String propertyName, MethodVisitor mv, CodeFlow cf) { String descriptor = cf.lastDescriptor(); if (descriptor == null) { cf.loadTarget(mv); } mv.visitLdcInsn(propertyName); mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "get","(Ljava/lang/Object;)Ljava/lang/Object;",true); } } /** * Exception thrown from {@code read} in order to reset a cached * PropertyAccessor, allowing other accessors to have a try. */ @SuppressWarnings("serial") private static class MapAccessException extends AccessException { private final String key; public MapAccessException(String key) { super(null); this.key = key; } @Override public String getMessage() { return "Map does not contain a value for key '" + this.key + "'"; } } public static class Greeter { public String getWorld() { return "world"; } public Object getObject() { return "object"; } } public static class FooObject { public Object getObject() { return "hello"; } } public static class FooString { public String getObject() { return "hello"; } } public static class Payload { Two[] DR = new Two[] {new Two()}; public Two holder = new Two(); public Two[] getDR() { return DR; } } public static class Payload2 { String var1 = "abc"; String var2 = "def"; public Object getField(String name) { if (name.equals("var1")) { return var1; } else if (name.equals("var2")) { return var2; } return null; } } public static class Payload2Holder { public Payload2 payload2 = new Payload2(); } public class Person { private int age; public Person(int age) { this.age = age; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } public class Person3 { private int age; public Person3(String name, int age) { this.age = age; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } public static class Two { Three three = new Three(); public Three getThree() { return three; } public String toString() { return "instanceof Two"; } } public static class Three { double four = 0.04d; public double getFour() { return four; } } public class PayloadX { public int valueI = 120; public Integer valueIB = 120; public Integer valueIB58 = 58; public Integer valueIB60 = 60; public long valueJ = 120L; public Long valueJB = 120L; public Long valueJB58 = 58L; public Long valueJB60 = 60L; public double valueD = 120D; public Double valueDB = 120D; public Double valueDB58 = 58D; public Double valueDB60 = 60D; public float valueF = 120F; public Float valueFB = 120F; public Float valueFB58 = 58F; public Float valueFB60 = 60F; public byte valueB = (byte)120; public byte valueB18 = (byte)18; public byte valueB20 = (byte)20; public Byte valueBB = (byte)120; public Byte valueBB18 = (byte)18; public Byte valueBB20 = (byte)20; public char valueC = (char)120; public Character valueCB = (char)120; public short valueS = (short)120; public short valueS18 = (short)18; public short valueS20 = (short)20; public Short valueSB = (short)120; public Short valueSB18 = (short)18; public Short valueSB20 = (short)20; public PayloadX payload; public PayloadX() { payload = this; } } public static class TestClass1 { public int index1 = 1; public int index2 = 3; public String word = "abcd"; } public static class TestClass4 { public boolean a,b; public boolean gettrue() { return true; } public boolean getfalse() { return false; } public boolean getA() { return a; } public boolean getB() { return b; } } public static class TestClass10 { public String s = null; public void reset() { s = null; } public void concat(String arg) { s = "::"+arg; } public void concat(String... vargs) { if (vargs == null) { s = ""; } else { s = ""; for (String varg : vargs) { s += varg; } } } public void concat2(Object arg) { s = "::"+arg; } public void concat2(Object... vargs) { if (vargs == null) { s = ""; } else { s = ""; for (Object varg : vargs) { s += varg; } } } } public static class TestClass5 { public int i = 0; public String s = null; public static int _i = 0; public static String _s = null; public static short s1 = (short)1; public static short s2 = (short)2; public static short s3 = (short)3; public static long l1 = 1L; public static long l2 = 2L; public static long l3 = 3L; public static float f1 = 1f; public static float f2 = 2f; public static float f3 = 3f; public static char c1 = 'a'; public static char c2 = 'b'; public static char c3 = 'c'; public static byte b1 = (byte)65; public static byte b2 = (byte)66; public static byte b3 = (byte)67; public static String[] stringArray = new String[] {"aaa","bbb","ccc"}; public static int[] intArray = new int[] {11,22,33}; public Object obj = null; public String field = null; public void reset() { i = 0; _i = 0; s = null; _s = null; field = null; } public void one() { i = 1; } public static void two() { _i = 1; } public String three() { return "hello"; } public long four() { return 3277700L; } public static String five() { return "hello"; } public static long six() { return 3277700L; } public void seven(String toset) { s = toset; } // public void seven(Number n) { s = n.toString(); } public void takeNumber(Number n) { s = n.toString(); } public void takeString(String s) { this.s = s; } public static void eight(String toset) { _s = toset; } public void nine(int toset) { i = toset; } public static void ten(int toset) { _i = toset; } public void eleven(String... vargs) { if (vargs == null) { s = ""; } else { s = ""; for (String varg: vargs) { s += varg; } } } public void twelve(int... vargs) { if (vargs == null) { i = 0; } else { i = 0; for (int varg: vargs) { i += varg; } } } public void thirteen(String a, String... vargs) { if (vargs == null) { s = a + "::"; } else { s = a+"::"; for (String varg: vargs) { s += varg; } } } public void arrayz(boolean... bs) { s = ""; if (bs != null) { s = ""; for (boolean b: bs) { s += Boolean.toString(b); } } } public void arrays(short... ss) { s = ""; if (ss != null) { s = ""; for (short s: ss) { this.s += Short.toString(s); } } } public void arrayd(double... vargs) { s = ""; if (vargs != null) { s = ""; for (double v: vargs) { this.s += Double.toString(v); } } } public void arrayf(float... vargs) { s = ""; if (vargs != null) { s = ""; for (float v: vargs) { this.s += Float.toString(v); } } } public void arrayj(long... vargs) { s = ""; if (vargs != null) { s = ""; for (long v: vargs) { this.s += Long.toString(v); } } } public void arrayb(byte... vargs) { s = ""; if (vargs != null) { s = ""; for (Byte v: vargs) { this.s += Byte.toString(v); } } } public void arrayc(char... vargs) { s = ""; if (vargs != null) { s = ""; for (char v: vargs) { this.s += Character.toString(v); } } } public void fourteen(String a, String[]... vargs) { if (vargs == null) { s = a+"::"; } else { s = a+"::"; for (String[] varg: vargs) { s += "{"; for (String v: varg) { s += v; } s += "}"; } } } public void fifteen(String a, int[]... vargs) { if (vargs == null) { s = a+"::"; } else { s = a+"::"; for (int[] varg: vargs) { s += "{"; for (int v: varg) { s += Integer.toString(v); } s += "}"; } } } public void sixteen(Object... vargs) { if (vargs == null) { s = ""; } else { s = ""; for (Object varg: vargs) { s += varg; } } } } public static class TestClass6 { public String orange = "value1"; public static String apple = "value2"; public long peach = 34L; public String getBanana() { return "value3"; } public static String getPlum() { return "value4"; } } public static class TestClass7 { public static String property; static { String s = "UK 123"; StringTokenizer st = new StringTokenizer(s); property = st.nextToken(); } public static void reset() { String s = "UK 123"; StringTokenizer st = new StringTokenizer(s); property = st.nextToken(); } } public static class TestClass8 { public int i; public String s; public double d; public boolean z; public TestClass8(int i, String s, double d, boolean z) { this.i = i; this.s = s; this.d = d; this.z = z; } public TestClass8() { } public TestClass8(Integer i) { this.i = i; } @SuppressWarnings("unused") private TestClass8(String a, String b) { this.s = a+b; } } public static class Obj { private final String param1; public Obj(String param1){ this.param1 = param1; } } public static class Obj2 { public final String output; public Obj2(String... params){ StringBuilder b = new StringBuilder(); for (String param: params) { b.append(param); } output = b.toString(); } } public static class Obj3 { public final String output; public Obj3(int... params) { StringBuilder b = new StringBuilder(); for (int param: params) { b.append(Integer.toString(param)); } output = b.toString(); } public Obj3(String s, Float f, int... ints) { StringBuilder b = new StringBuilder(); b.append(s); b.append(":"); b.append(Float.toString(f)); b.append(":"); for (int param: ints) { b.append(Integer.toString(param)); } output = b.toString(); } } public static class Obj4 { public final String output; public Obj4(int[] params) { StringBuilder b = new StringBuilder(); for (int param: params) { b.append(Integer.toString(param)); } output = b.toString(); } } @SuppressWarnings("unused") private static class TestClass9 { public TestClass9(int i) { } } // These test classes simulate a pattern of public/private classes seen in Spring Security // final class HttpServlet3RequestFactory implements HttpServletRequestFactory static class HttpServlet3RequestFactory { static Servlet3SecurityContextHolderAwareRequestWrapper getOne() { HttpServlet3RequestFactory outer = new HttpServlet3RequestFactory(); return outer.new Servlet3SecurityContextHolderAwareRequestWrapper(); } // private class Servlet3SecurityContextHolderAwareRequestWrapper extends SecurityContextHolderAwareRequestWrapper private class Servlet3SecurityContextHolderAwareRequestWrapper extends SecurityContextHolderAwareRequestWrapper { } } // public class SecurityContextHolderAwareRequestWrapper extends HttpServletRequestWrapper static class SecurityContextHolderAwareRequestWrapper extends HttpServletRequestWrapper { } public static class HttpServletRequestWrapper { public String getServletPath() { return "wibble"; } } // Here the declaring class is not public static class SomeCompareMethod { // method not public static int compare(Object o1, Object o2) { return -1; } // public public static int compare2(Object o1, Object o2) { return -1; } } public static class SomeCompareMethod2 { public static int negate(int i1) { return -i1; } public static String append(String... strings) { StringBuilder b = new StringBuilder(); for (String string : strings) { b.append(string); } return b.toString(); } public static String append2(Object... objects) { StringBuilder b = new StringBuilder(); for (Object object : objects) { b.append(object.toString()); } return b.toString(); } public static String append3(String[] strings) { StringBuilder b = new StringBuilder(); for (String string : strings) { b.append(string); } return b.toString(); } public static String append4(String s, String... strings) { StringBuilder b = new StringBuilder(); b.append(s).append("::"); for (String string : strings) { b.append(string); } return b.toString(); } public static String appendChar(char... values) { StringBuilder b = new StringBuilder(); for (char ch : values) { b.append(ch); } return b.toString(); } public static int sum(int... ints) { int total = 0; for (int i : ints) { total += i; } return total; } public static int sumDouble(double... values) { int total = 0; for (double i : values) { total += i; } return total; } public static int sumFloat(float... values) { int total = 0; for (float i : values) { total += i; } return total; } } public static class DelegatingStringFormat { public static String format(String s, Object... args) { return String.format(s, args); } } public static class StaticsHelper { static StaticsHelper sh = new StaticsHelper(); public static StaticsHelper fielda = sh; public static String fieldb = "fb"; public static StaticsHelper methoda() { return sh; } public static String methodb() { return "mb"; } public static StaticsHelper getPropertya() { return sh; } public static String getPropertyb() { return "pb"; } public String toString() { return "sh"; } } public static class Apple implements Comparable<Apple> { public Object gotComparedTo = null; public int i; public Apple(int i) { this.i = i; } public void setValue(int i) { this.i = i; } @Override public int compareTo(Apple that) { this.gotComparedTo = that; if (this.i < that.i) { return -1; } else if (this.i > that.i) { return +1; } else { return 0; } } } // For opNe_SPR14863 public static class MyContext { private final Map<String, String> data; public MyContext(Map<String, String> data) { this.data = data; } public Map<String, String> getData() { return data; } } public static class Foo { public String bar() { return "BAR"; } public String bar(String arg) { return arg.toUpperCase(); } } }