View Javadoc
1   /*
2    * Copyright 2014 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.expression.spel;
18  
19  import java.io.IOException;
20  import java.lang.reflect.Method;
21  import java.util.ArrayList;
22  import java.util.HashMap;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.StringTokenizer;
26  
27  import org.junit.Test;
28  
29  import org.springframework.asm.MethodVisitor;
30  import org.springframework.expression.AccessException;
31  import org.springframework.expression.EvaluationContext;
32  import org.springframework.expression.Expression;
33  import org.springframework.expression.TypedValue;
34  import org.springframework.expression.spel.ast.CompoundExpression;
35  import org.springframework.expression.spel.ast.OpLT;
36  import org.springframework.expression.spel.ast.SpelNodeImpl;
37  import org.springframework.expression.spel.ast.Ternary;
38  import org.springframework.expression.spel.standard.SpelCompiler;
39  import org.springframework.expression.spel.standard.SpelExpression;
40  import org.springframework.expression.spel.standard.SpelExpressionParser;
41  import org.springframework.expression.spel.support.StandardEvaluationContext;
42  import org.springframework.expression.spel.testdata.PersonInOtherPackage;
43  
44  import static org.junit.Assert.*;
45  
46  /**
47   * Checks the behaviour of the SpelCompiler. This should cover compilation all compiled node types.
48   *
49   * @author Andy Clement
50   * @since 4.1
51   */
52  public class SpelCompilationCoverageTests extends AbstractExpressionTests {
53  	
54  	private Expression expression;
55  	private SpelNodeImpl ast;
56  	
57  	/*
58  	 * Further TODOs for compilation:
59  	 * 
60  	 * - OpMinus with a single literal operand could be treated as a negative literal. Will save a
61  	 *   pointless loading of 0 and then a subtract instruction in code gen.
62  	 * - allow other accessors/resolvers to participate in compilation and create their own code
63  	 * - A TypeReference followed by (what ends up as) a static method invocation can really skip
64  	 *   code gen for the TypeReference since once that is used to locate the method it is not
65  	 *   used again.
66  	 * - The opEq implementation is quite basic. It will compare numbers of the same type (allowing
67  	 *   them to be their boxed or unboxed variants) or compare object references. It does not
68  	 *   compile expressions where numbers are of different types or when objects implement
69  	 *   Comparable.  
70       *
71  	 * Compiled nodes:
72  	 * 
73  	 * TypeReference
74  	 * OperatorInstanceOf
75  	 * StringLiteral
76  	 * NullLiteral
77  	 * RealLiteral
78  	 * IntLiteral
79  	 * LongLiteral
80  	 * BooleanLiteral
81  	 * FloatLiteral
82  	 * OpOr
83  	 * OpAnd
84  	 * OperatorNot
85  	 * Ternary
86  	 * Elvis
87  	 * VariableReference
88  	 * OpLt
89  	 * OpLe
90  	 * OpGt
91  	 * OpGe
92  	 * OpEq
93  	 * OpNe
94  	 * OpPlus
95  	 * OpMinus
96  	 * OpMultiply
97  	 * OpDivide
98  	 * MethodReference
99  	 * PropertyOrFieldReference
100 	 * Indexer
101 	 * CompoundExpression
102 	 * ConstructorReference
103 	 * FunctionReference
104 	 * InlineList
105 	 * OpModulus
106 	 * 
107 	 * Not yet compiled (some may never need to be):
108 	 * Assign
109 	 * BeanReference
110 	 * Identifier
111 	 * OpDec
112 	 * OpBetween
113 	 * OpMatches
114 	 * OpPower
115 	 * OpInc
116 	 * Projection
117 	 * QualifiedId
118 	 * Selection
119 	 */
120 	
121 	@Test
122 	public void typeReference() throws Exception {
123 		expression = parse("T(String)");
124 		assertEquals(String.class,expression.getValue());
125 		assertCanCompile(expression);
126 		assertEquals(String.class,expression.getValue());
127 		 
128 		expression = parse("T(java.io.IOException)");
129 		assertEquals(IOException.class,expression.getValue());
130 		assertCanCompile(expression);
131 		assertEquals(IOException.class,expression.getValue());
132 
133 		expression = parse("T(java.io.IOException[])");
134 		assertEquals(IOException[].class,expression.getValue());
135 		assertCanCompile(expression);
136 		assertEquals(IOException[].class,expression.getValue());
137 
138 		expression = parse("T(int[][])");
139 		assertEquals(int[][].class,expression.getValue());
140 		assertCanCompile(expression);
141 		assertEquals(int[][].class,expression.getValue());
142 
143 		expression = parse("T(int)");
144 		assertEquals(Integer.TYPE,expression.getValue());
145 		assertCanCompile(expression);
146 		assertEquals(Integer.TYPE,expression.getValue());
147 
148 		expression = parse("T(byte)");
149 		assertEquals(Byte.TYPE,expression.getValue());
150 		assertCanCompile(expression);
151 		assertEquals(Byte.TYPE,expression.getValue());
152 
153 		expression = parse("T(char)");
154 		assertEquals(Character.TYPE,expression.getValue());
155 		assertCanCompile(expression);
156 		assertEquals(Character.TYPE,expression.getValue());
157 
158 		expression = parse("T(short)");
159 		assertEquals(Short.TYPE,expression.getValue());
160 		assertCanCompile(expression);
161 		assertEquals(Short.TYPE,expression.getValue());
162 
163 		expression = parse("T(long)");
164 		assertEquals(Long.TYPE,expression.getValue());
165 		assertCanCompile(expression);
166 		assertEquals(Long.TYPE,expression.getValue());
167 
168 		expression = parse("T(float)");
169 		assertEquals(Float.TYPE,expression.getValue());
170 		assertCanCompile(expression);
171 		assertEquals(Float.TYPE,expression.getValue());
172 
173 		expression = parse("T(double)");
174 		assertEquals(Double.TYPE,expression.getValue());
175 		assertCanCompile(expression);
176 		assertEquals(Double.TYPE,expression.getValue());
177 
178 		expression = parse("T(boolean)");
179 		assertEquals(Boolean.TYPE,expression.getValue());
180 		assertCanCompile(expression);
181 		assertEquals(Boolean.TYPE,expression.getValue());
182 		
183 		expression = parse("T(Missing)");
184 		assertGetValueFail(expression);
185 		assertCantCompile(expression);
186 	}
187 
188 	@SuppressWarnings("unchecked")
189 	@Test
190 	public void operatorInstanceOf() throws Exception {
191 		expression = parse("'xyz' instanceof T(String)");
192 		assertEquals(true,expression.getValue());
193 		assertCanCompile(expression);
194 		assertEquals(true,expression.getValue());
195 
196 		expression = parse("'xyz' instanceof T(Integer)");
197 		assertEquals(false,expression.getValue());
198 		assertCanCompile(expression);
199 		assertEquals(false,expression.getValue());
200 
201 		List<String> list = new ArrayList<String>();
202 		expression = parse("#root instanceof T(java.util.List)");
203 		assertEquals(true,expression.getValue(list));
204 		assertCanCompile(expression);
205 		assertEquals(true,expression.getValue(list));
206 
207 		List<String>[] arrayOfLists = new List[]{new ArrayList<String>()};
208 		expression = parse("#root instanceof T(java.util.List[])");
209 		assertEquals(true,expression.getValue(arrayOfLists));
210 		assertCanCompile(expression);
211 		assertEquals(true,expression.getValue(arrayOfLists));
212 		
213 		int[] intArray = new int[]{1,2,3};
214 		expression = parse("#root instanceof T(int[])");
215 		assertEquals(true,expression.getValue(intArray));
216 		assertCanCompile(expression);
217 		assertEquals(true,expression.getValue(intArray));
218 
219 		String root = null;
220 		expression = parse("#root instanceof T(Integer)");
221 		assertEquals(false,expression.getValue(root));
222 		assertCanCompile(expression);
223 		assertEquals(false,expression.getValue(root));
224 
225 		// root still null
226 		expression = parse("#root instanceof T(java.lang.Object)");
227 		assertEquals(false,expression.getValue(root));
228 		assertCanCompile(expression);
229 		assertEquals(false,expression.getValue(root));
230 
231 		root = "howdy!";
232 		expression = parse("#root instanceof T(java.lang.Object)");
233 		assertEquals(true,expression.getValue(root));
234 		assertCanCompile(expression);
235 		assertEquals(true,expression.getValue(root));
236 	}
237 
238 	@Test
239 	public void stringLiteral() throws Exception {
240 		expression = parser.parseExpression("'abcde'");		
241 		assertEquals("abcde",expression.getValue(new TestClass1(),String.class));
242 		assertCanCompile(expression);
243 		String resultC = expression.getValue(new TestClass1(),String.class);
244 		assertEquals("abcde",resultC);
245 		assertEquals("abcde",expression.getValue(String.class));
246 		assertEquals("abcde",expression.getValue());
247 		assertEquals("abcde",expression.getValue(new StandardEvaluationContext()));
248 		expression = parser.parseExpression("\"abcde\"");
249 		assertCanCompile(expression);
250 		assertEquals("abcde",expression.getValue(String.class));
251 	}
252 	
253 	@Test
254 	public void nullLiteral() throws Exception {
255 		expression = parser.parseExpression("null");
256 		Object resultI = expression.getValue(new TestClass1(),Object.class);
257 		assertCanCompile(expression);
258 		Object resultC = expression.getValue(new TestClass1(),Object.class);
259 		assertEquals(null,resultI);
260 		assertEquals(null,resultC);
261 		assertEquals(null,resultC);
262 	}
263 	
264 	@Test
265 	public void realLiteral() throws Exception {
266 		expression = parser.parseExpression("3.4d");
267 		double resultI = expression.getValue(new TestClass1(),Double.TYPE);
268 		assertCanCompile(expression);
269 		double resultC = expression.getValue(new TestClass1(),Double.TYPE);
270 		assertEquals(3.4d,resultI,0.1d);
271 		assertEquals(3.4d,resultC,0.1d);
272 
273 		assertEquals(3.4d,expression.getValue());
274 	}
275 	
276 	@SuppressWarnings("rawtypes")
277 	@Test
278 	public void inlineList() throws Exception {
279 		expression = parser.parseExpression("'abcde'.substring({1,3,4}[0])");
280 		Object o = expression.getValue();
281 		assertEquals("bcde",o);
282 		assertCanCompile(expression);
283 		o = expression.getValue();
284 		assertEquals("bcde", o);
285 		
286 		expression = parser.parseExpression("{'abc','def'}");
287 		List<?> l = (List) expression.getValue();
288 		assertEquals("[abc, def]", l.toString());
289 		assertCanCompile(expression);
290 		l = (List) expression.getValue();
291 		assertEquals("[abc, def]", l.toString());
292 		
293 		expression = parser.parseExpression("{'abc','def'}[0]");
294 		o = expression.getValue();
295 		assertEquals("abc",o);
296 		assertCanCompile(expression);
297 		o = expression.getValue();
298 		assertEquals("abc", o);
299 		
300 		expression = parser.parseExpression("{'abcde','ijklm'}[0].substring({1,3,4}[0])");
301 		o = expression.getValue();
302 		assertEquals("bcde",o);
303 		assertCanCompile(expression);
304 		o = expression.getValue();
305 		assertEquals("bcde", o);
306 
307 		expression = parser.parseExpression("{'abcde','ijklm'}[0].substring({1,3,4}[0],{1,3,4}[1])");
308 		o = expression.getValue();
309 		assertEquals("bc",o);
310 		assertCanCompile(expression);
311 		o = expression.getValue();
312 		assertEquals("bc", o);
313 	}
314 
315 	@SuppressWarnings("rawtypes")
316 	@Test
317 	public void nestedInlineLists() throws Exception {
318 		Object o = null;
319 		
320 		expression = parser.parseExpression("{{1,2,3},{4,5,6},{7,8,9}}");
321 		o = expression.getValue();
322 		assertEquals("[[1, 2, 3], [4, 5, 6], [7, 8, 9]]",o.toString());
323 		assertCanCompile(expression);
324 		o = expression.getValue();
325 		assertEquals("[[1, 2, 3], [4, 5, 6], [7, 8, 9]]",o.toString());
326 
327 		expression = parser.parseExpression("{{1,2,3},{4,5,6},{7,8,9}}.toString()");
328 		o = expression.getValue();
329 		assertEquals("[[1, 2, 3], [4, 5, 6], [7, 8, 9]]",o);
330 		assertCanCompile(expression);
331 		o = expression.getValue();
332 		assertEquals("[[1, 2, 3], [4, 5, 6], [7, 8, 9]]",o);
333 
334 		expression = parser.parseExpression("{{1,2,3},{4,5,6},{7,8,9}}[1][0]");
335 		o = expression.getValue();
336 		assertEquals(4,o);
337 		assertCanCompile(expression);
338 		o = expression.getValue();
339 		assertEquals(4,o);
340 		
341 		expression = parser.parseExpression("{{1,2,3},'abc',{7,8,9}}[1]");
342 		o = expression.getValue();
343 		assertEquals("abc",o);
344 		assertCanCompile(expression);
345 		o = expression.getValue();
346 		assertEquals("abc",o);
347 
348 		expression = parser.parseExpression("'abcde'.substring({{1,3},1,3,4}[0][1])");
349 		o = expression.getValue();
350 		assertEquals("de",o);
351 		assertCanCompile(expression);
352 		o = expression.getValue();
353 		assertEquals("de", o);
354 
355 		expression = parser.parseExpression("'abcde'.substring({{1,3},1,3,4}[1])");
356 		o = expression.getValue();
357 		assertEquals("bcde",o);
358 		assertCanCompile(expression);
359 		o = expression.getValue();
360 		assertEquals("bcde", o);
361 		
362 		expression = parser.parseExpression("{'abc',{'def','ghi'}}");
363 		List<?> l = (List) expression.getValue();
364 		assertEquals("[abc, [def, ghi]]", l.toString());
365 		assertCanCompile(expression);
366 		l = (List) expression.getValue();
367 		assertEquals("[abc, [def, ghi]]", l.toString());
368 
369 		expression = parser.parseExpression("{'abcde',{'ijklm','nopqr'}}[0].substring({1,3,4}[0])");
370 		o = expression.getValue();
371 		assertEquals("bcde",o);
372 		assertCanCompile(expression);
373 		o = expression.getValue();
374 		assertEquals("bcde", o);
375 		
376 		expression = parser.parseExpression("{'abcde',{'ijklm','nopqr'}}[1][0].substring({1,3,4}[0])");
377 		o = expression.getValue();
378 		assertEquals("jklm",o);
379 		assertCanCompile(expression);
380 		o = expression.getValue();
381 		assertEquals("jklm", o);
382 
383 		expression = parser.parseExpression("{'abcde',{'ijklm','nopqr'}}[1][1].substring({1,3,4}[0],{1,3,4}[1])");
384 		o = expression.getValue();
385 		assertEquals("op",o);
386 		assertCanCompile(expression);
387 		o = expression.getValue();
388 		assertEquals("op", o);
389 	}
390 
391 	@Test
392 	public void intLiteral() throws Exception {
393 		expression = parser.parseExpression("42");
394 		int resultI = expression.getValue(new TestClass1(),Integer.TYPE);
395 		assertCanCompile(expression);
396 		int resultC = expression.getValue(new TestClass1(),Integer.TYPE);
397 		assertEquals(42,resultI);
398 		assertEquals(42,resultC);
399 
400 		expression = parser.parseExpression("T(Integer).valueOf(42)");
401 		expression.getValue(Integer.class);
402 		assertCanCompile(expression);
403 		assertEquals(new Integer(42),expression.getValue(null,Integer.class));
404 		
405 		// Code gen is different for -1 .. 6 because there are bytecode instructions specifically for those
406 		// values
407 		
408 		// Not an int literal but an opminus with one operand:
409 //		expression = parser.parseExpression("-1");
410 //		assertCanCompile(expression);
411 //		assertEquals(-1,expression.getValue());
412 		expression = parser.parseExpression("0");
413 		assertCanCompile(expression);
414 		assertEquals(0,expression.getValue());
415 		expression = parser.parseExpression("2");
416 		assertCanCompile(expression);
417 		assertEquals(2,expression.getValue());
418 		expression = parser.parseExpression("7");
419 		assertCanCompile(expression);
420 		assertEquals(7,expression.getValue());
421 	}
422 	
423 	@Test
424 	public void longLiteral() throws Exception {
425 		expression = parser.parseExpression("99L");
426 		long resultI = expression.getValue(new TestClass1(),Long.TYPE);
427 		assertCanCompile(expression);
428 		long resultC = expression.getValue(new TestClass1(),Long.TYPE);
429 		assertEquals(99L,resultI);
430 		assertEquals(99L,resultC);		
431 	}
432 		
433 	@Test
434 	public void booleanLiteral() throws Exception {
435 		expression = parser.parseExpression("true");
436 		boolean resultI = expression.getValue(1,Boolean.TYPE);
437 		assertEquals(true,resultI);
438 		assertTrue(SpelCompiler.compile(expression));
439 		boolean resultC = expression.getValue(1,Boolean.TYPE);
440 		assertEquals(true,resultC);
441 		
442 		expression = parser.parseExpression("false");
443 		resultI = expression.getValue(1,Boolean.TYPE);
444 		assertEquals(false,resultI);
445 		assertTrue(SpelCompiler.compile(expression));
446 		resultC = expression.getValue(1,Boolean.TYPE);
447 		assertEquals(false,resultC);
448 	}
449 	
450 	@Test
451 	public void floatLiteral() throws Exception {
452 		expression = parser.parseExpression("3.4f");
453 		float resultI = expression.getValue(new TestClass1(),Float.TYPE);
454 		assertCanCompile(expression);
455 		float resultC = expression.getValue(new TestClass1(),Float.TYPE);
456 		assertEquals(3.4f,resultI,0.1f);
457 		assertEquals(3.4f,resultC,0.1f);
458 
459 		assertEquals(3.4f,expression.getValue());
460 	}
461 	
462 	@Test
463 	public void opOr() throws Exception {
464 		Expression expression = parser.parseExpression("false or false");
465 		boolean resultI = expression.getValue(1,Boolean.TYPE);
466 		SpelCompiler.compile(expression);
467 		boolean resultC = expression.getValue(1,Boolean.TYPE);
468 		assertEquals(false,resultI);
469 		assertEquals(false,resultC);
470 		
471 		expression = parser.parseExpression("false or true");
472 		resultI = expression.getValue(1,Boolean.TYPE);
473 		assertCanCompile(expression);
474 		resultC = expression.getValue(1,Boolean.TYPE);
475 		assertEquals(true,resultI);
476 		assertEquals(true,resultC);
477 		
478 		expression = parser.parseExpression("true or false");
479 		resultI = expression.getValue(1,Boolean.TYPE);
480 		assertCanCompile(expression);
481 		resultC = expression.getValue(1,Boolean.TYPE);
482 		assertEquals(true,resultI);
483 		assertEquals(true,resultC);
484 		
485 		expression = parser.parseExpression("true or true");
486 		resultI = expression.getValue(1,Boolean.TYPE);
487 		assertCanCompile(expression);
488 		resultC = expression.getValue(1,Boolean.TYPE);
489 		assertEquals(true,resultI);
490 		assertEquals(true,resultC);
491 
492 		TestClass4 tc = new TestClass4();
493 		expression = parser.parseExpression("getfalse() or gettrue()");
494 		resultI = expression.getValue(tc,Boolean.TYPE);
495 		assertCanCompile(expression);
496 		resultC = expression.getValue(tc,Boolean.TYPE);
497 		assertEquals(true,resultI);
498 		assertEquals(true,resultC);
499 
500 		// Can't compile this as we aren't going down the getfalse() branch in our evaluation
501 		expression = parser.parseExpression("gettrue() or getfalse()");
502 		resultI = expression.getValue(tc,Boolean.TYPE);
503 		assertCantCompile(expression);
504 		
505 		expression = parser.parseExpression("getA() or getB()");
506 		tc.a = true;
507 		tc.b = true;
508 		resultI = expression.getValue(tc,Boolean.TYPE);
509 		assertCantCompile(expression); // Haven't yet been into second branch
510 		tc.a = false;
511 		tc.b = true;
512 		resultI = expression.getValue(tc,Boolean.TYPE);
513 		assertCanCompile(expression); // Now been down both
514 		assertTrue(resultI);
515 		
516 		boolean b = false;
517 		expression = parse("#root or #root");
518 		Object resultI2 = expression.getValue(b);
519 		assertCanCompile(expression);
520 		assertFalse((Boolean)resultI2);
521 		assertFalse((Boolean)expression.getValue(b));
522 	}
523 	
524 	@Test
525 	public void opAnd() throws Exception {
526 		Expression expression = parser.parseExpression("false and false");
527 		boolean resultI = expression.getValue(1,Boolean.TYPE);
528 		SpelCompiler.compile(expression);
529 		boolean resultC = expression.getValue(1,Boolean.TYPE);
530 		assertEquals(false,resultI);
531 		assertEquals(false,resultC);
532 
533 		expression = parser.parseExpression("false and true");
534 		resultI = expression.getValue(1,Boolean.TYPE);
535 		SpelCompiler.compile(expression);
536 		resultC = expression.getValue(1,Boolean.TYPE);
537 		assertEquals(false,resultI);
538 		assertEquals(false,resultC);
539 		
540 		expression = parser.parseExpression("true and false");
541 		resultI = expression.getValue(1,Boolean.TYPE);
542 		SpelCompiler.compile(expression);
543 		resultC = expression.getValue(1,Boolean.TYPE);
544 		assertEquals(false,resultI);
545 		assertEquals(false,resultC);
546 
547 		expression = parser.parseExpression("true and true");
548 		resultI = expression.getValue(1,Boolean.TYPE);
549 		SpelCompiler.compile(expression);
550 		resultC = expression.getValue(1,Boolean.TYPE);
551 		assertEquals(true,resultI);
552 		assertEquals(true,resultC);
553 		
554 		TestClass4 tc = new TestClass4();
555 
556 		// Can't compile this as we aren't going down the gettrue() branch in our evaluation
557 		expression = parser.parseExpression("getfalse() and gettrue()");
558 		resultI = expression.getValue(tc,Boolean.TYPE);
559 		assertCantCompile(expression);
560 		
561 		expression = parser.parseExpression("getA() and getB()");
562 		tc.a = false;
563 		tc.b = false;
564 		resultI = expression.getValue(tc,Boolean.TYPE);
565 		assertCantCompile(expression); // Haven't yet been into second branch
566 		tc.a = true;
567 		tc.b = false;
568 		resultI = expression.getValue(tc,Boolean.TYPE);
569 		assertCanCompile(expression); // Now been down both
570 		assertFalse(resultI);
571 		tc.a = true;
572 		tc.b = true;
573 		resultI = expression.getValue(tc,Boolean.TYPE);
574 		assertTrue(resultI);
575 		
576 		boolean b = true;
577 		expression = parse("#root and #root");
578 		Object resultI2 = expression.getValue(b);
579 		assertCanCompile(expression);
580 		assertTrue((Boolean)resultI2);
581 		assertTrue((Boolean)expression.getValue(b));
582 	}
583 	
584 	@Test
585 	public void operatorNot() throws Exception {
586 		expression = parse("!true");
587 		assertEquals(false,expression.getValue());
588 		assertCanCompile(expression);
589 		assertEquals(false,expression.getValue());
590 
591 		expression = parse("!false");
592 		assertEquals(true,expression.getValue());
593 		assertCanCompile(expression);
594 		assertEquals(true,expression.getValue());
595 
596 		boolean b = true;
597 		expression = parse("!#root");
598 		assertEquals(false,expression.getValue(b));
599 		assertCanCompile(expression);
600 		assertEquals(false,expression.getValue(b));
601 
602 		b = false;
603 		expression = parse("!#root");
604 		assertEquals(true,expression.getValue(b));
605 		assertCanCompile(expression);
606 		assertEquals(true,expression.getValue(b));
607 	}
608 
609 	@Test
610 	public void ternary() throws Exception {
611 		Expression expression = parser.parseExpression("true?'a':'b'");
612 		String resultI = expression.getValue(String.class);
613 		assertCanCompile(expression);
614 		String resultC = expression.getValue(String.class);
615 		assertEquals("a",resultI);
616 		assertEquals("a",resultC);
617 		
618 		expression = parser.parseExpression("false?'a':'b'");
619 		resultI = expression.getValue(String.class);
620 		assertCanCompile(expression);
621 		resultC = expression.getValue(String.class);
622 		assertEquals("b",resultI);
623 		assertEquals("b",resultC);
624 
625 		expression = parser.parseExpression("false?1:'b'");
626 		// All literals so we can do this straight away
627 		assertCanCompile(expression);
628 		assertEquals("b",expression.getValue());
629 
630 		boolean root = true;
631 		expression = parser.parseExpression("(#root and true)?T(Integer).valueOf(1):T(Long).valueOf(3L)");
632 		assertEquals(1,expression.getValue(root));
633 		assertCantCompile(expression); // Have not gone down false branch
634 		root = false;
635 		assertEquals(3L,expression.getValue(root));
636 		assertCanCompile(expression);
637 		assertEquals(3L,expression.getValue(root));
638 		root = true;
639 		assertEquals(1,expression.getValue(root));		
640 	}
641 	
642 	@Test
643 	public void ternaryWithBooleanReturn() { // SPR-12271
644 		expression = parser.parseExpression("T(Boolean).TRUE?'abc':'def'");
645 		assertEquals("abc",expression.getValue());
646 		assertCanCompile(expression);
647 		assertEquals("abc",expression.getValue());
648 
649 		expression = parser.parseExpression("T(Boolean).FALSE?'abc':'def'");
650 		assertEquals("def",expression.getValue());
651 		assertCanCompile(expression);
652 		assertEquals("def",expression.getValue());
653 	}
654 	
655 	@Test
656 	public void elvis() throws Exception {
657 		Expression expression = parser.parseExpression("'a'?:'b'");
658 		String resultI = expression.getValue(String.class);
659 		assertCanCompile(expression);
660 		String resultC = expression.getValue(String.class);
661 		assertEquals("a",resultI);
662 		assertEquals("a",resultC);
663 		
664 		expression = parser.parseExpression("null?:'a'");
665 		resultI = expression.getValue(String.class);
666 		assertCanCompile(expression);
667 		resultC = expression.getValue(String.class);
668 		assertEquals("a",resultI);
669 		assertEquals("a",resultC);
670 		
671 		String s = "abc";
672 		expression = parser.parseExpression("#root?:'b'");
673 		assertCantCompile(expression);
674 		resultI = expression.getValue(s,String.class);
675 		assertEquals("abc",resultI);
676 		assertCanCompile(expression);
677 	}
678 	
679 	@Test
680 	public void variableReference_root() throws Exception {
681 		String s = "hello";
682 		Expression expression = parser.parseExpression("#root");
683 		String resultI = expression.getValue(s,String.class);
684 		assertCanCompile(expression);
685 		String resultC = expression.getValue(s,String.class);
686 		assertEquals(s,resultI);
687 		assertEquals(s,resultC);		
688 
689 		expression = parser.parseExpression("#root");
690 		int i = (Integer)expression.getValue(42);
691 		assertEquals(42,i);
692 		assertCanCompile(expression);
693 		i = (Integer)expression.getValue(42);
694 		assertEquals(42,i);
695 	}
696 	
697 	public static String concat(String a, String b) {
698 		return a+b;
699 	}
700 	
701 	public static String join(String...strings) {
702 		StringBuilder buf = new StringBuilder();
703 		for (String string: strings) {
704 			buf.append(string);
705 		}
706 		return buf.toString();
707 	}
708 	
709 	@Test
710 	public void compiledExpressionShouldWorkWhenUsingCustomFunctionWithVarargs() throws Exception {
711 		StandardEvaluationContext context = null;
712 
713 		// Here the target method takes Object... and we are passing a string
714 		expression = parser.parseExpression("#doFormat('hey %s', 'there')");
715 		context = new StandardEvaluationContext();
716 		context.registerFunction("doFormat",
717 				DelegatingStringFormat.class.getDeclaredMethod("format", String.class,
718 						Object[].class));
719 		((SpelExpression) expression).setEvaluationContext(context);
720 
721 		assertEquals("hey there", expression.getValue(String.class));
722 		assertTrue(((SpelNodeImpl) ((SpelExpression) expression).getAST()).isCompilable());
723 		assertCanCompile(expression);
724 		assertEquals("hey there", expression.getValue(String.class));
725 
726 		expression = parser.parseExpression("#doFormat([0], 'there')");
727 		context = new StandardEvaluationContext(new Object[] { "hey %s" });
728 		context.registerFunction("doFormat",
729 				DelegatingStringFormat.class.getDeclaredMethod("format", String.class,
730 						Object[].class));
731 		((SpelExpression) expression).setEvaluationContext(context);
732 
733 		assertEquals("hey there", expression.getValue(String.class));
734 		assertTrue(((SpelNodeImpl) ((SpelExpression) expression).getAST()).isCompilable());
735 		assertCanCompile(expression);
736 		assertEquals("hey there", expression.getValue(String.class));
737 
738 		expression = parser.parseExpression("#doFormat([0], #arg)");
739 		context = new StandardEvaluationContext(new Object[] { "hey %s" });
740 		context.registerFunction("doFormat",
741 				DelegatingStringFormat.class.getDeclaredMethod("format", String.class,
742 						Object[].class));
743 		context.setVariable("arg", "there");
744 		((SpelExpression) expression).setEvaluationContext(context);
745 
746 		assertEquals("hey there", expression.getValue(String.class));
747 		assertTrue(((SpelNodeImpl) ((SpelExpression) expression).getAST()).isCompilable());
748 		assertCanCompile(expression);
749 		assertEquals("hey there", expression.getValue(String.class));
750 	}
751 	 
752 	@Test
753 	public void functionReference() throws Exception {
754 		EvaluationContext ctx = new StandardEvaluationContext();
755 		Method m = this.getClass().getDeclaredMethod("concat",String.class,String.class);
756 		ctx.setVariable("concat",m);
757 		
758 		expression = parser.parseExpression("#concat('a','b')");
759 		assertEquals("ab",expression.getValue(ctx));
760 		assertCanCompile(expression);
761 		assertEquals("ab",expression.getValue(ctx));
762 		
763 		expression = parser.parseExpression("#concat(#concat('a','b'),'c').charAt(1)");
764 		assertEquals('b',expression.getValue(ctx));
765 		assertCanCompile(expression);
766 		assertEquals('b',expression.getValue(ctx));
767 		
768 		expression = parser.parseExpression("#concat(#a,#b)");
769 		ctx.setVariable("a", "foo");
770 		ctx.setVariable("b", "bar");
771 		assertEquals("foobar",expression.getValue(ctx));
772 		assertCanCompile(expression);
773 		assertEquals("foobar",expression.getValue(ctx));
774 		ctx.setVariable("b", "boo");
775 		assertEquals("fooboo",expression.getValue(ctx));
776 		
777 		m = Math.class.getDeclaredMethod("pow",Double.TYPE,Double.TYPE);
778 		ctx.setVariable("kapow",m);
779 		expression = parser.parseExpression("#kapow(2.0d,2.0d)");
780 		assertEquals("4.0",expression.getValue(ctx).toString());
781 		assertCanCompile(expression);
782 		assertEquals("4.0",expression.getValue(ctx).toString());
783 	}
784 
785 	// Confirms visibility of what is being called.
786 	@Test
787 	public void functionReferenceVisibility_SPR12359() throws Exception {
788 		StandardEvaluationContext context = new StandardEvaluationContext(new  Object[] { "1" });
789 		context.registerFunction("doCompare", SomeCompareMethod.class.getDeclaredMethod(
790 				"compare", Object.class, Object.class));
791 		context.setVariable("arg", "2");
792 		// type nor method are public
793 		expression = parser.parseExpression("#doCompare([0],#arg)");
794 		assertEquals("-1",expression.getValue(context, Integer.class).toString());
795 		assertCantCompile(expression);
796 		
797 		// type not public but method is
798 		context = new StandardEvaluationContext(new  Object[] { "1" });
799 		context.registerFunction("doCompare", SomeCompareMethod.class.getDeclaredMethod(
800 				"compare2", Object.class, Object.class));
801 		context.setVariable("arg", "2");
802 		expression = parser.parseExpression("#doCompare([0],#arg)");
803 		assertEquals("-1",expression.getValue(context, Integer.class).toString());
804 		assertCantCompile(expression);
805 	}
806 	
807 	@Test
808 	public void functionReferenceNonCompilableArguments_SPR12359() throws Exception {
809 		StandardEvaluationContext context = new StandardEvaluationContext(new  Object[] { "1" });
810 		context.registerFunction("negate", SomeCompareMethod2.class.getDeclaredMethod(
811 				"negate", Integer.TYPE));
812 		context.setVariable("arg", "2");
813 		int[] ints = new int[]{1,2,3};
814 		context.setVariable("ints",ints);
815 
816 		expression = parser.parseExpression("#negate(#ints.?[#this<2][0])");
817 		assertEquals("-1",expression.getValue(context, Integer.class).toString());
818 		// Selection isn't compilable.
819 		assertFalse(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
820 	}
821 	
822 	@Test	
823 	public void functionReferenceVarargs_SPR12359() throws Exception {
824 		StandardEvaluationContext context = new StandardEvaluationContext();
825 		context.registerFunction("append",
826 				SomeCompareMethod2.class.getDeclaredMethod("append", String[].class));
827 		context.registerFunction("append2",
828 				SomeCompareMethod2.class.getDeclaredMethod("append2", Object[].class));
829 		context.registerFunction("append3",
830 				SomeCompareMethod2.class.getDeclaredMethod("append3", String[].class));
831 		context.registerFunction("append4",
832 				SomeCompareMethod2.class.getDeclaredMethod("append4", String.class, String[].class));
833 		context.registerFunction("appendChar",
834 				SomeCompareMethod2.class.getDeclaredMethod("appendChar", char[].class));
835 		context.registerFunction("sum",
836 				SomeCompareMethod2.class.getDeclaredMethod("sum", int[].class));
837 		context.registerFunction("sumDouble",
838 				SomeCompareMethod2.class.getDeclaredMethod("sumDouble", double[].class));
839 		context.registerFunction("sumFloat",
840 				SomeCompareMethod2.class.getDeclaredMethod("sumFloat", float[].class));
841 		context.setVariable("stringArray", new String[]{"x","y","z"});
842 		context.setVariable("intArray", new int[]{5,6,9});
843 		context.setVariable("doubleArray", new double[]{5.0d,6.0d,9.0d});
844 		context.setVariable("floatArray", new float[]{5.0f,6.0f,9.0f});
845 
846 		expression = parser.parseExpression("#append('a','b','c')");
847 		assertEquals("abc",expression.getValue(context).toString());
848 		assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
849 		assertCanCompile(expression);
850 		assertEquals("abc",expression.getValue(context).toString());
851 
852 		expression = parser.parseExpression("#append('a')");
853 		assertEquals("a",expression.getValue(context).toString());
854 		assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
855 		assertCanCompile(expression);
856 		assertEquals("a",expression.getValue(context).toString());
857 
858 		expression = parser.parseExpression("#append()");
859 		assertEquals("",expression.getValue(context).toString());
860 		assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
861 		assertCanCompile(expression);
862 		assertEquals("",expression.getValue(context).toString());
863 		
864 		expression = parser.parseExpression("#append(#stringArray)");
865 		assertEquals("xyz",expression.getValue(context).toString());
866 		assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
867 		assertCanCompile(expression);
868 		assertEquals("xyz",expression.getValue(context).toString());
869 		
870 		// This is a methodreference invocation, to compare with functionreference
871 		expression = parser.parseExpression("append(#stringArray)");
872 		assertEquals("xyz",expression.getValue(context,new SomeCompareMethod2()).toString());
873 		assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
874 		assertCanCompile(expression);
875 		assertEquals("xyz",expression.getValue(context,new SomeCompareMethod2()).toString());
876 		
877 		expression = parser.parseExpression("#append2('a','b','c')");
878 		assertEquals("abc",expression.getValue(context).toString());
879 		assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
880 		assertCanCompile(expression);
881 		assertEquals("abc",expression.getValue(context).toString());
882 
883 		expression = parser.parseExpression("append2('a','b')");
884 		assertEquals("ab",expression.getValue(context, new SomeCompareMethod2()).toString());
885 		assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
886 		assertCanCompile(expression);
887 		assertEquals("ab",expression.getValue(context, new SomeCompareMethod2()).toString());
888 
889 		expression = parser.parseExpression("#append2('a','b')");
890 		assertEquals("ab",expression.getValue(context).toString());
891 		assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
892 		assertCanCompile(expression);
893 		assertEquals("ab",expression.getValue(context).toString());
894 
895 		expression = parser.parseExpression("#append2()");
896 		assertEquals("",expression.getValue(context).toString());
897 		assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
898 		assertCanCompile(expression);
899 		assertEquals("",expression.getValue(context).toString());
900 		
901 		expression = parser.parseExpression("#append3(#stringArray)");
902 		assertEquals("xyz",expression.getValue(context, new SomeCompareMethod2()).toString());
903 		assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
904 		assertCanCompile(expression);
905 		assertEquals("xyz",expression.getValue(context, new SomeCompareMethod2()).toString());
906 
907 		// TODO fails due to conversionservice handling of String[] to Object...
908 //		expression = parser.parseExpression("#append2(#stringArray)");
909 //		assertEquals("xyz",expression.getValue(context).toString());
910 //		assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
911 //		assertCanCompile(expression);
912 //		assertEquals("xyz",expression.getValue(context).toString());
913 		
914 		expression = parser.parseExpression("#sum(1,2,3)");
915 		assertEquals(6,expression.getValue(context));
916 		assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
917 		assertCanCompile(expression);
918 		assertEquals(6,expression.getValue(context));
919 
920 		expression = parser.parseExpression("#sum(2)");
921 		assertEquals(2,expression.getValue(context));
922 		assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
923 		assertCanCompile(expression);
924 		assertEquals(2,expression.getValue(context));
925 
926 		expression = parser.parseExpression("#sum()");
927 		assertEquals(0,expression.getValue(context));
928 		assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
929 		assertCanCompile(expression);
930 		assertEquals(0,expression.getValue(context));
931 		
932 		expression = parser.parseExpression("#sum(#intArray)");
933 		assertEquals(20,expression.getValue(context));
934 		assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
935 		assertCanCompile(expression);
936 		assertEquals(20,expression.getValue(context));
937 		
938 		expression = parser.parseExpression("#sumDouble(1.0d,2.0d,3.0d)");
939 		assertEquals(6,expression.getValue(context));
940 		assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
941 		assertCanCompile(expression);
942 		assertEquals(6,expression.getValue(context));
943 
944 		expression = parser.parseExpression("#sumDouble(2.0d)");
945 		assertEquals(2,expression.getValue(context));
946 		assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
947 		assertCanCompile(expression);
948 		assertEquals(2,expression.getValue(context));
949 
950 		expression = parser.parseExpression("#sumDouble()");
951 		assertEquals(0,expression.getValue(context));
952 		assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
953 		assertCanCompile(expression);
954 		assertEquals(0,expression.getValue(context));
955 		
956 		expression = parser.parseExpression("#sumDouble(#doubleArray)");
957 		assertEquals(20,expression.getValue(context));
958 		assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
959 		assertCanCompile(expression);
960 		assertEquals(20,expression.getValue(context));
961 
962 		expression = parser.parseExpression("#sumFloat(1.0f,2.0f,3.0f)");
963 		assertEquals(6,expression.getValue(context));
964 		assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
965 		assertCanCompile(expression);
966 		assertEquals(6,expression.getValue(context));
967 
968 		expression = parser.parseExpression("#sumFloat(2.0f)");
969 		assertEquals(2,expression.getValue(context));
970 		assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
971 		assertCanCompile(expression);
972 		assertEquals(2,expression.getValue(context));
973 
974 		expression = parser.parseExpression("#sumFloat()");
975 		assertEquals(0,expression.getValue(context));
976 		assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
977 		assertCanCompile(expression);
978 		assertEquals(0,expression.getValue(context));
979 		
980 		expression = parser.parseExpression("#sumFloat(#floatArray)");
981 		assertEquals(20,expression.getValue(context));
982 		assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
983 		assertCanCompile(expression);
984 		assertEquals(20,expression.getValue(context));
985 		
986 		
987 		expression = parser.parseExpression("#appendChar('abc'.charAt(0),'abc'.charAt(1))");
988 		assertEquals("ab",expression.getValue(context));
989 		assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
990 		assertCanCompile(expression);
991 		assertEquals("ab",expression.getValue(context));
992 		
993 		
994 		expression = parser.parseExpression("#append4('a','b','c')");
995 		assertEquals("a::bc",expression.getValue(context).toString());
996 		assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
997 		assertCanCompile(expression);
998 		assertEquals("a::bc",expression.getValue(context).toString());
999 
1000 		expression = parser.parseExpression("#append4('a','b')");
1001 		assertEquals("a::b",expression.getValue(context).toString());
1002 		assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
1003 		assertCanCompile(expression);
1004 		assertEquals("a::b",expression.getValue(context).toString());
1005 
1006 		expression = parser.parseExpression("#append4('a')");
1007 		assertEquals("a::",expression.getValue(context).toString());
1008 		assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
1009 		assertCanCompile(expression);
1010 		assertEquals("a::",expression.getValue(context).toString());
1011 		
1012 		expression = parser.parseExpression("#append4('a',#stringArray)");
1013 		assertEquals("a::xyz",expression.getValue(context).toString());
1014 		assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
1015 		assertCanCompile(expression);
1016 		assertEquals("a::xyz",expression.getValue(context).toString());
1017 	}
1018 	
1019 	@Test
1020 	public void functionReferenceVarargs() throws Exception {
1021 		EvaluationContext ctx = new StandardEvaluationContext();
1022 		Method m = this.getClass().getDeclaredMethod("join", String[].class);
1023 		ctx.setVariable("join", m);
1024 		expression = parser.parseExpression("#join('a','b','c')");
1025 		assertEquals("abc",expression.getValue(ctx));
1026 		assertCanCompile(expression);
1027 		assertEquals("abc",expression.getValue(ctx));
1028 	}
1029 	
1030 	@Test
1031 	public void variableReference_userDefined() throws Exception {
1032 		EvaluationContext ctx = new StandardEvaluationContext();
1033 		ctx.setVariable("target", "abc");
1034 		expression = parser.parseExpression("#target");
1035 		assertEquals("abc",expression.getValue(ctx));
1036 		assertCanCompile(expression);
1037 		assertEquals("abc",expression.getValue(ctx));	
1038 		ctx.setVariable("target", "123");
1039 		assertEquals("123",expression.getValue(ctx));	
1040 		ctx.setVariable("target", 42);
1041 		try {
1042 			assertEquals(42,expression.getValue(ctx));
1043 			fail();
1044 		} catch (SpelEvaluationException see) {
1045 			assertTrue(see.getCause() instanceof ClassCastException);
1046 		}
1047 	
1048 		ctx.setVariable("target", "abc");
1049 		expression = parser.parseExpression("#target.charAt(0)");
1050 		assertEquals('a',expression.getValue(ctx));
1051 		assertCanCompile(expression);
1052 		assertEquals('a',expression.getValue(ctx));	
1053 		ctx.setVariable("target", "1");
1054 		assertEquals('1',expression.getValue(ctx));	
1055 		ctx.setVariable("target", 42);
1056 		try {
1057 			assertEquals('4',expression.getValue(ctx));
1058 			fail();
1059 		} catch (SpelEvaluationException see) {
1060 			assertTrue(see.getCause() instanceof ClassCastException);
1061 		}
1062 	}
1063 	
1064 	@Test
1065 	public void opLt() throws Exception {
1066 		expression = parse("3.0d < 4.0d");
1067 		assertCanCompile(expression);
1068 		assertTrue((Boolean)expression.getValue());
1069 		expression = parse("3446.0d < 1123.0d");
1070 		assertCanCompile(expression);
1071 		assertFalse((Boolean)expression.getValue());
1072 
1073 		expression = parse("3 < 1");
1074 		assertCanCompile(expression);
1075 		assertFalse((Boolean)expression.getValue());
1076 		expression = parse("2 < 4");
1077 		assertCanCompile(expression);
1078 		assertTrue((Boolean)expression.getValue());
1079 		
1080 		expression = parse("3.0f < 1.0f");
1081 		assertCanCompile(expression);
1082 		assertFalse((Boolean)expression.getValue());
1083 		expression = parse("1.0f < 5.0f");
1084 		assertCanCompile(expression);
1085 		assertTrue((Boolean)expression.getValue());
1086 		
1087 		expression = parse("30L < 30L");
1088 		assertCanCompile(expression);
1089 		assertFalse((Boolean)expression.getValue());
1090 		expression = parse("15L < 20L");
1091 		assertCanCompile(expression);
1092 		assertTrue((Boolean)expression.getValue());
1093 		
1094 		// Differing types of number, not yet supported
1095 		expression = parse("1 < 3.0d");
1096 		assertCantCompile(expression);
1097 		
1098 		expression = parse("T(Integer).valueOf(3) < 4");
1099 		assertTrue((Boolean)expression.getValue());
1100 		assertCanCompile(expression);
1101 		assertTrue((Boolean)expression.getValue());
1102 
1103 		expression = parse("T(Integer).valueOf(3) < T(Integer).valueOf(3)");
1104 		assertFalse((Boolean)expression.getValue());
1105 		assertCanCompile(expression);
1106 		assertFalse((Boolean)expression.getValue());
1107 
1108 		expression = parse("5 < T(Integer).valueOf(3)");
1109 		assertFalse((Boolean)expression.getValue());
1110 		assertCanCompile(expression);
1111 		assertFalse((Boolean)expression.getValue());
1112 	}
1113 	
1114 	@Test
1115 	public void opLe() throws Exception {
1116 		expression = parse("3.0d <= 4.0d");
1117 		assertCanCompile(expression);
1118 		assertTrue((Boolean)expression.getValue());
1119 		expression = parse("3446.0d <= 1123.0d");
1120 		assertCanCompile(expression);
1121 		assertFalse((Boolean)expression.getValue());
1122 		expression = parse("3446.0d <= 3446.0d");
1123 		assertCanCompile(expression);
1124 		assertTrue((Boolean)expression.getValue());
1125 
1126 		expression = parse("3 <= 1");
1127 		assertCanCompile(expression);
1128 		assertFalse((Boolean)expression.getValue());
1129 		expression = parse("2 <= 4");
1130 		assertCanCompile(expression);
1131 		assertTrue((Boolean)expression.getValue());
1132 		expression = parse("3 <= 3");
1133 		assertCanCompile(expression);
1134 		assertTrue((Boolean)expression.getValue());
1135 		
1136 		expression = parse("3.0f <= 1.0f");
1137 		assertCanCompile(expression);
1138 		assertFalse((Boolean)expression.getValue());
1139 		expression = parse("1.0f <= 5.0f");
1140 		assertCanCompile(expression);
1141 		assertTrue((Boolean)expression.getValue());
1142 		expression = parse("2.0f <= 2.0f");
1143 		assertCanCompile(expression);
1144 		assertTrue((Boolean)expression.getValue());
1145 		
1146 		expression = parse("30L <= 30L");
1147 		assertCanCompile(expression);
1148 		assertTrue((Boolean)expression.getValue());
1149 		expression = parse("15L <= 20L");
1150 		assertCanCompile(expression);
1151 		assertTrue((Boolean)expression.getValue());
1152 		
1153 		// Differing types of number, not yet supported
1154 		expression = parse("1 <= 3.0d");
1155 		assertCantCompile(expression);
1156 
1157 		expression = parse("T(Integer).valueOf(3) <= 4");
1158 		assertTrue((Boolean)expression.getValue());
1159 		assertCanCompile(expression);
1160 		assertTrue((Boolean)expression.getValue());
1161 
1162 		expression = parse("T(Integer).valueOf(3) <= T(Integer).valueOf(3)");
1163 		assertTrue((Boolean)expression.getValue());
1164 		assertCanCompile(expression);
1165 		assertTrue((Boolean)expression.getValue());
1166 
1167 		expression = parse("5 <= T(Integer).valueOf(3)");
1168 		assertFalse((Boolean)expression.getValue());
1169 		assertCanCompile(expression);
1170 		assertFalse((Boolean)expression.getValue());
1171 	}
1172 	
1173 	
1174 	@Test
1175 	public void opGt() throws Exception {
1176 		expression = parse("3.0d > 4.0d");
1177 		assertCanCompile(expression);
1178 		assertFalse((Boolean)expression.getValue());
1179 		expression = parse("3446.0d > 1123.0d");
1180 		assertCanCompile(expression);
1181 		assertTrue((Boolean)expression.getValue());
1182 
1183 		expression = parse("3 > 1");
1184 		assertCanCompile(expression);
1185 		assertTrue((Boolean)expression.getValue());
1186 		expression = parse("2 > 4");
1187 		assertCanCompile(expression);
1188 		assertFalse((Boolean)expression.getValue());
1189 		
1190 		expression = parse("3.0f > 1.0f");
1191 		assertCanCompile(expression);
1192 		assertTrue((Boolean)expression.getValue());
1193 		expression = parse("1.0f > 5.0f");
1194 		assertCanCompile(expression);
1195 		assertFalse((Boolean)expression.getValue());
1196 		
1197 		expression = parse("30L > 30L");
1198 		assertCanCompile(expression);
1199 		assertFalse((Boolean)expression.getValue());
1200 		expression = parse("15L > 20L");
1201 		assertCanCompile(expression);
1202 		assertFalse((Boolean)expression.getValue());
1203 		
1204 		// Differing types of number, not yet supported
1205 		expression = parse("1 > 3.0d");
1206 		assertCantCompile(expression);
1207 
1208 		expression = parse("T(Integer).valueOf(3) > 4");
1209 		assertFalse((Boolean)expression.getValue());
1210 		assertCanCompile(expression);
1211 		assertFalse((Boolean)expression.getValue());
1212 		
1213 		expression = parse("T(Integer).valueOf(3) > T(Integer).valueOf(3)");
1214 		assertFalse((Boolean)expression.getValue());
1215 		assertCanCompile(expression);
1216 		assertFalse((Boolean)expression.getValue());
1217 
1218 		expression = parse("5 > T(Integer).valueOf(3)");
1219 		assertTrue((Boolean)expression.getValue());
1220 		assertCanCompile(expression);
1221 		assertTrue((Boolean)expression.getValue());
1222 	}
1223 	
1224 	@Test
1225 	public void opGe() throws Exception {
1226 		expression = parse("3.0d >= 4.0d");
1227 		assertCanCompile(expression);
1228 		assertFalse((Boolean)expression.getValue());
1229 		expression = parse("3446.0d >= 1123.0d");
1230 		assertCanCompile(expression);
1231 		assertTrue((Boolean)expression.getValue());
1232 		expression = parse("3446.0d >= 3446.0d");
1233 		assertCanCompile(expression);
1234 		assertTrue((Boolean)expression.getValue());
1235 
1236 		expression = parse("3 >= 1");
1237 		assertCanCompile(expression);
1238 		assertTrue((Boolean)expression.getValue());
1239 		expression = parse("2 >= 4");
1240 		assertCanCompile(expression);
1241 		assertFalse((Boolean)expression.getValue());
1242 		expression = parse("3 >= 3");
1243 		assertCanCompile(expression);
1244 		assertTrue((Boolean)expression.getValue());
1245 		
1246 		expression = parse("3.0f >= 1.0f");
1247 		assertCanCompile(expression);
1248 		assertTrue((Boolean)expression.getValue());
1249 		expression = parse("1.0f >= 5.0f");
1250 		assertCanCompile(expression);
1251 		assertFalse((Boolean)expression.getValue());
1252 		expression = parse("3.0f >= 3.0f");
1253 		assertCanCompile(expression);
1254 		assertTrue((Boolean)expression.getValue());
1255 		
1256 		expression = parse("40L >= 30L");
1257 		assertCanCompile(expression);
1258 		assertTrue((Boolean)expression.getValue());
1259 		expression = parse("15L >= 20L");
1260 		assertCanCompile(expression);
1261 		assertFalse((Boolean)expression.getValue());
1262 		expression = parse("30L >= 30L");
1263 		assertCanCompile(expression);
1264 		assertTrue((Boolean)expression.getValue());
1265 		
1266 		// Differing types of number, not yet supported
1267 		expression = parse("1 >= 3.0d");
1268 		assertCantCompile(expression);
1269 
1270 		expression = parse("T(Integer).valueOf(3) >= 4");
1271 		assertFalse((Boolean)expression.getValue());
1272 		assertCanCompile(expression);
1273 		assertFalse((Boolean)expression.getValue());
1274 		
1275 		expression = parse("T(Integer).valueOf(3) >= T(Integer).valueOf(3)");
1276 		assertTrue((Boolean)expression.getValue());
1277 		assertCanCompile(expression);
1278 		assertTrue((Boolean)expression.getValue());
1279 
1280 		expression = parse("5 >= T(Integer).valueOf(3)");
1281 		assertTrue((Boolean)expression.getValue());
1282 		assertCanCompile(expression);
1283 		assertTrue((Boolean)expression.getValue());
1284 	}
1285 
1286 	@Test
1287 	public void opEq() throws Exception {
1288 		String tvar = "35";
1289 		expression = parse("#root == 35");
1290 		Boolean bb = (Boolean)expression.getValue(tvar);
1291 		System.out.println(bb);
1292 		assertFalse((Boolean)expression.getValue(tvar));
1293 		assertCanCompile(expression);
1294 		assertFalse((Boolean)expression.getValue(tvar));
1295 
1296 		expression = parse("35 == #root");
1297 		expression.getValue(tvar);
1298 		assertFalse((Boolean)expression.getValue(tvar));
1299 		assertCanCompile(expression);
1300 		assertFalse((Boolean)expression.getValue(tvar));
1301 
1302 		TestClass7 tc7 = new TestClass7();
1303 		expression = parse("property == 'UK'");
1304 		assertTrue((Boolean)expression.getValue(tc7));
1305 		TestClass7.property = null;
1306 		assertFalse((Boolean)expression.getValue(tc7));
1307 		assertCanCompile(expression);
1308 		TestClass7.reset();
1309 		assertTrue((Boolean)expression.getValue(tc7));
1310 		TestClass7.property = "UK";
1311 		assertTrue((Boolean)expression.getValue(tc7));
1312 		TestClass7.reset();
1313 		TestClass7.property = null;
1314 		assertFalse((Boolean)expression.getValue(tc7));
1315 		expression = parse("property == null");
1316 		assertTrue((Boolean)expression.getValue(tc7));
1317 		assertCanCompile(expression);
1318 		assertTrue((Boolean)expression.getValue(tc7));
1319 		
1320 		
1321 		expression = parse("3.0d == 4.0d");
1322 		assertCanCompile(expression);
1323 		assertFalse((Boolean)expression.getValue());
1324 		expression = parse("3446.0d == 3446.0d");
1325 		assertCanCompile(expression);
1326 		assertTrue((Boolean)expression.getValue());
1327 
1328 		expression = parse("3 == 1");
1329 		assertCanCompile(expression);
1330 		assertFalse((Boolean)expression.getValue());
1331 		expression = parse("3 == 3");
1332 		assertCanCompile(expression);
1333 		assertTrue((Boolean)expression.getValue());
1334 		
1335 		expression = parse("3.0f == 1.0f");
1336 		assertCanCompile(expression);
1337 		assertFalse((Boolean)expression.getValue());
1338 		expression = parse("2.0f == 2.0f");
1339 		assertCanCompile(expression);
1340 		assertTrue((Boolean)expression.getValue());
1341 		
1342 		expression = parse("30L == 30L");
1343 		assertCanCompile(expression);
1344 		assertTrue((Boolean)expression.getValue());
1345 		expression = parse("15L == 20L");
1346 		assertCanCompile(expression);
1347 		assertFalse((Boolean)expression.getValue());
1348 		
1349 		// number types are not the same
1350 		expression = parse("1 == 3.0d");
1351 		assertCantCompile(expression);
1352 		
1353 		Double d = 3.0d;
1354 		expression = parse("#root==3.0d");
1355 		assertTrue((Boolean)expression.getValue(d));
1356 		assertCanCompile(expression);
1357 		assertTrue((Boolean)expression.getValue(d));
1358 		
1359 		Integer i = 3;
1360 		expression = parse("#root==3");
1361 		assertTrue((Boolean)expression.getValue(i));
1362 		assertCanCompile(expression);
1363 		assertTrue((Boolean)expression.getValue(i));
1364 
1365 		Float f = 3.0f;
1366 		expression = parse("#root==3.0f");
1367 		assertTrue((Boolean)expression.getValue(f));
1368 		assertCanCompile(expression);
1369 		assertTrue((Boolean)expression.getValue(f));
1370 		
1371 		long l = 300l;
1372 		expression = parse("#root==300l");
1373 		assertTrue((Boolean)expression.getValue(l));
1374 		assertCanCompile(expression);
1375 		assertTrue((Boolean)expression.getValue(l));
1376 		
1377 		boolean b = true;
1378 		expression = parse("#root==true");
1379 		assertTrue((Boolean)expression.getValue(b));
1380 		assertCanCompile(expression);
1381 		assertTrue((Boolean)expression.getValue(b));
1382 
1383 		expression = parse("T(Integer).valueOf(3) == 4");
1384 		assertFalse((Boolean)expression.getValue());
1385 		assertCanCompile(expression);
1386 		assertFalse((Boolean)expression.getValue());
1387 		
1388 		expression = parse("T(Integer).valueOf(3) == T(Integer).valueOf(3)");
1389 		assertTrue((Boolean)expression.getValue());
1390 		assertCanCompile(expression);
1391 		assertTrue((Boolean)expression.getValue());
1392 
1393 		expression = parse("5 == T(Integer).valueOf(3)");
1394 		assertFalse((Boolean)expression.getValue());
1395 		assertCanCompile(expression);
1396 		assertFalse((Boolean)expression.getValue());
1397 
1398 		expression = parse("T(Float).valueOf(3.0f) == 4.0f");
1399 		assertFalse((Boolean)expression.getValue());
1400 		assertCanCompile(expression);
1401 		assertFalse((Boolean)expression.getValue());
1402 		
1403 		expression = parse("T(Float).valueOf(3.0f) == T(Float).valueOf(3.0f)");
1404 		assertTrue((Boolean)expression.getValue());
1405 		assertCanCompile(expression);
1406 		assertTrue((Boolean)expression.getValue());
1407 
1408 		expression = parse("5.0f == T(Float).valueOf(3.0f)");
1409 		assertFalse((Boolean)expression.getValue());
1410 		assertCanCompile(expression);
1411 		assertFalse((Boolean)expression.getValue());
1412 		
1413 		expression = parse("T(Long).valueOf(3L) == 4L");
1414 		assertFalse((Boolean)expression.getValue());
1415 		assertCanCompile(expression);
1416 		assertFalse((Boolean)expression.getValue());
1417 		
1418 		expression = parse("T(Long).valueOf(3L) == T(Long).valueOf(3L)");
1419 		assertTrue((Boolean)expression.getValue());
1420 		assertCanCompile(expression);
1421 		assertTrue((Boolean)expression.getValue());
1422 
1423 		expression = parse("5L == T(Long).valueOf(3L)");
1424 		assertFalse((Boolean)expression.getValue());
1425 		assertCanCompile(expression);
1426 		assertFalse((Boolean)expression.getValue());	
1427 		
1428 		expression = parse("T(Double).valueOf(3.0d) == 4.0d");
1429 		assertFalse((Boolean)expression.getValue());
1430 		assertCanCompile(expression);
1431 		assertFalse((Boolean)expression.getValue());
1432 		
1433 		expression = parse("T(Double).valueOf(3.0d) == T(Double).valueOf(3.0d)");
1434 		assertTrue((Boolean)expression.getValue());
1435 		assertCanCompile(expression);
1436 		assertTrue((Boolean)expression.getValue());
1437 
1438 		expression = parse("5.0d == T(Double).valueOf(3.0d)");
1439 		assertFalse((Boolean)expression.getValue());
1440 		assertCanCompile(expression);
1441 		assertFalse((Boolean)expression.getValue());
1442 
1443 		expression = parse("false == true");
1444 		assertFalse((Boolean)expression.getValue());
1445 		assertCanCompile(expression);
1446 		assertFalse((Boolean)expression.getValue());
1447 		
1448 		expression = parse("T(Boolean).valueOf('true') == T(Boolean).valueOf('true')");
1449 		assertTrue((Boolean)expression.getValue());
1450 		assertCanCompile(expression);
1451 		assertTrue((Boolean)expression.getValue());
1452 
1453 		expression = parse("T(Boolean).valueOf('true') == true");
1454 		assertTrue((Boolean)expression.getValue());
1455 		assertCanCompile(expression);
1456 		assertTrue((Boolean)expression.getValue());
1457 
1458 		expression = parse("false == T(Boolean).valueOf('false')");
1459 		assertTrue((Boolean)expression.getValue());
1460 		assertCanCompile(expression);
1461 		assertTrue((Boolean)expression.getValue());
1462 	}
1463 
1464 	@Test
1465 	public void opNe() throws Exception {
1466 		expression = parse("3.0d != 4.0d");
1467 		assertCanCompile(expression);
1468 		assertTrue((Boolean)expression.getValue());
1469 		expression = parse("3446.0d != 3446.0d");
1470 		assertCanCompile(expression);
1471 		assertFalse((Boolean)expression.getValue());
1472 
1473 		expression = parse("3 != 1");
1474 		assertCanCompile(expression);
1475 		assertTrue((Boolean)expression.getValue());
1476 		expression = parse("3 != 3");
1477 		assertCanCompile(expression);
1478 		assertFalse((Boolean)expression.getValue());
1479 		
1480 		expression = parse("3.0f != 1.0f");
1481 		assertCanCompile(expression);
1482 		assertTrue((Boolean)expression.getValue());
1483 		expression = parse("2.0f != 2.0f");
1484 		assertCanCompile(expression);
1485 		assertFalse((Boolean)expression.getValue());
1486 		
1487 		expression = parse("30L != 30L");
1488 		assertCanCompile(expression);
1489 		assertFalse((Boolean)expression.getValue());
1490 		expression = parse("15L != 20L");
1491 		assertCanCompile(expression);
1492 		assertTrue((Boolean)expression.getValue());
1493 		
1494 		// not compatible number types
1495 		expression = parse("1 != 3.0d");	
1496 		assertCantCompile(expression);
1497 
1498 		expression = parse("T(Integer).valueOf(3) != 4");
1499 		assertTrue((Boolean)expression.getValue());
1500 		assertCanCompile(expression);
1501 		assertTrue((Boolean)expression.getValue());
1502 		
1503 		expression = parse("T(Integer).valueOf(3) != T(Integer).valueOf(3)");
1504 		assertFalse((Boolean)expression.getValue());
1505 		assertCanCompile(expression);
1506 		assertFalse((Boolean)expression.getValue());
1507 
1508 		expression = parse("5 != T(Integer).valueOf(3)");
1509 		assertTrue((Boolean)expression.getValue());
1510 		assertCanCompile(expression);
1511 		assertTrue((Boolean)expression.getValue());
1512 
1513 		expression = parse("T(Float).valueOf(3.0f) != 4.0f");
1514 		assertTrue((Boolean)expression.getValue());
1515 		assertCanCompile(expression);
1516 		assertTrue((Boolean)expression.getValue());
1517 		
1518 		expression = parse("T(Float).valueOf(3.0f) != T(Float).valueOf(3.0f)");
1519 		assertFalse((Boolean)expression.getValue());
1520 		assertCanCompile(expression);
1521 		assertFalse((Boolean)expression.getValue());
1522 
1523 		expression = parse("5.0f != T(Float).valueOf(3.0f)");
1524 		assertTrue((Boolean)expression.getValue());
1525 		assertCanCompile(expression);
1526 		assertTrue((Boolean)expression.getValue());
1527 		
1528 		expression = parse("T(Long).valueOf(3L) != 4L");
1529 		assertTrue((Boolean)expression.getValue());
1530 		assertCanCompile(expression);
1531 		assertTrue((Boolean)expression.getValue());
1532 		
1533 		expression = parse("T(Long).valueOf(3L) != T(Long).valueOf(3L)");
1534 		assertFalse((Boolean)expression.getValue());
1535 		assertCanCompile(expression);
1536 		assertFalse((Boolean)expression.getValue());
1537 
1538 		expression = parse("5L != T(Long).valueOf(3L)");
1539 		assertTrue((Boolean)expression.getValue());
1540 		assertCanCompile(expression);
1541 		assertTrue((Boolean)expression.getValue());	
1542 		
1543 		expression = parse("T(Double).valueOf(3.0d) == 4.0d");
1544 		assertFalse((Boolean)expression.getValue());
1545 		assertCanCompile(expression);
1546 		assertFalse((Boolean)expression.getValue());
1547 		
1548 		expression = parse("T(Double).valueOf(3.0d) == T(Double).valueOf(3.0d)");
1549 		assertTrue((Boolean)expression.getValue());
1550 		assertCanCompile(expression);
1551 		assertTrue((Boolean)expression.getValue());
1552 
1553 		expression = parse("5.0d == T(Double).valueOf(3.0d)");
1554 		assertFalse((Boolean)expression.getValue());
1555 		assertCanCompile(expression);
1556 		assertFalse((Boolean)expression.getValue());
1557 
1558 		expression = parse("false == true");
1559 		assertFalse((Boolean)expression.getValue());
1560 		assertCanCompile(expression);
1561 		assertFalse((Boolean)expression.getValue());
1562 		
1563 		expression = parse("T(Boolean).valueOf('true') == T(Boolean).valueOf('true')");
1564 		assertTrue((Boolean)expression.getValue());
1565 		assertCanCompile(expression);
1566 		assertTrue((Boolean)expression.getValue());
1567 
1568 		expression = parse("T(Boolean).valueOf('true') == true");
1569 		assertTrue((Boolean)expression.getValue());
1570 		assertCanCompile(expression);
1571 		assertTrue((Boolean)expression.getValue());
1572 
1573 		expression = parse("false == T(Boolean).valueOf('false')");
1574 		assertTrue((Boolean)expression.getValue());
1575 		assertCanCompile(expression);
1576 		assertTrue((Boolean)expression.getValue());
1577 	}
1578 	
1579 	@Test
1580 	public void opPlus() throws Exception {
1581 		expression = parse("2+2");
1582 		expression.getValue();
1583 		assertCanCompile(expression);
1584 		assertEquals(4,expression.getValue());
1585 		
1586 		expression = parse("2L+2L");
1587 		expression.getValue();
1588 		assertCanCompile(expression);
1589 		assertEquals(4L,expression.getValue());
1590 
1591 		expression = parse("2.0f+2.0f");
1592 		expression.getValue();
1593 		assertCanCompile(expression);
1594 		assertEquals(4.0f,expression.getValue());
1595 
1596 		expression = parse("3.0d+4.0d");
1597 		expression.getValue();
1598 		assertCanCompile(expression);
1599 		assertEquals(7.0d,expression.getValue());
1600 		
1601 		expression = parse("+1");
1602 		expression.getValue();
1603 		assertCanCompile(expression);
1604 		assertEquals(1,expression.getValue());		
1605 
1606 		expression = parse("+1L");
1607 		expression.getValue();
1608 		assertCanCompile(expression);
1609 		assertEquals(1L,expression.getValue());		
1610 
1611 		expression = parse("+1.5f");
1612 		expression.getValue();
1613 		assertCanCompile(expression);
1614 		assertEquals(1.5f,expression.getValue());		
1615 
1616 		expression = parse("+2.5d");
1617 		expression.getValue();
1618 		assertCanCompile(expression);
1619 		assertEquals(2.5d,expression.getValue());	
1620 
1621 		expression = parse("+T(Double).valueOf(2.5d)");
1622 		expression.getValue();
1623 		assertCanCompile(expression);
1624 		assertEquals(2.5d,expression.getValue());	
1625 		
1626 		expression = parse("T(Integer).valueOf(2)+6");
1627 		assertEquals(8,expression.getValue());
1628 		assertCanCompile(expression);
1629 		assertEquals(8,expression.getValue());
1630 		
1631 		expression = parse("T(Integer).valueOf(1)+T(Integer).valueOf(3)");
1632 		assertEquals(4,expression.getValue());
1633 		assertCanCompile(expression);
1634 		assertEquals(4,expression.getValue());
1635 
1636 		expression = parse("1+T(Integer).valueOf(3)");
1637 		assertEquals(4,expression.getValue());
1638 		assertCanCompile(expression);
1639 		assertEquals(4,expression.getValue());
1640 
1641 		expression = parse("T(Float).valueOf(2.0f)+6");
1642 		assertEquals(8.0f,expression.getValue());
1643 		assertCantCompile(expression);
1644 		
1645 		expression = parse("T(Float).valueOf(2.0f)+T(Float).valueOf(3.0f)");
1646 		assertEquals(5.0f,expression.getValue());
1647 		assertCanCompile(expression);
1648 		assertEquals(5.0f,expression.getValue());
1649 
1650 		expression = parse("3L+T(Long).valueOf(4L)");
1651 		assertEquals(7L,expression.getValue());
1652 		assertCanCompile(expression);
1653 		assertEquals(7L,expression.getValue());
1654 
1655 		expression = parse("T(Long).valueOf(2L)+6");
1656 		assertEquals(8L,expression.getValue());
1657 		assertCantCompile(expression);
1658 		
1659 		expression = parse("T(Long).valueOf(2L)+T(Long).valueOf(3L)");
1660 		assertEquals(5L,expression.getValue());
1661 		assertCanCompile(expression);
1662 		assertEquals(5L,expression.getValue());
1663 
1664 		expression = parse("1L+T(Long).valueOf(2L)");
1665 		assertEquals(3L,expression.getValue());
1666 		assertCanCompile(expression);
1667 		assertEquals(3L,expression.getValue());
1668 	}
1669 	
1670 	@Test
1671 	public void opPlusString() throws Exception {
1672 		expression = parse("'hello' + 'world'");
1673 		assertEquals("helloworld",expression.getValue());
1674 		assertCanCompile(expression);
1675 		assertEquals("helloworld",expression.getValue());
1676 
1677 		// Method with string return
1678 		expression = parse("'hello' + getWorld()");
1679 		assertEquals("helloworld",expression.getValue(new Greeter()));
1680 		assertCanCompile(expression);
1681 		assertEquals("helloworld",expression.getValue(new Greeter()));
1682 		
1683 		// Method with string return
1684 		expression = parse("getWorld() + 'hello'");
1685 		assertEquals("worldhello",expression.getValue(new Greeter()));
1686 		assertCanCompile(expression);
1687 		assertEquals("worldhello",expression.getValue(new Greeter()));
1688 
1689 		// Three strings, optimal bytecode would only use one StringBuilder
1690 		expression = parse("'hello' + getWorld() + ' spring'");
1691 		assertEquals("helloworld spring",expression.getValue(new Greeter()));
1692 		assertCanCompile(expression);
1693 		assertEquals("helloworld spring",expression.getValue(new Greeter()));
1694 		
1695 		// Three strings, optimal bytecode would only use one StringBuilder
1696 		expression = parse("'hello' + 3 + ' spring'");
1697 		assertEquals("hello3 spring",expression.getValue(new Greeter()));
1698 		assertCantCompile(expression);
1699 		
1700 		expression = parse("object + 'a'");
1701 		assertEquals("objecta",expression.getValue(new Greeter()));
1702 		assertCanCompile(expression);
1703 		assertEquals("objecta",expression.getValue(new Greeter()));
1704 		
1705 		expression = parse("'a'+object");
1706 		assertEquals("aobject",expression.getValue(new Greeter()));
1707 		assertCanCompile(expression);
1708 		assertEquals("aobject",expression.getValue(new Greeter()));
1709 
1710 		expression = parse("'a'+object+'a'");
1711 		assertEquals("aobjecta",expression.getValue(new Greeter()));
1712 		assertCanCompile(expression);
1713 		assertEquals("aobjecta",expression.getValue(new Greeter()));
1714 
1715 		expression = parse("object+'a'+object");
1716 		assertEquals("objectaobject",expression.getValue(new Greeter()));
1717 		assertCanCompile(expression);
1718 		assertEquals("objectaobject",expression.getValue(new Greeter()));
1719 
1720 		expression = parse("object+object");
1721 		assertEquals("objectobject",expression.getValue(new Greeter()));
1722 		assertCanCompile(expression);
1723 		assertEquals("objectobject",expression.getValue(new Greeter()));
1724 	}
1725 	
1726 	public static class Greeter {
1727 		public String getWorld() {
1728 			return "world"; 
1729 		}
1730 		
1731 		public Object getObject() {
1732 			return "object";
1733 		}
1734 	}
1735 
1736 	@Test
1737 	public void opMinus() throws Exception {
1738 		expression = parse("2-2");
1739 		expression.getValue();
1740 		assertCanCompile(expression);
1741 		assertEquals(0,expression.getValue());
1742 		
1743 		expression = parse("4L-2L");
1744 		expression.getValue();
1745 		assertCanCompile(expression);
1746 		assertEquals(2L,expression.getValue());
1747 
1748 		expression = parse("4.0f-2.0f");
1749 		expression.getValue();
1750 		assertCanCompile(expression);
1751 		assertEquals(2.0f,expression.getValue());
1752 
1753 		expression = parse("3.0d-4.0d");
1754 		expression.getValue();
1755 		assertCanCompile(expression);
1756 		assertEquals(-1.0d,expression.getValue());
1757 		
1758 		expression = parse("-1");
1759 		expression.getValue();
1760 		assertCanCompile(expression);
1761 		assertEquals(-1,expression.getValue());		
1762 
1763 		expression = parse("-1L");
1764 		expression.getValue();
1765 		assertCanCompile(expression);
1766 		assertEquals(-1L,expression.getValue());		
1767 
1768 		expression = parse("-1.5f");
1769 		expression.getValue();
1770 		assertCanCompile(expression);
1771 		assertEquals(-1.5f,expression.getValue());		
1772 
1773 		expression = parse("-2.5d");
1774 		expression.getValue();
1775 		assertCanCompile(expression);
1776 		assertEquals(-2.5d,expression.getValue());	
1777 		
1778 		expression = parse("T(Integer).valueOf(2)-6");
1779 		assertEquals(-4,expression.getValue());
1780 		assertCanCompile(expression);
1781 		assertEquals(-4,expression.getValue());
1782 		
1783 		expression = parse("T(Integer).valueOf(1)-T(Integer).valueOf(3)");
1784 		assertEquals(-2,expression.getValue());
1785 		assertCanCompile(expression);
1786 		assertEquals(-2,expression.getValue());
1787 
1788 		expression = parse("4-T(Integer).valueOf(3)");
1789 		assertEquals(1,expression.getValue());
1790 		assertCanCompile(expression);
1791 		assertEquals(1,expression.getValue());
1792 
1793 		expression = parse("T(Float).valueOf(2.0f)-6");
1794 		assertEquals(-4.0f,expression.getValue());
1795 		assertCantCompile(expression);
1796 		
1797 		expression = parse("T(Float).valueOf(8.0f)-T(Float).valueOf(3.0f)");
1798 		assertEquals(5.0f,expression.getValue());
1799 		assertCanCompile(expression);
1800 		assertEquals(5.0f,expression.getValue());
1801 
1802 		expression = parse("11L-T(Long).valueOf(4L)");
1803 		assertEquals(7L,expression.getValue());
1804 		assertCanCompile(expression);
1805 		assertEquals(7L,expression.getValue());
1806 
1807 		expression = parse("T(Long).valueOf(9L)-6");
1808 		assertEquals(3L,expression.getValue());
1809 		assertCantCompile(expression);
1810 		
1811 		expression = parse("T(Long).valueOf(4L)-T(Long).valueOf(3L)");
1812 		assertEquals(1L,expression.getValue());
1813 		assertCanCompile(expression);
1814 		assertEquals(1L,expression.getValue());
1815 
1816 		expression = parse("8L-T(Long).valueOf(2L)");
1817 		assertEquals(6L,expression.getValue());
1818 		assertCanCompile(expression);
1819 		assertEquals(6L,expression.getValue());
1820 	}
1821 	
1822 	
1823 	@Test
1824 	public void opMultiply() throws Exception {
1825 		expression = parse("2*2");
1826 		expression.getValue();
1827 		assertCanCompile(expression);
1828 		assertEquals(4,expression.getValue());
1829 		
1830 		expression = parse("2L*2L");
1831 		expression.getValue();
1832 		assertCanCompile(expression);
1833 		assertEquals(4L,expression.getValue());
1834 
1835 		expression = parse("2.0f*2.0f");
1836 		expression.getValue();
1837 		assertCanCompile(expression);
1838 		assertEquals(4.0f,expression.getValue());
1839 
1840 		expression = parse("3.0d*4.0d");
1841 		expression.getValue();
1842 		assertCanCompile(expression);
1843 		assertEquals(12.0d,expression.getValue());
1844 
1845 		expression = parse("T(Float).valueOf(2.0f)*6");
1846 		assertEquals(12.0f,expression.getValue());
1847 		assertCantCompile(expression);
1848 		
1849 		expression = parse("T(Float).valueOf(8.0f)*T(Float).valueOf(3.0f)");
1850 		assertEquals(24.0f,expression.getValue());
1851 		assertCanCompile(expression);
1852 		assertEquals(24.0f,expression.getValue());
1853 
1854 		expression = parse("11L*T(Long).valueOf(4L)");
1855 		assertEquals(44L,expression.getValue());
1856 		assertCanCompile(expression);
1857 		assertEquals(44L,expression.getValue());
1858 
1859 		expression = parse("T(Long).valueOf(9L)*6");
1860 		assertEquals(54L,expression.getValue());
1861 		assertCantCompile(expression);
1862 		
1863 		expression = parse("T(Long).valueOf(4L)*T(Long).valueOf(3L)");
1864 		assertEquals(12L,expression.getValue());
1865 		assertCanCompile(expression);
1866 		assertEquals(12L,expression.getValue());
1867 
1868 		expression = parse("8L*T(Long).valueOf(2L)");
1869 		assertEquals(16L,expression.getValue());
1870 		assertCanCompile(expression);
1871 		assertEquals(16L,expression.getValue());
1872 
1873 		expression = parse("T(Float).valueOf(8.0f)*-T(Float).valueOf(3.0f)");
1874 		assertEquals(-24.0f,expression.getValue());
1875 		assertCanCompile(expression);
1876 		assertEquals(-24.0f,expression.getValue());
1877 	}
1878 	
1879 	@Test
1880 	public void opDivide() throws Exception {
1881 		expression = parse("2/2");
1882 		expression.getValue();
1883 		assertCanCompile(expression);
1884 		assertEquals(1,expression.getValue());
1885 		
1886 		expression = parse("2L/2L");
1887 		expression.getValue();
1888 		assertCanCompile(expression);
1889 		assertEquals(1L,expression.getValue());
1890 
1891 		expression = parse("2.0f/2.0f");
1892 		expression.getValue();
1893 		assertCanCompile(expression);
1894 		assertEquals(1.0f,expression.getValue());
1895 
1896 		expression = parse("3.0d/4.0d");
1897 		expression.getValue();
1898 		assertCanCompile(expression);
1899 		assertEquals(0.75d,expression.getValue());
1900 
1901 		expression = parse("T(Float).valueOf(6.0f)/2");
1902 		assertEquals(3.0f,expression.getValue());
1903 		assertCantCompile(expression);
1904 		
1905 		expression = parse("T(Float).valueOf(8.0f)/T(Float).valueOf(2.0f)");
1906 		assertEquals(4.0f,expression.getValue());
1907 		assertCanCompile(expression);
1908 		assertEquals(4.0f,expression.getValue());
1909 
1910 		expression = parse("12L/T(Long).valueOf(4L)");
1911 		assertEquals(3L,expression.getValue());
1912 		assertCanCompile(expression);
1913 		assertEquals(3L,expression.getValue());
1914 
1915 		expression = parse("T(Long).valueOf(44L)/11");
1916 		assertEquals(4L,expression.getValue());
1917 		assertCantCompile(expression);
1918 		
1919 		expression = parse("T(Long).valueOf(4L)/T(Long).valueOf(2L)");
1920 		assertEquals(2L,expression.getValue());
1921 		assertCanCompile(expression);
1922 		assertEquals(2L,expression.getValue());
1923 
1924 		expression = parse("8L/T(Long).valueOf(2L)");
1925 		assertEquals(4L,expression.getValue());
1926 		assertCanCompile(expression);
1927 		assertEquals(4L,expression.getValue());
1928 
1929 		expression = parse("T(Float).valueOf(8.0f)/-T(Float).valueOf(4.0f)");
1930 		assertEquals(-2.0f,expression.getValue());
1931 		assertCanCompile(expression);
1932 		assertEquals(-2.0f,expression.getValue());
1933 	}
1934 	
1935 	@Test
1936 	public void opModulus_12041() throws Exception {
1937 		expression = parse("2%2");
1938 		assertEquals(0,expression.getValue());
1939 		assertCanCompile(expression);
1940 		assertEquals(0,expression.getValue());
1941 
1942 		expression = parse("payload%2==0");
1943 		assertTrue(expression.getValue(new GenericMessageTestHelper<Integer>(4),Boolean.TYPE));
1944 		assertFalse(expression.getValue(new GenericMessageTestHelper<Integer>(5),Boolean.TYPE));
1945 		assertCanCompile(expression);
1946 		assertTrue(expression.getValue(new GenericMessageTestHelper<Integer>(4),Boolean.TYPE));
1947 		assertFalse(expression.getValue(new GenericMessageTestHelper<Integer>(5),Boolean.TYPE));
1948 
1949 		expression = parse("8%3");
1950 		assertEquals(2,expression.getValue());
1951 		assertCanCompile(expression);
1952 		assertEquals(2,expression.getValue());
1953 		
1954 		expression = parse("17L%5L");
1955 		assertEquals(2L,expression.getValue());
1956 		assertCanCompile(expression);
1957 		assertEquals(2L,expression.getValue());
1958 
1959 		expression = parse("3.0f%2.0f");
1960 		assertEquals(1.0f,expression.getValue());
1961 		assertCanCompile(expression);
1962 		assertEquals(1.0f,expression.getValue());
1963 
1964 		expression = parse("3.0d%4.0d");
1965 		assertEquals(3.0d,expression.getValue());
1966 		assertCanCompile(expression);
1967 		assertEquals(3.0d,expression.getValue());
1968 
1969 		expression = parse("T(Float).valueOf(6.0f)%2");
1970 		assertEquals(0.0f,expression.getValue());
1971 		assertCantCompile(expression);
1972 		
1973 		expression = parse("T(Float).valueOf(6.0f)%4");
1974 		assertEquals(2.0f,expression.getValue());
1975 		assertCantCompile(expression);
1976 
1977 		expression = parse("T(Float).valueOf(8.0f)%T(Float).valueOf(3.0f)");
1978 		assertEquals(2.0f,expression.getValue());
1979 		assertCanCompile(expression);
1980 		assertEquals(2.0f,expression.getValue());
1981 
1982 		expression = parse("13L%T(Long).valueOf(4L)");
1983 		assertEquals(1L,expression.getValue());
1984 		assertCanCompile(expression);
1985 		assertEquals(1L,expression.getValue());
1986 
1987 		expression = parse("T(Long).valueOf(44L)%12");
1988 		assertEquals(8L,expression.getValue());
1989 		assertCantCompile(expression);
1990 		
1991 		expression = parse("T(Long).valueOf(9L)%T(Long).valueOf(2L)");
1992 		assertEquals(1L,expression.getValue());
1993 		assertCanCompile(expression);
1994 		assertEquals(1L,expression.getValue());
1995 
1996 		expression = parse("7L%T(Long).valueOf(2L)");
1997 		assertEquals(1L,expression.getValue());
1998 		assertCanCompile(expression);
1999 		assertEquals(1L,expression.getValue());
2000 
2001 		expression = parse("T(Float).valueOf(9.0f)%-T(Float).valueOf(4.0f)");
2002 		assertEquals(1.0f,expression.getValue());
2003 		assertCanCompile(expression);
2004 		assertEquals(1.0f,expression.getValue());
2005 	}
2006 
2007 	@Test
2008 	public void failsWhenSettingContextForExpression_SPR12326() {
2009 	    SpelExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, this
2010 	            .getClass().getClassLoader()));
2011 	    Person3 person = new Person3("foo", 1);
2012 	    SpelExpression expression = parser.parseRaw("#it?.age?.equals([0])");
2013 	    StandardEvaluationContext context = new StandardEvaluationContext(new Object[] { 1 });
2014 	    context.setVariable("it", person);
2015 	    expression.setEvaluationContext(context);
2016 	    assertTrue(expression.getValue(Boolean.class));
2017 	    assertTrue(expression.getValue(Boolean.class));	     
2018 	    assertCanCompile(expression);
2019 	    assertTrue(expression.getValue(Boolean.class));
2020 	}
2021 	
2022 	@Test
2023 	public void constructorReference_SPR12326() {
2024 		String type = this.getClass().getName();
2025 		String prefix = "new "+type+".Obj";
2026 
2027 		expression = parser.parseExpression(prefix+"([0])");
2028 		assertEquals("test", ((Obj) expression.getValue(new Object[] { "test" })).param1);
2029 		assertCanCompile(expression);
2030 		assertEquals("test", ((Obj) expression.getValue(new Object[] { "test" })).param1);
2031 		
2032 		expression = parser.parseExpression(prefix+"2('foo','bar').output");
2033 		assertEquals("foobar", expression.getValue(String.class));
2034 		assertCanCompile(expression);
2035 		assertEquals("foobar", expression.getValue(String.class));
2036 
2037 		expression = parser.parseExpression(prefix+"2('foo').output");
2038 		assertEquals("foo", expression.getValue(String.class));
2039 		assertCanCompile(expression);
2040 		assertEquals("foo", expression.getValue(String.class));
2041 
2042 		expression = parser.parseExpression(prefix+"2().output");
2043 		assertEquals("", expression.getValue(String.class));
2044 		assertCanCompile(expression);
2045 		assertEquals("", expression.getValue(String.class));
2046 		
2047 		expression = parser.parseExpression(prefix+"3(1,2,3).output");
2048 		assertEquals("123", expression.getValue(String.class));
2049 		assertCanCompile(expression);
2050 		assertEquals("123", expression.getValue(String.class));
2051 
2052 		expression = parser.parseExpression(prefix+"3(1).output");
2053 		assertEquals("1", expression.getValue(String.class));
2054 		assertCanCompile(expression);
2055 		assertEquals("1", expression.getValue(String.class));
2056 
2057 		expression = parser.parseExpression(prefix+"3().output");
2058 		assertEquals("", expression.getValue(String.class));
2059 		assertCanCompile(expression);
2060 		assertEquals("", expression.getValue(String.class));
2061 		
2062 		expression = parser.parseExpression(prefix+"3('abc',5.0f,1,2,3).output");
2063 		assertEquals("abc:5.0:123", expression.getValue(String.class));
2064 		assertCanCompile(expression);
2065 		assertEquals("abc:5.0:123", expression.getValue(String.class));
2066 
2067 		expression = parser.parseExpression(prefix+"3('abc',5.0f,1).output");
2068 		assertEquals("abc:5.0:1", expression.getValue(String.class));
2069 		assertCanCompile(expression);
2070 		assertEquals("abc:5.0:1", expression.getValue(String.class));
2071 
2072 		expression = parser.parseExpression(prefix+"3('abc',5.0f).output");
2073 		assertEquals("abc:5.0:", expression.getValue(String.class));
2074 		assertCanCompile(expression);
2075 		assertEquals("abc:5.0:", expression.getValue(String.class));
2076 		
2077 		expression = parser.parseExpression(prefix+"4(#root).output");
2078 		assertEquals("123", expression.getValue(new int[]{1,2,3},String.class));
2079 		assertCanCompile(expression);
2080 		assertEquals("123", expression.getValue(new int[]{1,2,3},String.class));
2081 	}
2082 	
2083 	@Test
2084 	public void methodReferenceMissingCastAndRootObjectAccessing_SPR12326() {
2085 		// Need boxing code on the 1 so that toString() can be called
2086 		expression = parser.parseExpression("1.toString()");
2087 		assertEquals("1", expression.getValue());
2088 		assertCanCompile(expression);
2089 		assertEquals("1", expression.getValue());
2090 
2091 		expression = parser.parseExpression("#it?.age.equals([0])");
2092 		Person person = new Person(1);
2093 		StandardEvaluationContext context = 
2094 				new StandardEvaluationContext(new Object[] { person.getAge() });
2095 		context.setVariable("it", person);
2096 		assertTrue(expression.getValue(context, Boolean.class));
2097 		assertCanCompile(expression);
2098 		assertTrue(expression.getValue(context, Boolean.class));
2099 
2100 		// Variant of above more like what was in the bug report:
2101 		SpelExpressionParser parser = new SpelExpressionParser(
2102 				new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE,
2103 						this.getClass().getClassLoader()));
2104 
2105 		SpelExpression ex = parser.parseRaw("#it?.age.equals([0])");
2106 		context = new StandardEvaluationContext(new Object[] { person.getAge() });
2107 		context.setVariable("it", person);
2108 		assertTrue(ex.getValue(context, Boolean.class));
2109 		assertTrue(ex.getValue(context, Boolean.class));
2110 		
2111 		PersonInOtherPackage person2 = new PersonInOtherPackage(1);
2112 		ex = parser.parseRaw("#it?.age.equals([0])");
2113 		context = 
2114 				new StandardEvaluationContext(new Object[] { person2.getAge() });
2115 		context.setVariable("it", person2);
2116 		assertTrue(ex.getValue(context, Boolean.class));
2117 		assertTrue(ex.getValue(context, Boolean.class));
2118 		
2119 		ex = parser.parseRaw("#it?.age.equals([0])");
2120 		context = 
2121 				new StandardEvaluationContext(new Object[] { person2.getAge() });
2122 		context.setVariable("it", person2);
2123 		assertTrue((Boolean)ex.getValue(context));
2124 		assertTrue((Boolean)ex.getValue(context));
2125 	}
2126 		 
2127 	public class Person {
2128 	 
2129 	    private int age;
2130 	 
2131 	    public Person(int age) {
2132 	        this.age = age;
2133 	    }
2134 	 
2135 	    public int getAge() {
2136 	        return age;
2137 	    }
2138 	 
2139 	    public void setAge(int age) {
2140 	        this.age = age;
2141 	    }
2142 	}
2143 	
2144 	public class Person3 {
2145 		 
2146 	    private int age;
2147 	 
2148 	    public Person3(String name, int age) {
2149 	        this.age = age;
2150 	    }
2151 	 
2152 	    public int getAge() {
2153 	        return age;
2154 	    }
2155 	 
2156 	    public void setAge(int age) {
2157 	        this.age = age;
2158 	    }
2159 	}
2160 
2161 	@Test
2162 	public void constructorReference() throws Exception {
2163 		// simple ctor
2164 		expression = parser.parseExpression("new String('123')");
2165 		assertEquals("123",expression.getValue());
2166 		assertCanCompile(expression);
2167 		assertEquals("123",expression.getValue());
2168 
2169 		String testclass8 = "org.springframework.expression.spel.SpelCompilationCoverageTests$TestClass8"; 
2170 		// multi arg ctor that includes primitives
2171 		expression = parser.parseExpression("new "+testclass8+"(42,'123',4.0d,true)");
2172 		assertEquals(testclass8,expression.getValue().getClass().getName());
2173 		assertCanCompile(expression);
2174 		Object o = expression.getValue();
2175 		assertEquals(testclass8,o.getClass().getName());
2176 		TestClass8 tc8 = (TestClass8)o;
2177 		assertEquals(42,tc8.i);
2178 		assertEquals("123",tc8.s);
2179 		assertEquals(4.0d,tc8.d,0.5d);
2180 		assertEquals(true,tc8.z);
2181 		
2182 		// no-arg ctor
2183 		expression = parser.parseExpression("new "+testclass8+"()");
2184 		assertEquals(testclass8,expression.getValue().getClass().getName());
2185 		assertCanCompile(expression);
2186 		o = expression.getValue();
2187 		assertEquals(testclass8,o.getClass().getName());
2188 		
2189 		// pass primitive to reference type ctor
2190 		expression = parser.parseExpression("new "+testclass8+"(42)");
2191 		assertEquals(testclass8,expression.getValue().getClass().getName());
2192 		assertCanCompile(expression);
2193 		o = expression.getValue();
2194 		assertEquals(testclass8,o.getClass().getName());
2195 		tc8 = (TestClass8)o;
2196 		assertEquals(42,tc8.i);
2197 
2198 		// private class, can't compile it
2199 		String testclass9 = "org.springframework.expression.spel.SpelCompilationCoverageTests$TestClass9"; 
2200 		expression = parser.parseExpression("new "+testclass9+"(42)");
2201 		assertEquals(testclass9,expression.getValue().getClass().getName());
2202 		assertCantCompile(expression);
2203 	}
2204 	
2205 	@Test
2206 	public void methodReferenceReflectiveMethodSelectionWithVarargs() throws Exception {
2207 		TestClass10 tc = new TestClass10();
2208 		
2209 		// Should call the non varargs version of concat
2210 		// (which causes the '::' prefix in test output)
2211 		expression = parser.parseExpression("concat('test')");
2212 		assertCantCompile(expression);
2213 		expression.getValue(tc);
2214 		assertEquals("::test",tc.s);
2215 		assertCanCompile(expression);
2216 		tc.reset();
2217 		expression.getValue(tc);
2218 		assertEquals("::test",tc.s);
2219 		tc.reset();		
2220 
2221 		// This will call the varargs concat with an empty array
2222 		expression = parser.parseExpression("concat()");
2223 		assertCantCompile(expression);
2224 		expression.getValue(tc);
2225 		assertEquals("",tc.s);
2226 		assertCanCompile(expression);
2227 		tc.reset();
2228 		expression.getValue(tc);
2229 		assertEquals("",tc.s);
2230 		tc.reset();		
2231 		
2232 		// Should call the non varargs version of concat
2233 		// (which causes the '::' prefix in test output)
2234 		expression = parser.parseExpression("concat2('test')");
2235 		assertCantCompile(expression);
2236 		expression.getValue(tc);
2237 		assertEquals("::test",tc.s);
2238 		assertCanCompile(expression);
2239 		tc.reset();
2240 		expression.getValue(tc);
2241 		assertEquals("::test",tc.s);
2242 		tc.reset();		
2243 
2244 		// This will call the varargs concat with an empty array
2245 		expression = parser.parseExpression("concat2()");
2246 		assertCantCompile(expression);
2247 		expression.getValue(tc);
2248 		assertEquals("",tc.s);
2249 		assertCanCompile(expression);
2250 		tc.reset();
2251 		expression.getValue(tc);
2252 		assertEquals("",tc.s);
2253 		tc.reset();		
2254 	}
2255 
2256 	@Test
2257 	public void methodReferenceVarargs() throws Exception {
2258 		TestClass5 tc = new TestClass5();
2259 		
2260 		// varargs string
2261 		expression = parser.parseExpression("eleven()");
2262 		assertCantCompile(expression);
2263 		expression.getValue(tc);
2264 		assertEquals("",tc.s);
2265 		assertCanCompile(expression);
2266 		tc.reset();
2267 		expression.getValue(tc);
2268 		assertEquals("",tc.s);
2269 		tc.reset();
2270 		
2271 		// varargs string
2272 		expression = parser.parseExpression("eleven('aaa')");
2273 		assertCantCompile(expression);
2274 		expression.getValue(tc);
2275 		assertEquals("aaa",tc.s);
2276 		assertCanCompile(expression);
2277 		tc.reset();
2278 		expression.getValue(tc);
2279 		assertEquals("aaa",tc.s);
2280 		tc.reset();
2281 		
2282 		// varargs string
2283 		expression = parser.parseExpression("eleven(stringArray)");
2284 		assertCantCompile(expression);
2285 		expression.getValue(tc);
2286 		assertEquals("aaabbbccc",tc.s);
2287 		assertCanCompile(expression);
2288 		tc.reset();
2289 		expression.getValue(tc);
2290 		assertEquals("aaabbbccc",tc.s);
2291 		tc.reset();
2292 
2293 		// varargs string
2294 		expression = parser.parseExpression("eleven('aaa','bbb','ccc')");
2295 		assertCantCompile(expression);
2296 		expression.getValue(tc);
2297 		assertEquals("aaabbbccc",tc.s);
2298 		assertCanCompile(expression);
2299 		tc.reset();
2300 		expression.getValue(tc);
2301 		assertEquals("aaabbbccc",tc.s);
2302 		tc.reset();
2303 		
2304 		expression = parser.parseExpression("sixteen('aaa','bbb','ccc')");
2305 		assertCantCompile(expression);
2306 		expression.getValue(tc);
2307 		assertEquals("aaabbbccc",tc.s);
2308 		assertCanCompile(expression);
2309 		tc.reset();
2310 		expression.getValue(tc);
2311 		assertEquals("aaabbbccc",tc.s);
2312 		tc.reset();
2313 		
2314 		// TODO Fails related to conversion service converting a String[] to satisfy Object...
2315 //		expression = parser.parseExpression("sixteen(stringArray)");
2316 //		assertCantCompile(expression);
2317 //		expression.getValue(tc);
2318 //		assertEquals("aaabbbccc",tc.s);
2319 //		assertCanCompile(expression);
2320 //		tc.reset();
2321 //		expression.getValue(tc);
2322 //		assertEquals("aaabbbccc",tc.s);
2323 //		tc.reset();
2324 
2325 		// varargs int
2326 		expression = parser.parseExpression("twelve(1,2,3)");
2327 		assertCantCompile(expression);
2328 		expression.getValue(tc);
2329 		assertEquals(6,tc.i);
2330 		assertCanCompile(expression);
2331 		tc.reset();
2332 		expression.getValue(tc);
2333 		assertEquals(6,tc.i);
2334 		tc.reset();
2335 		
2336 		expression = parser.parseExpression("twelve(1)");
2337 		assertCantCompile(expression);
2338 		expression.getValue(tc);
2339 		assertEquals(1,tc.i);
2340 		assertCanCompile(expression);
2341 		tc.reset();
2342 		expression.getValue(tc);
2343 		assertEquals(1,tc.i);
2344 		tc.reset();
2345 
2346 		// one string then varargs string
2347 		expression = parser.parseExpression("thirteen('aaa','bbb','ccc')");
2348 		assertCantCompile(expression);
2349 		expression.getValue(tc);
2350 		assertEquals("aaa::bbbccc",tc.s);
2351 		assertCanCompile(expression);
2352 		tc.reset();
2353 		expression.getValue(tc);
2354 		assertEquals("aaa::bbbccc",tc.s);
2355 		tc.reset();
2356 		
2357 		// nothing passed to varargs parameter
2358 		expression = parser.parseExpression("thirteen('aaa')");
2359 		assertCantCompile(expression);
2360 		expression.getValue(tc);
2361 		assertEquals("aaa::",tc.s);
2362 		assertCanCompile(expression);
2363 		tc.reset();
2364 		expression.getValue(tc);
2365 		assertEquals("aaa::",tc.s);
2366 		tc.reset();
2367 		
2368 		// nested arrays
2369 		expression = parser.parseExpression("fourteen('aaa',stringArray,stringArray)");
2370 		assertCantCompile(expression);
2371 		expression.getValue(tc);
2372 		assertEquals("aaa::{aaabbbccc}{aaabbbccc}",tc.s);
2373 		assertCanCompile(expression);
2374 		tc.reset();
2375 		expression.getValue(tc);
2376 		assertEquals("aaa::{aaabbbccc}{aaabbbccc}",tc.s);
2377 		tc.reset();
2378 		
2379 		// nested primitive array
2380 		expression = parser.parseExpression("fifteen('aaa',intArray,intArray)");
2381 		assertCantCompile(expression);
2382 		expression.getValue(tc);
2383 		assertEquals("aaa::{112233}{112233}",tc.s);
2384 		assertCanCompile(expression);
2385 		tc.reset();
2386 		expression.getValue(tc);
2387 		assertEquals("aaa::{112233}{112233}",tc.s);
2388 		tc.reset();
2389 		
2390 		// varargs boolean
2391 		expression = parser.parseExpression("arrayz(true,true,false)");
2392 		assertCantCompile(expression);
2393 		expression.getValue(tc);
2394 		assertEquals("truetruefalse",tc.s);
2395 		assertCanCompile(expression);
2396 		tc.reset();
2397 		expression.getValue(tc);
2398 		assertEquals("truetruefalse",tc.s);
2399 		tc.reset();
2400 		
2401 		expression = parser.parseExpression("arrayz(true)");
2402 		assertCantCompile(expression);
2403 		expression.getValue(tc);
2404 		assertEquals("true",tc.s);
2405 		assertCanCompile(expression);
2406 		tc.reset();
2407 		expression.getValue(tc);
2408 		assertEquals("true",tc.s);
2409 		tc.reset();
2410 		
2411 		// varargs short
2412 		expression = parser.parseExpression("arrays(s1,s2,s3)");
2413 		assertCantCompile(expression);
2414 		expression.getValue(tc);
2415 		assertEquals("123",tc.s);
2416 		assertCanCompile(expression);
2417 		tc.reset();
2418 		expression.getValue(tc);
2419 		assertEquals("123",tc.s);
2420 		tc.reset();
2421 		
2422 		expression = parser.parseExpression("arrays(s1)");
2423 		assertCantCompile(expression);
2424 		expression.getValue(tc);
2425 		assertEquals("1",tc.s);
2426 		assertCanCompile(expression);
2427 		tc.reset();
2428 		expression.getValue(tc);
2429 		assertEquals("1",tc.s);
2430 		tc.reset();
2431 		
2432 		// varargs double
2433 		expression = parser.parseExpression("arrayd(1.0d,2.0d,3.0d)");
2434 		assertCantCompile(expression);
2435 		expression.getValue(tc);
2436 		assertEquals("1.02.03.0",tc.s);
2437 		assertCanCompile(expression);
2438 		tc.reset();
2439 		expression.getValue(tc);
2440 		assertEquals("1.02.03.0",tc.s);
2441 		tc.reset();
2442 
2443 		expression = parser.parseExpression("arrayd(1.0d)");
2444 		assertCantCompile(expression);
2445 		expression.getValue(tc);
2446 		assertEquals("1.0",tc.s);
2447 		assertCanCompile(expression);
2448 		tc.reset();
2449 		expression.getValue(tc);
2450 		assertEquals("1.0",tc.s);
2451 		tc.reset();
2452 		
2453 		// varargs long
2454 		expression = parser.parseExpression("arrayj(l1,l2,l3)");
2455 		assertCantCompile(expression);
2456 		expression.getValue(tc);
2457 		assertEquals("123",tc.s);
2458 		assertCanCompile(expression);
2459 		tc.reset();
2460 		expression.getValue(tc);
2461 		assertEquals("123",tc.s);
2462 		tc.reset();
2463 
2464 		expression = parser.parseExpression("arrayj(l1)");
2465 		assertCantCompile(expression);
2466 		expression.getValue(tc);
2467 		assertEquals("1",tc.s);
2468 		assertCanCompile(expression);
2469 		tc.reset();
2470 		expression.getValue(tc);
2471 		assertEquals("1",tc.s);
2472 		tc.reset();
2473 
2474 		// varargs char
2475 		expression = parser.parseExpression("arrayc(c1,c2,c3)");
2476 		assertCantCompile(expression);
2477 		expression.getValue(tc);
2478 		assertEquals("abc",tc.s);
2479 		assertCanCompile(expression);
2480 		tc.reset();
2481 		expression.getValue(tc);
2482 		assertEquals("abc",tc.s);
2483 		tc.reset();
2484 
2485 		expression = parser.parseExpression("arrayc(c1)");
2486 		assertCantCompile(expression);
2487 		expression.getValue(tc);
2488 		assertEquals("a",tc.s);
2489 		assertCanCompile(expression);
2490 		tc.reset();
2491 		expression.getValue(tc);
2492 		assertEquals("a",tc.s);
2493 		tc.reset();
2494 
2495 		// varargs byte
2496 		expression = parser.parseExpression("arrayb(b1,b2,b3)");
2497 		assertCantCompile(expression);
2498 		expression.getValue(tc);
2499 		assertEquals("656667",tc.s);
2500 		assertCanCompile(expression);
2501 		tc.reset();
2502 		expression.getValue(tc);
2503 		assertEquals("656667",tc.s);
2504 		tc.reset();
2505 		
2506 		expression = parser.parseExpression("arrayb(b1)");
2507 		assertCantCompile(expression);
2508 		expression.getValue(tc);
2509 		assertEquals("65",tc.s);
2510 		assertCanCompile(expression);
2511 		tc.reset();
2512 		expression.getValue(tc);
2513 		assertEquals("65",tc.s);
2514 		tc.reset();
2515 
2516 		// varargs float
2517 		expression = parser.parseExpression("arrayf(f1,f2,f3)");
2518 		assertCantCompile(expression);
2519 		expression.getValue(tc);
2520 		assertEquals("1.02.03.0",tc.s);
2521 		assertCanCompile(expression);
2522 		tc.reset();
2523 		expression.getValue(tc);
2524 		assertEquals("1.02.03.0",tc.s);
2525 		tc.reset();
2526 		
2527 		expression = parser.parseExpression("arrayf(f1)");
2528 		assertCantCompile(expression);
2529 		expression.getValue(tc);
2530 		assertEquals("1.0",tc.s);
2531 		assertCanCompile(expression);
2532 		tc.reset();
2533 		expression.getValue(tc);
2534 		assertEquals("1.0",tc.s);
2535 		tc.reset();
2536 	}
2537 	
2538 	@Test
2539 	public void methodReference() throws Exception {
2540 		TestClass5 tc = new TestClass5();
2541 		
2542 		// non-static method, no args, void return
2543 		expression = parser.parseExpression("one()");
2544 		assertCantCompile(expression);
2545 		expression.getValue(tc);
2546 		assertCanCompile(expression);
2547 		tc.reset();
2548 		expression.getValue(tc);
2549 		assertEquals(1,tc.i);
2550 		tc.reset();
2551 		
2552 		// static method, no args, void return
2553 		expression = parser.parseExpression("two()");
2554 		assertCantCompile(expression);
2555 		expression.getValue(tc);
2556 		assertCanCompile(expression);
2557 		tc.reset();
2558 		expression.getValue(tc);
2559 		assertEquals(1,TestClass5._i);
2560 		tc.reset();
2561 		
2562 		// non-static method, reference type return
2563 		expression = parser.parseExpression("three()");
2564 		assertCantCompile(expression);
2565 		expression.getValue(tc);
2566 		assertCanCompile(expression);
2567 		tc.reset();
2568 		assertEquals("hello",expression.getValue(tc));
2569 		tc.reset();
2570 
2571 		// non-static method, primitive type return
2572 		expression = parser.parseExpression("four()");
2573 		assertCantCompile(expression);
2574 		expression.getValue(tc);
2575 		assertCanCompile(expression);
2576 		tc.reset();
2577 		assertEquals(3277700L,expression.getValue(tc));
2578 		tc.reset();
2579 		
2580 		// static method, reference type return
2581 		expression = parser.parseExpression("five()");
2582 		assertCantCompile(expression);
2583 		expression.getValue(tc);
2584 		assertCanCompile(expression);
2585 		tc.reset();
2586 		assertEquals("hello",expression.getValue(tc));
2587 		tc.reset();
2588 
2589 		// static method, primitive type return
2590 		expression = parser.parseExpression("six()");
2591 		assertCantCompile(expression);
2592 		expression.getValue(tc);
2593 		assertCanCompile(expression);
2594 		tc.reset();
2595 		assertEquals(3277700L,expression.getValue(tc));
2596 		tc.reset();
2597 		
2598 		// non-static method, one parameter of reference type
2599 		expression = parser.parseExpression("seven(\"foo\")");
2600 		assertCantCompile(expression);
2601 		expression.getValue(tc);
2602 		assertCanCompile(expression);
2603 		tc.reset();
2604 		expression.getValue(tc);
2605 		assertEquals("foo",tc.s);
2606 		tc.reset();
2607 		
2608 		// static method, one parameter of reference type
2609 		expression = parser.parseExpression("eight(\"bar\")");
2610 		assertCantCompile(expression);
2611 		expression.getValue(tc);
2612 		assertCanCompile(expression);
2613 		tc.reset();
2614 		expression.getValue(tc);
2615 		assertEquals("bar",TestClass5._s);
2616 		tc.reset();
2617 
2618 		// non-static method, one parameter of primitive type
2619 		expression = parser.parseExpression("nine(231)");
2620 		assertCantCompile(expression);
2621 		expression.getValue(tc);
2622 		assertCanCompile(expression);
2623 		tc.reset();
2624 		expression.getValue(tc);
2625 		assertEquals(231,tc.i);
2626 		tc.reset();
2627 
2628 		// static method, one parameter of primitive type
2629 		expression = parser.parseExpression("ten(111)");
2630 		assertCantCompile(expression);
2631 		expression.getValue(tc);
2632 		assertCanCompile(expression);
2633 		tc.reset();
2634 		expression.getValue(tc);
2635 		assertEquals(111,TestClass5._i);
2636 		tc.reset();
2637 		
2638 		// method that gets type converted parameters
2639 		
2640 		// Converting from an int to a string
2641 		expression = parser.parseExpression("seven(123)");
2642 		assertCantCompile(expression);
2643 		expression.getValue(tc);
2644 		assertEquals("123",tc.s);
2645 		assertCantCompile(expression); // Uncompilable as argument conversion is occurring
2646 		
2647 		Expression expression = parser.parseExpression("'abcd'.substring(index1,index2)");
2648 		String resultI = expression.getValue(new TestClass1(),String.class);
2649 		assertCanCompile(expression);
2650 		String resultC = expression.getValue(new TestClass1(),String.class);
2651 		assertEquals("bc",resultI);
2652 		assertEquals("bc",resultC);
2653 		
2654 		// Converting from an int to a Number
2655 		expression = parser.parseExpression("takeNumber(123)");
2656 		assertCantCompile(expression);
2657 		expression.getValue(tc);
2658 		assertEquals("123",tc.s);
2659 		tc.reset();
2660 		assertCanCompile(expression); // The generated code should include boxing of the int to a Number
2661 		expression.getValue(tc);
2662 		assertEquals("123",tc.s);
2663 
2664 		// Passing a subtype
2665 		expression = parser.parseExpression("takeNumber(T(Integer).valueOf(42))");
2666 		assertCantCompile(expression);
2667 		expression.getValue(tc);
2668 		assertEquals("42",tc.s);
2669 		tc.reset();
2670 		assertCanCompile(expression); // The generated code should include boxing of the int to a Number
2671 		expression.getValue(tc);
2672 		assertEquals("42",tc.s);
2673 
2674 		// Passing a subtype
2675 		expression = parser.parseExpression("takeString(T(Integer).valueOf(42))");
2676 		assertCantCompile(expression);
2677 		expression.getValue(tc);
2678 		assertEquals("42",tc.s);
2679 		tc.reset();
2680 		assertCantCompile(expression); // method takes a string and we are passing an Integer
2681 	}
2682 		
2683 	
2684 	@Test 
2685 	public void errorHandling() throws Exception {
2686 		TestClass5 tc = new TestClass5();
2687 		
2688 		// changing target
2689 		
2690 		// from primitive array to reference type array
2691 		int[] is = new int[]{1,2,3};
2692 		String[] strings = new String[]{"a","b","c"};
2693 		expression = parser.parseExpression("[1]");
2694 		assertEquals(2,expression.getValue(is));
2695 		assertCanCompile(expression);
2696 		assertEquals(2,expression.getValue(is));
2697 		
2698 		try {
2699 			assertEquals(2,expression.getValue(strings));
2700 			fail();
2701 		} catch (SpelEvaluationException see) {
2702 			assertTrue(see.getCause() instanceof ClassCastException);
2703 		}
2704 		SpelCompiler.revertToInterpreted(expression);
2705 		assertEquals("b",expression.getValue(strings));
2706 		assertCanCompile(expression);
2707 		assertEquals("b",expression.getValue(strings));
2708 		
2709 		
2710 		tc.field = "foo";
2711 		expression = parser.parseExpression("seven(field)");
2712 		assertCantCompile(expression);
2713 		expression.getValue(tc);
2714 		assertEquals("foo",tc.s);
2715 		assertCanCompile(expression);
2716 		tc.reset();
2717 		tc.field="bar";
2718 		expression.getValue(tc);
2719 		
2720 		// method with changing parameter types (change reference type)
2721 		tc.obj = "foo";
2722 		expression = parser.parseExpression("seven(obj)");
2723 		assertCantCompile(expression);
2724 		expression.getValue(tc);
2725 		assertEquals("foo",tc.s);
2726 		assertCanCompile(expression);
2727 		tc.reset();
2728 		tc.obj=new Integer(42);
2729 		try {
2730 			expression.getValue(tc);
2731 			fail();
2732 		} catch (SpelEvaluationException see) {
2733 			assertTrue(see.getCause() instanceof ClassCastException);
2734 		}
2735 		
2736 		
2737 		// method with changing target
2738 		expression = parser.parseExpression("#root.charAt(0)");
2739 		assertEquals('a',expression.getValue("abc"));
2740 		assertCanCompile(expression);
2741 		try {
2742 			expression.getValue(new Integer(42));
2743 			fail();
2744 		} catch (SpelEvaluationException see) {
2745 			// java.lang.Integer cannot be cast to java.lang.String
2746 			assertTrue(see.getCause() instanceof ClassCastException);
2747 		}		
2748 	}
2749 	
2750 	@Test
2751 	public void methodReference_staticMethod() throws Exception {
2752 		Expression expression = parser.parseExpression("T(Integer).valueOf(42)");
2753 		int resultI = expression.getValue(new TestClass1(),Integer.TYPE);
2754 		assertCanCompile(expression);
2755 		int resultC = expression.getValue(new TestClass1(),Integer.TYPE);
2756 		assertEquals(42,resultI);
2757 		assertEquals(42,resultC);		
2758 	}
2759 	
2760 	@Test
2761 	public void methodReference_literalArguments_int() throws Exception {
2762 		Expression expression = parser.parseExpression("'abcd'.substring(1,3)");
2763 		String resultI = expression.getValue(new TestClass1(),String.class);
2764 		assertCanCompile(expression);
2765 		String resultC = expression.getValue(new TestClass1(),String.class);
2766 		assertEquals("bc",resultI);
2767 		assertEquals("bc",resultC);
2768 	}
2769 
2770 	@Test
2771 	public void methodReference_simpleInstanceMethodNoArg() throws Exception {
2772 		Expression expression = parser.parseExpression("toString()");
2773 		String resultI = expression.getValue(42,String.class);
2774 		assertCanCompile(expression);
2775 		String resultC = expression.getValue(42,String.class);
2776 		assertEquals("42",resultI);
2777 		assertEquals("42",resultC);
2778 	}
2779 
2780 	@Test
2781 	public void methodReference_simpleInstanceMethodNoArgReturnPrimitive() throws Exception {
2782 		expression = parser.parseExpression("intValue()");
2783 		int resultI = expression.getValue(new Integer(42),Integer.TYPE);
2784 		assertEquals(42,resultI);
2785 		assertCanCompile(expression);
2786 		int resultC = expression.getValue(new Integer(42),Integer.TYPE);
2787 		assertEquals(42,resultC);
2788 	}
2789 	
2790 	@Test
2791 	public void methodReference_simpleInstanceMethodOneArgReturnPrimitive1() throws Exception {
2792 		Expression expression = parser.parseExpression("indexOf('b')");
2793 		int resultI = expression.getValue("abc",Integer.TYPE);
2794 		assertCanCompile(expression);
2795 		int resultC = expression.getValue("abc",Integer.TYPE);
2796 		assertEquals(1,resultI);
2797 		assertEquals(1,resultC);
2798 	}
2799 
2800 	@Test
2801 	public void methodReference_simpleInstanceMethodOneArgReturnPrimitive2() throws Exception {
2802 		expression = parser.parseExpression("charAt(2)");
2803 		char resultI = expression.getValue("abc",Character.TYPE);
2804 		assertEquals('c',resultI);
2805 		assertCanCompile(expression);
2806 		char resultC = expression.getValue("abc",Character.TYPE);
2807 		assertEquals('c',resultC);
2808 	}
2809 
2810 	@Test
2811 	public void compoundExpression() throws Exception {
2812 		Payload payload = new Payload();
2813 		expression = parser.parseExpression("DR[0]");
2814 		assertEquals("instanceof Two",expression.getValue(payload).toString());
2815 		assertCanCompile(expression);
2816 		assertEquals("instanceof Two",expression.getValue(payload).toString());
2817 		ast = getAst();
2818 		assertEquals("Lorg/springframework/expression/spel/SpelCompilationCoverageTests$Two",ast.getExitDescriptor());
2819 
2820 		expression = parser.parseExpression("holder.three");
2821 		assertEquals("org.springframework.expression.spel.SpelCompilationCoverageTests$Three",expression.getValue(payload).getClass().getName());
2822 		assertCanCompile(expression);
2823 		assertEquals("org.springframework.expression.spel.SpelCompilationCoverageTests$Three",expression.getValue(payload).getClass().getName());
2824 		ast = getAst();
2825 		assertEquals("Lorg/springframework/expression/spel/SpelCompilationCoverageTests$Three",ast.getExitDescriptor());
2826 
2827 		expression = parser.parseExpression("DR[0]");
2828 		assertEquals("org.springframework.expression.spel.SpelCompilationCoverageTests$Two",expression.getValue(payload).getClass().getName());
2829 		assertCanCompile(expression);
2830 		assertEquals("org.springframework.expression.spel.SpelCompilationCoverageTests$Two",expression.getValue(payload).getClass().getName());
2831 		assertEquals("Lorg/springframework/expression/spel/SpelCompilationCoverageTests$Two",getAst().getExitDescriptor());
2832 
2833 		expression = parser.parseExpression("DR[0].three");
2834 		assertEquals("org.springframework.expression.spel.SpelCompilationCoverageTests$Three",expression.getValue(payload).getClass().getName());
2835 		assertCanCompile(expression);
2836 		assertEquals("org.springframework.expression.spel.SpelCompilationCoverageTests$Three",expression.getValue(payload).getClass().getName());
2837 		ast = getAst();
2838 		assertEquals("Lorg/springframework/expression/spel/SpelCompilationCoverageTests$Three",ast.getExitDescriptor());
2839 
2840 		expression = parser.parseExpression("DR[0].three.four");
2841 		assertEquals(0.04d,expression.getValue(payload));
2842 		assertCanCompile(expression);
2843 		assertEquals(0.04d,expression.getValue(payload));
2844 		assertEquals("D",getAst().getExitDescriptor());
2845 	}
2846 	
2847 	
2848 	@Test
2849 	public void mixingItUp_indexerOpEqTernary() throws Exception {
2850 		Map<String, String> m = new HashMap<String,String>();
2851 		m.put("andy","778");
2852 
2853 		expression = parse("['andy']==null?1:2");
2854 		System.out.println(expression.getValue(m));
2855 		assertCanCompile(expression);
2856 		assertEquals(2,expression.getValue(m));
2857 		m.remove("andy");
2858 		assertEquals(1,expression.getValue(m));
2859 	}
2860 	
2861 	@Test
2862 	public void propertyReference() throws Exception {
2863 		TestClass6 tc = new TestClass6();
2864 		
2865 		// non static field
2866 		expression = parser.parseExpression("orange");
2867 		assertCantCompile(expression);
2868 		assertEquals("value1",expression.getValue(tc));
2869 		assertCanCompile(expression);
2870 		assertEquals("value1",expression.getValue(tc));
2871 		
2872 		// static field
2873 		expression = parser.parseExpression("apple");
2874 		assertCantCompile(expression);
2875 		assertEquals("value2",expression.getValue(tc));
2876 		assertCanCompile(expression);
2877 		assertEquals("value2",expression.getValue(tc));	
2878 		
2879 		// non static getter
2880 		expression = parser.parseExpression("banana");
2881 		assertCantCompile(expression);
2882 		assertEquals("value3",expression.getValue(tc));
2883 		assertCanCompile(expression);
2884 		assertEquals("value3",expression.getValue(tc));
2885 
2886 		// static getter
2887 		expression = parser.parseExpression("plum");
2888 		assertCantCompile(expression);
2889 		assertEquals("value4",expression.getValue(tc));
2890 		assertCanCompile(expression);
2891 		assertEquals("value4",expression.getValue(tc));
2892 	}
2893 
2894 	@Test
2895 	public void propertyReferenceVisibility() { // SPR-12771
2896 		StandardEvaluationContext ctx = new StandardEvaluationContext();
2897 		ctx.setVariable("httpServletRequest", HttpServlet3RequestFactory.getOne());
2898 		// Without a fix compilation was inserting a checkcast to a private type
2899 		expression = parser.parseExpression("#httpServletRequest.servletPath");
2900 		assertEquals("wibble",expression.getValue(ctx));
2901 		assertCanCompile(expression);
2902 		assertEquals("wibble",expression.getValue(ctx));
2903 	}
2904 		
2905 	@SuppressWarnings("unchecked")
2906 	@Test
2907 	public void indexer() throws Exception {
2908 		String[] sss = new String[]{"a","b","c"};
2909 		Number[] ns = new Number[]{2,8,9};
2910 		int[] is = new int[]{8,9,10};
2911 		double[] ds = new double[]{3.0d,4.0d,5.0d};
2912 		long[] ls = new long[]{2L,3L,4L};
2913 		short[] ss = new short[]{(short)33,(short)44,(short)55};
2914 		float[] fs = new float[]{6.0f,7.0f,8.0f};
2915 		byte[] bs = new byte[]{(byte)2,(byte)3,(byte)4};
2916 		char[] cs = new char[]{'a','b','c'};
2917 				
2918 		// Access String (reference type) array
2919 		expression = parser.parseExpression("[0]");
2920 		assertEquals("a",expression.getValue(sss));
2921 		assertCanCompile(expression);
2922 		assertEquals("a",expression.getValue(sss));
2923 		assertEquals("Ljava/lang/String",getAst().getExitDescriptor());
2924 
2925 		expression = parser.parseExpression("[1]");
2926 		assertEquals(8,expression.getValue(ns));
2927 		assertCanCompile(expression);
2928 		assertEquals(8,expression.getValue(ns));
2929 		assertEquals("Ljava/lang/Number",getAst().getExitDescriptor());
2930 		
2931 		// Access int array
2932 		expression = parser.parseExpression("[2]");
2933 		assertEquals(10,expression.getValue(is));
2934 		assertCanCompile(expression);
2935 		assertEquals(10,expression.getValue(is));
2936 		assertEquals("I",getAst().getExitDescriptor());
2937 
2938 		// Access double array
2939 		expression = parser.parseExpression("[1]");
2940 		assertEquals(4.0d,expression.getValue(ds));
2941 		assertCanCompile(expression);
2942 		assertEquals(4.0d,expression.getValue(ds));
2943 		assertEquals("D",getAst().getExitDescriptor());
2944 
2945 		// Access long array
2946 		expression = parser.parseExpression("[0]");
2947 		assertEquals(2L,expression.getValue(ls));
2948 		assertCanCompile(expression);
2949 		assertEquals(2L,expression.getValue(ls));
2950 		assertEquals("J",getAst().getExitDescriptor());
2951 
2952 		// Access short array
2953 		expression = parser.parseExpression("[2]");
2954 		assertEquals((short)55,expression.getValue(ss));
2955 		assertCanCompile(expression);
2956 		assertEquals((short)55,expression.getValue(ss));
2957 		assertEquals("S",getAst().getExitDescriptor());
2958 
2959 		// Access float array
2960 		expression = parser.parseExpression("[0]");
2961 		assertEquals(6.0f,expression.getValue(fs));
2962 		assertCanCompile(expression);
2963 		assertEquals(6.0f,expression.getValue(fs));
2964 		assertEquals("F",getAst().getExitDescriptor());
2965 
2966 		// Access byte array
2967 		expression = parser.parseExpression("[2]");
2968 		assertEquals((byte)4,expression.getValue(bs));
2969 		assertCanCompile(expression);
2970 		assertEquals((byte)4,expression.getValue(bs));
2971 		assertEquals("B",getAst().getExitDescriptor());
2972 
2973 		// Access char array
2974 		expression = parser.parseExpression("[1]");
2975 		assertEquals('b',expression.getValue(cs));
2976 		assertCanCompile(expression);
2977 		assertEquals('b',expression.getValue(cs));
2978 		assertEquals("C",getAst().getExitDescriptor());
2979 		
2980 		// Collections
2981 		List<String> strings = new ArrayList<String>();
2982 		strings.add("aaa");
2983 		strings.add("bbb");
2984 		strings.add("ccc");
2985 		expression = parser.parseExpression("[1]");
2986 		assertEquals("bbb",expression.getValue(strings));
2987 		assertCanCompile(expression);
2988 		assertEquals("bbb",expression.getValue(strings));
2989 		assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
2990 		
2991 		List<Integer> ints = new ArrayList<Integer>();
2992 		ints.add(123);
2993 		ints.add(456);
2994 		ints.add(789);
2995 		expression = parser.parseExpression("[2]");
2996 		assertEquals(789,expression.getValue(ints));
2997 		assertCanCompile(expression);
2998 		assertEquals(789,expression.getValue(ints));
2999 		assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
3000 		
3001 		// Maps
3002 		Map<String,Integer> map1 = new HashMap<String,Integer>();
3003 		map1.put("aaa", 111);
3004 		map1.put("bbb", 222);
3005 		map1.put("ccc", 333);
3006 		expression = parser.parseExpression("['aaa']");
3007 		assertEquals(111,expression.getValue(map1));
3008 		assertCanCompile(expression);
3009 		assertEquals(111,expression.getValue(map1));
3010 		assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
3011 		
3012 		// Object
3013 		TestClass6 tc = new TestClass6();
3014 		expression = parser.parseExpression("['orange']");
3015 		assertEquals("value1",expression.getValue(tc));
3016 		assertCanCompile(expression);
3017 		assertEquals("value1",expression.getValue(tc));
3018 		assertEquals("Ljava/lang/String",getAst().getExitDescriptor());
3019 		
3020 		expression = parser.parseExpression("['peach']");
3021 		assertEquals(34L,expression.getValue(tc));
3022 		assertCanCompile(expression);
3023 		assertEquals(34L,expression.getValue(tc));
3024 		assertEquals("J",getAst().getExitDescriptor());
3025 
3026 		// getter
3027 		expression = parser.parseExpression("['banana']");
3028 		assertEquals("value3",expression.getValue(tc));
3029 		assertCanCompile(expression);
3030 		assertEquals("value3",expression.getValue(tc));
3031 		assertEquals("Ljava/lang/String",getAst().getExitDescriptor());
3032 		
3033 		// list of arrays
3034 		
3035 		List<String[]> listOfStringArrays = new ArrayList<String[]>();
3036 		listOfStringArrays.add(new String[]{"a","b","c"});
3037 		listOfStringArrays.add(new String[]{"d","e","f"});
3038 		expression = parser.parseExpression("[1]");
3039 		assertEquals("d e f",stringify(expression.getValue(listOfStringArrays)));
3040 		assertCanCompile(expression);
3041 		assertEquals("d e f",stringify(expression.getValue(listOfStringArrays)));
3042 		assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
3043 		
3044 		expression = parser.parseExpression("[1][0]");
3045 		assertEquals("d",stringify(expression.getValue(listOfStringArrays)));
3046 		assertCanCompile(expression);
3047 		assertEquals("d",stringify(expression.getValue(listOfStringArrays)));
3048 		assertEquals("Ljava/lang/String",getAst().getExitDescriptor());
3049 
3050 		List<Integer[]> listOfIntegerArrays = new ArrayList<Integer[]>();
3051 		listOfIntegerArrays.add(new Integer[]{1,2,3});
3052 		listOfIntegerArrays.add(new Integer[]{4,5,6});
3053 		expression = parser.parseExpression("[0]");
3054 		assertEquals("1 2 3",stringify(expression.getValue(listOfIntegerArrays)));
3055 		assertCanCompile(expression);
3056 		assertEquals("1 2 3",stringify(expression.getValue(listOfIntegerArrays)));
3057 		assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
3058 
3059 		expression = parser.parseExpression("[0][1]");
3060 		assertEquals(2,expression.getValue(listOfIntegerArrays));
3061 		assertCanCompile(expression);
3062 		assertEquals(2,expression.getValue(listOfIntegerArrays));
3063 		assertEquals("Ljava/lang/Integer",getAst().getExitDescriptor());
3064 		
3065 		// array of lists
3066 		List<String>[] stringArrayOfLists = new ArrayList[2];
3067 		stringArrayOfLists[0] = new ArrayList<String>();
3068 		stringArrayOfLists[0].add("a");
3069 		stringArrayOfLists[0].add("b");
3070 		stringArrayOfLists[0].add("c");
3071 		stringArrayOfLists[1] = new ArrayList<String>();
3072 		stringArrayOfLists[1].add("d");
3073 		stringArrayOfLists[1].add("e");
3074 		stringArrayOfLists[1].add("f");
3075 		expression = parser.parseExpression("[1]");
3076 		assertEquals("d e f",stringify(expression.getValue(stringArrayOfLists)));
3077 		assertCanCompile(expression);
3078 		assertEquals("d e f",stringify(expression.getValue(stringArrayOfLists)));
3079 		assertEquals("Ljava/util/ArrayList",getAst().getExitDescriptor());
3080 		
3081 		expression = parser.parseExpression("[1][2]");
3082 		assertEquals("f",stringify(expression.getValue(stringArrayOfLists)));
3083 		assertCanCompile(expression);
3084 		assertEquals("f",stringify(expression.getValue(stringArrayOfLists)));
3085 		assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
3086 		
3087 		// array of arrays
3088 		String[][] referenceTypeArrayOfArrays = new String[][]{new String[]{"a","b","c"},new String[]{"d","e","f"}};
3089 		expression = parser.parseExpression("[1]");
3090 		assertEquals("d e f",stringify(expression.getValue(referenceTypeArrayOfArrays)));
3091 		assertCanCompile(expression);
3092 		assertEquals("[Ljava/lang/String",getAst().getExitDescriptor());
3093 		assertEquals("d e f",stringify(expression.getValue(referenceTypeArrayOfArrays)));
3094 		assertEquals("[Ljava/lang/String",getAst().getExitDescriptor());
3095 		
3096 		expression = parser.parseExpression("[1][2]");
3097 		assertEquals("f",stringify(expression.getValue(referenceTypeArrayOfArrays)));
3098 		assertCanCompile(expression);
3099 		assertEquals("f",stringify(expression.getValue(referenceTypeArrayOfArrays)));
3100 		assertEquals("Ljava/lang/String",getAst().getExitDescriptor());
3101 		
3102 		int[][] primitiveTypeArrayOfArrays = new int[][]{new int[]{1,2,3},new int[]{4,5,6}};
3103 		expression = parser.parseExpression("[1]");
3104 		assertEquals("4 5 6",stringify(expression.getValue(primitiveTypeArrayOfArrays)));
3105 		assertCanCompile(expression);
3106 		assertEquals("4 5 6",stringify(expression.getValue(primitiveTypeArrayOfArrays)));
3107 		assertEquals("[I",getAst().getExitDescriptor());
3108 		
3109 		expression = parser.parseExpression("[1][2]");
3110 		assertEquals("6",stringify(expression.getValue(primitiveTypeArrayOfArrays)));
3111 		assertCanCompile(expression);
3112 		assertEquals("6",stringify(expression.getValue(primitiveTypeArrayOfArrays)));
3113 		assertEquals("I",getAst().getExitDescriptor());
3114 		
3115 		// list of lists of reference types
3116 		List<List<String>> listOfListOfStrings = new ArrayList<List<String>>();
3117 		List<String> list = new ArrayList<String>();
3118 		list.add("a");
3119 		list.add("b");
3120 		list.add("c");
3121 		listOfListOfStrings.add(list);
3122 		list = new ArrayList<String>();
3123 		list.add("d");
3124 		list.add("e");
3125 		list.add("f");
3126 		listOfListOfStrings.add(list);
3127 		
3128 		expression = parser.parseExpression("[1]");
3129 		assertEquals("d e f",stringify(expression.getValue(listOfListOfStrings)));
3130 		assertCanCompile(expression);
3131 		assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
3132 		assertEquals("d e f",stringify(expression.getValue(listOfListOfStrings)));
3133 		assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
3134 		
3135 		expression = parser.parseExpression("[1][2]");
3136 		assertEquals("f",stringify(expression.getValue(listOfListOfStrings)));
3137 		assertCanCompile(expression);
3138 		assertEquals("f",stringify(expression.getValue(listOfListOfStrings)));
3139 		assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
3140 		
3141 		// Map of lists
3142 		Map<String,List<String>> mapToLists = new HashMap<String,List<String>>();
3143 		list = new ArrayList<String>();
3144 		list.add("a");
3145 		list.add("b");
3146 		list.add("c");
3147 		mapToLists.put("foo", list);
3148 		expression = parser.parseExpression("['foo']");
3149 		assertEquals("a b c",stringify(expression.getValue(mapToLists)));
3150 		assertCanCompile(expression);
3151 		assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
3152 		assertEquals("a b c",stringify(expression.getValue(mapToLists)));
3153 		assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
3154 		
3155 		expression = parser.parseExpression("['foo'][2]");
3156 		assertEquals("c",stringify(expression.getValue(mapToLists)));
3157 		assertCanCompile(expression);
3158 		assertEquals("c",stringify(expression.getValue(mapToLists)));
3159 		assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
3160 		
3161 		// Map to array
3162 		Map<String,int[]> mapToIntArray = new HashMap<String,int[]>();
3163 		StandardEvaluationContext ctx = new StandardEvaluationContext();
3164 		ctx.addPropertyAccessor(new CompilableMapAccessor());
3165 		mapToIntArray.put("foo",new int[]{1,2,3});
3166 		expression = parser.parseExpression("['foo']");
3167 		assertEquals("1 2 3",stringify(expression.getValue(mapToIntArray)));
3168 		assertCanCompile(expression);
3169 		assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
3170 		assertEquals("1 2 3",stringify(expression.getValue(mapToIntArray)));
3171 		assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
3172 		
3173 		expression = parser.parseExpression("['foo'][1]");
3174 		assertEquals(2,expression.getValue(mapToIntArray));
3175 		assertCanCompile(expression);
3176 		assertEquals(2,expression.getValue(mapToIntArray));
3177 		
3178 		expression = parser.parseExpression("foo");
3179 		assertEquals("1 2 3",stringify(expression.getValue(ctx,mapToIntArray)));
3180 		assertCanCompile(expression);
3181 		assertEquals("1 2 3",stringify(expression.getValue(ctx,mapToIntArray)));
3182 		assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
3183 
3184 		expression = parser.parseExpression("foo[1]");
3185 		assertEquals(2,expression.getValue(ctx,mapToIntArray));
3186 		assertCanCompile(expression);
3187 		assertEquals(2,expression.getValue(ctx,mapToIntArray));
3188 
3189 		expression = parser.parseExpression("['foo'][2]");
3190 		assertEquals("3",stringify(expression.getValue(ctx,mapToIntArray)));
3191 		assertCanCompile(expression);
3192 		assertEquals("3",stringify(expression.getValue(ctx,mapToIntArray)));
3193 		assertEquals("I",getAst().getExitDescriptor());
3194 		
3195 		// Map array
3196 		Map<String,String>[] mapArray = new Map[1];
3197 		mapArray[0] = new HashMap<String,String>();
3198 		mapArray[0].put("key", "value1");
3199 		expression = parser.parseExpression("[0]");
3200 		assertEquals("{key=value1}",stringify(expression.getValue(mapArray)));
3201 		assertCanCompile(expression);
3202 		assertEquals("Ljava/util/Map",getAst().getExitDescriptor());
3203 		assertEquals("{key=value1}",stringify(expression.getValue(mapArray)));
3204 		assertEquals("Ljava/util/Map",getAst().getExitDescriptor());
3205 		
3206 		expression = parser.parseExpression("[0]['key']");
3207 		assertEquals("value1",stringify(expression.getValue(mapArray)));
3208 		assertCanCompile(expression);
3209 		assertEquals("value1",stringify(expression.getValue(mapArray)));
3210 		assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
3211 	}
3212 	
3213 	@Test
3214 	public void mixingItUp_propertyAccessIndexerOpLtTernaryRootNull() throws Exception {
3215 		Payload payload = new Payload();
3216 		
3217 		expression = parser.parseExpression("DR[0].three");
3218 		Object v = expression.getValue(payload);
3219 		assertEquals("Lorg/springframework/expression/spel/SpelCompilationCoverageTests$Three",getAst().getExitDescriptor());
3220 		
3221 		Expression expression = parser.parseExpression("DR[0].three.four lt 0.1d?#root:null");
3222 		v = expression.getValue(payload);
3223 		
3224 		SpelExpression sExpr = (SpelExpression)expression;
3225 		Ternary ternary = (Ternary)sExpr.getAST();
3226 		OpLT oplt = (OpLT)ternary.getChild(0);
3227 		CompoundExpression cExpr = (CompoundExpression)oplt.getLeftOperand();
3228 		String cExprExitDescriptor = cExpr.getExitDescriptor();
3229 		assertEquals("D",cExprExitDescriptor);
3230 		assertEquals("Z",oplt.getExitDescriptor());
3231 		
3232 		assertCanCompile(expression);
3233 		Object vc = expression.getValue(payload);
3234 		assertEquals(payload,v);
3235 		assertEquals(payload,vc);
3236 		payload.DR[0].three.four = 0.13d;
3237 		vc = expression.getValue(payload);
3238 		assertNull(vc);
3239 	}
3240 
3241 	@Test
3242 	public void variantGetter() throws Exception {
3243 		Payload2Holder holder = new Payload2Holder();
3244 		StandardEvaluationContext ctx = new StandardEvaluationContext();
3245 		ctx.addPropertyAccessor(new MyAccessor());
3246 		expression = parser.parseExpression("payload2.var1");
3247 		Object v = expression.getValue(ctx,holder);
3248 		assertEquals("abc",v);
3249 		
3250 //		// time it interpreted
3251 //		long stime = System.currentTimeMillis();
3252 //		for (int i=0;i<100000;i++) {
3253 //			v = expression.getValue(ctx,holder);
3254 //		}
3255 //		System.out.println((System.currentTimeMillis()-stime));
3256 //
3257 		assertCanCompile(expression);
3258 		v = expression.getValue(ctx,holder);
3259 		assertEquals("abc",v);
3260 //		
3261 //		// time it compiled
3262 //		stime = System.currentTimeMillis();
3263 //		for (int i=0;i<100000;i++) {
3264 //			v = expression.getValue(ctx,holder);
3265 //		}
3266 //		System.out.println((System.currentTimeMillis()-stime));
3267 	}
3268 	
3269 	@Test
3270 	public void compilerWithGenerics_12040() {
3271 		expression = parser.parseExpression("payload!=2");
3272 		assertTrue(expression.getValue(new GenericMessageTestHelper<Integer>(4),Boolean.class));
3273 		assertCanCompile(expression);
3274 		assertFalse(expression.getValue(new GenericMessageTestHelper<Integer>(2),Boolean.class));
3275 		
3276 		expression = parser.parseExpression("2!=payload");
3277 		assertTrue(expression.getValue(new GenericMessageTestHelper<Integer>(4),Boolean.class));
3278 		assertCanCompile(expression);
3279 		assertFalse(expression.getValue(new GenericMessageTestHelper<Integer>(2),Boolean.class));
3280 
3281 		expression = parser.parseExpression("payload!=6L");
3282 		assertTrue(expression.getValue(new GenericMessageTestHelper<Long>(4L),Boolean.class));
3283 		assertCanCompile(expression);
3284 		assertFalse(expression.getValue(new GenericMessageTestHelper<Long>(6L),Boolean.class));
3285 		
3286 		expression = parser.parseExpression("payload==2");
3287 		assertFalse(expression.getValue(new GenericMessageTestHelper<Integer>(4),Boolean.class));
3288 		assertCanCompile(expression);
3289 		assertTrue(expression.getValue(new GenericMessageTestHelper<Integer>(2),Boolean.class));
3290 		
3291 		expression = parser.parseExpression("2==payload");
3292 		assertFalse(expression.getValue(new GenericMessageTestHelper<Integer>(4),Boolean.class));
3293 		assertCanCompile(expression);
3294 		assertTrue(expression.getValue(new GenericMessageTestHelper<Integer>(2),Boolean.class));
3295 
3296 		expression = parser.parseExpression("payload==6L");
3297 		assertFalse(expression.getValue(new GenericMessageTestHelper<Long>(4L),Boolean.class));
3298 		assertCanCompile(expression);
3299 		assertTrue(expression.getValue(new GenericMessageTestHelper<Long>(6L),Boolean.class));
3300 
3301 		expression = parser.parseExpression("2==payload");
3302 		assertFalse(expression.getValue(new GenericMessageTestHelper<Integer>(4),Boolean.class));
3303 		assertCanCompile(expression);
3304 		assertTrue(expression.getValue(new GenericMessageTestHelper<Integer>(2),Boolean.class));
3305 
3306 		expression = parser.parseExpression("payload/2");
3307 		assertEquals(2,expression.getValue(new GenericMessageTestHelper<Integer>(4)));
3308 		assertCanCompile(expression);
3309 		assertEquals(3,expression.getValue(new GenericMessageTestHelper<Integer>(6)));
3310 		
3311 		expression = parser.parseExpression("100/payload");
3312 		assertEquals(25,expression.getValue(new GenericMessageTestHelper<Integer>(4)));
3313 		assertCanCompile(expression);
3314 		assertEquals(10,expression.getValue(new GenericMessageTestHelper<Integer>(10)));
3315 		
3316 		expression = parser.parseExpression("payload+2");
3317 		assertEquals(6,expression.getValue(new GenericMessageTestHelper<Integer>(4)));
3318 		assertCanCompile(expression);
3319 		assertEquals(8,expression.getValue(new GenericMessageTestHelper<Integer>(6)));
3320 		
3321 		expression = parser.parseExpression("100+payload");
3322 		assertEquals(104,expression.getValue(new GenericMessageTestHelper<Integer>(4)));
3323 		assertCanCompile(expression);
3324 		assertEquals(110,expression.getValue(new GenericMessageTestHelper<Integer>(10)));
3325 		
3326 		expression = parser.parseExpression("payload-2");
3327 		assertEquals(2,expression.getValue(new GenericMessageTestHelper<Integer>(4)));
3328 		assertCanCompile(expression);
3329 		assertEquals(4,expression.getValue(new GenericMessageTestHelper<Integer>(6)));
3330 		
3331 		expression = parser.parseExpression("100-payload");
3332 		assertEquals(96,expression.getValue(new GenericMessageTestHelper<Integer>(4)));
3333 		assertCanCompile(expression);
3334 		assertEquals(90,expression.getValue(new GenericMessageTestHelper<Integer>(10)));
3335 
3336 		expression = parser.parseExpression("payload*2");
3337 		assertEquals(8,expression.getValue(new GenericMessageTestHelper<Integer>(4)));
3338 		assertCanCompile(expression);
3339 		assertEquals(12,expression.getValue(new GenericMessageTestHelper<Integer>(6)));
3340 		
3341 		expression = parser.parseExpression("100*payload");
3342 		assertEquals(400,expression.getValue(new GenericMessageTestHelper<Integer>(4)));
3343 		assertCanCompile(expression);
3344 		assertEquals(1000,expression.getValue(new GenericMessageTestHelper<Integer>(10)));
3345 
3346 		expression = parser.parseExpression("payload/2L");
3347 		assertEquals(2L,expression.getValue(new GenericMessageTestHelper<Long>(4L)));
3348 		assertCanCompile(expression);
3349 		assertEquals(3L,expression.getValue(new GenericMessageTestHelper<Long>(6L)));
3350 		
3351 		expression = parser.parseExpression("100L/payload");
3352 		assertEquals(25L,expression.getValue(new GenericMessageTestHelper<Long>(4L)));
3353 		assertCanCompile(expression);
3354 		assertEquals(10L,expression.getValue(new GenericMessageTestHelper<Long>(10L)));
3355 
3356 		expression = parser.parseExpression("payload/2f");
3357 		assertEquals(2f,expression.getValue(new GenericMessageTestHelper<Float>(4f)));
3358 		assertCanCompile(expression);
3359 		assertEquals(3f,expression.getValue(new GenericMessageTestHelper<Float>(6f)));
3360 		
3361 		expression = parser.parseExpression("100f/payload");
3362 		assertEquals(25f,expression.getValue(new GenericMessageTestHelper<Float>(4f)));
3363 		assertCanCompile(expression);
3364 		assertEquals(10f,expression.getValue(new GenericMessageTestHelper<Float>(10f)));
3365 
3366 		expression = parser.parseExpression("payload/2d");
3367 		assertEquals(2d,expression.getValue(new GenericMessageTestHelper<Double>(4d)));
3368 		assertCanCompile(expression);
3369 		assertEquals(3d,expression.getValue(new GenericMessageTestHelper<Double>(6d)));
3370 		
3371 		expression = parser.parseExpression("100d/payload");
3372 		assertEquals(25d,expression.getValue(new GenericMessageTestHelper<Double>(4d)));
3373 		assertCanCompile(expression);
3374 		assertEquals(10d,expression.getValue(new GenericMessageTestHelper<Double>(10d)));
3375 	}
3376 	
3377 	// The new helper class here uses an upper bound on the generic
3378 	@Test
3379 	public void compilerWithGenerics_12040_2() {
3380 		expression = parser.parseExpression("payload/2");
3381 		assertEquals(2,expression.getValue(new GenericMessageTestHelper2<Integer>(4)));
3382 		assertCanCompile(expression);
3383 		assertEquals(3,expression.getValue(new GenericMessageTestHelper2<Integer>(6)));
3384 
3385 		expression = parser.parseExpression("9/payload");
3386 		assertEquals(1,expression.getValue(new GenericMessageTestHelper2<Integer>(9)));
3387 		assertCanCompile(expression);
3388 		assertEquals(3,expression.getValue(new GenericMessageTestHelper2<Integer>(3)));
3389 
3390 		expression = parser.parseExpression("payload+2");
3391 		assertEquals(6,expression.getValue(new GenericMessageTestHelper2<Integer>(4)));
3392 		assertCanCompile(expression);
3393 		assertEquals(8,expression.getValue(new GenericMessageTestHelper2<Integer>(6)));
3394 		
3395 		expression = parser.parseExpression("100+payload");
3396 		assertEquals(104,expression.getValue(new GenericMessageTestHelper2<Integer>(4)));
3397 		assertCanCompile(expression);
3398 		assertEquals(110,expression.getValue(new GenericMessageTestHelper2<Integer>(10)));
3399 		
3400 		expression = parser.parseExpression("payload-2");
3401 		assertEquals(2,expression.getValue(new GenericMessageTestHelper2<Integer>(4)));
3402 		assertCanCompile(expression);
3403 		assertEquals(4,expression.getValue(new GenericMessageTestHelper2<Integer>(6)));
3404 		
3405 		expression = parser.parseExpression("100-payload");
3406 		assertEquals(96,expression.getValue(new GenericMessageTestHelper2<Integer>(4)));
3407 		assertCanCompile(expression);
3408 		assertEquals(90,expression.getValue(new GenericMessageTestHelper2<Integer>(10)));
3409 
3410 		expression = parser.parseExpression("payload*2");
3411 		assertEquals(8,expression.getValue(new GenericMessageTestHelper2<Integer>(4)));
3412 		assertCanCompile(expression);
3413 		assertEquals(12,expression.getValue(new GenericMessageTestHelper2<Integer>(6)));
3414 		
3415 		expression = parser.parseExpression("100*payload");
3416 		assertEquals(400,expression.getValue(new GenericMessageTestHelper2<Integer>(4)));
3417 		assertCanCompile(expression);
3418 		assertEquals(1000,expression.getValue(new GenericMessageTestHelper2<Integer>(10)));
3419 	}
3420 	
3421 	// The other numeric operators
3422 	@Test
3423 	public void compilerWithGenerics_12040_3() {
3424 		expression = parser.parseExpression("payload >= 2");
3425 		assertTrue(expression.getValue(new GenericMessageTestHelper2<Integer>(4),Boolean.TYPE));
3426 		assertCanCompile(expression);
3427 		assertFalse(expression.getValue(new GenericMessageTestHelper2<Integer>(1),Boolean.TYPE));
3428 
3429 		expression = parser.parseExpression("2 >= payload");
3430 		assertFalse(expression.getValue(new GenericMessageTestHelper2<Integer>(5),Boolean.TYPE));
3431 		assertCanCompile(expression);
3432 		assertTrue(expression.getValue(new GenericMessageTestHelper2<Integer>(1),Boolean.TYPE));
3433 
3434 		expression = parser.parseExpression("payload > 2");
3435 		assertTrue(expression.getValue(new GenericMessageTestHelper2<Integer>(4),Boolean.TYPE));
3436 		assertCanCompile(expression);
3437 		assertFalse(expression.getValue(new GenericMessageTestHelper2<Integer>(1),Boolean.TYPE));
3438 
3439 		expression = parser.parseExpression("2 > payload");
3440 		assertFalse(expression.getValue(new GenericMessageTestHelper2<Integer>(5),Boolean.TYPE));
3441 		assertCanCompile(expression);
3442 		assertTrue(expression.getValue(new GenericMessageTestHelper2<Integer>(1),Boolean.TYPE));
3443 
3444 		expression = parser.parseExpression("payload <=2");
3445 		assertTrue(expression.getValue(new GenericMessageTestHelper2<Integer>(1),Boolean.TYPE));
3446 		assertCanCompile(expression);
3447 		assertFalse(expression.getValue(new GenericMessageTestHelper2<Integer>(6),Boolean.TYPE));
3448 
3449 		expression = parser.parseExpression("2 <= payload");
3450 		assertFalse(expression.getValue(new GenericMessageTestHelper2<Integer>(1),Boolean.TYPE));
3451 		assertCanCompile(expression);
3452 		assertTrue(expression.getValue(new GenericMessageTestHelper2<Integer>(6),Boolean.TYPE));
3453 
3454 		expression = parser.parseExpression("payload < 2");
3455 		assertTrue(expression.getValue(new GenericMessageTestHelper2<Integer>(1),Boolean.TYPE));
3456 		assertCanCompile(expression);
3457 		assertFalse(expression.getValue(new GenericMessageTestHelper2<Integer>(6),Boolean.TYPE));
3458 
3459 		expression = parser.parseExpression("2 < payload");
3460 		assertFalse(expression.getValue(new GenericMessageTestHelper2<Integer>(1),Boolean.TYPE));
3461 		assertCanCompile(expression);
3462 		assertTrue(expression.getValue(new GenericMessageTestHelper2<Integer>(6),Boolean.TYPE));
3463 	}
3464 
3465 	@Test
3466 	public void indexerMapAccessor_12045() throws Exception {
3467 		SpelParserConfiguration spc = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE,this.getClass().getClassLoader());
3468 		SpelExpressionParser sep = new SpelExpressionParser(spc);
3469 		expression=sep.parseExpression("headers[command]");
3470 		MyMessage root = new MyMessage();
3471 		assertEquals("wibble",expression.getValue(root));
3472 		// This next call was failing because the isCompilable check in Indexer did not check on the key being compilable
3473 		// (and also generateCode in the Indexer was missing the optimization that it didn't need necessarily need to call
3474 		// generateCode for that accessor)
3475 		assertEquals("wibble",expression.getValue(root));
3476 		assertCanCompile(expression);
3477 
3478 		// What about a map key that is an expression - ensure the getKey() is evaluated in the right scope
3479 		expression=sep.parseExpression("headers[getKey()]");
3480 		assertEquals("wobble",expression.getValue(root));
3481 		assertEquals("wobble",expression.getValue(root));
3482 		
3483 		expression=sep.parseExpression("list[getKey2()]");
3484 		assertEquals("wobble",expression.getValue(root));
3485 		assertEquals("wobble",expression.getValue(root));
3486 		
3487 		expression = sep.parseExpression("ia[getKey2()]");
3488 		assertEquals(3,expression.getValue(root));
3489 		assertEquals(3,expression.getValue(root));
3490 	}
3491 
3492 	// ---
3493 
3494 	public static interface Message<T> {
3495 		MessageHeaders getHeaders();
3496 		@SuppressWarnings("rawtypes")
3497 		List getList();
3498 		int[] getIa();
3499 	}
3500 	
3501 	public static class MyMessage implements Message<String> {
3502 		public MessageHeaders getHeaders() {
3503 			MessageHeaders mh = new MessageHeaders();
3504 			mh.put("command", "wibble");
3505 			mh.put("command2", "wobble");
3506 			return mh;
3507 		}
3508 		public int[] getIa() { return new int[]{5,3}; }
3509 		@SuppressWarnings({ "rawtypes", "unchecked" })
3510 		public List getList() {
3511 			List l = new ArrayList();
3512 			l.add("wibble");
3513 			l.add("wobble");
3514 			return l;
3515 		}
3516 		
3517 		public String getKey() {
3518 			return "command2";
3519 		}
3520 		
3521 		public int getKey2() {
3522 			return 1;
3523 		}
3524 	}
3525 
3526 	@SuppressWarnings("serial")
3527 	public static class MessageHeaders extends HashMap<String,Object> {	}
3528 
3529 	public static class GenericMessageTestHelper<T> {
3530 		private T payload;
3531 		
3532 		GenericMessageTestHelper(T value) {
3533 			this.payload = value;
3534 		}
3535 		
3536 		public T getPayload() {
3537 			return payload;
3538 		}
3539 	}
3540 	
3541 	// This test helper has a bound on the type variable
3542 	public static class GenericMessageTestHelper2<T extends Number> {
3543 		private T payload;
3544 		
3545 		GenericMessageTestHelper2(T value) {
3546 			this.payload = value;
3547 		}
3548 		
3549 		public T getPayload() {
3550 			return payload;
3551 		}
3552 	}
3553 	
3554 	static class MyAccessor implements CompilablePropertyAccessor {
3555 
3556 		private Method method;
3557 
3558 		public Class<?>[] getSpecificTargetClasses() {
3559 			return new Class[]{Payload2.class};
3560 		}
3561 
3562 		public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException {
3563 			// target is a Payload2 instance
3564 			return true;
3565 		}
3566 
3567 		public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
3568 			Payload2 payload2 = (Payload2)target;
3569 			return new TypedValue(payload2.getField(name));
3570 		}
3571 
3572 		public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
3573 			return false;
3574 		}
3575 
3576 		public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException {
3577 		}
3578 
3579 		@Override
3580 		public boolean isCompilable() {
3581 			return true;
3582 		}
3583 
3584 		@Override
3585 		public Class<?> getPropertyType() {
3586 			return Object.class;
3587 		}
3588 
3589 		@Override
3590 		public void generateCode(String propertyName, MethodVisitor mv,CodeFlow cf) {
3591 			if (method == null) {
3592 				try {
3593 					method = Payload2.class.getDeclaredMethod("getField", String.class);
3594 				}
3595 				catch (Exception e) {
3596 				}
3597 			}
3598 			String descriptor = cf.lastDescriptor();
3599 			String memberDeclaringClassSlashedDescriptor = method.getDeclaringClass().getName().replace('.','/');
3600 			if (descriptor == null) {
3601 				cf.loadTarget(mv);
3602 			}
3603 			if (descriptor == null || !memberDeclaringClassSlashedDescriptor.equals(descriptor.substring(1))) {
3604 				mv.visitTypeInsn(CHECKCAST, memberDeclaringClassSlashedDescriptor);
3605 			}
3606 			mv.visitLdcInsn(propertyName);
3607 			mv.visitMethodInsn(INVOKEVIRTUAL, memberDeclaringClassSlashedDescriptor, method.getName(),CodeFlow.createSignatureDescriptor(method),false);
3608 		}
3609 	}
3610 
3611 
3612 	static class CompilableMapAccessor implements CompilablePropertyAccessor {
3613 
3614 		@Override
3615 		public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException {
3616 			Map<?,?> map = (Map<?,?>) target;
3617 			return map.containsKey(name);
3618 		}
3619 
3620 		@Override
3621 		public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
3622 			Map<?,?> map = (Map<?,?>) target;
3623 			Object value = map.get(name);
3624 			if (value == null && !map.containsKey(name)) {
3625 				throw new MapAccessException(name);
3626 			}
3627 			return new TypedValue(value);
3628 		}
3629 
3630 		@Override
3631 		public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
3632 			return true;
3633 		}
3634 
3635 		@Override
3636 		@SuppressWarnings("unchecked")
3637 		public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException {
3638 			Map<String,Object> map = (Map<String,Object>) target;
3639 			map.put(name, newValue);
3640 		}
3641 
3642 		@Override
3643 		public Class<?>[] getSpecificTargetClasses() {
3644 			return new Class[] {Map.class};
3645 		}
3646 
3647 		@Override
3648 		public boolean isCompilable() {
3649 			return true;
3650 		}
3651 
3652 		@Override
3653 		public Class<?> getPropertyType() {
3654 			return Object.class;
3655 		}
3656 
3657 		@Override
3658 		public void generateCode(String propertyName, MethodVisitor mv, CodeFlow cf) {
3659 			String descriptor = cf.lastDescriptor();
3660 			if (descriptor == null) {
3661 				cf.loadTarget(mv);
3662 			}
3663 			mv.visitLdcInsn(propertyName);
3664 			mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "get","(Ljava/lang/Object;)Ljava/lang/Object;",true);
3665 
3666 //			if (method == null) {
3667 //				try {
3668 //					method = Payload2.class.getDeclaredMethod("getField", String.class);
3669 //				} catch (Exception e) {}
3670 //			}
3671 //			String descriptor = codeflow.lastDescriptor();
3672 //			String memberDeclaringClassSlashedDescriptor = method.getDeclaringClass().getName().replace('.','/');
3673 //			if (descriptor == null) {
3674 //				codeflow.loadTarget(mv);
3675 //			}
3676 //			if (descriptor == null || !memberDeclaringClassSlashedDescriptor.equals(descriptor.substring(1))) {
3677 //				mv.visitTypeInsn(CHECKCAST, memberDeclaringClassSlashedDescriptor);
3678 //			}
3679 //			mv.visitLdcInsn(propertyReference.getName());
3680 //			mv.visitMethodInsn(INVOKEVIRTUAL, memberDeclaringClassSlashedDescriptor, method.getName(),CodeFlow.createDescriptor(method));
3681 //			   6:	invokeinterface	#6,  2; //InterfaceMethod java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object;
3682 		}
3683 	}
3684 
3685 
3686 	/**
3687 	 * Exception thrown from {@code read} in order to reset a cached
3688 	 * PropertyAccessor, allowing other accessors to have a try.
3689 	 */
3690 	@SuppressWarnings("serial")
3691 	private static class MapAccessException extends AccessException {
3692 
3693 		private final String key;
3694 
3695 		public MapAccessException(String key) {
3696 			super(null);
3697 			this.key = key;
3698 		}
3699 
3700 		@Override
3701 		public String getMessage() {
3702 			return "Map does not contain a value for key '" + this.key + "'";
3703 		}
3704 	}
3705 
3706 	
3707 	// helpers
3708 
3709 	private SpelNodeImpl getAst() {
3710 		SpelExpression spelExpression = (SpelExpression)expression;
3711 		SpelNode ast = spelExpression.getAST();
3712 		return (SpelNodeImpl)ast;
3713 	}
3714 
3715 	private String stringify(Object object) {
3716 		StringBuilder s = new StringBuilder();
3717 		if (object instanceof List) {
3718 			List<?> ls = (List<?>)object;
3719 			for (Object l: ls) {
3720 				s.append(l);
3721 				s.append(" ");
3722 			}
3723 		}
3724 		else if (object instanceof Object[]) {
3725 			Object[] os = (Object[])object;
3726 			for (Object o: os) {
3727 				s.append(o);
3728 				s.append(" ");
3729 			}
3730 		}
3731 		else if (object instanceof int[]) {
3732 			int[] is = (int[])object;
3733 			for (int i: is) {
3734 				s.append(i);
3735 				s.append(" ");
3736 			}
3737 		}
3738 		else {
3739 			s.append(object.toString());
3740 		}
3741 		return s.toString().trim();
3742 	}
3743 	
3744 	private void assertCanCompile(Expression expression) {
3745 		assertTrue(SpelCompiler.compile(expression));
3746 	}
3747 	
3748 	private void assertCantCompile(Expression expression) {
3749 		assertFalse(SpelCompiler.compile(expression));
3750 	}
3751 	
3752 	private Expression parse(String expression) {
3753 		return parser.parseExpression(expression);
3754 	}
3755 	
3756 	private void assertGetValueFail(Expression expression) {
3757 		try {
3758 			Object o = expression.getValue();
3759 			fail("Calling getValue on the expression should have failed but returned "+o);
3760 		} catch (Exception ex) {
3761 			// success!
3762 		}
3763 	}
3764 	
3765 	// test classes
3766 		
3767 	public static class Payload {
3768 		Two[] DR = new Two[]{new Two()};
3769 		public Two holder = new Two();
3770 		
3771 		public Two[] getDR() {
3772 			return DR;
3773 		}
3774 	}
3775 	
3776 	public static class Payload2 {
3777 		String var1 = "abc";
3778 		String var2 = "def";
3779 		public Object getField(String name) {
3780 			if (name.equals("var1")) {
3781 				return var1;
3782 			} else if (name.equals("var2")) {
3783 				return var2;
3784 			}
3785 			return null;
3786 		}
3787 	}
3788 
3789 	public static class Payload2Holder {
3790 		public Payload2 payload2 = new Payload2();
3791 	}
3792 	
3793 	public static class Two {
3794 		Three three = new Three();
3795 		public Three getThree() {
3796 			return three;
3797 		}
3798 		public String toString() {
3799 			return "instanceof Two";
3800 		}
3801 	}
3802 	
3803 	public static class Three {
3804 		double four = 0.04d;
3805 		public double getFour() {
3806 			return four;
3807 		}
3808 	}
3809 
3810 	public static class TestClass1 {
3811 		public int index1 = 1;
3812 		public int index2 = 3;
3813 		public String word = "abcd";		
3814 	}
3815 	
3816 	public static class TestClass4 {
3817 		public boolean a,b;
3818 		public boolean gettrue() { return true; }
3819 		public boolean getfalse() { return false; }
3820 		public boolean getA() { return a; }
3821 		public boolean getB() { return b; }
3822 	}
3823 	
3824 	public static class TestClass10 {
3825 		public String s = null;
3826 		
3827 		public void reset() {
3828 			s = null;
3829 		}
3830 		
3831 		public void concat(String arg) {
3832 			s = "::"+arg;
3833 		}
3834 
3835 		public void concat(String... vargs) { 
3836 			if (vargs==null) {
3837 				s = "";
3838 			}
3839 			else {
3840 				s = "";
3841 				for (String varg: vargs) {
3842 					s+=varg;
3843 				}
3844 			}
3845 		}
3846 		
3847 		public void concat2(Object arg) {
3848 			s = "::"+arg;
3849 		}
3850 
3851 		public void concat2(Object... vargs) { 
3852 			if (vargs==null) {
3853 				s = "";
3854 			}
3855 			else {
3856 				s = "";
3857 				for (Object varg: vargs) {
3858 					s+=varg;
3859 				}
3860 			}
3861 		}
3862 	}
3863 	
3864 	public static class TestClass5 {
3865 		public int i = 0;
3866 		public String s = null;
3867 		public static int _i = 0;
3868 		public static String _s = null;
3869 		
3870 		public static short s1 = (short)1;
3871 		public static short s2 = (short)2;
3872 		public static short s3 = (short)3;
3873 
3874 		public static long l1 = 1L;
3875 		public static long l2 = 2L;
3876 		public static long l3 = 3L;
3877 
3878 		public static float f1 = 1f;
3879 		public static float f2 = 2f;
3880 		public static float f3 = 3f;
3881 
3882 		public static char c1 = 'a';
3883 		public static char c2 = 'b';
3884 		public static char c3 = 'c';
3885 		
3886 		public static byte b1 = (byte)65;
3887 		public static byte b2 = (byte)66;
3888 		public static byte b3 = (byte)67;
3889 
3890 		public static String[] stringArray = new String[]{"aaa","bbb","ccc"};
3891 		public static int[] intArray = new int[]{11,22,33};
3892 		
3893 		public Object obj = null;
3894 		
3895 		public String field = null;
3896 		
3897 		public void reset() {
3898 			i = 0;
3899 			_i=0;
3900 			s = null;
3901 			_s = null;
3902 			field = null;
3903 		}
3904 		
3905 		public void one() { i = 1; }
3906 		
3907 		public static void two() { _i = 1; }
3908 		
3909 		public String three() { return "hello"; }
3910 		public long four() { return 3277700L; }
3911 
3912 		public static String five() { return "hello"; }
3913 		public static long six() { return 3277700L; }
3914 		
3915 		public void seven(String toset) { s = toset; }
3916 //		public void seven(Number n) { s = n.toString(); }
3917 		
3918 		public void takeNumber(Number n) { s = n.toString(); }
3919 		public void takeString(String s) { this.s = s; }
3920 		public static void eight(String toset) { _s = toset; }
3921 		
3922 		public void nine(int toset) { i = toset; }
3923 		public static void ten(int toset) { _i = toset; }
3924 		
3925 		public void eleven(String... vargs) { 
3926 			if (vargs==null) {
3927 				s = "";
3928 			}
3929 			else {
3930 				s = "";
3931 				for (String varg: vargs) {
3932 					s+=varg;
3933 				}
3934 			}
3935 		}
3936 		
3937 		public void twelve(int... vargs) { 
3938 			if (vargs==null) {
3939 				i = 0;
3940 			}
3941 			else {
3942 				i = 0;
3943 				for (int varg: vargs) {
3944 					i+=varg;
3945 				}
3946 			}
3947 		}
3948 		
3949 		public void thirteen(String a, String... vargs) { 
3950 			if (vargs==null) {
3951 				s = a+"::";
3952 			}
3953 			else {
3954 				s = a+"::";
3955 				for (String varg: vargs) {
3956 					s+=varg;
3957 				}
3958 			}
3959 		}
3960 		
3961 		public void arrayz(boolean... bs) {
3962 			s = "";
3963 			if (bs != null) {
3964 				s = "";
3965 				for (boolean b: bs) {
3966 					s+=Boolean.toString(b);
3967 				}
3968 			}
3969 		}
3970 		
3971 		public void arrays(short... ss) {
3972 			s = "";
3973 			if (ss != null) {
3974 				s = "";
3975 				for (short s: ss) {
3976 					this.s+=Short.toString(s);
3977 				}
3978 			}
3979 		}
3980 		
3981 		public void arrayd(double... vargs) {
3982 			s = "";
3983 			if (vargs != null) {
3984 				s = "";
3985 				for (double v: vargs) {
3986 					this.s+=Double.toString(v);
3987 				}
3988 			}
3989 		}
3990 
3991 		public void arrayf(float... vargs) {
3992 			s = "";
3993 			if (vargs != null) {
3994 				s = "";
3995 				for (float v: vargs) {
3996 					this.s+=Float.toString(v);
3997 				}
3998 			}
3999 		}
4000 
4001 		public void arrayj(long... vargs) {
4002 			s = "";
4003 			if (vargs != null) {
4004 				s = "";
4005 				for (long v: vargs) {
4006 					this.s+=Long.toString(v);
4007 				}
4008 			}
4009 		}
4010 
4011 		public void arrayb(byte... vargs) {
4012 			s = "";
4013 			if (vargs != null) {
4014 				s = "";
4015 				for (Byte v: vargs) {
4016 					this.s+=Byte.toString(v);
4017 				}
4018 			}
4019 		}
4020 		
4021 		public void arrayc(char... vargs) {
4022 			s = "";
4023 			if (vargs != null) {
4024 				s = "";
4025 				for (char v: vargs) {
4026 					this.s+=Character.toString(v);
4027 				}
4028 			}
4029 		}
4030 
4031 		public void fourteen(String a, String[]... vargs) { 
4032 			if (vargs==null) {
4033 				s = a+"::";
4034 			}
4035 			else {
4036 				s = a+"::";
4037 				for (String[] varg: vargs) {
4038 					s+="{";
4039 					for (String v: varg) {
4040 						s+=v;						
4041 					}
4042 					s+="}";
4043 				}
4044 			}
4045 		}
4046 		
4047 		public void fifteen(String a, int[]... vargs) { 
4048 			if (vargs==null) {
4049 				s = a+"::";
4050 			}
4051 			else {
4052 				s = a+"::";
4053 				for (int[] varg: vargs) {
4054 					s+="{";
4055 					for (int v: varg) {
4056 						s+=Integer.toString(v);						
4057 					}
4058 					s+="}";
4059 				}
4060 			}
4061 		}
4062 		
4063 		public void sixteen(Object... vargs) { 
4064 			if (vargs==null) {
4065 				s = "";
4066 			}
4067 			else {
4068 				s = "";
4069 				for (Object varg: vargs) {
4070 					s+=varg;
4071 				}
4072 			}
4073 		}
4074 		
4075 	}
4076 	
4077 	public static class TestClass6 {
4078 		public String orange = "value1";
4079 		public static String apple = "value2";
4080 		
4081 		public long peach = 34L;
4082 		
4083 		public String getBanana() {
4084 			return "value3";
4085 		}
4086 
4087 		public static String getPlum() {
4088 			return "value4";
4089 		}
4090 	}
4091 	
4092 	public static class TestClass7 {
4093 		public static String property;
4094 		static {
4095 			String s = "UK 123";
4096 			StringTokenizer st = new StringTokenizer(s);
4097 			property = st.nextToken();
4098 		}
4099 		
4100 		public static void reset() {
4101 			String s = "UK 123";
4102 			StringTokenizer st = new StringTokenizer(s);
4103 			property = st.nextToken();
4104 		}
4105 		
4106 	}
4107 
4108 	public static class TestClass8 {
4109 		public int i;
4110 		public String s;
4111 		public double d;
4112 		public boolean z;
4113 		
4114 		public TestClass8(int i, String s, double d, boolean z) {
4115 			this.i = i;
4116 			this.s = s;
4117 			this.d = d;
4118 			this.z = z;
4119 		}
4120 		
4121 		public TestClass8() {
4122 			
4123 		}
4124 		
4125 		public TestClass8(Integer i) {
4126 			this.i = i;
4127 		}
4128 		
4129 		@SuppressWarnings("unused")
4130 		private TestClass8(String a, String b) {
4131 			this.s = a+b;
4132 		}
4133 	}
4134 
4135     public static class Obj {
4136  
4137         private final String param1;
4138  
4139         public Obj(String param1){
4140             this.param1 = param1;
4141         }
4142     }
4143 
4144     public static class Obj2 {
4145  
4146         public final String output;
4147  
4148         public Obj2(String... params){
4149         	StringBuilder b = new StringBuilder();
4150         	for (String param: params) {
4151         		b.append(param);
4152         	}
4153         	output = b.toString();
4154         }
4155     }
4156 
4157     public static class Obj3 {
4158  
4159         public final String output;
4160  
4161         public Obj3(int... params) {
4162         	StringBuilder b = new StringBuilder();
4163         	for (int param: params) {
4164         		b.append(Integer.toString(param));
4165         	}
4166         	output = b.toString();
4167         }
4168         
4169         public Obj3(String s, Float f, int... ints) {
4170         	StringBuilder b = new StringBuilder();
4171         	b.append(s);
4172         	b.append(":");
4173         	b.append(Float.toString(f));
4174         	b.append(":");
4175         	for (int param: ints) {
4176         		b.append(Integer.toString(param));
4177         	}
4178         	output = b.toString();
4179         }
4180     }
4181     
4182     public static class Obj4 {
4183     	 
4184         public final String output;
4185  
4186         public Obj4(int[] params) {
4187         	StringBuilder b = new StringBuilder();
4188         	for (int param: params) {
4189         		b.append(Integer.toString(param));
4190         	}
4191         	output = b.toString();
4192         }
4193     }
4194 	
4195 	@SuppressWarnings("unused")
4196 	private static class TestClass9 {
4197 		public TestClass9(int i) {}
4198 	}
4199 	
4200 	// These test classes simulate a pattern of public/private classes seen in Spring Security
4201 	
4202 	// final class HttpServlet3RequestFactory implements HttpServletRequestFactory 
4203 	static class HttpServlet3RequestFactory {
4204 	
4205 	  static Servlet3SecurityContextHolderAwareRequestWrapper getOne() {
4206 		  HttpServlet3RequestFactory outer = new HttpServlet3RequestFactory();
4207 		  return outer.new Servlet3SecurityContextHolderAwareRequestWrapper();
4208 	  }
4209 	  // private class Servlet3SecurityContextHolderAwareRequestWrapper extends SecurityContextHolderAwareRequestWrapper
4210 	  private class Servlet3SecurityContextHolderAwareRequestWrapper extends SecurityContextHolderAwareRequestWrapper {
4211 	  }
4212 	}
4213 	
4214 	// public class SecurityContextHolderAwareRequestWrapper extends HttpServletRequestWrapper 
4215 	static class SecurityContextHolderAwareRequestWrapper extends HttpServletRequestWrapper {
4216 	}
4217 	
4218 	public static class HttpServletRequestWrapper {
4219 		public String getServletPath() {
4220 			return "wibble";
4221 		}
4222 	}
4223 	
4224 	// Here the declaring class is not public
4225 	static class SomeCompareMethod {
4226 
4227 		// method not public
4228 		static int compare(Object o1, Object o2) {
4229 			return -1;
4230 		}
4231 
4232 		// public
4233 		public static int compare2(Object o1, Object o2) {
4234 			return -1;
4235 		}
4236 	}
4237 	
4238 	public static class SomeCompareMethod2 {
4239 		public static int negate(int i1) {
4240 			return -i1;
4241 		}
4242 
4243 		public static String append(String... strings) {
4244 			StringBuilder b = new StringBuilder();
4245 			for (String string: strings) {
4246 				b.append(string);
4247 			}
4248 			return b.toString();
4249 		}
4250 		
4251 		public static String append2(Object... objects) {
4252 			StringBuilder b = new StringBuilder();
4253 			for (Object object: objects) {
4254 				b.append(object.toString());
4255 			}
4256 			return b.toString();
4257 		}
4258 		
4259 		public static String append3(String[] strings) {
4260 			StringBuilder b = new StringBuilder();
4261 			for (String string: strings) {
4262 				b.append(string);
4263 			}
4264 			return b.toString();
4265 		}
4266 		
4267 		public static String append4(String s, String... strings) {
4268 			StringBuilder b = new StringBuilder();
4269 			b.append(s).append("::");
4270 			for (String string: strings) {
4271 				b.append(string);
4272 			}
4273 			return b.toString();
4274 		}
4275 
4276 		public static String appendChar(char... values) {
4277 			StringBuilder b = new StringBuilder();
4278 			for (char ch: values) {
4279 				b.append(ch);
4280 			}
4281 			return b.toString();
4282 		}
4283 		
4284 		public static int sum(int... ints) {
4285 			int total = 0;
4286 			for (int i: ints) {
4287 				total+=i;
4288 			}
4289 			return total;
4290 		}
4291 
4292 		public static int sumDouble(double... values) {
4293 			int total = 0;
4294 			for (double i: values) {
4295 				total+=i;
4296 			}
4297 			return total;
4298 		}
4299 
4300 		public static int sumFloat(float... values) {
4301 			int total = 0;
4302 			for (float i: values) {
4303 				total+=i;
4304 			}
4305 			return total;
4306 		}
4307 
4308 	}
4309 	
4310 	public static class DelegatingStringFormat {
4311 		public static String format(String s, Object... args) {
4312 			return String.format(s, args);
4313 		}
4314 	}
4315 		
4316 }