diff --git a/core/src/main/java/org/apache/struts2/StrutsConstants.java b/core/src/main/java/org/apache/struts2/StrutsConstants.java
index b2b7c57c8..d205a15b7 100644
--- a/core/src/main/java/org/apache/struts2/StrutsConstants.java
+++ b/core/src/main/java/org/apache/struts2/StrutsConstants.java
@@ -246,4 +246,10 @@ public final class StrutsConstants {
/** Enable handling exceptions by Dispatcher - true by default **/
public static final String STRUTS_HANDLE_EXCEPTION = "struts.handle.exception";
+ public static final String STRUTS_CONVERTER_PROPERTIES_PROCESSOR = "struts.converter.properties.processor";
+ public static final String STRUTS_CONVERTER_FILE_PROCESSOR = "struts.converter.file.processor";
+ public static final String STRUTS_CONVERTER_ANNOTATION_PROCESSOR = "struts.converter.annotation.processor";
+ public static final String STRUTS_CONVERTER_CREATOR = "struts.converter.creator";
+ public static final String STRUTS_CONVERTER_HOLDER = "struts..converter.holder";
+
}
diff --git a/core/src/main/java/org/apache/struts2/config/BeanSelectionProvider.java b/core/src/main/java/org/apache/struts2/config/BeanSelectionProvider.java
index 434688dd6..ddd1c5e0d 100644
--- a/core/src/main/java/org/apache/struts2/config/BeanSelectionProvider.java
+++ b/core/src/main/java/org/apache/struts2/config/BeanSelectionProvider.java
@@ -32,7 +32,12 @@ import com.opensymphony.xwork2.XWorkConstants;
import com.opensymphony.xwork2.config.Configuration;
import com.opensymphony.xwork2.config.ConfigurationException;
import com.opensymphony.xwork2.config.ConfigurationProvider;
+import com.opensymphony.xwork2.conversion.ConversionAnnotationProcessor;
+import com.opensymphony.xwork2.conversion.ConversionFileProcessor;
+import com.opensymphony.xwork2.conversion.ConversionPropertiesProcessor;
import com.opensymphony.xwork2.conversion.ObjectTypeDeterminer;
+import com.opensymphony.xwork2.conversion.TypeConverterCreator;
+import com.opensymphony.xwork2.conversion.TypeConverterHolder;
import com.opensymphony.xwork2.conversion.impl.ArrayConverter;
import com.opensymphony.xwork2.conversion.impl.CollectionConverter;
import com.opensymphony.xwork2.conversion.impl.DateConverter;
@@ -241,6 +246,36 @@ import java.util.StringTokenizer;
*
singleton |
* Converter used to convert any object to String and back |
*
+ *
+ * | com.opensymphony.xwork2.conversion.ConversionPropertiesProcessor |
+ * struts.conversion.properties.processor |
+ * singleton |
+ * Process Properties to create converters |
+ *
+ *
+ * | com.opensymphony.xwork2.conversion.ConversionPropertiesProcessor |
+ * struts.converter.file.processor |
+ * singleton |
+ * Process -conversion.properties file create converters |
+ *
+ *
+ * | com.opensymphony.xwork2.conversion.ConversionAnnotationProcessor |
+ * struts.converter.annotation.processor |
+ * singleton |
+ * Process TypeConversion annotation to create converters |
+ *
+ *
+ * | com.opensymphony.xwork2.conversion.TypeConverterCreator |
+ * struts.converter.creator |
+ * singleton |
+ * Creates user converters |
+ *
+ *
+ * | com.opensymphony.xwork2.conversion.TypeConverterHolder |
+ * struts.converter.holder |
+ * singleton |
+ * Holds user converters' instances |
+ *
*
*
*
@@ -287,8 +322,22 @@ public class BeanSelectionProvider implements ConfigurationProvider {
public void register(ContainerBuilder builder, LocatableProperties props) {
alias(ObjectFactory.class, StrutsConstants.STRUTS_OBJECTFACTORY, builder, props);
alias(FileManagerFactory.class, StrutsConstants.STRUTS_FILE_MANAGER_FACTORY, builder, props, Scope.SINGLETON);
+
alias(XWorkConverter.class, StrutsConstants.STRUTS_XWORKCONVERTER, builder, props);
+ alias(CollectionConverter.class, StrutsConstants.STRUTS_CONVERTER_COLLECTION, builder, props);
+ alias(ArrayConverter.class, StrutsConstants.STRUTS_CONVERTER_ARRAY, builder, props);
+ alias(DateConverter.class, StrutsConstants.STRUTS_CONVERTER_DATE, builder, props);
+ alias(NumberConverter.class, StrutsConstants.STRUTS_CONVERTER_NUMBER, builder, props);
+ alias(StringConverter.class, StrutsConstants.STRUTS_CONVERTER_STRING, builder, props);
+
+ alias(ConversionPropertiesProcessor.class, StrutsConstants.STRUTS_CONVERTER_PROPERTIES_PROCESSOR, builder, props);
+ alias(ConversionFileProcessor.class, StrutsConstants.STRUTS_CONVERTER_FILE_PROCESSOR, builder, props);
+ alias(ConversionAnnotationProcessor.class, StrutsConstants.STRUTS_CONVERTER_ANNOTATION_PROCESSOR, builder, props);
+ alias(TypeConverterCreator.class, StrutsConstants.STRUTS_CONVERTER_CREATOR, builder, props);
+ alias(TypeConverterHolder.class, StrutsConstants.STRUTS_CONVERTER_HOLDER, builder, props);
+
alias(TextProvider.class, StrutsConstants.STRUTS_XWORKTEXTPROVIDER, builder, props, Scope.DEFAULT);
+
alias(LocaleProvider.class, StrutsConstants.STRUTS_LOCALE_PROVIDER, builder, props);
alias(ActionProxyFactory.class, StrutsConstants.STRUTS_ACTIONPROXYFACTORY, builder, props);
alias(ObjectTypeDeterminer.class, StrutsConstants.STRUTS_OBJECTTYPEDETERMINER, builder, props);
@@ -306,12 +355,6 @@ public class BeanSelectionProvider implements ConfigurationProvider {
alias(UnknownHandlerManager.class, StrutsConstants.STRUTS_UNKNOWN_HANDLER_MANAGER, builder, props);
alias(UrlHelper.class, StrutsConstants.STRUTS_URL_HELPER, builder, props);
- alias(CollectionConverter.class, StrutsConstants.STRUTS_CONVERTER_COLLECTION, builder, props);
- alias(ArrayConverter.class, StrutsConstants.STRUTS_CONVERTER_ARRAY, builder, props);
- alias(DateConverter.class, StrutsConstants.STRUTS_CONVERTER_DATE, builder, props);
- alias(NumberConverter.class, StrutsConstants.STRUTS_CONVERTER_NUMBER, builder, props);
- alias(StringConverter.class, StrutsConstants.STRUTS_CONVERTER_STRING, builder, props);
-
if ("true".equalsIgnoreCase(props.getProperty(StrutsConstants.STRUTS_DEVMODE))) {
props.setProperty(StrutsConstants.STRUTS_I18N_RELOAD, "true");
props.setProperty(StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD, "true");
diff --git a/core/src/main/resources/struts-default.xml b/core/src/main/resources/struts-default.xml
index 0b6ff544e..8a9691896 100644
--- a/core/src/main/resources/struts-default.xml
+++ b/core/src/main/resources/struts-default.xml
@@ -65,6 +65,12 @@
+
+
+
+
+
+
diff --git a/xwork-core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java b/xwork-core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java
index f72a7ece3..911c5a331 100644
--- a/xwork-core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java
+++ b/xwork-core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java
@@ -37,12 +37,22 @@ import com.opensymphony.xwork2.config.entities.ResultConfig;
import com.opensymphony.xwork2.config.entities.ResultTypeConfig;
import com.opensymphony.xwork2.config.entities.UnknownHandlerConfig;
import com.opensymphony.xwork2.config.providers.InterceptorBuilder;
+import com.opensymphony.xwork2.conversion.ConversionAnnotationProcessor;
+import com.opensymphony.xwork2.conversion.ConversionFileProcessor;
+import com.opensymphony.xwork2.conversion.ConversionPropertiesProcessor;
import com.opensymphony.xwork2.conversion.ObjectTypeDeterminer;
import com.opensymphony.xwork2.conversion.TypeConverter;
+import com.opensymphony.xwork2.conversion.TypeConverterCreator;
+import com.opensymphony.xwork2.conversion.TypeConverterHolder;
import com.opensymphony.xwork2.conversion.impl.ArrayConverter;
import com.opensymphony.xwork2.conversion.impl.CollectionConverter;
import com.opensymphony.xwork2.conversion.impl.DateConverter;
+import com.opensymphony.xwork2.conversion.impl.DefaultConversionAnnotationProcessor;
+import com.opensymphony.xwork2.conversion.impl.DefaultConversionFileProcessor;
+import com.opensymphony.xwork2.conversion.impl.DefaultConversionPropertiesProcessor;
import com.opensymphony.xwork2.conversion.impl.DefaultObjectTypeDeterminer;
+import com.opensymphony.xwork2.conversion.impl.DefaultTypeConverterCreator;
+import com.opensymphony.xwork2.conversion.impl.DefaultTypeConverterHolder;
import com.opensymphony.xwork2.conversion.impl.NumberConverter;
import com.opensymphony.xwork2.conversion.impl.StringConverter;
import com.opensymphony.xwork2.conversion.impl.XWorkBasicConverter;
@@ -289,7 +299,14 @@ public class DefaultConfiguration implements Configuration {
}
builder.factory(ReflectionProvider.class, OgnlReflectionProvider.class, Scope.SINGLETON);
builder.factory(ValueStackFactory.class, OgnlValueStackFactory.class, Scope.SINGLETON);
+
builder.factory(XWorkConverter.class, Scope.SINGLETON);
+ builder.factory(ConversionPropertiesProcessor.class, DefaultConversionPropertiesProcessor.class, Scope.SINGLETON);
+ builder.factory(ConversionFileProcessor.class, DefaultConversionFileProcessor.class, Scope.SINGLETON);
+ builder.factory(ConversionAnnotationProcessor.class, DefaultConversionAnnotationProcessor.class, Scope.SINGLETON);
+ builder.factory(TypeConverterCreator.class, DefaultTypeConverterCreator.class, Scope.SINGLETON);
+ builder.factory(TypeConverterHolder.class, DefaultTypeConverterHolder.class, Scope.SINGLETON);
+
builder.factory(XWorkBasicConverter.class, Scope.SINGLETON);
builder.factory(TypeConverter.class, XWorkConstants.COLLECTION_CONVERTER, CollectionConverter.class, Scope.SINGLETON);
builder.factory(TypeConverter.class, XWorkConstants.ARRAY_CONVERTER, ArrayConverter.class, Scope.SINGLETON);
diff --git a/xwork-core/src/main/java/com/opensymphony/xwork2/config/providers/XWorkConfigurationProvider.java b/xwork-core/src/main/java/com/opensymphony/xwork2/config/providers/XWorkConfigurationProvider.java
index 49473423e..ca8074099 100644
--- a/xwork-core/src/main/java/com/opensymphony/xwork2/config/providers/XWorkConfigurationProvider.java
+++ b/xwork-core/src/main/java/com/opensymphony/xwork2/config/providers/XWorkConfigurationProvider.java
@@ -15,12 +15,22 @@ import com.opensymphony.xwork2.XWorkConstants;
import com.opensymphony.xwork2.config.Configuration;
import com.opensymphony.xwork2.config.ConfigurationException;
import com.opensymphony.xwork2.config.ConfigurationProvider;
+import com.opensymphony.xwork2.conversion.ConversionAnnotationProcessor;
+import com.opensymphony.xwork2.conversion.ConversionFileProcessor;
+import com.opensymphony.xwork2.conversion.ConversionPropertiesProcessor;
import com.opensymphony.xwork2.conversion.NullHandler;
import com.opensymphony.xwork2.conversion.ObjectTypeDeterminer;
+import com.opensymphony.xwork2.conversion.TypeConverterCreator;
+import com.opensymphony.xwork2.conversion.TypeConverterHolder;
import com.opensymphony.xwork2.conversion.impl.ArrayConverter;
import com.opensymphony.xwork2.conversion.impl.CollectionConverter;
import com.opensymphony.xwork2.conversion.impl.DateConverter;
+import com.opensymphony.xwork2.conversion.impl.DefaultConversionAnnotationProcessor;
+import com.opensymphony.xwork2.conversion.impl.DefaultConversionFileProcessor;
+import com.opensymphony.xwork2.conversion.impl.DefaultConversionPropertiesProcessor;
import com.opensymphony.xwork2.conversion.impl.DefaultObjectTypeDeterminer;
+import com.opensymphony.xwork2.conversion.impl.DefaultTypeConverterCreator;
+import com.opensymphony.xwork2.conversion.impl.DefaultTypeConverterHolder;
import com.opensymphony.xwork2.conversion.impl.InstantiatingNullHandler;
import com.opensymphony.xwork2.conversion.impl.NumberConverter;
import com.opensymphony.xwork2.conversion.impl.StringConverter;
@@ -92,7 +102,15 @@ public class XWorkConfigurationProvider implements ConfigurationProvider {
builder.factory(com.opensymphony.xwork2.ObjectFactory.class)
.factory(ActionProxyFactory.class, DefaultActionProxyFactory.class, Scope.SINGLETON)
.factory(ObjectTypeDeterminer.class, DefaultObjectTypeDeterminer.class, Scope.SINGLETON)
+
.factory(XWorkConverter.class, Scope.SINGLETON)
+ .factory(XWorkBasicConverter.class, Scope.SINGLETON)
+ .factory(ConversionPropertiesProcessor.class, DefaultConversionPropertiesProcessor.class, Scope.SINGLETON)
+ .factory(ConversionFileProcessor.class, DefaultConversionFileProcessor.class, Scope.SINGLETON)
+ .factory(ConversionAnnotationProcessor.class, DefaultConversionAnnotationProcessor.class, Scope.SINGLETON)
+ .factory(TypeConverterCreator.class, DefaultTypeConverterCreator.class, Scope.SINGLETON)
+ .factory(TypeConverterHolder.class, DefaultTypeConverterHolder.class, Scope.SINGLETON)
+
.factory(FileManager.class, "system", DefaultFileManager.class, Scope.SINGLETON)
.factory(FileManagerFactory.class, DefaultFileManagerFactory.class, Scope.SINGLETON)
.factory(ValueStackFactory.class, OgnlValueStackFactory.class, Scope.SINGLETON)
@@ -107,18 +125,18 @@ public class XWorkConfigurationProvider implements ConfigurationProvider {
.factory(PropertyAccessor.class, Enumeration.class.getName(), XWorkEnumerationAccessor.class, Scope.SINGLETON)
.factory(UnknownHandlerManager.class, DefaultUnknownHandlerManager.class, Scope.SINGLETON)
- // silly workarounds for ognl since there is no way to flush its caches
+ // silly workarounds for ognl since there is no way to flush its caches
.factory(PropertyAccessor.class, List.class.getName(), XWorkListPropertyAccessor.class, Scope.SINGLETON)
.factory(PropertyAccessor.class, ArrayList.class.getName(), XWorkListPropertyAccessor.class, Scope.SINGLETON)
.factory(PropertyAccessor.class, HashSet.class.getName(), XWorkCollectionPropertyAccessor.class, Scope.SINGLETON)
.factory(PropertyAccessor.class, Set.class.getName(), XWorkCollectionPropertyAccessor.class, Scope.SINGLETON)
.factory(PropertyAccessor.class, HashMap.class.getName(), XWorkMapPropertyAccessor.class, Scope.SINGLETON)
.factory(PropertyAccessor.class, Map.class.getName(), XWorkMapPropertyAccessor.class, Scope.SINGLETON)
-
.factory(PropertyAccessor.class, Collection.class.getName(), XWorkCollectionPropertyAccessor.class, Scope.SINGLETON)
.factory(PropertyAccessor.class, ObjectProxy.class.getName(), ObjectProxyPropertyAccessor.class, Scope.SINGLETON)
.factory(MethodAccessor.class, Object.class.getName(), XWorkMethodAccessor.class, Scope.SINGLETON)
.factory(MethodAccessor.class, CompoundRoot.class.getName(), CompoundRootAccessor.class, Scope.SINGLETON)
+
.factory(NullHandler.class, Object.class.getName(), InstantiatingNullHandler.class, Scope.SINGLETON)
.factory(ActionValidatorManager.class, AnnotationActionValidatorManager.class, Scope.SINGLETON)
.factory(ActionValidatorManager.class, "no-annotations", DefaultActionValidatorManager.class, Scope.SINGLETON)
@@ -126,7 +144,6 @@ public class XWorkConfigurationProvider implements ConfigurationProvider {
.factory(TextProvider.class, TextProviderSupport.class, Scope.SINGLETON)
.factory(LocaleProvider.class, DefaultLocaleProvider.class, Scope.SINGLETON)
.factory(OgnlUtil.class, Scope.SINGLETON)
- .factory(XWorkBasicConverter.class, Scope.SINGLETON)
.factory(CollectionConverter.class, Scope.SINGLETON)
.factory(ArrayConverter.class, Scope.SINGLETON)
.factory(DateConverter.class, Scope.SINGLETON)
diff --git a/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/ConversionAnnotationProcessor.java b/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/ConversionAnnotationProcessor.java
new file mode 100644
index 000000000..159f8d524
--- /dev/null
+++ b/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/ConversionAnnotationProcessor.java
@@ -0,0 +1,23 @@
+package com.opensymphony.xwork2.conversion;
+
+import com.opensymphony.xwork2.conversion.annotations.TypeConversion;
+
+import java.util.Map;
+
+/**
+ * Used to process {@link com.opensymphony.xwork2.conversion.annotations.TypeConversion}
+ * annotation to read defined Converters
+ */
+public interface ConversionAnnotationProcessor {
+
+ /**
+ * Process annotation and build {@link TypeConverter} base on provided annotation
+ * and assigning it under given key
+ *
+ * @param mapping keeps converters per given key
+ * @param tc annotation which keeps information about converter
+ * @param key key under which converter should be registered
+ */
+ void process(Map mapping, TypeConversion tc, String key);
+
+}
diff --git a/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/ConversionFileProcessor.java b/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/ConversionFileProcessor.java
new file mode 100644
index 000000000..8d2803ff5
--- /dev/null
+++ b/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/ConversionFileProcessor.java
@@ -0,0 +1,19 @@
+package com.opensymphony.xwork2.conversion;
+
+import java.util.Map;
+
+/**
+ * Used to process -conversion.properties file to read defined Converters
+ */
+public interface ConversionFileProcessor {
+
+ /**
+ * Process conversion file to create mapping for key (property, type) and corresponding converter
+ *
+ * @param mapping keeps converters per given key
+ * @param clazz class which should be converted by the converter
+ * @param converterFilename to read converters from
+ */
+ void process(Map mapping, Class clazz, String converterFilename);
+
+}
diff --git a/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/ConversionPropertiesProcessor.java b/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/ConversionPropertiesProcessor.java
new file mode 100644
index 000000000..8d0bab841
--- /dev/null
+++ b/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/ConversionPropertiesProcessor.java
@@ -0,0 +1,22 @@
+package com.opensymphony.xwork2.conversion;
+
+/**
+ * Used to read converters from Properties file
+ */
+public interface ConversionPropertiesProcessor {
+
+ /**
+ * Process given property to load converters as not required (Properties file doesn't have to exist)
+ *
+ * @param propsName Properties file name
+ */
+ void process(String propsName);
+
+ /**
+ * Process given property to load converters as required (Properties file must exist)
+ *
+ * @param propsName Properties file name
+ */
+ void processRequired(String propsName);
+
+}
diff --git a/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/TypeConverterCreator.java b/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/TypeConverterCreator.java
new file mode 100644
index 000000000..738bbe82f
--- /dev/null
+++ b/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/TypeConverterCreator.java
@@ -0,0 +1,17 @@
+package com.opensymphony.xwork2.conversion;
+
+/**
+ * Instantiate converter classes, if cannot create TypeConverter throws exception
+ */
+public interface TypeConverterCreator {
+
+ /**
+ * Creates {@link TypeConverter} from given class
+ *
+ * @param className convert class
+ * @return instance of {@link TypeConverter}
+ * @throws Exception when cannot create/cast to {@link TypeConverter}
+ */
+ TypeConverter createTypeConverter(String className) throws Exception;
+
+}
diff --git a/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/TypeConverterHolder.java b/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/TypeConverterHolder.java
new file mode 100644
index 000000000..6a67b8bf9
--- /dev/null
+++ b/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/TypeConverterHolder.java
@@ -0,0 +1,82 @@
+package com.opensymphony.xwork2.conversion;
+
+import java.util.Map;
+
+/**
+ * Holds all mappings related to {@link TypeConverter}s
+ */
+public interface TypeConverterHolder {
+
+ /**
+ * Adds mapping for default type converters - application scoped
+ *
+ * @param className name of the class with associated converter
+ * @param typeConverter {@link TypeConverter} instance for associated class
+ */
+ void addDefaultMapping(String className, TypeConverter typeConverter);
+
+ /**
+ * Checks if converter was already defined for given class
+ *
+ * @param className name of the class to check for
+ * @return true if default mapping was already specified
+ */
+ boolean containsDefaultMapping(String className);
+
+ /**
+ * Returns instance of {@link TypeConverter} associated with given class
+ *
+ * @param className name of the class to return converter for
+ * @return instance of {@link TypeConverter} to be used to convert class
+ */
+ TypeConverter getDefaultMapping(String className);
+
+ /**
+ * Target class conversion Mappings.
+ *
+ * @param clazz class to convert to/from
+ * @return {@link TypeConverter} for given class
+ */
+ Map getMapping(Class clazz);
+
+ /**
+ * Assign mapping of converters for given class
+ *
+ * @param clazz class to convert to/from
+ * @param mapping property converters
+ */
+ void addMapping(Class clazz, Map mapping);
+
+ /**
+ * Check if there is no mapping for given class to convert
+ *
+ * @param clazz class to convert to/from
+ * @return true if mapping couldn't be found
+ */
+ boolean containsNoMapping(Class clazz);
+
+ /**
+ * Adds no mapping flag for give class
+ *
+ * @param clazz class to register missing converter
+ */
+ void addNoMapping(Class clazz);
+
+ /**
+ * Checks if no mapping was defined for given class name
+ * FIXME lukaszlenart: maybe it should be merged with NoMapping
+ *
+ * @param className name of the class to check for
+ * @return true if converter was defined for given class name
+ */
+ boolean containsUnknownMapping(String className);
+
+ /**
+ * Adds no converter flag for given class name
+ * FIXME lukaszlenart: maybe it should be merged with NoMapping
+ *
+ * @param className name of the class to mark there is no converter for it
+ */
+ void addUnknownMapping(String className);
+
+}
diff --git a/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/DefaultConversionAnnotationProcessor.java b/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/DefaultConversionAnnotationProcessor.java
new file mode 100644
index 000000000..0f1008514
--- /dev/null
+++ b/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/DefaultConversionAnnotationProcessor.java
@@ -0,0 +1,84 @@
+package com.opensymphony.xwork2.conversion.impl;
+
+import com.opensymphony.xwork2.conversion.ConversionAnnotationProcessor;
+import com.opensymphony.xwork2.conversion.TypeConverter;
+import com.opensymphony.xwork2.conversion.TypeConverterCreator;
+import com.opensymphony.xwork2.conversion.TypeConverterHolder;
+import com.opensymphony.xwork2.conversion.annotations.ConversionRule;
+import com.opensymphony.xwork2.conversion.annotations.ConversionType;
+import com.opensymphony.xwork2.conversion.annotations.TypeConversion;
+import com.opensymphony.xwork2.inject.Inject;
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.xwork2.util.logging.LoggerFactory;
+
+import java.util.Map;
+
+/**
+ * Default implementation of {@link ConversionAnnotationProcessor}
+ */
+public class DefaultConversionAnnotationProcessor implements ConversionAnnotationProcessor {
+
+ private static final Logger LOG = LoggerFactory.getLogger(DefaultConversionAnnotationProcessor.class);
+
+ private TypeConverterCreator converterCreator;
+ private TypeConverterHolder converterHolder;
+
+ @Inject
+ public void setTypeConverterCreator(TypeConverterCreator converterCreator) {
+ this.converterCreator = converterCreator;
+ }
+
+ @Inject
+ public void setTypeConverterHolder(TypeConverterHolder converterHolder) {
+ this.converterHolder = converterHolder;
+ }
+
+ public void process(Map mapping, TypeConversion tc, String key) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("TypeConversion [#0] with key: [#1]", tc.converter(), key);
+ }
+ if (key == null) {
+ return;
+ }
+ try {
+ if (tc.type() == ConversionType.APPLICATION) {
+ converterHolder.addDefaultMapping(key, converterCreator.createTypeConverter(tc.converter()));
+ } else {
+ if (tc.rule() == ConversionRule.KEY_PROPERTY || tc.rule() == ConversionRule.CREATE_IF_NULL) {
+ mapping.put(key, tc.value());
+ }
+ //for properties of classes
+ else if (tc.rule() != ConversionRule.ELEMENT || tc.rule() == ConversionRule.KEY || tc.rule() == ConversionRule.COLLECTION) {
+ mapping.put(key, converterCreator.createTypeConverter(tc.converter()));
+ }
+ //for keys of Maps
+ else if (tc.rule() == ConversionRule.KEY) {
+ Class converterClass = Thread.currentThread().getContextClassLoader().loadClass(tc.converter());
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Converter class: [#0]", converterClass);
+ }
+ //check if the converter is a type converter if it is one
+ //then just put it in the map as is. Otherwise
+ //put a value in for the type converter of the class
+ if (converterClass.isAssignableFrom(TypeConverter.class)) {
+ mapping.put(key, converterCreator.createTypeConverter(tc.converter()));
+ } else {
+ mapping.put(key, converterClass);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Object placed in mapping for key [#0] is [#1]", key, mapping.get(key));
+ }
+ }
+ }
+ //elements(values) of maps / lists
+ else {
+ mapping.put(key, Thread.currentThread().getContextClassLoader().loadClass(tc.converter()));
+ }
+ }
+ } catch (Exception e) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Got exception for #0", e, key);
+ }
+ }
+ }
+
+}
diff --git a/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/DefaultConversionFileProcessor.java b/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/DefaultConversionFileProcessor.java
new file mode 100644
index 000000000..4537b0e12
--- /dev/null
+++ b/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/DefaultConversionFileProcessor.java
@@ -0,0 +1,112 @@
+package com.opensymphony.xwork2.conversion.impl;
+
+import com.opensymphony.xwork2.FileManager;
+import com.opensymphony.xwork2.FileManagerFactory;
+import com.opensymphony.xwork2.conversion.ConversionFileProcessor;
+import com.opensymphony.xwork2.conversion.TypeConverter;
+import com.opensymphony.xwork2.conversion.TypeConverterCreator;
+import com.opensymphony.xwork2.inject.Inject;
+import com.opensymphony.xwork2.util.ClassLoaderUtil;
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.xwork2.util.logging.LoggerFactory;
+
+import java.io.InputStream;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * Default implementation of {@link ConversionFileProcessor}
+ */
+public class DefaultConversionFileProcessor implements ConversionFileProcessor {
+
+ private static final Logger LOG = LoggerFactory.getLogger(DefaultConversionFileProcessor.class);
+
+ private FileManager fileManager;
+ private TypeConverterCreator converterCreator;
+
+ @Inject
+ public void setFileManagerFactory(FileManagerFactory factory) {
+ fileManager = factory.getFileManager();
+ }
+
+ @Inject
+ public void setTypeConverterCreator(TypeConverterCreator converterCreator) {
+ this.converterCreator = converterCreator;
+ }
+
+ public void process(Map mapping, Class clazz, String converterFilename) {
+ try {
+ InputStream is = fileManager.loadFile(ClassLoaderUtil.getResource(converterFilename, clazz));
+
+ if (is != null) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Processing conversion file [#0] for class [#1]", converterFilename, clazz);
+ }
+
+ Properties prop = new Properties();
+ prop.load(is);
+
+ for (Map.Entry