Anonymous avatar Anonymous committed 7c7c582

Resolves OGNL-24. ListPropertyAccessor wasn't delegating to superclass for getSource in operations where a list object has been extended ..

Comments (0)

Files changed (12)

   </component>
   <component name="ChangeListManager">
     <list default="true" name="Default" comment="">
-      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/test/java/org/ognl/test/NullStringCatenationTest.java" afterPath="$PROJECT_DIR$/src/test/java/org/ognl/test/NullStringCatenationTest.java" />
-      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/java/ognl/ASTAdd.java" afterPath="$PROJECT_DIR$/src/java/ognl/ASTAdd.java" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/test/java/org/ognl/test/CollectionDirectPropertyTest.java" afterPath="$PROJECT_DIR$/src/test/java/org/ognl/test/CollectionDirectPropertyTest.java" />
+      <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/test/java/org/ognl/test/TestOgnlRuntime.java" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/java/ognl/OgnlRuntime.java" afterPath="$PROJECT_DIR$/src/java/ognl/OgnlRuntime.java" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/test/java/org/ognl/test/IndexedPropertyTest.java" afterPath="$PROJECT_DIR$/src/test/java/org/ognl/test/IndexedPropertyTest.java" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/test/java/org/ognl/test/objects/Indexed.java" afterPath="$PROJECT_DIR$/src/test/java/org/ognl/test/objects/Indexed.java" />
+      <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/test/java/org/ognl/test/objects/ListSource.java" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/java/ognl/ListPropertyAccessor.java" afterPath="$PROJECT_DIR$/src/java/ognl/ListPropertyAccessor.java" />
+      <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/test/java/org/ognl/test/objects/ListSourceImpl.java" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/java/ognl/enhance/ExpressionCompiler.java" afterPath="$PROJECT_DIR$/src/java/ognl/enhance/ExpressionCompiler.java" />
       <change type="MODIFICATION" beforePath="$PROJECT_DIR$/OGNL.iws" afterPath="$PROJECT_DIR$/OGNL.iws" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/test/java/org/ognl/test/accessors/ListPropertyAccessorTest.java" afterPath="$PROJECT_DIR$/src/test/java/org/ognl/test/accessors/ListPropertyAccessorTest.java" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/java/ognl/ASTChain.java" afterPath="$PROJECT_DIR$/src/java/ognl/ASTChain.java" />
     </list>
   </component>
   <component name="ChangesViewManager" flattened_view="true" />
       <file leaf-file-name="ExpressionCompiler.java" pinned="false" current="true" current-in-tab="true">
         <entry file="file://$PROJECT_DIR$/src/java/ognl/enhance/ExpressionCompiler.java">
           <provider selected="true" editor-type-id="text-editor">
-            <state line="381" column="11" selection-start="14550" selection-end="14550" vertical-scroll-proportion="0.32197616">
+            <state line="82" column="0" selection-start="3419" selection-end="3419" vertical-scroll-proportion="0.3943782">
+              <folding />
+            </state>
+          </provider>
+        </entry>
+      </file>
+      <file leaf-file-name="IndexedPropertyTest.java" pinned="false" current="false" current-in-tab="false">
+        <entry file="file://$PROJECT_DIR$/src/test/java/org/ognl/test/IndexedPropertyTest.java">
+          <provider selected="true" editor-type-id="text-editor">
+            <state line="55" column="0" selection-start="3050" selection-end="3050" vertical-scroll-proportion="0.31942078">
+              <folding />
+            </state>
+          </provider>
+        </entry>
+      </file>
+      <file leaf-file-name="ASTProperty.java" pinned="false" current="false" current-in-tab="false">
+        <entry file="file://$PROJECT_DIR$/src/java/ognl/ASTProperty.java">
+          <provider selected="true" editor-type-id="text-editor">
+            <state line="598" column="54" selection-start="26507" selection-end="26507" vertical-scroll-proportion="0.83390117">
+              <folding />
+            </state>
+          </provider>
+        </entry>
+      </file>
+      <file leaf-file-name="ListPropertyAccessor.java" pinned="false" current="false" current-in-tab="false">
+        <entry file="file://$PROJECT_DIR$/src/java/ognl/ListPropertyAccessor.java">
+          <provider selected="true" editor-type-id="text-editor">
+            <state line="185" column="0" selection-start="7094" selection-end="7094" vertical-scroll-proportion="0.41226575">
+              <folding>
+                <element signature="imports" expanded="true" />
+              </folding>
+            </state>
+          </provider>
+        </entry>
+      </file>
+      <file leaf-file-name="ObjectPropertyAccessor.java" pinned="false" current="false" current-in-tab="false">
+        <entry file="file://$PROJECT_DIR$/src/java/ognl/ObjectPropertyAccessor.java">
+          <provider selected="true" editor-type-id="text-editor">
+            <state line="266" column="100" selection-start="9833" selection-end="9833" vertical-scroll-proportion="0.770017">
               <folding />
             </state>
           </provider>
   </component>
   <component name="RecentsManager" />
   <component name="RestoreUpdateTree" />
