simplified conversion service
mvc view postback
This commit is contained in:
@@ -38,32 +38,4 @@ public interface ConversionService {
|
||||
*/
|
||||
public ConversionExecutor getConversionExecutor(Class sourceClass, Class targetClass) throws ConversionException;
|
||||
|
||||
/**
|
||||
* Return a conversion executor command object capable of converting source objects of the specified
|
||||
* <code>sourceClass</code> to target objects of the type associated with the specified alias.
|
||||
* @param sourceClass the sourceClass
|
||||
* @param targetAlias the target alias
|
||||
* @return the conversion executor, or null if the alias cannot be found
|
||||
* @throws ConversionException an exception occured retrieving a converter for the source-to-target pair
|
||||
*/
|
||||
public ConversionExecutor getConversionExecutorByTargetAlias(Class sourceClass, String targetAlias)
|
||||
throws ConversionException;
|
||||
|
||||
/**
|
||||
* Return all conversion executors capable of converting source objects of the the specified
|
||||
* <code>sourceClass</code>.
|
||||
* @param sourceClass the source class to convert from
|
||||
* @return the matching conversion executors
|
||||
* @throws ConversionException an exception occured retrieving the converters
|
||||
*/
|
||||
public ConversionExecutor[] getConversionExecutorsForSource(Class sourceClass) throws ConversionException;
|
||||
|
||||
/**
|
||||
* Return the class with the specified alias.
|
||||
* @param alias the class alias
|
||||
* @return the class, or null if not aliased
|
||||
* @throws ConversionException when an error occurs looking up the class by alias
|
||||
*/
|
||||
public Class getClassByAlias(String alias) throws ConversionException;
|
||||
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004-2007 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.support;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.binding.convert.ConversionException;
|
||||
import org.springframework.binding.convert.ConversionExecutor;
|
||||
import org.springframework.binding.convert.ConversionService;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A conversion service that delegates to an ordered chain of other conversion services. The first correct reply
|
||||
* received from a conversion service in the chain is returned to the caller.
|
||||
*
|
||||
* @author Erwin Vervaet
|
||||
*/
|
||||
public class CompositeConversionService implements ConversionService {
|
||||
|
||||
private ConversionService[] chain;
|
||||
|
||||
/**
|
||||
* Create a new composite conversion service.
|
||||
* @param conversionServices the conversion services in the chain
|
||||
*/
|
||||
public CompositeConversionService(ConversionService[] conversionServices) {
|
||||
Assert.notNull(conversionServices, "The conversion services chain is required");
|
||||
this.chain = conversionServices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the conversion services in the chain managed by this composite conversion service.
|
||||
*/
|
||||
public ConversionService[] getConversionServices() {
|
||||
return chain;
|
||||
}
|
||||
|
||||
public ConversionExecutor getConversionExecutor(Class sourceClass, Class targetClass) throws ConversionException {
|
||||
for (int i = 0; i < chain.length; i++) {
|
||||
try {
|
||||
return chain[i].getConversionExecutor(sourceClass, targetClass);
|
||||
} catch (ConversionException e) {
|
||||
// ignore and try the next conversion service in the chain
|
||||
}
|
||||
}
|
||||
throw new ConversionException(sourceClass, targetClass, "No converter registered to convert from sourceClass '"
|
||||
+ sourceClass + "' to target class '" + targetClass + "'");
|
||||
}
|
||||
|
||||
public ConversionExecutor getConversionExecutorByTargetAlias(Class sourceClass, String targetAlias)
|
||||
throws ConversionException {
|
||||
boolean exceptionThrown = false;
|
||||
for (int i = 0; i < chain.length; i++) {
|
||||
try {
|
||||
ConversionExecutor res = chain[i].getConversionExecutorByTargetAlias(sourceClass, targetAlias);
|
||||
if (res != null) {
|
||||
return res;
|
||||
}
|
||||
} catch (ConversionException e) {
|
||||
exceptionThrown = true;
|
||||
}
|
||||
}
|
||||
if (exceptionThrown) {
|
||||
throw new ConversionException(sourceClass, "No converter registered to convert from sourceClass '"
|
||||
+ sourceClass + "' to aliased target type '" + targetAlias + "'");
|
||||
} else {
|
||||
// alias was not recognized by any conversion service in the chain
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public ConversionExecutor[] getConversionExecutorsForSource(Class sourceClass) throws ConversionException {
|
||||
Set executors = new HashSet();
|
||||
for (int i = 0; i < chain.length; i++) {
|
||||
executors.addAll(Arrays.asList(chain[i].getConversionExecutorsForSource(sourceClass)));
|
||||
}
|
||||
return (ConversionExecutor[]) executors.toArray(new ConversionExecutor[executors.size()]);
|
||||
}
|
||||
|
||||
public Class getClassByAlias(String alias) throws ConversionException {
|
||||
for (int i = 0; i < chain.length; i++) {
|
||||
try {
|
||||
Class res = chain[i].getClassByAlias(alias);
|
||||
if (res != null) {
|
||||
return res;
|
||||
}
|
||||
} catch (ConversionException e) {
|
||||
// ignore and try the next conversion service in the chain
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004-2007 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.support;
|
||||
|
||||
import org.springframework.binding.convert.ConversionService;
|
||||
|
||||
/**
|
||||
* Marker interface that denotes an object has a dependency on a conversion service that is expected to be fulfilled.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface ConversionServiceAware {
|
||||
|
||||
/**
|
||||
* Set the conversion service this object should be made aware of (as it presumably depends on it).
|
||||
*
|
||||
* @param conversionService the conversion service
|
||||
*/
|
||||
public void setConversionService(ConversionService conversionService);
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004-2007 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.support;
|
||||
|
||||
import org.springframework.binding.convert.ConversionService;
|
||||
import org.springframework.binding.convert.ConversionExecutor;
|
||||
import org.springframework.binding.expression.Expression;
|
||||
|
||||
/**
|
||||
* Base class for converters that use other converters to convert things, thus they are conversion-service aware.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public abstract class ConversionServiceAwareConverter extends AbstractConverter implements ConversionServiceAware {
|
||||
|
||||
/**
|
||||
* The conversion service this converter is aware of.
|
||||
*/
|
||||
private ConversionService conversionService;
|
||||
|
||||
/**
|
||||
* Default constructor, expects to conversion service to be injected using
|
||||
* {@link #setConversionService(ConversionService)}.
|
||||
*/
|
||||
protected ConversionServiceAwareConverter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a converter using given conversion service.
|
||||
*/
|
||||
protected ConversionServiceAwareConverter(ConversionService conversionService) {
|
||||
setConversionService(conversionService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the conversion service used.
|
||||
*/
|
||||
public ConversionService getConversionService() {
|
||||
if (conversionService == null) {
|
||||
throw new IllegalStateException("Conversion service not yet set: set it first before calling this method");
|
||||
}
|
||||
return conversionService;
|
||||
}
|
||||
|
||||
public void setConversionService(ConversionService conversionService) {
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a conversion executor capable of converting string objects to the specified target class.
|
||||
* @param targetClass the target class
|
||||
* @return the conversion executor, never null
|
||||
*/
|
||||
protected ConversionExecutor fromStringTo(Class targetClass) {
|
||||
return getConversionService().getConversionExecutor(String.class, targetClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a conversion executor capable of converting string objects to the target class aliased by the provided
|
||||
* alias.
|
||||
* @param targetAlias the target class alias, e.g "long" or "float"
|
||||
* @return the conversion executor, or <code>null</code> if no suitable converter exists for alias
|
||||
*/
|
||||
protected ConversionExecutor fromStringToAliased(String targetAlias) {
|
||||
return getConversionService().getConversionExecutorByTargetAlias(String.class, targetAlias);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a conversion executor capable of converting objects from one class to another.
|
||||
* @param sourceClass the source class to convert from
|
||||
* @param targetClass the target class to convert to
|
||||
* @return the conversion executor, never null
|
||||
*/
|
||||
protected ConversionExecutor converterFor(Class sourceClass, Class targetClass) {
|
||||
return getConversionService().getConversionExecutor(sourceClass, targetClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper that parsers the given expression string into an expression, using the installed String->Expression
|
||||
* converter.
|
||||
* @param expressionString the expression string to parse
|
||||
* @return the parsed, evaluatable expression
|
||||
*/
|
||||
protected Expression parseExpression(String expressionString) {
|
||||
return (Expression) fromStringTo(Expression.class).execute(expressionString);
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004-2005 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.support;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.PropertyEditorRegistrar;
|
||||
import org.springframework.beans.PropertyEditorRegistry;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.binding.convert.ConversionService;
|
||||
import org.springframework.binding.convert.ConversionExecutor;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Registers all 'from string' converters known to a conversion service with a Spring bean factory.
|
||||
* <p>
|
||||
* Acts as bean factory post processor, registering property editor adapters for each supported conversion with a
|
||||
* <code>java.lang.String sourceClass</code>. This makes for very convenient use with the Spring container.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class CustomConverterConfigurer implements BeanFactoryPostProcessor, InitializingBean {
|
||||
|
||||
private ConversionService conversionService;
|
||||
|
||||
/**
|
||||
* Set the conversion service.
|
||||
* @param conversionService the conversion service to take converters from
|
||||
*/
|
||||
public void setConversionService(ConversionService conversionService) {
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(conversionService, "The conversion service is required");
|
||||
}
|
||||
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
final ConversionExecutor[] executors = conversionService.getConversionExecutorsForSource(String.class);
|
||||
PropertyEditorRegistrar registrar = new PropertyEditorRegistrar() {
|
||||
public void registerCustomEditors(PropertyEditorRegistry registry) {
|
||||
for (int i = 0; i < executors.length; i++) {
|
||||
ConverterPropertyEditorAdapter editor = new ConverterPropertyEditorAdapter(executors[i]);
|
||||
registry.registerCustomEditor(editor.getTargetClass(), editor);
|
||||
}
|
||||
}
|
||||
};
|
||||
beanFactory.addPropertyEditorRegistrar(registrar);
|
||||
}
|
||||
}
|
||||
@@ -15,14 +15,10 @@
|
||||
*/
|
||||
package org.springframework.binding.convert.support;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.springframework.binding.format.FormatterRegistry;
|
||||
import org.springframework.binding.format.factories.DateFormatterFactory;
|
||||
import org.springframework.binding.format.factories.NumberFormatterFactory;
|
||||
import org.springframework.binding.format.impl.FormatterRegistryImpl;
|
||||
import org.springframework.core.enums.LabeledEnum;
|
||||
|
||||
/**
|
||||
* Default, local implementation of a conversion service. Will automatically register <i>from string</i> converters for
|
||||
@@ -54,19 +50,6 @@ public class DefaultConversionService extends GenericConversionService {
|
||||
addConverter(new TextToLabeledEnum());
|
||||
addConverter(new TextToNumber(formatterRegistry));
|
||||
addConverter(new TextToDate(formatterRegistry));
|
||||
addAlias("string", String.class);
|
||||
addAlias("short", Short.class);
|
||||
addAlias("integer", Integer.class);
|
||||
addAlias("int", Integer.class);
|
||||
addAlias("byte", Byte.class);
|
||||
addAlias("long", Long.class);
|
||||
addAlias("float", Float.class);
|
||||
addAlias("double", Double.class);
|
||||
addAlias("bigInteger", BigInteger.class);
|
||||
addAlias("bigDecimal", BigDecimal.class);
|
||||
addAlias("boolean", Boolean.class);
|
||||
addAlias("class", Class.class);
|
||||
addAlias("labeledEnum", LabeledEnum.class);
|
||||
}
|
||||
|
||||
protected FormatterRegistry createDefaultFormatterRegistry() {
|
||||
|
||||
@@ -15,22 +15,16 @@
|
||||
*/
|
||||
package org.springframework.binding.convert.support;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.binding.convert.ConversionException;
|
||||
import org.springframework.binding.convert.ConversionExecutor;
|
||||
import org.springframework.binding.convert.ConversionService;
|
||||
import org.springframework.binding.convert.Converter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Base implementation of a conversion service. Initially empty, e.g. no converters are registered by default.
|
||||
@@ -46,11 +40,6 @@ public class GenericConversionService implements ConversionService {
|
||||
*/
|
||||
private Map sourceClassConverters = new HashMap();
|
||||
|
||||
/**
|
||||
* A map of string aliases to convertible classes. Allows lookup of converters by alias.
|
||||
*/
|
||||
private Map aliasMap = new HashMap();
|
||||
|
||||
/**
|
||||
* An optional parent conversion service.
|
||||
*/
|
||||
@@ -71,8 +60,8 @@ public class GenericConversionService implements ConversionService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add given converter to this conversion service. If the converter is {@link ConversionServiceAware}, it will get
|
||||
* the conversion service injected.
|
||||
* Add given converter to this conversion service.
|
||||
* @param converter the converter
|
||||
*/
|
||||
public void addConverter(Converter converter) {
|
||||
Class[] sourceClasses = converter.getSourceClasses();
|
||||
@@ -89,44 +78,6 @@ public class GenericConversionService implements ConversionService {
|
||||
sourceMap.put(targetClass, converter);
|
||||
}
|
||||
}
|
||||
if (converter instanceof ConversionServiceAware) {
|
||||
((ConversionServiceAware) converter).setConversionService(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all given converters. If the converters are {@link ConversionServiceAware}, they will get the conversion
|
||||
* service injected.
|
||||
*/
|
||||
public void addConverters(Converter[] converters) {
|
||||
for (int i = 0; i < converters.length; i++) {
|
||||
addConverter(converters[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add given converter with an alias to the conversion service. If the converter is {@link ConversionServiceAware},
|
||||
* it will get the conversion service injected.
|
||||
*/
|
||||
public void addConverter(Converter converter, String alias) {
|
||||
aliasMap.put(alias, converter);
|
||||
addConverter(converter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an alias for given target type.
|
||||
*/
|
||||
public void addAlias(String alias, Class targetType) {
|
||||
Assert.isTrue(!targetType.isPrimitive(), "Primitive types cannot be registered");
|
||||
aliasMap.put(alias, targetType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a conventions based alias for given target type. For instance, "java.lang.Boolean" will get the
|
||||
* "boolean" alias.
|
||||
*/
|
||||
public void addDefaultAlias(Class targetType) {
|
||||
addAlias(StringUtils.uncapitalize(ClassUtils.getShortName(targetType)), targetType);
|
||||
}
|
||||
|
||||
public ConversionExecutor getConversionExecutor(Class sourceClass, Class targetClass) throws ConversionException {
|
||||
@@ -157,72 +108,6 @@ public class GenericConversionService implements ConversionService {
|
||||
}
|
||||
}
|
||||
|
||||
public ConversionExecutor getConversionExecutorByTargetAlias(Class sourceClass, String alias)
|
||||
throws IllegalArgumentException {
|
||||
Assert.notNull(sourceClass, "The source class to convert from is required");
|
||||
Assert.hasText(alias, "The target alias is required and must either be a type alias (e.g 'boolean') "
|
||||
+ "or a generic converter alias (e.g. 'bean') ");
|
||||
Object targetType = aliasMap.get(alias);
|
||||
if (targetType == null) {
|
||||
if (parent != null) {
|
||||
// try the parent
|
||||
return parent.getConversionExecutorByTargetAlias(sourceClass, alias);
|
||||
} else {
|
||||
// not aliased
|
||||
return null;
|
||||
}
|
||||
} else if (targetType instanceof Class) {
|
||||
return getConversionExecutor(sourceClass, (Class) targetType);
|
||||
} else {
|
||||
Assert.isInstanceOf(Converter.class, targetType, "Not a converter: ");
|
||||
Converter converter = (Converter) targetType;
|
||||
return new ConversionExecutorImpl(sourceClass, Object.class, converter);
|
||||
}
|
||||
}
|
||||
|
||||
public ConversionExecutor[] getConversionExecutorsForSource(Class sourceClass) {
|
||||
Assert.notNull(sourceClass, "The source class to convert from is required");
|
||||
Map sourceTargetConverters = findConvertersForSource(sourceClass);
|
||||
if (sourceTargetConverters.isEmpty()) {
|
||||
if (parent != null) {
|
||||
// use the parent
|
||||
return parent.getConversionExecutorsForSource(sourceClass);
|
||||
} else {
|
||||
// no converters for source class
|
||||
return new ConversionExecutor[0];
|
||||
}
|
||||
} else {
|
||||
Set executors = new HashSet();
|
||||
if (parent != null) {
|
||||
executors.addAll(Arrays.asList(parent.getConversionExecutorsForSource(sourceClass)));
|
||||
}
|
||||
Iterator it = sourceTargetConverters.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry) it.next();
|
||||
executors.add(new ConversionExecutorImpl(sourceClass, (Class) entry.getKey(), (Converter) entry
|
||||
.getValue()));
|
||||
}
|
||||
return (ConversionExecutor[]) executors.toArray(new ConversionExecutor[executors.size()]);
|
||||
}
|
||||
}
|
||||
|
||||
public Class getClassByAlias(String alias) {
|
||||
Assert.hasText(alias, "The alias is required and must be a type alias (e.g 'boolean')");
|
||||
Object clazz = aliasMap.get(alias);
|
||||
if (clazz != null) {
|
||||
Assert.isInstanceOf(Class.class, clazz, "Not a Class alias '" + alias + "': ");
|
||||
return (Class) clazz;
|
||||
} else {
|
||||
if (parent != null) {
|
||||
// try parent service
|
||||
return parent.getClassByAlias(alias);
|
||||
} else {
|
||||
// alias does not index a class, return null
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// subclassing support
|
||||
|
||||
/**
|
||||
@@ -235,11 +120,13 @@ public class GenericConversionService implements ConversionService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a map of known aliases. Each entry key is a String alias and the associated value is either a target
|
||||
* class or a converter.
|
||||
* Returns a registered converter object
|
||||
* @param sourceClass the source class
|
||||
* @param targetClass the target class
|
||||
*/
|
||||
protected Map getAliasMap() {
|
||||
return aliasMap;
|
||||
protected Converter getConverter(Class sourceClass, Class targetClass) {
|
||||
Map sourceTargetConverters = findConvertersForSource(sourceClass);
|
||||
return findTargetConverter(sourceTargetConverters, targetClass);
|
||||
}
|
||||
|
||||
// internal helpers
|
||||
|
||||
@@ -15,8 +15,13 @@
|
||||
*/
|
||||
package org.springframework.binding.convert.support;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.binding.convert.ConversionContext;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.core.enums.LabeledEnum;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -25,11 +30,20 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class TextToClass extends ConversionServiceAwareConverter {
|
||||
public class TextToClass extends AbstractConverter {
|
||||
|
||||
private static final String ALIAS_PREFIX = "type:";
|
||||
private Map aliasMap = new HashMap();
|
||||
|
||||
private static final String CLASS_PREFIX = "class:";
|
||||
public TextToClass() {
|
||||
addDefaultAliases();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an alias for given target type.
|
||||
*/
|
||||
public void addAlias(String alias, Class targetType) {
|
||||
aliasMap.put(alias, targetType);
|
||||
}
|
||||
|
||||
public Class[] getSourceClasses() {
|
||||
return new Class[] { String.class };
|
||||
@@ -42,27 +56,30 @@ public class TextToClass extends ConversionServiceAwareConverter {
|
||||
protected Object doConvert(Object source, Class targetClass, ConversionContext context) throws Exception {
|
||||
String text = (String) source;
|
||||
if (StringUtils.hasText(text)) {
|
||||
String classNameOrAlias = text.trim();
|
||||
if (classNameOrAlias.startsWith(CLASS_PREFIX)) {
|
||||
return ClassUtils.forName(text.substring(CLASS_PREFIX.length()));
|
||||
} else if (classNameOrAlias.startsWith(ALIAS_PREFIX)) {
|
||||
String alias = text.substring(ALIAS_PREFIX.length());
|
||||
Class clazz = getConversionService().getClassByAlias(alias);
|
||||
Assert.notNull(clazz, "No class found associated with type alias '" + alias + "'");
|
||||
return clazz;
|
||||
text = text.trim();
|
||||
if (aliasMap.containsKey(text)) {
|
||||
return aliasMap.get(text);
|
||||
} else {
|
||||
// try first an aliased based lookup
|
||||
if (getConversionService() != null) {
|
||||
Class aliasedClass = getConversionService().getClassByAlias(classNameOrAlias);
|
||||
if (aliasedClass != null) {
|
||||
return aliasedClass;
|
||||
}
|
||||
}
|
||||
// treat as a class name
|
||||
return ClassUtils.forName(classNameOrAlias);
|
||||
return ClassUtils.forName(text);
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void addDefaultAliases() {
|
||||
addAlias("string", String.class);
|
||||
addAlias("short", Short.class);
|
||||
addAlias("integer", Integer.class);
|
||||
addAlias("int", Integer.class);
|
||||
addAlias("byte", Byte.class);
|
||||
addAlias("long", Long.class);
|
||||
addAlias("float", Float.class);
|
||||
addAlias("double", Double.class);
|
||||
addAlias("bigInteger", BigInteger.class);
|
||||
addAlias("bigDecimal", BigDecimal.class);
|
||||
addAlias("boolean", Boolean.class);
|
||||
addAlias("class", Class.class);
|
||||
addAlias("labeledEnum", LabeledEnum.class);
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004-2007 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.support;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.binding.convert.ConversionException;
|
||||
import org.springframework.binding.convert.ConversionExecutor;
|
||||
import org.springframework.binding.convert.ConversionService;
|
||||
|
||||
/**
|
||||
* Test case for the {@link CompositeConversionService}.
|
||||
*
|
||||
* @author Erwin Vervaet
|
||||
*/
|
||||
public class CompositeConversionServiceTests extends TestCase {
|
||||
|
||||
private CompositeConversionService service;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
GenericConversionService first = new GenericConversionService();
|
||||
first.addConverter(new TextToClass());
|
||||
first.addConverter(new TextToBoolean("ja", "nee"));
|
||||
first.addDefaultAlias(Boolean.class);
|
||||
GenericConversionService second = new GenericConversionService();
|
||||
second.addConverter(new TextToBoolean());
|
||||
second.addDefaultAlias(Integer.class);
|
||||
service = new CompositeConversionService(new ConversionService[] { first, second });
|
||||
}
|
||||
|
||||
public void testGetConversionExecutor() {
|
||||
assertNotNull(service.getConversionExecutor(String.class, Class.class));
|
||||
assertNotNull(service.getConversionExecutor(String.class, Boolean.class));
|
||||
assertEquals(Boolean.TRUE, service.getConversionExecutor(String.class, Boolean.class).execute("ja"));
|
||||
try {
|
||||
service.getConversionExecutor(String.class, Date.class);
|
||||
fail();
|
||||
} catch (ConversionException e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
public void testGetConversionExecutorByTargetAlias() {
|
||||
assertNotNull(service.getConversionExecutorByTargetAlias(String.class, "boolean"));
|
||||
assertEquals(Boolean.TRUE, service.getConversionExecutorByTargetAlias(String.class, "boolean").execute("ja"));
|
||||
assertNull(service.getConversionExecutorByTargetAlias(String.class, "class"));
|
||||
}
|
||||
|
||||
public void testGetConversionExecutorsForSource() {
|
||||
assertEquals(new TextToClass().getTargetClasses().length + new TextToBoolean().getTargetClasses().length,
|
||||
service.getConversionExecutorsForSource(String.class).length);
|
||||
assertEquals(0, service.getConversionExecutorsForSource(Date.class).length);
|
||||
ConversionExecutor[] fromStringConversionExecutors = service.getConversionExecutorsForSource(String.class);
|
||||
ConversionExecutorImpl booleanConversionExecutor = null;
|
||||
for (int i = 0; i < fromStringConversionExecutors.length; i++) {
|
||||
if (((ConversionExecutorImpl) fromStringConversionExecutors[i]).getConverter() instanceof TextToBoolean) {
|
||||
booleanConversionExecutor = (ConversionExecutorImpl) fromStringConversionExecutors[i];
|
||||
}
|
||||
}
|
||||
assertEquals(Boolean.TRUE, booleanConversionExecutor.execute("ja"));
|
||||
}
|
||||
|
||||
public void testGetClassByAlias() {
|
||||
assertEquals(Boolean.class, service.getClassByAlias("boolean"));
|
||||
assertNull(service.getClassByAlias("class"));
|
||||
}
|
||||
}
|
||||
@@ -34,11 +34,9 @@ public class DefaultConversionServiceTests extends TestCase {
|
||||
|
||||
public void testConvertCompatibleTypes() {
|
||||
DefaultConversionService service = new DefaultConversionService();
|
||||
service.addAlias("list", List.class);
|
||||
|
||||
List lst = new ArrayList();
|
||||
assertSame(lst, service.getConversionExecutor(ArrayList.class, List.class).execute(lst));
|
||||
assertSame(lst, service.getConversionExecutorByTargetAlias(ArrayList.class, "list").execute(lst));
|
||||
|
||||
try {
|
||||
service.getConversionExecutor(List.class, ArrayList.class);
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
|
||||
<classpathentry kind="src" path="src/main/resources"/>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
|
||||
<classpathentry kind="src" path="src/test/resources"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/spring-binding"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/spring-webflow"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
|
||||
@@ -14,6 +14,7 @@ package org.springframework.faces.model.converter;
|
||||
|
||||
import org.springframework.binding.convert.ConversionService;
|
||||
import org.springframework.binding.convert.support.DefaultConversionService;
|
||||
import org.springframework.binding.convert.support.TextToClass;
|
||||
import org.springframework.faces.model.OneSelectionTrackingListDataModel;
|
||||
|
||||
/**
|
||||
@@ -25,13 +26,12 @@ import org.springframework.faces.model.OneSelectionTrackingListDataModel;
|
||||
public class FacesConversionService extends DefaultConversionService {
|
||||
|
||||
public FacesConversionService() {
|
||||
super();
|
||||
addFacesConverters();
|
||||
}
|
||||
|
||||
protected void addFacesConverters() {
|
||||
addConverter(new DataModelConverter());
|
||||
|
||||
addAlias("dataModel", OneSelectionTrackingListDataModel.class);
|
||||
TextToClass classConverter = (TextToClass) getConverter(String.class, Class.class);
|
||||
classConverter.addAlias("dataModel", OneSelectionTrackingListDataModel.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/resources"/>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/resources"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/spring-binding"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="var" path="IVY_CACHE/edu.oswego.cs/concurrent/concurrent-1.3.4.jar" sourcepath="IVY_CACHE/edu.oswego.cs/concurrent/concurrent-sources-1.3.4.jar"/>
|
||||
|
||||
@@ -177,7 +177,8 @@ class FlowExecutorFactoryBean implements FactoryBean, InitializingBean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the conversion service for converting string-encoded flow execution attributes to typed values.
|
||||
* TODO never called. Sets the conversion service for converting string-encoded flow execution attributes to typed
|
||||
* values.
|
||||
* @param conversionService the conversion service
|
||||
*/
|
||||
public void setConversionService(ConversionService conversionService) {
|
||||
@@ -351,11 +352,15 @@ class FlowExecutorFactoryBean implements FactoryBean, InitializingBean {
|
||||
|
||||
private Object getConvertedValue(FlowElementAttribute attribute) {
|
||||
if (attribute.needsTypeConversion()) {
|
||||
ConversionExecutor converter = conversionService.getConversionExecutorByTargetAlias(String.class, attribute
|
||||
.getType());
|
||||
Class targetType = fromStringToClass(attribute.getType());
|
||||
ConversionExecutor converter = conversionService.getConversionExecutor(String.class, targetType);
|
||||
return converter.execute(attribute.getValue());
|
||||
} else {
|
||||
return attribute.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
private Class fromStringToClass(String type) {
|
||||
return (Class) conversionService.getConversionExecutor(String.class, Class.class).execute(type);
|
||||
}
|
||||
}
|
||||
@@ -151,14 +151,20 @@ class FlowRegistryFactoryBean implements FactoryBean, InitializingBean {
|
||||
|
||||
private Object getConvertedValue(FlowElementAttribute attribute) {
|
||||
if (attribute.needsTypeConversion()) {
|
||||
ConversionExecutor converter = flowBuilderServices.getConversionService()
|
||||
.getConversionExecutorByTargetAlias(String.class, attribute.getType());
|
||||
Class targetType = fromStringToClass(attribute.getType());
|
||||
ConversionExecutor converter = flowBuilderServices.getConversionService().getConversionExecutor(
|
||||
String.class, targetType);
|
||||
return converter.execute(attribute.getValue());
|
||||
} else {
|
||||
return attribute.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
private Class fromStringToClass(String type) {
|
||||
return (Class) flowBuilderServices.getConversionService().getConversionExecutor(String.class, Class.class)
|
||||
.execute(type);
|
||||
}
|
||||
|
||||
private FlowDefinition buildFlowDefinition(FlowBuilderInfo builderInfo) {
|
||||
try {
|
||||
Class flowBuilderClass = ClassUtils.forName(builderInfo.getClassName());
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package org.springframework.webflow.mvc;
|
||||
|
||||
import org.springframework.binding.expression.Expression;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.io.ContextResource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.web.servlet.view.InternalResourceView;
|
||||
import org.springframework.web.servlet.view.JstlView;
|
||||
import org.springframework.webflow.execution.RequestContext;
|
||||
import org.springframework.webflow.execution.View;
|
||||
import org.springframework.webflow.execution.ViewFactory;
|
||||
|
||||
/**
|
||||
* View factory implementation that creates a Spring-MVC Internal Resource view to render a flow-relative view resource
|
||||
* such as a JSP or Velocity template.
|
||||
* @author Keith Donald
|
||||
*/
|
||||
class InternalFlowResourceMvcViewFactory implements ViewFactory {
|
||||
private static final boolean JSTL_PRESENT = ClassUtils.isPresent("javax.servlet.jsp.jstl.fmt.LocalizationContext");
|
||||
|
||||
private Expression viewIdExpression;
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
public InternalFlowResourceMvcViewFactory(Expression viewIdExpression, ApplicationContext context,
|
||||
ResourceLoader resourceLoader) {
|
||||
this.viewIdExpression = viewIdExpression;
|
||||
this.applicationContext = context;
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
public View getView(RequestContext context) {
|
||||
String viewId = (String) viewIdExpression.getValue(context);
|
||||
if (viewId.startsWith("/")) {
|
||||
return getViewInternal(viewId, context);
|
||||
} else {
|
||||
ContextResource viewResource = (ContextResource) resourceLoader.getResource(viewId);
|
||||
return getViewInternal(viewResource.getPathWithinContext(), context);
|
||||
}
|
||||
}
|
||||
|
||||
private View getViewInternal(String viewPath, RequestContext context) {
|
||||
if (viewPath.endsWith(".jsp")) {
|
||||
if (JSTL_PRESENT) {
|
||||
JstlView view = new JstlView(viewPath);
|
||||
view.setApplicationContext(applicationContext);
|
||||
return new MvcView(view, context);
|
||||
} else {
|
||||
InternalResourceView view = new InternalResourceView(viewPath);
|
||||
view.setApplicationContext(applicationContext);
|
||||
return new MvcView(view, context);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported view type " + viewPath + " only types supported are [.jsp]");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* Copyright 2004-2007 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.webflow.mvc;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.binding.collection.MapAdaptable;
|
||||
import org.springframework.binding.expression.Expression;
|
||||
import org.springframework.binding.expression.ExpressionParser;
|
||||
import org.springframework.binding.expression.support.ParserContextImpl;
|
||||
import org.springframework.binding.format.FormatterRegistry;
|
||||
import org.springframework.binding.format.factories.DateFormatterFactory;
|
||||
import org.springframework.binding.format.factories.NumberFormatterFactory;
|
||||
import org.springframework.binding.format.impl.FormatterRegistryImpl;
|
||||
import org.springframework.binding.mapping.MappingResult;
|
||||
import org.springframework.binding.mapping.MappingResults;
|
||||
import org.springframework.binding.mapping.MappingResultsCriteria;
|
||||
import org.springframework.binding.mapping.impl.DefaultMapper;
|
||||
import org.springframework.binding.mapping.impl.DefaultMapping;
|
||||
import org.springframework.binding.mapping.results.TargetAccessError;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.webflow.core.collection.ParameterMap;
|
||||
import org.springframework.webflow.engine.Transition;
|
||||
import org.springframework.webflow.engine.TransitionableState;
|
||||
import org.springframework.webflow.execution.Event;
|
||||
import org.springframework.webflow.execution.RequestContext;
|
||||
import org.springframework.webflow.execution.View;
|
||||
import org.springframework.webflow.expression.DefaultExpressionParserFactory;
|
||||
|
||||
class MvcView implements View {
|
||||
|
||||
private static final MappingResultsCriteria PROPERTY_NOT_FOUND_ERRORS = new PropertyNotFoundErrors();
|
||||
|
||||
private org.springframework.web.servlet.View view;
|
||||
|
||||
private RequestContext context;
|
||||
|
||||
private ExpressionParser expressionParser = DefaultExpressionParserFactory.getExpressionParser();
|
||||
|
||||
private FormatterRegistry formatterRegistry;
|
||||
|
||||
private MappingResults mappingResults;
|
||||
|
||||
private boolean postbackSuccess;
|
||||
|
||||
private String eventId;
|
||||
|
||||
public MvcView(org.springframework.web.servlet.View view, RequestContext context) {
|
||||
this.view = view;
|
||||
this.context = context;
|
||||
this.formatterRegistry = createDefaultFormatterRegistry();
|
||||
}
|
||||
|
||||
public void setExpressionParser(ExpressionParser expressionParser) {
|
||||
this.expressionParser = expressionParser;
|
||||
}
|
||||
|
||||
public void setFormatterRegistry(FormatterRegistry formatterRegistry) {
|
||||
this.formatterRegistry = formatterRegistry;
|
||||
}
|
||||
|
||||
public void render() throws IOException {
|
||||
Map model = new HashMap();
|
||||
model.putAll(flowScopes());
|
||||
exposeBindingModel(model);
|
||||
model.put("flowRequestContext", context);
|
||||
model.put("flowExecutionKey", context.getFlowExecutionContext().getKey().toString());
|
||||
model.put("flowExecutionUrl", context.getFlowExecutionUrl());
|
||||
model.put("currentUser", context.getExternalContext().getCurrentUser());
|
||||
try {
|
||||
view.render(model, (HttpServletRequest) context.getExternalContext().getNativeRequest(),
|
||||
(HttpServletResponse) context.getExternalContext().getNativeResponse());
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Unexpected exception occurred rendering view " + view, e);
|
||||
}
|
||||
}
|
||||
|
||||
public void postback() {
|
||||
determineEventId(context);
|
||||
Object model = getModelObject();
|
||||
if (model == null) {
|
||||
postbackSuccess = true;
|
||||
return;
|
||||
}
|
||||
if (shouldBind(model)) {
|
||||
mappingResults = bind(model);
|
||||
if (!mappingResults.hasErrorResults()) {
|
||||
postbackSuccess = true;
|
||||
} else {
|
||||
if (onlyPropertyNotFoundErrors()) {
|
||||
postbackSuccess = true;
|
||||
} else {
|
||||
postbackSuccess = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean onlyPropertyNotFoundErrors() {
|
||||
return mappingResults.getResults(PROPERTY_NOT_FOUND_ERRORS).size() == mappingResults.getErrorResults().size();
|
||||
}
|
||||
|
||||
public boolean eventSignaled() {
|
||||
return postbackSuccess && eventId != null;
|
||||
}
|
||||
|
||||
public Event getEvent() {
|
||||
return new Event(this, eventId, context.getRequestParameters().asAttributeMap());
|
||||
}
|
||||
|
||||
protected FormatterRegistry createDefaultFormatterRegistry() {
|
||||
FormatterRegistryImpl registry = new FormatterRegistryImpl();
|
||||
registry.registerFormatter(new NumberFormatterFactory());
|
||||
registry.registerFormatter(new DateFormatterFactory());
|
||||
return registry;
|
||||
}
|
||||
|
||||
private Map flowScopes() {
|
||||
return context.getConversationScope().union(context.getFlowScope()).union(context.getFlashScope()).union(
|
||||
context.getRequestScope()).asMap();
|
||||
}
|
||||
|
||||
private void exposeBindingModel(Map model) {
|
||||
Object modelObject = getModelObject();
|
||||
if (modelObject != null) {
|
||||
BindingModel bindingModel = new BindingModel(modelObject, expressionParser, formatterRegistry, context
|
||||
.getMessageContext());
|
||||
bindingModel.setMappingResults(mappingResults);
|
||||
model.put(BindingResult.MODEL_KEY_PREFIX + getModelExpression().getExpressionString(), model);
|
||||
}
|
||||
}
|
||||
|
||||
private Object getModelObject() {
|
||||
Expression model = getModelExpression();
|
||||
if (model != null) {
|
||||
return model.getValue(context);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Expression getModelExpression() {
|
||||
return (Expression) context.getCurrentState().getAttributes().get("model");
|
||||
}
|
||||
|
||||
private boolean shouldBind(Object model) {
|
||||
// this downcast is not ideal
|
||||
TransitionableState currentState = (TransitionableState) context.getCurrentState();
|
||||
// TODO this won't work because last event isn't set yet...
|
||||
Transition transition = currentState.getRequiredTransition(context);
|
||||
if (transition.getAttributes().contains("bind")) {
|
||||
return transition.getAttributes().getBoolean("bind").booleanValue();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private MappingResults bind(Object model) {
|
||||
DefaultMapper mapper = new DefaultMapper();
|
||||
addDefaultMappings(mapper, context.getRequestParameters(), model);
|
||||
return mapper.map(context.getRequestParameters(), model);
|
||||
}
|
||||
|
||||
private void addDefaultMappings(DefaultMapper mapper, ParameterMap requestParameters, Object model) {
|
||||
for (Iterator it = requestParameters.asMap().keySet().iterator(); it.hasNext();) {
|
||||
String name = (String) it.next();
|
||||
Expression source = expressionParser
|
||||
.parseExpression(name, new ParserContextImpl().eval(MapAdaptable.class));
|
||||
Expression target = expressionParser.parseExpression(name, new ParserContextImpl().eval(model.getClass()));
|
||||
mapper.addMapping(new DefaultMapping(source, target));
|
||||
}
|
||||
}
|
||||
|
||||
private void determineEventId(RequestContext context) {
|
||||
eventId = findParameter("_eventId", context.getRequestParameters());
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a named parameter from the request parameters. This method will try to obtain a parameter value using the
|
||||
* following algorithm:
|
||||
* <ol>
|
||||
* <li>Try to get the parameter value using just the given <i>logical</i> name. This handles parameters of the
|
||||
* form <tt>logicalName = value</tt>. For normal parameters, e.g. submitted using a hidden HTML form field, this
|
||||
* will return the requested value.</li>
|
||||
* <li>Try to obtain the parameter value from the parameter name, where the parameter name in the request is of the
|
||||
* form <tt>logicalName_value = xyz</tt> with "_" being the configured delimiter. This deals with parameter values
|
||||
* submitted using an HTML form submit button.</li>
|
||||
* <li>If the value obtained in the previous step has a ".x" or ".y" suffix, remove that. This handles cases where
|
||||
* the value was submitted using an HTML form image button. In this case the parameter in the request would actually
|
||||
* be of the form <tt>logicalName_value.x = 123</tt>. </li>
|
||||
* </ol>
|
||||
* @param logicalParameterName the <i>logical</i> name of the request parameter
|
||||
* @param parameters the available parameter map
|
||||
* @return the value of the parameter, or <code>null</code> if the parameter does not exist in given request
|
||||
*/
|
||||
private String findParameter(String logicalParameterName, ParameterMap parameters) {
|
||||
// first try to get it as a normal name=value parameter
|
||||
String value = parameters.get(logicalParameterName);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
// if no value yet, try to get it as a name_value=xyz parameter
|
||||
String prefix = logicalParameterName + "_";
|
||||
Iterator paramNames = parameters.asMap().keySet().iterator();
|
||||
while (paramNames.hasNext()) {
|
||||
String paramName = (String) paramNames.next();
|
||||
if (paramName.startsWith(prefix)) {
|
||||
String strValue = paramName.substring(prefix.length());
|
||||
// support images buttons, which would submit parameters as
|
||||
// name_value.x=123
|
||||
if (strValue.endsWith(".x") || strValue.endsWith(".y")) {
|
||||
strValue = strValue.substring(0, strValue.length() - 2);
|
||||
}
|
||||
return strValue;
|
||||
}
|
||||
}
|
||||
// we couldn't find the parameter value
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class PropertyNotFoundErrors implements MappingResultsCriteria {
|
||||
public boolean test(MappingResult result) {
|
||||
return result.getResult() instanceof TargetAccessError
|
||||
&& result.getResult().getErrorCode().equals("propertyNotFound");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,33 +15,15 @@
|
||||
*/
|
||||
package org.springframework.webflow.mvc;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.binding.expression.Expression;
|
||||
import org.springframework.binding.expression.ExpressionParser;
|
||||
import org.springframework.binding.format.FormatterRegistry;
|
||||
import org.springframework.binding.mapping.MappingResults;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.core.io.ContextResource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.servlet.ViewResolver;
|
||||
import org.springframework.web.servlet.view.InternalResourceView;
|
||||
import org.springframework.web.servlet.view.JstlView;
|
||||
import org.springframework.webflow.core.collection.ParameterMap;
|
||||
import org.springframework.webflow.engine.builder.ViewFactoryCreator;
|
||||
import org.springframework.webflow.execution.Event;
|
||||
import org.springframework.webflow.execution.RequestContext;
|
||||
import org.springframework.webflow.execution.View;
|
||||
import org.springframework.webflow.execution.ViewFactory;
|
||||
|
||||
/**
|
||||
@@ -58,12 +40,8 @@ import org.springframework.webflow.execution.ViewFactory;
|
||||
*/
|
||||
public class MvcViewFactoryCreator implements ViewFactoryCreator, ApplicationContextAware {
|
||||
|
||||
private static final boolean jstlPresent = ClassUtils.isPresent("javax.servlet.jsp.jstl.fmt.LocalizationContext");
|
||||
|
||||
// TODO
|
||||
private ExpressionParser expressionParser;
|
||||
|
||||
// TODO
|
||||
private FormatterRegistry formatterRegistry;
|
||||
|
||||
private List viewResolvers;
|
||||
@@ -96,193 +74,4 @@ public class MvcViewFactoryCreator implements ViewFactoryCreator, ApplicationCon
|
||||
return viewStateId + ".jsp";
|
||||
}
|
||||
|
||||
/**
|
||||
* View factory implementation that creates a Spring-MVC Internal Resource view to render a flow-relative view
|
||||
* resource such as a JSP or Velocity template.
|
||||
* @author Keith Donald
|
||||
*/
|
||||
static class InternalFlowResourceMvcViewFactory implements ViewFactory {
|
||||
private Expression viewIdExpression;
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
public InternalFlowResourceMvcViewFactory(Expression viewIdExpression, ApplicationContext context,
|
||||
ResourceLoader resourceLoader) {
|
||||
this.viewIdExpression = viewIdExpression;
|
||||
this.applicationContext = context;
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
public View getView(RequestContext context) {
|
||||
String viewId = (String) viewIdExpression.getValue(context);
|
||||
if (viewId.startsWith("/")) {
|
||||
return getViewInternal(viewId, context);
|
||||
} else {
|
||||
ContextResource viewResource = (ContextResource) resourceLoader.getResource(viewId);
|
||||
return getViewInternal(viewResource.getPathWithinContext(), context);
|
||||
}
|
||||
}
|
||||
|
||||
private View getViewInternal(String viewPath, RequestContext context) {
|
||||
if (viewPath.endsWith(".jsp")) {
|
||||
if (jstlPresent) {
|
||||
JstlView view = new JstlView(viewPath);
|
||||
view.setApplicationContext(applicationContext);
|
||||
return new MvcView(view, context);
|
||||
} else {
|
||||
InternalResourceView view = new InternalResourceView(viewPath);
|
||||
view.setApplicationContext(applicationContext);
|
||||
return new MvcView(view, context);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported view type " + viewPath
|
||||
+ " only types supported are [.jsp]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* View factory implementation that delegates to the Spring-configured view resolver chain to resolve the Spring MVC
|
||||
* view implementation to render.
|
||||
* @author Keith Donald
|
||||
*/
|
||||
private static class ViewResolvingMvcViewFactory implements ViewFactory {
|
||||
private Expression viewIdExpression;
|
||||
|
||||
private List viewResolvers;
|
||||
|
||||
public ViewResolvingMvcViewFactory(Expression viewIdExpression, List viewResolvers) {
|
||||
this.viewIdExpression = viewIdExpression;
|
||||
this.viewResolvers = viewResolvers;
|
||||
}
|
||||
|
||||
public View getView(RequestContext context) {
|
||||
String view = (String) viewIdExpression.getValue(context);
|
||||
return new MvcView(resolveView(view), context);
|
||||
}
|
||||
|
||||
protected org.springframework.web.servlet.View resolveView(String viewName) {
|
||||
for (Iterator it = viewResolvers.iterator(); it.hasNext();) {
|
||||
ViewResolver viewResolver = (ViewResolver) it.next();
|
||||
try {
|
||||
org.springframework.web.servlet.View view = viewResolver.resolveViewName(viewName,
|
||||
LocaleContextHolder.getLocale());
|
||||
if (view != null) {
|
||||
return view;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Exception resolving view with name '" + viewName + "'", e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MvcView implements View {
|
||||
|
||||
private RequestContext context;
|
||||
|
||||
private org.springframework.web.servlet.View view;
|
||||
|
||||
private String eventId;
|
||||
|
||||
public MvcView(org.springframework.web.servlet.View view, RequestContext context) {
|
||||
this.view = view;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public void render() {
|
||||
Map model = new HashMap();
|
||||
model.putAll(context.getConversationScope().union(context.getFlowScope()).union(context.getFlashScope())
|
||||
.union(context.getRequestScope()).asMap());
|
||||
exposeBindingModel(model);
|
||||
model.put("flowRequestContext", context);
|
||||
model.put("flowExecutionKey", context.getFlowExecutionContext().getKey().toString());
|
||||
model.put("flowExecutionUrl", context.getFlowExecutionUrl());
|
||||
model.put("currentUser", context.getExternalContext().getCurrentUser());
|
||||
try {
|
||||
view.render(model, (HttpServletRequest) context.getExternalContext().getNativeRequest(),
|
||||
(HttpServletResponse) context.getExternalContext().getNativeResponse());
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Exception rendering view", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void postback() {
|
||||
// TODO implement me with real data binding behavior
|
||||
}
|
||||
|
||||
public boolean eventSignaled() {
|
||||
determineEventId(context);
|
||||
return eventId != null;
|
||||
}
|
||||
|
||||
public Event getEvent() {
|
||||
return new Event(this, eventId, context.getRequestParameters().asAttributeMap());
|
||||
}
|
||||
|
||||
private void exposeBindingModel(Map model) {
|
||||
Expression boundObjectExpr = (Expression) context.getCurrentState().getAttributes().get("model");
|
||||
if (boundObjectExpr != null) {
|
||||
Object boundObject = boundObjectExpr.getValue(context);
|
||||
// TODO
|
||||
BindingModel bindingModel = new BindingModel(boundObject, null, null, context.getMessageContext());
|
||||
MappingResults bindResults = (MappingResults) context.getRequestScope().get(
|
||||
boundObjectExpr.getExpressionString() + "MappingResults");
|
||||
bindingModel.setMappingResults(bindResults);
|
||||
model.put(BindingResult.MODEL_KEY_PREFIX + boundObjectExpr.getExpressionString(), model);
|
||||
}
|
||||
}
|
||||
|
||||
private void determineEventId(RequestContext context) {
|
||||
eventId = findParameter("_eventId", context.getRequestParameters());
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a named parameter from the request parameters. This method will try to obtain a parameter value using
|
||||
* the following algorithm:
|
||||
* <ol>
|
||||
* <li>Try to get the parameter value using just the given <i>logical</i> name. This handles parameters of the
|
||||
* form <tt>logicalName = value</tt>. For normal parameters, e.g. submitted using a hidden HTML form field,
|
||||
* this will return the requested value.</li>
|
||||
* <li>Try to obtain the parameter value from the parameter name, where the parameter name in the request is of
|
||||
* the form <tt>logicalName_value = xyz</tt> with "_" being the configured delimiter. This deals with
|
||||
* parameter values submitted using an HTML form submit button.</li>
|
||||
* <li>If the value obtained in the previous step has a ".x" or ".y" suffix, remove that. This handles cases
|
||||
* where the value was submitted using an HTML form image button. In this case the parameter in the request
|
||||
* would actually be of the form <tt>logicalName_value.x = 123</tt>. </li>
|
||||
* </ol>
|
||||
* @param logicalParameterName the <i>logical</i> name of the request parameter
|
||||
* @param parameters the available parameter map
|
||||
* @return the value of the parameter, or <code>null</code> if the parameter does not exist in given request
|
||||
*/
|
||||
private String findParameter(String logicalParameterName, ParameterMap parameters) {
|
||||
// first try to get it as a normal name=value parameter
|
||||
String value = parameters.get(logicalParameterName);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
// if no value yet, try to get it as a name_value=xyz parameter
|
||||
String prefix = logicalParameterName + "_";
|
||||
Iterator paramNames = parameters.asMap().keySet().iterator();
|
||||
while (paramNames.hasNext()) {
|
||||
String paramName = (String) paramNames.next();
|
||||
if (paramName.startsWith(prefix)) {
|
||||
String strValue = paramName.substring(prefix.length());
|
||||
// support images buttons, which would submit parameters as
|
||||
// name_value.x=123
|
||||
if (strValue.endsWith(".x") || strValue.endsWith(".y")) {
|
||||
strValue = strValue.substring(0, strValue.length() - 2);
|
||||
}
|
||||
return strValue;
|
||||
}
|
||||
}
|
||||
// we couldn't find the parameter value
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package org.springframework.webflow.mvc;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.binding.expression.Expression;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.web.servlet.ViewResolver;
|
||||
import org.springframework.webflow.execution.RequestContext;
|
||||
import org.springframework.webflow.execution.View;
|
||||
import org.springframework.webflow.execution.ViewFactory;
|
||||
|
||||
/**
|
||||
* View factory implementation that delegates to the Spring-configured view resolver chain to resolve the Spring MVC
|
||||
* view implementation to render.
|
||||
* @author Keith Donald
|
||||
*/
|
||||
class ViewResolvingMvcViewFactory implements ViewFactory {
|
||||
private Expression viewIdExpression;
|
||||
|
||||
private List viewResolvers;
|
||||
|
||||
public ViewResolvingMvcViewFactory(Expression viewIdExpression, List viewResolvers) {
|
||||
this.viewIdExpression = viewIdExpression;
|
||||
this.viewResolvers = viewResolvers;
|
||||
}
|
||||
|
||||
public View getView(RequestContext context) {
|
||||
String view = (String) viewIdExpression.getValue(context);
|
||||
return new MvcView(resolveView(view), context);
|
||||
}
|
||||
|
||||
protected org.springframework.web.servlet.View resolveView(String viewName) {
|
||||
for (Iterator it = viewResolvers.iterator(); it.hasNext();) {
|
||||
ViewResolver viewResolver = (ViewResolver) it.next();
|
||||
try {
|
||||
org.springframework.web.servlet.View view = viewResolver.resolveViewName(viewName,
|
||||
LocaleContextHolder.getLocale());
|
||||
if (view != null) {
|
||||
return view;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Exception resolving view with name '" + viewName + "'", e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user