bug fixes related to binding and type conversion

This commit is contained in:
Keith Donald
2008-07-03 17:23:42 +00:00
parent f20578be56
commit 29cb51240e
25 changed files with 242 additions and 48 deletions

View File

@@ -19,8 +19,7 @@ package org.springframework.binding.convert;
* A service interface for retrieving type conversion executors. The returned command objects are thread-safe and may be
* safely cached for use by client code.
*
* Type converters convert from one type to another. They are more generic than formatters, which convert from string to
* object and back.
* Type converters convert from one type to another.
*
* @author Keith Donald
*/
@@ -39,13 +38,19 @@ public interface ConversionService {
public ConversionExecutor getConversionExecutor(Class sourceClass, Class targetClass)
throws ConversionExecutorNotFoundException;
/**
* Return all conversion executors capable of converting <i>from</i> the provided <code>sourceClass</code>. For
* example, <code>ConversionExecutor[] getConversionExecutor(String.class)</code> would return all converters that
* convert from String to some other Object.
* @param sourceClass the source class converting from
* @return the conversion executors that can convert from that source class
*/
public ConversionExecutor[] getConversionExecutors(Class sourceClass);
/**
* Lookup a class by it alias. For example, <code>long</code> for <code>java.lang.Long</code>
* @param alias the class alias
* @return the class, or <code>null</code> if no alias exists
*/
public Class getClassForAlias(String alias);
public ConversionExecutor[] getConversionExecutors(Class sourceClass);
}

View File