-  <component name="RunManager" selected="JUnit.PropertyTest">
-    <tempConfiguration default="false" name="PropertyTest" type="JUnit" factoryName="JUnit" enabled="false" merge="false">
+  <component name="RunManager" selected="JUnit.CollectionDirectPropertyTest">
+    <tempConfiguration default="false" name="CollectionDirectPropertyTest" type="JUnit" factoryName="JUnit" enabled="false" merge="false">
       <pattern value="org.ognl.test.*" />
       <module name="OGNL" />
       <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
       <option name="ALTERNATIVE_JRE_PATH" />
       <option name="PACKAGE_NAME" value="org.ognl.test" />
-      <option name="MAIN_CLASS_NAME" value="org.ognl.test.PropertyTest" />
+      <option name="MAIN_CLASS_NAME" value="org.ognl.test.CollectionDirectPropertyTest" />
       <option name="METHOD_NAME" />
       <option name="TEST_OBJECT" value="class" />
       <option name="VM_PARAMETERS" />
     <option name="PERFORM_COMMIT_IN_BACKGROUND" value="false" />
     <option name="PUT_FOCUS_INTO_COMMENT" value="false" />
     <option name="FORCE_NON_EMPTY_COMMENT" value="false" />
-    <option name="LAST_COMMIT_MESSAGE" value="Resolves OGNL-23. String concatenation not working properly in ternary statements." />
+    <option name="LAST_COMMIT_MESSAGE" value="Resolves OGNL-24. ListPropertyAccessor wasn't delegating to superclass for getSource in operations where a list object has been extended .." />
     <option name="SAVE_LAST_COMMIT_MESSAGE" value="true" />
     <option name="CHECKIN_DIALOG_SPLITTER_PROPORTION" value="0.8" />
     <option name="OPTIMIZE_IMPORTS_BEFORE_PROJECT_COMMIT" value="true" />
     <option name="UPDATE_GROUP_BY_PACKAGES" value="false" />
     <option name="SHOW_FILE_HISTORY_AS_TREE" value="false" />
     <option name="FILE_HISTORY_SPLITTER_PROPORTION" value="0.6" />
-    <MESSAGE value="Partially fixes OGNL-17 . It's only partial because someone tried to sneak in two different tickets under one." />
     <MESSAGE value="Fixes OGNL-17. ...Too much to list, the summary is that ASTCtor / ASTList hadn't had the same kind of context/ refactoring love &#10;that ASTMethod/ property/ etc had ...." />
     <MESSAGE value="Fixes OGNL-18.&#10;&#10;Array/List/etc accessors weren't properly detecting object vs primitive types when accessing their respective properties because ASTConst was still sticking the old object class type as the current context type. This involved refactoring ASTConst to correctly place the native type for numerics as well as fixing all the problems resulting from this new behavior." />
     <MESSAGE value="Fixes OGNL-14 &amp;&amp; OGNL-16. &#10;&#10;OgnlRuntime.getChildSource was still using the old non &quot;($w)&quot; widening casting semantics provided by javassist." />
     <MESSAGE value="Upgraded javacc and re-ran grammar generator." />
     <MESSAGE value="Resolves OGNL-22. Null strings weren't being handled properly in mathematical expressions." />
     <MESSAGE value="Resolves OGNL-23. String concatenation not working properly in ternary statements." />
