You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2011/09/23 19:20:38 UTC

svn commit: r1174893 - in /tapestry/tapestry5/trunk/tapestry-core/src: main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java

Author: hlship
Date: Fri Sep 23 17:20:38 2011
New Revision: 1174893

URL: http://svn.apache.org/viewvc?rev=1174893&view=rev
Log:
TAP5-1555: Property Expression Array Disallows null and this

Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java?rev=1174893&r1=1174892&r2=1174893&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java Fri Sep 23 17:20:38 2011
@@ -14,34 +14,6 @@
 
 package org.apache.tapestry5.internal.services;
 
-import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.DECIMAL;
-import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.DEREF;
-import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.FALSE;
-import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.IDENTIFIER;
-import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.INTEGER;
-import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.INVOKE;
-import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.LIST;
-import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.MAP;
-import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.NOT;
-import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.NULL;
-import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.RANGEOP;
-import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.SAFEDEREF;
-import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.STRING;
-import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.THIS;
-import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.TRUE;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.lang.reflect.Type;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
 import org.antlr.runtime.ANTLRInputStream;
 import org.antlr.runtime.CommonTokenStream;
 import org.antlr.runtime.tree.Tree;
@@ -56,26 +28,28 @@ import org.apache.tapestry5.ioc.internal
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.internal.util.GenericsUtils;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
-import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
-import org.apache.tapestry5.ioc.services.PropertyAccess;
-import org.apache.tapestry5.ioc.services.PropertyAdapter;
-import org.apache.tapestry5.ioc.services.TypeCoercer;
+import org.apache.tapestry5.ioc.services.*;
 import org.apache.tapestry5.ioc.util.AvailableValues;
 import org.apache.tapestry5.ioc.util.UnknownValueException;
-import org.apache.tapestry5.plastic.Condition;
-import org.apache.tapestry5.plastic.InstructionBuilder;
-import org.apache.tapestry5.plastic.InstructionBuilderCallback;
-import org.apache.tapestry5.plastic.MethodDescription;
-import org.apache.tapestry5.plastic.PlasticClass;
-import org.apache.tapestry5.plastic.PlasticClassTransformer;
-import org.apache.tapestry5.plastic.PlasticField;
-import org.apache.tapestry5.plastic.PlasticMethod;
-import org.apache.tapestry5.plastic.PlasticUtils;
+import org.apache.tapestry5.plastic.*;
 import org.apache.tapestry5.services.ComponentLayer;
 import org.apache.tapestry5.services.InvalidationListener;
 import org.apache.tapestry5.services.PropertyConduitSource;
 
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.*;
+
 public class PropertyConduitSourceImpl implements PropertyConduitSource, InvalidationListener
 {
     static class ConduitMethods
@@ -124,7 +98,7 @@ public class PropertyConduitSourceImpl i
     };
 
     private static final String[] SINGLE_OBJECT_ARGUMENT = new String[]
-    { Object.class.getName() };
+            {Object.class.getName()};
 
     @SuppressWarnings("unchecked")
     private static Method getMethod(Class containingClass, String name, Class... parameterTypes)
@@ -132,8 +106,7 @@ public class PropertyConduitSourceImpl i
         try
         {
             return containingClass.getMethod(name, parameterTypes);
-        }
-        catch (NoSuchMethodException ex)
+        } catch (NoSuchMethodException ex)
         {
             throw new IllegalArgumentException(ex);
         }
@@ -176,16 +149,20 @@ public class PropertyConduitSourceImpl i
 
         final Class genericType;
 
-        /** Describes the term, for use in error messages. */
+        /**
+         * Describes the term, for use in error messages.
+         */
         final String description;
 
         final AnnotationProvider annotationProvider;
 
-        /** Callback that will implement the term. */
+        /**
+         * Callback that will implement the term.
+         */
         final InstructionBuilderCallback callback;
 
         Term(Type type, Class genericType, String description, AnnotationProvider annotationProvider,
-                InstructionBuilderCallback callback)
+             InstructionBuilderCallback callback)
         {
             this.type = type;
             this.genericType = genericType;
@@ -204,7 +181,9 @@ public class PropertyConduitSourceImpl i
             this(type, description, null, callback);
         }
 
