You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by pe...@apache.org on 2016/09/21 01:09:54 UTC

wicket git commit: WICKET-4008 parser differentiates java identifiers from bean properties

Repository: wicket
Updated Branches:
  refs/heads/WICKET-4008-property-expression-parser b0f7da85e -> 697052f71


WICKET-4008 parser differentiates java identifiers from bean properties


Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/697052f7
Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/697052f7
Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/697052f7

Branch: refs/heads/WICKET-4008-property-expression-parser
Commit: 697052f713345484b93f4ef61163587473b7b202
Parents: b0f7da8
Author: Pedro Henrique Oliveira dos Santos <pe...@apache.org>
Authored: Tue Sep 20 22:09:36 2016 -0300
Committer: Pedro Henrique Oliveira dos Santos <pe...@apache.org>
Committed: Tue Sep 20 22:09:36 2016 -0300

----------------------------------------------------------------------
 .../core/util/lang/PropertyExpression.java      | 70 ++++++++++++++---
 .../util/lang/PropertyExpressionParser.java     | 69 ++++++++++------
 .../util/lang/PropertyExpressionParserTest.java | 82 +++++++++++---------
 .../wicket/util/lang/PropertyResolverTest.java  | 10 ++-
 4 files changed, 160 insertions(+), 71 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/697052f7/wicket-core/src/main/java/org/apache/wicket/core/util/lang/PropertyExpression.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/core/util/lang/PropertyExpression.java b/wicket-core/src/main/java/org/apache/wicket/core/util/lang/PropertyExpression.java