+    <MESSAGE value="Resolves OGNL-24. ListPropertyAccessor wasn't delegating to superclass for getSource in operations where a list object has been extended .." />
   </component>
   <component name="antWorkspaceConfiguration">
     <option name="IS_AUTOSCROLL_TO_SOURCE" value="false" />
     <option name="myLastEditedConfigurable" />
   </component>
   <component name="editorHistoryManager">
-    <entry file="file://$PROJECT_DIR$/src/java/ognl/ASTProperty.java">
+    <entry file="file://$PROJECT_DIR$/src/test/java/org/ognl/test/objects/Indexed.java">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="445" column="124" selection-start="19295" selection-end="19295" vertical-scroll-proportion="0.012776831">
+        <state line="40" column="41" selection-start="1989" selection-end="1989" vertical-scroll-proportion="0.15807962">
           <folding />
         </state>
       </provider>
     </entry>
-    <entry file="file://$PROJECT_DIR$/src/java/ognl/ASTShiftLeft.java">
+    <entry file="file://$PROJECT_DIR$/src/test/java/org/ognl/test/accessors/ListPropertyAccessorTest.java">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="58" column="0" selection-start="2405" selection-end="2405" vertical-scroll-proportion="0.3705281">
+        <state line="67" column="0" selection-start="2308" selection-end="2308" vertical-scroll-proportion="1.0187354">
           <folding />
         </state>
       </provider>
     </entry>
-    <entry file="file://$PROJECT_DIR$/src/java/ognl/ObjectArrayPool.java">
+    <entry file="jar:///usr/local/jdk1.5.0_11/src.zip!/java/security/Permission.java">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="174" column="0" selection-start="5314" selection-end="5314" vertical-scroll-proportion="0.39948893">
+        <state line="14" column="3" selection-start="454" selection-end="454" vertical-scroll-proportion="0.15807962">
           <folding />
         </state>
       </provider>
     </entry>
-    <entry file="file://$PROJECT_DIR$/src/java/ognl/OgnlParser.java">
+    <entry file="jar:///usr/local/jdk1.5.0_11/src.zip!/java/lang/SecurityManager.java">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="11" column="43" selection-start="500" selection-end="500" vertical-scroll-proportion="0.1423641">
+        <state line="512" column="41" selection-start="20490" selection-end="20490" vertical-scroll-proportion="0.22014052">
           <folding />
         </state>
       </provider>
     </entry>
-    <entry file="file://$PROJECT_DIR$/build.xml">
+    <entry file="file://$PROJECT_DIR$/src/test/java/org/ognl/test/CollectionDirectPropertyTest.java">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="24" column="0" selection-start="792" selection-end="792" vertical-scroll-proportion="0.30664396">
+        <state line="61" column="0" selection-start="3318" selection-end="3318" vertical-scroll-proportion="0.3705281">
           <folding />
         </state>
       </provider>
     </entry>
-    <entry file="file://$PROJECT_DIR$/src/java/ognl/ExpressionNode.java">
+    <entry file="file://$PROJECT_DIR$/src/java/ognl/ListPropertyAccessor.java">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="101" column="28" selection-start="3906" selection-end="3906" vertical-scroll-proportion="0.3501171">
+        <state line="185" column="0" selection-start="7094" selection-end="7094" vertical-scroll-proportion="0.41226575">
+          <folding>
+            <element signature="imports" expanded="true" />
+          </folding>
+        </state>
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/src/java/ognl/ASTProperty.java">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="598" column="54" selection-start="26507" selection-end="26507" vertical-scroll-proportion="0.83390117">
           <folding />
         </state>
       </provider>
     </entry>
-    <entry file="file://$PROJECT_DIR$/src/java/ognl/NumericExpression.java">
+    <entry file="file://$PROJECT_DIR$/src/java/ognl/ASTStaticMethod.java">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="15" column="55" selection-start="238" selection-end="238" vertical-scroll-proportion="0.19320843">
+        <state line="177" column="62" selection-start="6713" selection-end="6713" vertical-scroll-proportion="0.21492206">
           <folding />
         </state>
       </provider>
     </entry>
-    <entry file="file://$PROJECT_DIR$/src/java/ognl/ASTConst.java">
+    <entry file="file://$PROJECT_DIR$/src/java/ognl/ASTMethod.java">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="133" column="8" selection-start="4340" selection-end="4340" vertical-scroll-proportion="0.3559719">
+        <state line="392" column="50" selection-start="15305" selection-end="15305" vertical-scroll-proportion="0.7995546">
           <folding />
         </state>
       </provider>
     </entry>
