You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by mb...@apache.org on 2007/03/13 17:28:15 UTC

svn commit: r517757 - in /myfaces/core/branches/jsf12/api/src: main/java/javax/faces/component/ test/java/javax/faces/component/

Author: mbr
Date: Tue Mar 13 09:28:14 2007
New Revision: 517757

URL: http://svn.apache.org/viewvc?view=rev&rev=517757
Log:
fixed several issues with method binding to method expression adapter
+test

Added:
    myfaces/core/branches/jsf12/api/src/test/java/javax/faces/component/_MethodBindingToMethodExpressionTest.java   (with props)
Modified:
    myfaces/core/branches/jsf12/api/src/main/java/javax/faces/component/_MethodBindingToMethodExpression.java
    myfaces/core/branches/jsf12/api/src/main/java/javax/faces/component/_MethodExpressionToMethodBinding.java

Modified: myfaces/core/branches/jsf12/api/src/main/java/javax/faces/component/_MethodBindingToMethodExpression.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/jsf12/api/src/main/java/javax/faces/component/_MethodBindingToMethodExpression.java?view=diff&rev=517757&r1=517756&r2=517757
==============================================================================
--- myfaces/core/branches/jsf12/api/src/main/java/javax/faces/component/_MethodBindingToMethodExpression.java (original)
+++ myfaces/core/branches/jsf12/api/src/main/java/javax/faces/component/_MethodBindingToMethodExpression.java Tue Mar 13 09:28:14 2007
@@ -18,161 +18,259 @@
 
 import javax.el.ELContext;
 import javax.el.ELException;
-import javax.el.ExpressionFactory;
 import javax.el.MethodExpression;
 import javax.el.MethodInfo;
 import javax.el.MethodNotFoundException;
 import javax.el.PropertyNotFoundException;
-import javax.faces.FacesException;
-import javax.faces.FactoryFinder;
-import javax.faces.application.Application;
-import javax.faces.application.ApplicationFactory;
-import javax.faces.component.StateHolder;
 import javax.faces.context.FacesContext;
+import javax.faces.el.EvaluationException;
 import javax.faces.el.MethodBinding;
 
 /**
  * Converts a MethodBinding to a MethodExpression
- *
+ * 
+ * TODO: find a way to share the implementation of class with impl.
+ * 
  * @author Stan Silvert
  */
