Commits

Anonymous committed 868f754

Merging the no-statics branch into 2.1 trunk. Consists of
* OGNL API separation so that the EL could be replaced
* Rid of almost all static state, preferring dep injection
* Rid of static factories, again in favor of dep injection
* Better use of dep injection library (bootstrap phase)

XW-566 XW-461 XW-561

git-svn-id: http://svn.opensymphony.com/svn/xwork/trunk@1608e221344d-f017-0410-9bd5-d282ab1896d7

  • Participants
  • Parent commits 6e52cb3

Comments (0)

Files changed (159)

File src/java/com/opensymphony/xwork2/ActionContext.java

  */
 package com.opensymphony.xwork2;
 
+import com.opensymphony.xwork2.inject.Container;
 import com.opensymphony.xwork2.util.ValueStack;
 import com.opensymphony.xwork2.util.ValueStackFactory;
 
  * @author Bill Lynch (docs)
  */
 public class ActionContext implements Serializable {
-    static ThreadLocal actionContext = new ActionContextThreadLocal();
+    static ThreadLocal actionContext = new ThreadLocal();
 
     /**
      * Constant that indicates the action is running under a "development mode".
     public static final String CONVERSION_ERRORS = "com.opensymphony.xwork2.ActionContext.conversionErrors";
 
 
+    /**
+     * Constant for the container
+     */
+    public static final String CONTAINER = "com.opensymphony.xwork.ActionContext.container";
+    
     Map context;
 
 
     public static ActionContext getContext() {
         ActionContext context = (ActionContext) actionContext.get();
 
-        if (context == null) {
-            ValueStack vs = ValueStackFactory.getFactory().createValueStack();
-            context = new ActionContext(vs.getContext());
-            setContext(context);
-        }
+        // Don't do lazy context creation, as it requires container; the creation of which may 
+        // precede the context creation
+        //if (context == null) {
+        //    ValueStack vs = ValueStackFactory.getFactory().createValueStack();
+        //    context = new ActionContext(vs.getContext());
+        //    setContext(context);
+        //}
 
         return context;
     }
     public ValueStack getValueStack() {
         return (ValueStack) get(VALUE_STACK);
     }
+    
+    /**
+     * Gets the container for this request
+     * 
+     * @param cont The container
+     */
+    public void setContainer(Container cont) {
+        put(CONTAINER, cont);
+    }
+    
+    /**
+     * Sets the container for this request
+     * 
+     * @return The container
+     */
+    public Container getContainer() {
+        return (Container) get(CONTAINER);
+    }
+    
+    public <T> T getInstance(Class<T> type) {
+        Container cont = getContainer();
+        if (cont != null) {
+            return cont.getInstance(type);
+        } else {
+            throw new XWorkException("Cannot find an initialized container for this request.");
+        }
+    }
 
     /**
      * Returns a value that is stored in the current ActionContext by doing a lookup using the value's key.
     public void put(Object key, Object value) {
         context.put(key, value);
     }
-
-
-    private static class ActionContextThreadLocal extends ThreadLocal {
-        protected Object initialValue() {
-            ValueStack vs = ValueStackFactory.getFactory().createValueStack();
-
-            return new ActionContext(vs.getContext());
-        }
-    }
 }

File src/java/com/opensymphony/xwork2/ActionInvocation.java

 import com.opensymphony.xwork2.util.ValueStack;
 
 import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
 
 
 /**
      */
     void setActionEventListener(ActionEventListener listener);
 
+    void init(ActionProxy proxy) throws Exception;
+
 }

File src/java/com/opensymphony/xwork2/ActionProxyFactory.java

      * @throws Exception can be thrown
      */
     public ActionProxy createActionProxy(String namespace, String actionName, Map extraContext, boolean executeResult, boolean cleanupContext) throws Exception;
+
+    public ActionProxy createActionProxy(ActionInvocation inv, String namespace, String actionName,
+            Map extraContext, boolean executeResult, boolean cleanupContext) throws Exception;
     
 }

File src/java/com/opensymphony/xwork2/DefaultActionInvocation.java

 import com.opensymphony.xwork2.config.entities.ActionConfig;
 import com.opensymphony.xwork2.config.entities.InterceptorMapping;
 import com.opensymphony.xwork2.config.entities.ResultConfig;
+import com.opensymphony.xwork2.inject.Container;
+import com.opensymphony.xwork2.inject.Inject;
 import com.opensymphony.xwork2.interceptor.PreResultListener;
 import com.opensymphony.xwork2.util.ValueStack;
 import com.opensymphony.xwork2.util.ValueStackFactory;
     protected boolean pushAction = true;
     protected ObjectFactory objectFactory;
     protected ActionEventListener actionEventListener;
-
+    protected ValueStackFactory valueStackFactory;
+    protected Container container;
     protected UnknownHandler unknownHandler;
 
-    protected DefaultActionInvocation(ObjectFactory objectFactory, UnknownHandler handler, ActionProxy proxy, Map extraContext) throws Exception {
-        this(objectFactory, handler, proxy, extraContext, true, null);
+    public DefaultActionInvocation(final Map extraContext, final boolean pushAction) throws Exception {
+        DefaultActionInvocation.this.extraContext = extraContext;
+        DefaultActionInvocation.this.pushAction = pushAction;
     }
-
-    protected DefaultActionInvocation(final ObjectFactory objectFactory, final UnknownHandler handler, final ActionProxy proxy, final Map extraContext, final boolean pushAction) throws Exception {
-        this(objectFactory, handler, proxy, extraContext, pushAction, null);
+    
+    @Inject
+    public void setValueStackFactory(ValueStackFactory fac) {
+        this.valueStackFactory = fac;
     }
-
-    protected DefaultActionInvocation(final ObjectFactory objectFactory, final UnknownHandler handler, final ActionProxy proxy, final Map extraContext, final boolean pushAction, final ActionEventListener actionEventListener) throws Exception {
-    	UtilTimerStack.profile("create DefaultActionInvocation: ",
-    			new UtilTimerStack.ProfilingBlock<Object>() {
-					public Object doProfiling() throws Exception {
-						DefaultActionInvocation.this.proxy = proxy;
-                        DefaultActionInvocation.this.objectFactory = objectFactory;
-				        DefaultActionInvocation.this.extraContext = extraContext;
-				        DefaultActionInvocation.this.pushAction = pushAction;
-                        DefaultActionInvocation.this.unknownHandler = handler;
-                        DefaultActionInvocation.this.actionEventListener = actionEventListener;
-                        init();
-						return null;
-					}
-    			});
+    
+    @Inject
+    public void setObjectFactory(ObjectFactory fac) {
+        this.objectFactory = fac;
+    }
+    
+    @Inject
+    public void setContainer(Container cont) {
+        this.container = cont;
+    }
+    
+    @Inject(required=false)
+    public void setUnknownHandler(UnknownHandler hand) {
+        this.unknownHandler = hand;
     }
     
+    @Inject(required=false)
     public void setActionEventListener(ActionEventListener listener) {
         this.actionEventListener = listener;
     }
         } else {
             // create the value stack
             // this also adds the ValueStack to its context
-            stack = ValueStackFactory.getFactory().createValueStack();
+            stack = valueStackFactory.createValueStack();
 
             // create the action context
             contextMap = stack.getContext();
 
         //put this DefaultActionInvocation into the context map
         contextMap.put(ActionContext.ACTION_INVOCATION, this);
+        contextMap.put(ActionContext.CONTAINER, container);
 
         return contextMap;
     }
         }
     }
 