-    <entry file="file://$PROJECT_DIR$/src/test/java/org/ognl/test/QuotingTest.java">
+    <entry file="file://$PROJECT_DIR$/src/java/ognl/ObjectPropertyAccessor.java">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="43" column="6" selection-start="2153" selection-end="2153" vertical-scroll-proportion="0.24590164">
+        <state line="266" column="100" selection-start="9833" selection-end="9833" vertical-scroll-proportion="0.770017">
           <folding />
         </state>
       </provider>
     </entry>
-    <entry file="file://$PROJECT_DIR$/src/test/java/org/ognl/test/NullStringCatenationTest.java">
+    <entry file="file://$PROJECT_DIR$/src/java/ognl/OgnlRuntime.java">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="45" column="6" selection-start="2361" selection-end="2361" vertical-scroll-proportion="0.26346603">
+        <state line="2017" column="35" selection-start="77132" selection-end="77132" vertical-scroll-proportion="34.666275">
           <folding />
         </state>
       </provider>
     </entry>
-    <entry file="file://$PROJECT_DIR$/src/java/ognl/JavaSource.java">
+    <entry file="file://$PROJECT_DIR$/src/test/java/org/ognl/test/TestOgnlRuntime.java">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="34" column="0" selection-start="1086" selection-end="1086" vertical-scroll-proportion="0.5620609">
+        <state line="24" column="0" selection-start="671" selection-end="671" vertical-scroll-proportion="0.30664396">
+          <folding>
+            <element signature="imports" expanded="true" />
+          </folding>
+        </state>
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/src/test/java/org/ognl/test/IndexAccessTest.java">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="54" column="6" selection-start="3109" selection-end="3109" vertical-scroll-proportion="0.2810903">
           <folding />
         </state>
       </provider>
     </entry>
-    <entry file="file://$PROJECT_DIR$/src/java/ognl/ASTChain.java">
+    <entry file="file://$PROJECT_DIR$/src/test/java/org/ognl/test/IndexedPropertyTest.java">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="43" column="1" selection-start="2083" selection-end="2083" vertical-scroll-proportion="0.17564403">
-          <folding />
-        </state>
-      </provider>
-    </entry>
-    <entry file="file://$PROJECT_DIR$/src/test/java/org/ognl/test/PropertyTest.java">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="45" column="87" selection-start="2136" selection-end="2136" vertical-scroll-proportion="0.15332198">
-          <folding />
-        </state>
-      </provider>
-    </entry>
-    <entry file="file://$PROJECT_DIR$/src/java/ognl/ASTAdd.java">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="227" column="0" selection-start="10070" selection-end="10070" vertical-scroll-proportion="0.44463372">
+        <state line="55" column="0" selection-start="3050" selection-end="3050" vertical-scroll-proportion="0.31942078">
           <folding />
         </state>
       </provider>
     </entry>
     <entry file="file://$PROJECT_DIR$/src/java/ognl/enhance/ExpressionCompiler.java">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="381" column="11" selection-start="14550" selection-end="14550" vertical-scroll-proportion="0.32197616">
+        <state line="82" column="0" selection-start="3419" selection-end="3419" vertical-scroll-proportion="0.3943782">
           <folding />
         </state>
       </provider>

src/java/ognl/ASTChain.java

                         
                         value = OgnlRuntime.getCompiler().castExpression(context, _children[i], value);
                     }
