You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by rd...@apache.org on 2011/06/03 09:37:39 UTC

svn commit: r1130922 - in /myfaces/test/trunk/test12/src: main/java/org/apache/myfaces/test/el/ main/java/org/apache/myfaces/test/mock/ test/java/org/apache/myfaces/test/el/

Author: rdebusscher
Date: Fri Jun  3 07:37:38 2011
New Revision: 1130922

URL: http://svn.apache.org/viewvc?rev=1130922&view=rev
Log:
MYFACESTEST-55: MockValueExpression cannot handle list/array indices. Thx to Matt Benson

Added:
    myfaces/test/trunk/test12/src/main/java/org/apache/myfaces/test/el/ExpressionTokenizer.java
Modified:
    myfaces/test/trunk/test12/src/main/java/org/apache/myfaces/test/el/MockValueExpression.java
    myfaces/test/trunk/test12/src/main/java/org/apache/myfaces/test/mock/MockPropertyResolver.java
    myfaces/test/trunk/test12/src/test/java/org/apache/myfaces/test/el/MockValueExpressionTest.java

Added: myfaces/test/trunk/test12/src/main/java/org/apache/myfaces/test/el/ExpressionTokenizer.java
URL: http://svn.apache.org/viewvc/myfaces/test/trunk/test12/src/main/java/org/apache/myfaces/test/el/ExpressionTokenizer.java?rev=1130922&view=auto
==============================================================================
--- myfaces/test/trunk/test12/src/main/java/org/apache/myfaces/test/el/ExpressionTokenizer.java (added)
+++ myfaces/test/trunk/test12/src/main/java/org/apache/myfaces/test/el/ExpressionTokenizer.java Fri Jun  3 07:37:38 2011
@@ -0,0 +1,187 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.myfaces.test.el;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.text.ParsePosition;
+import java.util.ArrayList;
+
+/**
+ * Expression Tokenizer
+ */
+class ExpressionTokenizer
+{
+    private ExpressionTokenizer()
+    {
+    }
+
+    public static String[] tokenize(CharSequence expr)
+    {
+        final ArrayList<String> tokens = new ArrayList<String>();
+        ParsePosition pos = new ParsePosition(0);
+        int len = expr.length();
+        boolean sep = true;
+        while (pos.getIndex() < len)
+        {
+            int here = pos.getIndex();
+            char c = expr.charAt(here);
+            switch (c)
+            {
+            case ' ':
+                next(pos);
+                break;
+            case ']':
+                throw new IllegalStateException(String.format("Position %s: unexpected '%s'", here, c));
+            case '[':
+                tokens.add(parseIndex(expr, next(pos)));
+                break;
+            case '.':
+                if (sep)
+                {
+                    throw new IllegalStateException(String.format(
+                        "Position %s: expected property, index/key, or end of expression", here));
+                }
+                sep = true;
+                next(pos);
+                // fall through:
+            default:
+                if (!sep)
+                {
+                    throw new IllegalStateException(String.format(
+                        "Position %s: expected property path separator, index/key, or end of expression", here));
+                }
+                tokens.add(parseProperty(expr, pos));
+            }
+            sep = false;
+        }
+        return tokens.toArray(new String[tokens.size()]);
+    }
+
+    private static ParsePosition next(ParsePosition pos)
+    {
+        pos.setIndex(pos.getIndex() + 1);
+        return pos;
+    }
+
+    private static String parseProperty(CharSequence expr, ParsePosition pos)
+    {
+        int len = expr.length();
+        int start = pos.getIndex();
+        loop: while (pos.getIndex() < len)
+        {
+            switch (expr.charAt(pos.getIndex()))
+            {
+            case '[':
+            case ']':
+            case '.':
+                break loop;
+            }
+            next(pos);
+        }
+        if (pos.getIndex() > start)
+        {
+            return expr.subSequence(start, pos.getIndex()).toString();
+        }
+        throw new IllegalStateException(String.format("Position %s: expected property", start));
+    }
+
+    /**
+     * Handles an index/key. If the text contained between [] is surrounded by a
+     * pair of " or ', these will be stripped.
+     * 
+     * @param expr Expression string to tokenize
+     * @param pos current position of parser, will be updated by the method.
+     * @return token found on the position
+     */
+    private static String parseIndex(CharSequence expr, ParsePosition pos)
+    {
+        int len = expr.length();
+        int start = pos.getIndex();
+        if (start < len)
+        {
+            char first = expr.charAt(pos.getIndex());
+            if (first == '"' || first == '\'')
+            {
+                String s = parseQuotedString(expr, pos);
+                if (s != null && expr.charAt(pos.getIndex()) == ']')
+                {
+                    next(pos);
+                    return s;
+                }
+            }
+            // no quoted string; match ] greedily and trim
+            while (pos.getIndex() < len)
+            {
+                int here = pos.getIndex();
+                try
+                {
+                    if (expr.charAt(here) == ']')
+                    {
+                        return expr.subSequence(start, here).toString().trim();
+                    }
+                } finally
+                {
+                    next(pos);
+                }
+            }
+        }
+        throw new IllegalStateException(String.format("Position %s: unparsable index", start));
+    }
+
+    private static String parseQuotedString(CharSequence expr, ParsePosition pos)
+    {
+        int len = expr.length();
+        int start = pos.getIndex();
+        if (start < len)
+        {
+            char quote = expr.charAt(start);
+            next(pos);
+            StringWriter w = new StringWriter();
+            while (pos.getIndex() < len)
+            {
+                int here = pos.getIndex();
+                char c = expr.charAt(here);
+                boolean esc = false;
+                if (c == '\\' && here + 1 < len && expr.charAt(here + 1) == quote)
+                {
+                    esc = true;
+                    here = next(pos).getIndex();
+                }
+                try
+                {
+                    // look for matching quote
+                    if (c == quote && !esc)
+                    {
+                        return w.toString();
+                    }
+                    w.write(Character.toChars(Character.codePointAt(expr, here)));
+                } catch (IOException e)
+                {
+                    throw new RuntimeException(e);
+                } finally
+                {
+                    next(pos);
+                }
+            }
+            // if reached, reset due to no ending quote found
+            pos.setIndex(start);
+        }
+        return null;
+    }
+
+}