-class _MethodBindingToMethodExpression extends MethodExpression implements StateHolder {
-    
-    private static final ExpressionFactory expFactory;
-    
-    static {
-        ApplicationFactory appFactory = 
-                    (ApplicationFactory)FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY);
-        Application application = appFactory.getApplication();
-        expFactory = application.getExpressionFactory();
-    }
-    
+@SuppressWarnings("deprecation")
+class _MethodBindingToMethodExpression extends MethodExpression implements StateHolder
+{
+    private static final Class[] EXPECTED_TYPES = new Class[] { MethodBinding.class, StateHolder.class };
+
     private MethodBinding methodBinding;
-    
-    private MethodExpression methodExpression;
-    private boolean paramTypesKnown = false;
-    
+
+    private boolean _transientFlag;
+
+    private transient MethodInfo methodInfo;
+
     /**
      * No-arg constructor used during restoreState
      */
-    public _MethodBindingToMethodExpression() {
-        
+    protected _MethodBindingToMethodExpression()
+    {
     }
-    
+
     /** Creates a new instance of MethodBindingToMethodExpression */
-    public _MethodBindingToMethodExpression(MethodBinding methodBinding) {
+    public _MethodBindingToMethodExpression(MethodBinding methodBinding)
+    {
+        checkNullArgument(methodBinding, "methodBinding");
         this.methodBinding = methodBinding;
-        
-        if (!(methodBinding instanceof StateHolder)) {
-            throw new IllegalArgumentException("methodBinding must be an instance of StateHolder");
-        }
-        
-        // We can't determine the expectecParamTypes from the MethodBinding
-        // until someone calls invoke.
-        // Therefore, we will just create a new one when invoke is called.
-        methodExpression = makeMethodExpression(methodBinding, new Class[0]);
     }
-    
-    private MethodExpression makeMethodExpression(MethodBinding methodBinding, Class[] expectedParamTypes) {
-        FacesContext facesContext = FacesContext.getCurrentInstance();
-        
-        String expressionString = methodBinding.getExpressionString();
-        if (expressionString == null) expressionString = "null";
-        return expFactory.createMethodExpression(facesContext.getELContext(), 
-                                                 expressionString, 
-                                                 null,
-                                                 expectedParamTypes);
-    }
-    
+
     /**
      * Return the wrapped MethodBinding.
      */
-    public MethodBinding getMethodBinding() {
+    public MethodBinding getMethodBinding()
+    {
         return methodBinding;
     }
+    
+    void setMethodBinding(MethodBinding methodBinding)
+    {
+        this.methodBinding = methodBinding;
+    }
 
     /**
-     * Note: MethodInfo.getParamTypes() may incorrectly return an empty
-     * class array if invoke() has not been called.
-     *
-     * @throws IllegalStateException if expected params types have not been determined.
+     * Note: MethodInfo.getParamTypes() may incorrectly return an empty class array if invoke() has not been called.
+     * 
+     * @throws IllegalStateException
+     *             if expected params types have not been determined.
      */
-    public MethodInfo getMethodInfo(ELContext context) 
-        throws NullPointerException, PropertyNotFoundException, MethodNotFoundException, ELException {
-        
-        if (!paramTypesKnown) throw new IllegalStateException("MethodInfo unavailable until invoke is called.");
-        
-        return methodExpression.getMethodInfo(context);
-    }
-
-    public Object invoke(ELContext context, Object[] params) 
-        throws NullPointerException, PropertyNotFoundException, MethodNotFoundException, ELException {
-        
-        if (!paramTypesKnown) {
-            Class[] paramTypes = findParamTypes(params);
-            methodExpression = makeMethodExpression(methodBinding, paramTypes);
-            paramTypesKnown = true;
+    public MethodInfo getMethodInfo(ELContext context) throws PropertyNotFoundException, MethodNotFoundException,
+            ELException
+    {
+        checkNullArgument(context, "elcontext");
+        checkNullState(methodBinding, "methodBinding");
+
+        if (methodInfo == null)
+        {
+            final FacesContext facesContext = (FacesContext) context.getContext(FacesContext.class);
+            if (facesContext != null)
+            {
+                methodInfo = invoke(new Invoker<MethodInfo>()
+                {
+                    public MethodInfo invoke()
+                    {
+                        return new MethodInfo(null, methodBinding.getType(facesContext), null);
+                    }
+                });
+            }
         }
-        
-        return methodExpression.invoke(context, params);
-    }
-    
-    private Class[] findParamTypes(Object[] params) {
-        Class[] paramTypes = new Class[params.length];
-        for (int i = 0; i < params.length; i++) {
-            paramTypes[i] = params[i].getClass();
-        }
-        
-        return paramTypes;
+        return methodInfo;
     }
 
-    public boolean isLiteralText() {
-        return methodExpression.isLiteralText();
+    public Object invoke(ELContext context, final Object[] params) throws PropertyNotFoundException,
+            MethodNotFoundException, ELException
+    {
+        checkNullArgument(context, "elcontext");
+        checkNullState(methodBinding, "methodBinding");
+        final FacesContext facesContext = (FacesContext) context.getContext(FacesContext.class);
+        if (facesContext != null)
+        {
+            return invoke(new Invoker<Object>()
+            {
+                public Object invoke()
+                {
+                    return methodBinding.invoke(facesContext, params);
+                }
+            });
+        }
+        return null;
     }
 
-    public String getExpressionString() {
-        return methodExpression.getExpressionString();
-    }
-    
-    public boolean equals(Object obj) {
-        return methodExpression.equals(obj);
-    }
-    
-    public int hashCode() {
-     return methodExpression.hashCode();
+    public boolean isLiteralText()
+    {
+        if (methodBinding == null)
+            throw new IllegalStateException("methodBinding is null");
+        String expr = methodBinding.getExpressionString();
+        return !(expr.startsWith("#{") && expr.endsWith("}"));
+    }
+
+    public String getExpressionString()
+    {
+        return methodBinding.getExpressionString();
+    }
+
+    public Object saveState(FacesContext context)
+    {
+        if (!isTransient())
+        {
+            if (methodBinding instanceof StateHolder)
+            {
+                Object[] state = new Object[2];
+                state[0] = methodBinding.getClass().getName();
+                state[1] = ((StateHolder) methodBinding).saveState(context);
+                return state;
+            }
+            else
+            {
+                return methodBinding;
+            }
+        }
+        return null;
     }
 
-    public void restoreState(FacesContext context, Object state) {
-        Object[] stateArray = (Object[])state;
-        try {
-            methodBinding = (MethodBinding)Thread.currentThread()
-                                                 .getContextClassLoader()
-                                                 .loadClass((String)stateArray[0])
-                                                 .newInstance();
-        } catch (Exception e) {
-            throw new FacesException(e);
+    public void restoreState(FacesContext context, Object state)
+    {
+        if (state instanceof MethodBinding)
+        {
+            methodBinding = (MethodBinding) state;
+            methodInfo = null;
+        }
+        else if (state != null)
+        {
+            Object[] values = (Object[]) state;
+            methodBinding = (MethodBinding) newInstance(values[0].toString(), EXPECTED_TYPES);
+            ((StateHolder) methodBinding).restoreState(context, values[1]);
+            methodInfo = null;
         }
-        
-        ((StateHolder)methodBinding).restoreState(context, stateArray[1]);
-        paramTypesKnown = ((Boolean)stateArray[2]).booleanValue();
-        methodExpression = makeMethodExpression(methodBinding, (Class[])stateArray[3]);
     }
 
-    public Object saveState(FacesContext context) {
-        Object[] state = new Object[4];
-        state[0] = methodBinding.getClass().getName();
-        state[1] = ((StateHolder)methodBinding).saveState(context);
-        state[2] = Boolean.valueOf(paramTypesKnown);
-        state[3] = methodExpression.getMethodInfo(context.getELContext()).getParamTypes();
-        return state;
+    public void setTransient(boolean transientFlag)
+    {
+        _transientFlag = transientFlag;
+    }
+
+    public boolean isTransient()
+    {
+        return _transientFlag;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        final int PRIME = 31;
+        int result = 1;
+        result = PRIME * result + ((methodBinding == null) ? 0 : methodBinding.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        final _MethodBindingToMethodExpression other = (_MethodBindingToMethodExpression) obj;
+        if (methodBinding == null)
+        {
+            if (other.methodBinding != null)
+                return false;
+        }
+        else if (!methodBinding.equals(other.methodBinding))
+            return false;
+        return true;
+    }
+
+    @SuppressWarnings("unchecked")
+    protected Object newInstance(String className, Class[] expectedTypes)
+    {
+        try
+        {
+            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+            if (classLoader == null)
+            {
+                classLoader = getClass().getClassLoader();
+            }
+            Class clazz = classLoader.loadClass(className);
+            for (int i = 0, size = expectedTypes.length; i < size; i++)
+            {
+                if (!expectedTypes[i].isAssignableFrom(clazz))
+                {
+                    throw new IllegalStateException("class for name " + className + " does not implement "
+                            + expectedTypes[i].getName());
+                }
+            }
+            return clazz.newInstance();
+        }
+        catch (ClassNotFoundException e)
+        {
+            throw new IllegalStateException(e.getMessage(), e);
+        }
+        catch (InstantiationException e)
+        {
+            throw new IllegalStateException(e.getMessage(), e);
+        }
+        catch (IllegalAccessException e)
+        {
+            throw new IllegalStateException(e.getMessage(), e);
+        }
     }
 
-    public void setTransient(boolean newTransientValue) {
-        ((StateHolder)methodBinding).setTransient(newTransientValue);
+    private void checkNullState(Object notNullInstance, String instanceName)
+    {
+        if (notNullInstance == null)
+            throw new IllegalStateException(instanceName + " is null");
+    }
+
+    private void checkNullArgument(Object notNullInstance, String instanceName)
+    {
+        if (notNullInstance == null)
+            throw new IllegalArgumentException(instanceName + " is null");
+    }
+
+    private <T> T invoke(Invoker<T> invoker)
+    {
+        try
+        {
+            return invoker.invoke();
+        }
+        catch (javax.faces.el.MethodNotFoundException e)
+        {
+            throw new MethodNotFoundException(e.getMessage(), e);
+        }
+        catch (EvaluationException e)
+        {
+            throw new ELException(e.getMessage(), e);
+        }
     }
 
-    public boolean isTransient() {
-        return ((StateHolder)methodBinding).isTransient();
+    private interface Invoker<T>
+    {
+        T invoke();
     }
-    
 }

Modified: myfaces/core/branches/jsf12/api/src/main/java/javax/faces/component/_MethodExpressionToMethodBinding.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/jsf12/api/src/main/java/javax/faces/component/_MethodExpressionToMethodBinding.java?view=diff&rev=517757&r1=517756&r2=517757
==============================================================================
--- myfaces/core/branches/jsf12/api/src/main/java/javax/faces/component/_MethodExpressionToMethodBinding.java (original)
+++ myfaces/core/branches/jsf12/api/src/main/java/javax/faces/component/_MethodExpressionToMethodBinding.java Tue Mar 13 09:28:14 2007
@@ -49,6 +49,12 @@
     public _MethodExpressionToMethodBinding(MethodExpression methodExpression) {
         this.methodExpression = methodExpression;
     }
+    
+    @Override
+    public String getExpressionString()
+    {
+        return methodExpression.getExpressionString();
+    }
 
     public Class getType(FacesContext facesContext) 
         throws MethodNotFoundException {
@@ -57,6 +63,8 @@
             return methodExpression.getMethodInfo(facesContext.getELContext()).getReturnType();
         } catch (javax.el.MethodNotFoundException e) {
             throw new javax.faces.el.MethodNotFoundException(e);
+        } catch (ELException e) {
+            throw new EvaluationException(e);
         }
     }
 
@@ -75,11 +83,14 @@
 // -------- StateHolder methods -------------------------------------------    
     
     public void restoreState(FacesContext context, Object state) {
-        methodExpression = (MethodExpression)state;
+        if(state != null)
+            methodExpression = (MethodExpression)state;
     }
 
     public Object saveState(FacesContext context) {
-        return methodExpression;
+        if(!isTransient)
+            return methodExpression;
+        return null;
     }
 
     public void setTransient(boolean newTransientValue) {

Added: myfaces/core/branches/jsf12/api/src/test/java/javax/faces/component/_MethodBindingToMethodExpressionTest.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/jsf12/api/src/test/java/javax/faces/component/_MethodBindingToMethodExpressionTest.java?view=auto&rev=517757
==============================================================================
--- myfaces/core/branches/jsf12/api/src/test/java/javax/faces/component/_MethodBindingToMethodExpressionTest.java (added)
+++ myfaces/core/branches/jsf12/api/src/test/java/javax/faces/component/_MethodBindingToMethodExpressionTest.java Tue Mar 13 09:28:14 2007
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2007 The Apache Software Foundation.
+ *
+ * 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.
+ */
+package javax.faces.component;
+
+import static org.easymock.EasyMock.*;
+
+import java.util.Date;
+
+import javax.el.ELException;
+import javax.el.ExpressionFactory;
+import javax.el.MethodInfo;
+import javax.el.MethodNotFoundException;
+import javax.faces.application.Application;
+import javax.faces.context.FacesContext;
+import javax.faces.el.MethodBinding;
+
+import junit.framework.TestCase;
+
+import org.apache.myfaces.Assert;
+import org.apache.myfaces.TestRunner;
+import org.apache.shale.test.el.MockELContext;
+import org.apache.shale.test.mock.MockFacesContext12;
+import org.easymock.classextension.EasyMock;
+import org.easymock.classextension.IMocksControl;
+
+/**
+ * @author Mathias Broekelmann (latest modification by $Author$)
+ * @version $Revision$ $Date$
+ */
+@SuppressWarnings("deprecation")
+public class _MethodBindingToMethodExpressionTest extends TestCase
+{
+
+    private IMocksControl _mocksControl;
+    private MethodBinding _methodBinding;
+    private MockELContext _elContext;
+    private MockFacesContext12 _facesContext;
+    private Application _application;
+    private ExpressionFactory _expressionFactory;
+
+    protected void setUp() throws Exception
+    {
+        _mocksControl = EasyMock.createControl();
+        _facesContext = new MockFacesContext12();
+        _application = _mocksControl.createMock(Application.class);
+        _facesContext.setApplication(_application);
+        _expressionFactory = _mocksControl.createMock(ExpressionFactory.class);
+        _elContext = new MockELContext();
+        _elContext.putContext(FacesContext.class, _facesContext);
+        _methodBinding = _mocksControl.createMock(MethodBinding.class);
+    }
+
+    /**
+     * Test method for {@link javax.faces.component._MethodBindingToMethodExpression#_MethodBindingToMethodExpression()}.
+     */
+    public void test_MethodBindingToMethodExpression()
+    {
+        _MethodBindingToMethodExpression testimpl = new _MethodBindingToMethodExpression();
+        assertNull(testimpl.getMethodBinding());
+    }
+
+    /**
+     * Test method for
+     * {@link javax.faces.component._MethodBindingToMethodExpression#_MethodBindingToMethodExpression(javax.faces.el.MethodBinding)}.
+     */
+    public void test_MethodBindingToMethodExpressionMethodBinding()
+    {
+        Assert.assertException(IllegalArgumentException.class, new TestRunner()
+        {
+            public void run() throws Throwable
+            {
+                new _MethodBindingToMethodExpression(null);
+            }
+        });
+        _MethodBindingToMethodExpression testimpl = new _MethodBindingToMethodExpression(_methodBinding);
+        assertEquals(_methodBinding, testimpl.getMethodBinding());
+    }
+
+    /**
+     * Test method for {@link javax.faces.component._MethodBindingToMethodExpression#isLiteralText()}.
+     */
+    public void testIsLiteralText()
+    {
+        assertIsLiteralText(true, "xxx");
+        assertIsLiteralText(false, "#{xxx}");
+    }
+
+    private void assertIsLiteralText(boolean expected, String expressionString)
+    {
+        _MethodBindingToMethodExpression testimpl = new _MethodBindingToMethodExpression(_methodBinding);
+        expect(_methodBinding.getExpressionString()).andReturn(expressionString);
+        _mocksControl.replay();
+        assertEquals(expected, testimpl.isLiteralText());
+        _mocksControl.reset();
+    }
+
+    /**
+     * Test method for {@link javax.faces.component._MethodBindingToMethodExpression#getMethodInfo(javax.el.ELContext)}.
+     */
+    public void testGetMethodInfoELContext()
+    {
+        _MethodBindingToMethodExpression testimpl = new _MethodBindingToMethodExpression(_methodBinding);
+        Class expectedReturnType = Date.class;
+        expect(_methodBinding.getType(same(_facesContext))).andReturn(expectedReturnType);
+        _mocksControl.replay();
+        MethodInfo methodInfo = testimpl.getMethodInfo(_elContext);
+        assertNotNull(methodInfo);
+        // assertNull(methodInfo.getName());
+        assertEquals(expectedReturnType, methodInfo.getReturnType());
+        // assertNull(methodInfo.getParamTypes());
+        _mocksControl.verify();
+        _mocksControl.reset();
+
+        assertGetMethodInfoException(MethodNotFoundException.class, new javax.faces.el.MethodNotFoundException());
+        assertGetMethodInfoException(ELException.class, new javax.faces.el.EvaluationException());
+    }
+
+    private void assertGetMethodInfoException(Class<? extends Throwable> expected, final Throwable firedFromMBGetType)
+    {
+        final _MethodBindingToMethodExpression testimpl = new _MethodBindingToMethodExpression(_methodBinding);
+        expect(_methodBinding.getType(same(_facesContext))).andThrow(firedFromMBGetType);
+        _mocksControl.replay();
+        Assert.assertException(expected, new TestRunner()
+        {
+            public void run() throws Throwable
+            {
+                testimpl.getMethodInfo(_elContext);
+            }
+        });
+        _mocksControl.verify();
+        _mocksControl.reset();
+    }
+
+    /**
+     * Test method for
+     * {@link javax.faces.component._MethodBindingToMethodExpression#invoke(javax.el.ELContext, java.lang.Object[])}.
+     */
+    public void testInvoke()
+    {
+        _MethodBindingToMethodExpression testimpl = new _MethodBindingToMethodExpression(_methodBinding);
+        Object[] testParams = new Object[] { "test" };
+        Object expectedResult = new StringBuffer();
+        expect(_methodBinding.invoke(same(_facesContext), same(testParams))).andReturn(expectedResult);
+        _mocksControl.replay();
+        assertEquals(expectedResult, testimpl.invoke(_elContext, testParams));
+        _mocksControl.verify();
+        _mocksControl.reset();
+
+        assertInvokeException(MethodNotFoundException.class, new javax.faces.el.MethodNotFoundException());
+        assertInvokeException(ELException.class, new javax.faces.el.EvaluationException());
+    }
+
+    private void assertInvokeException(Class<? extends Throwable> expected, final Throwable firedFromMBInvoke)
+    {
+        final _MethodBindingToMethodExpression testimpl = new _MethodBindingToMethodExpression(_methodBinding);
+        expect(_methodBinding.invoke(same(_facesContext), (Object[]) isNull())).andThrow(firedFromMBInvoke);
+        _mocksControl.replay();
+        Assert.assertException(expected, new TestRunner()
+        {
+            public void run() throws Throwable
+            {
+                testimpl.invoke(_elContext, null);
+            }
+        });
+        _mocksControl.verify();
+        _mocksControl.reset();
+    }
+
+    /**
+     * Test method for {@link javax.faces.component._MethodBindingToMethodExpression#getExpressionString()}.
+     */
+    public void testGetExpressionString()
+    {
+        _MethodBindingToMethodExpression testimpl = new _MethodBindingToMethodExpression(_methodBinding);
+        expect(_methodBinding.getExpressionString()).andReturn("xxx");
+        _mocksControl.replay();
+        assertEquals("xxx", testimpl.getExpressionString());
+        _mocksControl.verify();
+    }
+
+    /**
+     * Test method for
+     * {@link javax.faces.component._MethodBindingToMethodExpression#restoreState(javax.faces.context.FacesContext, java.lang.Object)}.
+     * 
+     * @throws Exception
+     */
+    public void testStateHolder() throws Exception
+    {
+        _MethodBindingToMethodExpression testimpl = new _MethodBindingToMethodExpression(_methodBinding);
+        assertFalse(testimpl.isTransient());
+        testimpl.setTransient(true);        
+        assertTrue(testimpl.isTransient());
+        assertNull(testimpl.saveState(_facesContext));
+    }
+}

Propchange: myfaces/core/branches/jsf12/api/src/test/java/javax/faces/component/_MethodBindingToMethodExpressionTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/core/branches/jsf12/api/src/test/java/javax/faces/component/_MethodBindingToMethodExpressionTest.java
------------------------------------------------------------------------------
    svn:keywords = URL Author Revision Date