Commits

Anonymous committed ee37a71

Various ports of XWork 1.2.x fixes to XWork 2.0

Issue Number: XW-437

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

Comments (0)

Files changed (9)

src/java/com/opensymphony/xwork2/util/DomHelper.java

 
 import java.util.Map;
 
-import com.opensymphony.xwork2.util.ClassLoaderUtil;
-
 import com.opensymphony.xwork2.util.location.Location;
 import com.opensymphony.xwork2.util.location.LocationAttributes;
 import com.opensymphony.xwork2.XWorkException;
+import com.opensymphony.xwork2.ObjectFactory;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
     /**
      * Creates a W3C Document that remembers the location of each element in
      * the source file. The location of element nodes can then be retrieved
-     * using the {@link #getLocation(Element)} method.
+     * using the {@link #getLocationObject(Element)} method.
      *
      * @param inputSource the inputSource to read the document from
      */
     /**
      * Creates a W3C Document that remembers the location of each element in
      * the source file. The location of element nodes can then be retrieved
-     * using the {@link #getLocation(Element)} method.
+     * using the {@link #getLocationObject(Element)} method.
      *
      * @param inputSource the inputSource to read the document from
      * @param dtdMappings a map of DTD names and public ids
      */
     public static Document parse(InputSource inputSource, Map dtdMappings) {
                 
-        SAXParserFactory factory = SAXParserFactory.newInstance();
+        SAXParserFactory factory = null;
+        String parserProp = System.getProperty("xwork.saxParserFactory");
+        if (parserProp != null) {
+            try {
+                Class clazz = ObjectFactory.getObjectFactory().getClassInstance(parserProp);
+                factory = (SAXParserFactory) clazz.newInstance();
+            }
+            catch (ClassNotFoundException e) {
+                LOG.error("Unable to load saxParserFactory set by system property 'xwork.saxParserFactory': " + parserProp, e);
+            }
+            catch (Exception e) {
+                LOG.error("Unable to load saxParserFactory set by system property 'xwork.saxParserFactory': " + parserProp, e);
+            }
+        }
+
+        if (factory == null) {
+            factory = SAXParserFactory.newInstance();
+        }
+
         factory.setValidating((dtdMappings != null));
         factory.setNamespaceAware(true);
         
     static public class DOMBuilder implements ContentHandler {
     
         /** The default transformer factory shared by all instances */
-        protected static final SAXTransformerFactory FACTORY = (SAXTransformerFactory) TransformerFactory.newInstance();
+        protected static SAXTransformerFactory FACTORY;
     
         /** The transformer factory */
         protected SAXTransformerFactory factory;
         
         protected ContentHandler nextHandler;
     
+        static {
+            String parserProp = System.getProperty("xwork.saxTransformerFactory");
+            if (parserProp != null) {
+                try {
+                    Class clazz = ObjectFactory.getObjectFactory().getClassInstance(parserProp);
+                    FACTORY = (SAXTransformerFactory) clazz.newInstance();
+                }
+                catch (ClassNotFoundException e) {
+                    LOG.error("Unable to load SAXTransformerFactory set by system property 'xwork.saxTransformerFactory': " + parserProp, e);
+                }
+                catch (Exception e) {
+                    LOG.error("Unable to load SAXTransformerFactory set by system property 'xwork.saxTransformerFactory': " + parserProp, e);
+                }
+            }
+
+            if (FACTORY == null) {
+                 FACTORY = (SAXTransformerFactory) TransformerFactory.newInstance();
+            }
+        }
+
         /**
          * Construct a new instance of this DOMBuilder.
          */

src/java/com/opensymphony/xwork2/util/EnumTypeConverter.java

+/*
+ * Copyright (c) 2002-2006 by OpenSymphony
+ * All rights reserved.
+ */
+
+package com.opensymphony.xwork2.util;
+
+import ognl.DefaultTypeConverter;
+
+import java.util.Map;
+
+/**
+ * <code>EnumTypeConverter</code>
+ *
+ * <!-- START SNIPPET: description -->
+ * This class converts java 5 enums to String and from String[] to enum.
+ * <p/>
+ * One of Java 5's improvements is providing enumeration facility.
+ * Up to now, there existed no enumerations. The only way to simulate was the so-called int Enum pattern:
+ * {code}
+ * public static final int SEASON_WINTER = 0;
+ * public static final int SEASON_SPRING = 1;
+ * public static final int SEASON_SUMMER = 2;
+ * public static final int SEASON_FALL   = 3;
+ * {code}
+ * <p/>
+ * Java 5.0 now provides the following construct:
+ * {code}
+ * public static enum Season { WINTER, SPRING, SUMMER, FALL };
+ * {code}
+ * <!-- END SNIPPET: description -->
+ *
+ * <!-- START SNIPPET: example -->
+ * h3. Implementing Java 5 Enumeration Type Conversion
+ * <p/>
+ * 1. myAction-conversion.properties*
+ * <p/>
+ * Place a myAction-conversion.properties-file in the path of your Action.
+ * Add the following entry to the properties-file:
+ * {code}
+ * nameOfYourField=fullyClassifiedNameOfYourConverter
+ * {code}
+ * &nbsp;
+ * <p/>
+ * 2. myAction.java*
+ * Your action contains the _enumeration_:
+ * {code}
+ * public enum Criticality {DEBUG, INFO, WARNING, ERROR, FATAL}
+ * {code}
+ * &nbsp;
+ * * Your action contains the _private field_:
+ * {code}
+ * private myEnum myFieldForEnum;
+ * {code}
+ * &nbsp;
+ * Your action contains _getters and setters_ for your field:
+ * {code}
+ * public myEnum getCriticality() {
+ *         return myFieldForEnum;
+ *     }
+ *
+ *     public void setCriticality(myEnum myFieldForEnum) {
+ *         this.myFieldForEnum= myFieldForEnum;
+ *     }
+ * {code}
+ * <p/>
+ * 3. JSP*
+ * <p/>
+ * &nbsp;&nbsp;&nbsp; In your jsp you can access an enumeration value just normal by using the known <ww:property>-Tag:
+ * {code}
+ * <ww:property value="myField"/>
+ * {code}
+ * <!-- END SNIPPET: example -->
+ *
+ * @author Tamara Cattivelli
+ * @author <a href="mailto:hermanns@aixcept.de">Rainer Hermanns</a>
+ * @version $Id: EnumTypeConverter.java 1050 2006-06-26 21:46:27 +0200 (Mon, 26 Jun 2006) rainerh $
+ */
+public class EnumTypeConverter extends DefaultTypeConverter {
+
+    /**
+     * Converts the given object to a given type. How this is to be done is implemented in toClass. The OGNL context, o
+     * and toClass are given. This method should be able to handle conversion in general without any context or object
+     * specified.
+     *
+     * @param context - OGNL context under which the conversion is being done
+     * @param o       - the object to be converted
+     * @param toClass - the class that contains the code to convert to enumeration
+     * @return Converted value of type declared in toClass or TypeConverter.NoConversionPossible to indicate that the
+     *         conversion was not possible.
+     */
+    public Object convertValue(Map context, Object o, Class toClass) {
+        if (o instanceof String[]) {
+            return convertFromString(((String[]) o)[0], toClass);
+        } else if (o instanceof String) {
+            return convertFromString((String) o, toClass);
+        }
+
+        return super.convertValue(context, o, toClass);
+    }
+
+    /**
+     * Converts one or more String values to the specified class.
+     * @param value - the String values to be converted, such as those submitted from an HTML form
+     * @param toClass - the class to convert to
+     * @return the converted object
+     */
+    public java.lang.Enum convertFromString(String value, Class toClass) {
+        return Enum.valueOf(toClass, value);
+    }
+
+}

src/java/com/opensymphony/xwork2/util/XWorkConverter.java

                 LOG.debug("field-level type converter for property ["+property+"] = "+(tc==null?"none found":tc));
         }
         
+        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);
+            Class clazz = (Class) context.get(XWorkConverter.LAST_BEAN_CLASS_ACCESSED);
+            if (lastPropertyPath != null && clazz != null) {
+                String path = lastPropertyPath + "." + property;
+                tc = (TypeConverter) getConverter(clazz, path);
+            }
+        }
 
         if (tc == null) {
             if (toClass.equals(String.class) && (value != null) && !(value.getClass().equals(String.class) || value.getClass().equals(String[].class)))

src/test/com/opensymphony/xwork2/GenericsBean.java

 package com.opensymphony.xwork2;
 
 import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.ArrayList;
 
 /**
  * <code>GenericsBean</code>
  * @version $Id$
  */
 public class GenericsBean {
-
-    private List<Double> doubles;
+    private List<Double> blubb;
+    private List<Double> getterList;
+    private Map<Double, Integer> genericMap = new HashMap<Double, Integer>();
+    private Map<Double, List<Integer>> extendedMap = new HashMap<Double, List<Integer>>();
 
     /**
      * @return Returns the doubles.
      */
     public List<Double> getDoubles() {
-        return doubles;
+        return blubb;
     }
 
     /**
      * @param doubles The doubles to set.
      */
     public void setDoubles(List<Double> doubles) {
-        this.doubles = doubles;
+        this.blubb = doubles;
+    }
+
+    public Map<Double, Integer> getGenericMap() {
+        return genericMap;
+    }
+
+    public void setGenericMap(Map<Double, Integer> genericMap) {
+        this.genericMap = genericMap;
+    }
+
+    public List<Double> getGetterList() {
+        if ( getterList == null ) {
+            getterList = new ArrayList<Double>(1);
+            getterList.add(42.42);
+        }
+        return getterList;
+    }
+
+    public Map<Double, List<Integer>> getExtendedMap() {
+        return extendedMap;
+    }
+
+    public void setExtendedMap(Map<Double, List<Integer>> extendedMap) {
+        this.extendedMap = extendedMap;
     }
 }

src/test/com/opensymphony/xwork2/util/AnnotationXWorkConverterTest.java

         assertEquals(new Double(123.45), gb.getDoubles().get(1));
     }
 
