commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From hen...@apache.org
Subject svn commit: r889641 - in /commons/proper/jexl/trunk: src/main/java/org/apache/commons/jexl2/ src/main/java/org/apache/commons/jexl2/introspection/ src/site/ src/test/java/org/apache/commons/jexl2/ xdocs/
Date Fri, 11 Dec 2009 14:38:03 GMT
Author: henrib
Date: Fri Dec 11 14:38:03 2009
New Revision: 889641

URL: http://svn.apache.org/viewvc?rev=889641&view=rev
Log:
Fixed JEXL-93; optional flag at UberspectImpl creation allows to consider public fields as
properties

Added:
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/PublicFieldsTest.java
  (with props)
Modified:
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/JexlEngine.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/JexlMethod.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/JexlPropertyGet.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/JexlPropertySet.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/UberspectImpl.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/package.html
    commons/proper/jexl/trunk/src/site/site.xml
    commons/proper/jexl/trunk/xdocs/index.xml

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java?rev=889641&r1=889640&r2=889641&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java Fri
Dec 11 14:38:03 2009
@@ -785,7 +785,7 @@
             if (xjexl == null) {
                 Object eval = vm.invoke(data, argv); // vm cannot be null if xjexl is null
                 // cache executor in volatile JexlNode.value
-                if (cache) {
+                if (cache && vm.isCacheable()) {
                     node.jjtSetValue(vm);
                 }
                 return eval;
@@ -879,7 +879,7 @@
             if (xjexl == null) {
                 Object eval = vm.invoke(namespace, argv); // vm cannot be null if xjexl is
null
                 // cache executor in volatile JexlNode.value
-                if (cache) {
+                if (cache && vm.isCacheable()) {
                     node.jjtSetValue(vm);
                 }
                 return eval;
@@ -1169,7 +1169,7 @@
             try {
                 Object value = vg.invoke(object);
                 // cache executor in volatile JexlNode.value
-                if (node != null && cache) {
+                if (node != null && cache && vg.isCacheable()) {
                     node.jjtSetValue(vg);
                 }
                 return value;
@@ -1230,7 +1230,7 @@
             try {
                 // cache executor in volatile JexlNode.value
                 vs.invoke(object, value);
-                if (node != null && cache) {
+                if (node != null && cache && vs.isCacheable()) {
                     node.jjtSetValue(vs);
                 }
                 return;

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/JexlEngine.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/JexlEngine.java?rev=889641&r1=889640&r2=889641&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/JexlEngine.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/JexlEngine.java Fri Dec
11 14:38:03 2009
@@ -23,14 +23,14 @@
 import java.io.InputStreamReader;
 import java.io.StringReader;
 import java.io.Reader;
+import java.net.URL;
+import java.net.URLConnection;
 import java.lang.ref.SoftReference;
 import java.lang.reflect.Constructor;
 import java.util.Map;
+import java.util.Set;
 import java.util.Collections;
-import java.net.URL;
-import java.net.URLConnection;
 import java.util.Map.Entry;
-import java.util.Set;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
@@ -117,7 +117,7 @@
      */
     private static final class UberspectHolder {
         /** The default uberspector that handles all introspection patterns. */
-        private static final Uberspect UBERSPECT = new UberspectImpl(LogFactory.getLog(JexlEngine.class));
+        private static final Uberspect UBERSPECT = new UberspectImpl(LogFactory.getLog(JexlEngine.class),
false);
         /** Non-instantiable. */
         private UberspectHolder() {}
     }
@@ -203,7 +203,7 @@
         if (logger == null || logger.equals(LogFactory.getLog(JexlEngine.class))) {
             return UberspectHolder.UBERSPECT;
         }
-        return new UberspectImpl(logger);
+        return new UberspectImpl(logger, false);
     }
 
     /**

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/JexlMethod.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/JexlMethod.java?rev=889641&r1=889640&r2=889641&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/JexlMethod.java
(original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/JexlMethod.java
Fri Dec 11 14:38:03 2009
@@ -43,6 +43,7 @@
     /**
      * Attempts to reuse this JexlMethod, checking that it is compatible with
      * the actual set of arguments.
+     * Related to isCacheable since this method is often used with cached JexlMethod instances.
      * @param obj the object to invoke the method upon
      * @param name the method name
      * @param params the method arguments
@@ -52,14 +53,14 @@
     Object tryInvoke(String name, Object obj, Object[] params);
 
     /**
-     * Checks wether a tryExecute failed or not.
+     * Checks wether a tryInvoke failed or not.
      * @param rval the value returned by tryInvoke
      * @return true if tryInvoke failed, false otherwise
      */
     boolean tryFailed(Object rval);
 
     /**
-     * specifies if this JexlMethod is cacheable and able to be reused for this
+     * Specifies if this JexlMethod is cacheable and able to be reused for this
      * class of object it was returned for.
      * 
      * @return true if can be reused for this class, false if not

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/JexlPropertyGet.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/JexlPropertyGet.java?rev=889641&r1=889640&r2=889641&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/JexlPropertyGet.java
(original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/JexlPropertyGet.java
Fri Dec 11 14:38:03 2009
@@ -48,7 +48,7 @@
     Object tryInvoke(Object obj, Object key);
 
     /**
-     * Checks wether a tryExecute failed or not.
+     * Checks wether a tryInvoke failed or not.
      * @param rval the value returned by tryInvoke
      * @return true if tryInvoke failed, false otherwise
      */
@@ -61,12 +61,4 @@
      * @return true if can be reused for this class, false if not
      */
     boolean isCacheable();
-
-    /**
-     * Tell whether the method underlying this 'property' is alive by
-     * checking to see if represents a successful name resolution.
-     *
-     * @return boolean Whether 'property' is alive.
-     */
-    boolean isAlive();
 }

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/JexlPropertySet.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/JexlPropertySet.java?rev=889641&r1=889640&r2=889641&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/JexlPropertySet.java
(original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/JexlPropertySet.java
Fri Dec 11 14:38:03 2009
@@ -52,7 +52,7 @@
     /**
      * Checks wether a tryInvoke failed or not.
      * @param rval the value returned by tryInvoke
-     * @return true if tryExecute failed, false otherwise
+     * @return true if tryInvoke failed, false otherwise
      */
     boolean tryFailed(Object rval);
     
@@ -63,5 +63,4 @@
      * @return true if can be reused for this class, false if not
      */
     boolean isCacheable();
-
 }

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/UberspectImpl.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/UberspectImpl.java?rev=889641&r1=889640&r2=889641&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/UberspectImpl.java
(original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/UberspectImpl.java
Fri Dec 11 14:38:03 2009
@@ -14,11 +14,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.commons.jexl2.introspection;
 
 import org.apache.commons.jexl2.internal.Introspector;
 import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
 import java.util.Enumeration;
 import java.util.Iterator;
 
@@ -28,6 +28,7 @@
 import org.apache.commons.jexl2.internal.AbstractExecutor;
 import org.apache.commons.jexl2.internal.ArrayIterator;
 import org.apache.commons.jexl2.internal.EnumerationIterator;
+import org.apache.commons.jexl2.internal.introspection.MethodKey;
 import org.apache.commons.logging.Log;
 
 /**
@@ -42,11 +43,22 @@
  */
 public class UberspectImpl extends Introspector implements Uberspect {
     /**
+     * Publicly exposed special failure object returned by tryInvoke.
+     */
+    public static final Object TRY_FAILED = AbstractExecutor.TRY_FAILED;
+    /**
+     * Whether public fields can be considered as properties.
+     */
+    protected final boolean publicProperties;
+    
+    /**
      * Creates a new UberspectImpl.
      * @param runtimeLogger the logger used for all logging needs
+     * @param publicFields whether public fields should be considered as properties
      */
-    public UberspectImpl(Log runtimeLogger) {
+    public UberspectImpl(Log runtimeLogger, boolean publicFields) {
         super(runtimeLogger);
+        publicProperties = publicFields;
     }
 
     /**
@@ -86,9 +98,9 @@
     /**
      * {@inheritDoc}
      */
-   public Constructor<?> getConstructor(Object ctorHandle, Object[] args, JexlInfo
info) {
+    public Constructor<?> getConstructor(Object ctorHandle, Object[] args, JexlInfo
info) {
         return getConstructor(ctorHandle, args);
-   }
+    }
 
     /**
      * {@inheritDoc}
@@ -98,16 +110,163 @@
     }
 
     /**
+     * Gets a field by name from a class.
+     * @param clazz the class to find the field in
+     * @param name the field name
+     * @return the field instance or null if it could not be found
+     */
+    protected static Field getField(Class<?> clazz, String name) {
+        try {
+            Field field = clazz.getField(name);
+            if (!field.isAccessible()) {
+                field.setAccessible(true);
+            }
+            return field;
+        } catch (NoSuchFieldException xnsf) {
+            return null;
+        } catch (SecurityException xsec) {
+            return null;
+        }
+    }
+
+    /**
+     * A JexlPropertyGet for public fields.
+     */
+    public static final class FieldPropertyGet implements JexlPropertyGet {
+        /**
+         * The public field.
+         */
+        private final Field field;
+
+        /**
+         * Creates a new instance of FieldPropertyGet.
+         * @param theField the class public field
+         */
+        public FieldPropertyGet(Field theField) {
+            field = theField;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public Object invoke(Object obj) throws Exception {
+            return field.get(obj);
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public Object tryInvoke(Object obj, Object key) {
+            if (obj.getClass().equals(field.getDeclaringClass()) && key.equals(field.getName()))
{
+                try {
+                    return field.get(obj);
+                } catch (IllegalAccessException xill) {
+                    return TRY_FAILED;
+                }
+            }
+            return TRY_FAILED;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public boolean tryFailed(Object rval) {
+            return rval == TRY_FAILED;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public boolean isCacheable() {
+            return true;
+        }
+    }
+
+    /**
      * {@inheritDoc}
      */
     public JexlPropertyGet getPropertyGet(Object obj, Object identifier, JexlInfo info) {
-        return getGetExecutor(obj, identifier);
+        JexlPropertyGet get = getGetExecutor(obj, identifier);
+        if (get == null && publicProperties && obj != null && identifier
!= null) {
+            Class<?> clazz = obj instanceof Class<?>? (Class<?>) obj :
obj.getClass();
+            Field field = getField(clazz, identifier.toString());
+            if (field != null) {
+                return new FieldPropertyGet(field);
+            }
+        }
+        return get;
+    }
+
+    /**
+     * A JexlPropertySet for public fields.
+     */
+    public static final class FieldPropertySet implements JexlPropertySet {
+        /**
+         * The public field.
+         */
+        private final Field field;
+
+        /**
+         * Creates a new instance of FieldPropertySet.
+         * @param theField the class public field
+         */
+        public FieldPropertySet(Field theField) {
+            field = theField;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public Object invoke(Object obj, Object arg) throws Exception {
+            field.set(obj, arg);
+            return arg;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public Object tryInvoke(Object obj, Object key, Object value) {
+            if (obj.getClass().equals(field.getDeclaringClass())
+                && key.equals(field.getName())
+                && (value == null || MethodKey.isInvocationConvertible(field.getType(),
value.getClass(), false))) {
+                try {
+                    field.set(obj, value);
+                    return value;
+                } catch (IllegalAccessException xill) {
+                    return TRY_FAILED;
+                }
+            }
+            return TRY_FAILED;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public boolean tryFailed(Object rval) {
+            return rval == TRY_FAILED;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public boolean isCacheable() {
+            return true;
+        }
     }
 
     /**
      * {@inheritDoc}
      */
     public JexlPropertySet getPropertySet(final Object obj, final Object identifier, Object
arg, JexlInfo info) {
-        return getSetExecutor(obj, identifier, arg);
+        JexlPropertySet set = getSetExecutor(obj, identifier, arg);
+        if (set == null && publicProperties && obj != null && identifier
!= null) {
+            Class<?> clazz = obj instanceof Class<?>? (Class<?>) obj :
obj.getClass();
+            Field field = getField(clazz, identifier.toString());
+            if (field != null
+                && (arg == null || MethodKey.isInvocationConvertible(field.getType(),
arg.getClass(), false))) {
+                return new FieldPropertySet(field);
+            }
+        }
+        return set;
     }
-}
\ No newline at end of file
+}

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/package.html
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/package.html?rev=889641&r1=889640&r2=889641&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/package.html (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/package.html Fri Dec
11 14:38:03 2009
@@ -268,7 +268,7 @@
         <p>
             {@link org.apache.commons.jexl2.introspection.UberspectImpl}
             is the class to derive if you need to add introspection or reflection capabilities
for some objects.
-            For instance, being able to expose and manipulate public fields instead of Java-beans
conventions.
+            The code already optionally reflects public fields as properties on top of Java-beans
conventions.
         </p>
     </body>
 </html>

Modified: commons/proper/jexl/trunk/src/site/site.xml
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/site/site.xml?rev=889641&r1=889640&r2=889641&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/site/site.xml (original)
+++ commons/proper/jexl/trunk/src/site/site.xml Fri Dec 11 14:38:03 2009
@@ -28,7 +28,7 @@
             <item name="2.0&#xA0;Javadoc"        href="apidocs/index.html"/>
             <item name="1.1&#xA0;Javadoc"        href="apidocs-1.1/index.html"/>
             <item name="Releases and Builds"     href="releases.html"/>
-            <item name="Download"                href="http://commons.apache.org/downloads/download_jexl.cgi"/>
+            <item name="Download"                href="download_jexl.cgi"/>
             <item name="Reference"               href="reference/index.html"/>
             <item name="JEXL Wiki"               href="http://wiki.apache.org/commons/JEXL"/>
         </menu>

Added: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/PublicFieldsTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/PublicFieldsTest.java?rev=889641&view=auto
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/PublicFieldsTest.java
(added)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/PublicFieldsTest.java
Fri Dec 11 14:38:03 2009
@@ -0,0 +1,124 @@
+/*
+ *  Copyright 2009 henri.
+ * 
+ *  Licensed 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.
+ *  under the License.
+ */
+package org.apache.commons.jexl2;
+
+import org.apache.commons.jexl2.introspection.UberspectImpl;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Tests public field set/get.
+ */
+public class PublicFieldsTest extends JexlTestCase {
+    // some constants
+    private static final String LOWER42 = "fourty-two";
+    private static final String UPPER42 = "FOURTY-TWO";
+    /**
+     * An Inner class.
+     */
+    public static class Inner {
+        public double aDouble = 42.0;
+    }
+
+    /**
+     * A Struct, all fields public
+     */
+    public static class Struct {
+        public Inner inner = new Inner();
+        public int anInt = 42;
+        public String aString = LOWER42;
+    }
+
+    // a pub instance
+    private Struct pub;
+    // the JexlContext to use
+    private JexlContext ctxt;
+
+    public PublicFieldsTest() {
+        // create an Uberspect that considers public fields as properties
+        super(new JexlEngine(new UberspectImpl(LogFactory.getLog(PublicFieldsTest.class),
true), null, null, null));
+        JEXL.setLenient(false);
+    }
+
+    @Override
+    public void setUp() {
+        pub = new Struct();
+        ctxt = new MapContext();
+        ctxt.set("pub", pub);
+    }
+
+    public void testGetInt() throws Exception {
+        Expression get = JEXL.createExpression("pub.anInt");
+        assertEquals(42, get.evaluate(ctxt));
+        JEXL.setProperty(pub, "anInt", -42);
+        assertEquals(-42, get.evaluate(ctxt));
+    }
+
+    public void testSetInt() throws Exception {
+        Expression set = JEXL.createExpression("pub.anInt = value");
+        ctxt.set("value", -42);
+        assertEquals(-42, set.evaluate(ctxt));
+        assertEquals(-42, JEXL.getProperty(pub, "anInt"));
+        ctxt.set("value", 42);
+        assertEquals(42, set.evaluate(ctxt));
+        assertEquals(42, JEXL.getProperty(pub, "anInt"));
+        try {
+            ctxt.set("value", UPPER42);
+            assertEquals(null, set.evaluate(ctxt));
+            fail("should have thrown");
+        } catch(JexlException xjexl) {}
+    }
+
+    public void testGetString() throws Exception {
+        Expression get = JEXL.createExpression("pub.aString");
+        assertEquals(LOWER42, get.evaluate(ctxt));
+        JEXL.setProperty(pub, "aString", UPPER42);
+        assertEquals(UPPER42, get.evaluate(ctxt));
+    }
+
+    public void testSetString() throws Exception {
+        Expression set = JEXL.createExpression("pub.aString = value");
+        ctxt.set("value", UPPER42);
+        assertEquals(UPPER42, set.evaluate(ctxt));
+        assertEquals(UPPER42, JEXL.getProperty(pub, "aString"));
+        ctxt.set("value", LOWER42);
+        assertEquals(LOWER42, set.evaluate(ctxt));
+        assertEquals(LOWER42, JEXL.getProperty(pub, "aString"));
+    }
+
+    public void testGetInnerDouble() throws Exception {
+        Expression get = JEXL.createExpression("pub.inner.aDouble");
+        assertEquals(42.0, get.evaluate(ctxt));
+        JEXL.setProperty(pub, "inner.aDouble", -42);
+        assertEquals(-42.0, get.evaluate(ctxt));
+    }
+
+    public void testSetInnerDouble() throws Exception {
+        Expression set = JEXL.createExpression("pub.inner.aDouble = value");
+        ctxt.set("value", -42.0);
+        assertEquals(-42.0, set.evaluate(ctxt));
+        assertEquals(-42.0, JEXL.getProperty(pub, "inner.aDouble"));
+        ctxt.set("value", 42.0);
+        assertEquals(42.0, set.evaluate(ctxt));
+        assertEquals(42.0, JEXL.getProperty(pub, "inner.aDouble"));
+        try {
+            ctxt.set("value", UPPER42);
+            assertEquals(null, set.evaluate(ctxt));
+            fail("should have thrown");
+        } catch(JexlException xjexl) {}
+    }
+
+}

Propchange: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/PublicFieldsTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: commons/proper/jexl/trunk/xdocs/index.xml
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/xdocs/index.xml?rev=889641&r1=889640&r2=889641&view=diff
==============================================================================
--- commons/proper/jexl/trunk/xdocs/index.xml (original)
+++ commons/proper/jexl/trunk/xdocs/index.xml Fri Dec 11 14:38:03 2009
@@ -67,7 +67,8 @@
             </p>
             <p>
             The API and the expression language exploit Java-beans naming patterns through
-            introspection to expose property getters and setters.
+            introspection to expose property getters and setters. It may also optionally
consider public class fields
+            as properties.
             </p>
             <p>
             JEXL attempts to bring some of the lessons learned by the Velocity



Mime
View raw message