-        /** Returns a clone of this Term with a new callback. */
+        /**
+         * Returns a clone of this Term with a new callback.
+         */
         Term withCallback(InstructionBuilderCallback newCallback)
         {
             return new Term(type, genericType, description, annotationProvider, newCallback);
@@ -388,8 +367,7 @@ public class PropertyConduitSourceImpl i
             if (callbacks.isEmpty())
             {
                 navMethod = getRootMethod;
-            }
-            else
+            } else
             {
                 navMethod = plasticClass.introducePrivateMethod(PlasticUtils.toTypeName(activeClass), "navigate",
                         SINGLE_OBJECT_ARGUMENT, null);
@@ -649,8 +627,7 @@ public class PropertyConduitSourceImpl i
         }
 
         /**
-         * @param node
-         *            subexpression to invert
+         * @param node subexpression to invert
          */
         private void implementNotOpGetter(final Tree node)
         {
@@ -685,13 +662,10 @@ public class PropertyConduitSourceImpl i
 
         /**
          * Uses the builder to add instructions for a subexpression.
-         * 
-         * @param builder
-         *            used to add instructions
-         * @param activeType
-         *            type of value on top of the stack when this code will execute, or null if no value on stack
-         * @param node
-         *            defines the expression
+         *
+         * @param builder    used to add instructions
+         * @param activeType type of value on top of the stack when this code will execute, or null if no value on stack
+         * @param node       defines the expression
          * @return the expression type
          */
         private Type implementSubexpression(InstructionBuilder builder, Type activeType, Tree node)
@@ -774,9 +748,21 @@ public class PropertyConduitSourceImpl i
 
                         return implementNotExpression(builder, node);
 
+                    case THIS:
+
+                        invokeGetRootMethod(builder);
+
+                        return rootType;
+
+                    case NULL:
+
+                        builder.loadNull();
+
+                        return Void.class;
+
                     default:
                         throw unexpectedNodeType(node, TRUE, FALSE, INTEGER, DECIMAL, STRING, DEREF, SAFEDEREF,
-                                IDENTIFIER, INVOKE, LIST, NOT);
+                                IDENTIFIER, INVOKE, LIST, NOT, THIS, NULL);
                 }
             }
         }
@@ -842,7 +828,7 @@ public class PropertyConduitSourceImpl i
             builder.newInstance(HashMap.class);
             builder.dupe().loadConstant(count).invokeConstructor(HashMap.class, int.class);
 
-            for (int i = 0; i < count; i+=2)
+            for (int i = 0; i < count; i += 2)
             {
                 builder.dupe();
 
@@ -851,7 +837,7 @@ public class PropertyConduitSourceImpl i
                 boxIfPrimitive(builder, GenericsUtils.asClass(keyType));
 
                 //and the value:
-                Type valueType = implementSubexpression(builder, null, mapNode.getChild(i+1));
+                Type valueType = implementSubexpression(builder, null, mapNode.getChild(i + 1));
                 boxIfPrimitive(builder, GenericsUtils.asClass(valueType));
 
                 //put the value into the array, then pop off the returned object.
@@ -885,16 +871,12 @@ public class PropertyConduitSourceImpl i
         /**
          * Invokes a method that may take parameters. The children of the invokeNode are subexpressions
          * to be evaluated, and potentially coerced, so that they may be passed to the method.
-         * 
-         * @param builder
-         *            constructs code
-         * @param method
-         *            method to invoke
-         * @param node
-         *            INVOKE or RANGEOP node
-         * @param childOffset
-         *            offset within the node to the first child expression (1 in an INVOKE node because the
-         *            first child is the method name, 0 in a RANGEOP node)
+         *
+         * @param builder     constructs code
+         * @param method      method to invoke
+         * @param node        INVOKE or RANGEOP node
+         * @param childOffset offset within the node to the first child expression (1 in an INVOKE node because the
+         *                    first child is the method name, 0 in a RANGEOP node)
          */
         private void invokeMethod(InstructionBuilder builder, Method method, Tree node, int childOffset)
         {
@@ -927,8 +909,7 @@ public class PropertyConduitSourceImpl i
                     if (parameterType.isPrimitive())
                     {
                         builder.castOrUnbox(parameterType.getName());
-                    }
-                    else
+                    } else
                     {
                         builder.checkcast(parameterType);
                     }
@@ -947,7 +928,7 @@ public class PropertyConduitSourceImpl i
         /**
          * Analyzes a DEREF or SAFEDEREF node, proving back a term that identifies its type and provides a callback to
          * peform the dereference.
-         * 
+         *
          * @return a term indicating the type of the expression to this point, and a {@link InstructionBuilderCallback}
          *         to advance the evaluation of the expression form the previous value to the current
          */
@@ -1062,11 +1043,17 @@ public class PropertyConduitSourceImpl i
 
             // Prefer the accessor over the field
 
-            if (adapter.getReadMethod() != null) { return buildGetterMethodAccessTerm(activeType, propertyName,
-                    adapter.getReadMethod()); }
+            if (adapter.getReadMethod() != null)
+            {
+                return buildGetterMethodAccessTerm(activeType, propertyName,
+                        adapter.getReadMethod());
+            }
 
-            if (adapter.getField() != null) { return buildPublicFieldAccessTerm(activeType, propertyName,
-                    adapter.getField()); }
+            if (adapter.getField() != null)
+            {
+                return buildPublicFieldAccessTerm(activeType, propertyName,
+                        adapter.getField());
+            }
 
             throw new RuntimeException(String.format(
                     "Property '%s' of class %s is not readable (it has no read accessor method).", adapter.getName(),
@@ -1129,13 +1116,10 @@ public class PropertyConduitSourceImpl i
 
         /**
          * Casts the results of a field read or method invocation based on generic information.
-         * 
-         * @param builder
-         *            used to add instructions
-         * @param rawType
-         *            the simple type (often Object) of the field (or method return type)
-         * @param genericType
-         *            the generic Type, from which parameterizations can be determined
+         *
+         * @param builder     used to add instructions
+         * @param rawType     the simple type (often Object) of the field (or method return type)
+         * @param genericType the generic Type, from which parameterizations can be determined
          */
         private void castToGenericType(InstructionBuilder builder, Class rawType, final Type genericType)
         {
@@ -1178,7 +1162,8 @@ public class PropertyConduitSourceImpl i
 
                     castToGenericType(builder, method.getReturnType(), genericType);
                 }
-            });
+            }
+            );
         }
 
         private Method findMethod(Class activeType, String methodName, int parameterCount)
