initial typeDescriptor awareness in the EL. some basic testing of using GenericConversionService

This commit is contained in:
Andy Clement
2009-04-01 21:38:51 +00:00
parent 65afc80821
commit 54865c0c1f
18 changed files with 328 additions and 29 deletions

View File

@@ -16,13 +16,14 @@
package org.springframework.expression.spel;
import java.awt.*;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
@@ -264,6 +265,10 @@ public class ExpressionLanguageScenarioTests extends ExpressionTestCase {
public void write(EvaluationContext context, Object target, String name, Object newValue)
throws AccessException {
}
public TypeDescriptor getTypeDescriptor(EvaluationContext context, Object target, String name) {
return null;
}
}
@@ -301,6 +306,9 @@ public class ExpressionLanguageScenarioTests extends ExpressionTestCase {
public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException {
}
public TypeDescriptor getTypeDescriptor(EvaluationContext context, Object target, String name) {
return null;
}
}
}

View File

@@ -0,0 +1,121 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel;
import java.util.ArrayList;
import java.util.List;
import org.springframework.core.convert.ConversionExecutor;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.service.DefaultConversionService;
import org.springframework.core.convert.service.GenericConversionService;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.Expression;
import org.springframework.expression.TypeConverter;
import org.springframework.expression.spel.support.StandardEvaluationContext;
/**
* Expression evaluation where the TypeConverter plugged in is the {@link GenericConversionService}
*
* @author Andy Clement
*/
public class ExpressionTestsUsingCoreConversionService extends ExpressionTestCase {
private static List<String> listOfString = new ArrayList<String>();
private static TypeDescriptor typeDescriptorForListOfString = null;
private static List<Integer> listOfInteger = new ArrayList<Integer>();
private static TypeDescriptor typeDescriptorForListOfInteger = null;
static {
listOfString.add("1");
listOfString.add("2");
listOfString.add("3");
listOfInteger.add(4);
listOfInteger.add(5);
listOfInteger.add(6);
}
public void setUp() throws Exception {
super.setUp();
typeDescriptorForListOfString = new TypeDescriptor(ExpressionTestsUsingCoreConversionService.class.getDeclaredField("listOfString"));
typeDescriptorForListOfInteger = new TypeDescriptor(ExpressionTestsUsingCoreConversionService.class.getDeclaredField("listOfInteger"));
}
/**
* Test the service can convert what we are about to use in the expression evaluation tests.
*/
public void testConversionsAvailable() throws Exception {
TypeConvertorUsingConversionService tcs = new TypeConvertorUsingConversionService();
// ArrayList containing List<Integer> to List<String>
Class<?> clazz = typeDescriptorForListOfString.getElementType();
assertEquals(String.class,clazz);
ConversionExecutor executor = tcs.getConversionExecutor(ArrayList.class, typeDescriptorForListOfString);
assertNotNull(executor);
List l = (List)executor.execute(listOfInteger);
assertNotNull(l);
// ArrayList containing List<String> to List<Integer>
clazz = typeDescriptorForListOfInteger.getElementType();
assertEquals(Integer.class,clazz);
executor = tcs.getConversionExecutor(ArrayList.class, typeDescriptorForListOfInteger);
assertNotNull(executor);
l = (List)executor.execute(listOfString);
assertNotNull(l);
}
public void testSetParameterizedList() throws Exception {
StandardEvaluationContext context = TestScenarioCreator.getTestEvaluationContext();
Expression e = parser.parseExpression("listOfInteger.size()");
assertEquals(0,e.getValue(context,Integer.class).intValue());
context.setTypeConverter(new TypeConvertorUsingConversionService());
// Assign a List<String> to the List<Integer> field - the component elements should be converted
parser.parseExpression("listOfInteger").setValue(context,listOfString);
assertEquals(3,e.getValue(context,Integer.class).intValue()); // size now 3
Class clazz = parser.parseExpression("listOfInteger[1].getClass()").getValue(context,Class.class); // element type correctly Integer
assertEquals(Integer.class,clazz);
}
/**
* Type convertor that uses the core conversion service.
*/
private static class TypeConvertorUsingConversionService extends DefaultConversionService implements TypeConverter {
public boolean canConvert(Class<?> sourceType, Class<?> targetType) {
return super.canConvert(sourceType, TypeDescriptor.valueOf(targetType));
}
public boolean canConvert(Class<?> sourceType, TypeDescriptor typeDescriptor) {
return super.canConvert(sourceType, typeDescriptor);
}
@SuppressWarnings("unchecked")
public <T> T convertValue(Object value, Class<T> targetType) throws EvaluationException {
return (T)super.executeConversion(value,TypeDescriptor.valueOf(targetType));
}
@SuppressWarnings("unchecked")
public <T> T convertValue(Object value, TypeDescriptor typeDescriptor)
throws EvaluationException {
return (T)super.executeConversion(value, typeDescriptor);
}
}
}

