Anonymous avatar Anonymous committed 01a640b

added Ognl NullHandler to dynamically create new objects

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

Comments (0)

Files changed (2)

src/java/com/opensymphony/xwork/interceptor/ParametersInterceptor.java

 
 import com.opensymphony.xwork.ActionContext;
 import com.opensymphony.xwork.ActionInvocation;
+import com.opensymphony.xwork.util.InstantiatingNullHandler;
 import com.opensymphony.xwork.util.OgnlValueStack;
 
 import java.util.Iterator;
 
 
 /**
- *
- *
  * @author $Author$
  * @version $Revision$
  */
             log.debug("Setting params " + parameters);
         }
 
-        if (parameters != null) {
-            final OgnlValueStack stack = ActionContext.getContext().getValueStack();
+        try {
+            InstantiatingNullHandler.setState(true);
 
-            for (Iterator iterator = parameters.entrySet().iterator();
-                    iterator.hasNext();) {
-                Map.Entry entry = (Map.Entry) iterator.next();
-                stack.setValue(entry.getKey().toString(), entry.getValue());
+            if (parameters != null) {
+                final OgnlValueStack stack = ActionContext.getContext().getValueStack();
+
+                for (Iterator iterator = parameters.entrySet().iterator();
+                        iterator.hasNext();) {
+                    Map.Entry entry = (Map.Entry) iterator.next();
+                    stack.setValue(entry.getKey().toString(), entry.getValue());
+                }
             }
+        } finally {
+            InstantiatingNullHandler.setState(false);
         }
     }
 }

src/java/com/opensymphony/xwork/util/InstantiatingNullHandler.java

+/*
+ * Copyright (c) 2002-2003 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.xwork.util;
+
+import ognl.NullHandler;
+
+import java.lang.reflect.Method;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ *
+ * @author $Id$
+ * @version $Revision$
+ */
+public class InstantiatingNullHandler implements NullHandler {
+    //~ Static fields/initializers /////////////////////////////////////////////
+
+    private static ThreadLocal state = new ThreadLocal();
+
+    //~ Instance fields ////////////////////////////////////////////////////////
+
+    private Map clazzMap = new HashMap();
+
+    //~ Methods ////////////////////////////////////////////////////////////////
+
+    /**
+     * this is very ugly!  however, it gets the job done.  if the state is set to on, then the InstantiatingNullHandler
+     * will create a new object if the requested property does not already exist.  the intended paradigm is
+     *
+     * <pre>
+     * try {
+     *    InstantiatingNullHandler.setState(true);
+     *    // call Ognl setters
+     * } finally {
+     *    InstantiatingNullHandler.setState(false);
+     * }
+     * </pre>
+     * @param on indicates whether or not new objects should be created
+     */
+    public static void setState(boolean on) {
+        if (on) {
+            state.set(Boolean.TRUE);
+        } else {
+            state.set(null);
+        }
+    }
+
+    public Object nullMethodResult(Map context, Object target, String methodName, Object[] args) {
+        return null;
+    }
+
+    /**
+     * @see NullHandler#nullPropertyValue(Map, Object, Object) for additional documentation
+     * @param context
+     * @param target
+     * @param property
+     * @return
+     */
+    public Object nullPropertyValue(Map context, Object target, Object property) {
+        if (state.get() == null) {
+            return null;
+        }
+
+        if ((target == null) || (property == null)) {
+            return null;
+        }
+
+        Map methodMap = getMethodMap(target);
+        Method method = getMethod(methodMap, property.toString(), target);
+
+        /**
+         * if we didn't find any single parameter setters for this method, then there's nothing we can do.
+         */
+        if (method == null) {
+            return null;
+        }
+
+        try {
+            Class clazz = method.getParameterTypes()[0];
+            Object param = clazz.newInstance();
+            method.invoke(target, new Object[] {param});
+
+            return param;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        return null;
+    }
+
+    /**
+     * Attempt to find the setter associated with the provided instance and propertyName.  If we do find it, place that
+     * Method into the methodMap keyed by property name
+     * @param methodMap
+     * @param propertyName the name of the property we're looking up
+     * @param instance of instance of the Class we're attempting to find the setter for
+     * @return
+     */
+    private Method getMethod(Map methodMap, String propertyName, Object instance) {
+        Method method = (Method) methodMap.get(propertyName);
+
+        if (method == null) {
+            synchronized (methodMap) {
+                method = (Method) methodMap.get(propertyName);
+
+                if (method == null) {
+                    String getter = "set" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
+                    Method[] methods = instance.getClass().getDeclaredMethods();
+
+                    for (int i = 0; i < methods.length; i++) {
+                        String name = methods[i].getName();
+
+                        if (!getter.equals(name) || (methods[i].getParameterTypes().length != 1)) {
+                            continue;
+                        } else {
+                            method = methods[i];
+                            methodMap.put(propertyName, method);
+                        }
+                    }
+                }
+            }
+        }
+
+        return method;
+    }
+
+    /**
+     * returns the Map associated with a given Class of Objects
+     * @param instance an instance of the Class we're interested in
+     * @return a Map of Method instances keyed by property name
+     */
+    private Map getMethodMap(Object instance) {
+        Map methodMap = (Map) clazzMap.get(instance.getClass());
+
+        if (methodMap == null) {
+            synchronized (clazzMap) {
+                methodMap = (Map) clazzMap.get(instance.getClass());
+
+                if (methodMap == null) {
+                    methodMap = new HashMap();
+                    clazzMap.put(instance.getClass(), methodMap);
+                }
+            }
+        }
+
+        return methodMap;
+    }
+}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.