@@ -1199,8 +1184,7 @@ public class PropertyConduitSourceImpl i
                 if (searchType != Object.class)
                 {
                     searchType = Object.class;
-                }
-                else
+                } else
                 {
                     throw new RuntimeException(String.format("Class %s does not contain a public method named '%s()'.",
                             activeType.getName(), methodName));
@@ -1234,7 +1218,9 @@ public class PropertyConduitSourceImpl i
             return boolean.class;
         }
 
-        /** Defer creation of the delegate field unless actually needed. */
+        /**
+         * Defer creation of the delegate field unless actually needed.
+         */
         private PlasticField getDelegateField()
         {
             if (delegateField == null)
@@ -1297,11 +1283,9 @@ public class PropertyConduitSourceImpl i
      * conduits for the same
      * rootClass/expression, and it will get sorted out when the conduit is
      * stored into the cache.
-     * 
-     * @param rootClass
-     *            class of root object for expression evaluation
-     * @param expression
-     *            expression to be evaluated
+     *
+     * @param rootClass  class of root object for expression evaluation
+     * @param expression expression to be evaluated
      * @return the conduit
      */
     private PropertyConduit build(final Class rootClass, String expression)
@@ -1371,8 +1355,7 @@ public class PropertyConduitSourceImpl i
 
             return proxyFactory.createProxy(InternalPropertyConduit.class,
                     new PropertyConduitBuilder(rootClass, expression, tree)).newInstance();
-        }
-        catch (Exception ex)
+        } catch (Exception ex)
         {
             throw new PropertyExpressionException(String.format("Exception generating conduit for expression '%s': %s",
                     expression, InternalUtils.toMessage(ex)), expression, ex);
@@ -1420,8 +1403,7 @@ public class PropertyConduitSourceImpl i
         try
         {
             ais = new ANTLRInputStream(is);
-        }
-        catch (IOException ex)
+        } catch (IOException ex)
         {
             throw new RuntimeException(ex);
         }
@@ -1435,8 +1417,7 @@ public class PropertyConduitSourceImpl i
         try
         {
             return (Tree) parser.start().getTree();
-        }
-        catch (Exception ex)
+        } catch (Exception ex)
         {
             throw new RuntimeException(String.format("Error parsing property expression '%s': %s.", expression,
                     ex.getMessage()), ex);

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java?rev=1174893&r1=1174892&r2=1174893&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java Fri Sep 23 17:20:38 2011
@@ -25,7 +25,6 @@ import org.apache.tapestry5.internal.tes
 import org.apache.tapestry5.internal.util.Holder;
 import org.apache.tapestry5.internal.util.IntegerRange;
 import org.apache.tapestry5.ioc.internal.services.ClassFactoryImpl;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.services.ClassFab;
 import org.apache.tapestry5.ioc.services.ClassFactory;
 import org.apache.tapestry5.services.PropertyConduitSource;
@@ -105,8 +104,7 @@ public class PropertyConduitSourceImplTe
         {
             pc.set(bean, 42);
             unreachable();
-        }
-        catch (RuntimeException ex)
+        } catch (RuntimeException ex)
         {
             assertEquals(ex.getMessage(), "Literal values are not updateable.");
         }