+    public void testGenericPropertiesFromField() {
+        GenericsBean gb = new GenericsBean();
+        ValueStack stack = ac.getValueStack();
+        stack.push(gb);
+
+        stack.setValue("genericMap[123.12]", "66");
+        stack.setValue("genericMap[456.12]", "42");
+
+        assertEquals(2, gb.getGenericMap().size());
+        assertEquals(Integer.class, stack.findValue("genericMap.get(123.12).class"));
+        assertEquals(Integer.class, stack.findValue("genericMap.get(456.12).class"));
+        assertEquals(66, stack.findValue("genericMap.get(123.12)"));
+        assertEquals(42, stack.findValue("genericMap.get(456.12)"));
+        assertEquals(true, stack.findValue("genericMap.containsValue(66)"));
+        assertEquals(true, stack.findValue("genericMap.containsValue(42)"));
+        assertEquals(true, stack.findValue("genericMap.containsKey(123.12)"));
+        assertEquals(true, stack.findValue("genericMap.containsKey(456.12)"));
+    }
+
+    public void testGenericPropertiesFromSetter() {
+        GenericsBean gb = new GenericsBean();
+        ValueStack stack = ac.getValueStack();
+        stack.push(gb);
+
+        stack.setValue("genericMap[123.12]", "66");
+        stack.setValue("genericMap[456.12]", "42");
+
+        assertEquals(2, gb.getGenericMap().size());
+        assertEquals(Integer.class, stack.findValue("genericMap.get(123.12).class"));
+        assertEquals(Integer.class, stack.findValue("genericMap.get(456.12).class"));
+        assertEquals(66, stack.findValue("genericMap.get(123.12)"));
+        assertEquals(42, stack.findValue("genericMap.get(456.12)"));
+        assertEquals(true, stack.findValue("genericMap.containsValue(66)"));
+        assertEquals(true, stack.findValue("genericMap.containsValue(42)"));
+        assertEquals(true, stack.findValue("genericMap.containsKey(123.12)"));
+        assertEquals(true, stack.findValue("genericMap.containsKey(456.12)"));
+    }
+
+    public void testGenericPropertiesFromGetter() {
+        GenericsBean gb = new GenericsBean();
+        ValueStack stack = ac.getValueStack();
+        stack.push(gb);
+
+        assertEquals(1, gb.getGetterList().size());
+        assertEquals(Double.class, stack.findValue("getterList.get(0).class"));
+        assertEquals(new Double(42.42), stack.findValue("getterList.get(0)"));
+        assertEquals(new Double(42.42), gb.getGetterList().get(0));
+
+    }
+
+
+    // FIXME: Implement nested Generics such as: List of Generics List, Map of Generic keys/values, etc...
+    public void no_testGenericPropertiesWithNestedGenerics() {
+        GenericsBean gb = new GenericsBean();
+        ValueStack stack = ac.getValueStack();
+        stack.push(gb);
+
+        stack.setValue("extendedMap[123.12]", new String[] {"1", "2", "3", "4"});
+        stack.setValue("extendedMap[456.12]", new String[] {"5", "6", "7", "8", "9"});
+
+        System.out.println("gb.getExtendedMap(): " + gb.getExtendedMap());
+
+        assertEquals(2, gb.getExtendedMap().size());
+        assertEquals(4, stack.findValue("extendedMap.get(123.12).size"));
+        assertEquals(5, stack.findValue("extendedMap.get(456.12).size"));
+        assertEquals(List.class, stack.findValue("extendedMap.get(123.12).class"));
+        assertEquals(List.class, stack.findValue("extendedMap.get(456.12).class"));
+    }
+
     public static class Foo1 {
         public Bar1 getBar() {
             return new Bar1Impl();

src/test/com/opensymphony/xwork2/util/Cat-conversion.properties

 Collection_kittens = com.opensymphony.xwork2.util.Cat
+foo.number = com.opensymphony.xwork2.util.FooNumberConverter

src/test/com/opensymphony/xwork2/util/Foo.java

     }
 
     /**
-     * @param catSet The catSet to set.
+     * @param barCollection The barCollection to set.
      */
     public void setBarCollection(Collection barCollection) {
         this.barCollection = barCollection;

src/test/com/opensymphony/xwork2/util/FooNumberConverter.java

+package com.opensymphony.xwork2.util;
+
+import ognl.DefaultTypeConverter;
+
+import java.util.Map;
+
+public class FooNumberConverter extends DefaultTypeConverter {
+    public Object convertValue(Map map, Object object, Class aClass) {
+        String s = (String) object;
+
+        int length = s.length();
+        StringBuffer r = new StringBuffer();
+        for (int i = length; i > 0; i--) {
+            r.append(s.charAt(i - 1));
+        }
+
+        return super.convertValue(map, r.toString(), aClass);
+    }
+}

src/test/com/opensymphony/xwork2/util/XWorkConverterTest.java

         assertNotNull(bar);
     }
 
+    public void testNestedConverters() {
+        OgnlValueStack stack = new OgnlValueStack();
+        Cat cat = new Cat();
+        cat.setFoo(new Foo());
+        stack.push(cat);
+        stack.setValue("foo.number", "123");
+        assertEquals(321, cat.getFoo().getNumber());
+    }
+
     public static class Foo1 {
         public Bar1 getBar() {
             return new Bar1Impl();