View File

@@ -18,6 +18,7 @@ package org.springframework.expression.spel;
import java.util.Map;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
@@ -61,7 +62,7 @@ public class MapAccessTests extends ExpressionTestCase {
}
private static class MapAccessor implements PropertyAccessor {
public static class MapAccessor implements PropertyAccessor {
public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException {
return (((Map) target).containsKey(name));
@@ -75,6 +76,7 @@ public class MapAccessTests extends ExpressionTestCase {
return true;
}
@SuppressWarnings("unchecked")
public void write(EvaluationContext context, Object target, String name, Object newValue)
throws AccessException {
((Map) target).put(name, newValue);
@@ -83,6 +85,10 @@ public class MapAccessTests extends ExpressionTestCase {
public Class<?>[] getSpecificTargetClasses() {
return new Class[] { Map.class };
}
public TypeDescriptor getTypeDescriptor(EvaluationContext context, Object target, String name) {
return TypeDescriptor.valueOf(Map.class);
}
}
}

View File

@@ -16,6 +16,7 @@
package org.springframework.expression.spel;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
@@ -87,6 +88,10 @@ public class PropertyAccessTests extends ExpressionTestCase {
int flibbles = 7;
public TypeDescriptor getTypeDescriptor(EvaluationContext context, Object target, String name) {
return null;
}
public Class<?>[] getSpecificTargetClasses() {
return new Class[] { String.class };
}

View File

@@ -18,6 +18,7 @@ package org.springframework.expression.spel;
import java.lang.reflect.Method;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
@@ -224,6 +225,11 @@ public class ScenariosForSpringSecurity extends ExpressionTestCase {
public Class<?>[] getSpecificTargetClasses() {
return null;
}
public TypeDescriptor getTypeDescriptor(EvaluationContext context, Object target, String name) {
return null;
}
}
@@ -252,6 +258,10 @@ public class ScenariosForSpringSecurity extends ExpressionTestCase {
public Class<?>[] getSpecificTargetClasses() {
return null;
}
public TypeDescriptor getTypeDescriptor(EvaluationContext context, Object target, String name) {
return null;
}
}

View File

@@ -98,11 +98,14 @@ public class SetValueTests extends ExpressionTestCase {
setValueExpectError("'hello'[3]", 'p');
}
// public void testSetPropertyTypeCoersion() {
// setValue("publicBoolean", "true");
// }
public void testSetPropertyTypeCoersion() {
setValue("publicBoolean", "true", Boolean.TRUE);
}
public void testSetPropertyTypeCoersionThroughSetter() {
setValue("SomeProperty", "true", Boolean.TRUE);
}
/**
* Call setValue() but expect it to fail.
*/
@@ -116,7 +119,6 @@ public class SetValueTests extends ExpressionTestCase {
SpelUtilities.printAbstractSyntaxTree(System.out, e);
}
StandardEvaluationContext lContext = TestScenarioCreator.getTestEvaluationContext();
// assertTrue("Expression is not writeable but should be", e.isWritable(lContext));
e.setValue(lContext, value);
fail("expected an error");
} catch (ParseException pe) {
@@ -148,4 +150,30 @@ public class SetValueTests extends ExpressionTestCase {
fail("Unexpected Exception: " + pe.getMessage());
}
}
/**
* For use when coercion is happening during a setValue(). The expectedValue should be
* the coerced form of the value.
*/
protected void setValue(String expression, Object value, Object expectedValue) {
try {
Expression e = parser.parseExpression(expression);
if (e == null) {
fail("Parser returned null for expression");
}
if (DEBUG) {
SpelUtilities.printAbstractSyntaxTree(System.out, e);
}
StandardEvaluationContext lContext = TestScenarioCreator.getTestEvaluationContext();
assertTrue("Expression is not writeable but should be", e.isWritable(lContext));
e.setValue(lContext, value);
assertEquals("Retrieved value was not equal to set value", expectedValue, e.getValue(lContext));
} catch (EvaluationException ee) {
ee.printStackTrace();
fail("Unexpected Exception: " + ee.getMessage());
} catch (ParseException pe) {
pe.printStackTrace();
fail("Unexpected Exception: " + pe.getMessage());
}
}
}

View File

@@ -21,6 +21,8 @@ public class Inventor {
private List<PlaceOfBirth> placesLivedList = new ArrayList<PlaceOfBirth>();
public ArrayContainer arrayContainer;
public boolean publicBoolean;
private boolean accessedThroughGetSet;
public List<Integer> listOfInteger = new ArrayList<Integer>();
public Inventor(String name, Date birthdate, String nationality) {
this.name = name;
@@ -110,4 +112,12 @@ public class Inventor {
public Inventor(String... strings) {
}
public boolean getSomeProperty() {
return accessedThroughGetSet;
}
public void setSomeProperty(boolean b) {
this.accessedThroughGetSet = b;
}
}