@@ -1,3 +1,18 @@
/*
* Copyright 2004-2008 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.binding.convert.converters;
import java.lang.reflect.Array;
@@ -5,10 +20,21 @@ import java.lang.reflect.Array;
import org.springframework.binding.convert.ConversionExecutor;
import org.springframework.binding.convert.ConversionService;
/**
* Special one-way converter that converts from a source array to a target array. Supports type conversion of the
* individual array elements; for example, the ability to convert a String[] to an Integer[]. Mainly used internally by
* {@link ConversionService} implementations.
*
* @author Keith Donald
*/
public class ArrayToArray implements Converter {
private ConversionService conversionService;
/**
* Creates a new array-to-array converter.
* @param conversionService the service to use to lookup conversion executors for individual array elements
*/
public ArrayToArray(ConversionService conversionService) {
this.conversionService = conversionService;
}

View File

@@ -1,3 +1,18 @@
/*
* Copyright 2004-2008 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.binding.convert.converters;
import java.lang.reflect.Array;
@@ -16,6 +31,19 @@ import org.springframework.binding.convert.ConversionService;
import org.springframework.core.GenericCollectionTypeResolver;
import org.springframework.core.JdkVersion;
/**
* Special one-way converter that converts from a source array to a target collection. Supports the selection of an
* "approximate" collection implementation when a target collection interface such as <code>List.class</code> is
* specified. Supports type conversion of array elements when a concrete parameterized collection class is provided,
* such as <code>IntegerList<Integer>.class</code>.
*
* Note that type erasure prevents arbitrary access to generic collection element type information at runtime,
* preventing the ability to convert elements for collections declared as properties.
*
* Mainly used internally by {@link ConversionService} implementations.
*
* @author Keith Donald
*/
public class ArrayToCollection implements TwoWayConverter {
private ConversionService conversionService;

View File

@@ -1,3 +1,18 @@
/*
* Copyright 2004-2008 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.binding.convert.converters;
import java.lang.reflect.Array;

View File

@@ -1,3 +1,18 @@
/*
* Copyright 2004-2008 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.binding.convert.converters;
import java.beans.PropertyEditor;

View File

@@ -1,3 +1,18 @@
/*
* Copyright 2004-2008 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.binding.convert.converters;
public class ReverseConverter implements Converter {

View File

@@ -1,3 +1,18 @@
/*
* Copyright 2004-2008 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.binding.convert.converters;
public class StringToCharacter extends StringToObject {

View File

@@ -1,3 +1,18 @@
/*
* Copyright 2004-2008 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.binding.convert.converters;
public abstract class StringToObject implements TwoWayConverter {

View File

@@ -20,14 +20,11 @@ import java.math.BigInteger;
import java.util.Date;
import java.util.Locale;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.binding.convert.ConversionService;
import org.springframework.binding.convert.converters.StringToBigDecimal;
import org.springframework.binding.convert.converters.StringToBigInteger;
import org.springframework.binding.convert.converters.StringToBoolean;
import org.springframework.binding.convert.converters.StringToByte;
import org.springframework.binding.convert.converters.StringToCharacter;
import org.springframework.binding.convert.converters.StringToClass;
import org.springframework.binding.convert.converters.StringToDate;
import org.springframework.binding.convert.converters.StringToDouble;
import org.springframework.binding.convert.converters.StringToFloat;
@@ -37,7 +34,6 @@ import org.springframework.binding.convert.converters.StringToLocale;
import org.springframework.binding.convert.converters.StringToLong;
import org.springframework.binding.convert.converters.StringToShort;
import org.springframework.core.enums.LabeledEnum;
import org.springframework.util.ClassUtils;
/**
* Default, local implementation of a conversion service. Will automatically register <i>from string</i> converters for
@@ -45,14 +41,7 @@ import org.springframework.util.ClassUtils;
*
* @author Keith Donald
*/
public class DefaultConversionService extends GenericConversionService implements BeanClassLoaderAware {
/**
* A singleton shared instance. Should never be modified.
*/
private static DefaultConversionService SHARED_INSTANCE;
private ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
public class DefaultConversionService extends GenericConversionService {
/**
* Creates a new default conversion service, installing the default converters.
@@ -76,7 +65,6 @@ public class DefaultConversionService extends GenericConversionService implement
addConverter(new StringToDouble());
addConverter(new StringToBigInteger());
addConverter(new StringToBigDecimal());
addConverter(new StringToClass(classLoader));
addConverter(new StringToLocale());
addConverter(new StringToDate());
addConverter(new StringToLabeledEnum());
@@ -94,23 +82,9 @@ public class DefaultConversionService extends GenericConversionService implement
addAlias("double", Double.class);
addAlias("bigInteger", BigInteger.class);
addAlias("bigDecimal", BigDecimal.class);
addAlias("class", Class.class);
addAlias("locale", Locale.class);
addAlias("date", Date.class);
addAlias("labeledEnum", LabeledEnum.class);
}
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
/**
* Returns the shared {@link DefaultConversionService} instance.
*/
public synchronized static ConversionService getSharedInstance() {
if (SHARED_INSTANCE == null) {
SHARED_INSTANCE = new DefaultConversionService();
}
return SHARED_INSTANCE;
}
}

View File

@@ -1,3 +1,18 @@
/*
* Copyright 2004-2008 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.binding.expression.beanwrapper;
import java.beans.PropertyEditorSupport;
@@ -12,12 +27,34 @@ import org.springframework.binding.expression.EvaluationException;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.PropertyNotFoundException;
/**
* An expression that delegates to a {@link BeanWrapperImpl bean wrapper} to evaluate or set a property of a context.
*
* Also supports the configuration of a {@link ConversionService} to allow StringToObject type conversion to occur as
* part of setting a property. The StringToObject ConversionExecutors are automatically adapted and registered as
* PropertyEditors.
*
* Mainly exists to take advantage of BeanWrapper's unique property access features as an Expression implementation,
* notably the ability to infer types of generic collections and maps and perform type coersion on collection elements
* when setting values.
*
* Note that Spring's BeanWrapper is not a full-blown EL implementation: it only supports property access, and does not
* support method invocation, arithmetic operations, or logic operations.
*
* @author Keith Donald
*/
public class BeanWrapperExpression implements Expression {
private String expression;
private ConversionService conversionService;
/**
* Creates a new bean wrapper expression.
* @param expression the property expression string
* @param conversionService the conversion service containing converters to use as PropertyEditors for type
* conversion
*/
public BeanWrapperExpression(String expression, ConversionService conversionService) {
this.expression = expression;
this.conversionService = conversionService;
@@ -81,7 +118,7 @@ public class BeanWrapperExpression implements Expression {
return expression;
}
public static class PropertyEditorConverter extends PropertyEditorSupport {
private static class PropertyEditorConverter extends PropertyEditorSupport {
private ConversionExecutor converter;

View File

@@ -15,6 +15,9 @@
*/
package org.springframework.binding.expression.beanwrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.propertyeditors.PropertiesEditor;
import org.springframework.binding.convert.ConversionExecutor;
import org.springframework.binding.convert.ConversionService;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.ParserContext;
@@ -22,7 +25,7 @@ import org.springframework.binding.expression.ParserException;
import org.springframework.binding.expression.support.AbstractExpressionParser;
/**
* An expression parser that parses Ognl expressions.
* An expression parser that parses BeanWrapper property expressions.
*
* @author Keith Donald
*/
@@ -30,10 +33,22 @@ public class BeanWrapperExpressionParser extends AbstractExpressionParser {
private ConversionService conversionService;
/**
* The conversion service to use to obtain {@link ConversionExecutor conversion executors} that will be adapted to
* {@link PropertiesEditor property editors} for use during a
* {@link BeanWrapperImpl#setPropertyValue(String, Object) set value} call.
* @return the conversion service
*/
public ConversionService getConversionService() {
return conversionService;
}
/**
* Sets the conversion service to use to obtain {@link ConversionExecutor conversion executors} that will be adapted
* to {@link PropertiesEditor property editors} for use during a
* {@link BeanWrapperImpl#setPropertyValue(String, Object) set value} call.
* @param conversionService the conversion service
*/
public void setConversionService(ConversionService conversionService) {
this.conversionService = conversionService;
}

View File

@@ -44,7 +44,8 @@ public class DefaultExpressionFactoryUtils {
public static ExpressionFactory createExpressionFactory() throws IllegalStateException {
Class expressionFactoryClass;
try {
expressionFactoryClass = ClassUtils.forName(getDefaultExpressionFactoryClassName());
expressionFactoryClass = ClassUtils.forName(getDefaultExpressionFactoryClassName(),
DefaultExpressionFactoryUtils.class.getClassLoader());
} catch (ClassNotFoundException e) {
IllegalStateException ise = new IllegalStateException(
"The default ExpressionFactory class '"

View File

@@ -17,6 +17,8 @@ package org.springframework.binding.expression.ognl;
import ognl.Ognl;
import ognl.OgnlException;
import ognl.OgnlRuntime;
import ognl.PropertyAccessor;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.ParserContext;
@@ -29,6 +31,16 @@ import org.springframework.binding.expression.support.AbstractExpressionParser;
* @author Keith Donald
*/
public class OgnlExpressionParser extends AbstractExpressionParser {
/**
* Add a property access strategy for the given class.
* @param clazz the class that contains properties needing access
* @param propertyAccessor the property access strategy
*/
public void addPropertyAccessor(Class clazz, PropertyAccessor propertyAccessor) {
OgnlRuntime.setPropertyAccessor(clazz, propertyAccessor);
}
protected Expression doParseExpression(String expressionString, ParserContext context) throws ParserException {
try {
return new OgnlExpression(Ognl.parseExpression(expressionString), parseVariableExpressions(context

View File

@@ -39,7 +39,7 @@ public class MethodInvoker {
/**
* Conversion service for converting arguments to the necessary type if required.
*/
private ConversionService conversionService = DefaultConversionService.getSharedInstance();
private ConversionService conversionService = new DefaultConversionService();
/**
* A cache of invoked bean methods, keyed weakly.