-
 /*
                     System.out.println("astchain value now : " + value + " with index " + i
                     + " current type " + context.getCurrentType() + " current accessor " + context.getCurrentAccessor()

src/java/ognl/ListPropertyAccessor.java

 // --------------------------------------------------------------------------
 package ognl;
 
+import ognl.enhance.UnsupportedCompilationException;
+
+import java.lang.reflect.Method;
 import java.util.*;
 
 /**
     
     public String getSourceAccessor(OgnlContext context, Object target, Object index)
     {
-        context.setCurrentAccessor(List.class);
-        
         String indexStr = index.toString().replaceAll("\"", "");
         
         if (index instanceof String) {
 
             if (indexStr.equals("size")) {
+                context.setCurrentAccessor(List.class);
                 context.setCurrentType(int.class);
                 return ".size()";
             } else {
                 if (indexStr.equals("iterator")) {
+                    context.setCurrentAccessor(List.class);
                     context.setCurrentType(Iterator.class);
                     return ".iterator()";
                 } else {
                     if (indexStr.equals("isEmpty") || indexStr.equals("empty")) {
+                        context.setCurrentAccessor(List.class);
                         context.setCurrentType(boolean.class);
                         return ".isEmpty()";
                     }
             }
         }
         
+        // TODO: This feels really inefficient, must be some better way
+        // check if the index string represents a method on a custom class implementing java.util.List instead..
+        if (context.getCurrentObject() != null && !Number.class.isInstance(context.getCurrentObject())) {
+
+            try {
+                Method m = OgnlRuntime.getReadMethod(target.getClass(), indexStr);
+
+                if (m != null)
+                    return super.getSourceAccessor(context, target, index);
+                
+            } catch (Throwable t) {
+                if (UnsupportedCompilationException.class.isInstance(t))
+                    throw (UnsupportedCompilationException) t;
+                else
+                    throw new RuntimeException(t);
+            }
+        }
+
+        context.setCurrentAccessor(List.class);
+
         // need to convert to primitive for list index access
         // System.out.println("Curent type: " + context.getCurrentType() + " current object type " + context.getCurrentObject().getClass());
         
 
     public String getSourceSetter(OgnlContext context, Object target, Object index)
     {
-        context.setCurrentAccessor(List.class);
         
         String indexStr = index.toString().replaceAll("\"", "");
         
+        // TODO: This feels really inefficient, must be some better way
+        // check if the index string represents a method on a custom class implementing java.util.List instead..
+        if (context.getCurrentObject() != null && !Number.class.isInstance(context.getCurrentObject())) {
+
+            try {
+                Method m = OgnlRuntime.getWriteMethod(target.getClass(), indexStr);
+
+                if (m != null)
+                    return super.getSourceSetter(context, target, index);
+
+            } catch (Throwable t) {
+                if (UnsupportedCompilationException.class.isInstance(t))
+                    throw (UnsupportedCompilationException) t;
+                else
+                    throw new RuntimeException(t);
+            }
+        }
+
         if (index instanceof String) {
+            context.setCurrentAccessor(List.class);
             return "";
         }
 
+        context.setCurrentAccessor(List.class);
+
         // need to convert to primitive for list index access
 
         if (!context.getCurrentType().isPrimitive() && Number.class.isAssignableFrom(context.getCurrentType())) {

src/java/ognl/OgnlRuntime.java

             PropertyDescriptor[] pds = info.getPropertyDescriptors();
 
             for (int i = 0; i < pds.length; i++) {
-                //System.out.println("checking for " + name + " in " + pds[i].getShortDescription());
+                
                 if (pds[i].getName().equalsIgnoreCase(name)
                         || pds[i].getName().toLowerCase().equals(name.toLowerCase())
                         || pds[i].getName().toLowerCase().endsWith(name.toLowerCase()))
 
         return null;
     }
-
+    
     public static Class getSuperOrInterfaceClass(Method m, Class clazz)
     {
         if (clazz.getSuperclass() != null) {
             Class superClass = getSuperOrInterfaceClass(m, clazz.getSuperclass());
-
+            
             if (superClass != null)
                 return superClass;
         }

src/java/ognl/enhance/ExpressionCompiler.java

                 + "\n current Accessor: " + context.getCurrentAccessor()
                 + " previous Accessor: " + context.getPreviousAccessor()
                 + " current object " + context.getCurrentObject());
-        */
+  */      
         
         String castClass = null;
         if (context.getCurrentType() != null && context.getCurrentType().isArray()) {
         } else if (context.getCurrentAccessor().isArray()) {
             
             castClass = ExpressionCompiler.getCastString(context.getCurrentAccessor());
-        } else
-            castClass = OgnlRuntime.getCompiler().getInterfaceClass(context.getCurrentAccessor()).getName();
+        } else {
+            castClass = (context.getCurrentAccessor().getName().indexOf("$") > -1) 
+            ? OgnlRuntime.getCompiler().getInterfaceClass(context.getCurrentAccessor()).getName()
+                : context.getCurrentAccessor().getName();
+        }
 
         ExpressionCompiler.addCastString(context, "((" + castClass + ")");
         

