WICKET-6318 adding ParsedPropertyExpressionResolver, a resolver that uses 
parsed property expressions; moving DefaultPropertyLocator, IPropertyResolver, 
CachingPropertyLocator back to 
OGNLPropertyExpressionResolverOGNLPropertyExpressionResolver; restoring 
IPropertyResolver name back to IPropertyLocator


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

Branch: refs/heads/WICKET-6318-configurable-property-expression-resolver
Commit: 7fd219c3b764f844665c3cff8d5cc719e77c6a99
Parents: 6a895f0
Author: Pedro Henrique Oliveira dos Santos <[email protected]>
Authored: Mon Feb 27 03:13:43 2017 -0300
Committer: Pedro Henrique Oliveira dos Santos <[email protected]>
Committed: Mon Feb 27 03:15:27 2017 -0300

----------------------------------------------------------------------
 .../validation/DefaultPropertyResolver.java     |   2 +-
 .../core/util/lang/DefaultPropertyLocator.java  | 160 ----
 .../util/lang/IPropertyExpressionResolver.java  |  22 +-
 .../core/util/lang/IPropertyResolver.java       |  18 -
 .../lang/OGNLPropertyExpressionResolver.java    | 393 +++++---
 .../wicket/core/util/lang/PropertyResolver.java |  97 +-
 .../ParsedPropertyExpressionResolver.java       | 173 ++++
 .../core/util/parser/PropertyExpression.java    |  25 +
 .../util/parser/PropertyExpressionResolver.java |  21 -
 .../util/reflection/CachingPropertyLocator.java |  70 --
 .../reflection/IndexedPropertyGetAndSet.java    |   2 +-
 .../core/util/reflection/MethodGetAndSet.java   |  51 +-
 .../util/reflection/ObjectWithGetAndSet.java    |   8 +-
 .../core/util/reflection/ReflectionUtility.java |  78 +-
 .../wicket/model/AbstractPropertyModel.java     |   2 +-
 .../ParsedPropertyExpressionResolverTest.java   | 103 +++
 .../parser/PropertyExpressionParserTest.java    |  16 +
 .../OGNLPropertyExpressionResolverTest.java     | 916 +------------------
 .../lang/PropertyExpressionResolverTest.java    | 852 +++++++++++++++++
 .../org/apache/wicket/util/lang/WeirdList.java  |  48 +
 .../org/apache/wicket/util/lang/WeirdMap.java   |  48 +
 21 files changed, 1721 insertions(+), 1384 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/7fd219c3/wicket-bean-validation/src/main/java/org/apache/wicket/bean/validation/DefaultPropertyResolver.java
----------------------------------------------------------------------
diff --git 
a/wicket-bean-validation/src/main/java/org/apache/wicket/bean/validation/DefaultPropertyResolver.java
 
b/wicket-bean-validation/src/main/java/org/apache/wicket/bean/validation/DefaultPropertyResolver.java
index 174598a..e6a4985 100644
--- 
a/wicket-bean-validation/src/main/java/org/apache/wicket/bean/validation/DefaultPropertyResolver.java
+++ 
b/wicket-bean-validation/src/main/java/org/apache/wicket/bean/validation/DefaultPropertyResolver.java
@@ -35,7 +35,7 @@ public class DefaultPropertyResolver implements 
IPropertyResolver
                
                String expression = delegate.getPropertyExpression();
                IPropertyExpressionResolver propertyExpressionResolver = 
Application.get().getApplicationSettings().getPropertyExpressionResolver();
-               ObjectWithGetAndSet objectWithGetAndSet = 
propertyExpressionResolver.resolve(expression, target, target.getClass());
+               ObjectWithGetAndSet objectWithGetAndSet = 
propertyExpressionResolver.resolve(expression, target, target.getClass(), 
IPropertyExpressionResolver.RESOLVE_CLASS);
 
                Method getter = objectWithGetAndSet.getGetter();
                if (getter != null)

http://git-wip-us.apache.org/repos/asf/wicket/blob/7fd219c3/wicket-core/src/main/java/org/apache/wicket/core/util/lang/DefaultPropertyLocator.java
----------------------------------------------------------------------
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/core/util/lang/DefaultPropertyLocator.java
 
