Commits

plightbo  committed dcb94d8

handling of null lists done, now for maps and sets

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

  • Participants
  • Parent commits d6ffcc6

Comments (0)

Files changed (6)

File src/java/com/opensymphony/xwork/util/CompoundRootAccessor.java

                     if ((OgnlRuntime.hasGetProperty(ognlContext, o, name)) || ((o instanceof Map) && ((Map) o).containsKey(name))) {
                         Object value = OgnlRuntime.getProperty(ognlContext, o, name);
 
-                        if (value != null) {
-                            //Ognl.getValue(OgnlUtil.compile((String) name), context, o);
-                            Evaluation currentEvaluation = ognlContext.getCurrentEvaluation();
+                        //Ognl.getValue(OgnlUtil.compile((String) name), context, o);
+                        Evaluation currentEvaluation = ognlContext.getCurrentEvaluation();
 
-                            SimpleNode node = currentEvaluation.getNode();
-                            currentEvaluation.setSource(o);
-                            ognlContext.pushEvaluation(new Evaluation(node, o));
+                        SimpleNode node = currentEvaluation.getNode();
+                        currentEvaluation.setSource(o);
+                        ognlContext.pushEvaluation(new Evaluation(node, o));
 
-                            return value;
-                        }
+                        return value;
                     }
                 } catch (OgnlException e) {
                     if (e.getReason() != null) {

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

  */
 package com.opensymphony.xwork.util;
 
-import ognl.NullHandler;
+import ognl.*;
 
 import java.lang.reflect.Method;
 import java.util.*;
+import java.io.InputStream;
+
+import com.opensymphony.util.FileManager;
 
 
 /**
     private Map clazzMap = new HashMap();
     public static final String CREATE_NULL_OBJECTS = "xwork.NullHandler.createNullObjects";
 
+    HashMap mappings = new HashMap();
+    HashSet noMapping = new HashSet();
+
     //~ Methods ////////////////////////////////////////////////////////////////
 
     public Object nullMethodResult(Map context, Object target, String methodName, Object[] args) {
             return null;
         }
 
-        Map methodMap = getMethodMap(target);
-        Method method = getMethod(methodMap, property.toString(), target);
+        Method method = null;
+        if (target instanceof CompoundRoot) {
+            // sometimes the null object may be at the root, so we need to check all of them
+            CompoundRoot root = (CompoundRoot) target;
+            for (Iterator iterator = root.iterator(); iterator.hasNext();) {
+                Object o = iterator.next();
+                Map methodMap = getMethodMap(o);
+                method = getMethod(methodMap, property.toString(), o);
+
+                if (method != null) {
+                    target = o;
+                    break;
+                }
+            }
+        } else {
+            Map methodMap = getMethodMap(target);
+            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.
 
         try {
             Class clazz = method.getParameterTypes()[0];
-            Object param = createObject(clazz, context);
+            Object param = createObject(context, clazz, target, property.toString());
             method.invoke(target, new Object[]{param});
 
             return param;
         return null;
     }
 
-    private Object createObject(Class clazz, Map context) throws InstantiationException, IllegalAccessException {
+    private Object createObject(Map context, Class clazz, Object target, String property) throws InstantiationException, IllegalAccessException {
         if (clazz == Collection.class || clazz == List.class) {
-            return createNewList(context);
+            return createNewList(target, property);
         } else if (clazz == Set.class) {
 
         } else if (clazz == Map.class) {
         return clazz.newInstance();
     }
 
-    private XWorkList createNewList(Map context) {
-        Class clazz = null;
+    private XWorkList createNewList(Object target, String property) {
+        Class clazz = getCollectionType(target.getClass(), property);
         return new XWorkList(clazz);
     }
 
+    private Map buildConverterMapping(Class clazz) throws Exception {
+        Map mapping = new HashMap();
+
+        String resource = XWorkConverter.buildConverterFilename(clazz);
+        InputStream is = FileManager.loadFile(resource, clazz);
+
+        if (is != null) {
+            Properties props = new Properties();
+            props.load(is);
+            mapping.putAll(props);
+
+            for (Iterator iterator = mapping.entrySet().iterator();
+                    iterator.hasNext();) {
+                Map.Entry entry = (Map.Entry) iterator.next();
+                String propName = (String) entry.getKey();
+                String className = (String) entry.getValue();
+                if (propName.startsWith("Collection_")) {
+                    entry.setValue(Class.forName(className));
+                }
+            }
+
+            mappings.put(clazz, mapping);
+        } else {
+            noMapping.add(clazz);
+        }
+
+        return mapping;
+    }
+
+    private Class getCollectionType(Class clazz, String property) {
+        Class propClass = null;
+        if (!noMapping.contains(clazz)) {
+            try {
+                Map mapping = (Map) mappings.get(clazz);
+
+                if (mapping == null) {
+                    mapping = buildConverterMapping(clazz);
+                } else {
+                    mapping = conditionalReload(clazz, mapping);
+                }
+
+                propClass = (Class) mapping.get("Collection_" + property);
+            } catch (Throwable t) {
+                noMapping.add(clazz);
+            }
+        }
+
+        return propClass;
+    }
+
+    private Map conditionalReload(Class clazz, Map oldValues) throws Exception {
+        Map mapping = oldValues;
+
+        if (FileManager.isReloadingConfigs()) {
+            if (FileManager.fileNeedsReloading(XWorkConverter.buildConverterFilename(clazz))) {
+                mapping = buildConverterMapping(clazz);
+            }
+        }
+
+        return mapping;
+    }
+
+
     /**
      * 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

File src/java/com/opensymphony/xwork/util/XWorkConverter.java

             Class clazz = null;
 
             clazz = target.getClass();
+            Object[] classProp = null;
 
             // this is to handle weird issues with setValue with a different type
             if ((target instanceof CompoundRoot) && (context != null)) {
-                OgnlContext ognlContext = (OgnlContext) context;
-                Evaluation eval = ognlContext.getCurrentEvaluation();
-
-                if (eval == null) {
-                    eval = ognlContext.getLastEvaluation();
-                }
-
-                if ((eval != null) && (eval.getLastChild() != null)) {
-                    // since we changed what the source was (tricked Ognl essentially)
-                    if ((eval.getLastChild().getLastChild() != null) && (eval.getLastChild().getLastChild().getSource() != null) && (eval.getLastChild().getLastChild().getSource().getClass() != CompoundRoot.class)) {
-                        clazz = eval.getLastChild().getLastChild().getSource().getClass();
-                    } else {
-                        clazz = eval.getLastChild().getSource().getClass();
-                    }
-
-                    // ugly hack getting the property, but it works
-                    property = eval.getNode().jjtGetChild(eval.getNode().jjtGetNumChildren() - 1).toString();
+                classProp = getClassProperty(context);
+            }
 
-                    if (property.startsWith("\"") && property.endsWith("\"")) {
-                        property = property.substring(1, property.length() - 1);
-                    }
-                }
+            if (classProp != null) {
+                clazz = (Class) classProp[0];
+                property = (String) classProp[1];
             }
 
             if (!noMapping.contains(clazz)) {
         }
     }
 
+    private Object[] getClassProperty(Map context) {
+        Object[] classProp = null;
+        OgnlContext ognlContext = (OgnlContext) context;
+        Evaluation eval = ognlContext.getCurrentEvaluation();
+
+        if (eval == null) {
+            eval = ognlContext.getLastEvaluation();
+        }
+
+        if ((eval != null) && (eval.getLastChild() != null)) {
+            classProp = new Object[2];
+
+            // since we changed what the source was (tricked Ognl essentially)
+            if ((eval.getLastChild().getLastChild() != null) && (eval.getLastChild().getLastChild().getSource() != null) && (eval.getLastChild().getLastChild().getSource().getClass() != CompoundRoot.class)) {
+                classProp[0] = eval.getLastChild().getLastChild().getSource().getClass();
+            } else {
+                classProp[0] = eval.getLastChild().getSource().getClass();
+            }
+
+            // ugly hack getting the property, but it works
+            String property = eval.getNode().jjtGetChild(eval.getNode().jjtGetNumChildren() - 1).toString();
+
+            if (property.startsWith("\"") && property.endsWith("\"")) {
+                property = property.substring(1, property.length() - 1);
+            }
+
+            classProp[1] = property;
+        }
+
+        return classProp;
+    }
+
     public TypeConverter lookup(String className) {
         if (unknownMappings.contains(className)) {
             return null;
         return null;
     }
 
-    private String buildConverterFilename(Class clazz) {
+    public static String buildConverterFilename(Class clazz) {
         String className = clazz.getName();
         String resource = className.replace('.', '/') + "-conversion.properties";
 

File src/test/com/opensymphony/xwork/util/Foo-conversion.properties

 bar=com.opensymphony.xwork.util.FooBarConverter
-Collection_bars=com.opensymphony.xwork.util.Bar
+Collection_cats=com.opensymphony.xwork.util.Cat

File src/test/com/opensymphony/xwork/util/Foo.java

     boolean useful;
     int number;
     long aLong;
-    List bars;
+    List cats;
 
     //~ Methods ////////////////////////////////////////////////////////////////
 
         return useful;
     }
 
-    public List getBars() {
-        return bars;
+    public List getCats() {
+        return cats;
     }
 
-    public void setBars(List bars) {
-        this.bars = bars;
+    public void setCats(List cats) {
+        this.cats = cats;
     }
 }

File src/test/com/opensymphony/xwork/util/OgnlValueStackTest.java

         assertEquals(123, foo.getChild().getChild().getBar().getSomethingElse());
     }
 
+    public void testSetNullList() {
+        Foo foo = new Foo();
+        OgnlValueStack vs = new OgnlValueStack();
+        vs.getContext().put(InstantiatingNullHandler.CREATE_NULL_OBJECTS, Boolean.TRUE);
+        vs.push(foo);
+
+        vs.setValue("cats[0].name", "Cat One");
+        vs.setValue("cats[1].name", "Cat Two");
+
+        assertNotNull(foo.getCats());
+        assertEquals(2, foo.getCats().size());
+        assertEquals("Cat One", ((Cat) foo.getCats().get(0)).getName());
+        assertEquals("Cat Two", ((Cat) foo.getCats().get(1)).getName());
+
+        vs.setValue("cats[0].foo.cats[1].name", "Deep null cat");
+        assertNotNull(((Cat) foo.getCats().get(0)).getFoo());
+        assertNotNull(((Cat) foo.getCats().get(0)).getFoo().getCats());
+        assertNotNull(((Cat) ((Cat) foo.getCats().get(0)).getFoo().getCats().get(1)));
+        assertEquals("Deep null cat", ((Cat) ((Cat) foo.getCats().get(0)).getFoo().getCats().get(1)).name);
+    }
+
     public void testSettingDogGender() {
         OgnlValueStack vs = new OgnlValueStack();