src/test/java/org/ognl/test/CollectionDirectPropertyTest.java

 
 import java.util.Arrays;
 
-public class CollectionDirectPropertyTest extends OgnlTestCase
-{
+public class CollectionDirectPropertyTest extends OgnlTestCase {
 
     private static Root ROOT = new Root();
 
     private static Object[][] TESTS = {
             // Collection direct properties
-            
-            { Arrays.asList(new String[] { "hello", "world" }), "size", new Integer(2) },
-            { Arrays.asList(new String[] { "hello", "world" }), "isEmpty", Boolean.FALSE },
-            { Arrays.asList(new String[] {}), "isEmpty", Boolean.TRUE },
-            { Arrays.asList(new String[] { "hello", "world" }), "iterator.next", "hello" },
-            { Arrays.asList(new String[] { "hello", "world" }), "iterator.hasNext", Boolean.TRUE },
-            { Arrays.asList(new String[] { "hello", "world" }), "#it = iterator, #it.next, #it.next, #it.hasNext",
-                    Boolean.FALSE },
-            { Arrays.asList(new String[] { "hello", "world" }), "#it = iterator, #it.next, #it.next", "world" },
-            { Arrays.asList(new String[] { "hello", "world" }), "size", new Integer(2) },
-            { ROOT, "map[\"test\"]", ROOT },
-            { ROOT, "map.size", new Integer(ROOT.getMap().size()) },
-            { ROOT, "map.keySet", ROOT.getMap().keySet() },
-            { ROOT, "map.values", ROOT.getMap().values() },
-            { ROOT, "map.keys.size", new Integer(ROOT.getMap().keySet().size()) },
-            { ROOT, "map[\"size\"]", ROOT.getMap().get("size") },
-            { ROOT, "map.isEmpty", ROOT.getMap().isEmpty() ? Boolean.TRUE : Boolean.FALSE },
-            { ROOT, "map[\"isEmpty\"]", null },
-            };
+            {Arrays.asList(new String[]{"hello", "world"}), "size", new Integer(2)},
+            {Arrays.asList(new String[]{"hello", "world"}), "isEmpty", Boolean.FALSE},
+            {Arrays.asList(new String[]{}), "isEmpty", Boolean.TRUE},
+            {Arrays.asList(new String[]{"hello", "world"}), "iterator.next", "hello"},
+            {Arrays.asList(new String[]{"hello", "world"}), "iterator.hasNext", Boolean.TRUE},
+            {Arrays.asList(new String[]{"hello", "world"}), "#it = iterator, #it.next, #it.next, #it.hasNext",
+                    Boolean.FALSE},
+            {Arrays.asList(new String[]{"hello", "world"}), "#it = iterator, #it.next, #it.next", "world"},
+            {Arrays.asList(new String[]{"hello", "world"}), "size", new Integer(2)},
+            {ROOT, "map[\"test\"]", ROOT},
+            {ROOT, "map.size", new Integer(ROOT.getMap().size())},
+            {ROOT, "map.keySet", ROOT.getMap().keySet()},
+            {ROOT, "map.values", ROOT.getMap().values()},
+            {ROOT, "map.keys.size", new Integer(ROOT.getMap().keySet().size())},
+            {ROOT, "map[\"size\"]", ROOT.getMap().get("size")},
+            {ROOT, "map.isEmpty", ROOT.getMap().isEmpty() ? Boolean.TRUE : Boolean.FALSE},
+            {ROOT, "map[\"isEmpty\"]", null},
+    };
 
     /*
      * =================================================================== Public static methods
     {
         TestSuite result = new TestSuite();
 
-        for(int i = 0; i < TESTS.length; i++) {
+        for (int i = 0; i < TESTS.length; i++) {
             if (TESTS[i].length == 3) {
                 result.addTest(new CollectionDirectPropertyTest((String) TESTS[i][1], TESTS[i][0],
                         (String) TESTS[i][1], TESTS[i][2]));
     }
 
     public CollectionDirectPropertyTest(String name, Object root, String expressionString, Object expectedResult,
-            Object setValue, Object expectedAfterSetResult)
+                                        Object setValue, Object expectedAfterSetResult)
     {
         super(name, root, expressionString, expectedResult, setValue, expectedAfterSetResult);
     }
 
     public CollectionDirectPropertyTest(String name, Object root, String expressionString, Object expectedResult,
-            Object setValue)
+                                        Object setValue)
     {
         super(name, root, expressionString, expectedResult, setValue);
     }

src/test/java/org/ognl/test/IndexedPropertyTest.java

             {INDEXED, "values[1]", "bar" + "xxx", "xxxx" + "xxx", "xxxx" + "xxx"}, // set through setValues(int, String)
             {INDEXED, "values[1]", "xxxx" + "xxx"}, // getValues(int) again to check if setValues(int, String) was called
             {INDEXED, "setValues(2, \"xxxx\")", null}, // was "baz" -> "xxxx"
-            {INDEXED, "getTitle(list.size)", "Title count 3"}
+            {INDEXED, "getTitle(list.size)", "Title count 3"},
+            {INDEXED, "source.total", 1}
     };
 
     /*

src/test/java/org/ognl/test/TestOgnlRuntime.java

+package org.ognl.test;
+
+import junit.framework.TestCase;
+import ognl.OgnlRuntime;
+import org.ognl.test.objects.ListSource;
+import org.ognl.test.objects.ListSourceImpl;
+
+import java.lang.reflect.Method;
+
+/**
+ * Tests various methods / functionality of {@link ognl.OgnlRuntime}.
+ */
+public class TestOgnlRuntime extends TestCase {
+
+    public void test_Get_Super_Or_Interface_Class() throws Exception
+    {
+        ListSource list = new ListSourceImpl();
+
+        Method m = OgnlRuntime.getReadMethod(list.getClass(), "total");
+        assertNotNull(m);
+        
+        assertEquals(ListSourceImpl.class, OgnlRuntime.getSuperOrInterfaceClass(m, list.getClass()));
+    }
+}

src/test/java/org/ognl/test/accessors/ListPropertyAccessorTest.java

 import ognl.ListPropertyAccessor;
 import ognl.Ognl;
 import ognl.OgnlContext;
+import ognl.enhance.ExpressionCompiler;
+import org.ognl.test.objects.ListSource;
+import org.ognl.test.objects.ListSourceImpl;
 import org.ognl.test.objects.Root;
 
 import java.util.List;
         assertEquals(null, context.getPreviousAccessor());
     }
 
