Commits

tm_jee  committed 1c12edd

Implemented new methods due to upgrade of OGNL to 2.7.x which include enchanced feature (through compilation instead of interpretation)

git-svn-id: http://svn.opensymphony.com/svn/xwork/branches/xwork_1-2@1672e221344d-f017-0410-9bd5-d282ab1896d7

  • Participants
  • Parent commits f01f408
  • Branches xwork_1-2

Comments (0)

Files changed (2)

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

  */
 package com.opensymphony.xwork.util;
 
+import com.opensymphony.xwork.XworkException;
 import ognl.*;
+import ognl.enhance.ExpressionCompiler;
+import ognl.enhance.UnsupportedCompilationException;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
 import java.beans.PropertyDescriptor;
 import java.util.*;
 
-import com.opensymphony.xwork.XworkException;
-
 
 /**
- * A stack that is able to call methods on objects in the stack.
+ * An OGNL property accessor that is able to call methods on objects in the {@link CompoundRoot}.
  *
- * @author $Author$
  * @author Rainer Hermanns
- * @version $Revision$
+ * @author tmjee
+ * @version $Date$ $Id$
  */
 public class CompoundRootAccessor implements PropertyAccessor, MethodAccessor, ClassResolver {
 
     private final static Log log = LogFactory.getLog(CompoundRootAccessor.class);
     private static Map invalidMethods = new HashMap();
 
+    public Class getPropertyClass(OgnlContext ognlcontext, Object target, Object name) {
+        CompoundRoot root = (CompoundRoot) target;
+
+        if (name instanceof Integer) {
+           // this means user probably 'cut' the stack
+            return CompoundRoot.class;
+        }
+        else if (name instanceof String) {
+            String beanName = ((String)name).replaceAll("\"", "");
+
+            try {
+                Integer.valueOf(beanName);
+                return CompoundRoot.class;
+            }
+            catch(NumberFormatException e) { /* ignore, its not a number */ }
+
+            if ("top".equals(beanName)) {
+                if (root.size() > 0 && (root.get(0) != null)) {
+                    return root.get(0).getClass();
+                }
+            }
+            else {
+                // let's go through the root
+                for (Iterator i = root.iterator(); i.hasNext(); ) {
+                    try {
+                        Object tmp = i.next();
+                        if (tmp != null) {
+                            PropertyDescriptor pd = OgnlRuntime.getPropertyDescriptor(tmp.getClass(), beanName);
+                            if (pd != null) {
+                                if (Map.class.isAssignableFrom(pd.getClass())) {
+                                    return Map.class;
+                                }
+                                return pd.getClass();
+                            }
+                        }
+                    }
+                    catch(IntrospectionException e) {
+                        // we'll just try the next one
+                    }
+                    catch(OgnlException e) {
+                        // we'll just try the next one
+                    }
+                }
+            }
+        }
+        return Object.class;  // always fall back to Object.class
+    }
+
+    public String getSourceAccessor(OgnlContext ognlcontext, Object target, Object name) {
+        CompoundRoot root = (CompoundRoot) target;
+
+        if (name instanceof Integer) {
+            return ".cutStack("+name+")";    
+        }
+        else if (name instanceof String) {
+            String beanName = ((String)name).replaceAll("\"", "");
+
+            try {
+                Integer.valueOf(beanName);
+                return ".cutStack("+name+")";
+            }
+            catch(NumberFormatException e) { /* ignore, its not a number */ }
+
+            if ("top".equals(name)) {
+                return ".get(0)";
+            }
+
+
+            int a = 0;
+            for (Iterator i = root.iterator(); i.hasNext(); a++) {
+                try {
+                Object tmp = i.next();
+                    if (tmp != null) {
+                        PropertyDescriptor pd = OgnlRuntime.getPropertyDescriptor(tmp.getClass(), beanName);
+                        if (pd != null) {
+                            if (Map.class.isAssignableFrom(pd.getClass())) {
+
+                                ExpressionCompiler.addCastString(ognlcontext, "(("+Map.class.getName()+")");
+
+                                ognlcontext.setCurrentType(Map.class);
+                                ognlcontext.setCurrentAccessor(CompoundRoot.class);
+
+                                return ".get("+a+")).get(\""+beanName+"\")";
+                            }
+
+                            Class type = OgnlRuntime.getCompiler().getInterfaceClass(pd.getClass());
+
+                            ExpressionCompiler.addCastString(ognlcontext, "((" + type.getName() + ")");
+
+                            ognlcontext.setCurrentType(type);
+                            ognlcontext.setCurrentAccessor(CompoundRoot.class);
+
+                            return ".get("+a+"))."+pd.getReadMethod().getName()+"()";
+                        }
+                    }
+                }
+                catch(IntrospectionException e) {
+                    // ignore, continue with next element
+                }
+                catch(OgnlException e) {
+                    // ignore, continue with next element
+                }
+            }
+        }
+        return "";
+    }
+
+    public String getSourceSetter(OgnlContext ognlcontext, Object target, Object name) {
+
+        CompoundRoot root = (CompoundRoot) target;
+        if (name instanceof String) {
+            String beanName = ((String)name).replaceAll("\"", "");
+
+            int a = 0;
+            for (Iterator i = root.iterator(); i.hasNext(); a++) {
+                try {
+                Object tmp = i.next();
+                    if (tmp != null) {
+                        PropertyDescriptor pd = OgnlRuntime.getPropertyDescriptor(tmp.getClass(), beanName);
+                        if (pd != null) {
+                            if (Map.class.isAssignableFrom(pd.getClass())) {
+
+                                ExpressionCompiler.addCastString(ognlcontext, "(("+Map.class.getName()+")");
+
+                                ognlcontext.setCurrentType(Map.class);
+                                ognlcontext.setCurrentAccessor(CompoundRoot.class);
+
+                                return ".get("+a+")).get(\""+beanName+"\")";
+                            }
+
+                            if (pd.getWriteMethod().getParameterTypes().length > 1) {
+                                 throw new UnsupportedCompilationException("Object property accessors can only support single parameter setters.");
+                            }
+
+                            Class param = pd.getWriteMethod().getParameterTypes()[0];
+                            String conversion = null;
+
+                            if (param.isPrimitive()) {
+                                Class wrapClass = OgnlRuntime.getPrimitiveWrapperClass(param);
+                                conversion = OgnlRuntime.getCompiler().createLocalReference(ognlcontext,
+                                                                            "((" + wrapClass.getName() + ")ognl.OgnlOps#convertValue($3," + wrapClass.getName()
+                                                                            + ".class, true))." + OgnlRuntime.getNumericValueGetter(wrapClass),
+                                                                            param);
+
+                            } else if (param.isArray()) {
+                                conversion = OgnlRuntime.getCompiler().createLocalReference(ognlcontext,
+                                                                            "(" + ExpressionCompiler.getCastString(param) + ")ognl.OgnlOps#toArray($3,"
+                                                                            + param.getComponentType().getName() + ".class)",
+                                                                            param);
+
+                            } else {
+                                conversion = OgnlRuntime.getCompiler().createLocalReference(ognlcontext,
+                                                                            "(" + param.getName()+ ")ognl.OgnlOps#convertValue($3,"
+                                                                            + param.getName()
+                                                                            + ".class)",
+                                                                            param);
+                            }
+
+                            Class type = OgnlRuntime.getCompiler().getInterfaceClass(pd.getWriteMethod().getClass());
+
+                            ExpressionCompiler.addCastString(ognlcontext, "((" + type.getName() + ")");
+
+                            ognlcontext.setCurrentType(type);
+                            ognlcontext.setCurrentAccessor(CompoundRoot.class);
+
+                            return ".get("+a+"))."+pd.getWriteMethod().getName()+"("+conversion+")";
+                        }
+                    }
+                }
+                catch(IntrospectionException e) {
+                    // ignore, continue with next element
+                }
+                catch(OgnlException e) {
+                    // ignore, continue with next element
+                }
+            }
+        }
+        return "";
+    }
 
+    /**
+     * 
+     * @param context
+     * @param target
+     * @param name
+     * @param value
+     * @throws OgnlException
+     */
     public void setProperty(Map context, Object target, Object name, Object value) throws OgnlException {
         CompoundRoot root = (CompoundRoot) target;
         OgnlContext ognlContext = (OgnlContext) context;
                     map.put(name, value);
                     return;
                 }
-//            } catch (OgnlException e) {
-//                if (e.getReason() != null) {
-//                    final String msg = "Caught an Ognl exception while setting property " + name;
-//                    log.error(msg, e);
-//                    throw new XworkException(msg, e.getReason());
-//                }
             } catch (IntrospectionException e) {
                 // this is OK if this happens, we'll just keep trying the next
             }
         }
     }
 
