View Javadoc
1   /*
2    * Copyright 2002-2015 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.lang.reflect.Array;
20  import java.lang.reflect.Field;
21  import java.lang.reflect.Method;
22  import java.util.ArrayList;
23  import java.util.Arrays;
24  import java.util.Collection;
25  import java.util.Collections;
26  import java.util.HashMap;
27  import java.util.Iterator;
28  import java.util.LinkedHashMap;
29  import java.util.LinkedHashSet;
30  import java.util.List;
31  import java.util.ListIterator;
32  import java.util.Map;
33  import java.util.Properties;
34  import java.util.concurrent.atomic.AtomicInteger;
35  
36  import org.junit.Rule;
37  import org.junit.Test;
38  import org.junit.rules.ExpectedException;
39  
40  import org.springframework.core.MethodParameter;
41  import org.springframework.core.convert.TypeDescriptor;
42  import org.springframework.expression.AccessException;
43  import org.springframework.expression.BeanResolver;
44  import org.springframework.expression.EvaluationContext;
45  import org.springframework.expression.EvaluationException;
46  import org.springframework.expression.Expression;
47  import org.springframework.expression.ExpressionException;
48  import org.springframework.expression.ExpressionParser;
49  import org.springframework.expression.MethodExecutor;
50  import org.springframework.expression.MethodResolver;
51  import org.springframework.expression.ParserContext;
52  import org.springframework.expression.PropertyAccessor;
53  import org.springframework.expression.TypedValue;
54  import org.springframework.expression.spel.standard.SpelExpression;
55  import org.springframework.expression.spel.standard.SpelExpressionParser;
56  import org.springframework.expression.spel.support.ReflectiveMethodResolver;
57  import org.springframework.expression.spel.support.ReflectivePropertyAccessor;
58  import org.springframework.expression.spel.support.StandardEvaluationContext;
59  import org.springframework.expression.spel.support.StandardTypeLocator;
60  import org.springframework.expression.spel.testresources.le.div.mod.reserved.Reserver;
61  
62  import static org.hamcrest.Matchers.*;
63  import static org.junit.Assert.*;
64  
65  /**
66   * Reproduction tests cornering various SpEL JIRA issues.
67   *
68   * @author Andy Clement
69   * @author Juergen Hoeller
70   * @author Clark Duplichien
71   * @author Phillip Webb
72   * @author Sam Brannen
73   */
74  public class SpelReproTests extends AbstractExpressionTests {
75  
76  	@Rule
77  	public ExpectedException thrown = ExpectedException.none();
78  
79  
80  	@Test
81  	public void NPE_SPR5661() {
82  		evaluate("joinThreeStrings('a',null,'c')", "anullc", String.class);
83  	}
84  
85  	@Test
86  	public void SWF1086() {
87  		evaluate("printDouble(T(java.math.BigDecimal).valueOf(14.35))", "14.35", String.class);
88  	}
89  
90  	@Test
91  	public void doubleCoercion() {
92  		evaluate("printDouble(14.35)", "14.35", String.class);
93  	}
94  
95  	@Test
96  	public void doubleArrayCoercion() {
97  		evaluate("printDoubles(getDoublesAsStringList())", "{14.35, 15.45}", String.class);
98  	}
99  
100 	@Test
101 	public void SPR5899() throws Exception {
102 		StandardEvaluationContext eContext = new StandardEvaluationContext(new Spr5899Class());
103 		Expression expr = new SpelExpressionParser().parseRaw("tryToInvokeWithNull(12)");
104 		assertEquals(12, expr.getValue(eContext));
105 		expr = new SpelExpressionParser().parseRaw("tryToInvokeWithNull(null)");
106 		assertEquals(null, expr.getValue(eContext));
107 		try {
108 			expr = new SpelExpressionParser().parseRaw("tryToInvokeWithNull2(null)");
109 			expr.getValue();
110 			fail("Should have failed to find a method to which it could pass null");
111 		}
112 		catch (EvaluationException see) {
113 			// success
114 		}
115 		eContext.setTypeLocator(new MyTypeLocator());
116 
117 		// varargs
118 		expr = new SpelExpressionParser().parseRaw("tryToInvokeWithNull3(null,'a','b')");
119 		assertEquals("ab", expr.getValue(eContext));
120 
121 		// varargs 2 - null is packed into the varargs
122 		expr = new SpelExpressionParser().parseRaw("tryToInvokeWithNull3(12,'a',null,'c')");
123 		assertEquals("anullc", expr.getValue(eContext));
124 
125 		// check we can find the ctor ok
126 		expr = new SpelExpressionParser().parseRaw("new Spr5899Class().toString()");
127 		assertEquals("instance", expr.getValue(eContext));
128 
129 		expr = new SpelExpressionParser().parseRaw("new Spr5899Class(null).toString()");
130 		assertEquals("instance", expr.getValue(eContext));
131 
132 		// ctor varargs
133 		expr = new SpelExpressionParser().parseRaw("new Spr5899Class(null,'a','b').toString()");
134 		assertEquals("instance", expr.getValue(eContext));
135 
136 		// ctor varargs 2
137 		expr = new SpelExpressionParser().parseRaw("new Spr5899Class(null,'a', null, 'b').toString()");
138 		assertEquals("instance", expr.getValue(eContext));
139 	}
140 
141 
142 	static class MyTypeLocator extends StandardTypeLocator {
143 
144 		@Override
145 		public Class<?> findType(String typeName) throws EvaluationException {
146 			if (typeName.equals("Spr5899Class")) {
147 				return Spr5899Class.class;
148 			}
149 			if (typeName.equals("Outer")) {
150 				return Outer.class;
151 			}
152 			return super.findType(typeName);
153 		}
154 	}
155 
156 
157 	static class Spr5899Class {
158 
159 		public Spr5899Class() {
160 		}
161 
162 		public Spr5899Class(Integer i) {
163 		}
164 
165 		public Spr5899Class(Integer i, String... s) {
166 		}
167 
168 		public Integer tryToInvokeWithNull(Integer value) {
169 			return value;
170 		}
171 
172 		public Integer tryToInvokeWithNull2(int i) {
173 			return new Integer(i);
174 		}
175 
176 		public String tryToInvokeWithNull3(Integer value, String... strings) {
177 			StringBuilder sb = new StringBuilder();
178 			for (String string : strings) {
179 				if (string == null) {
180 					sb.append("null");
181 				}
182 				else {
183 					sb.append(string);
184 				}
185 			}
186 			return sb.toString();
187 		}
188 
189 		@Override
190 		public String toString() {
191 			return "instance";
192 		}
193 	}
194 
195 
196 	@Test
197 	public void SPR5905_InnerTypeReferences() throws Exception {
198 		StandardEvaluationContext eContext = new StandardEvaluationContext(new Spr5899Class());
199 		Expression expr = new SpelExpressionParser().parseRaw("T(java.util.Map$Entry)");
200 		assertEquals(Map.Entry.class, expr.getValue(eContext));
201 
202 		expr = new SpelExpressionParser().parseRaw("T(org.springframework.expression.spel.SpelReproTests$Outer$Inner).run()");
203 		assertEquals(12, expr.getValue(eContext));
204 
205 		expr = new SpelExpressionParser().parseRaw("new org.springframework.expression.spel.SpelReproTests$Outer$Inner().run2()");
206 		assertEquals(13, expr.getValue(eContext));
207 	}
208 
209 
210 	static class Outer {
211 
212 		static class Inner {
213 
214 			public Inner() {
215 			}
216 
217 			public static int run() {
218 				return 12;
219 			}
220 
221 			public int run2() {
222 				return 13;
223 			}
224 		}
225 	}
226 
227 
228 	@Test
229 	public void SPR5804() throws Exception {
230 		Map<String, String> m = new HashMap<String, String>();
231 		m.put("foo", "bar");
232 		StandardEvaluationContext eContext = new StandardEvaluationContext(m); // root is a map instance
233 		eContext.addPropertyAccessor(new MapAccessor());
234 		Expression expr = new SpelExpressionParser().parseRaw("['foo']");
235 		assertEquals("bar", expr.getValue(eContext));
236 	}
237 
238 	@Test
239 	public void SPR5847() throws Exception {
240 		StandardEvaluationContext eContext = new StandardEvaluationContext(new TestProperties());
241 		String name = null;
242 		Expression expr = null;
243 
244 		expr = new SpelExpressionParser().parseRaw("jdbcProperties['username']");
245 		name = expr.getValue(eContext, String.class);
246 		assertEquals("Dave", name);
247 
248 		expr = new SpelExpressionParser().parseRaw("jdbcProperties[username]");
249 		name = expr.getValue(eContext, String.class);
250 		assertEquals("Dave", name);
251 
252 		// MapAccessor required for this to work
253 		expr = new SpelExpressionParser().parseRaw("jdbcProperties.username");
254 		eContext.addPropertyAccessor(new MapAccessor());
255 		name = expr.getValue(eContext, String.class);
256 		assertEquals("Dave", name);
257 
258 		// --- dotted property names
259 
260 		// lookup foo on the root, then bar on that, then use that as the key into
261 		// jdbcProperties
262 		expr = new SpelExpressionParser().parseRaw("jdbcProperties[foo.bar]");
263 		eContext.addPropertyAccessor(new MapAccessor());
264 		name = expr.getValue(eContext, String.class);
265 		assertEquals("Dave2", name);
266 
267 		// key is foo.bar
268 		expr = new SpelExpressionParser().parseRaw("jdbcProperties['foo.bar']");
269 		eContext.addPropertyAccessor(new MapAccessor());
270 		name = expr.getValue(eContext, String.class);
271 		assertEquals("Elephant", name);
272 	}
273 
274 
275 	static class TestProperties {
276 
277 		public Properties jdbcProperties = new Properties();
278 		public Properties foo = new Properties();
279 
280 		TestProperties() {
281 			jdbcProperties.put("username", "Dave");
282 			jdbcProperties.put("alias", "Dave2");
283 			jdbcProperties.put("foo.bar", "Elephant");
284 			foo.put("bar", "alias");
285 		}
286 	}
287 
288 
289 	static class MapAccessor implements PropertyAccessor {
290 
291 		@Override
292 		public Class<?>[] getSpecificTargetClasses() {
293 			return new Class<?>[] {Map.class};
294 		}
295 
296 		@Override
297 		public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException {
298 			return (((Map<?, ?>) target).containsKey(name));
299 		}
300 
301 		@Override
302 		public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
303 			return new TypedValue(((Map<?, ?>) target).get(name));
304 		}
305 
306 		@Override
307 		public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
308 			return true;
309 		}
310 
311 		@Override
312 		@SuppressWarnings("unchecked")
313 		public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException {
314 			((Map<String, Object>) target).put(name, newValue);
315 		}
316 	}
317 
318 
319 	@Test
320 	public void NPE_SPR5673() throws Exception {
321 		ParserContext hashes = TemplateExpressionParsingTests.HASH_DELIMITED_PARSER_CONTEXT;
322 		ParserContext dollars = TemplateExpressionParsingTests.DEFAULT_TEMPLATE_PARSER_CONTEXT;
323 
324 		checkTemplateParsing("abc${'def'} ghi", "abcdef ghi");
325 
326 		checkTemplateParsingError("abc${ {}( 'abc'", "Missing closing ')' for '(' at position 8");
327 		checkTemplateParsingError("abc${ {}[ 'abc'", "Missing closing ']' for '[' at position 8");
328 		checkTemplateParsingError("abc${ {}{ 'abc'", "Missing closing '}' for '{' at position 8");
329 		checkTemplateParsingError("abc${ ( 'abc' }", "Found closing '}' at position 14 but most recent opening is '(' at position 6");
330 		checkTemplateParsingError("abc${ '... }", "Found non terminating string literal starting at position 6");
331 		checkTemplateParsingError("abc${ \"... }", "Found non terminating string literal starting at position 6");
332 		checkTemplateParsingError("abc${ ) }", "Found closing ')' at position 6 without an opening '('");
333 		checkTemplateParsingError("abc${ ] }", "Found closing ']' at position 6 without an opening '['");
334 		checkTemplateParsingError("abc${ } }", "No expression defined within delimiter '${}' at character 3");
335 		checkTemplateParsingError("abc$[ } ]", DOLLARSQUARE_TEMPLATE_PARSER_CONTEXT, "Found closing '}' at position 6 without an opening '{'");
336 
337 		checkTemplateParsing("abc ${\"def''g}hi\"} jkl", "abc def'g}hi jkl");
338 		checkTemplateParsing("abc ${'def''g}hi'} jkl", "abc def'g}hi jkl");
339 		checkTemplateParsing("}", "}");
340 		checkTemplateParsing("${'hello'} world", "hello world");
341 		checkTemplateParsing("Hello ${'}'}]", "Hello }]");
342 		checkTemplateParsing("Hello ${'}'}", "Hello }");
343 		checkTemplateParsingError("Hello ${ ( ", "No ending suffix '}' for expression starting at character 6: ${ ( ");
344 		checkTemplateParsingError("Hello ${ ( }", "Found closing '}' at position 11 but most recent opening is '(' at position 9");
345 		checkTemplateParsing("#{'Unable to render embedded object: File ({#this == 2}'}", hashes, "Unable to render embedded object: File ({#this == 2}");
346 		checkTemplateParsing("This is the last odd number in the list: ${listOfNumbersUpToTen.$[#this%2==1]}", dollars, "This is the last odd number in the list: 9");
347 		checkTemplateParsing("Hello ${'here is a curly bracket }'}", dollars, "Hello here is a curly bracket }");
348 		checkTemplateParsing("He${'${'}llo ${'here is a curly bracket }'}}", dollars, "He${llo here is a curly bracket }}");
349 		checkTemplateParsing("Hello ${'()()()}{}{}{][]{}{][}[][][}{()()'} World", dollars, "Hello ()()()}{}{}{][]{}{][}[][][}{()() World");
350 		checkTemplateParsing("Hello ${'inner literal that''s got {[(])]}an escaped quote in it'} World", "Hello inner literal that's got {[(])]}an escaped quote in it World");
351 		checkTemplateParsingError("Hello ${", "No ending suffix '}' for expression starting at character 6: ${");
352 	}
353 
354 	@Test
355 	public void accessingNullPropertyViaReflection_SPR5663() throws AccessException {
356 		PropertyAccessor propertyAccessor = new ReflectivePropertyAccessor();
357 		EvaluationContext context = TestScenarioCreator.getTestEvaluationContext();
358 		assertFalse(propertyAccessor.canRead(context, null, "abc"));
359 		assertFalse(propertyAccessor.canWrite(context, null, "abc"));
360 		try {
361 			propertyAccessor.read(context, null, "abc");
362 			fail("Should have failed with an AccessException");
363 		}
364 		catch (AccessException ae) {
365 			// success
366 		}
367 		try {
368 			propertyAccessor.write(context, null, "abc", "foo");
369 			fail("Should have failed with an AccessException");
370 		}
371 		catch (AccessException ae) {
372 			// success
373 		}
374 	}
375 
376 	@Test
377 	public void nestedProperties_SPR6923() {
378 		StandardEvaluationContext eContext = new StandardEvaluationContext(new Foo());
379 		Expression expr = new SpelExpressionParser().parseRaw("resource.resource.server");
380 		String name = expr.getValue(eContext, String.class);
381 		assertEquals("abc", name);
382 	}
383 
384 
385 	static class Foo {
386 
387 		public ResourceSummary resource = new ResourceSummary();
388 	}
389 
390 
391 	static class ResourceSummary {
392 
393 		private final Resource resource;
394 
395 		ResourceSummary() {
396 			this.resource = new Resource();
397 		}
398 
399 		public Resource getResource() {
400 			return resource;
401 		}
402 	}
403 
404 
405 	static class Resource {
406 
407 		public String getServer() {
408 			return "abc";
409 		}
410 	}
411 
412 
413 	/** Should be accessing Goo.getKey because 'bar' field evaluates to "key" */
414 	@Test
415 	public void indexingAsAPropertyAccess_SPR6968_1() {
416 		StandardEvaluationContext eContext = new StandardEvaluationContext(new Goo());
417 		String name = null;
418 		Expression expr = null;
419 		expr = new SpelExpressionParser().parseRaw("instance[bar]");
420 		name = expr.getValue(eContext, String.class);
421 		assertEquals("hello", name);
422 		name = expr.getValue(eContext, String.class); // will be using the cached accessor this time
423 		assertEquals("hello", name);
424 	}
425 
426 	/** Should be accessing Goo.getKey because 'bar' variable evaluates to "key" */
427 	@Test
428 	public void indexingAsAPropertyAccess_SPR6968_2() {
429 		StandardEvaluationContext eContext = new StandardEvaluationContext(new Goo());
430 		eContext.setVariable("bar", "key");
431 		String name = null;
432 		Expression expr = null;
433 		expr = new SpelExpressionParser().parseRaw("instance[#bar]");
434 		name = expr.getValue(eContext, String.class);
435 		assertEquals("hello", name);
436 		name = expr.getValue(eContext, String.class); // will be using the cached accessor this time
437 		assertEquals("hello", name);
438 	}
439 
440 	/** $ related identifiers */
441 	@Test
442 	public void dollarPrefixedIdentifier_SPR7100() {
443 		Holder h = new Holder();
444 		StandardEvaluationContext eContext = new StandardEvaluationContext(h);
445 		eContext.addPropertyAccessor(new MapAccessor());
446 		h.map.put("$foo", "wibble");
447 		h.map.put("foo$bar", "wobble");
448 		h.map.put("foobar$$", "wabble");
449 		h.map.put("$", "wubble");
450 		h.map.put("$$", "webble");
451 		h.map.put("$_$", "tribble");
452 		String name = null;
453 		Expression expr = null;
454 
455 		expr = new SpelExpressionParser().parseRaw("map.$foo");
456 		name = expr.getValue(eContext, String.class);
457 		assertEquals("wibble", name);
458 
459 		expr = new SpelExpressionParser().parseRaw("map.foo$bar");
460 		name = expr.getValue(eContext, String.class);
461 		assertEquals("wobble", name);
462 
463 		expr = new SpelExpressionParser().parseRaw("map.foobar$$");
464 		name = expr.getValue(eContext, String.class);
465 		assertEquals("wabble", name);
466 
467 		expr = new SpelExpressionParser().parseRaw("map.$");
468 		name = expr.getValue(eContext, String.class);
469 		assertEquals("wubble", name);
470 
471 		expr = new SpelExpressionParser().parseRaw("map.$$");
472 		name = expr.getValue(eContext, String.class);
473 		assertEquals("webble", name);
474 
475 		expr = new SpelExpressionParser().parseRaw("map.$_$");
476 		name = expr.getValue(eContext, String.class);
477 		assertEquals("tribble", name);
478 	}
479 
480 	/** Should be accessing Goo.wibble field because 'bar' variable evaluates to "wibble" */
481 	@Test
482 	public void indexingAsAPropertyAccess_SPR6968_3() {
483 		StandardEvaluationContext eContext = new StandardEvaluationContext(new Goo());
484 		eContext.setVariable("bar", "wibble");
485 		String name = null;
486 		Expression expr = null;
487 		expr = new SpelExpressionParser().parseRaw("instance[#bar]");
488 		// will access the field 'wibble' and not use a getter
489 		name = expr.getValue(eContext, String.class);
490 		assertEquals("wobble", name);
491 		name = expr.getValue(eContext, String.class); // will be using the cached accessor this time
492 		assertEquals("wobble", name);
493 	}
494 
495 	/**
496 	 * Should be accessing (setting) Goo.wibble field because 'bar' variable evaluates to
497 	 * "wibble"
498 	 */
499 	@Test
500 	public void indexingAsAPropertyAccess_SPR6968_4() {
501 		Goo g = Goo.instance;
502 		StandardEvaluationContext eContext = new StandardEvaluationContext(g);
503 		eContext.setVariable("bar", "wibble");
504 		Expression expr = null;
505 		expr = new SpelExpressionParser().parseRaw("instance[#bar]='world'");
506 		// will access the field 'wibble' and not use a getter
507 		expr.getValue(eContext, String.class);
508 		assertEquals("world", g.wibble);
509 		expr.getValue(eContext, String.class); // will be using the cached accessor this time
510 		assertEquals("world", g.wibble);
511 	}
512 
513 	/** Should be accessing Goo.setKey field because 'bar' variable evaluates to "key" */
514 	@Test
515 	public void indexingAsAPropertyAccess_SPR6968_5() {
516 		Goo g = Goo.instance;
517 		StandardEvaluationContext eContext = new StandardEvaluationContext(g);
518 		Expression expr = null;
519 		expr = new SpelExpressionParser().parseRaw("instance[bar]='world'");
520 		expr.getValue(eContext, String.class);
521 		assertEquals("world", g.value);
522 		expr.getValue(eContext, String.class); // will be using the cached accessor this time
523 		assertEquals("world", g.value);
524 	}
525 
526 	@Test
527 	public void dollars() {
528 		StandardEvaluationContext eContext = new StandardEvaluationContext(new XX());
529 		Expression expr = null;
530 		expr = new SpelExpressionParser().parseRaw("m['$foo']");
531 		eContext.setVariable("file_name", "$foo");
532 		assertEquals("wibble", expr.getValue(eContext, String.class));
533 	}
534 
535 	@Test
536 	public void dollars2() {
537 		StandardEvaluationContext eContext = new StandardEvaluationContext(new XX());
538 		Expression expr = null;
539 		expr = new SpelExpressionParser().parseRaw("m[$foo]");
540 		eContext.setVariable("file_name", "$foo");
541 		assertEquals("wibble", expr.getValue(eContext, String.class));
542 	}
543 
544 
545 	static class XX {
546 
547 		public Map<String, String> m;
548 
549 		public String floo = "bar";
550 
551 		public XX() {
552 			m = new HashMap<String, String>();
553 			m.put("$foo", "wibble");
554 			m.put("bar", "siddle");
555 		}
556 	}
557 
558 
559 	static class Goo {
560 
561 		public static Goo instance = new Goo();
562 
563 		public String bar = "key";
564 
565 		public String value = null;
566 
567 		public String wibble = "wobble";
568 
569 		public String getKey() {
570 			return "hello";
571 		}
572 
573 		public void setKey(String s) {
574 			value = s;
575 		}
576 	}
577 
578 
579 	static class Holder {
580 
581 		public Map<String, String> map = new HashMap<String, String>();
582 	}
583 
584 
585 	// ---
586 
587 	private void checkTemplateParsing(String expression, String expectedValue) throws Exception {
588 		checkTemplateParsing(expression, TemplateExpressionParsingTests.DEFAULT_TEMPLATE_PARSER_CONTEXT, expectedValue);
589 	}
590 
591 	private void checkTemplateParsing(String expression, ParserContext context, String expectedValue) throws Exception {
592 		SpelExpressionParser parser = new SpelExpressionParser();
593 		Expression expr = parser.parseExpression(expression, context);
594 		assertEquals(expectedValue, expr.getValue(TestScenarioCreator.getTestEvaluationContext()));
595 	}
596 
597 	private void checkTemplateParsingError(String expression, String expectedMessage) throws Exception {
598 		checkTemplateParsingError(expression, TemplateExpressionParsingTests.DEFAULT_TEMPLATE_PARSER_CONTEXT, expectedMessage);
599 	}
600 
601 	private void checkTemplateParsingError(String expression, ParserContext context, String expectedMessage) throws Exception {
602 		SpelExpressionParser parser = new SpelExpressionParser();
603 		try {
604 			parser.parseExpression(expression, context);
605 			fail("Should have failed with message: " + expectedMessage);
606 		}
607 		catch (Exception ex) {
608 			String message = ex.getMessage();
609 			if (ex instanceof ExpressionException) {
610 				message = ((ExpressionException) ex).getSimpleMessage();
611 			}
612 			if (!message.equals(expectedMessage)) {
613 				ex.printStackTrace();
614 			}
615 			assertThat(expectedMessage, equalTo(message));
616 		}
617 	}
618 
619 
620 	private static final ParserContext DOLLARSQUARE_TEMPLATE_PARSER_CONTEXT = new ParserContext() {
621 		@Override
622 		public String getExpressionPrefix() {
623 			return "$[";
624 		}
625 		@Override
626 		public String getExpressionSuffix() {
627 			return "]";
628 		}
629 		@Override
630 		public boolean isTemplate() {
631 			return true;
632 		}
633 	};
634 
635 
636 	static class Foo2 {
637 
638 		public void execute(String str) {
639 			System.out.println("Value: " + str);
640 		}
641 	}
642 
643 
644 	static class Message {
645 
646 		private String payload;
647 
648 		public String getPayload() {
649 			return payload;
650 		}
651 
652 		public void setPayload(String payload) {
653 			this.payload = payload;
654 		}
655 	}
656 
657 
658 	// bean resolver tests
659 
660 	@Test
661 	public void beanResolution() {
662 		StandardEvaluationContext eContext = new StandardEvaluationContext(new XX());
663 		Expression expr = null;
664 
665 		// no resolver registered == exception
666 		try {
667 			expr = new SpelExpressionParser().parseRaw("@foo");
668 			assertEquals("custard", expr.getValue(eContext, String.class));
669 		}
670 		catch (SpelEvaluationException see) {
671 			assertEquals(SpelMessage.NO_BEAN_RESOLVER_REGISTERED, see.getMessageCode());
672 			assertEquals("foo", see.getInserts()[0]);
673 		}
674 
675 		eContext.setBeanResolver(new MyBeanResolver());
676 
677 		// bean exists
678 		expr = new SpelExpressionParser().parseRaw("@foo");
679 		assertEquals("custard", expr.getValue(eContext, String.class));
680 
681 		// bean does not exist
682 		expr = new SpelExpressionParser().parseRaw("@bar");
683 		assertEquals(null, expr.getValue(eContext, String.class));
684 
685 		// bean name will cause AccessException
686 		expr = new SpelExpressionParser().parseRaw("@goo");
687 		try {
688 			assertEquals(null, expr.getValue(eContext, String.class));
689 		}
690 		catch (SpelEvaluationException see) {
691 			assertEquals(SpelMessage.EXCEPTION_DURING_BEAN_RESOLUTION, see.getMessageCode());
692 			assertEquals("goo", see.getInserts()[0]);
693 			assertTrue(see.getCause() instanceof AccessException);
694 			assertTrue(see.getCause().getMessage().startsWith("DONT"));
695 		}
696 
697 		// bean exists
698 		expr = new SpelExpressionParser().parseRaw("@'foo.bar'");
699 		assertEquals("trouble", expr.getValue(eContext, String.class));
700 
701 		// bean exists
702 		try {
703 			expr = new SpelExpressionParser().parseRaw("@378");
704 			assertEquals("trouble", expr.getValue(eContext, String.class));
705 		}
706 		catch (SpelParseException spe) {
707 			assertEquals(SpelMessage.INVALID_BEAN_REFERENCE, spe.getMessageCode());
708 		}
709 	}
710 
711 
712 	static class MyBeanResolver implements BeanResolver {
713 
714 		@Override
715 		public Object resolve(EvaluationContext context, String beanName) throws AccessException {
716 			if (beanName.equals("foo")) {
717 				return "custard";
718 			}
719 			else if (beanName.equals("foo.bar")) {
720 				return "trouble";
721 			}
722 			else if (beanName.equals("goo")) {
723 				throw new AccessException("DONT ASK ME ABOUT GOO");
724 			}
725 			return null;
726 		}
727 	}
728 
729 
730 	// end bean resolver tests
731 
732 	@Test
733 	public void elvis_SPR7209_1() {
734 		StandardEvaluationContext eContext = new StandardEvaluationContext(new XX());
735 		Expression expr = null;
736 
737 		// Different parts of elvis expression are null
738 		expr = new SpelExpressionParser().parseRaw("(?:'default')");
739 		assertEquals("default", expr.getValue());
740 		expr = new SpelExpressionParser().parseRaw("?:'default'");
741 		assertEquals("default", expr.getValue());
742 		expr = new SpelExpressionParser().parseRaw("?:");
743 		assertEquals(null, expr.getValue());
744 
745 		// Different parts of ternary expression are null
746 		try {
747 			expr = new SpelExpressionParser().parseRaw("(?'abc':'default')");
748 			expr.getValue(eContext);
749 			fail();
750 		}
751 		catch (SpelEvaluationException see) {
752 			assertEquals(SpelMessage.TYPE_CONVERSION_ERROR, see.getMessageCode());
753 		}
754 		expr = new SpelExpressionParser().parseRaw("(false?'abc':null)");
755 		assertEquals(null, expr.getValue());
756 
757 		// Assignment
758 		try {
759 			expr = new SpelExpressionParser().parseRaw("(='default')");
760 			expr.getValue(eContext);
761 			fail();
762 		}
763 		catch (SpelEvaluationException see) {
764 			assertEquals(SpelMessage.SETVALUE_NOT_SUPPORTED, see.getMessageCode());
765 		}
766 	}
767 
768 	@Test
769 	public void elvis_SPR7209_2() {
770 		Expression expr = null;
771 		// Have empty string treated as null for elvis
772 		expr = new SpelExpressionParser().parseRaw("?:'default'");
773 		assertEquals("default", expr.getValue());
774 		expr = new SpelExpressionParser().parseRaw("\"\"?:'default'");
775 		assertEquals("default", expr.getValue());
776 		expr = new SpelExpressionParser().parseRaw("''?:'default'");
777 		assertEquals("default", expr.getValue());
778 	}
779 
780 	@Test
781 	public void mapOfMap_SPR7244() throws Exception {
782 		Map<String, Object> map = new LinkedHashMap<String, Object>();
783 		map.put("uri", "http:");
784 		Map<String, String> nameMap = new LinkedHashMap<String, String>();
785 		nameMap.put("givenName", "Arthur");
786 		map.put("value", nameMap);
787 
788 		StandardEvaluationContext ctx = new StandardEvaluationContext(map);
789 		ExpressionParser parser = new SpelExpressionParser();
790 		String el1 = "#root['value'].get('givenName')";
791 		Expression exp = parser.parseExpression(el1);
792 		Object evaluated = exp.getValue(ctx);
793 		assertEquals("Arthur", evaluated);
794 
795 		String el2 = "#root['value']['givenName']";
796 		exp = parser.parseExpression(el2);
797 		evaluated = exp.getValue(ctx);
798 		assertEquals("Arthur", evaluated);
799 	}
800 
801 	@Test
802 	public void projectionTypeDescriptors_1() throws Exception {
803 		StandardEvaluationContext ctx = new StandardEvaluationContext(new C());
804 		SpelExpressionParser parser = new SpelExpressionParser();
805 		String el1 = "ls.![#this.equals('abc')]";
806 		SpelExpression exp = parser.parseRaw(el1);
807 		List<?> value = (List<?>) exp.getValue(ctx);
808 		// value is list containing [true,false]
809 		assertEquals(Boolean.class, value.get(0).getClass());
810 		TypeDescriptor evaluated = exp.getValueTypeDescriptor(ctx);
811 		assertEquals(null, evaluated.getElementTypeDescriptor());
812 	}
813 
814 	@Test
815 	public void projectionTypeDescriptors_2() throws Exception {
816 		StandardEvaluationContext ctx = new StandardEvaluationContext(new C());
817 		SpelExpressionParser parser = new SpelExpressionParser();
818 		String el1 = "as.![#this.equals('abc')]";
819 		SpelExpression exp = parser.parseRaw(el1);
820 		Object[] value = (Object[]) exp.getValue(ctx);
821 		// value is array containing [true,false]
822 		assertEquals(Boolean.class, value[0].getClass());
823 		TypeDescriptor evaluated = exp.getValueTypeDescriptor(ctx);
824 		assertEquals(Boolean.class, evaluated.getElementTypeDescriptor().getType());
825 	}
826 
827 	@Test
828 	public void projectionTypeDescriptors_3() throws Exception {
829 		StandardEvaluationContext ctx = new StandardEvaluationContext(new C());
830 		SpelExpressionParser parser = new SpelExpressionParser();
831 		String el1 = "ms.![key.equals('abc')]";
832 		SpelExpression exp = parser.parseRaw(el1);
833 		List<?> value = (List<?>) exp.getValue(ctx);
834 		// value is list containing [true,false]
835 		assertEquals(Boolean.class, value.get(0).getClass());
836 		TypeDescriptor evaluated = exp.getValueTypeDescriptor(ctx);
837 		assertEquals(null, evaluated.getElementTypeDescriptor());
838 	}
839 
840 
841 	static class C {
842 
843 		public List<String> ls;
844 		public String[] as;
845 		public Map<String, String> ms;
846 
847 		C() {
848 			ls = new ArrayList<String>();
849 			ls.add("abc");
850 			ls.add("def");
851 			as = new String[] { "abc", "def" };
852 			ms = new HashMap<String, String>();
853 			ms.put("abc", "xyz");
854 			ms.put("def", "pqr");
855 		}
856 	}
857 
858 
859 	static class D {
860 
861 		public String a;
862 
863 		private D(String s) {
864 			a = s;
865 		}
866 
867 		@Override
868 		public String toString() {
869 			return "D(" + a + ")";
870 		}
871 	}
872 
873 
874 	@Test
875 	public void greaterThanWithNulls_SPR7840() throws Exception {
876 		List<D> list = new ArrayList<D>();
877 		list.add(new D("aaa"));
878 		list.add(new D("bbb"));
879 		list.add(new D(null));
880 		list.add(new D("ccc"));
881 		list.add(new D(null));
882 		list.add(new D("zzz"));
883 
884 		StandardEvaluationContext ctx = new StandardEvaluationContext(list);
885 		SpelExpressionParser parser = new SpelExpressionParser();
886 
887 		String el1 = "#root.?[a < 'hhh']";
888 		SpelExpression exp = parser.parseRaw(el1);
889 		Object value = exp.getValue(ctx);
890 		assertEquals("[D(aaa), D(bbb), D(null), D(ccc), D(null)]", value.toString());
891 
892 		String el2 = "#root.?[a > 'hhh']";
893 		SpelExpression exp2 = parser.parseRaw(el2);
894 		Object value2 = exp2.getValue(ctx);
895 		assertEquals("[D(zzz)]", value2.toString());
896 
897 		// trim out the nulls first
898 		String el3 = "#root.?[a!=null].?[a < 'hhh']";
899 		SpelExpression exp3 = parser.parseRaw(el3);
900 		Object value3 = exp3.getValue(ctx);
901 		assertEquals("[D(aaa), D(bbb), D(ccc)]", value3.toString());
902 	}
903 
904 	/**
905 	 * Test whether {@link ReflectiveMethodResolver} follows Java Method Invocation
906 	 * Conversion order. And more precisely that widening reference conversion is 'higher'
907 	 * than a unboxing conversion.
908 	 */
909 	@Test
910 	public void conversionPriority_8224() throws Exception {
911 
912 		@SuppressWarnings("unused")
913 		class ConversionPriority1 {
914 			public int getX(Number i) {
915 				return 20;
916 			}
917 			public int getX(int i) {
918 				return 10;
919 			}
920 		}
921 
922 		@SuppressWarnings("unused")
923 		class ConversionPriority2 {
924 			public int getX(int i) {
925 				return 10;
926 			}
927 			public int getX(Number i) {
928 				return 20;
929 			}
930 		}
931 
932 		final Integer INTEGER = Integer.valueOf(7);
933 
934 		EvaluationContext emptyEvalContext = new StandardEvaluationContext();
935 
936 		List<TypeDescriptor> args = new ArrayList<TypeDescriptor>();
937 		args.add(TypeDescriptor.forObject(new Integer(42)));
938 
939 		ConversionPriority1 target = new ConversionPriority1();
940 		MethodExecutor me = new ReflectiveMethodResolver(true).resolve(emptyEvalContext, target, "getX", args);
941 		// MethodInvoker chooses getX(int i) when passing Integer
942 		final int actual = (Integer) me.execute(emptyEvalContext, target, new Integer(42)).getValue();
943 		// Compiler chooses getX(Number i) when passing Integer
944 		final int compiler = target.getX(INTEGER);
945 		// Fails!
946 		assertEquals(compiler, actual);
947 
948 		ConversionPriority2 target2 = new ConversionPriority2();
949 		MethodExecutor me2 = new ReflectiveMethodResolver(true).resolve(emptyEvalContext, target2, "getX", args);
950 		// MethodInvoker chooses getX(int i) when passing Integer
951 		int actual2 = (Integer) me2.execute(emptyEvalContext, target2, new Integer(42)).getValue();
952 		// Compiler chooses getX(Number i) when passing Integer
953 		int compiler2 = target2.getX(INTEGER);
954 		// Fails!
955 		assertEquals(compiler2, actual2);
956 
957 	}
958 
959 	/**
960 	 * Test whether {@link ReflectiveMethodResolver} handles Widening Primitive Conversion. That's passing an 'int' to a
961 	 * method accepting 'long' is ok.
962 	 */
963 	@Test
964 	public void wideningPrimitiveConversion_8224() throws Exception {
965 
966 		class WideningPrimitiveConversion {
967 			public int getX(long i) {
968 				return 10;
969 			}
970 		}
971 
972 		final Integer INTEGER_VALUE = Integer.valueOf(7);
973 		WideningPrimitiveConversion target = new WideningPrimitiveConversion();
974 		EvaluationContext emptyEvalContext = new StandardEvaluationContext();
975 
976 		List<TypeDescriptor> args = new ArrayList<TypeDescriptor>();
977 		args.add(TypeDescriptor.forObject(INTEGER_VALUE));
978 
979 		MethodExecutor me = new ReflectiveMethodResolver(true).resolve(emptyEvalContext, target, "getX", args);
980 		final int actual = (Integer) me.execute(emptyEvalContext, target, INTEGER_VALUE).getValue();
981 
982 		final int compiler = target.getX(INTEGER_VALUE);
983 		assertEquals(compiler, actual);
984 	}
985 
986 	@Test
987 	public void varargsAndPrimitives_SPR8174() throws Exception {
988 		EvaluationContext emptyEvalContext = new StandardEvaluationContext();
989 		List<TypeDescriptor> args = new ArrayList<TypeDescriptor>();
990 
991 		args.add(TypeDescriptor.forObject(34L));
992 		ReflectionUtil<Integer> ru = new ReflectionUtil<Integer>();
993 		MethodExecutor me = new ReflectiveMethodResolver().resolve(emptyEvalContext, ru, "methodToCall", args);
994 
995 		args.set(0, TypeDescriptor.forObject(23));
996 		me = new ReflectiveMethodResolver().resolve(emptyEvalContext, ru, "foo", args);
997 		me.execute(emptyEvalContext, ru, 45);
998 
999 		args.set(0, TypeDescriptor.forObject(23f));
1000 		me = new ReflectiveMethodResolver().resolve(emptyEvalContext, ru, "foo", args);
1001 		me.execute(emptyEvalContext, ru, 45f);
1002 
1003 		args.set(0, TypeDescriptor.forObject(23d));
1004 		me = new ReflectiveMethodResolver().resolve(emptyEvalContext, ru, "foo", args);
1005 		me.execute(emptyEvalContext, ru, 23d);
1006 
1007 		args.set(0, TypeDescriptor.forObject((short) 23));
1008 		me = new ReflectiveMethodResolver().resolve(emptyEvalContext, ru, "foo", args);
1009 		me.execute(emptyEvalContext, ru, (short) 23);
1010 
1011 		args.set(0, TypeDescriptor.forObject(23L));
1012 		me = new ReflectiveMethodResolver().resolve(emptyEvalContext, ru, "foo", args);
1013 		me.execute(emptyEvalContext, ru, 23L);
1014 
1015 		args.set(0, TypeDescriptor.forObject((char) 65));
1016 		me = new ReflectiveMethodResolver().resolve(emptyEvalContext, ru, "foo", args);
1017 		me.execute(emptyEvalContext, ru, (char) 65);
1018 
1019 		args.set(0, TypeDescriptor.forObject((byte) 23));
1020 		me = new ReflectiveMethodResolver().resolve(emptyEvalContext, ru, "foo", args);
1021 		me.execute(emptyEvalContext, ru, (byte) 23);
1022 
1023 		args.set(0, TypeDescriptor.forObject(true));
1024 		me = new ReflectiveMethodResolver().resolve(emptyEvalContext, ru, "foo", args);
1025 		me.execute(emptyEvalContext, ru, true);
1026 
1027 		// trickier:
1028 		args.set(0, TypeDescriptor.forObject(12));
1029 		args.add(TypeDescriptor.forObject(23f));
1030 		me = new ReflectiveMethodResolver().resolve(emptyEvalContext, ru, "bar", args);
1031 		me.execute(emptyEvalContext, ru, 12, 23f);
1032 	}
1033 
1034 
1035 	public class ReflectionUtil<T extends Number> {
1036 
1037 		public Object methodToCall(T param) {
1038 			System.out.println(param + " " + param.getClass());
1039 			return "Object methodToCall(T param)";
1040 		}
1041 
1042 		public void foo(int... array) {
1043 			if (array.length == 0) {
1044 				throw new RuntimeException();
1045 			}
1046 		}
1047 
1048 		public void foo(float... array) {
1049 			if (array.length == 0) {
1050 				throw new RuntimeException();
1051 			}
1052 		}
1053 
1054 		public void foo(double... array) {
1055 			if (array.length == 0) {
1056 				throw new RuntimeException();
1057 			}
1058 		}
1059 
1060 		public void foo(short... array) {
1061 			if (array.length == 0) {
1062 				throw new RuntimeException();
1063 			}
1064 		}
1065 
1066 		public void foo(long... array) {
1067 			if (array.length == 0) {
1068 				throw new RuntimeException();
1069 			}
1070 		}
1071 
1072 		public void foo(boolean... array) {
1073 			if (array.length == 0) {
1074 				throw new RuntimeException();
1075 			}
1076 		}
1077 
1078 		public void foo(char... array) {
1079 			if (array.length == 0) {
1080 				throw new RuntimeException();
1081 			}
1082 		}
1083 
1084 		public void foo(byte... array) {
1085 			if (array.length == 0) {
1086 				throw new RuntimeException();
1087 			}
1088 		}
1089 
1090 		public void bar(int... array) {
1091 			if (array.length == 0) {
1092 				throw new RuntimeException();
1093 			}
1094 		}
1095 	}
1096 
1097 
1098 	@Test
1099 	public void reservedWords_8228() throws Exception {
1100 		// "DIV","EQ","GE","GT","LE","LT","MOD","NE","NOT"
1101 		@SuppressWarnings("unused")
1102 		class Reserver {
1103 			public Reserver getReserver() {
1104 				return this;
1105 			}
1106 			public String NE = "abc";
1107 			public String ne = "def";
1108 
1109 			public int DIV = 1;
1110 			public int div = 3;
1111 
1112 			public Map<String, String> m = new HashMap<String, String>();
1113 
1114 			Reserver() {
1115 				m.put("NE", "xyz");
1116 			}
1117 		}
1118 
1119 		StandardEvaluationContext ctx = new StandardEvaluationContext(new Reserver());
1120 		SpelExpressionParser parser = new SpelExpressionParser();
1121 		String ex = "getReserver().NE";
1122 		SpelExpression exp = parser.parseRaw(ex);
1123 		String value = (String) exp.getValue(ctx);
1124 		assertEquals("abc", value);
1125 
1126 		ex = "getReserver().ne";
1127 		exp = parser.parseRaw(ex);
1128 		value = (String) exp.getValue(ctx);
1129 		assertEquals("def", value);
1130 
1131 		ex = "getReserver().m[NE]";
1132 		exp = parser.parseRaw(ex);
1133 		value = (String) exp.getValue(ctx);
1134 		assertEquals("xyz", value);
1135 
1136 		ex = "getReserver().DIV";
1137 		exp = parser.parseRaw(ex);
1138 		assertEquals(1, exp.getValue(ctx));
1139 
1140 		ex = "getReserver().div";
1141 		exp = parser.parseRaw(ex);
1142 		assertEquals(3, exp.getValue(ctx));
1143 
1144 		exp = parser.parseRaw("NE");
1145 		assertEquals("abc", exp.getValue(ctx));
1146 	}
1147 
1148 	@Test
1149 	public void reservedWordProperties_9862() throws Exception {
1150 		StandardEvaluationContext ctx = new StandardEvaluationContext();
1151 		SpelExpressionParser parser = new SpelExpressionParser();
1152 		SpelExpression expression = parser.parseRaw("T(org.springframework.expression.spel.testresources.le.div.mod.reserved.Reserver).CONST");
1153 		Object value = expression.getValue(ctx);
1154 		assertEquals(value, Reserver.CONST);
1155 	}
1156 
1157 	/**
1158 	 * We add property accessors in the order:
1159 	 * First, Second, Third, Fourth.
1160 	 * They are not utilized in this order; preventing a priority or order of operations
1161 	 * in evaluation of SPEL expressions for a given context.
1162 	 */
1163 	@Test
1164 	public void propertyAccessorOrder_8211() {
1165 		ExpressionParser expressionParser = new SpelExpressionParser();
1166 		StandardEvaluationContext evaluationContext = new StandardEvaluationContext(new ContextObject());
1167 
1168 		evaluationContext.addPropertyAccessor(new TestPropertyAccessor("firstContext"));
1169 		evaluationContext.addPropertyAccessor(new TestPropertyAccessor("secondContext"));
1170 		evaluationContext.addPropertyAccessor(new TestPropertyAccessor("thirdContext"));
1171 		evaluationContext.addPropertyAccessor(new TestPropertyAccessor("fourthContext"));
1172 
1173 		assertEquals("first", expressionParser.parseExpression("shouldBeFirst").getValue(evaluationContext));
1174 		assertEquals("second", expressionParser.parseExpression("shouldBeSecond").getValue(evaluationContext));
1175 		assertEquals("third", expressionParser.parseExpression("shouldBeThird").getValue(evaluationContext));
1176 		assertEquals("fourth", expressionParser.parseExpression("shouldBeFourth").getValue(evaluationContext));
1177 	}
1178 
1179 
1180 	class TestPropertyAccessor implements PropertyAccessor {
1181 
1182 		private String mapName;
1183 
1184 		public TestPropertyAccessor(String mapName) {
1185 			this.mapName = mapName;
1186 		}
1187 
1188 		@SuppressWarnings("unchecked")
1189 		public Map<String, String> getMap(Object target) {
1190 			try {
1191 				Field f = target.getClass().getDeclaredField(mapName);
1192 				return (Map<String, String>) f.get(target);
1193 			}
1194 			catch (Exception ex) {
1195 			}
1196 			return null;
1197 		}
1198 
1199 		@Override
1200 		public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException {
1201 			return getMap(target).containsKey(name);
1202 		}
1203 
1204 		@Override
1205 		public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
1206 			return getMap(target).containsKey(name);
1207 		}
1208 
1209 		@Override
1210 		public Class<?>[] getSpecificTargetClasses() {
1211 			return new Class<?>[] {ContextObject.class};
1212 		}
1213 
1214 		@Override
1215 		public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
1216 			return new TypedValue(getMap(target).get(name));
1217 		}
1218 
1219 		@Override
1220 		public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException {
1221 			getMap(target).put(name, (String) newValue);
1222 		}
1223 	}
1224 
1225 
1226 	class ContextObject {
1227 
1228 		public Map<String, String> firstContext = new HashMap<String, String>();
1229 		public Map<String, String> secondContext = new HashMap<String, String>();
1230 		public Map<String, String> thirdContext = new HashMap<String, String>();
1231 		public Map<String, String> fourthContext = new HashMap<String, String>();
1232 
1233 		public ContextObject() {
1234 			firstContext.put("shouldBeFirst", "first");
1235 			secondContext.put("shouldBeFirst", "second");
1236 			thirdContext.put("shouldBeFirst", "third");
1237 			fourthContext.put("shouldBeFirst", "fourth");
1238 
1239 			secondContext.put("shouldBeSecond", "second");
1240 			thirdContext.put("shouldBeSecond", "third");
1241 			fourthContext.put("shouldBeSecond", "fourth");
1242 
1243 			thirdContext.put("shouldBeThird", "third");
1244 			fourthContext.put("shouldBeThird", "fourth");
1245 
1246 			fourthContext.put("shouldBeFourth", "fourth");
1247 		}
1248 
1249 		public Map<String, String> getFirstContext() {
1250 			return firstContext;
1251 		}
1252 
1253 		public Map<String, String> getSecondContext() {
1254 			return secondContext;
1255 		}
1256 
1257 		public Map<String, String> getThirdContext() {
1258 			return thirdContext;
1259 		}
1260 
1261 		public Map<String, String> getFourthContext() {
1262 			return fourthContext;
1263 		}
1264 	}
1265 
1266 
1267 	/**
1268 	 * Test the ability to subclass the ReflectiveMethodResolver and change how it
1269 	 * determines the set of methods for a type.
1270 	 */
1271 	@Test
1272 	public void customStaticFunctions_SPR9038() {
1273 		ExpressionParser parser = new SpelExpressionParser();
1274 		StandardEvaluationContext context = new StandardEvaluationContext();
1275 		List<MethodResolver> methodResolvers = new ArrayList<MethodResolver>();
1276 		methodResolvers.add(new ReflectiveMethodResolver() {
1277 			@Override
1278 			protected Method[] getMethods(Class<?> type) {
1279 				try {
1280 					return new Method[] {
1281 							Integer.class.getDeclaredMethod("parseInt", new Class<?>[] {String.class, Integer.TYPE})};
1282 				}
1283 				catch (NoSuchMethodException ex) {
1284 					return new Method[0];
1285 				}
1286 			}
1287 		});
1288 
1289 		context.setMethodResolvers(methodResolvers);
1290 		Expression expression = parser.parseExpression("parseInt('-FF', 16)");
1291 
1292 		Integer result = expression.getValue(context, "", Integer.class);
1293 		assertEquals(-255, result.intValue());
1294 	}
1295 
1296 	@Test
1297 	public void array() {
1298 		ExpressionParser parser = new SpelExpressionParser();
1299 		StandardEvaluationContext context = new StandardEvaluationContext();
1300 		Expression expression = null;
1301 		Object result = null;
1302 
1303 		expression = parser.parseExpression("new java.lang.Long[0].class");
1304 		result = expression.getValue(context, "");
1305 		assertEquals("Equal assertion failed: ", "class [Ljava.lang.Long;", result.toString());
1306 
1307 		expression = parser.parseExpression("T(java.lang.Long[])");
1308 		result = expression.getValue(context, "");
1309 		assertEquals("Equal assertion failed: ", "class [Ljava.lang.Long;", result.toString());
1310 
1311 		expression = parser.parseExpression("T(java.lang.String[][][])");
1312 		result = expression.getValue(context, "");
1313 		assertEquals("Equal assertion failed: ", "class [[[Ljava.lang.String;", result.toString());
1314 		assertEquals("T(java.lang.String[][][])", ((SpelExpression) expression).toStringAST());
1315 
1316 		expression = parser.parseExpression("new int[0].class");
1317 		result = expression.getValue(context, "");
1318 		assertEquals("Equal assertion failed: ", "class [I", result.toString());
1319 
1320 		expression = parser.parseExpression("T(int[][])");
1321 		result = expression.getValue(context, "");
1322 		assertEquals("class [[I", result.toString());
1323 	}
1324 
1325 	@Test
1326 	public void SPR9486_floatFunctionResolver() throws Exception {
1327 		Number expectedResult = Math.abs(-10.2f);
1328 		ExpressionParser parser = new SpelExpressionParser();
1329 		SPR9486_FunctionsClass testObject = new SPR9486_FunctionsClass();
1330 
1331 		StandardEvaluationContext context = new StandardEvaluationContext();
1332 		Expression expression = parser.parseExpression("abs(-10.2f)");
1333 		Number result = expression.getValue(context, testObject, Number.class);
1334 		assertEquals(expectedResult, result);
1335 	}
1336 
1337 
1338 	class SPR9486_FunctionsClass {
1339 
1340 		public int abs(int value) {
1341 			return Math.abs(value);
1342 		}
1343 
1344 		public float abs(float value) {
1345 			return Math.abs(value);
1346 		}
1347 	}
1348 
1349 
1350 	@Test
1351 	public void SPR9486_addFloatWithDouble() {
1352 		Number expectedNumber = 10.21f + 10.2;
1353 		ExpressionParser parser = new SpelExpressionParser();
1354 		StandardEvaluationContext context = new StandardEvaluationContext();
1355 		Expression expression = parser.parseExpression("10.21f + 10.2");
1356 		Number result = expression.getValue(context, null, Number.class);
1357 		assertEquals(expectedNumber, result);
1358 	}
1359 
1360 	@Test
1361 	public void SPR9486_addFloatWithFloat() {
1362 		Number expectedNumber = 10.21f + 10.2f;
1363 		ExpressionParser parser = new SpelExpressionParser();
1364 		StandardEvaluationContext context = new StandardEvaluationContext();
1365 		Expression expression = parser.parseExpression("10.21f + 10.2f");
1366 		Number result = expression.getValue(context, null, Number.class);
1367 		assertEquals(expectedNumber, result);
1368 	}
1369 
1370 	@Test
1371 	public void SPR9486_subtractFloatWithDouble() {
1372 		Number expectedNumber = 10.21f - 10.2;
1373 		ExpressionParser parser = new SpelExpressionParser();
1374 		StandardEvaluationContext context = new StandardEvaluationContext();
1375 		Expression expression = parser.parseExpression("10.21f - 10.2");
1376 		Number result = expression.getValue(context, null, Number.class);
1377 		assertEquals(expectedNumber, result);
1378 	}
1379 
1380 	@Test
1381 	public void SPR9486_subtractFloatWithFloat() {
1382 		Number expectedNumber = 10.21f - 10.2f;
1383 		ExpressionParser parser = new SpelExpressionParser();
1384 		StandardEvaluationContext context = new StandardEvaluationContext();
1385 		Expression expression = parser.parseExpression("10.21f - 10.2f");
1386 		Number result = expression.getValue(context, null, Number.class);
1387 		assertEquals(expectedNumber, result);
1388 	}
1389 
1390 	@Test
1391 	public void SPR9486_multiplyFloatWithDouble() {
1392 		Number expectedNumber = 10.21f * 10.2;
1393 		ExpressionParser parser = new SpelExpressionParser();
1394 		StandardEvaluationContext context = new StandardEvaluationContext();
1395 		Expression expression = parser.parseExpression("10.21f * 10.2");
1396 		Number result = expression.getValue(context, null, Number.class);
1397 		assertEquals(expectedNumber, result);
1398 	}
1399 
1400 	@Test
1401 	public void SPR9486_multiplyFloatWithFloat() {
1402 		Number expectedNumber = 10.21f * 10.2f;
1403 		ExpressionParser parser = new SpelExpressionParser();
1404 		StandardEvaluationContext context = new StandardEvaluationContext();
1405 		Expression expression = parser.parseExpression("10.21f * 10.2f");
1406 		Number result = expression.getValue(context, null, Number.class);
1407 		assertEquals(expectedNumber, result);
1408 	}
1409 
1410 	@Test
1411 	public void SPR9486_floatDivideByFloat() {
1412 		Number expectedNumber = -10.21f / -10.2f;
1413 		ExpressionParser parser = new SpelExpressionParser();
1414 		StandardEvaluationContext context = new StandardEvaluationContext();
1415 		Expression expression = parser.parseExpression("-10.21f / -10.2f");
1416 		Number result = expression.getValue(context, null, Number.class);
1417 		assertEquals(expectedNumber, result);
1418 	}
1419 
1420 	@Test
1421 	public void SPR9486_floatDivideByDouble() {
1422 		Number expectedNumber = -10.21f / -10.2;
1423 		ExpressionParser parser = new SpelExpressionParser();
1424 		StandardEvaluationContext context = new StandardEvaluationContext();
1425 		Expression expression = parser.parseExpression("-10.21f / -10.2");
1426 		Number result = expression.getValue(context, null, Number.class);
1427 		assertEquals(expectedNumber, result);
1428 	}
1429 
1430 	@Test
1431 	public void SPR9486_floatEqFloatUnaryMinus() {
1432 		Boolean expectedResult = -10.21f == -10.2f;
1433 		ExpressionParser parser = new SpelExpressionParser();
1434 		StandardEvaluationContext context = new StandardEvaluationContext();
1435 		Expression expression = parser.parseExpression("-10.21f == -10.2f");
1436 		Boolean result = expression.getValue(context, null, Boolean.class);
1437 		assertEquals(expectedResult, result);
1438 	}
1439 
1440 	@Test
1441 	public void SPR9486_floatEqDoubleUnaryMinus() {
1442 		Boolean expectedResult = -10.21f == -10.2;
1443 		ExpressionParser parser = new SpelExpressionParser();
1444 		StandardEvaluationContext context = new StandardEvaluationContext();
1445 		Expression expression = parser.parseExpression("-10.21f == -10.2");
1446 		Boolean result = expression.getValue(context, null, Boolean.class);
1447 		assertEquals(expectedResult, result);
1448 	}
1449 
1450 	@Test
1451 	public void SPR9486_floatEqFloat() {
1452 		Boolean expectedResult = 10.215f == 10.2109f;
1453 		ExpressionParser parser = new SpelExpressionParser();
1454 		StandardEvaluationContext context = new StandardEvaluationContext();
1455 		Expression expression = parser.parseExpression("10.215f == 10.2109f");
1456 		Boolean result = expression.getValue(context, null, Boolean.class);
1457 		assertEquals(expectedResult, result);
1458 	}
1459 
1460 	@Test
1461 	public void SPR9486_floatEqDouble() {
1462 		Boolean expectedResult = 10.215f == 10.2109;
1463 		ExpressionParser parser = new SpelExpressionParser();
1464 		StandardEvaluationContext context = new StandardEvaluationContext();
1465 		Expression expression = parser.parseExpression("10.215f == 10.2109");
1466 		Boolean result = expression.getValue(context, null, Boolean.class);
1467 		assertEquals(expectedResult, result);
1468 	}
1469 
1470 	@Test
1471 	public void SPR9486_floatNotEqFloat() {
1472 		Boolean expectedResult = 10.215f != 10.2109f;
1473 		ExpressionParser parser = new SpelExpressionParser();
1474 		StandardEvaluationContext context = new StandardEvaluationContext();
1475 		Expression expression = parser.parseExpression("10.215f != 10.2109f");
1476 		Boolean result = expression.getValue(context, null, Boolean.class);
1477 		assertEquals(expectedResult, result);
1478 	}
1479 
1480 	@Test
1481 	public void SPR9486_floatNotEqDouble() {
1482 		Boolean expectedResult = 10.215f != 10.2109;
1483 		ExpressionParser parser = new SpelExpressionParser();
1484 		StandardEvaluationContext context = new StandardEvaluationContext();
1485 		Expression expression = parser.parseExpression("10.215f != 10.2109");
1486 		Boolean result = expression.getValue(context, null, Boolean.class);
1487 		assertEquals(expectedResult, result);
1488 	}
1489 
1490 	@Test
1491 	public void SPR9486_floatLessThanFloat() {
1492 		Boolean expectedNumber = -10.21f < -10.2f;
1493 		ExpressionParser parser = new SpelExpressionParser();
1494 		StandardEvaluationContext context = new StandardEvaluationContext();
1495 		Expression expression = parser.parseExpression("-10.21f < -10.2f");
1496 		Boolean result = expression.getValue(context, null, Boolean.class);
1497 		assertEquals(expectedNumber, result);
1498 	}
1499 
1500 	@Test
1501 	public void SPR9486_floatLessThanDouble() {
1502 		Boolean expectedNumber = -10.21f < -10.2;
1503 		ExpressionParser parser = new SpelExpressionParser();
1504 		StandardEvaluationContext context = new StandardEvaluationContext();
1505 		Expression expression = parser.parseExpression("-10.21f < -10.2");
1506 		Boolean result = expression.getValue(context, null, Boolean.class);
1507 		assertEquals(expectedNumber, result);
1508 	}
1509 
1510 	@Test
1511 	public void SPR9486_floatLessThanOrEqualFloat() {
1512 		Boolean expectedNumber = -10.21f <= -10.22f;
1513 		ExpressionParser parser = new SpelExpressionParser();
1514 		StandardEvaluationContext context = new StandardEvaluationContext();
1515 		Expression expression = parser.parseExpression("-10.21f <= -10.22f");
1516 		Boolean result = expression.getValue(context, null, Boolean.class);
1517 		assertEquals(expectedNumber, result);
1518 	}
1519 
1520 	@Test
1521 	public void SPR9486_floatLessThanOrEqualDouble() {
1522 		Boolean expectedNumber = -10.21f <= -10.2;
1523 		ExpressionParser parser = new SpelExpressionParser();
1524 		StandardEvaluationContext context = new StandardEvaluationContext();
1525 		Expression expression = parser.parseExpression("-10.21f <= -10.2");
1526 		Boolean result = expression.getValue(context, null, Boolean.class);
1527 		assertEquals(expectedNumber, result);
1528 	}
1529 
1530 	@Test
1531 	public void SPR9486_floatGreaterThanFloat() {
1532 		Boolean expectedNumber = -10.21f > -10.2f;
1533 		ExpressionParser parser = new SpelExpressionParser();
1534 		StandardEvaluationContext context = new StandardEvaluationContext();
1535 		Expression expression = parser.parseExpression("-10.21f > -10.2f");
1536 		Boolean result = expression.getValue(context, null, Boolean.class);
1537 		assertEquals(expectedNumber, result);
1538 	}
1539 
1540 	@Test
1541 	public void SPR9486_floatGreaterThanDouble() {
1542 		Boolean expectedResult = -10.21f > -10.2;
1543 		ExpressionParser parser = new SpelExpressionParser();
1544 		StandardEvaluationContext context = new StandardEvaluationContext();
1545 		Expression expression = parser.parseExpression("-10.21f > -10.2");
1546 		Boolean result = expression.getValue(context, null, Boolean.class);
1547 		assertEquals(expectedResult, result);
1548 	}
1549 
1550 	@Test
1551 	public void SPR9486_floatGreaterThanOrEqualFloat() {
1552 		Boolean expectedNumber = -10.21f >= -10.2f;
1553 		ExpressionParser parser = new SpelExpressionParser();
1554 		StandardEvaluationContext context = new StandardEvaluationContext();
1555 		Expression expression = parser.parseExpression("-10.21f >= -10.2f");
1556 		Boolean result = expression.getValue(context, null, Boolean.class);
1557 		assertEquals(expectedNumber, result);
1558 	}
1559 
1560 	@Test
1561 	public void SPR9486_floatGreaterThanEqualDouble() {
1562 		Boolean expectedResult = -10.21f >= -10.2;
1563 		ExpressionParser parser = new SpelExpressionParser();
1564 		StandardEvaluationContext context = new StandardEvaluationContext();
1565 		Expression expression = parser.parseExpression("-10.21f >= -10.2");
1566 		Boolean result = expression.getValue(context, null, Boolean.class);
1567 		assertEquals(expectedResult, result);
1568 	}
1569 
1570 	@Test
1571 	public void SPR9486_floatModulusFloat() {
1572 		Number expectedResult = 10.21f % 10.2f;
1573 		ExpressionParser parser = new SpelExpressionParser();
1574 		StandardEvaluationContext context = new StandardEvaluationContext();
1575 		Expression expression = parser.parseExpression("10.21f % 10.2f");
1576 		Number result = expression.getValue(context, null, Number.class);
1577 		assertEquals(expectedResult, result);
1578 	}
1579 
1580 	@Test
1581 	public void SPR9486_floatModulusDouble() {
1582 		Number expectedResult = 10.21f % 10.2;
1583 		ExpressionParser parser = new SpelExpressionParser();
1584 		StandardEvaluationContext context = new StandardEvaluationContext();
1585 		Expression expression = parser.parseExpression("10.21f % 10.2");
1586 		Number result = expression.getValue(context, null, Number.class);
1587 		assertEquals(expectedResult, result);
1588 	}
1589 
1590 	@Test
1591 	public void SPR9486_floatPowerFloat() {
1592 		Number expectedResult = Math.pow(10.21f, -10.2f);
1593 		ExpressionParser parser = new SpelExpressionParser();
1594 		StandardEvaluationContext context = new StandardEvaluationContext();
1595 		Expression expression = parser.parseExpression("10.21f ^ -10.2f");
1596 		Number result = expression.getValue(context, null, Number.class);
1597 		assertEquals(expectedResult, result);
1598 	}
1599 
1600 	@Test
1601 	public void SPR9486_floatPowerDouble() {
1602 		Number expectedResult = Math.pow(10.21f, 10.2);
1603 		ExpressionParser parser = new SpelExpressionParser();
1604 		StandardEvaluationContext context = new StandardEvaluationContext();
1605 		Expression expression = parser.parseExpression("10.21f ^ 10.2");
1606 		Number result = expression.getValue(context, null, Number.class);
1607 		assertEquals(expectedResult, result);
1608 	}
1609 
1610 	@Test
1611 	public void SPR9994_bridgeMethods() throws Exception {
1612 		ReflectivePropertyAccessor accessor = new ReflectivePropertyAccessor();
1613 		StandardEvaluationContext context = new StandardEvaluationContext();
1614 		Object target = new GenericImplementation();
1615 		TypedValue value = accessor.read(context, target, "property");
1616 		assertEquals(Integer.class, value.getTypeDescriptor().getType());
1617 	}
1618 
1619 	@Test
1620 	public void SPR10162_onlyBridgeMethod() throws Exception {
1621 		ReflectivePropertyAccessor accessor = new ReflectivePropertyAccessor();
1622 		StandardEvaluationContext context = new StandardEvaluationContext();
1623 		Object target = new OnlyBridgeMethod();
1624 		TypedValue value = accessor.read(context, target, "property");
1625 		assertEquals(Integer.class, value.getTypeDescriptor().getType());
1626 	}
1627 
1628 	@Test
1629 	public void SPR10091_simpleTestValueType() {
1630 		ExpressionParser parser = new SpelExpressionParser();
1631 		StandardEvaluationContext evaluationContext = new StandardEvaluationContext(new BooleanHolder());
1632 		Class<?> valueType = parser.parseExpression("simpleProperty").getValueType(evaluationContext);
1633 		assertNotNull(valueType);
1634 	}
1635 
1636 	@Test
1637 	public void SPR10091_simpleTestValue() {
1638 		ExpressionParser parser = new SpelExpressionParser();
1639 		StandardEvaluationContext evaluationContext = new StandardEvaluationContext(new BooleanHolder());
1640 		Object value = parser.parseExpression("simpleProperty").getValue(evaluationContext);
1641 		assertNotNull(value);
1642 	}
1643 
1644 	@Test
1645 	public void SPR10091_primitiveTestValueType() {
1646 		ExpressionParser parser = new SpelExpressionParser();
1647 		StandardEvaluationContext evaluationContext = new StandardEvaluationContext(new BooleanHolder());
1648 		Class<?> valueType = parser.parseExpression("primitiveProperty").getValueType(evaluationContext);
1649 		assertNotNull(valueType);
1650 	}
1651 
1652 	@Test
1653 	public void SPR10091_primitiveTestValue() {
1654 		ExpressionParser parser = new SpelExpressionParser();
1655 		StandardEvaluationContext evaluationContext = new StandardEvaluationContext(new BooleanHolder());
1656 		Object value = parser.parseExpression("primitiveProperty").getValue(evaluationContext);
1657 		assertNotNull(value);
1658 	}
1659 
1660 	@Test
1661 	public void SPR10146_malformedExpressions() throws Exception {
1662 		doTestSpr10146("/foo", "EL1070E:(pos 0): Problem parsing left operand");
1663 		doTestSpr10146("*foo", "EL1070E:(pos 0): Problem parsing left operand");
1664 		doTestSpr10146("%foo", "EL1070E:(pos 0): Problem parsing left operand");
1665 		doTestSpr10146("<foo", "EL1070E:(pos 0): Problem parsing left operand");
1666 		doTestSpr10146(">foo", "EL1070E:(pos 0): Problem parsing left operand");
1667 		doTestSpr10146("&&foo", "EL1070E:(pos 0): Problem parsing left operand");
1668 		doTestSpr10146("||foo", "EL1070E:(pos 0): Problem parsing left operand");
1669 		doTestSpr10146("&foo", "EL1069E:(pos 0): missing expected character '&'");
1670 		doTestSpr10146("|foo", "EL1069E:(pos 0): missing expected character '|'");
1671 	}
1672 
1673 	private void doTestSpr10146(String expression, String expectedMessage) {
1674 		thrown.expect(SpelParseException.class);
1675 		thrown.expectMessage(expectedMessage);
1676 		new SpelExpressionParser().parseExpression(expression);
1677 	}
1678 
1679 	@Test
1680 	public void SPR10125() throws Exception {
1681 		StandardEvaluationContext context = new StandardEvaluationContext();
1682 		String fromInterface = parser.parseExpression("T(" + StaticFinalImpl1.class.getName() + ").VALUE").getValue(
1683 				context, String.class);
1684 		assertThat(fromInterface, is("interfaceValue"));
1685 		String fromClass = parser.parseExpression("T(" + StaticFinalImpl2.class.getName() + ").VALUE").getValue(
1686 				context, String.class);
1687 		assertThat(fromClass, is("interfaceValue"));
1688 	}
1689 
1690 	@Test
1691 	public void SPR10210() throws Exception {
1692 		StandardEvaluationContext context = new StandardEvaluationContext();
1693 		context.setVariable("bridgeExample", new org.springframework.expression.spel.spr10210.D());
1694 		Expression parseExpression = parser.parseExpression("#bridgeExample.bridgeMethod()");
1695 		parseExpression.getValue(context);
1696 	}
1697 
1698 	@Test
1699 	public void SPR10328() throws Exception {
1700 		thrown.expect(SpelParseException.class);
1701 		thrown.expectMessage("EL1071E:(pos 2): A required selection expression has not been specified");
1702 		Expression exp = parser.parseExpression("$[]");
1703 		exp.getValue(Arrays.asList("foo", "bar", "baz"));
1704 	}
1705 
1706 	@Test
1707 	public void SPR10452() throws Exception {
1708 		SpelParserConfiguration configuration = new SpelParserConfiguration(false, false);
1709 		ExpressionParser parser = new SpelExpressionParser(configuration);
1710 
1711 		StandardEvaluationContext context = new StandardEvaluationContext();
1712 		Expression spel = parser.parseExpression("#enumType.values()");
1713 
1714 		context.setVariable("enumType", ABC.class);
1715 		Object result = spel.getValue(context);
1716 		assertNotNull(result);
1717 		assertTrue(result.getClass().isArray());
1718 		assertEquals(ABC.A, Array.get(result, 0));
1719 		assertEquals(ABC.B, Array.get(result, 1));
1720 		assertEquals(ABC.C, Array.get(result, 2));
1721 
1722 		context.setVariable("enumType", XYZ.class);
1723 		result = spel.getValue(context);
1724 		assertNotNull(result);
1725 		assertTrue(result.getClass().isArray());
1726 		assertEquals(XYZ.X, Array.get(result, 0));
1727 		assertEquals(XYZ.Y, Array.get(result, 1));
1728 		assertEquals(XYZ.Z, Array.get(result, 2));
1729 	}
1730 
1731 	@Test
1732 	public void SPR9495() throws Exception {
1733 		SpelParserConfiguration configuration = new SpelParserConfiguration(false, false);
1734 		ExpressionParser parser = new SpelExpressionParser(configuration);
1735 
1736 		StandardEvaluationContext context = new StandardEvaluationContext();
1737 		Expression spel = parser.parseExpression("#enumType.values()");
1738 
1739 		context.setVariable("enumType", ABC.class);
1740 		Object result = spel.getValue(context);
1741 		assertNotNull(result);
1742 		assertTrue(result.getClass().isArray());
1743 		assertEquals(ABC.A, Array.get(result, 0));
1744 		assertEquals(ABC.B, Array.get(result, 1));
1745 		assertEquals(ABC.C, Array.get(result, 2));
1746 
1747 		context.addMethodResolver(new MethodResolver() {
1748 			@Override
1749 			public MethodExecutor resolve(EvaluationContext context, Object targetObject, String name,
1750 					List<TypeDescriptor> argumentTypes) throws AccessException {
1751 				return new MethodExecutor() {
1752 					@Override
1753 					public TypedValue execute(EvaluationContext context, Object target, Object... arguments)
1754 							throws AccessException {
1755 						try {
1756 							Method method = XYZ.class.getMethod("values");
1757 							Object value = method.invoke(target, arguments);
1758 							return new TypedValue(value, new TypeDescriptor(new MethodParameter(method, -1)).narrow(value));
1759 						}
1760 						catch (Exception ex) {
1761 							throw new AccessException(ex.getMessage(), ex);
1762 						}
1763 					}
1764 				};
1765 			}
1766 		});
1767 		result = spel.getValue(context);
1768 		assertNotNull(result);
1769 		assertTrue(result.getClass().isArray());
1770 		assertEquals(XYZ.X, Array.get(result, 0));
1771 		assertEquals(XYZ.Y, Array.get(result, 1));
1772 		assertEquals(XYZ.Z, Array.get(result, 2));
1773 	}
1774 
1775 	@Test
1776 	public void SPR10486() throws Exception {
1777 		SpelExpressionParser parser = new SpelExpressionParser();
1778 		StandardEvaluationContext context = new StandardEvaluationContext();
1779 		Spr10486 rootObject = new Spr10486();
1780 		Expression classNameExpression = parser.parseExpression("class.name");
1781 		Expression nameExpression = parser.parseExpression("name");
1782 		assertThat(classNameExpression.getValue(context, rootObject), equalTo((Object) Spr10486.class.getName()));
1783 		assertThat(nameExpression.getValue(context, rootObject), equalTo((Object) "name"));
1784 	}
1785 
1786 	@Test
1787 	public void SPR11142() throws Exception {
1788 		SpelExpressionParser parser = new SpelExpressionParser();
1789 		StandardEvaluationContext context = new StandardEvaluationContext();
1790 		Spr11142 rootObject = new Spr11142();
1791 		Expression expression = parser.parseExpression("something");
1792 		thrown.expect(SpelEvaluationException.class);
1793 		thrown.expectMessage("'something' cannot be found");
1794 		expression.getValue(context, rootObject);
1795 	}
1796 
1797 	@Test
1798 	public void SPR9194() {
1799 		TestClass2 one = new TestClass2("abc");
1800 		TestClass2 two = new TestClass2("abc");
1801 		Map<String, TestClass2> map = new HashMap<String, TestClass2>();
1802 		map.put("one", one);
1803 		map.put("two", two);
1804 
1805 		SpelExpressionParser parser = new SpelExpressionParser();
1806 		Expression expr = parser.parseExpression("['one'] == ['two']");
1807 		assertTrue(expr.getValue(map, Boolean.class));
1808 	}
1809 
1810 	@Test
1811 	public void SPR11348() {
1812 		Collection<String> coll = new LinkedHashSet<String>();
1813 		coll.add("one");
1814 		coll.add("two");
1815 		coll = Collections.unmodifiableCollection(coll);
1816 
1817 		SpelExpressionParser parser = new SpelExpressionParser();
1818 		Expression expr = parser.parseExpression("new java.util.ArrayList(#root)");
1819 		Object value = expr.getValue(coll);
1820 		assertTrue(value instanceof ArrayList);
1821 		@SuppressWarnings("rawtypes")
1822 		ArrayList list = (ArrayList) value;
1823 		assertEquals("one", list.get(0));
1824 		assertEquals("two", list.get(1));
1825 	}
1826 
1827 	@Test
1828 	public void SPR11445_simple() {
1829 		StandardEvaluationContext context = new StandardEvaluationContext(new Spr11445Class());
1830 		Expression expr = new SpelExpressionParser().parseRaw("echo(parameter())");
1831 		assertEquals(1, expr.getValue(context));
1832 	}
1833 
1834 	@Test
1835 	public void SPR11445_beanReference() {
1836 		StandardEvaluationContext context = new StandardEvaluationContext();
1837 		context.setBeanResolver(new Spr11445Class());
1838 		Expression expr = new SpelExpressionParser().parseRaw("@bean.echo(@bean.parameter())");
1839 		assertEquals(1, expr.getValue(context));
1840 	}
1841 
1842 	@Test
1843 	@SuppressWarnings("unchecked")
1844 	public void SPR11494() {
1845 		Expression exp = new SpelExpressionParser().parseExpression("T(java.util.Arrays).asList('a','b')");
1846 		List<String> list = (List<String>) exp.getValue();
1847 		assertThat(list.size(), is(2));
1848 	}
1849 
1850 	@Test
1851 	public void SPR11609() {
1852 		StandardEvaluationContext sec = new StandardEvaluationContext();
1853 		sec.addPropertyAccessor(new MapAccessor());
1854 		Expression exp = new SpelExpressionParser().parseExpression(
1855 				"T(org.springframework.expression.spel.SpelReproTests$MapWithConstant).X");
1856 		assertEquals(1, exp.getValue(sec));
1857 	}
1858 
1859 	@Test
1860 	public void SPR9735() {
1861 		Item item = new Item();
1862 		item.setName("parent");
1863 
1864 		Item item1 = new Item();
1865 		item1.setName("child1");
1866 
1867 		Item item2 = new Item();
1868 		item2.setName("child2");
1869 
1870 		item.add(item1);
1871 		item.add(item2);
1872 
1873 		ExpressionParser parser = new SpelExpressionParser();
1874 		EvaluationContext context = new StandardEvaluationContext();
1875 		Expression exp = parser.parseExpression("#item[0].name");
1876 		context.setVariable("item", item);
1877 
1878 		assertEquals("child1", exp.getValue(context));
1879 	}
1880 
1881 	@Test
1882 	public void SPR12502() {
1883 		SpelExpressionParser parser = new SpelExpressionParser();
1884 		Expression expression = parser.parseExpression("#root.getClass().getName()");
1885 		assertEquals(UnnamedUser.class.getName(), expression.getValue(new UnnamedUser()));
1886 		assertEquals(NamedUser.class.getName(), expression.getValue(new NamedUser()));
1887 	}
1888 
1889 	@Test
1890 	public void SPR12522() {
1891 		SpelExpressionParser parser = new SpelExpressionParser();
1892 		Expression expression = parser.parseExpression("T(java.util.Arrays).asList('')");
1893 		Object value = expression.getValue();
1894 		assertTrue(value instanceof List);
1895 		assertTrue(((List) value).isEmpty());
1896 	}
1897 
1898 	@Test
1899 	public void SPR12803() throws Exception {
1900 		StandardEvaluationContext sec = new StandardEvaluationContext();
1901 		sec.setVariable("iterable", Collections.emptyList());
1902 		SpelExpressionParser parser = new SpelExpressionParser();
1903 		Expression expression = parser.parseExpression("T(org.springframework.expression.spel.SpelReproTests.GuavaLists).newArrayList(#iterable)");
1904 		assertTrue(expression.getValue(sec) instanceof ArrayList);
1905 	}
1906 
1907 
1908 	private static enum ABC { A, B, C }
1909 
1910 	private static enum XYZ { X, Y, Z }
1911 
1912 
1913 	public static class BooleanHolder {
1914 
1915 		private Boolean simpleProperty = true;
1916 
1917 		private boolean primitiveProperty = true;
1918 
1919 		public void setSimpleProperty(Boolean simpleProperty) {
1920 			this.simpleProperty = simpleProperty;
1921 		}
1922 
1923 		public Boolean isSimpleProperty() {
1924 			return this.simpleProperty;
1925 		}
1926 
1927 		public void setPrimitiveProperty(boolean primitiveProperty) {
1928 			this.primitiveProperty = primitiveProperty;
1929 		}
1930 
1931 		public boolean isPrimitiveProperty() {
1932 			return this.primitiveProperty;
1933 		}
1934 	}
1935 
1936 
1937 	private static interface GenericInterface<T extends Number> {
1938 
1939 		public T getProperty();
1940 	}
1941 
1942 
1943 	private static class GenericImplementation implements GenericInterface<Integer> {
1944 
1945 		@Override
1946 		public Integer getProperty() {
1947 			return null;
1948 		}
1949 	}
1950 
1951 
1952 	static class PackagePrivateClassWithGetter {
1953 
1954 		public Integer getProperty() {
1955 			return null;
1956 		}
1957 	}
1958 
1959 
1960 	public static class OnlyBridgeMethod extends PackagePrivateClassWithGetter {
1961 	}
1962 
1963 
1964 	public static interface StaticFinal {
1965 
1966 		public static final String VALUE = "interfaceValue";
1967 	}
1968 
1969 
1970 	public abstract static class AbstractStaticFinal implements StaticFinal {
1971 	}
1972 
1973 
1974 	public static class StaticFinalImpl1 extends AbstractStaticFinal implements StaticFinal {
1975 	}
1976 
1977 
1978 	public static class StaticFinalImpl2 extends AbstractStaticFinal {
1979 	}
1980 
1981 
1982 	public static class Spr10486 {
1983 
1984 		private String name = "name";
1985 
1986 		public void setName(String name) {
1987 			this.name = name;
1988 		}
1989 
1990 		public String getName() {
1991 			return this.name;
1992 		}
1993 	}
1994 
1995 
1996 	static class Spr11142 {
1997 
1998 		public String isSomething() {
1999 			return "";
2000 		}
2001 	}
2002 
2003 
2004 	static class TestClass2 {  // SPR-9194
2005 
2006 		String string;
2007 
2008 		public TestClass2(String string) {
2009 			this.string = string;
2010 		}
2011 
2012 		public boolean equals(Object other) {
2013 			return (this == other || (other instanceof TestClass2 &&
2014 					this.string.equals(((TestClass2) other).string)));
2015 		}
2016 
2017 		@Override
2018 		public int hashCode() {
2019 			return this.string.hashCode();
2020 		}
2021 	}
2022 
2023 
2024 	static class Spr11445Class implements BeanResolver {
2025 
2026 		private final AtomicInteger counter = new AtomicInteger();
2027 
2028 		public int echo(int invocation) {
2029 			return invocation;
2030 		}
2031 
2032 		public int parameter() {
2033 			return this.counter.incrementAndGet();
2034 		}
2035 
2036 		@Override
2037 		public Object resolve(EvaluationContext context, String beanName) throws AccessException {
2038 			return (beanName.equals("bean") ? this : null);
2039 		}
2040 	}
2041 
2042 
2043 	@SuppressWarnings({ "rawtypes", "serial" })
2044 	public static class MapWithConstant extends HashMap {
2045 
2046 		public static final int X = 1;
2047 	}
2048 
2049 
2050 	public class Item implements List<Item> {
2051 
2052 		private String name;
2053 
2054 		private List<Item> children = new ArrayList<Item>();
2055 
2056 		public void setName(String name) {
2057 			this.name = name;
2058 		}
2059 
2060 		public String getName() {
2061 			return this.name;
2062 		}
2063 
2064 		@Override
2065 		public int size() {
2066 			return this.children.size();
2067 		}
2068 
2069 		@Override
2070 		public boolean isEmpty() {
2071 			return this.children.isEmpty();
2072 		}
2073 
2074 		@Override
2075 		public boolean contains(Object o) {
2076 			return this.children.contains(o);
2077 		}
2078 
2079 		@Override
2080 		public Iterator<Item> iterator() {
2081 			return this.children.iterator();
2082 		}
2083 
2084 		@Override
2085 		public Object[] toArray() {
2086 			return this.children.toArray();
2087 		}
2088 
2089 		@Override
2090 		public <T> T[] toArray(T[] a) {
2091 			return this.children.toArray(a);
2092 		}
2093 
2094 		@Override
2095 		public boolean add(Item e) {
2096 			return this.children.add(e);
2097 		}
2098 
2099 		@Override
2100 		public boolean remove(Object o) {
2101 			return this.children.remove(o);
2102 		}
2103 
2104 		@Override
2105 		public boolean containsAll(Collection<?> c) {
2106 			return this.children.containsAll(c);
2107 		}
2108 
2109 		@Override
2110 		public boolean addAll(Collection<? extends Item> c) {
2111 			return this.children.addAll(c);
2112 		}
2113 
2114 		@Override
2115 		public boolean addAll(int index, Collection<? extends Item> c) {
2116 			return this.children.addAll(index, c);
2117 		}
2118 
2119 		@Override
2120 		public boolean removeAll(Collection<?> c) {
2121 			return this.children.removeAll(c);
2122 		}
2123 
2124 		@Override
2125 		public boolean retainAll(Collection<?> c) {
2126 			return this.children.retainAll(c);
2127 		}
2128 
2129 		@Override
2130 		public void clear() {
2131 			this.children.clear();
2132 		}
2133 
2134 		@Override
2135 		public Item get(int index) {
2136 			return this.children.get(index);
2137 		}
2138 
2139 		@Override
2140 		public Item set(int index, Item element) {
2141 			return this.children.set(index, element);
2142 		}
2143 
2144 		@Override
2145 		public void add(int index, Item element) {
2146 			this.children.add(index, element);
2147 		}
2148 
2149 		@Override
2150 		public Item remove(int index) {
2151 			return this.children.remove(index);
2152 		}
2153 
2154 		@Override
2155 		public int indexOf(Object o) {
2156 			return this.children.indexOf(o);
2157 		}
2158 
2159 		@Override
2160 		public int lastIndexOf(Object o) {
2161 			return this.children.lastIndexOf(o);
2162 		}
2163 
2164 		@Override
2165 		public ListIterator<Item> listIterator() {
2166 			return this.children.listIterator();
2167 		}
2168 
2169 		@Override
2170 		public ListIterator<Item> listIterator(int index) {
2171 			return this.children.listIterator(index);
2172 		}
2173 
2174 		@Override
2175 		public List<Item> subList(int fromIndex, int toIndex) {
2176 			return this.children.subList(fromIndex, toIndex);
2177 		}
2178 	}
2179 
2180 
2181 	public static class UnnamedUser {
2182 	}
2183 
2184 
2185 	public static class NamedUser {
2186 
2187 		public String getName() {
2188 			return "foo";
2189 		}
2190 	}
2191 
2192 
2193 	public static class GuavaLists {
2194 
2195 		public static <T> List<T> newArrayList(Iterable<T> iterable) {
2196 			return new ArrayList<T>();
2197 		}
2198 
2199 		public static <T> List<T> newArrayList(Object... elements) {
2200 			throw new UnsupportedOperationException();
2201 		}
2202 	}
2203 
2204 }