index 635f95e..dab79ec 100644
--- a/wicket-core/src/main/java/org/apache/wicket/core/util/lang/PropertyExpression.java
+++ b/wicket-core/src/main/java/org/apache/wicket/core/util/lang/PropertyExpression.java
@@ -18,21 +18,76 @@ package org.apache.wicket.core.util.lang;
 
 public class PropertyExpression
 {
-	Property property;
+	JavaProperty javaProperty;
+	BeanProperty beanProperty;
 	CharSequence index;
 	PropertyExpression next;
 
-	static class Property
+	static class BeanProperty
+	{
+		CharSequence propertyName;
+		CharSequence index;
+
+		public BeanProperty()
+		{
+		}
+
+		public BeanProperty(String name, String index)
+		{
+			this.propertyName = name;
+			this.index = index;
+		}
+
+		@Override
+		public int hashCode()
+		{
+			final int prime = 31;
+			int result = 1;
+			result = prime * result + ((index == null) ? 0 : index.hashCode());
+			result = prime * result + ((propertyName == null) ? 0 : propertyName.hashCode());
+			return result;
+		}
+
+		@Override
+		public boolean equals(Object obj)
+		{
+			if (this == obj)
+				return true;
+			if (obj == null)
+				return false;
+			if (getClass() != obj.getClass())
+				return false;
+			BeanProperty other = (BeanProperty)obj;
+			if (index == null)
+			{
+				if (other.index != null)
+					return false;
+			}
+			else if (!index.equals(other.index))
+				return false;
+			if (propertyName == null)
+			{
+				if (other.propertyName != null)
+					return false;
+			}
+			else if (!propertyName.equals(other.propertyName))
+				return false;
+			return true;
+		}
+
+	}
+
+	static class JavaProperty
 	{
 		CharSequence javaIdentifier;
 		CharSequence index;
 		public boolean hasMethodSign;
 
-		public Property()
+		public JavaProperty()
 		{
 		}
 
-		public Property(String javaIdentifier, String index, boolean hasMethodSign)
+		public JavaProperty(String javaIdentifier, String index, boolean hasMethodSign)
 		{
 			this.javaIdentifier = javaIdentifier;
 			this.index = index;
@@ -59,7 +114,7 @@ public class PropertyExpression
 				return false;
 			if (getClass() != obj.getClass())
 				return false;
-			Property other = (Property)obj;
+			JavaProperty other = (JavaProperty)obj;
 			if (hasMethodSign != other.hasMethodSign)
 				return false;
 			if (index == null)
@@ -79,11 +134,6 @@ public class PropertyExpression
 			return true;
 		}
 
-		@Override
-		public String toString()
-		{
-			return javaIdentifier + (index == null ? "" : "[" + index + "]");
-		}
 	}
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/wicket/blob/697052f7/wicket-core/src/main/java/org/apache/wicket/core/util/lang/PropertyExpressionParser.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/core/util/lang/PropertyExpressionParser.java b/wicket-core/src/main/java/org/apache/wicket/core/util/lang/PropertyExpressionParser.java
index 3ecb81e..2102456 100644
--- a/wicket-core/src/main/java/org/apache/wicket/core/util/lang/PropertyExpressionParser.java
+++ b/wicket-core/src/main/java/org/apache/wicket/core/util/lang/PropertyExpressionParser.java
@@ -20,25 +20,25 @@ import static java.lang.Character.isJavaIdentifierPart;
 import static java.lang.Character.isJavaIdentifierStart;
 import static java.lang.String.format;
 
-import org.apache.wicket.core.util.lang.PropertyExpression.Property;
+import org.apache.wicket.core.util.lang.PropertyExpression.BeanProperty;
+import org.apache.wicket.core.util.lang.PropertyExpression.JavaProperty;
 
 /**
  * EBNF like description of the property expression syntax <code>
  * 
- *  java letter				= "_" | "$" | "A" | "a" | "B" | "b" | (...) ;
+ *  java letter				= "_" | "$" | "A" | "a" | "B" | "b" | (...);
  *  java letter or digit	= java letter | "0" | "1" | (...) ;
  *  char					= java letter or digit | "." | "(" | ")" | "[" | "]" | "!" | "@" | "#" | (...);
- *  index char				= char - "]"
+ *  index char				= char - "]";
  *  
- *  java identifier			= java letter , {java letter or digit}
- *  property name			= java letter or digit , {java letter or digit}
- *  method sign				= "(" , { " " } , ")"
- *  index					= "[" , index char , {index char} , "]" ;
+ *  java identifier			= java letter , {java letter or digit};
+ *  property name			= java letter or digit , {java letter or digit};
+ *  method sign				= "(" , { " " } , ")";
+ *  index					= "[" , index char , { index char } , "]";
  *  
- *  bean property			= property name, [ index ]
- *  java property			= java identifier , [ index | method sign ]
- *  map property			= index
- *  property expression		= [ bean property | java property | map property ], { "." , property expression } ;
+ *  bean property			= property name, [ index ];
+ *  java property			= java identifier , [ index | method sign ];
+ *  property expression		= [ bean property | java property | index ] , { "." , property expression };
  *  
  * </code>
  * 
@@ -99,9 +99,17 @@ public class PropertyExpressionParser
 		{
 			expression.index = index();
 		}
+		else if (Character.isJavaIdentifierStart(currentToken))
+		{
+			expression.javaProperty = javaProperty();
+		}
+		else if (Character.isJavaIdentifierPart(currentToken))
+		{
+			expression.beanProperty = beanProperty();
+		}
 		else
 		{
-			expression.property = property();
+			throw new ParserException("Expecting an expression but got: " + currentToken);
 		}
 		switch (lookaheadToken)
 		{
@@ -113,14 +121,27 @@ public class PropertyExpressionParser
 			case END_OF_EXPRESSION :
 				return expression;
 			default :
-				throw new ParserException(
-					"Expecting a new expression but got: '" + lookaheadToken + "'");
+				throw new ParserException(format(
+					"Expecting a new expression but got the invalid character '%s' at: '%s<--'",
+					lookaheadToken, text.substring(0, nextPosition + 1)));
+		}
+	}
+
+	private BeanProperty beanProperty()
+	{
+		BeanProperty property = new BeanProperty();
+		property.propertyName = propertyName();
+		if (lookaheadToken == '[')
+		{
+			advance();// skips left bracket
+			property.index = index();
 		}
+		return property;
 	}
 
-	private Property property()
+	private JavaProperty javaProperty()
 	{
-		Property property = new Property();
+		JavaProperty property = new JavaProperty();
 		property.javaIdentifier = javaIdentifier();
 		switch (lookaheadToken)
 		{
@@ -136,13 +157,8 @@ public class PropertyExpressionParser
 		return property;
 	}
 
-
-	private CharSequence javaIdentifier()
+	private CharSequence propertyName()
 	{
-		if (!isJavaIdentifierStart(currentToken))
-		{
-			throw new ParserException("Expeting a java identifier but got a :" + currentToken);
-		}
 		int begin = currentPosition;
 		while (isJavaIdentifierPart(lookaheadToken))
 		{
@@ -151,6 +167,15 @@ public class PropertyExpressionParser
 		return text.substring(begin, nextPosition);
 	}
 
+	private CharSequence javaIdentifier()
+	{
+		if (!isJavaIdentifierStart(currentToken))
+		{
+			throw new ParserException("Expeting a java identifier but got a :" + currentToken);
+		}
+		return propertyName();
+	}
+
 	private CharSequence index()
 	{
 		advance();// escape bracket

http://git-wip-us.apache.org/repos/asf/wicket/blob/697052f7/wicket-core/src/test/java/org/apache/wicket/core/util/lang/PropertyExpressionParserTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/core/util/lang/PropertyExpressionParserTest.java b/wicket-core/src/test/java/org/apache/wicket/core/util/lang/PropertyExpressionParserTest.java
index 104a01d..ac5ed26 100644
--- a/wicket-core/src/test/java/org/apache/wicket/core/util/lang/PropertyExpressionParserTest.java
+++ b/wicket-core/src/test/java/org/apache/wicket/core/util/lang/PropertyExpressionParserTest.java
@@ -1,10 +1,11 @@
 package org.apache.wicket.core.util.lang;
 
 import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
 import static org.junit.Assert.assertThat;
 
-import org.apache.wicket.core.util.lang.PropertyExpression.Property;
-import org.hamcrest.CoreMatchers;
+import org.apache.wicket.core.util.lang.PropertyExpression.BeanProperty;
+import org.apache.wicket.core.util.lang.PropertyExpression.JavaProperty;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
@@ -15,57 +16,62 @@ public class PropertyExpressionParserTest
 	@Rule
 	public ExpectedException expectedException = ExpectedException.none();
 	private PropertyExpressionParser parser = new PropertyExpressionParser();
-	
+
 	@Test
 	public void shouldParsePropertyExpressions()
 	{
 		PropertyExpression expression = parser.parse("person");
-		assertThat(expression.index, CoreMatchers.nullValue());
-		assertThat(expression.property, is(new Property("person", null, false)));
-		assertThat(expression.next, CoreMatchers.nullValue());
+		assertThat(expression.index, nullValue());
+		assertThat(expression.beanProperty, nullValue());
+		assertThat(expression.javaProperty, is(new JavaProperty("person", null, false)));
+		assertThat(expression.next, nullValue());
 	}
 
 	@Test
 	public void shouldParsePropertyExpressionStartingWithDigits()
 	{
 		PropertyExpression expression = parser.parse("1person");
-		assertThat(expression.index, CoreMatchers.nullValue());
-		assertThat(expression.property, is(new Property("person", null, false)));
-		assertThat(expression.next, CoreMatchers.nullValue());
+		assertThat(expression.index, nullValue());
+		assertThat(expression.beanProperty, is(new BeanProperty("1person", null)));
+		assertThat(expression.javaProperty, nullValue());
+		assertThat(expression.next, nullValue());
 	}
-	
+
 	@Test
 	public void shouldParseShortPropertyExpressions()
 	{
 		PropertyExpression expression = parser.parse("a");
-		assertThat(expression.index, CoreMatchers.nullValue());
-		assertThat(expression.property, is(new Property("a", null, false)));
-		assertThat(expression.next, CoreMatchers.nullValue());
+		assertThat(expression.index, nullValue());
+		assertThat(expression.beanProperty, nullValue());
+		assertThat(expression.javaProperty, is(new JavaProperty("a", null, false)));
+		assertThat(expression.next, nullValue());
 	}
 
 	@Test
 	public void shouldParseIndexedPropertyExpressions()
 	{
 		PropertyExpression expression = parser.parse("person[age]");
-		assertThat(expression.index, CoreMatchers.nullValue());
-		assertThat(expression.property, is(new Property("person", "age", false)));
-		assertThat(expression.next, CoreMatchers.nullValue());
+		assertThat(expression.index, nullValue());
+		assertThat(expression.beanProperty, nullValue());
+		assertThat(expression.javaProperty, is(new JavaProperty("person", "age", false)));
+		assertThat(expression.next, nullValue());
 	}
 
 	@Test
 	public void shouldParseMethodExpressions()
 	{
 		PropertyExpression expression = parser.parse("person()");
-		assertThat(expression.index, CoreMatchers.nullValue());
-		assertThat(expression.property, is(new Property("person", null, true)));
-		assertThat(expression.next, CoreMatchers.nullValue());
+		assertThat(expression.index, nullValue());
+		assertThat(expression.beanProperty, nullValue());
+		assertThat(expression.javaProperty, is(new JavaProperty("person", null, true)));
+		assertThat(expression.next, nullValue());
 	}
 
 	@Test
 	public void shouldParsePropertyExpressionsWithSpaceInMethod()
 	{
 		final PropertyExpression parse = parser.parse("person( )");
-		assertThat(parse.property, is(new Property("person", null, true)));
+		assertThat(parse.javaProperty, is(new JavaProperty("person", null, true)));
 	}
 
 	@Test
@@ -73,40 +79,40 @@ public class PropertyExpressionParserTest
 	{
 		PropertyExpression expression = parser.parse("[person#name]");
 		assertThat(expression.index, is("person#name"));
-		assertThat(expression.property, CoreMatchers.nullValue());
-		assertThat(expression.next, CoreMatchers.nullValue());
+		assertThat(expression.javaProperty, nullValue());
+		assertThat(expression.next, nullValue());
 	}
 
 	@Test
 	public void shouldParseChainedPropertyExpressions()
 	{
 		PropertyExpression expression = parser.parse("person.child");
-		assertThat(expression.property, is(new Property("person", null, false)));
-		assertThat(expression.next.property, is(new Property("child", null, false)));
+		assertThat(expression.javaProperty, is(new JavaProperty("person", null, false)));
+		assertThat(expression.next.javaProperty, is(new JavaProperty("child", null, false)));
 	}
 
 	@Test
 	public void shouldParseShortChainedPropertyExpressions()
 	{
 		PropertyExpression expression = parser.parse("a.b");
-		assertThat(expression.property, is(new Property("a", null, false)));
-		assertThat(expression.next.property, is(new Property("b", null, false)));
+		assertThat(expression.javaProperty, is(new JavaProperty("a", null, false)));
+		assertThat(expression.next.javaProperty, is(new JavaProperty("b", null, false)));
 	}
 
 	@Test
 	public void shouldParseChainedIndexedPropertyExpressions()
 	{
 		PropertyExpression expression = parser.parse("person[1].child");
-		assertThat(expression.property, is(new Property("person", "1", false)));
-		assertThat(expression.next.property, is(new Property("child", null, false)));
+		assertThat(expression.javaProperty, is(new JavaProperty("person", "1", false)));
+		assertThat(expression.next.javaProperty, is(new JavaProperty("child", null, false)));
 	}
 
 	@Test
 	public void shouldParseChainedMethodExpressions()
 	{
 		PropertyExpression expression = parser.parse("person().child");
-		assertThat(expression.property, is(new Property("person", null, true)));
-		assertThat(expression.next.property, is(new Property("child", null, false)));
+		assertThat(expression.javaProperty, is(new JavaProperty("person", null, true)));
+		assertThat(expression.next.javaProperty, is(new JavaProperty("child", null, false)));
 	}
 
 	@Test
@@ -114,16 +120,16 @@ public class PropertyExpressionParserTest
 	{
 		PropertyExpression expression = parser.parse("[person].child");
 		assertThat(expression.index, is("person"));
-		assertThat(expression.next.property, is(new Property("child", null, false)));
+		assertThat(expression.next.javaProperty, is(new JavaProperty("child", null, false)));
 	}
 
 	@Test
 	public void shouldParseDeeperChainedPropertyExpressions()
 	{
 		PropertyExpression expression = parser.parse("person.child.name");
-		assertThat(expression.property, is(new Property("person", null, false)));
-		assertThat(expression.next.property, is(new Property("child", null, false)));
-		assertThat(expression.next.next.property, is(new Property("name", null, false)));
+		assertThat(expression.javaProperty, is(new JavaProperty("person", null, false)));
+		assertThat(expression.next.javaProperty, is(new JavaProperty("child", null, false)));
+		assertThat(expression.next.next.javaProperty, is(new JavaProperty("name", null, false)));
 	}
 
 
@@ -139,7 +145,8 @@ public class PropertyExpressionParserTest
 	public void shouldFailParsePropertyExpressionsWithSpace()
 	{
 		expectedException.expect(ParserException.class);
-		expectedException.expectMessage("Expecting a new expression but got: ' '");
+		expectedException.expectMessage(
+			"Expecting a new expression but got the invalid character ' ' at: 'per <--'");
 		parser.parse("per son");
 	}
 
@@ -161,13 +168,12 @@ public class PropertyExpressionParserTest
 		parser.parse("repository.getPerson(filter)");
 	}
 
-	//TODO: better exception message
 	@Test
 	public void shouldFailParseInvalidMethodName()
 	{
 		expectedException.expect(ParserException.class);
-		// expectedException.expectMessage(
-		// "The expression can't have method parameters: 'repository.getPerson(<--'");
+		expectedException.expectMessage(
+			"Expecting a new expression but got the invalid character '#' at: 'repository.get#<--'");
 		parser.parse("repository.get#name()");
 	}
 

http://git-wip-us.apache.org/repos/asf/wicket/blob/697052f7/wicket-core/src/test/java/org/apache/wicket/util/lang/PropertyResolverTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/util/lang/PropertyResolverTest.java b/wicket-core/src/test/java/org/apache/wicket/util/lang/PropertyResolverTest.java
index 14c0a98..5929eef 100644
--- a/wicket-core/src/test/java/org/apache/wicket/util/lang/PropertyResolverTest.java
+++ b/wicket-core/src/test/java/org/apache/wicket/util/lang/PropertyResolverTest.java
@@ -246,13 +246,21 @@ public class PropertyResolverTest extends WicketTestCase
 	}
 
 	@Test
-	public void shouldMapKeysWithSpecialCharacters() throws Exception
+	public void shouldAllowMapKeysWithSpecialCharacters() throws Exception
 	{
 		String expression = "[!@#$%^&*()_+-=[{}|]";
 		PropertyResolver.setValue(expression, integerMap, AN_INTEGER, CONVERTER);
 		assertThat(PropertyResolver.getValue(expression, integerMap), is(AN_INTEGER));
 		assertThat(integerMap.get(expression), is(AN_INTEGER));
+	}
 
+	@Test
+	public void shouldAllowMapKeysHavingQuotes() throws Exception
+	{
+		String expression = "the\"key\"";
+		PropertyResolver.setValue(expression, integerMap, AN_INTEGER, CONVERTER);
+		assertThat(PropertyResolver.getValue(expression, integerMap), is(AN_INTEGER));
+		assertThat(integerMap.get(expression), is(AN_INTEGER));
 	}
 
 	@Test