+    /**
+     * 
+     * @param context
+     * @param target
+     * @param name
+     * @return
+     * @throws OgnlException
+     */
     public Object getProperty(Map context, Object target, Object name) throws OgnlException {
         CompoundRoot root = (CompoundRoot) target;
         OgnlContext ognlContext = (OgnlContext) context;

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

 
 package com.opensymphony.xwork.util;
 
+import ognl.OgnlContext;
 import ognl.OgnlException;
 import ognl.OgnlRuntime;
 import ognl.PropertyAccessor;
+import ognl.enhance.ExpressionCompiler;
+import ognl.enhance.UnsupportedCompilationException;
 
+import java.lang.reflect.Method;
 import java.util.Map;
 
 /**
  * Uses Ognl internal.
  *
  * @author Gabe
+ * @author tmjee
  */
 public class ObjectProxyPropertyAccessor implements PropertyAccessor {
+
+
     public Object getProperty(Map context, Object target, Object name) throws OgnlException {
         ObjectProxy proxy = (ObjectProxy) target;
         setupContext(context, proxy);
         OgnlRuntime.getPropertyAccessor(proxy.getValue().getClass()).setProperty(context, target, name, value);
     }
 
+    public Class getPropertyClass(OgnlContext ognlcontext, Object target, Object name) {
+        ObjectProxy proxy = (ObjectProxy) target;
+
+        Object tmp = proxy.getValue();
+        if (tmp != null) {
+            return tmp.getClass();
+        }
+        return Object.class;
+    }
+
+    public String getSourceAccessor(OgnlContext ognlcontext, Object target, Object name) {
+        ObjectProxy proxy = (ObjectProxy) target;
+        Object tmp = proxy.getValue();
+        String beanName = ((String)name).replaceAll("\"", "");
+        
+        if (tmp != null) {
+            Method m = OgnlRuntime.getReadMethod(tmp.getClass(), beanName);
+
+            Class type = OgnlRuntime.getCompiler().getInterfaceClass(proxy.getValue().getClass());
+
+            ExpressionCompiler.addCastString(ognlcontext, "((" + type.getName() + ")");
+
+            ognlcontext.setCurrentType(type);
+            ognlcontext.setCurrentAccessor(ObjectProxy.class);
+
+            return "."+m.getName()+"()";
+        }
+        return "";
+    }
+
+    public String getSourceSetter(OgnlContext ognlcontext, Object target, Object name) {
+        ObjectProxy proxy = (ObjectProxy) target;
+        Object tmp = proxy.getValue();
+        String beanName = ((String)name).replaceAll("\"", "");
+
+        if (tmp != null) {
+            Method m = OgnlRuntime.getWriteMethod(tmp.getClass(), beanName);
+
+            Class type = OgnlRuntime.getCompiler().getInterfaceClass(proxy.getValue().getClass());
+
+            if (m.getParameterTypes().length > 1) {
+                throw new UnsupportedCompilationException("Object property accessors can only support single parameter setters.");
+            }
+
+            Class param = m.getParameterTypes()[0];
+            String conversion = null;
+
+            if (param.isPrimitive()) {
+                Class wrapClass = OgnlRuntime.getPrimitiveWrapperClass(param);
+                conversion = OgnlRuntime.getCompiler().createLocalReference(ognlcontext,
+                                      "((" + wrapClass.getName() + ")ognl.OgnlOps#convertValue($3," + wrapClass.getName()
+                                      + ".class, true))." + OgnlRuntime.getNumericValueGetter(wrapClass),
+                                      param);
+
+            } else if (param.isArray()) {
+                                      conversion = OgnlRuntime.getCompiler().createLocalReference(ognlcontext,
+                                      "(" + ExpressionCompiler.getCastString(param) + ")ognl.OgnlOps#toArray($3,"
+                                      + param.getComponentType().getName() + ".class)",
+                                      param);
+            } else {
+                                      conversion = OgnlRuntime.getCompiler().createLocalReference(ognlcontext,
+                                      "(" + param.getName()+ ")ognl.OgnlOps#convertValue($3,"
+                                      + param.getName()
+                                      + ".class)",
+                                      param);
+            }
+
+
+            ExpressionCompiler.addCastString(ognlcontext, "((" + type.getName() + ")");
+
+            ognlcontext.setCurrentType(type);
+            ognlcontext.setCurrentAccessor(ObjectProxy.class);
+
+            return "."+m.getName()+"("+conversion+")";
+        }
+        return "";
+    }
+
     /**
      * Sets up the context with the last property and last class
      * accessed.