You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2010/03/22 04:30:23 UTC

svn commit: r925946 - in /tapestry/tapestry5/trunk/tapestry-ioc/src: main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java test/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImplTest.java

Author: hlship
Date: Mon Mar 22 03:30:23 2010
New Revision: 925946

URL: http://svn.apache.org/viewvc?rev=925946&view=rev
Log:
TAP5-1064: Extend PropertyAccess to understand Scala style properties (which use a different naming convention than JavaBeans)

Modified:
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImplTest.java

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java?rev=925946&r1=925945&r2=925946&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java Mon Mar 22 03:30:23 2010
@@ -1,10 +1,10 @@
-// Copyright 2006, 2007, 2008 The Apache Software Foundation
+// Copyright 2006, 2007, 2008, 2010 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
+// 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,
@@ -22,11 +22,14 @@ import java.beans.BeanInfo;
 import java.beans.IntrospectionException;
 import java.beans.Introspector;
 import java.beans.PropertyDescriptor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
 import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 
+@SuppressWarnings("unchecked")
 public class PropertyAccessImpl implements PropertyAccess
 {
     private final Map<Class, ClassPropertyAdapter> adapters = CollectionFactory.newConcurrentMap();
@@ -42,7 +45,7 @@ public class PropertyAccessImpl implemen
     }
 
     /**
-     * Clears the cache of adapters and asks the Introspector to clear its cache.
+     * Clears the cache of adapters and asks the {@link Introspector} to clear its cache.
      */
     public synchronized void clearCache()
     {
@@ -81,15 +84,18 @@ public class PropertyAccessImpl implemen
 
         try
         {
-                BeanInfo info = Introspector.getBeanInfo(forClass);
+            BeanInfo info = Introspector.getBeanInfo(forClass);
 
-                List<PropertyDescriptor> descriptors = CollectionFactory.newList();
+            List<PropertyDescriptor> descriptors = CollectionFactory.newList();
 
-                addAll(descriptors, info.getPropertyDescriptors());
+            addAll(descriptors, info.getPropertyDescriptors());
+
+            if (forClass.isInterface())
+                addPropertiesFromExtendedInterfaces(forClass, descriptors);
 
-                if (forClass.isInterface()) addPropertiesFromExtendedInterfaces(forClass, descriptors);
+            addPropertiesFromScala(forClass, descriptors);
 
-                return new ClassPropertyAdapterImpl(forClass, descriptors);
+            return new ClassPropertyAdapterImpl(forClass, descriptors);
         }
         catch (Throwable ex)
         {
@@ -121,4 +127,76 @@ public class PropertyAccessImpl implemen
         }
     }
 
+    private void addPropertiesFromScala(Class forClass, List<PropertyDescriptor> descriptors)
+            throws IntrospectionException
+    {
+        for (Method method : forClass.getMethods())
+        {
+            addPropertyIfScalaGetterMethod(forClass, descriptors, method);
+        }
+    }
+
+    private void addPropertyIfScalaGetterMethod(Class forClass, List<PropertyDescriptor> descriptors, Method method)
+            throws IntrospectionException
+    {
+        if (!isScalaGetterMethod(method))
+            return;
+
+        PropertyDescriptor propertyDescriptor = new PropertyDescriptor(method.getName(), forClass, method.getName(),
+                null);
+
+        // found a getter, looking for the setter now
+        try
+        {
+            Method setterMethod = findScalaSetterMethod(forClass, method);
+
+            propertyDescriptor.setWriteMethod(setterMethod);
+        }
+        catch (NoSuchMethodException e)
+        {
+            // ignore
+        }
+
+        // check if the same property was already discovered with java bean accessors
+
+        addScalaPropertyIfNoJavaBeansProperty(descriptors, propertyDescriptor, method);
+    }
+
+    private void addScalaPropertyIfNoJavaBeansProperty(List<PropertyDescriptor> descriptors,
+            PropertyDescriptor propertyDescriptor, Method getterMethod)
+    {
+        boolean found = false;
+
+        for (PropertyDescriptor currentPropertyDescriptor : descriptors)
+        {
+            if (currentPropertyDescriptor.getName().equals(getterMethod.getName()))
+            {
+                found = true;
+
+                break;
+            }
+        }
+
+        if (!found)
+            descriptors.add(propertyDescriptor);
+    }
+
+    private Method findScalaSetterMethod(Class forClass, Method getterMethod) throws NoSuchMethodException
+    {
+        return forClass.getMethod(getterMethod.getName() + "_$eq", getterMethod.getReturnType());
+    }
+
+    private boolean isScalaGetterMethod(Method method)
+    {
+        try
+        {
+            return Modifier.isPublic(method.getModifiers()) && method.getParameterTypes().length == 0
+                    && !method.getReturnType().equals(Void.TYPE)
+                    && method.getDeclaringClass().getDeclaredField(method.getName()) != null;
+        }
+        catch (NoSuchFieldException ex)
+        {
+            return false;
+        }
+    }
 }

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImplTest.java?rev=925946&r1=925945&r2=925946&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImplTest.java Mon Mar 22 03:30:23 2010
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008 The Apache Software Foundation
+// Copyright 2006, 2007, 2008, 2010 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.
@@ -145,6 +145,44 @@ public class PropertyAccessImplTest exte
 
     }
 
+    public static class ScalaBean {
+        private String value;
+
+        public String getValue()
+        {
+            return value;
+        }
+
+        public void setValue(String value)
+        {
+            this.value = value;
+        }
+
+        public String value()
+        {
+            return value;
+        }
+
+        public void value_$eq(String value)
+        {
+            this.value = value;
+        }
+    }
+
+    public static class ScalaClass {
+        private String value;
+
+        public String value()
+        {
+            return value;
+        }
+
+        public void value_$eq(String value)
+        {
+            this.value = value;
+        }
+    }
+
     public static class BooleanHolder
     {
         private boolean flag;
@@ -523,4 +561,21 @@ public class PropertyAccessImplTest exte
         assertFalse(pa2.isCastRequired());
 
     }
+
+    @Test
+    public void get_scala_properties_with_bean_accessors() {
+        PropertyAdapter pa = access.getAdapter(ScalaBean.class).getPropertyAdapter("value");
+
+        // even thought scala accessors are present the java bean ones should be the ones used by Tapestry
+        assertEquals(pa.getReadMethod().getName(), "getValue");
+        assertEquals(pa.getWriteMethod().getName(), "setValue");
+    }
+
+    @Test
+    public void get_scala_properties() {
+        PropertyAdapter pa = access.getAdapter(ScalaClass.class).getPropertyAdapter("value");
+
+        assertEquals(pa.getReadMethod().getName(), "value");
+        assertEquals(pa.getWriteMethod().getName(), "value_$eq");
+    }
 }