Modified: myfaces/test/trunk/test12/src/main/java/org/apache/myfaces/test/el/MockValueExpression.java
URL: http://svn.apache.org/viewvc/myfaces/test/trunk/test12/src/main/java/org/apache/myfaces/test/el/MockValueExpression.java?rev=1130922&r1=1130921&r2=1130922&view=diff
==============================================================================
--- myfaces/test/trunk/test12/src/main/java/org/apache/myfaces/test/el/MockValueExpression.java (original)
+++ myfaces/test/trunk/test12/src/main/java/org/apache/myfaces/test/el/MockValueExpression.java Fri Jun  3 07:37:38 2011
@@ -17,8 +17,6 @@
 
 package org.apache.myfaces.test.el;
 
-import java.util.ArrayList;
-import java.util.List;
 import javax.el.ELContext;
 import javax.el.ELResolver;
 import javax.el.ValueExpression;
@@ -290,49 +288,7 @@ public class MockValueExpression extends
         {
             if (expression.endsWith("}"))
             {
-                List names = new ArrayList();
-                StringBuffer expr = new StringBuffer(expression.substring(2,
-                        expression.length() - 1).replaceAll(" ", ""));
-                boolean isBlockOn = false;
-                for (int i = expr.length() - 1; i > -1; i--)
-                {
-                    if (expr.charAt(i) == ' ')
-                    {
-                        expr.deleteCharAt(i);
-                    }
-                    else if (expr.charAt(i) == ']')
-                    {
-                        expr.deleteCharAt(i);
-                    }
-                    else if (expr.charAt(i) == '[')
-                    {
-                        expr.deleteCharAt(i);
-                    }
-                    else if (expr.charAt(i) == '\'')
-                    {
-                        if (!isBlockOn)
-                        {
-                            expr.deleteCharAt(i);
-                        }
-                        else
-                        {
-                            names.add(0, expr.substring(i + 1));
-                            expr.delete(i, expr.length());
-                        }
-                        isBlockOn = !isBlockOn;
-                    }
-                    else if (expr.charAt(i) == '.' && !isBlockOn)
-                    {
-                        names.add(0, expr.substring(i + 1));
-                        expr.delete(i, expr.length());
-                    }
-                }
-                if (expr.length() > 0)
-                {
-                    names.add(0, expr.toString());
-                }
-
-                elements = (String[]) names.toArray(new String[names.size()]);
+                elements = ExpressionTokenizer.tokenize(expression.substring(2, expression.length() - 1));
             }
             else
             {

Modified: myfaces/test/trunk/test12/src/main/java/org/apache/myfaces/test/mock/MockPropertyResolver.java
URL: http://svn.apache.org/viewvc/myfaces/test/trunk/test12/src/main/java/org/apache/myfaces/test/mock/MockPropertyResolver.java?rev=1130922&r1=1130921&r2=1130922&view=diff
==============================================================================
--- myfaces/test/trunk/test12/src/main/java/org/apache/myfaces/test/mock/MockPropertyResolver.java (original)
+++ myfaces/test/trunk/test12/src/main/java/org/apache/myfaces/test/mock/MockPropertyResolver.java Fri Jun  3 07:37:38 2011
@@ -21,7 +21,9 @@ import java.beans.BeanInfo;
 import java.beans.IntrospectionException;
 import java.beans.Introspector;
 import java.beans.PropertyDescriptor;
+import java.lang.reflect.Array;
 import java.lang.reflect.InvocationTargetException;
+import java.util.List;
 import java.util.Map;
 import javax.faces.el.EvaluationException;
 import javax.faces.el.PropertyNotFoundException;
@@ -87,6 +89,13 @@ public class MockPropertyResolver extend
             throws PropertyNotFoundException
     {
 
+        if (base instanceof List) {
+            List l = (List) base;
+            return index < l.size() ? l.get(index) : null;
+        }
+        if (base != null && base.getClass().isArray()) {
+            return index < Array.getLength(base) ? Array.get(base, index) : null;
+        }
         return getValue(base, "" + index);
 
     }
@@ -127,6 +136,21 @@ public class MockPropertyResolver extend
             throws PropertyNotFoundException
     {
 
+        if (base instanceof List) {
+            List l = (List) base;
+            if (index > l.size()) {
+                throw new PropertyNotFoundException();
+            }
+            l.set(index, value);
+            return;
+        }
+        if (base != null && base.getClass().isArray()) {
+            if (index < Array.getLength(base)) {
+                Array.set(base, index, value);
+                return;
+            }
+            throw new PropertyNotFoundException();
+        }
         setValue(base, "" + index, value);
 
     }
@@ -191,6 +215,25 @@ public class MockPropertyResolver extend
             throws PropertyNotFoundException
     {
 
+        if (base instanceof List)
+        {
+            if (index < ((List) base).size())
+            {
+                Object element = getValue(base, index);
+                return element == null ? null : element.getClass();
+            }
+            throw new PropertyNotFoundException();
+        }
+        if (base != null && base.getClass().isArray())
+        {
+            if (index < Array.getLength(base))
+            {
+                Object element = Array.get(base, index);
+                return element != null ? element.getClass()
+                    : base.getClass().getComponentType();
+            }
+            throw new PropertyNotFoundException();
+        }
         return getType(base, "" + index);
 
     }

Modified: myfaces/test/trunk/test12/src/test/java/org/apache/myfaces/test/el/MockValueExpressionTest.java
URL: http://svn.apache.org/viewvc/myfaces/test/trunk/test12/src/test/java/org/apache/myfaces/test/el/MockValueExpressionTest.java?rev=1130922&r1=1130921&r2=1130922&view=diff
==============================================================================
--- myfaces/test/trunk/test12/src/test/java/org/apache/myfaces/test/el/MockValueExpressionTest.java (original)
+++ myfaces/test/trunk/test12/src/test/java/org/apache/myfaces/test/el/MockValueExpressionTest.java Fri Jun  3 07:37:38 2011
@@ -18,6 +18,8 @@
  */
 package org.apache.myfaces.test.el;
 
+import java.util.ArrayList;
+
 import javax.el.ELContext;
 import javax.el.ValueExpression;
 
@@ -72,7 +74,6 @@ public class MockValueExpressionTest ext
         assertEquals("test BAR", value);
     }
 
-
     public void testGetType()
     {
         // set value of #{foo} to BAR in request scope
@@ -97,4 +98,20 @@ public class MockValueExpressionTest ext
         assertEquals(String.class, value);
     }
 
+    public void testGetIndexedValue() {
+        ArrayList<String> strings = new ArrayList<String>();
+        strings.add("foo");
+        strings.add("bar");
+        strings.add("baz");
+        externalContext.getRequestMap().put("strings", strings);
+        ELContext elContext = facesContext.getELContext();
+        for (int i = 0, sz = strings.size(); i < sz; i++) {
+            ValueExpression ve =
+                application.getExpressionFactory()
+                    .createValueExpression(elContext,
+                        String.format("#{strings[%s]}", i), String.class);
+            assertEquals(strings.get(i), ve.getValue(elContext));
+        }
+    }
+
 }