-    private void init() throws Exception {
+    public void init(ActionProxy proxy) throws Exception {
+        this.proxy = proxy;
         Map contextMap = createContextMap();
 
         createAction(contextMap);

File src/java/com/opensymphony/xwork2/DefaultActionProxy.java

      * The reason for the builder methods is so that you can use a subclass to create your own DefaultActionProxy instance
      * (like a RMIActionProxy).
      */
-    protected DefaultActionProxy(String namespace, String actionName, Map extraContext, boolean executeResult, boolean cleanupContext) throws Exception {
+    protected DefaultActionProxy(ActionInvocation inv, String namespace, String actionName, Map extraContext, boolean executeResult, boolean cleanupContext) throws Exception {
         
-    		
+        this.invocation = inv;
 		this.cleanupContext = cleanupContext;
 		if (LOG.isDebugEnabled()) {
 			LOG.debug("Creating an DefaultActionProxy for namespace " + namespace + " and action name " + actionName);
                 throw new ConfigurationException(message);
             }
             
-            invocation = new DefaultActionInvocation(objectFactory, unknownHandler, this, extraContext, true, actionEventListener);
+            
+            invocation.init(this);
             resolveMethod();
         } finally {
             UtilTimerStack.pop(profileKey);

File src/java/com/opensymphony/xwork2/DefaultActionProxyFactory.java

     }
 
     public ActionProxy createActionProxy(String namespace, String actionName, Map extraContext, boolean executeResult, boolean cleanupContext) throws Exception {
-        ActionProxy proxy = new DefaultActionProxy(namespace, actionName, extraContext, executeResult, cleanupContext);
+        
+        ActionInvocation inv = new DefaultActionInvocation(extraContext, true);
+        container.inject(inv);
+        return createActionProxy(inv, namespace, actionName, extraContext, executeResult, cleanupContext);
+    }
+    
+    public ActionProxy createActionProxy(ActionInvocation inv, String namespace, String actionName, Map extraContext, boolean executeResult, boolean cleanupContext) throws Exception {
+        
+        ActionProxy proxy = new DefaultActionProxy(inv, namespace, actionName, extraContext, executeResult, cleanupContext);
         container.inject(proxy);
         proxy.prepare();
         return proxy;

File src/java/com/opensymphony/xwork2/DefaultTextProvider.java

 
     private static final Object[] EMPTY_ARGS = new Object[0];
 
-    public static final DefaultTextProvider INSTANCE = new DefaultTextProvider();
-
-    private DefaultTextProvider() {
+    public DefaultTextProvider() {
     }
 
     public String getText(String key) {
         return null;
     }
 
-    private Object readResolve() throws ObjectStreamException {
-        return INSTANCE;
-    }
 }

File src/java/com/opensymphony/xwork2/ObjectFactory.java

 package com.opensymphony.xwork2;
 
 import com.opensymphony.xwork2.util.ClassLoaderUtil;
+import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
 import com.opensymphony.xwork2.config.ConfigurationException;
 import com.opensymphony.xwork2.config.entities.ActionConfig;
 import com.opensymphony.xwork2.config.entities.InterceptorConfig;
 import com.opensymphony.xwork2.inject.Container;
 import com.opensymphony.xwork2.inject.Inject;
 import com.opensymphony.xwork2.interceptor.Interceptor;
-import com.opensymphony.xwork2.util.OgnlUtil;
 import com.opensymphony.xwork2.validator.Validator;
 
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
 
-import ognl.OgnlException;
-
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
     private static final Log LOG = LogFactory.getLog(ObjectFactory.class);
 
     private transient ClassLoader ccl;
-    private static ThreadLocal<ObjectFactory> thSelf = new ThreadLocal<ObjectFactory>();
     private Container container;
+    protected ReflectionProvider reflectionProvider;
 
     @Inject(value="objectFactory.classloader", required=false)
     public void setClassLoader(ClassLoader cl) {
         this.ccl = cl;
     }
+    
+    @Inject
+    public void setReflectionProvider(ReflectionProvider prov) {
+        this.reflectionProvider = prov;
+    }
 
     public ObjectFactory() {
     }
     
+    public ObjectFactory(ReflectionProvider prov) {
+        this.reflectionProvider = prov;
+    }
+    
     @Inject
     public void setContainer(Container container) {
         this.container = container;
     }
 
-    @Inject
-    public static void setObjectFactory(ObjectFactory factory) {
-        thSelf.set(factory);
-    }
-
+    /**
+     * @deprecated Since 2.1
+     */
     public static ObjectFactory getObjectFactory() {
-        return thSelf.get();
+        return ActionContext.getContext().getContainer().getInstance(ObjectFactory.class);
     }
 
     /**
         try {
             // interceptor instances are long-lived and used across user sessions, so don't try to pass in any extra context
             Interceptor interceptor = (Interceptor) buildBean(interceptorClassName, null);
-            OgnlUtil.setProperties(params, interceptor);
+            reflectionProvider.setProperties(params, interceptor);
             interceptor.init();
 
             return interceptor;
 
         if (resultClassName != null) {
             result = (Result) buildBean(resultClassName, extraContext);
-            try {
-            	OgnlUtil.setProperties(resultConfig.getParams(), result, extraContext, true);
-            } catch (XWorkException ex) {
-            	Throwable reason = ex.getCause();
-            	if (reason instanceof OgnlException)
-            	{
-            		// ognl exceptions could be thrown and be ok if, for example, the result uses parameters in ways other than
-            		// as properties for the result object.  For example, the redirect result from Struts 2 allows any parameters
-            		// to be set on the result, which it appends to the redirecting url.  These parameters wouldn't have a 
-            		// corresponding setter on the result object, so an OGNL exception could be thrown.  Still, this is a misuse
-            		// of exceptions, so we should look at improving it.
-            		LOG.debug(ex.getMessage(), reason);
-            	} else {
-            		throw ex;
-            	}
-            }
+        	reflectionProvider.setProperties(resultConfig.getParams(), result, extraContext, true);
         }
 
         return result;
      */
     public Validator buildValidator(String className, Map params, Map extraContext) throws Exception {
         Validator validator = (Validator) buildBean(className, null);
-        OgnlUtil.setProperties(params, validator);
+        reflectionProvider.setProperties(params, validator);
 
         return validator;
     }

File src/java/com/opensymphony/xwork2/XWorkTestCase.java

 
 package com.opensymphony.xwork2;
 
+import java.util.Arrays;
+
 import junit.framework.TestCase;
 
 import com.opensymphony.xwork2.config.Configuration;
+import com.opensymphony.xwork2.config.ConfigurationException;
 import com.opensymphony.xwork2.config.ConfigurationManager;
 import com.opensymphony.xwork2.config.ConfigurationProvider;
+import com.opensymphony.xwork2.config.impl.DefaultConfiguration;
 import com.opensymphony.xwork2.config.impl.MockConfiguration;
+import com.opensymphony.xwork2.config.providers.XWorkConfigurationProvider;
+import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
+import com.opensymphony.xwork2.conversion.ObjectTypeDeterminer;
 import com.opensymphony.xwork2.inject.Container;
+import com.opensymphony.xwork2.inject.ContainerBuilder;
+import com.opensymphony.xwork2.inject.Context;
+import com.opensymphony.xwork2.inject.Factory;
+import com.opensymphony.xwork2.inject.Scope;
+import com.opensymphony.xwork2.mock.MockObjectTypeDeterminer;
+import com.opensymphony.xwork2.util.Cat;
 import com.opensymphony.xwork2.util.XWorkTestCaseHelper;
+import com.opensymphony.xwork2.util.location.LocatableProperties;
 
 
 /**
     
     protected void setUp() throws Exception {
         configurationManager = XWorkTestCaseHelper.setUp();
-        configuration = new MockConfiguration();
+        configuration = configurationManager.getConfiguration();
         container = configuration.getContainer();
         actionProxyFactory = container.getInstance(ActionProxyFactory.class);
     }
         container = configuration.getContainer();
         actionProxyFactory = container.getInstance(ActionProxyFactory.class);
     }
+    
+    protected void loadButAdd(final Class<?> type, final Object impl) {
+        loadConfigurationProviders(new StubConfigurationProvider() {
+            public void register(ContainerBuilder builder,
+                    LocatableProperties props) throws ConfigurationException {
+                builder.factory(type, new Factory() {
+                    public Object create(Context context) throws Exception {
+                        return impl;
+                    }
+                    
+                }, Scope.SINGLETON);
+            }
+        });
+    }
+    
 }

File src/java/com/opensymphony/xwork2/config/ConfigurationManager.java

 
 import com.opensymphony.xwork2.util.FileManager;
 import com.opensymphony.xwork2.config.impl.DefaultConfiguration;
+import com.opensymphony.xwork2.config.providers.XWorkConfigurationProvider;
 import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
         providerLock.lock();
         try {
             if (configurationProviders.size() == 0) {
-                configurationProviders.add(new XmlConfigurationProvider("xwork.xml", true));
+                configurationProviders.add(new XWorkConfigurationProvider());
+                configurationProviders.add(new XmlConfigurationProvider("xwork.xml", false));
             }
 
             return configurationProviders;

File src/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java

  */
 package com.opensymphony.xwork2.config.impl;
 
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.DefaultTextProvider;
 import com.opensymphony.xwork2.ObjectFactory;
+import com.opensymphony.xwork2.TextProvider;
 import com.opensymphony.xwork2.config.Configuration;
 import com.opensymphony.xwork2.config.ConfigurationException;
 import com.opensymphony.xwork2.config.ConfigurationProvider;
 import com.opensymphony.xwork2.config.RuntimeConfiguration;
 import com.opensymphony.xwork2.config.entities.*;
 import com.opensymphony.xwork2.config.providers.InterceptorBuilder;
+import com.opensymphony.xwork2.conversion.ObjectTypeDeterminer;
+import com.opensymphony.xwork2.conversion.impl.DefaultObjectTypeDeterminer;
+import com.opensymphony.xwork2.conversion.impl.XWorkBasicConverter;
+import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
 import com.opensymphony.xwork2.inject.Container;
 import com.opensymphony.xwork2.inject.ContainerBuilder;
 import com.opensymphony.xwork2.inject.Context;
 import com.opensymphony.xwork2.inject.Factory;
+import com.opensymphony.xwork2.inject.Scope;
+import com.opensymphony.xwork2.ognl.OgnlReflectionProvider;
+import com.opensymphony.xwork2.ognl.OgnlUtil;
+import com.opensymphony.xwork2.ognl.OgnlValueStackFactory;
+import com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor;
+import com.opensymphony.xwork2.util.CompoundRoot;
+import com.opensymphony.xwork2.util.ValueStack;
+import com.opensymphony.xwork2.util.ValueStackFactory;
 import com.opensymphony.xwork2.util.location.LocatableProperties;
+import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
+import com.opensymphony.xwork2.util.reflection.ReflectionProviderFactory;
+
+import ognl.PropertyAccessor;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
         });
         
         try {
-            // Set the object factory for the purposes of factory creation
-            ObjectFactory.setObjectFactory(new ObjectFactory());
-            
+            // Set the bootstrap container for the purposes of factory creation
+            Container bootstrap = createBootstrapContainer();
+            setContext(bootstrap);
             container = builder.create(false);
+            setContext(container);
             objectFactory = container.getInstance(ObjectFactory.class);
-            ObjectFactory.setObjectFactory(objectFactory);
             
             for (ConfigurationProvider configurationProvider : providers)
             {
     
             rebuildRuntimeConfiguration();
         } finally {
-            ObjectFactory.setObjectFactory(null);
+            ActionContext.setContext(null);
         }
     }
+    
+    protected ActionContext setContext(Container cont) {
+        ValueStack vs = cont.getInstance(ValueStackFactory.class).createValueStack();
+        ActionContext context = new ActionContext(vs.getContext());
+        ActionContext.setContext(context);
+        return context;
+    }
+
+    protected Container createBootstrapContainer() {
+        ContainerBuilder builder = new ContainerBuilder();
+        builder.factory(ObjectFactory.class, Scope.SINGLETON);
+        builder.factory(ReflectionProvider.class, OgnlReflectionProvider.class, Scope.SINGLETON);
+        builder.factory(ValueStackFactory.class, OgnlValueStackFactory.class, Scope.SINGLETON);
+        builder.factory(XWorkConverter.class, Scope.SINGLETON);
+        builder.factory(XWorkBasicConverter.class, Scope.SINGLETON);
+        builder.factory(TextProvider.class, "system", DefaultTextProvider.class, Scope.SINGLETON);
+        builder.factory(ObjectTypeDeterminer.class, DefaultObjectTypeDeterminer.class, Scope.SINGLETON);
+        builder.factory(PropertyAccessor.class, CompoundRoot.class.getName(), CompoundRootAccessor.class, Scope.SINGLETON);
+        builder.factory(OgnlUtil.class, Scope.SINGLETON);
+        builder.constant("devMode", "false");
+        return builder.create(true);
+    }
 
     public void removePackageConfig(String name) {
         PackageConfig toBeRemoved = packageContexts.get(name);

File src/java/com/opensymphony/xwork2/config/impl/MockConfiguration.java

 import com.opensymphony.xwork2.config.ConfigurationProvider;
 import com.opensymphony.xwork2.config.RuntimeConfiguration;
 import com.opensymphony.xwork2.config.entities.PackageConfig;
+import com.opensymphony.xwork2.config.providers.XWorkConfigurationProvider;
+import com.opensymphony.xwork2.conversion.ObjectTypeDeterminer;
+import com.opensymphony.xwork2.conversion.impl.DefaultObjectTypeDeterminer;
+import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
 import com.opensymphony.xwork2.inject.Container;
 import com.opensymphony.xwork2.inject.ContainerBuilder;
 import com.opensymphony.xwork2.inject.Context;
 import com.opensymphony.xwork2.inject.Factory;
+import com.opensymphony.xwork2.ognl.OgnlReflectionProvider;
+import com.opensymphony.xwork2.util.location.LocatableProperties;
+import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
 
 import java.util.HashSet;
 import java.util.List;
     private Container container;
     
     public MockConfiguration() {
-        container = new ContainerBuilder()
-            .factory(ObjectFactory.class)
-            .factory(ActionProxyFactory.class, DefaultActionProxyFactory.class)
-            .factory(Configuration.class, new Factory() {
-
-                public Object create(Context context) throws Exception {
-                    return MockConfiguration.this;
-                }
-                
-            })
-            .create(true);
+        ContainerBuilder builder = new ContainerBuilder();
+        LocatableProperties props = new LocatableProperties();
+        new XWorkConfigurationProvider().register(builder, props);
+        builder.constant("devMode", "false");
+        container = builder.create(true);
     }
 
     public PackageConfig getPackageConfig(String name) {

File src/java/com/opensymphony/xwork2/config/providers/XWorkConfigurationProvider.java

+package com.opensymphony.xwork2.config.providers;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import com.opensymphony.xwork2.ActionProxyFactory;
+import com.opensymphony.xwork2.DefaultActionProxyFactory;
+import com.opensymphony.xwork2.DefaultTextProvider;
+import com.opensymphony.xwork2.TextProvider;
+import com.opensymphony.xwork2.config.Configuration;
+import com.opensymphony.xwork2.config.ConfigurationException;
+import com.opensymphony.xwork2.config.ConfigurationProvider;
+import com.opensymphony.xwork2.conversion.NullHandler;
+import com.opensymphony.xwork2.conversion.ObjectTypeDeterminer;
+import com.opensymphony.xwork2.conversion.impl.DefaultObjectTypeDeterminer;
+import com.opensymphony.xwork2.conversion.impl.InstantiatingNullHandler;
+import com.opensymphony.xwork2.conversion.impl.XWorkBasicConverter;
+import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
+import com.opensymphony.xwork2.inject.ContainerBuilder;
+import com.opensymphony.xwork2.inject.Scope;
+import com.opensymphony.xwork2.util.location.LocatableProperties;
+import com.opensymphony.xwork2.util.reflection.ReflectionContextFactory;
+import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
+
+import ognl.MethodAccessor;
+import ognl.PropertyAccessor;
+import com.opensymphony.xwork2.util.CompoundRoot;
+import com.opensymphony.xwork2.util.ValueStackFactory;
+import com.opensymphony.xwork2.validator.ActionValidatorManager;
+import com.opensymphony.xwork2.validator.AnnotationActionValidatorManager;
+import com.opensymphony.xwork2.validator.DefaultActionValidatorManager;
+import com.opensymphony.xwork2.ognl.ObjectProxy;
+import com.opensymphony.xwork2.ognl.OgnlReflectionContextFactory;
+import com.opensymphony.xwork2.ognl.OgnlReflectionProvider;
+import com.opensymphony.xwork2.ognl.OgnlUtil;
+import com.opensymphony.xwork2.ognl.OgnlValueStackFactory;
+import com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor;
+import com.opensymphony.xwork2.ognl.accessor.ObjectAccessor;
+import com.opensymphony.xwork2.ognl.accessor.ObjectProxyPropertyAccessor;
+import com.opensymphony.xwork2.ognl.accessor.XWorkCollectionPropertyAccessor;
+import com.opensymphony.xwork2.ognl.accessor.XWorkEnumerationAccessor;
+import com.opensymphony.xwork2.ognl.accessor.XWorkIteratorPropertyAccessor;
+import com.opensymphony.xwork2.ognl.accessor.XWorkListPropertyAccessor;
+import com.opensymphony.xwork2.ognl.accessor.XWorkMapPropertyAccessor;
+import com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor;
+
+public class XWorkConfigurationProvider implements ConfigurationProvider {
+
+    public void destroy() {
+    }
+
+    public void init(Configuration configuration) throws ConfigurationException {
+    }
+
+    public void loadPackages() throws ConfigurationException {
+    }
+
+    public boolean needsReload() {
+        return false;
+    }
+
+    public void register(ContainerBuilder builder, LocatableProperties props)
+            throws ConfigurationException {
+
+        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(ValueStackFactory.class, OgnlValueStackFactory.class, Scope.SINGLETON)
+               .factory(ReflectionProvider.class, OgnlReflectionProvider.class, Scope.SINGLETON)
+               .factory(ReflectionContextFactory.class, OgnlReflectionContextFactory.class, Scope.SINGLETON)
+               .factory(PropertyAccessor.class, CompoundRoot.class.getName(), CompoundRootAccessor.class, Scope.SINGLETON)
+               .factory(PropertyAccessor.class, Object.class.getName(), ObjectAccessor.class, Scope.SINGLETON)
+               .factory(PropertyAccessor.class, Iterator.class.getName(), XWorkIteratorPropertyAccessor.class, Scope.SINGLETON)
+               .factory(PropertyAccessor.class, Enumeration.class.getName(), XWorkEnumerationAccessor.class, Scope.SINGLETON)
+               
+               // 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)
+               .factory(TextProvider.class, "system", DefaultTextProvider.class, Scope.SINGLETON)
+               .factory(OgnlUtil.class, Scope.SINGLETON)
+               .factory(XWorkBasicConverter.class, Scope.SINGLETON);
+        props.setProperty("devMode", Boolean.FALSE.toString());
+    }
+
+}

File src/java/com/opensymphony/xwork2/config/providers/XmlConfigurationProvider.java

     private boolean errorIfMissing;
     private Map<String, String> dtdMappings;
     private Configuration configuration;
+    private boolean throwExceptionOnDuplicateBeans = true;
 
     public XmlConfigurationProvider() {
         this("xwork.xml", true);
         mappings.put("-//OpenSymphony Group//XWork 1.0//EN", "xwork-1.0.dtd");
         setDtdMappings(mappings);
     }
+    
+    public void setThrowExceptionOnDuplicateBeans(boolean val) {
+        this.throwExceptionOnDuplicateBeans = val;
+    }
 
     public void setDtdMappings(Map<String, String> mappings) {
         this.dtdMappings = Collections.unmodifiableMap(mappings);
                             } else {
                                 if (containerBuilder.contains(ctype, name)) {
                                     Location loc = LocationUtils.getLocation(loadedBeans.get(ctype.getName() + name));
-                                    throw new ConfigurationException("Bean type " + ctype + " with the name " +
-                                            name + " has already been loaded by " + loc, child);
+                                    if (throwExceptionOnDuplicateBeans) {
+                                        throw new ConfigurationException("Bean type " + ctype + " with the name " +
+                                                name + " has already been loaded by " + loc, child);
+                                    } 
                                 }
 
                                 // Force loading of class to detect no class def found exceptions

File src/java/com/opensymphony/xwork2/conversion/NullHandler.java

+//--------------------------------------------------------------------------
+//Copyright (c) 1998-2004, Drew Davidson and Luke Blanshard
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions are
+//met:
+//
+//Redistributions of source code must retain the above copyright notice,
+//this list of conditions and the following disclaimer.
+//Redistributions in binary form must reproduce the above copyright
+//notice, this list of conditions and the following disclaimer in the
+//documentation and/or other materials provided with the distribution.
+//Neither the name of the Drew Davidson nor the names of its contributors
+//may be used to endorse or promote products derived from this software
+//without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+//OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+//AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+//OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+//THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+//DAMAGE.
+//--------------------------------------------------------------------------
+package com.opensymphony.xwork2.conversion;
+
+import java.util.Map;
+
+/**
+* Interface for handling null results from Chains.
+* Object has the opportunity to substitute an object for the
+* null and continue.
+* @author Luke Blanshard (blanshlu@netscape.net)
+* @author Drew Davidson (drew@ognl.org)
+*/
+public interface NullHandler
+{
+    /**
+        Method called on target returned null.
+     */
+    public Object nullMethodResult(Map context, Object target, String methodName, Object[] args);
+    
+    /**
+        Property in target evaluated to null.  Property can be a constant
+        String property name or a DynamicSubscript.
+     */
+    public Object nullPropertyValue(Map context, Object target, Object property);
+}

File src/java/com/opensymphony/xwork2/conversion/ObjectTypeDeterminerFactory.java

-/*
- * Copyright (c) 2002-2007 by OpenSymphony
- * All rights reserved.
- */
-package com.opensymphony.xwork2.conversion;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import com.opensymphony.xwork2.conversion.impl.DefaultObjectTypeDeterminer;
-import com.opensymphony.xwork2.conversion.impl.GenericsObjectTypeDeterminer;
-
-/**
- * Factory for getting an instance of {@link ObjectTypeDeterminer}.
- * <p/>
- * Will use <code>com.opensymphony.xwork2.util.GenericsObjectTypeDeterminer</code> by default.
- *
- * @see com.opensymphony.xwork2.conversion.impl.GenericsObjectTypeDeterminer
- * @see com.opensymphony.xwork2.conversion.ObjectTypeDeterminer
- * @see com.opensymphony.xwork2.conversion.impl.DefaultObjectTypeDeterminer
- *
- * @author plightbo
- * @author Rainer Hermanns
- * @author Rene Gielen
- */
-public class ObjectTypeDeterminerFactory {
-    private static final Log LOG = LogFactory.getLog(ObjectTypeDeterminerFactory.class);
-
-    private static ObjectTypeDeterminer instance = new DefaultObjectTypeDeterminer();
-
-    static {
-        LOG.info("Setting DefaultObjectTypeDeterminer as default ...");
-    }
-
-    /**
-     * Sets a new instance of ObjectTypeDeterminer to be used.
-     *
-     * @param instance  instance of ObjectTypeDeterminer
-     */
-    public static void setInstance(ObjectTypeDeterminer instance) {
-        if (instance != null) {
-            if (!instance.getClass().equals(ObjectTypeDeterminerFactory.instance.getClass())) {
-                LOG.info("Switching to ObjectTypeDeterminer of type " + instance.getClass().getName());
-            }
-            ObjectTypeDeterminerFactory.instance = instance;
-        }
-    }
-
-    /**
-     * Gets the instance of ObjectTypeDeterminer to be used.
-     *
-     * @return instance of ObjectTypeDeterminer
-     */
-    public static ObjectTypeDeterminer getInstance() {
-        return instance;
-    }
-
-}

File src/java/com/opensymphony/xwork2/conversion/OgnlTypeConverterWrapper.java

-/*
- * Copyright (c) 2002-2007 by OpenSymphony
- * All rights reserved.
- */
-package com.opensymphony.xwork2.conversion;
-
-import java.lang.reflect.Member;
-import java.util.Map;
-
-/**
- * Wraps an XWork type conversion class for as an OGNL TypeConverter
- */
-public class OgnlTypeConverterWrapper implements ognl.TypeConverter {
-
-    private TypeConverter typeConverter;
-    
-    public OgnlTypeConverterWrapper(TypeConverter conv) {
-        this.typeConverter = conv;
-    }
-    
-    public Object convertValue(Map context, Object target, Member member,
-            String propertyName, Object value, Class toType) {
-        return typeConverter.convertValue(context, target, member, propertyName, value, toType);
-    }
-    
-    public TypeConverter getTarget() {
-        return typeConverter;
-    }
-}

File src/java/com/opensymphony/xwork2/conversion/TypeConverter.java

 /**
  * Interface for accessing the type conversion facilities within a context.
  * 
- * This interface was copied from OGNL's ognl.TypeConverter
+ * This interface was copied from OGNL's TypeConverter
  * 
  * @author Luke Blanshard (blanshlu@netscape.net)
  * @author Drew Davidson (drew@ognl.org)

File src/java/com/opensymphony/xwork2/conversion/XWorkTypeConverterWrapper.java

-/*
- * Copyright (c) 2002-2007 by OpenSymphony
- * All rights reserved.
- */
-package com.opensymphony.xwork2.conversion;
-
-import java.lang.reflect.Member;
-import java.util.Map;
-
-/**
- * Wraps an OGNL TypeConverter as an XWork TypeConverter
- */
-public class XWorkTypeConverterWrapper implements TypeConverter {
-
-    private ognl.TypeConverter typeConverter;
-    
-    public XWorkTypeConverterWrapper(ognl.TypeConverter conv) {
-        this.typeConverter = conv;
-    }
-    
-    public Object convertValue(Map context, Object target, Member member,
-            String propertyName, Object value, Class toType) {
-        return typeConverter.convertValue(context, target, member, propertyName, value, toType);
-    }
-}

File src/java/com/opensymphony/xwork2/conversion/impl/AnnotationXWorkConverter.java

  * <p/> Using this "point" example, if your action (or another compound object in which you are setting properties on)
  * has a corresponding ClassName-conversion.properties file, XWork will use the configured type converters for
  * conversion to and from strings. So turning "3, 22" in to new Point(3, 22) is done by merely adding the following
- * entry to <b>ClassName-conversion.properties</b> (Note that the PointConverter should impl the ognl.TypeConverter
+ * entry to <b>ClassName-conversion.properties</b> (Note that the PointConverter should impl the TypeConverter
  * interface):
  * <p/>
  * <p/><b>point = com.acme.PointConverter</b>

File src/java/com/opensymphony/xwork2/conversion/impl/DefaultObjectTypeDeterminer.java

 import org.apache.commons.logging.LogFactory;
 
 import com.opensymphony.xwork2.conversion.ObjectTypeDeterminer;
+import com.opensymphony.xwork2.inject.Inject;
+import com.opensymphony.xwork2.ognl.accessor.XWorkCollectionPropertyAccessor;
+import com.opensymphony.xwork2.ognl.accessor.XWorkListPropertyAccessor;
+import com.opensymphony.xwork2.ognl.accessor.XWorkMapPropertyAccessor;
 import com.opensymphony.xwork2.util.CreateIfNull;
 import com.opensymphony.xwork2.util.Element;
 import com.opensymphony.xwork2.util.Key;
 import com.opensymphony.xwork2.util.KeyProperty;
-import com.opensymphony.xwork2.util.XWorkCollectionPropertyAccessor;
-import com.opensymphony.xwork2.util.XWorkListPropertyAccessor;
-import com.opensymphony.xwork2.util.XWorkMapPropertyAccessor;
-
-import ognl.OgnlRuntime;
-import ognl.OgnlException;
+import com.opensymphony.xwork2.util.reflection.ReflectionException;
+import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
 
 /**
  * <!-- START SNIPPET: javadoc -->
  * 
  *
  * @author Gabriel Zimmerman
- * @see XWorkListPropertyAccessor
- * @see XWorkCollectionPropertyAccessor
- * @see XWorkMapPropertyAccessor
  */
 public class DefaultObjectTypeDeterminer implements ObjectTypeDeterminer {
     
     public static final String KEY_PROPERTY_PREFIX = "KeyProperty_";
     public static final String CREATE_IF_NULL_PREFIX = "CreateIfNull_";
     public static final String DEPRECATED_ELEMENT_PREFIX = "Collection_";
-
+    
+    private ReflectionProvider reflectionProvider;
+    private XWorkConverter xworkConverter;
+    
+    @Inject
+    public DefaultObjectTypeDeterminer(@Inject XWorkConverter conv, @Inject ReflectionProvider prov) {
+        this.reflectionProvider = prov;
+        this.xworkConverter = conv;
+        
+    }
+    
     /**
      * Determines the key class by looking for the value of @Key annotation for the given class.
      * If no annotation is found, the key class is determined by using the generic parametrics.
             return clazz;
         }
 
-        return (Class) XWorkConverter.getInstance().getConverter(parentClass, KEY_PREFIX + property);
+        return (Class) xworkConverter.getConverter(parentClass, KEY_PREFIX + property);
     }
 
 
             return clazz;
         }
 
-        clazz = (Class) XWorkConverter.getInstance().getConverter(parentClass, ELEMENT_PREFIX + property);
+        clazz = (Class) xworkConverter.getConverter(parentClass, ELEMENT_PREFIX + property);
 
         if (clazz == null) {
-            clazz = (Class) XWorkConverter.getInstance()
+            clazz = (Class) xworkConverter
                     .getConverter(parentClass, DEPRECATED_ELEMENT_PREFIX + property);
 
             if (clazz != null) {
             return annotation.value();
         }
 
-        return (String) XWorkConverter.getInstance().getConverter(parentClass, KEY_PROPERTY_PREFIX + property);
+        return (String) xworkConverter.getConverter(parentClass, KEY_PROPERTY_PREFIX + property);
     }
 
 
             return annotation.value();
         }
 
-        String configValue = (String) XWorkConverter.getInstance().getConverter(parentClass, CREATE_IF_NULL_PREFIX + property);
+        String configValue = (String) xworkConverter.getConverter(parentClass, CREATE_IF_NULL_PREFIX + property);
         //check if a value is in the config
         if (configValue!=null) {
             if (configValue.equals("true")) {
      */
     protected <T extends Annotation> T getAnnotation(Class parentClass, String property, Class<T> annotationClass) {
         T annotation = null;
-        Field field = OgnlRuntime.getField(parentClass, property);
+        Field field = reflectionProvider.getField(parentClass, property);
 
         if (field != null) {
             annotation = field.getAnnotation(annotationClass);
      */
     private <T extends Annotation>T getAnnotationFromGetter(Class parentClass, String property, Class<T> annotationClass) {
         try {
-            Method getter = OgnlRuntime.getGetMethod(null, parentClass, property);
+            Method getter = reflectionProvider.getGetMethod(parentClass, property);
 
             if (getter != null) {
                 return getter.getAnnotation(annotationClass);
             }
         }
-        catch (OgnlException ognle) {
+        catch (ReflectionException ognle) {
             ; // ignore
         }
         catch (IntrospectionException ie) {
      */
     private <T extends Annotation>T getAnnotationFromSetter(Class parentClass, String property, Class<T> annotationClass) {
         try {
-            Method setter = OgnlRuntime.getSetMethod(null, parentClass, property);
+            Method setter = reflectionProvider.getSetMethod(parentClass, property);
 
             if (setter != null) {
                 return setter.getAnnotation(annotationClass);
             }
         }
-        catch (OgnlException ognle) {
+        catch (ReflectionException ognle) {
             ; // ignore
         }
         catch (IntrospectionException ie) {
 
         try {
 
-            Field field = OgnlRuntime.getField(parentClass, property);
+            Field field = reflectionProvider.getField(parentClass, property);
 
             Type genericType = null;
 
             // Try to get ParameterType from setter method
             if (genericType == null || !(genericType instanceof ParameterizedType)) {
                 try {
-                    Method setter = OgnlRuntime.getSetMethod(null, parentClass, property);
+                    Method setter = reflectionProvider.getSetMethod(parentClass, property);
                     genericType = setter.getGenericParameterTypes()[0];
                 }
-                catch (OgnlException ognle) {
+                catch (ReflectionException ognle) {
                     ; // ignore
                 }
                 catch (IntrospectionException ie) {
             // Try to get ReturnType from getter method
             if (genericType == null || !(genericType instanceof ParameterizedType)) {
                 try {
-                    Method getter = OgnlRuntime.getGetMethod(null, parentClass, property);
+                    Method getter = reflectionProvider.getGetMethod(parentClass, property);
                     genericType = getter.getGenericReturnType();
                 }
-                catch (OgnlException ognle) {
+                catch (ReflectionException ognle) {
                     ; // ignore
                 }
                 catch (IntrospectionException ie) {

File src/java/com/opensymphony/xwork2/conversion/impl/DefaultTypeConverter.java

 import java.util.Map;
 
 import com.opensymphony.xwork2.conversion.TypeConverter;
-import com.opensymphony.xwork2.conversion.XWorkTypeConverterWrapper;
+import com.opensymphony.xwork2.ognl.XWorkTypeConverterWrapper;
 
 /**
  * Default type conversion. Converts among numeric types and also strings.  Contains the basic 
         Object obj = context.get(TypeConverter.TYPE_CONVERTER_CONTEXT_KEY);
         if (obj instanceof TypeConverter) {
             return (TypeConverter) obj;
+            
+        // for backwards-compatibility
         } else if (obj instanceof ognl.TypeConverter) {
             return new XWorkTypeConverterWrapper((ognl.TypeConverter) obj);
         }

File src/java/com/opensymphony/xwork2/conversion/impl/GenericsObjectTypeDeterminer.java

 
 package com.opensymphony.xwork2.conversion.impl;
 
+import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
+
 
 /**
  * GenericsObjectTypeDeterminer
  *             annotation processing.
  */
 public class GenericsObjectTypeDeterminer extends DefaultObjectTypeDeterminer {
+
+    public GenericsObjectTypeDeterminer(XWorkConverter conv,
+            XWorkBasicConverter basicConv, ReflectionProvider prov) {
+        super(conv, prov);
+    }
 }

File src/java/com/opensymphony/xwork2/conversion/impl/InstantiatingNullHandler.java

+/*
+ * Copyright (c) 2002-2006 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.xwork2.conversion.impl;
+
+import com.opensymphony.xwork2.ObjectFactory;
+import com.opensymphony.xwork2.conversion.NullHandler;
+import com.opensymphony.xwork2.inject.Inject;
+import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
+import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.beans.PropertyDescriptor;
+import java.util.*;
+
+
+/**
+ * <!-- START SNIPPET: javadoc -->
+ *
+ * Provided that the key {@link ReflectionContextState#CREATE_NULL_OBJECTS} is in the action context with a value of true (this key is set
+ * only during the execution of the {@link com.opensymphony.xwork2.interceptor.ParametersInterceptor}), OGNL expressions
+ * that have caused a NullPointerException will be temporarily stopped for evaluation while the system automatically
+ * tries to solve the null references by automatically creating the object.
+ *
+ * <p/> The following rules are used when handling null references:
+ *
+ * <ul>
+ *
+ * <li>If the property is declared <i>exactly</i> as a {@link Collection} or {@link List}, then an ArrayList shall be
+ * returned and assigned to the null references.</li>
+ *
+ * <li>If the property is declared as a {@link Map}, then a HashMap will be returned and assigned to the null
+ * references.</li>
+ *
+ * <li>If the null property is a simple bean with a no-arg constructor, it will simply be created using the {@link
+ * ObjectFactory#buildBean(java.lang.Class, java.util.Map)} method.</li>
+ *
+ * </ul>
+ *
+ * <!-- END SNIPPET: javadoc -->
+ *
+ * <!-- START SNIPPET: example -->
+ *
+ * For example, if a form element has a text field named <b>person.name</b> and the expression <i>person</i> evaluates
+ * to null, then this class will be invoked. Because the <i>person</i> expression evaluates to a <i>Person</i> class, a
+ * new Person is created and assigned to the null reference. Finally, the name is set on that object and the overall
+ * effect is that the system automatically created a Person object for you, set it by calling setUsers() and then
+ * finally called getUsers().setName() as you would typically expect.
+ *
+ * <!-- END SNIPPET: example>
+ *
+ * @author Matt Ho
+ * @author Patrick Lightbody
+ */
+public class InstantiatingNullHandler implements NullHandler {
+
+    /**
+     * @deprecated Use {@link ReflectionContextState#CREATE_NULL_OBJECTS} instead
+     */
+    public static final String CREATE_NULL_OBJECTS = ReflectionContextState.CREATE_NULL_OBJECTS;
+    private static final Log LOG = LogFactory.getLog(InstantiatingNullHandler.class);
+    private ReflectionProvider reflectionProvider;
+    private ObjectFactory objectFactory;
+    
+    @Inject
+    public void setReflectionProvider(ReflectionProvider prov) {
+        this.reflectionProvider = prov;
+    }
+    
+    @Inject
+    public void setObjectFactory(ObjectFactory fac) {
+        this.objectFactory = fac;
+    }
+    
+    public Object nullMethodResult(Map context, Object target, String methodName, Object[] args) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Entering nullMethodResult ");
+        }
+
+        return null;
+    }
+
+    public Object nullPropertyValue(Map context, Object target, Object property) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Entering nullPropertyValue [target="+target+", property="+property+"]");
+        }
+
+        boolean c = ReflectionContextState.isCreatingNullObjects(context);
+
+        if (!c) {
+            return null;
+        }
+
+        if ((target == null) || (property == null)) {
+            return null;
+        }
+
+        try {
+            String propName = property.toString();
+            Object realTarget = reflectionProvider.getRealTarget(propName, context, target);
+            Class clazz = null;
+
+            if (realTarget != null) {
+                PropertyDescriptor pd = reflectionProvider.getPropertyDescriptor(realTarget.getClass(), propName);
+                if (pd == null) {
+                    return null;
+                }
+
+                clazz = pd.getPropertyType();
+            }
+
+            if (clazz == null) {
+                // can't do much here!
+                return null;
+            }
+
+            Object param = createObject(clazz, realTarget, propName, context);
+
+            reflectionProvider.setValue(propName, context, realTarget, param);
+
+            return param;
+        } catch (Exception e) {
+            LOG.error("Could not create and/or set value back on to object", e);
+        }
+
+        return null;
+    }
+
+    private Object createObject(Class clazz, Object target, String property, Map context) throws Exception {
+        if (Collection.class.isAssignableFrom(clazz)) {
+            return new ArrayList();
+        } else if (clazz == Map.class) {
+            return new HashMap();
+        }
+
+        return objectFactory.buildBean(clazz, context);
+    }
+}

File src/java/com/opensymphony/xwork2/conversion/impl/XWorkBasicConverter.java

 import java.util.TreeSet;
 
 import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.ObjectFactory;
 import com.opensymphony.xwork2.XWorkException;
+import com.opensymphony.xwork2.conversion.ObjectTypeDeterminer;
 import com.opensymphony.xwork2.conversion.TypeConverter;
+import com.opensymphony.xwork2.inject.Inject;
 import com.opensymphony.xwork2.util.TextUtils;
 import com.opensymphony.xwork2.util.XWorkList;
 
 public class XWorkBasicConverter extends DefaultTypeConverter {
 
     private static String MILLISECOND_FORMAT = ".SSS";
+    
+    private ObjectTypeDeterminer objectTypeDeterminer;
+    private XWorkConverter xworkConverter;
+    private ObjectFactory objectFactory;
+    
+    @Inject
+    public void setObjectTypeDeterminer(ObjectTypeDeterminer det) {
+        this.objectTypeDeterminer = det;
+    }
+    
+    @Inject
+    public void setXWorkConverter(XWorkConverter conv) {
+        this.xworkConverter = conv;
+    }
+    
+    @Inject
+    public void setObjectFactory(ObjectFactory fac) {
+        this.objectFactory = fac;
+    }
 
     public Object convertValue(Map context, Object o, Member member, String s, Object value, Class toType) {
         Object result = null;
             result = new TreeSet();
         } else {
             if (size > 0) {
-                result = new XWorkList(memberType, size);
+                result = new XWorkList(objectFactory, xworkConverter, memberType, size);
             } else {
-                result = new XWorkList(memberType);
+                result = new XWorkList(objectFactory, xworkConverter, memberType);
             }
         }
 
 
         if (o != null) {
             //memberType = (Class) XWorkConverter.getInstance().getConverter(o.getClass(), XWorkConverter.CONVERSION_COLLECTION_PREFIX + prop);
-            memberType = XWorkConverter.getInstance().getObjectTypeDeterminer().getElementClass(o.getClass(), prop, null);
+            memberType = objectTypeDeterminer.getElementClass(o.getClass(), prop, null);
 
             if (memberType == null) {
                 memberType = String.class;

File src/java/com/opensymphony/xwork2/conversion/impl/XWorkConverter.java

 import org.apache.commons.logging.LogFactory;
 
 import com.opensymphony.xwork2.inject.Inject;
+import com.opensymphony.xwork2.ognl.OgnlTypeConverterWrapper;
+import com.opensymphony.xwork2.ognl.XWorkTypeConverterWrapper;
 import com.opensymphony.xwork2.util.AnnotationUtils;
 import com.opensymphony.xwork2.util.CompoundRoot;
 import com.opensymphony.xwork2.util.FileManager;
 import com.opensymphony.xwork2.util.LocalizedTextUtil;
-import com.opensymphony.xwork2.util.OgnlContextState;
 import com.opensymphony.xwork2.util.ValueStack;
+import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
 import com.opensymphony.xwork2.ActionContext;
 import com.opensymphony.xwork2.ObjectFactory;
 import com.opensymphony.xwork2.XWorkMessages;
 import com.opensymphony.xwork2.conversion.ObjectTypeDeterminer;
-import com.opensymphony.xwork2.conversion.ObjectTypeDeterminerFactory;
-import com.opensymphony.xwork2.conversion.OgnlTypeConverterWrapper;
 import com.opensymphony.xwork2.conversion.TypeConverter;
-import com.opensymphony.xwork2.conversion.XWorkTypeConverterWrapper;
 import com.opensymphony.xwork2.conversion.annotations.Conversion;
 import com.opensymphony.xwork2.conversion.annotations.ConversionType;
 import com.opensymphony.xwork2.conversion.annotations.ConversionRule;
  * <p/> Using this "point" example, if your action (or another compound object in which you are setting properties on)
  * has a corresponding ClassName-conversion.properties file, Struts 2 will use the configured type converters for
  * conversion to and from strings. So turning "3, 22" in to new Point(3, 22) is done by merely adding the following
- * entry to <b>ClassName-conversion.properties</b> (Note that the PointConverter should impl the ognl.TypeConverter
+ * entry to <b>ClassName-conversion.properties</b> (Note that the PointConverter should impl the TypeConverter
  * interface):
  *
  * <p/><b>point = com.acme.PointConverter</b>
  */
 public class XWorkConverter extends DefaultTypeConverter {
 
-    private static XWorkConverter instance;
     protected static final Log LOG = LogFactory.getLog(XWorkConverter.class);
     public static final String REPORT_CONVERSION_ERRORS = "report.conversion.errors";
     public static final String CONVERSION_PROPERTY_FULLNAME = "conversion.property.fullName";
      */
     protected HashSet<String> unknownMappings = new HashSet<String>(); 	// non-action (eg. returned value)
     
-    protected TypeConverter defaultTypeConverter = new XWorkBasicConverter();
-    protected ObjectTypeDeterminer objectTypeDeterminer = null;
+    private TypeConverter defaultTypeConverter;
+    private ObjectFactory objectFactory;
 
 
     protected XWorkConverter() {
     }
 
 
-    public static XWorkConverter getInstance() {
-         if (instance == null) {
-             instance = new XWorkConverter();
-         }
-
-         return instance;
-     }
-    
-    public static ognl.TypeConverter getOgnlInstance() {
-        //return getInstance();
-        return new OgnlTypeConverterWrapper(getInstance());
+    @Inject
+    public void setObjectFactory(ObjectFactory factory) {
+        this.objectFactory = factory;
     }
-
     
     @Inject
-    public static void setInstance(XWorkConverter instance) {
-        XWorkConverter.instance = instance;
+    public void setDefaultTypeConverter(XWorkBasicConverter conv) {
+        this.defaultTypeConverter = conv;
     }
-
+    
     public static String buildConverterFilename(Class clazz) {
         String className = clazz.getName();
         String resource = className.replace('.', '/') + "-conversion.properties";
         return resource;
     }
 
-    public static void resetInstance() {
-        instance = null;
-    }
-
-    public void setDefaultConverter(TypeConverter defaultTypeConverter) {
-        this.defaultTypeConverter = defaultTypeConverter;
-    }
-
     public Object convertValue(Map map, Object o, Class aClass) {
         return convertValue(map, null, null, null, o, aClass);
     }
      * 		<li>supplying context, target and value.</li>
      * </ul>
      * 
-     * @see ognl.TypeConverter#convertValue(java.util.Map, java.lang.Object, java.lang.reflect.Member, java.lang.String, java.lang.Object, java.lang.Class)
+     * @see TypeConverter#convertValue(java.util.Map, java.lang.Object, java.lang.reflect.Member, java.lang.String, java.lang.Object, java.lang.Class)
      */
     public Object convertValue(Map context, Object target, Member member, String property, Object value, Class toClass) {
         //
         
         if (tc == null && context != null) {
             // ok, let's see if we can look it up by path as requested in XW-297
-            Object lastPropertyPath = context.get(OgnlContextState.CURRENT_PROPERTY_PATH);
+            Object lastPropertyPath = context.get(ReflectionContextState.CURRENT_PROPERTY_PATH);
             Class clazz = (Class) context.get(XWorkConverter.LAST_BEAN_CLASS_ACCESSED);
             if (lastPropertyPath != null && clazz != null) {
                 String path = lastPropertyPath + "." + property;
             try {
                 return tc.convertValue(context, target, member, property, value, toClass);
             } catch (Exception e) {
+                e.printStackTrace();
                 handleConversionException(context, property, value, target);
 
                 return TypeConverter.NO_CONVERSION_POSSIBLE;
                     LOG.debug("falling back to default type converter ["+defaultTypeConverter+"]");
                 return defaultTypeConverter.convertValue(context, target, member, property, value, toClass);
             } catch (Exception e) {
+                e.printStackTrace();
                 handleConversionException(context, property, value, target);
 
                 return TypeConverter.NO_CONVERSION_POSSIBLE;
             try {
                 if (LOG.isDebugEnabled())
                     LOG.debug("falling back to Ognl's default type conversion");
-                return super.convertValue(context, target, member, property, value, toClass);
+                return super.convertValue(value, toClass);
             } catch (Exception e) {
+                e.printStackTrace();
                 handleConversionException(context, property, value, target);
 
                 return TypeConverter.NO_CONVERSION_POSSIBLE;
 
     TypeConverter createTypeConverter(String className) throws Exception {
         // type converters are used across users
-        Object obj = ObjectFactory.getObjectFactory().buildBean(className, null);
+        Object obj = objectFactory.buildBean(className, null);
         if (obj instanceof TypeConverter) {
             return (TypeConverter) obj;
+            
+        // For backwards compatibility
         } else if (obj instanceof ognl.TypeConverter) {
             return new XWorkTypeConverterWrapper((ognl.TypeConverter)obj);
         } else {
         return result;
     }
 
-    public ObjectTypeDeterminer getObjectTypeDeterminer() {
-        if (objectTypeDeterminer == null) {
-        	return ObjectTypeDeterminerFactory.getInstance();
-        } else {
-        	return objectTypeDeterminer;
-        }