From 98808347ca4e1c0fffa3430321e701bc4c297257 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Thu, 6 Sep 2012 18:40:00 -0700 Subject: [PATCH 1/2] Remove trailing whitespace --- .../support/ReflectiveMethodResolver.java | 4 +- .../support/ReflectivePropertyAccessor.java | 42 +++++------ .../spel/MethodInvocationTests.java | 70 +++++++++---------- .../expression/spel/PropertyAccessTests.java | 16 ++--- 4 files changed, 66 insertions(+), 66 deletions(-) diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java index 33d1f510b17..dd8045430d0 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java @@ -53,7 +53,7 @@ public class ReflectiveMethodResolver implements MethodResolver { private Map, MethodFilter> filters = null; - // Using distance will ensure a more accurate match is discovered, + // Using distance will ensure a more accurate match is discovered, // more closely following the Java rules. private boolean useDistance = false; @@ -66,7 +66,7 @@ public class ReflectiveMethodResolver implements MethodResolver { * This constructors allows the ReflectiveMethodResolver to be configured such that it will * use a distance computation to check which is the better of two close matches (when there * are multiple matches). Using the distance computation is intended to ensure matches - * are more closely representative of what a Java compiler would do when taking into + * are more closely representative of what a Java compiler would do when taking into * account boxing/unboxing and whether the method candidates are declared to handle a * supertype of the type (of the argument) being passed in. * @param useDistance true if distance computation should be used when calculating matches diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java index 3409bd47f91..108e926e09f 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java @@ -37,8 +37,8 @@ import org.springframework.util.StringUtils; /** * Simple PropertyAccessor that uses reflection to access properties for reading and writing. A property can be accessed - * if it is accessible as a field on the object or through a getter (if being read) or a setter (if being written). - * + * if it is accessible as a field on the object or through a getter (if being read) or a setter (if being written). + * * @author Andy Clement * @author Juergen Hoeller * @since 3.0 @@ -48,7 +48,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { protected final Map readerCache = new ConcurrentHashMap(); protected final Map writerCache = new ConcurrentHashMap(); - + protected final Map typeDescriptorCache = new ConcurrentHashMap(); @@ -85,7 +85,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { Field field = findField(name, type, target instanceof Class); if (field != null) { TypeDescriptor typeDescriptor = new TypeDescriptor(field); - this.readerCache.put(cacheKey, new InvokerPair(field,typeDescriptor)); + this.readerCache.put(cacheKey, new InvokerPair(field,typeDescriptor)); this.typeDescriptorCache.put(cacheKey, typeDescriptor); return true; } @@ -252,7 +252,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { throw new AccessException("Neither setter nor field found for property '" + name + "'"); } - + private TypeDescriptor getTypeDescriptor(EvaluationContext context, Object target, String name) { if (target == null) { return null; @@ -340,22 +340,22 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { } return null; } - + /** * Captures the member (method/field) to call reflectively to access a property value and the type descriptor for the * value returned by the reflective call. */ private static class InvokerPair { - + final Member member; - + final TypeDescriptor typeDescriptor; public InvokerPair(Member member, TypeDescriptor typeDescriptor) { this.member = member; this.typeDescriptor = typeDescriptor; - } - + } + } private static class CacheKey { @@ -387,9 +387,9 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { } } - /** + /** * Attempt to create an optimized property accessor tailored for a property of a particular name on - * a particular class. The general ReflectivePropertyAccessor will always work but is not optimal + * a particular class. The general ReflectivePropertyAccessor will always work but is not optimal * due to the need to lookup which reflective member (method/field) to use each time read() is called. * This method will just return the ReflectivePropertyAccessor instance if it is unable to build * something more optimal. @@ -438,10 +438,10 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { } return this; } - + /** - * An optimized form of a PropertyAccessor that will use reflection but only knows how to access a particular property - * on a particular class. This is unlike the general ReflectivePropertyResolver which manages a cache of methods/fields that + * An optimized form of a PropertyAccessor that will use reflection but only knows how to access a particular property + * on a particular class. This is unlike the general ReflectivePropertyResolver which manages a cache of methods/fields that * may be invoked to access different properties on different classes. This optimal accessor exists because looking up * the appropriate reflective object by class/name on each read is not cheap. */ @@ -449,13 +449,13 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { private final Member member; private final TypeDescriptor typeDescriptor; private final boolean needsToBeMadeAccessible; - + OptimalPropertyAccessor(InvokerPair target) { - this.member = target.member; + this.member = target.member; this.typeDescriptor = target.typeDescriptor; if (this.member instanceof Field) { Field field = (Field)member; - needsToBeMadeAccessible = (!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())) + needsToBeMadeAccessible = (!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())) && !field.isAccessible(); } else { @@ -468,7 +468,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { public Class[] getSpecificTargetClasses() { throw new UnsupportedOperationException("Should not be called on an OptimalPropertyAccessor"); } - + public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { if (target == null) { return false; @@ -504,7 +504,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { catch (Exception ex) { throw new AccessException("Unable to access property '" + name + "' through getter", ex); } - } + } if (member instanceof Field) { try { if (needsToBeMadeAccessible) { @@ -523,7 +523,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { throw new UnsupportedOperationException("Should not be called on an OptimalPropertyAccessor"); } - + public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException { throw new UnsupportedOperationException("Should not be called on an OptimalPropertyAccessor"); diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/MethodInvocationTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/MethodInvocationTests.java index 9ed90cae419..75ccfb3b4a8 100644 --- a/spring-expression/src/test/java/org/springframework/expression/spel/MethodInvocationTests.java +++ b/spring-expression/src/test/java/org/springframework/expression/spel/MethodInvocationTests.java @@ -40,7 +40,7 @@ import org.springframework.expression.spel.testresources.PlaceOfBirth; /** * Tests invocation of methods. - * + * * @author Andy Clement */ public class MethodInvocationTests extends ExpressionTestCase { @@ -89,7 +89,7 @@ public class MethodInvocationTests extends ExpressionTestCase { evaluate("new String('hello 2.0 to you').startsWith(7.0d)", false, Boolean.class); evaluate("new String('7.0 foobar').startsWith(7.0d)", true, Boolean.class); } - + @Test public void testMethodThrowingException_SPR6760() { // Test method on inventor: throwException() @@ -97,7 +97,7 @@ public class MethodInvocationTests extends ExpressionTestCase { // On 2 it will throw a RuntimeException // On 3 it will exit normally // In each case it increments the Inventor field 'counter' when invoked - + SpelExpressionParser parser = new SpelExpressionParser(); Expression expr = parser.parseExpression("throwException(#bar)"); @@ -115,18 +115,18 @@ public class MethodInvocationTests extends ExpressionTestCase { o = expr.getValue(eContext); Assert.assertEquals("London", o); // That confirms the logic to mark the cached reference stale and retry is working - - + + // Now let's cause the method to exit via exception and ensure it doesn't cause // a retry. - + // First, switch back to throwException(int) eContext.setVariable("bar",3); o = expr.getValue(eContext); Assert.assertEquals(3, o); Assert.assertEquals(2,parser.parseExpression("counter").getValue(eContext)); - + // Now cause it to throw an exception: eContext.setVariable("bar",1); try { @@ -157,7 +157,7 @@ public class MethodInvocationTests extends ExpressionTestCase { // If counter is 5 then the method got called twice! Assert.assertEquals(4,parser.parseExpression("counter").getValue(eContext)); } - + /** * Check on first usage (when the cachedExecutor in MethodReference is null) that the exception is not wrapped. */ @@ -168,10 +168,10 @@ public class MethodInvocationTests extends ExpressionTestCase { // On 2 it will throw a RuntimeException // On 3 it will exit normally // In each case it increments the Inventor field 'counter' when invoked - + SpelExpressionParser parser = new SpelExpressionParser(); Expression expr = parser.parseExpression("throwException(#bar)"); - + eContext.setVariable("bar",2); try { expr.getValue(eContext); @@ -184,7 +184,7 @@ public class MethodInvocationTests extends ExpressionTestCase { // normal } } - + @Test public void testMethodThrowingException_SPR6941_2() { // Test method on inventor: throwException() @@ -192,10 +192,10 @@ public class MethodInvocationTests extends ExpressionTestCase { // On 2 it will throw a RuntimeException // On 3 it will exit normally // In each case it increments the Inventor field 'counter' when invoked - + SpelExpressionParser parser = new SpelExpressionParser(); Expression expr = parser.parseExpression("throwException(#bar)"); - + eContext.setVariable("bar",4); try { expr.getValue(eContext); @@ -207,7 +207,7 @@ public class MethodInvocationTests extends ExpressionTestCase { } Assert.fail("Should not be a SpelEvaluationException"); } - + @Test public void testMethodFiltering_SPR6764() { SpelExpressionParser parser = new SpelExpressionParser(); @@ -215,13 +215,13 @@ public class MethodInvocationTests extends ExpressionTestCase { context.setRootObject(new TestObject()); LocalFilter filter = new LocalFilter(); context.registerMethodFilter(TestObject.class,filter); - + // Filter will be called but not do anything, so first doit() will be invoked SpelExpression expr = (SpelExpression) parser.parseExpression("doit(1)"); String result = expr.getValue(context,String.class); Assert.assertEquals("1",result); Assert.assertTrue(filter.filterCalled); - + // Filter will now remove non @Anno annotated methods filter.removeIfNotAnnotated = true; filter.filterCalled = false; @@ -229,7 +229,7 @@ public class MethodInvocationTests extends ExpressionTestCase { result = expr.getValue(context,String.class); Assert.assertEquals("double 1.0",result); Assert.assertTrue(filter.filterCalled); - + // check not called for other types filter.filterCalled=false; context.setRootObject(new String("abc")); @@ -237,7 +237,7 @@ public class MethodInvocationTests extends ExpressionTestCase { result = expr.getValue(context,String.class); Assert.assertEquals("a",result); Assert.assertFalse(filter.filterCalled); - + // check de-registration works filter.filterCalled = false; context.registerMethodFilter(TestObject.class,null);//clear filter @@ -247,14 +247,14 @@ public class MethodInvocationTests extends ExpressionTestCase { Assert.assertEquals("1",result); Assert.assertFalse(filter.filterCalled); } - + // Simple filter static class LocalFilter implements MethodFilter { - + public boolean removeIfNotAnnotated = false; - + public boolean filterCalled = false; - + private boolean isAnnotated(Method m) { Annotation[] annos = m.getAnnotations(); if (annos==null) { @@ -282,53 +282,53 @@ public class MethodInvocationTests extends ExpressionTestCase { } return methods; } - + } - + @Retention(RetentionPolicy.RUNTIME) @interface Anno {} - + class TestObject { public int doit(int i) { return i; } - + @Anno public String doit(double d) { return "double "+d; } - + } - + @Test public void testAddingMethodResolvers() { StandardEvaluationContext ctx = new StandardEvaluationContext(); - + // reflective method accessor is the only one by default List methodResolvers = ctx.getMethodResolvers(); Assert.assertEquals(1,methodResolvers.size()); - + MethodResolver dummy = new DummyMethodResolver(); ctx.addMethodResolver(dummy); Assert.assertEquals(2,ctx.getMethodResolvers().size()); - + List copy = new ArrayList(); copy.addAll(ctx.getMethodResolvers()); Assert.assertTrue(ctx.removeMethodResolver(dummy)); Assert.assertFalse(ctx.removeMethodResolver(dummy)); Assert.assertEquals(1,ctx.getMethodResolvers().size()); - + ctx.setMethodResolvers(copy); Assert.assertEquals(2,ctx.getMethodResolvers().size()); } - + static class DummyMethodResolver implements MethodResolver { public MethodExecutor resolve(EvaluationContext context, Object targetObject, String name, List argumentTypes) throws AccessException { throw new UnsupportedOperationException("Auto-generated method stub"); } - + } @@ -355,7 +355,7 @@ public class MethodInvocationTests extends ExpressionTestCase { evaluate("aVarargsMethod2(2,'a',3.0d)", 4, Integer.class); // evaluate("aVarargsMethod2(8,new String[]{'a','b','c'})", 11, Integer.class); } - + @Test public void testInvocationOnNullContextObject() { evaluateAndCheckError("null.toString()",SpelMessage.METHOD_CALL_ON_NULL_OBJECT_NOT_ALLOWED); diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/PropertyAccessTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/PropertyAccessTests.java index 2610b3a6be9..d49e69d9917 100644 --- a/spring-expression/src/test/java/org/springframework/expression/spel/PropertyAccessTests.java +++ b/spring-expression/src/test/java/org/springframework/expression/spel/PropertyAccessTests.java @@ -37,7 +37,7 @@ import org.springframework.expression.spel.support.StandardEvaluationContext; /** * Tests accessing of properties. - * + * * @author Andy Clement */ public class PropertyAccessTests extends ExpressionTestCase { @@ -65,9 +65,9 @@ public class PropertyAccessTests extends ExpressionTestCase { // name is ok but foobar does not exist: evaluateAndCheckError("name.foobar", SpelMessage.PROPERTY_OR_FIELD_NOT_READABLE, 5); } - + /** - * The standard reflection resolver cannot find properties on null objects but some + * The standard reflection resolver cannot find properties on null objects but some * supplied resolver might be able to - so null shouldn't crash the reflection resolver. */ @Test @@ -132,25 +132,25 @@ public class PropertyAccessTests extends ExpressionTestCase { // System.out.println(e.getMessage()); } } - + @Test public void testAddingRemovingAccessors() { StandardEvaluationContext ctx = new StandardEvaluationContext(); - + // reflective property accessor is the only one by default List propertyAccessors = ctx.getPropertyAccessors(); Assert.assertEquals(1,propertyAccessors.size()); - + StringyPropertyAccessor spa = new StringyPropertyAccessor(); ctx.addPropertyAccessor(spa); Assert.assertEquals(2,ctx.getPropertyAccessors().size()); - + List copy = new ArrayList(); copy.addAll(ctx.getPropertyAccessors()); Assert.assertTrue(ctx.removePropertyAccessor(spa)); Assert.assertFalse(ctx.removePropertyAccessor(spa)); Assert.assertEquals(1,ctx.getPropertyAccessors().size()); - + ctx.setPropertyAccessors(copy); Assert.assertEquals(2,ctx.getPropertyAccessors().size()); } From d28592a6c66f62059c0cf056cc7db04cebb947c3 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Thu, 6 Sep 2012 20:06:35 -0700 Subject: [PATCH 2/2] =?UTF-8?q?SpEL=20support=20for=20methods=20and=20prop?= =?UTF-8?q?erties=20on=20class=20=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update the ReflectiveMethodResolver and ReflectivePropertyAccessor to allow methods and properties of java.lang.Class to be resolved when the target object is a class. Issue: SPR-9017 --- .../support/ReflectiveMethodResolver.java | 16 ++++++- .../support/ReflectivePropertyAccessor.java | 44 ++++++++++++++----- .../spel/MethodInvocationTests.java | 10 ++++- .../expression/spel/PropertyAccessTests.java | 11 ++++- 4 files changed, 67 insertions(+), 14 deletions(-) diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java index dd8045430d0..c086771cbed 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,8 +21,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import org.springframework.core.MethodParameter; import org.springframework.core.convert.TypeDescriptor; @@ -90,7 +92,7 @@ public class ReflectiveMethodResolver implements MethodResolver { try { TypeConverter typeConverter = context.getTypeConverter(); Class type = (targetObject instanceof Class ? (Class) targetObject : targetObject.getClass()); - Method[] methods = getMethods(type); + Method[] methods = getMethods(type, targetObject); // If a filter is registered for this type, call it MethodFilter filter = (this.filters != null ? this.filters.get(type) : null); @@ -197,6 +199,16 @@ public class ReflectiveMethodResolver implements MethodResolver { } } + private Method[] getMethods(Class type, Object targetObject) { + if(targetObject instanceof Class) { + Set methods = new HashSet(); + methods.addAll(Arrays.asList(getMethods(type))); + methods.addAll(Arrays.asList(getMethods(targetObject.getClass()))); + return methods.toArray(new Method[methods.size()]); + } + return getMethods(type); + } + /** * Return the set of methods for this type. The default implementation returns the * result of Class#getMethods for the given {@code type}, but subclasses may override diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java index 108e926e09f..0dd11d23ca0 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -71,7 +71,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { if (this.readerCache.containsKey(cacheKey)) { return true; } - Method method = findGetterForProperty(name, type, target instanceof Class); + Method method = findGetterForProperty(name, type, target); if (method != null) { // Treat it like a property // The readerCache will only contain gettable properties (let's not worry about setters for now) @@ -82,7 +82,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { return true; } else { - Field field = findField(name, type, target instanceof Class); + Field field = findField(name, type, target); if (field != null) { TypeDescriptor typeDescriptor = new TypeDescriptor(field); this.readerCache.put(cacheKey, new InvokerPair(field,typeDescriptor)); @@ -112,7 +112,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { if (invoker == null || invoker.member instanceof Method) { Method method = (Method) (invoker != null ? invoker.member : null); if (method == null) { - method = findGetterForProperty(name, type, target instanceof Class); + method = findGetterForProperty(name, type, target); if (method != null) { // TODO remove the duplication here between canRead and read // Treat it like a property @@ -138,7 +138,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { if (invoker == null || invoker.member instanceof Field) { Field field = (Field) (invoker == null ? null : invoker.member); if (field == null) { - field = findField(name, type, target instanceof Class); + field = findField(name, type, target); if (field != null) { invoker = new InvokerPair(field, new TypeDescriptor(field)); this.readerCache.put(cacheKey, invoker); @@ -168,7 +168,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { if (this.writerCache.containsKey(cacheKey)) { return true; } - Method method = findSetterForProperty(name, type, target instanceof Class); + Method method = findSetterForProperty(name, type, target); if (method != null) { // Treat it like a property Property property = new Property(type, null, method); @@ -178,7 +178,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { return true; } else { - Field field = findField(name, type, target instanceof Class); + Field field = findField(name, type, target); if (field != null) { this.writerCache.put(cacheKey, field); this.typeDescriptorCache.put(cacheKey, new TypeDescriptor(field)); @@ -211,7 +211,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { if (cachedMember == null || cachedMember instanceof Method) { Method method = (Method) cachedMember; if (method == null) { - method = findSetterForProperty(name, type, target instanceof Class); + method = findSetterForProperty(name, type, target); if (method != null) { cachedMember = method; this.writerCache.put(cacheKey, cachedMember); @@ -232,7 +232,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { if (cachedMember == null || cachedMember instanceof Field) { Field field = (Field) cachedMember; if (field == null) { - field = findField(name, type, target instanceof Class); + field = findField(name, type, target); if (field != null) { cachedMember = field; this.writerCache.put(cacheKey, cachedMember); @@ -281,6 +281,30 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { return typeDescriptor; } + private Method findGetterForProperty(String propertyName, Class clazz, Object target) { + Method method = findGetterForProperty(propertyName, clazz, target instanceof Class); + if(method == null && target instanceof Class) { + method = findGetterForProperty(propertyName, target.getClass(), false); + } + return method; + } + + private Method findSetterForProperty(String propertyName, Class clazz, Object target) { + Method method = findSetterForProperty(propertyName, clazz, target instanceof Class); + if(method == null && target instanceof Class) { + method = findSetterForProperty(propertyName, target.getClass(), false); + } + return method; + } + + private Field findField(String name, Class clazz, Object target) { + Field field = findField(name, clazz, target instanceof Class); + if(field == null && target instanceof Class) { + field = findField(name, target.getClass(), false); + } + return field; + } + /** * Find a getter method for the specified property. */ @@ -410,7 +434,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { if (invocationTarget == null || invocationTarget.member instanceof Method) { Method method = (Method) (invocationTarget==null?null:invocationTarget.member); if (method == null) { - method = findGetterForProperty(name, type, target instanceof Class); + method = findGetterForProperty(name, type, target); if (method != null) { invocationTarget = new InvokerPair(method,new TypeDescriptor(new MethodParameter(method,-1))); ReflectionUtils.makeAccessible(method); diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/MethodInvocationTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/MethodInvocationTests.java index 75ccfb3b4a8..6134533eb1b 100644 --- a/spring-expression/src/test/java/org/springframework/expression/spel/MethodInvocationTests.java +++ b/spring-expression/src/test/java/org/springframework/expression/spel/MethodInvocationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,8 @@ package org.springframework.expression.spel; +import static org.junit.Assert.*; + import java.lang.annotation.Annotation; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -361,4 +363,10 @@ public class MethodInvocationTests extends ExpressionTestCase { evaluateAndCheckError("null.toString()",SpelMessage.METHOD_CALL_ON_NULL_OBJECT_NOT_ALLOWED); } + @Test + public void testMethodOfClass() throws Exception { + Expression expression = parser.parseExpression("getName()"); + Object value = expression.getValue(new StandardEvaluationContext(String.class)); + assertEquals(value, "java.lang.String"); + } } diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/PropertyAccessTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/PropertyAccessTests.java index d49e69d9917..3cb81de5e92 100644 --- a/spring-expression/src/test/java/org/springframework/expression/spel/PropertyAccessTests.java +++ b/spring-expression/src/test/java/org/springframework/expression/spel/PropertyAccessTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,8 @@ package org.springframework.expression.spel; +import static org.junit.Assert.*; + import java.util.ArrayList; import java.util.List; @@ -155,6 +157,13 @@ public class PropertyAccessTests extends ExpressionTestCase { Assert.assertEquals(2,ctx.getPropertyAccessors().size()); } + @Test + public void testAccessingPropertyOfClass() throws Exception { + Expression expression = parser.parseExpression("name"); + Object value = expression.getValue(new StandardEvaluationContext(String.class)); + assertEquals(value, "java.lang.String"); + } + // This can resolve the property 'flibbles' on any String (very useful...) private static class StringyPropertyAccessor implements PropertyAccessor {