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));
+ }
+ }
+
}