b/wicket-core/src/main/java/org/apache/wicket/core/util/lang/DefaultPropertyLocator.java
deleted file mode 100644
index c8803c7..0000000
--- 
a/wicket-core/src/main/java/org/apache/wicket/core/util/lang/DefaultPropertyLocator.java
+++ /dev/null
@@ -1,160 +0,0 @@
-package org.apache.wicket.core.util.lang;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.wicket.WicketRuntimeException;
-import org.apache.wicket.core.util.reflection.ArrayGetAndSet;
-import org.apache.wicket.core.util.reflection.ArrayLengthGetAndSet;
-import org.apache.wicket.core.util.reflection.FieldGetAndSet;
-import org.apache.wicket.core.util.reflection.IGetAndSet;
-import org.apache.wicket.core.util.reflection.IndexedPropertyGetAndSet;
-import org.apache.wicket.core.util.reflection.ListGetAndSet;
-import org.apache.wicket.core.util.reflection.MapGetAndSet;
-import org.apache.wicket.core.util.reflection.MethodGetAndSet;
-import org.apache.wicket.core.util.reflection.ReflectionUtility;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Default locator supporting <em>Java Beans</em> properties, maps, lists and 
method invocations.
- */
-public class DefaultPropertyLocator implements IPropertyResolver
-{
-       public static final Logger log = 
LoggerFactory.getLogger(DefaultPropertyLocator.class);
-       
-       public IGetAndSet get(Class<?> clz, String exp)
-       {
-               IGetAndSet getAndSet = null;
-
-               Method method = null;
-               Field field;
-               if (exp.startsWith("["))
-               {
-                       // if expression begins with [ skip method finding and 
use it as
-                       // a key/index lookup on a map.
-                       exp = exp.substring(1, exp.length() - 1);
-               }
-               else if (exp.endsWith("()"))
-               {
-                       // if expression ends with (), don't test for setters 
just skip
-                       // directly to method finding.
-                       method = ReflectionUtility.findMethod(clz, exp);
-               }
-               else
-               {
-                       method = ReflectionUtility.findGetter(clz, exp);
-               }
-               if (method == null)
-               {
-                       if (List.class.isAssignableFrom(clz))
-                       {
-                               try
-                               {
-                                       int index = Integer.parseInt(exp);
-                                       getAndSet = new ListGetAndSet(index);
-                               }
-                               catch (NumberFormatException ex)
-                               {
-                                       // can't parse the exp as an index, 
maybe the exp was a
-                                       // method.
-                                       method = 
ReflectionUtility.findMethod(clz, exp);
-                                       if (method != null)
-                                       {
-                                               getAndSet = new 
MethodGetAndSet(method,
-                                                       
MethodGetAndSet.findSetter(method, clz), null);
-                                       }
-                                       else
-                                       {
-                                               field = 
ReflectionUtility.findField(clz, exp);
-                                               if (field != null)
-                                               {
-                                                       getAndSet = new 
FieldGetAndSet(field);
-                                               }
-                                               else
-                                               {
-                                                       throw new 
WicketRuntimeException("The expression '" + exp
-                                                               + "' is neither 
an index nor is it a method or field for the list "
-                                                               + clz);
-                                               }
-                                       }
-                               }
-                       }
-                       else if (Map.class.isAssignableFrom(clz))
-                       {
-                               getAndSet = new MapGetAndSet(exp);
-                       }
-                       else if (clz.isArray())
-                       {
-                               try
-                               {
-                                       int index = Integer.parseInt(exp);
-                                       getAndSet = new 
ArrayGetAndSet(clz.getComponentType(), index);
-                               }
-                               catch (NumberFormatException ex)
-                               {
-                                       if (exp.equals("length") || 
exp.equals("size"))
-                                       {
-                                               getAndSet = new 
ArrayLengthGetAndSet();
-                                       }
-                                       else
-                                       {
-                                               throw new 
WicketRuntimeException("Can't parse the expression '" + exp
-                                                       + "' as an index for an 
array lookup");
-                                       }
-                               }
-                       }
-                       else
-                       {
-                               field = ReflectionUtility.findField(clz, exp);
-                               if (field == null)
-                               {
-                                       method = 
ReflectionUtility.findMethod(clz, exp);
-                                       if (method == null)
-                                       {
-                                               int index = exp.indexOf('.');
-                                               if (index != -1)
-                                               {
-                                                       String propertyName = 
exp.substring(0, index);
-                                                       String propertyIndex = 
exp.substring(index + 1);
-                                                       try
-                                                       {
-                                                               int parsedIndex 
= Integer.parseInt(propertyIndex);
-                                                               // if so then 
it could be a getPropertyIndex(int)
-                                                               // and 
setPropertyIndex(int, object)
-                                                               String name = 
Character.toUpperCase(propertyName.charAt(0))
-                                                                       + 
propertyName.substring(1);
-                                                               method = 
clz.getMethod(MethodGetAndSet.GET + name,
-                                                                       new 
Class[] { int.class });
-                                                               getAndSet = new 
IndexedPropertyGetAndSet(method, parsedIndex);
-                                                       }
-                                                       catch (Exception e)
-                                                       {
-                                                               throw new 
WicketRuntimeException("No get method defined for class: "
-                                                                       + clz + 
" expression: " + propertyName);
-                                                       }
-                                               }
-                                       }
-                                       else
-                                       {
-                                               getAndSet = new 
MethodGetAndSet(method,
-                                                       
MethodGetAndSet.findSetter(method, clz), null);
-                                       }
-                               }
-                               else
-                               {
-                                       getAndSet = new FieldGetAndSet(field);
-                               }
-                       }
-               }
-               else
-               {
-                       field = ReflectionUtility.findField(clz, exp);
-                       getAndSet = new MethodGetAndSet(method, 
MethodGetAndSet.findSetter(method, clz), field);
-               }
-
-               return getAndSet;
-       }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/wicket/blob/7fd219c3/wicket-core/src/main/java/org/apache/wicket/core/util/lang/IPropertyExpressionResolver.java
----------------------------------------------------------------------
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/core/util/lang/IPropertyExpressionResolver.java
 
b/wicket-core/src/main/java/org/apache/wicket/core/util/lang/IPropertyExpressionResolver.java
index 4574be2..526d40c 100644
--- 
a/wicket-core/src/main/java/org/apache/wicket/core/util/lang/IPropertyExpressionResolver.java
+++ 
b/wicket-core/src/main/java/org/apache/wicket/core/util/lang/IPropertyExpressionResolver.java
@@ -10,6 +10,10 @@ import 
org.apache.wicket.core.util.reflection.ObjectWithGetAndSet;
 public interface IPropertyExpressionResolver
 {
 
+       int RETURN_NULL = 0;
+       int CREATE_NEW_VALUE = 1;
+       int RESOLVE_CLASS = 2;
+
        /**
         * @param expression
         * @param object
@@ -17,21 +21,7 @@ public interface IPropertyExpressionResolver
         * @param clz
         * @return {@link ObjectWithGetAndSet}
         */
-       ObjectWithGetAndSet resolve(String expression, Object object, Class<? 
extends Object> clz);
-
-       /**
-        * Creates a new value to each null property in the way to the 
expressed property. So the
-        * property expression: "attr1.attr2.attr3" would have "attr1" and 
"attr2" tested for null, in
-        * which case they would get new constructed values to guarantee a 
place to set the new value at
-        * "attr3"
-        * 
-        * @param expression
-        * @param object
-        * @param value
-        * @param prc
-        */
-       // TODO find a better name, multiple values are being setting here
-       // TODO if possible, to move to PropertyExpression
-       void setValue(String expression, Object object, Object value, 
PropertyResolverConverter prc);
+       ObjectWithGetAndSet resolve(String expression, Object object, Class<? 
extends Object> clz,
+               int tryToCreateNull);
 
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/7fd219c3/wicket-core/src/main/java/org/apache/wicket/core/util/lang/IPropertyResolver.java
----------------------------------------------------------------------
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/core/util/lang/IPropertyResolver.java
 
b/wicket-core/src/main/java/org/apache/wicket/core/util/lang/IPropertyResolver.java
deleted file mode 100644
index 65b7cdb..0000000
--- 
a/wicket-core/src/main/java/org/apache/wicket/core/util/lang/IPropertyResolver.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package org.apache.wicket.core.util.lang;
-
-import org.apache.wicket.core.util.reflection.IGetAndSet;
-
-/**
- * Resolves a property string to an {@link IGetAndSet}.
- * 
- * @see {@link IPropertyExpressionResolver} Property expression are resolved by
- *      {@link IPropertyExpressionResolver} implementations instead
- *
- * @author pedro
- */
-public interface IPropertyResolver
-{
-
-       IGetAndSet get(Class<?> clz, String exp);
-
-}

http://git-wip-us.apache.org/repos/asf/wicket/blob/7fd219c3/wicket-core/src/main/java/org/apache/wicket/core/util/lang/OGNLPropertyExpressionResolver.java
----------------------------------------------------------------------
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/core/util/lang/OGNLPropertyExpressionResolver.java
 
b/wicket-core/src/main/java/org/apache/wicket/core/util/lang/OGNLPropertyExpressionResolver.java
index 085adb3..1c74173 100644
--- 
a/wicket-core/src/main/java/org/apache/wicket/core/util/lang/OGNLPropertyExpressionResolver.java
+++ 
b/wicket-core/src/main/java/org/apache/wicket/core/util/lang/OGNLPropertyExpressionResolver.java
@@ -18,13 +18,23 @@ package org.apache.wicket.core.util.lang;
 
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
-import org.apache.wicket.Application;
-import org.apache.wicket.Session;
 import org.apache.wicket.WicketRuntimeException;
-import org.apache.wicket.core.util.reflection.CachingPropertyLocator;
+import org.apache.wicket.core.util.reflection.AbstractGetAndSet;
+import org.apache.wicket.core.util.reflection.ArrayGetAndSet;
+import org.apache.wicket.core.util.reflection.ArrayLengthGetAndSet;
+import org.apache.wicket.core.util.reflection.FieldGetAndSet;
 import org.apache.wicket.core.util.reflection.IGetAndSet;
+import org.apache.wicket.core.util.reflection.IndexedPropertyGetAndSet;
+import org.apache.wicket.core.util.reflection.ListGetAndSet;
+import org.apache.wicket.core.util.reflection.MapGetAndSet;
+import org.apache.wicket.core.util.reflection.MethodGetAndSet;
 import org.apache.wicket.core.util.reflection.ObjectWithGetAndSet;
+import org.apache.wicket.core.util.reflection.ReflectionUtility;
+import org.apache.wicket.util.lang.Generics;
 import org.apache.wicket.util.string.Strings;
 
 /**
@@ -63,147 +73,25 @@ import org.apache.wicket.util.string.Strings;
 
 public class OGNLPropertyExpressionResolver implements 
IPropertyExpressionResolver
 {
-       private final static int RETURN_NULL = 0;
-       private final static int CREATE_NEW_VALUE = 1;
-       private final static int RESOLVE_CLASS = 2;
 
-       private IPropertyResolver locator = new CachingPropertyLocator( new 
DefaultPropertyLocator());
-
-
-       /**
-        * Looks up the value from the object with the given expression. If the 
expression, the object
-        * itself or one property evaluates to null then a null will be 
returned.
-        *
-        * @param expression
-        *            The expression string with the property to be lookup.
-        * @param object
-        *            The object which is evaluated.
-        * @return The value that is evaluated. Null something in the 
expression evaluated to null.
-        */
-       //TODO remove, only being used in tests
-       public Object getValue(final String expression, final Object object)
+       private IPropertyLocator locator;
+       
+       public OGNLPropertyExpressionResolver()
        {
-               ObjectWithGetAndSet objectWithGetAndSet = 
getObjectWithGetAndSet(expression, object,
-                       RETURN_NULL);
-               if (objectWithGetAndSet == null)
-               {
-                       return null;
-               }
-
-               return objectWithGetAndSet.getValue();
+               this(new CachingPropertyLocator(new DefaultPropertyLocator()));
        }
 
-       /**
-        * Set the value on the object with the given expression. If the 
expression can't be evaluated
-        * then a WicketRuntimeException will be thrown. If a null object is 
encountered then it will
-        * try to generate it by calling the default constructor and set it on 
the object.
-        *
-        * The value will be tried to convert to the right type with the given 
converter.
-        *
-        * @param expression
-        *            The expression string with the property to be set.
-        * @param object
-        *            The object which is evaluated to set the value on.
-        * @param value
-        *            The value to set.
-        * @param converter
-        *            The converter to convert the value if needed to the right 
type.
-        * @throws WicketRuntimeException
-        */
-       @Override
-       public void setValue(final String expression, final Object object, 
final Object value,
-               final PropertyResolverConverter converter)
+       public OGNLPropertyExpressionResolver(IPropertyLocator locator)
        {
-               if (Strings.isEmpty(expression))
-               {
-                       throw new WicketRuntimeException(
-                               "Empty expression setting value: " + value + " 
on object: " + object);
-               }
-               if (object == null)
-               {
-                       throw new WicketRuntimeException(
-                               "Attempted to set property value on a null 
object. Property expression: "
-                                       + expression + " Value: " + value);
-               }
-
-               ObjectWithGetAndSet objectWithGetAndSet = 
getObjectWithGetAndSet(expression, object,
-                       CREATE_NEW_VALUE);
-               if (objectWithGetAndSet == null)
-               {
-                       throw new WicketRuntimeException("Null object returned 
for expression: " + expression
-                               + " for setting value: " + value + " on: " + 
object);
-               }
-               objectWithGetAndSet.setValue(value,
-                       converter == null
-                               ? new 
PropertyResolverConverter(Application.get().getConverterLocator(),
-                                       Session.get().getLocale())
-                               : converter);
-       }
-
-       /**
-       /**
-        * @param expression
-        * @param object
-        * @return Field for the property expression
-        * @throws WicketRuntimeException
-        *             if there is no such field
-        */
-       public Field getPropertyField(final String expression, final Object 
object)
-       {
-               ObjectWithGetAndSet objectWithGetAndSet = 
getObjectWithGetAndSet(expression, object,
-                       RESOLVE_CLASS);
-               if (objectWithGetAndSet == null)
-               {
-                       throw new WicketRuntimeException("Null object returned 
for expression: " + expression
-                               + " for getting the target class of: " + 
object);
-               }
-               return objectWithGetAndSet.getField();
-       }
-
-       /**
-        * @param expression
-        * @param object
-        * @return Getter method for the property expression
-        * @throws WicketRuntimeException
-        *             if there is no getter method
-        */
-       public Method getPropertyGetter(final String expression, final Object 
object)
-       {
-               ObjectWithGetAndSet objectWithGetAndSet = 
getObjectWithGetAndSet(expression, object,
-                       RESOLVE_CLASS);
-               if (objectWithGetAndSet == null)
-               {
-                       throw new WicketRuntimeException("Null object returned 
for expression: " + expression
-                               + " for getting the target class of: " + 
object);
-               }
-               return objectWithGetAndSet.getGetter();
-       }
-
-       /**
-        * @param expression
-        * @param object
-        * @return Setter method for the property expression
-        * @throws WicketRuntimeException
-        *             if there is no setter method
-        */
-       public Method getPropertySetter(final String expression, final Object 
object)
-       {
-               ObjectWithGetAndSet objectWithGetAndSet = 
getObjectWithGetAndSet(expression, object,
-                       RESOLVE_CLASS);
-               if (objectWithGetAndSet == null)
-               {
-                       throw new WicketRuntimeException("Null object returned 
for expression: " + expression
-                               + " for getting the target class of: " + 
object);
-               }
-               return objectWithGetAndSet.getSetter();
+               this.locator = locator;
        }
 
        @Override
-       public ObjectWithGetAndSet resolve(String expression, Object object, 
Class<? extends Object> clz)
+       public ObjectWithGetAndSet resolve(String expression, Object object, 
Class<? extends Object> clz, int tryToCreateNull)
        {
                ObjectWithGetAndSet objectWithGetAndSet = 
getObjectWithGetAndSet(expression, object,
-                       RESOLVE_CLASS, clz);
-               if (objectWithGetAndSet == null)
+                       tryToCreateNull, clz);
+               if (objectWithGetAndSet == null && tryToCreateNull != 
RETURN_NULL)
                {
                        throw new WicketRuntimeException("Null object returned 
for expression: " + expression
                                + " for getting the target class of: " + clz);
@@ -212,21 +100,6 @@ public class OGNLPropertyExpressionResolver implements 
IPropertyExpressionResolv
        }
 
        /**
-        * Just delegating the call to the original getObjectAndGetSetter 
passing the object type as
-        * parameter.
-        *
-        * @param expression
-        * @param object
-        * @param tryToCreateNull
-        * @return {@link ObjectWithGetAndSet}
-        */
-       private ObjectWithGetAndSet getObjectWithGetAndSet(final String 
expression,
-               final Object object, int tryToCreateNull)
-       {
-               return getObjectWithGetAndSet(expression, object, 
tryToCreateNull, object.getClass());
-       }
-
-       /**
         * Receives the class parameter also, since this method can resolve the 
type for some
         * expression, only knowing the target class.
         *
@@ -293,7 +166,7 @@ public class OGNLPropertyExpressionResolver implements 
IPropertyExpressionResolv
                        }
                        if (nextValue == null)
                        {
-                               if (tryToCreateNull == CREATE_NEW_VALUE)
+                               if (tryToCreateNull == 
IPropertyExpressionResolver.CREATE_NEW_VALUE)
                                {
                                        nextValue = getAndSet.newValue(value);
                                        if (nextValue == null)
@@ -301,7 +174,7 @@ public class OGNLPropertyExpressionResolver implements 
IPropertyExpressionResolv
                                                return null;
                                        }
                                }
-                               else if (tryToCreateNull == RESOLVE_CLASS)
+                               else if (tryToCreateNull == 
IPropertyExpressionResolver.RESOLVE_CLASS)
                                {
                                        clz = getAndSet.getTargetClass();
                                }
@@ -370,5 +243,223 @@ public class OGNLPropertyExpressionResolver implements 
IPropertyExpressionResolv
                return getAndSet;
        }
 
+       /**
+        * A locator of properties.
+        * 
+        * @see https://issues.apache.org/jira/browse/WICKET-5623
+        */
+       public static interface IPropertyLocator
+       {
+               /**
+                * Get {@link IGetAndSet} for a property.
+                * 
+                * @param clz owning class
+                * @param exp identifying the property
+                * @return getAndSet or {@code null} if non located
+                */
+               IGetAndSet get(Class<?> clz, String exp);
+       }
+
+       /**
+        * A wrapper for another {@link IPropertyLocator} that caches results of
+        * {@link #get(Class, String)}.
+        */
+       public static class CachingPropertyLocator implements IPropertyLocator
+       {
+               private final ConcurrentHashMap<String, IGetAndSet> map = 
Generics.newConcurrentHashMap(16);
+
+               /**
+                * Special token to put into the cache representing no located 
{@link IGetAndSet}.
+                */
+               private IGetAndSet NONE = new AbstractGetAndSet()
+               {
+
+                       @Override
+                       public Object getValue(Object object)
+                       {
+                               return null;
+                       }
+
+                       @Override
+                       public Object newValue(Object object)
+                       {
+                               return null;
+                       }
+
+                       @Override
+                       public void setValue(Object object, Object value, 
PropertyResolverConverter converter)
+                       {
+                       }
+               };
+
+               private IPropertyLocator resolver;
+
+               public CachingPropertyLocator(IPropertyLocator locator)
+               {
+                       this.resolver = locator;
+               }
+
+               public IGetAndSet get(Class<?> clz, String exp)
+               {
+                       String key = clz.getName() + "#" + exp;
+
+                       IGetAndSet located = map.get(key);
+                       if (located == null)
+                       {
+                               located = resolver.get(clz, exp);
+                               if (located == null)
+                               {
+                                       located = NONE;
+                               }
+                               map.put(key, located);
+                       }
+
+                       if (located == NONE)
+                       {
+                               located = null;
+                       }
+
+                       return located;
+               }
+       }
+
+       /**
+        * Default locator supporting <em>Java Beans</em> properties, maps, 
lists and method invocations.
+        */
+       public static class DefaultPropertyLocator implements IPropertyLocator
+       {
+               
+               public IGetAndSet get(Class<?> clz, String exp)
+               {
+                       IGetAndSet getAndSet = null;
 
+                       Method method = null;
+                       Field field;
+                       if (exp.startsWith("["))
+                       {
+                               // if expression begins with [ skip method 
finding and use it as
+                               // a key/index lookup on a map.
+                               exp = exp.substring(1, exp.length() - 1);
+                       }
+                       else if (exp.endsWith("()"))
+                       {
+                               // if expression ends with (), don't test for 
setters just skip
+                               // directly to method finding.
+                               method = ReflectionUtility.findMethod(clz, exp);
+                       }
+                       else
+                       {
+                               method = ReflectionUtility.findGetter(clz, exp);
+                       }
+                       if (method == null)
+                       {
+                               if (List.class.isAssignableFrom(clz))
+                               {
+                                       try
+                                       {
+                                               int index = 
Integer.parseInt(exp);
+                                               getAndSet = new 
ListGetAndSet(index);
+                                       }
+                                       catch (NumberFormatException ex)
+                                       {
+                                               // can't parse the exp as an 
index, maybe the exp was a
+                                               // method.
+                                               method = 
ReflectionUtility.findMethod(clz, exp);
+                                               if (method != null)
+                                               {
+                                                       getAndSet = new 
MethodGetAndSet(method,
+                                                               
ReflectionUtility.findSetter(method, clz), null);
+                                               }
+                                               else
+                                               {
+                                                       field = 
ReflectionUtility.findField(clz, exp);
+                                                       if (field != null)
+                                                       {
+                                                               getAndSet = new 
FieldGetAndSet(field);
+                                                       }
+                                                       else
+                                                       {
+                                                               throw new 
WicketRuntimeException("The expression '" + exp
+                                                                       + "' is 
neither an index nor is it a method or field for the list "
+                                                                       + clz);
+                                                       }
+                                               }
+                                       }
+                               }
+                               else if (Map.class.isAssignableFrom(clz))
+                               {
+                                       getAndSet = new MapGetAndSet(exp);
+                               }
+                               else if (clz.isArray())
+                               {
+                                       try
+                                       {
+                                               int index = 
Integer.parseInt(exp);
+                                               getAndSet = new 
ArrayGetAndSet(clz.getComponentType(), index);
+                                       }
+                                       catch (NumberFormatException ex)
+                                       {
+                                               if (exp.equals("length") || 
exp.equals("size"))
+                                               {
+                                                       getAndSet = new 
ArrayLengthGetAndSet();
+                                               }
+                                               else
+                                               {
+                                                       throw new 
WicketRuntimeException("Can't parse the expression '" + exp
+                                                               + "' as an 
index for an array lookup");
+                                               }
+                                       }
+                               }
+                               else
+                               {
+                                       field = 
ReflectionUtility.findField(clz, exp);
+                                       if (field == null)
+                                       {
+                                               method = 
ReflectionUtility.findMethod(clz, exp);
+                                               if (method == null)
+                                               {
+                                                       int index = 
exp.indexOf('.');
+                                                       if (index != -1)
+                                                       {
+                                                               String 
propertyName = exp.substring(0, index);
+                                                               String 
propertyIndex = exp.substring(index + 1);
+                                                               try
+                                                               {
+                                                                       int 
parsedIndex = Integer.parseInt(propertyIndex);
+                                                                       // if 
so then it could be a getPropertyIndex(int)
+                                                                       // and 
setPropertyIndex(int, object)
+                                                                       String 
name = Character.toUpperCase(propertyName.charAt(0))
+                                                                               
+ propertyName.substring(1);
+                                                                       method 
= clz.getMethod(ReflectionUtility.GET + name,
+                                                                               
new Class[] { int.class });
+                                                                       
getAndSet = new IndexedPropertyGetAndSet(method, parsedIndex);
+                                                               }
+                                                               catch 
(Exception e)
+                                                               {
+                                                                       throw 
new WicketRuntimeException("No get method defined for class: "
+                                                                               
+ clz + " expression: " + propertyName);
+                                                               }
+                                                       }
+                                               }
+                                               else
+                                               {
+                                                       getAndSet = new 
MethodGetAndSet(method,
+                                                               
ReflectionUtility.findSetter(method, clz), null);
+                                               }
+                                       }
+                                       else
+                                       {
+                                               getAndSet = new 
FieldGetAndSet(field);
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               field = ReflectionUtility.findField(clz, exp);
+                               getAndSet = new MethodGetAndSet(method, 
ReflectionUtility.findSetter(method, clz), field);
+                       }
+
+                       return getAndSet;
+               }
+       }
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/7fd219c3/wicket-core/src/main/java/org/apache/wicket/core/util/lang/PropertyResolver.java
----------------------------------------------------------------------
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/core/util/lang/PropertyResolver.java
 
b/wicket-core/src/main/java/org/apache/wicket/core/util/lang/PropertyResolver.java
index b7f87dc..ccbc0a9 100644
--- 
a/wicket-core/src/main/java/org/apache/wicket/core/util/lang/PropertyResolver.java
+++ 
b/wicket-core/src/main/java/org/apache/wicket/core/util/lang/PropertyResolver.java
@@ -16,37 +16,110 @@
  */
 package org.apache.wicket.core.util.lang;
 
+import static 
org.apache.wicket.core.util.lang.IPropertyExpressionResolver.CREATE_NEW_VALUE;
+import static 
org.apache.wicket.core.util.lang.IPropertyExpressionResolver.RESOLVE_CLASS;
+import static 
org.apache.wicket.core.util.lang.IPropertyExpressionResolver.RETURN_NULL;
+
 import org.apache.wicket.Application;
+import org.apache.wicket.Session;
+import org.apache.wicket.WicketRuntimeException;
+import org.apache.wicket.core.util.reflection.ObjectWithGetAndSet;
+import org.apache.wicket.util.string.Strings;
 
 /**
- * Old {@link PropertyResolver} kept just as a facade for the current 
implementation
+ * Facade with common usages of the {@link ObjectWithGetAndSet} resolved by 
{@link Application}'s
+ * {@link IPropertyExpressionResolver}
  */
-@Deprecated
 public final class PropertyResolver
 {
-
-       public static <T> T getValue(String expression, T object)
+       /**
+        * Looks up the value from the object with the given expression. If the 
expression, the object
+        * itself or one property evaluates to null then a null will be 
returned.
+        *
+        * @param expression
+        *            The expression string with the property to be lookup.
+        * @param object
+        *            The object which is evaluated.
+        * @return The value that is evaluated. Null something in the 
expression evaluated to null.
+        */
+       public static Object getValue(String expression, Object object)
        {
                if (expression == null || expression.equals("") || object == 
null)
                {
                        return object;
                }
-               IPropertyExpressionResolver propertyExpressionResolver = 
Application.get().getApplicationSettings().getPropertyExpressionResolver();
-               return (T)propertyExpressionResolver.resolve(expression, 
object, object.getClass()).getValue();
+               IPropertyExpressionResolver propertyExpressionResolver = 
Application.get()
+                       
.getApplicationSettings().getPropertyExpressionResolver();
+               ObjectWithGetAndSet property = 
propertyExpressionResolver.resolve(expression, object,
+                       object.getClass(), RETURN_NULL);
+               return property == null ? null : property.getValue(false);
        }
 
-       public static <T> Class<T> getPropertyClass(String expression, Object 
object,
-               Class<?> targetClass)
+       /**
+        * @param expression
+        * @param object
+        * @param targetClass
+        * @return class of the target property object
+        * @throws WicketRuntimeException
+        *             if the cannot be resolved
+        */
+       public static Class<?> getPropertyClass(String expression, Object 
object, Class<?> targetClass)
        {
-               IPropertyExpressionResolver propertyExpressionResolver = 
Application.get().getApplicationSettings().getPropertyExpressionResolver();
-               return (Class<T>)propertyExpressionResolver.resolve(expression, 
object, targetClass).getTargetClass();
+               IPropertyExpressionResolver propertyExpressionResolver = 
Application.get()
+                       
.getApplicationSettings().getPropertyExpressionResolver();
+               ObjectWithGetAndSet objectWithGetAndSet = 
propertyExpressionResolver.resolve(expression,
+                       object, targetClass, RESOLVE_CLASS);
+               if (objectWithGetAndSet == null)
+               {
+                       throw new WicketRuntimeException("No Class returned for 
expression: " + expression
+                               + " for getting the target class of: " + 
targetClass);
+               }
+               return objectWithGetAndSet.getTargetClass();
        }
 
+       /**
+        * Set the value on the object with the given expression. If the 
expression can't be evaluated
+        * then a WicketRuntimeException will be thrown. If a null object is 
encountered then it will
+        * try to generate it by calling the default constructor and set it on 
the object.
+        *
+        * The value will be tried to convert to the right type with the given 
converter.
+        *
+        * @param expression
+        *            The expression string with the property to be set.
+        * @param object
+        *            The object which is evaluated to set the value on.
+        * @param value
+        *            The value to set.
+        * @param converter
+        *            The converter to convert the value if needed to the right 
type.
+        * @throws WicketRuntimeException
+        */
        public static void setValue(String expression, Object object, Object 
value,
                PropertyResolverConverter prc)
        {
-               
Application.get().getApplicationSettings().getPropertyExpressionResolver()
-                       .setValue(expression, object, value, prc);
+               IPropertyExpressionResolver propertyExpressionResolver = 
Application.get()
+                       
.getApplicationSettings().getPropertyExpressionResolver();
+
+               if (Strings.isEmpty(expression))
+               {
+                       throw new WicketRuntimeException(
+                               "Empty expression setting value: " + value + " 
on object: " + object);
+               }
+               if (object == null)
+               {
+                       throw new WicketRuntimeException(
+                               "Attempted to set property value on a null 
object. Property expression: "
+                                       + expression + " Value: " + value);
+               }
+
+               ObjectWithGetAndSet objectWithGetAndSet = 
propertyExpressionResolver.resolve(expression,
+                       object, object.getClass(), CREATE_NEW_VALUE);
+
+               objectWithGetAndSet.setValue(value,
+                       prc == null
+                               ? new 
PropertyResolverConverter(Application.get().getConverterLocator(),
+                                       Session.get().getLocale())
+                               : prc);
        }
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/wicket/blob/7fd219c3/wicket-core/src/main/java/org/apache/wicket/core/util/parser/ParsedPropertyExpressionResolver.java
----------------------------------------------------------------------
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/core/util/parser/ParsedPropertyExpressionResolver.java
 
b/wicket-core/src/main/java/org/apache/wicket/core/util/parser/ParsedPropertyExpressionResolver.java
new file mode 100644
index 0000000..34847e4
--- /dev/null
+++ 
b/wicket-core/src/main/java/org/apache/wicket/core/util/parser/ParsedPropertyExpressionResolver.java
@@ -0,0 +1,173 @@
+package org.apache.wicket.core.util.parser;
+
+import static java.lang.Integer.parseInt;
+import static 
org.apache.wicket.core.util.reflection.ReflectionUtility.findField;
+import static 
org.apache.wicket.core.util.reflection.ReflectionUtility.findGetter;
+import static 
org.apache.wicket.core.util.reflection.ReflectionUtility.findMethod;
+import static 
org.apache.wicket.core.util.reflection.ReflectionUtility.findPositionGetter;
+import static 
org.apache.wicket.core.util.reflection.ReflectionUtility.findSetter;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.wicket.WicketRuntimeException;
+import org.apache.wicket.core.util.lang.IPropertyExpressionResolver;
+import org.apache.wicket.core.util.reflection.ArrayGetAndSet;
+import org.apache.wicket.core.util.reflection.ArrayLengthGetAndSet;
+import org.apache.wicket.core.util.reflection.FieldGetAndSet;
+import org.apache.wicket.core.util.reflection.IGetAndSet;
+import org.apache.wicket.core.util.reflection.IndexedPropertyGetAndSet;
+import org.apache.wicket.core.util.reflection.ListGetAndSet;
+import org.apache.wicket.core.util.reflection.MapGetAndSet;
+import org.apache.wicket.core.util.reflection.MethodGetAndSet;
+import org.apache.wicket.core.util.reflection.ObjectWithGetAndSet;
+
+public class ParsedPropertyExpressionResolver implements 
IPropertyExpressionResolver
+{
+       @Override
+       public ObjectWithGetAndSet resolve(String expression, Object object,
+               Class<? extends Object> clz, int tryToCreateNull)
+       {
+               PropertyExpression ast = new 
PropertyExpressionParser().parse(expression);
+               return resolveExpression(ast, object, clz, tryToCreateNull);
+       }
+
+       public ObjectWithGetAndSet resolveExpression(PropertyExpression ast, 
Object object,
+               Class<?> clz, int tryToCreateNull)
+       {
+
+               IGetAndSet getAndSet = resolveProperty(clz, ast);
+
+               if (getAndSet == null
+                       && (ast.index != null || ast.next != null && 
ast.next.canDefaultToIndex()))
+               {
+                       getAndSet = resolvePropertyAtPosition(clz, 
ast.getPropertyToken(),
+                               ast.index != null ? ast.index : 
ast.next.toIndex());
+
+                       if (getAndSet != null && ast.index == null)
+                               ast = ast.next;
+               }
+
+               if (getAndSet == null && ast.canDefaultToIndex())
+                       getAndSet = resolveIndex(clz, ast.toIndex());
+
+               if (getAndSet == null)// ok, finally give up
+                       throw new WicketRuntimeException("Can't parse the 
expression '" + ast);
+
+               ObjectWithGetAndSet resolved = new 
ObjectWithGetAndSet(getAndSet, object);
+
+               if (ast.javaProperty != null && ast.javaProperty.index != null)
+               {
+                       getAndSet = resolveIndex(getAndSet.getTargetClass(), 
ast.javaProperty.index);
+                       resolved = new ObjectWithGetAndSet(getAndSet,
+                               resolved.getValue(tryToCreateNull == 
CREATE_NEW_VALUE));
+               }
+               if (ast.beanProperty != null && ast.beanProperty.index != null)
+               {
+                       getAndSet = resolveIndex(getAndSet.getTargetClass(), 
ast.beanProperty.index);
+                       resolved = new ObjectWithGetAndSet(getAndSet,
+                               resolved.getValue(tryToCreateNull == 
CREATE_NEW_VALUE));
+               }
+
+               if (ast.next == null)
+                       return resolved;
+
+               Object nextValue = resolved.getValue(tryToCreateNull == 
CREATE_NEW_VALUE);
+               Class<?> nextClass = nextValue != null ? nextValue.getClass() : 
resolved.getTargetClass();
+
+               if (nextValue == null && tryToCreateNull == RETURN_NULL)
+                       return null;
+
+               return resolveExpression(ast.next, nextValue, nextClass, 
tryToCreateNull);
+
+       }
+
+       private IGetAndSet resolveProperty(Class<?> clz, PropertyExpression ast)
+       {
+               if (ast.javaProperty != null)
+                       return resolveJavaProperty(clz, ast);
+               else if (ast.beanProperty != null)
+                       return resolveBeanProperty(clz, ast);
+               else if (ast.index != null)
+                       return resolveIndex(clz, ast.index);
+               else
+                       throw new WicketRuntimeException("Resolver failed to 
find a property to resolve");
+       }
+
+       private IGetAndSet resolveJavaProperty(Class<?> clz, PropertyExpression 
ast)
+       {
+               if (ast.javaProperty.hasMethodSign)
+               {
+                       Method method = findMethod(clz, 
ast.javaProperty.javaIdentifier);
+                       return new MethodGetAndSet(method, findSetter(method, 
clz), null);
+               }
+               else
+               {
+                       Method method = findGetter(clz, 
ast.javaProperty.javaIdentifier);
+                       Field field = findField(clz, 
ast.javaProperty.javaIdentifier);
+
+                       if (method == null && field == null)
+                               return null;
+                       else if (method == null)
+                               return new FieldGetAndSet(field);
+                       else
+                               return new MethodGetAndSet(method, 
findSetter(method, clz), field);
+               }
+       }
+
+       private IGetAndSet resolveBeanProperty(Class<?> clz, PropertyExpression 
ast)
+       {
+               Method method = findGetter(clz, ast.beanProperty.propertyName);
+
+               return method == null ? null : new MethodGetAndSet(method, 
findSetter(method, clz), null);
+       }
+
+       private IGetAndSet resolveIndex(Class<?> clz, String index)
+       {
+               if (List.class.isAssignableFrom(clz))
+               {
+                       int position = Integer.parseInt(index);
+                       return new ListGetAndSet(position);
+               }
+               else if (Map.class.isAssignableFrom(clz))
+               {
+                       return new MapGetAndSet(index);
+               }
+               else if (clz.isArray())
+               {
+                       try
+                       {
+                               int position = Integer.parseInt(index);
+                               return new 
ArrayGetAndSet(clz.getComponentType(), position);
+                       }
+                       catch (NumberFormatException ex)
+                       {
+                               if (index.equals("length") || 
index.equals("size"))
+                               {
+                                       return new ArrayLengthGetAndSet();
+                               }
+                               throw new WicketRuntimeException(
+                                       "Can't parse the expression '" + index 
+ "' as an index for an array lookup");
+                       }
+               }
+               return null;
+       }
+
+       private IGetAndSet resolvePropertyAtPosition(Class<?> clz, String 
property, String position)
+       {
+               Method method = findPositionGetter(clz, property);
+               if (method == null)
+                       return null;
+               try
+               {
+                       return new IndexedPropertyGetAndSet(method, 
parseInt(position));
+               }
+               catch (NumberFormatException e)
+               {
+                       return null;
+               }
+       }
+
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/7fd219c3/wicket-core/src/main/java/org/apache/wicket/core/util/parser/PropertyExpression.java
----------------------------------------------------------------------
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/core/util/parser/PropertyExpression.java
 
b/wicket-core/src/main/java/org/apache/wicket/core/util/parser/PropertyExpression.java
index 2cd5e6d..1030b26 100644
--- 
a/wicket-core/src/main/java/org/apache/wicket/core/util/parser/PropertyExpression.java
+++ 
b/wicket-core/src/main/java/org/apache/wicket/core/util/parser/PropertyExpression.java
@@ -28,6 +28,31 @@ public class PropertyExpression
        String index;
        PropertyExpression next;
 
+       public String getPropertyToken()
+       {
+               if (javaProperty != null)
+                       return javaProperty.javaIdentifier;
+               else if (beanProperty != null)
+                       return beanProperty.propertyName;
+               return null;
+       }
+
+       public boolean canDefaultToIndex()
+       {
+               return (javaProperty != null && (javaProperty.index == null && 
!javaProperty.hasMethodSign))
+                       || (beanProperty != null && beanProperty.index == null);
+       }
+
+       public String toIndex()
+       {
+               if (index != null)
+                       return index;
+               else if (javaProperty != null)
+                       return javaProperty.javaIdentifier;
+               else
+                       return beanProperty.propertyName;
+       }
+
        static class BeanProperty
        {
                String propertyName;

http://git-wip-us.apache.org/repos/asf/wicket/blob/7fd219c3/wicket-core/src/main/java/org/apache/wicket/core/util/parser/PropertyExpressionResolver.java
----------------------------------------------------------------------
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/core/util/parser/PropertyExpressionResolver.java
 
b/wicket-core/src/main/java/org/apache/wicket/core/util/parser/PropertyExpressionResolver.java
deleted file mode 100644
index fd976aa..0000000
--- 
a/wicket-core/src/main/java/org/apache/wicket/core/util/parser/PropertyExpressionResolver.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package org.apache.wicket.core.util.parser;
-
-import org.apache.wicket.core.util.lang.IPropertyExpressionResolver;
-import org.apache.wicket.core.util.lang.PropertyResolverConverter;
-import org.apache.wicket.core.util.reflection.ObjectWithGetAndSet;
-
-public class PropertyExpressionResolver implements IPropertyExpressionResolver
-{
-       @Override
-       public ObjectWithGetAndSet resolve(String expression, Object object, 
Class<? extends Object> clz)
-       {
-               return null;
-       }
-
-       @Override
-       public void setValue(String expression, Object object, Object value, 
PropertyResolverConverter prc)
-       {
-
-       }
-
-}

http://git-wip-us.apache.org/repos/asf/wicket/blob/7fd219c3/wicket-core/src/main/java/org/apache/wicket/core/util/reflection/CachingPropertyLocator.java
----------------------------------------------------------------------
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/core/util/reflection/CachingPropertyLocator.java
 
b/wicket-core/src/main/java/org/apache/wicket/core/util/reflection/CachingPropertyLocator.java
deleted file mode 100644
index 78fafc1..0000000
--- 
a/wicket-core/src/main/java/org/apache/wicket/core/util/reflection/CachingPropertyLocator.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package org.apache.wicket.core.util.reflection;
-
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.wicket.core.util.lang.IPropertyResolver;
-import org.apache.wicket.core.util.lang.PropertyResolverConverter;
-import org.apache.wicket.util.lang.Generics;
-
-/**
- * A wrapper for another {@link IPropertyLocator} that caches results of
- * {@link #get(Class, String)}.
- */
-public class CachingPropertyLocator  implements IPropertyResolver
-{
-       private final ConcurrentHashMap<String, IGetAndSet> map = 
Generics.newConcurrentHashMap(16);
-
-       /**
-        * Special token to put into the cache representing no located {@link 
IGetAndSet}.
-        */
-       private IGetAndSet NONE = new AbstractGetAndSet()
-       {
-
-               @Override
-               public Object getValue(Object object)
-               {
-                       return null;
-               }
-
-               @Override
-               public Object newValue(Object object)
-               {
-                       return null;
-               }
-
-               @Override
-               public void setValue(Object object, Object value, 
PropertyResolverConverter converter)
-               {
-               }
-       };
-
-       private IPropertyResolver resolver;
-
-       public CachingPropertyLocator(IPropertyResolver locator)
-       {
-               this.resolver = locator;
-       }
-
-       public IGetAndSet get(Class<?> clz, String exp)
-       {
-               String key = clz.getName() + "#" + exp;
-
-               IGetAndSet located = map.get(key);
-               if (located == null)
-               {
-                       located = resolver.get(clz, exp);
-                       if (located == null)
-                       {
-                               located = NONE;
-                       }
-                       map.put(key, located);
-               }
-
-               if (located == NONE)
-               {
-                       located = null;
-               }
-
-               return located;
-       }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/wicket/blob/7fd219c3/wicket-core/src/main/java/org/apache/wicket/core/util/reflection/IndexedPropertyGetAndSet.java
----------------------------------------------------------------------
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/core/util/reflection/IndexedPropertyGetAndSet.java
 
b/wicket-core/src/main/java/org/apache/wicket/core/util/reflection/IndexedPropertyGetAndSet.java
index 1eac5af..96fdceb 100644
--- 
a/wicket-core/src/main/java/org/apache/wicket/core/util/reflection/IndexedPropertyGetAndSet.java
+++ 
b/wicket-core/src/main/java/org/apache/wicket/core/util/reflection/IndexedPropertyGetAndSet.java
@@ -26,7 +26,7 @@ public final class IndexedPropertyGetAndSet extends 
AbstractGetAndSet
        private static Method findSetter(final Method getMethod, final Class<?> 
clz)
        {
                String name = getMethod.getName();
-               name = MethodGetAndSet.SET + name.substring(3);
+               name = ReflectionUtility.SET + name.substring(3);
                try
                {
                        return clz.getMethod(name, new Class[] { int.class, 
getMethod.getReturnType() });

http://git-wip-us.apache.org/repos/asf/wicket/blob/7fd219c3/wicket-core/src/main/java/org/apache/wicket/core/util/reflection/MethodGetAndSet.java
----------------------------------------------------------------------
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/core/util/reflection/MethodGetAndSet.java
 
b/wicket-core/src/main/java/org/apache/wicket/core/util/reflection/MethodGetAndSet.java
index 6765dbf..c7fc13a 100644
--- 
a/wicket-core/src/main/java/org/apache/wicket/core/util/reflection/MethodGetAndSet.java
+++ 
b/wicket-core/src/main/java/org/apache/wicket/core/util/reflection/MethodGetAndSet.java
@@ -12,10 +12,7 @@ import org.slf4j.LoggerFactory;
 
 public final class MethodGetAndSet extends AbstractGetAndSet
 {
-       private static final Logger log = 
LoggerFactory.getLogger(MethodGetAndSet.class);
-       public static final String GET = "get";
-       public static final String IS = "is";
-       public static final String SET = "set";
+       static final Logger log = 
LoggerFactory.getLogger(MethodGetAndSet.class);
 
        private final Method getMethod;
        private final Method setMethod;
@@ -133,52 +130,6 @@ public final class MethodGetAndSet extends 
AbstractGetAndSet
                }
        }
 
-       public static Method findSetter(Method getMethod, Class<?> clz)
-       {
-               String name = getMethod.getName();
-               if (name.startsWith(GET))
-               {
-                       name = SET + name.substring(3);
-               }
-               else
-               {
-                       name = SET + name.substring(2);
-               }
-               try
-               {
-                       Method method = clz.getMethod(name, new Class[] { 
getMethod.getReturnType() });
-                       if (method != null)
-                       {
-                               method.setAccessible(true);
-                       }
-                       return method;
-               }
-               catch (NoSuchMethodException e)
-               {
-                       Method[] methods = clz.getMethods();
-                       for (Method method : methods)
-                       {
-                               if (method.getName().equals(name))
-                               {
-                                       Class<?>[] parameterTypes = 
method.getParameterTypes();
-                                       if (parameterTypes.length == 1)
-                                       {
-                                               if 
(parameterTypes[0].isAssignableFrom(getMethod.getReturnType()))
-                                               {
-                                                       return method;
-                                               }
-                                       }
-                               }
-                       }
-                       log.debug("Cannot find setter corresponding to " + 
getMethod);
-               }
-               catch (Exception e)
-               {
-                       log.debug("Cannot find setter corresponding to " + 
getMethod);
-               }
-               return null;
-       }
-
        /**
         * {@inheritDoc}
         */

http://git-wip-us.apache.org/repos/asf/wicket/blob/7fd219c3/wicket-core/src/main/java/org/apache/wicket/core/util/reflection/ObjectWithGetAndSet.java
----------------------------------------------------------------------
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/core/util/reflection/ObjectWithGetAndSet.java
 
b/wicket-core/src/main/java/org/apache/wicket/core/util/reflection/ObjectWithGetAndSet.java
index 4dec997..f6b1aa5 100644
--- 
a/wicket-core/src/main/java/org/apache/wicket/core/util/reflection/ObjectWithGetAndSet.java
+++ 
b/wicket-core/src/main/java/org/apache/wicket/core/util/reflection/ObjectWithGetAndSet.java
@@ -34,11 +34,15 @@ public class ObjectWithGetAndSet
        }
 
        /**
+        * @param createIfNull if the value should be created in case the 
property is null
         * @return The value
         */
-       public Object getValue()
+       public Object getValue(boolean createIfNull)
        {
-               return getAndSet.getValue(value);
+               Object propertyValue = getAndSet.getValue(value);
+               if(propertyValue == null && createIfNull)
+                       propertyValue = getAndSet.newValue(value);
+               return propertyValue;
        }
 
        /**

http://git-wip-us.apache.org/repos/asf/wicket/blob/7fd219c3/wicket-core/src/main/java/org/apache/wicket/core/util/reflection/ReflectionUtility.java
----------------------------------------------------------------------
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/core/util/reflection/ReflectionUtility.java
 
b/wicket-core/src/main/java/org/apache/wicket/core/util/reflection/ReflectionUtility.java
index caa0fed..e035d4b 100644
--- 
a/wicket-core/src/main/java/org/apache/wicket/core/util/reflection/ReflectionUtility.java
+++ 
b/wicket-core/src/main/java/org/apache/wicket/core/util/reflection/ReflectionUtility.java
@@ -3,11 +3,17 @@ package org.apache.wicket.core.util.reflection;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 
-import org.apache.wicket.core.util.lang.DefaultPropertyLocator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class ReflectionUtility
 {
 
+       private static final Logger log = 
LoggerFactory.getLogger(ReflectionUtility.class);
+       public static final String GET = "get";
+       private static final String IS = "is";
+       public static final String SET = "set";
+
        /**
         * @param clz
         * @param expression
@@ -36,7 +42,7 @@ public class ReflectionUtility
                                }
                                tmp = tmp.getSuperclass();
                        }
-                       DefaultPropertyLocator.log.debug("Cannot find field " + 
clz + "." + expression);
+                       log.debug("Cannot find field " + clz + "." + 
expression);
                }
                return field;
        }
@@ -52,7 +58,7 @@ public class ReflectionUtility
                Method method = null;
                try
                {
-                       method = clz.getMethod(MethodGetAndSet.GET + name, 
(Class[])null);
+                       method = clz.getMethod(GET + name, (Class[])null);
                }
                catch (Exception ignored)
                {
@@ -61,11 +67,11 @@ public class ReflectionUtility
                {
                        try
                        {
-                               method = clz.getMethod(MethodGetAndSet.IS + 
name, (Class[])null);
+                               method = clz.getMethod(IS + name, 
(Class[])null);
                        }
                        catch (Exception e)
                        {
-                               DefaultPropertyLocator.log.debug("Cannot find 
getter " + clz + "." + expression);
+                               log.debug("Cannot find getter " + clz + "." + 
expression);
                        }
                }
                return method;
@@ -84,9 +90,69 @@ public class ReflectionUtility
                }
                catch (Exception e)
                {
-                       DefaultPropertyLocator.log.debug("Cannot find method " 
+ clz + "." + expression);
+                       log.debug("Cannot find method " + clz + "." + 
expression);
                }
                return method;
        }
 
+       public static Method findPositionGetter(Class<?> clz, String property)
+       {
+               String name = Character.toUpperCase(property.charAt(0)) + 
property.substring(1);
+               try
+               {
+                       return clz.getMethod(GET + name, new Class[] { 
int.class });
+               }
+               catch (Exception e)
+               {
+                       log.debug("Cannot find method " + clz + "." + name + 
"(int)");
+                       return null;
+               }
+       }
+
+       public static Method findSetter(Method getMethod, Class<?> clz)
+       {
+               String name = getMethod.getName();
+               if (name.startsWith(GET))
+               {
+                       name = SET + name.substring(3);
+               }
+               else
+               {
+                       name = SET + name.substring(2);
+               }
+               try
+               {
+                       Method method = clz.getMethod(name, new Class[] { 
getMethod.getReturnType() });
+                       if (method != null)
+                       {
+                               method.setAccessible(true);
+                       }
+                       return method;
+               }
+               catch (NoSuchMethodException e)
+               {
+                       Method[] methods = clz.getMethods();
+                       for (Method method : methods)
+                       {
+                               if (method.getName().equals(name))
+                               {
+                                       Class<?>[] parameterTypes = 
method.getParameterTypes();
+                                       if (parameterTypes.length == 1)
+                                       {
+                                               if 
(parameterTypes[0].isAssignableFrom(getMethod.getReturnType()))
+                                               {
+                                                       return method;
+                                               }
+                                       }
+                               }
+                       }
+                       log.debug("Cannot find setter corresponding to " + 
getMethod);
+               }
+               catch (Exception e)
+               {
+                       log.debug("Cannot find setter corresponding to " + 
getMethod);
+               }
+               return null;
+       }
+
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/7fd219c3/wicket-core/src/main/java/org/apache/wicket/model/AbstractPropertyModel.java
----------------------------------------------------------------------
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/model/AbstractPropertyModel.java 
b/wicket-core/src/main/java/org/apache/wicket/model/AbstractPropertyModel.java
index 4c48366..4db3ddc 100644
--- 
a/wicket-core/src/main/java/org/apache/wicket/model/AbstractPropertyModel.java
+++ 
b/wicket-core/src/main/java/org/apache/wicket/model/AbstractPropertyModel.java
@@ -159,7 +159,7 @@ public abstract class AbstractPropertyModel<T> extends 
ChainingModel<T>
                                Class<?> targetClass = 
((IObjectClassAwareModel<?>) getTarget()).getObjectClass();
                                if (targetClass != null)
                                {
-                                       return 
PropertyResolver.getPropertyClass(expression, null, targetClass);
+                                       return 
(Class<T>)PropertyResolver.getPropertyClass(expression, null, targetClass);
                                }
                        }
                        catch (WicketRuntimeException e)

http://git-wip-us.apache.org/repos/asf/wicket/blob/7fd219c3/wicket-core/src/test/java/org/apache/wicket/core/util/parser/ParsedPropertyExpressionResolverTest.java
----------------------------------------------------------------------
diff --git 
a/wicket-core/src/test/java/org/apache/wicket/core/util/parser/ParsedPropertyExpressionResolverTest.java
 
b/wicket-core/src/test/java/org/apache/wicket/core/util/parser/ParsedPropertyExpressionResolverTest.java
new file mode 100644
index 0000000..aa00732
--- /dev/null
+++ 
b/wicket-core/src/test/java/org/apache/wicket/core/util/parser/ParsedPropertyExpressionResolverTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.wicket.core.util.parser;
+
+import static org.hamcrest.CoreMatchers.is;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.wicket.ConverterLocator;
+import org.apache.wicket.core.util.lang.IPropertyExpressionResolver;
+import org.apache.wicket.core.util.lang.PropertyResolver;
+import org.apache.wicket.core.util.lang.PropertyResolverConverter;
+import org.apache.wicket.util.lang.Person;
+import org.apache.wicket.util.lang.WeirdList;
+import org.apache.wicket.util.lang.WeirdMap;
+import org.apache.wicket.util.tester.WicketTestCase;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ParsedPropertyExpressionResolverTest extends WicketTestCase
+{
+
+       private static final Integer AN_INTEGER = 10;
+       private static final Integer ANOTHER_INTEGER = 11;
+       private static final PropertyResolverConverter CONVERTER = new 
PropertyResolverConverter(
+               new ConverterLocator(), Locale.US);
+
+       private IPropertyExpressionResolver resolver = new 
ParsedPropertyExpressionResolver();
+       private Person person = new Person();
+       private Map<String, Integer> integerMap = new HashMap<String, 
Integer>();
+       private WeirdMap map = new WeirdMap();
+       private WeirdList list = new WeirdList();
+
+       @Before
+       public void before()
+       {
+               
tester.getApplication().getApplicationSettings().setPropertyExpressionResolver(resolver);
+       }
+
+       @Test
+       public void shouldAllowEmptySpacesInsideMethodCallBrackets() throws 
Exception
+       {
+               person.setName("bob");
+               assertThat("bob", is(PropertyResolver.getValue("person.getName( 
)", this)));
+       }
+
+       @Test
+       public void 
shouldAllowMapKeysWithSpecialCharactersIncludingOpenSquareBracket() throws 
Exception
+       {
+               String code = "!@#$%^&*()_+-=[{}|";
+               String expression = "[" + code + "]";
+               PropertyResolver.setValue(expression, integerMap, AN_INTEGER, 
CONVERTER);
+               assertThat(PropertyResolver.getValue(expression, integerMap), 
is(AN_INTEGER));
+               assertThat(integerMap.get(code), is(AN_INTEGER));
+       }
+
+       @Test
+       public void shouldGetValueAtAListPosition() throws Exception
+       {
+               list.add(null);
+               PropertyResolver.setValue("valueAt.0", list, AN_INTEGER, 
CONVERTER);
+               assertThat(list.get(0), is(AN_INTEGER));
+       }
+
+       @Test
+       public void shouldGetValueAtAMapPosition() throws Exception
+       {
+               PropertyResolver.setValue("valueAt.0", map, AN_INTEGER, 
CONVERTER);
+               assertThat(map.getValueAt(0), is(AN_INTEGER));
+       }
+       
+       /**
+        * https://issues.apache.org/jira/browse/WICKET-6327
+        */
+       @Test
+       public void shouldGetValueInAField() throws Exception
+       {
+               map.field = AN_INTEGER;
+               map.put("field", ANOTHER_INTEGER);
+               list.field = AN_INTEGER;
+               assertThat(PropertyResolver.getValue("map.field", this), 
is(AN_INTEGER));
+               assertThat(PropertyResolver.getValue("map[field]", this), 
is(ANOTHER_INTEGER));
+               assertThat(PropertyResolver.getValue("list.field", this), 
is(AN_INTEGER));
+               
+       }
+
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/7fd219c3/wicket-core/src/test/java/org/apache/wicket/core/util/parser/PropertyExpressionParserTest.java
----------------------------------------------------------------------
diff --git 
a/wicket-core/src/test/java/org/apache/wicket/core/util/parser/PropertyExpressionParserTest.java
 
b/wicket-core/src/test/java/org/apache/wicket/core/util/parser/PropertyExpressionParserTest.java
index da043f2..c0b6d9b 100644
--- 
a/wicket-core/src/test/java/org/apache/wicket/core/util/parser/PropertyExpressionParserTest.java
+++ 
b/wicket-core/src/test/java/org/apache/wicket/core/util/parser/PropertyExpressionParserTest.java
@@ -1,3 +1,19 @@
+/*
+ * 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.wicket.core.util.parser;
 
 import static org.hamcrest.CoreMatchers.is;

http://git-wip-us.apache.org/repos/asf/wicket/blob/7fd219c3/wicket-core/src/test/java/org/apache/wicket/util/lang/OGNLPropertyExpressionResolverTest.java
----------------------------------------------------------------------
diff --git 
a/wicket-core/src/test/java/org/apache/wicket/util/lang/OGNLPropertyExpressionResolverTest.java
 
b/wicket-core/src/test/java/org/apache/wicket/util/lang/OGNLPropertyExpressionResolverTest.java
index af87541..7baf210 100644
--- 
a/wicket-core/src/test/java/org/apache/wicket/util/lang/OGNLPropertyExpressionResolverTest.java
+++ 
b/wicket-core/src/test/java/org/apache/wicket/util/lang/OGNLPropertyExpressionResolverTest.java
@@ -16,922 +16,88 @@
  */
 package org.apache.wicket.util.lang;
 
-import static org.hamcrest.CoreMatchers.is;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Vector;
-
-import org.apache.wicket.ConverterLocator;
-import org.apache.wicket.IConverterLocator;
-import org.apache.wicket.WicketRuntimeException;
-import org.apache.wicket.core.util.lang.DefaultPropertyLocator;
 import org.apache.wicket.core.util.lang.OGNLPropertyExpressionResolver;
+import 
org.apache.wicket.core.util.lang.OGNLPropertyExpressionResolver.DefaultPropertyLocator;
+import 
org.apache.wicket.core.util.lang.OGNLPropertyExpressionResolver.IPropertyLocator;
 import org.apache.wicket.core.util.lang.PropertyResolver;
 import org.apache.wicket.core.util.lang.PropertyResolverConverter;
 import org.apache.wicket.core.util.reflection.AbstractGetAndSet;
-import org.apache.wicket.core.util.reflection.CachingPropertyLocator;
 import org.apache.wicket.core.util.reflection.IGetAndSet;
-import org.apache.wicket.util.convert.ConversionException;
-import org.apache.wicket.util.convert.IConverter;
-import org.apache.wicket.util.convert.converter.AbstractConverter;
 import org.apache.wicket.util.tester.WicketTestCase;
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Test;
 
-/**
- * @author jcompagner
- * 
- */
 public class OGNLPropertyExpressionResolverTest extends WicketTestCase
 {
-
-       private static final PropertyResolverConverter CONVERTER = new 
PropertyResolverConverter(
-               new ConverterLocator(), Locale.US);
-       OGNLPropertyExpressionResolver ognlResolver = new 
OGNLPropertyExpressionResolver();
-
-       private static final int AN_INTEGER = 10;
-       private Person person;
-       private Map<String, Integer> integerMap = new HashMap<String, 
Integer>();
-       private WeirdList integerList = new WeirdList();
-
-       /**
-        * @throws Exception
-        */
-       @Before
-       public void before()
-       {
-               person = new Person();
-       }
-
-       /**
-        * @throws Exception
-        */
-       @After
-       public void after()
-       {
-//             ognlResolver.destroy(tester.getApplication());
-       }
+       private OGNLPropertyExpressionResolver ognlResolver = new 
OGNLPropertyExpressionResolver(
+               new CustomGetAndSetLocator());
 
        /**
-        * @throws Exception
+        * WICKET-5623 custom properties
         */
        @Test
-       public void simpleExpression() throws Exception
+       public void custom()
        {
-               String name = (String)ognlResolver.getValue("name", person);
-               assertNull(name);
-
-               ognlResolver.setValue("name", person, "wicket", CONVERTER);
-               name = (String)ognlResolver.getValue("name", person);
-               assertEquals(name, "wicket");
-       }
-
-       /**
-        * @throws Exception
-        */
-       @Test(expected = ConversionException.class)
-       public void primitiveValue() throws Exception
-       {
-               Integer integer = (Integer)ognlResolver.getValue("age", person);
-               assertTrue(integer == 0);
-
-               ognlResolver.setValue("age", person, 10, CONVERTER);
-               integer = (Integer)ognlResolver.getValue("age", person);
-               assertTrue(integer == 10);
+               tester.getApplication().getApplicationSettings()
+                       .setPropertyExpressionResolver(ognlResolver);
 
-               ognlResolver.setValue("age", person, null, CONVERTER);
-               fail("primitive type can't be set to null");
+               Document document = new Document();
+               document.setType("type");
+               document.setProperty("string", "string");
 
-       }
-
-       /**
-        * @throws Exception
-        */
-       @Test
-       public void pathExpression() throws Exception
-       {
-               person.setAddress(new Address());
-               ognlResolver.setValue("address.street", person, "wicket-street",
-                       CONVERTER);
-               String street = (String)ognlResolver.getValue("address.street", 
person);
-               assertEquals(street, "wicket-street");
+               Document nestedCustom = new Document();
+               nestedCustom.setProperty("string", "string2");
+               document.setProperty("nested", nestedCustom);
 
+               assertEquals("type", PropertyResolver.getValue("type", 
document));
+               assertEquals("string", PropertyResolver.getValue("string", 
document));
+               assertEquals("string2", 
PropertyResolver.getValue("nested.string", document));
        }
 
-       /**
-        * @throws Exception
-        */
-       @Test
-       public void testNull() throws Exception
+       class CustomGetAndSetLocator implements IPropertyLocator
        {
-               String street = (String)ognlResolver.getValue("address.street", 
person);
-               assertNull(street);
-       }
 
-       /**
-        * @throws Exception
-        */
-       @Test
-       public void nullCreation() throws Exception
-       {
-               ognlResolver.setValue("address.street", person, "wicket-street",
-                       CONVERTER);
-               String street = (String)ognlResolver.getValue("address.street", 
person);
-               assertEquals(street, "wicket-street");
+               private IPropertyLocator locator = new DefaultPropertyLocator();
 
-               try
+               @Override
+               public IGetAndSet get(Class<?> clz, String exp)
                {
-                       ognlResolver.setValue("country.name", person, "US", 
CONVERTER);
-                       fail("name can't be set on a country that doesn't have 
default constructor");
-               }
-               catch (WicketRuntimeException ex)
-               {
-               }
-       }
-
-       /**
-        * @throws Exception
-        */
-       @Test
-       public void getterOnly() throws Exception
-       {
-               ognlResolver.setValue("country", person, new Country("US"), 
CONVERTER);
-               ognlResolver.getValue("country.name", person);
-
-               try
-               {
-                       ognlResolver.setValue("country.name", person, "NL", 
CONVERTER);
-               }
-               catch (WicketRuntimeException ex)
-               {
-               }
-       }
-
-       /**
-        * @throws Exception
-        */
-       @Test
-       public void pathExpressionWithConversion() throws Exception
-       {
-               person.setAddress(new Address());
-               ognlResolver.setValue("address.number", person, "10", 
CONVERTER);
-               Integer number = 
(Integer)ognlResolver.getValue("address.number", person);
-               assertEquals(number, new Integer(10));
-
-               try
-               {
-                       ognlResolver.setValue("address.number", person, "10a", 
CONVERTER);
-                       throw new Exception("Conversion error should be 
thrown");
-               }
-               catch (ConversionException ex)
-               {
-               }
-
-       }
-
-       /**
-        * @throws Exception
-        */
-       @Test
-       public void mapLookup() throws Exception
-       {
-               Address address = new Address();
-               ognlResolver.setValue("addressMap", person,
-                       new HashMap<String, Address>(), CONVERTER);
-               ognlResolver.setValue("addressMap.address", person, address, 
CONVERTER);
-               ognlResolver.setValue("addressMap.address.street", person,
-                       "wicket-street", CONVERTER);
-               String street = 
(String)ognlResolver.getValue("addressMap.address.street",
-                       person);
-               assertEquals(street, "wicket-street");
-       }
-
-       /**
-        * @throws Exception
-        */
-       @Test
-       public void mapWithDotLookup() throws Exception
-       {
-               Address address = new Address();
-               HashMap<String, Address> hm = new HashMap<String, Address>();
-               ognlResolver.setValue("addressMap", person, hm, CONVERTER);
-               ognlResolver.setValue("addressMap[address.test]", person, 
address,
-                       CONVERTER);
-               assertNotNull(hm.get("address.test"));
-               ognlResolver.setValue("addressMap[address.test].street", person,
-                       "wicket-street", CONVERTER);
-               String street = (String)ognlResolver
-                       .getValue("addressMap[address.test].street", person);
-               assertEquals(street, "wicket-street");
-       }
-
-       /**
-        * @throws Exception
-        */
-       @Test
-       public void listLookup() throws Exception
-       {
-               ognlResolver.setValue("addressList", person, new 
ArrayList<Address>(),
-                       CONVERTER);
-               ognlResolver.setValue("addressList.0", person, new Address(), 
CONVERTER);
-               ognlResolver.setValue("addressList.10", person, new Address(), 
CONVERTER);
-               ognlResolver.setValue("addressList.1", person, new Address(), 
CONVERTER);
-               ognlResolver.setValue("addressList.1.street", person, 
"wicket-street",
-                       CONVERTER);
-
-               String street = 
(String)ognlResolver.getValue("addressList.0.street",
-                       person);
-               assertNull(street);
-               street = (String)ognlResolver.getValue("addressList.1.street", 
person);
-               assertEquals(street, "wicket-street");
-       }
-
-       /**
-        * @throws Exception
-        */
-       @Test
-       public void arrayLookup() throws Exception
-       {
-               ognlResolver.setValue("addressArray", person,
-                       new Address[] { new Address(), null }, CONVERTER);
-               ognlResolver.setValue("addressArray.0.street", person, 
"wicket-street",
-                       CONVERTER);
-               String street = 
(String)ognlResolver.getValue("addressArray.0.street",
-                       person);
-               assertEquals(street, "wicket-street");
-
-               ognlResolver.setValue("addressArray.1.street", person, 
"wicket-street",
-                       CONVERTER);
-               street = (String)ognlResolver.getValue("addressArray.1.street", 
person);
-               assertEquals(street, "wicket-street");
-       }
-
-       /**
-        * @throws Exception
-        */
-       @Test
-       public void arrayLookupByBrackets() throws Exception
-       {
-               ognlResolver.setValue("addressArray", person,
-                       new Address[] { new Address(), null }, CONVERTER);
-               ognlResolver.setValue("addressArray[0].street", person, 
"wicket-street",
-                       CONVERTER);
-               String street = 
(String)ognlResolver.getValue("addressArray[0].street",
-                       person);
-               assertEquals(street, "wicket-street");
-
-               ognlResolver.setValue("addressArray[1].street", person, 
"wicket-street",
-                       CONVERTER);
-               street = 
(String)ognlResolver.getValue("addressArray[1].street", person);
-               assertEquals(street, "wicket-street");
-       }
-
-       /**
-        * @throws Exception
-        */
-       @Test
-       public void propertyByIndexLookup() throws Exception
-       {
-               ognlResolver.setValue("addressAt.0", person, new Address(), 
CONVERTER);
-               ognlResolver.setValue("addressAt.0.street", person, 
"wicket-street",
-                       CONVERTER);
-               String street = 
(String)ognlResolver.getValue("addressAt.0.street",
-                       person);
-               assertEquals(street, "wicket-street");
-       }
-
-       /**
-        * @throws Exception
-        */
-       @Test
-       public void getPropertyByNotExistingIndexArrayLookup() throws Exception
-       {
-               ognlResolver.setValue("addressArray", person, new Address[] { },
-                       CONVERTER);
-               String street = 
(String)ognlResolver.getValue("addressArray.0.street",
-                       person);
-               assertNull(street);
-               street = 
(String)ognlResolver.getValue("addressArray[0].street", person);
-               assertNull(street);
-       }
-
-       /**
-        * @throws Exception
-        */
-       @Test
-       public void getPropertyByNotExistingIndexListLookup() throws Exception
-       {
-               ognlResolver.setValue("addressList", person, new 
ArrayList<Address>(),
-                       CONVERTER);
-               String street = 
(String)ognlResolver.getValue("addressList.0.street",
-                       person);
-               assertNull(street);
-               street = (String)ognlResolver.getValue("addressList[0].street", 
person);
-               assertNull(street);
-       }
-
-       /**
-        * @throws Exception
-        */
-       @Test
-       public void getIndexPropertyDirectly() throws Exception
-       {
-               Address address = new Address();
-               Address[] addresses = new Address[] { address };
-
-               Address address2 = (Address)ognlResolver.getValue("[0]", 
addresses);
-               assertSame(address, address2);
-       }
-
-       /**
-        * @throws Exception
-        */
-       @Test
-       public void listSizeLookup() throws Exception
-       {
-               List<Address> addresses = new ArrayList<Address>();
-               addresses.add(new Address());
-               addresses.add(new Address());
-               person.setAddressList(addresses);
-               Object size = ognlResolver.getValue("addressList.size", person);
-               assertEquals(size, 2);
-               size = ognlResolver.getValue("addressList.size()", person);
-               assertEquals(size, 2);
-       }
-
-
-       /**
-        * @throws Exception
-        */
-       @Test
-       public void mapSizeLookup() throws Exception
-       {
-               Map<String, Address> addresses = new HashMap<String, Address>();
-               Address address = new Address();
-               addresses.put("size", address);
-               addresses.put("test", new Address());
-               person.setAddressMap(addresses);
-               Object addressFromMap = 
ognlResolver.getValue("addressMap.size", person);
-               assertEquals(addressFromMap, address);
-               Object size = ognlResolver.getValue("addressMap.size()", 
person);
-               assertEquals(size, 2);
-       }
-
-       /**
-        * @throws Exception
-        */
-       @Test
-       public void arraySizeLookup() throws Exception
-       {
-               person.setAddressArray(new Address[] { new Address(), new 
Address() });
-               Object size = ognlResolver.getValue("addressArray.length", 
person);
-               assertEquals(size, 2);
-               size = ognlResolver.getValue("addressArray.size", person);
-               assertEquals(size, 2);
-       }
-
-       /**
-        * @throws Exception
-        */
-       @Test
-       public void methodLookup() throws Exception
-       {
-               Address[] addresses = new Address[] { new Address(), new 
Address() };
-               person.setAddressArray(addresses);
-               Object value = ognlResolver.getValue("getAddressArray()", 
person);
-               assertEquals(value, addresses);
-       }
-
-       /**
-        * @throws Exception
-        */
-       @Test
-       public void field() throws Exception
-       {
-               Address address = new Address();
-               ognlResolver.setValue("address2", person, address, CONVERTER);
-               Address address2 = (Address)ognlResolver.getValue("address2", 
person);
-               assertEquals(address, address2);
-
-               try
-               {
-                       ognlResolver.setValue("address3", person, address, 
CONVERTER);
-                       fail("Shoudln't come here");
-               }
-               catch (RuntimeException ex)
-               {
-
+                       // first try default properties
+                       IGetAndSet getAndSet = locator.get(clz, exp);
+                       if (getAndSet == null && 
Document.class.isAssignableFrom(clz))
+                       {
+                               // fall back to document properties
+                               getAndSet = new DocumentPropertyGetAndSet(exp);
+                       }
+                       return getAndSet;
                }
-       }
-
-       /**
-        * @throws Exception
-        */
-       @Test
-       public void testPrivateField() throws Exception
-       {
-               Address address = new Address();
-               ognlResolver.setValue("privateAddress", person, address, 
CONVERTER);
-               Address address2 = 
(Address)ognlResolver.getValue("privateAddress",
-                       person);
-               assertEquals(address, address2);
-       }
-
-       /**
-        * @throws Exception
-        */
-       @Test
-       public void privateFieldOfSuperClass() throws Exception
-       {
-               Person2 person2 = new Person2();
-               Address address = new Address();
-               ognlResolver.setValue("privateAddress", person2, address, 
CONVERTER);
-               Address address2 = 
(Address)ognlResolver.getValue("privateAddress",
-                       person2);
-               assertEquals(address, address2);
-       }
-
-       /**
-        * 
-        */
-       @Test
-       public void getTargetClass()
-       {
-               Address address = new Address();
-
-               Class<?> clazz = ognlResolver.resolve("number", address, 
address.getClass()).getTargetClass();
-               assertEquals(int.class, clazz);
-
-               Person person = new Person();
-               person.setAddress(new Address());
-
-               clazz = ognlResolver.resolve("address.number", person, 
person.getClass()).getTargetClass();
-               assertEquals(int.class, clazz);
-
-               person.setAddressArray(new Address[] { new Address(), new 
Address() });
-               clazz = ognlResolver.resolve("addressArray[0]", person, 
person.getClass()).getTargetClass();
-               assertEquals(Address.class, clazz);
-
-               clazz = ognlResolver.resolve("addressArray[0].number", person, 
person.getClass()).getTargetClass();
-               assertEquals(int.class, clazz);
-       }
-
-       /**
-        * 
-        */
-       @Test
-       public void getTargetField()
-       {
-               Address address = new Address();
-
-               Field field = ognlResolver.getPropertyField("number", address);
-               assertEquals(field.getName(), "number");
-               assertEquals(field.getType(), int.class);
-
-               Person person = new Person();
-               person.setAddress(new Address());
-
-               field = ognlResolver.getPropertyField("address.number", person);
-               assertEquals(field.getName(), "number");
-               assertEquals(field.getType(), int.class);
-
-               person.setAddressArray(new Address[] { new Address(), new 
Address() });
-               field = ognlResolver.getPropertyField("addressArray[0].number", 
person);
-               assertEquals(field.getName(), "number");
-               assertEquals(field.getType(), int.class);
-       }
-
-       /**
-        * 
-        */
-       @Test
-       public void getTargetGetter()
-       {
-               Address address = new Address();
-
-               Method method = ognlResolver.getPropertyGetter("number", 
address);
-               assertEquals(method.getName(), "getNumber");
-               assertEquals(method.getReturnType(), int.class);
-
-               Person person = new Person();
-               person.setAddress(new Address());
-
-               method = ognlResolver.getPropertyGetter("address.number", 
person);
-               assertEquals(method.getName(), "getNumber");
-               assertEquals(method.getReturnType(), int.class);
-
-               person.setAddressArray(new Address[] { new Address(), new 
Address() });
-               method = 
ognlResolver.getPropertyGetter("addressArray[0].number", person);
-               assertEquals(method.getName(), "getNumber");
-               assertEquals(method.getReturnType(), int.class);
-       }
-
-       /**
-        * @throws Exception
-        */
-       @Test
-       public void onlyPrimitiveGetter() throws Exception
-       {
-               Person person = new Person();
-
-               ognlResolver.setValue("onlyGetterPrimitive", person, 1, 
CONVERTER);
-
-               assertEquals(person.getOnlyGetterPrimitive(), 1);
-               assertEquals(ognlResolver.getValue("onlyGetterPrimitive", 
person), 1);
-
-       }
-
-       /**
-        * @throws Exception
-        */
-       @Test
-       public void onlyStringGetter() throws Exception
-       {
-               Person person = new Person();
-
-               ognlResolver.setValue("onlyGetterString", person, "onlygetter",
-                       CONVERTER);
 
-               assertEquals(person.getOnlyGetterString(), "onlygetter");
-               assertEquals(ognlResolver.getValue("onlyGetterString", person),
-                       "onlygetter");
-
-       }
-
-       /**
-        * 
-        */
-       @Test
-       public void getTargetSetter()
-       {
-               Address address = new Address();
-
-               Method method = ognlResolver.getPropertySetter("number", 
address);
-               assertEquals(method.getName(), "setNumber");
-
-               Person person = new Person();
-               person.setAddress(new Address());
-
-               method = ognlResolver.getPropertySetter("address.number", 
person);
-               assertEquals(method.getName(), "setNumber");
-
-               person.setAddressArray(new Address[] { new Address(), new 
Address() });
-               method = 
ognlResolver.getPropertySetter("addressArray[0].number", person);
-               assertEquals(method.getName(), "setNumber");
-       }
-
-       /**
-        * @throws Exception
-        */
-       @Test
-       public void overriddenGetter() throws Exception
-       {
-               Person2 person = new Person2();
-               person.setName("foo");
-
-               String name = (String)ognlResolver.getValue("name", person);
-               assertEquals("foo", name);
-
-               ognlResolver.setValue("name", person, "bar", CONVERTER);
-
-               name = (String)ognlResolver.getValue("name", person);
-               assertEquals("bar", name);
-
-       }
-
-       /**
-        * @throws Exception
-        */
-       @Test
-       public void propertyClassWithSubType() throws Exception
-       {
-               Person person = new Person();
-               assertEquals(String.class,
-                       ognlResolver.resolve("country.name", person, 
person.getClass()).getTargetClass());
-               try
-               {
-                       ognlResolver.resolve("country.subCountry.name", person, 
person.getClass()).getTargetClass();
-                       fail("country.subCountry shouldnt be found");
-               }
-               catch (Exception e)
+               public class DocumentPropertyGetAndSet extends AbstractGetAndSet
                {
 
-               }
-               person.setCountry(new Country2("test", new Country("test")));
-               ognlResolver.resolve("country.subCountry.name", person, 
person.getClass()).getTargetClass();
-       }
-
-       /**
-        * Used for models in testing.
-        */
-       private static class InnerVectorPOJO extends Vector<Void>
-       {
-               private static final long serialVersionUID = 1L;
-
-               /**
-                */
-               @SuppressWarnings("unused")
-               public String testValue = "vector";
-       }
-
-       /**
-        * Tests the PropertyModel with vector.
-        */
-       @Test
-       public void propertyModel()
-       {
-               String value = (String)ognlResolver.getValue("testValue",
-                       new InnerVectorPOJO());
-               assertEquals("vector", value);
-       }
+                       private String name;
 
-       /**
-        * 
-        */
-       @Test
-       public void directFieldSetWithDifferentTypeThanGetter()
-       {
-               final DirectFieldSetWithDifferentTypeThanGetter obj = new 
DirectFieldSetWithDifferentTypeThanGetter();
-               ognlResolver.setValue("value", obj, 1, null);
-               assertEquals(1, obj.value);
-       }
-
-       private static class DirectFieldSetWithDifferentTypeThanGetter
-       {
-               private int value;
-
-               @SuppressWarnings("unused")
-               public String getValue()
-               {
-                       return String.valueOf(value);
-               }
-       }
-
-       /**
-        * @see <a 
href="https://issues.apache.org/jira/browse/WICKET-1802";>WICKET-1802</a>
-        */
-       @Test
-       public void 
conversionExceptionMessageContainsTheObjectPropertyBeingSet()
-       {
-               try
-               {
-                       PropertyResolverConverter convertToNull = new 
PropertyResolverConverter(null, null)
+                       public DocumentPropertyGetAndSet(String name)
                        {
-                               private static final long serialVersionUID = 1L;
-
-                               @Override
-                               public <T> T convert(Object object, 
java.lang.Class<T> clz)
-                               {
-                                       return null;
-                               }
-                       };
-                       ognlResolver.setValue("name", person, "", 
convertToNull);
-                       fail("Should have thrown an ConversionException");
-               }
-               catch (ConversionException e)
-               {
-                       
assertTrue(e.getMessage().toLowerCase().contains("name"));
-               }
-       }
-
-       /**
-        * WICKET-3441
-        */
-       @Test
-       public void dateToStringConverting()
-       {
-               IConverterLocator converterLocator = new ConverterLocator();
-               Locale locale = Locale.GERMAN;
-               PropertyResolverConverter converter = new 
PropertyResolverConverter(converterLocator,
-                       locale);
-
-               Calendar calDate = Calendar.getInstance();
-               calDate.clear();
-               calDate.set(2011, Calendar.APRIL, 17);
-               Date date = calDate.getTime();
-
-               Object actual = converter.convert(date, String.class);
-               String expected = 
converterLocator.getConverter(Date.class).convertToString(date, locale);
-               assertEquals(expected, actual);
-       }
-
-       /**
-        * WICKET-3441
-        */
-       @Test
-       public void dateToLongConverting()
-       {
-               ConverterLocator converterLocator = new ConverterLocator();
-               final IConverter<Date> dateConverter = 
converterLocator.get(Date.class);
-               IConverter<Long> customLongConverter = new 
AbstractConverter<Long>()
-               {
-                       private static final long serialVersionUID = 1L;
+                               this.name = name;
+                       }
 
                        @Override
-                       public Long convertToObject(String value, Locale locale)
+                       public Object getValue(Object object)
                        {
-                               Date date = 
dateConverter.convertToObject(value, locale);
-                               return date != null ? date.getTime() : null;
+                               return ((Document)object).getProperty(name);
                        }
 
                        @Override
-                       public String convertToString(Long value, Locale locale)
+                       public Object newValue(Object object)
                        {
-                               Date date;
-                               if (value != null)
-                               {
-                                       date = new Date();
-                                       date.setTime(value);
-                               }
-                               else
-                               {
-                                       date = null;
-                               }
-
-                               return dateConverter.convertToString(date, 
locale);
+                               return new Document();
                        }
 
                        @Override
-                       protected Class<Long> getTargetType()
+                       public void setValue(Object object, Object value, 
PropertyResolverConverter converter)
                        {
-                               return Long.class;
+                               ((Document)object).setProperty(name, value);
                        }
-               };
-               converterLocator.set(Long.class, customLongConverter);
-               converterLocator.set(Long.TYPE, customLongConverter);
-
-               PropertyResolverConverter converter = new 
PropertyResolverConverter(converterLocator,
-                       Locale.ENGLISH);
-
-               Calendar calDate = Calendar.getInstance();
-               calDate.clear();
-               calDate.set(2011, Calendar.APRIL, 17);
-               Date date = calDate.getTime();
-
-               Object actual = converter.convert(date, Long.class);
-               assertEquals(date.getTime(), actual);
-       }
-
-//     /**
-//      * WICKET-5623 custom properties
-//      */
-//     @Test
-//     public void custom()
-//     {
-//             Document document = new Document();
-//             document.setType("type");
-//             document.setProperty("string", "string");
-//
-//             Document nestedCustom = new Document();
-//             nestedCustom.setProperty("string", "string2");
-//             document.setProperty("nested", nestedCustom);
-//
-//             ognlResolver.setLocator(tester.getApplication(),
-//                     new CachingPropertyLocator(new 
CustomGetAndSetLocator()));
-//
-//             assertEquals("type", ognlResolver.getValue("type", document));
-//             assertEquals("string", ognlResolver.getValue("string", 
document));
-//             assertEquals("string2", ognlResolver.getValue("nested.string", 
document));
-//     }
-
-//     class CustomGetAndSetLocator implements IPropertyLocator
-//     {
-//
-//             private IPropertyLocator locator = new DefaultPropertyLocator();
-//
-//             @Override
-//             public IGetAndSet get(Class<?> clz, String exp)
-//             {
-//                     // first try default properties
-//                     IGetAndSet getAndSet = locator.get(clz, exp);
-//                     if (getAndSet == null && 
Document.class.isAssignableFrom(clz))
-//                     {
-//                             // fall back to document properties
-//                             getAndSet = new DocumentPropertyGetAndSet(exp);
-//                     }
-//                     return getAndSet;
-//             }
-//
-//             public class DocumentPropertyGetAndSet extends AbstractGetAndSet
-//             {
-//
-//                     private String name;
-//
-//                     public DocumentPropertyGetAndSet(String name)
-//                     {
-//                             this.name = name;
-//                     }
-//
-//                     @Override
-//                     public Object getValue(Object object)
-//                     {
-//                             return ((Document)object).getProperty(name);
-//                     }
-//
-//                     @Override
-//                     public Object newValue(Object object)
-//                     {
-//                             return new Document();
-//                     }
-//
-//                     @Override
-//                     public void setValue(Object object, Object value, 
PropertyResolverConverter converter)
-//                     {
-//                             ((Document)object).setProperty(name, value);
-//                     }
-//             }
-//     }
-
-
-       // EDGE CASES
-       @Test
-       public void shouldAllowEmptySpacesInsideMethodCallBrackets() throws 
Exception
-       {
-               person.setName("bob");
-               assertThat("bob", is(PropertyResolver.getValue("person.getName( 
)", this)));
-       }
-
-       @Test
-       public void 
shouldAllowMapKeysWithSpecialCharactersIncludingOpenSquareBracket() throws 
Exception
-       {
-               String code = "!@#$%^&*()_+-=[{}|";
-               String expression = "[" + code + "]";
-               PropertyResolver.setValue(expression, integerMap, AN_INTEGER, 
CONVERTER);
-               assertThat(PropertyResolver.getValue(expression, integerMap), 
is(AN_INTEGER));
-               assertThat(integerMap.get(code), is(AN_INTEGER));
-       }
-
-       @Test
-       public void shouldAllowMapKeysWithDot() throws Exception
-       {
-               String code = "code-1.0";
-               String expression = "[" + code + "]";
-               PropertyResolver.setValue(expression, integerMap, AN_INTEGER, 
CONVERTER);
-               assertThat(PropertyResolver.getValue(expression, integerMap), 
is(AN_INTEGER));
-               assertThat(integerMap.get(code), is(AN_INTEGER));
-       }
-
-       @Test
-       public void shouldAllowMapKeysHavingQuotes() throws Exception
-       {
-               String code = "the\"key\"";
-               String expression = "[" + code + "]";
-               PropertyResolver.setValue(expression, integerMap, AN_INTEGER, 
CONVERTER);
-               assertThat(PropertyResolver.getValue(expression, integerMap), 
is(AN_INTEGER));
-               assertThat(integerMap.get(code), is(AN_INTEGER));
-       }
-
-       @Test
-       public void shouldPriorityzeListIndex() throws Exception
-       {
-               integerList.set0(AN_INTEGER);
-               assertThat(PropertyResolver.getValue("integerList.0", this), 
is(AN_INTEGER));
-       }
-
-       @Test
-       public void shouldPriorityzeMapKeyInSquareBrakets() throws Exception
-       {
-               PropertyResolver.setValue("[class]", integerMap, AN_INTEGER, 
CONVERTER);
-               assertThat(PropertyResolver.getValue("[class]", integerMap), 
is(AN_INTEGER));
-       }
-
-       @Test
-       public void shouldPriorityzeMapKeyInSquareBraketsAfterAnExpresison() 
throws Exception
-       {
-               PropertyResolver.setValue("integerMap[class]", this, 
AN_INTEGER, CONVERTER);
-               assertThat(PropertyResolver.getValue("integerMap[class]", 
this), is(AN_INTEGER));
-       }
-
-       @Test
-       public void shouldPriorityzeMethodCallWhenEndedByParentises() throws 
Exception
-       {
-               assertThat(PropertyResolver.getValue("integerMap.getClass()", 
this), is(HashMap.class));
-       }
-
-
-       static class WeirdList extends ArrayList<Integer>
-       {
-               private static final long serialVersionUID = 1L;
-               private Integer integer;
-
-               public void set0(Integer integer)
-               {
-                       this.integer = integer;
-
-               }
-
-               public Integer get0()
-               {
-                       return integer;
                }
        }
-}
\ No newline at end of file
+}

Reply via email to