-    
+    public void test_List_To_Object_Property_Accessor_Read() throws Exception
+    {
+        ListPropertyAccessor pa = new ListPropertyAccessor();
+        
+        ListSource list = new ListSourceImpl();
+
+        OgnlContext context = (OgnlContext) Ognl.createDefaultContext(null);
+        context.setRoot(list);
+        context.setCurrentObject(list);
+
+        assertEquals(".getTotal()", pa.getSourceAccessor(context, list, "total"));
+
+        assertNull(context.get(ExpressionCompiler.PRE_CAST));
+        assertEquals(int.class, context.getCurrentType());
+        assertEquals(ListSourceImpl.class, context.getCurrentAccessor());
+   }
 }

src/test/java/org/ognl/test/objects/Indexed.java

 
     private List _list = new ArrayList();
 
+    private ListSource _source = new ListSourceImpl();
+
     public Indexed()
     {
         _list.add(new Integer(1));
         _list.add(new Integer(2));
         _list.add(new Integer(3));
+
+        _source.addValue(new Bean2());
     }
 
     public Indexed(String[] values)
     {
         return "Title count " + count;
     }
+    
+    public ListSource getSource()
+    {
+        return _source;
+    }
 }

src/test/java/org/ognl/test/objects/ListSource.java

+package org.ognl.test.objects;
+
+/**
+ *
+ */
+public interface ListSource {
+
+    public int getTotal();
+
+    public Object addValue(Object value);
+}

src/test/java/org/ognl/test/objects/ListSourceImpl.java

+package org.ognl.test.objects;
+
+import java.util.ArrayList;
+
+/**
+ *
+ */
+public class ListSourceImpl extends ArrayList implements ListSource {
+
+    public ListSourceImpl()
+    {
+    }
+
+    public int getTotal()
+    {
+        return super.size();
+    }
+
+    public Object addValue(Object value)
+    {
+        return super.add(value);
+    }
+}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.