@@ -122,8 +120,7 @@ public class PropertyConduitSourceImplTe
         {
             normal.set(bean, 42);
             unreachable();
-        }
-        catch (RuntimeException ex)
+        } catch (RuntimeException ex)
         {
             assertEquals(ex.getMessage(), "Literal values are not updateable.");
         }
@@ -147,8 +144,7 @@ public class PropertyConduitSourceImplTe
         {
             normal.get(bean);
             unreachable();
-        }
-        catch (NullPointerException ex)
+        } catch (NullPointerException ex)
         {
             // Expected.
         }
@@ -159,8 +155,7 @@ public class PropertyConduitSourceImplTe
         {
             normal.set(bean, "Howard");
             unreachable();
-        }
-        catch (NullPointerException ex)
+        } catch (NullPointerException ex)
         {
             // Expected.
         }
@@ -408,7 +403,7 @@ public class PropertyConduitSourceImplTe
         bean.type1Field = holder;
         bean.type2Field = 5678L;
         bean.type2ArrayField = new Long[]
-        { 123L, 456L };
+                {123L, 456L};
 
         PropertyConduit conduit = source.create(RealizedParameters.class, "type1property.get().firstName");
         assertSame(conduit.get(bean), first);
@@ -465,8 +460,7 @@ public class PropertyConduitSourceImplTe
         {
             conduit.get(null);
             unreachable();
-        }
-        catch (NullPointerException ex)
+        } catch (NullPointerException ex)
         {
             assertEquals(ex.getMessage(), "Root object of property expression 'value.get()' is null.");
         }
@@ -484,8 +478,7 @@ public class PropertyConduitSourceImplTe
         {
             conduit.get(bean);
             unreachable();
-        }
-        catch (NullPointerException ex)
+        } catch (NullPointerException ex)
         {
             assertMessageContains(ex, "Property 'simple' (within property expression 'simple.lastName', of",
                     ") is null.");
@@ -613,9 +606,9 @@ public class PropertyConduitSourceImplTe
         EchoBean bean = new EchoBean();
 
         bean.setStoredArray(new Number[][]
-        { new Integer[]
-        { 1, 2 }, new Double[]
-        { 3.0, 4.0 } });
+                {new Integer[]
+                        {1, 2}, new Double[]
+                        {3.0, 4.0}});
 
         Number[][] array = (Number[][]) conduit.get(bean);
 
@@ -656,7 +649,7 @@ public class PropertyConduitSourceImplTe
         PropertyConduit conduit = source.create(EchoBean.class, "echoMap({ 1: 'one', 2.0: 'two', storedString: stringSource.value })");
         EchoBean bean = new EchoBean();
 
-        bean.setStoredString( "3" );
+        bean.setStoredString("3");
         bean.setStringSource(new StringSource("three"));
 
         Map m = (Map) conduit.get(bean);
@@ -720,8 +713,7 @@ public class PropertyConduitSourceImplTe
         {
             source.create(IntegerHolder.class, "getValue(");
             unreachable();
-        }
-        catch (RuntimeException ex)
+        } catch (RuntimeException ex)
         {
             //note that addition of map support changed how this expression was parsed such that the error is now
             //reported at character 8, (, rather than 0: getValue(.
@@ -737,8 +729,7 @@ public class PropertyConduitSourceImplTe
         {
             source.create(IntegerHolder.class, "fred #");
             unreachable();
-        }
-        catch (RuntimeException ex)
+        } catch (RuntimeException ex)
         {
             assertEquals(ex.getMessage(),
                     "Error parsing property expression 'fred #': Unable to parse input at character position 6.");
@@ -831,4 +822,21 @@ public class PropertyConduitSourceImplTe
 
         assertNotNull(pc.getAnnotation(NonVisual.class));
     }
+
+    /**
+     * TAP5-1555
+     */
+    @Test
+    public void this_and_null_inside_array()
+    {
+        PropertyConduit pc = source.create(NonVisualBean.class, "[this, null]");
+
+        Object bean = new NonVisualBean();
+
+        List list = (List) pc.get(bean);
+
+        assertEquals(list.size(), 2);
+        assertSame(list.get(0), bean);
+        assertNull(list.get(1));
+    }
 }