Fourth pass creating the BeanModel and Commons packages.

Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/c7bf35ce
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/c7bf35ce
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/c7bf35ce

Branch: refs/heads/master
Commit: c7bf35ce7840d1131b657da7ec77eb2d9a494eb6
Parents: 9f9e569
Author: Thiago H. de Paula Figueiredo <thiag...@apache.org>
Authored: Sat Dec 6 19:45:14 2014 -0200
Committer: Thiago H. de Paula Figueiredo <thiag...@apache.org>
Committed: Sat Dec 6 20:32:39 2014 -0200

----------------------------------------------------------------------
 beanmodel/build.gradle                          |   1 +
 .../beaneditor/BeanModelSourceBuilder.java      | 121 +++++
 .../internal/InternalBeanModelUtils.java        | 145 ------
 .../internal/beaneditor/BeanModelImpl.java      |   4 +-
 .../internal/beaneditor/BeanModelUtils.java     |   4 +-
 .../internal/beaneditor/PropertyModelImpl.java  |  10 +-
 .../services/PropertyConduitSourceImpl.java     |  10 +-
 .../services/ClassPropertyAdapterImpl.java      | 249 +++++++++
 .../services/PlasticClassListenerLogger.java    |  47 ++
 .../services/PlasticProxyFactoryImpl.java       | 285 +++++++++++
 .../internal/services/PropertyAccessImpl.java   | 217 ++++++++
 .../internal/services/PropertyAdapterImpl.java  | 273 ++++++++++
 commons/build.gradle                            |   1 +
 .../internal/services/StringInternerImpl.java   |  54 ++
 .../org/apache/tapestry5/ioc/Configuration.java |  53 ++
 .../tapestry5/ioc/MappedConfiguration.java      |  81 +++
 .../tapestry5/ioc/OrderedConfiguration.java     |  84 +++
 .../ioc/internal/BasicTypeCoercions.java        | 342 +++++++++++++
 .../AccessableObjectAnnotationProvider.java     |  46 ++
 .../services/AnnotationProviderChain.java       |  59 +++
 .../ioc/internal/services/CompoundCoercion.java |  54 ++
 .../ioc/internal/services/ServiceMessages.java  |  68 +++
 .../ioc/internal/services/StringLocation.java   |  65 +++
 .../ioc/internal/services/TypeCoercerImpl.java  | 508 +++++++++++++++++++
 .../ioc/internal/util/InheritanceSearch.java    | 159 ++++++
 .../ioc/internal/util/InternalCommonsUtils.java | 388 ++++++++++++++
 .../ioc/internal/util/InternalStringUtils.java  | 203 --------
 .../ioc/internal/util/LockSupport.java          |  89 ++++
 .../ioc/internal/util/MessageFormatterImpl.java |  65 +++
 .../ioc/internal/util/MessagesImpl.java         |  74 +++
 .../ioc/internal/util/TapestryException.java    |  23 +-
 .../tapestry5/ioc/util/AbstractMessages.java    |  94 ++++
 .../tapestry5/ioc/util/AvailableValues.java     |   4 +-
 .../apache/tapestry5/ioc/util/TimeInterval.java | 195 +++++++
 .../tapestry5/util/StringToEnumCoercion.java    |  91 ++++
 .../internal/TapestryInternalUtils.java         |   8 +-
 .../internal/services/StringInternerImpl.java   |  53 --
 .../org/apache/tapestry5/ioc/Configuration.java |  53 --
 .../tapestry5/ioc/MappedConfiguration.java      |  81 ---
 .../tapestry5/ioc/OrderedConfiguration.java     |  84 ---
 .../AccessableObjectAnnotationProvider.java     |  46 --
 .../services/AnnotationProviderChain.java       |  59 ---
 .../services/ClassPropertyAdapterImpl.java      | 250 ---------
 .../ioc/internal/services/CompoundCoercion.java |  54 --
 .../services/PlasticClassListenerLogger.java    |  47 --
 .../services/PlasticProxyFactoryImpl.java       | 286 -----------
 .../internal/services/PropertyAccessImpl.java   | 217 --------
 .../internal/services/PropertyAdapterImpl.java  | 273 ----------
 .../ioc/internal/services/ServiceMessages.java  |  68 ---
 .../ioc/internal/services/StringLocation.java   |  65 ---
 .../ioc/internal/services/TypeCoercerImpl.java  | 508 -------------------
 .../ioc/internal/util/InheritanceSearch.java    | 159 ------
 .../ioc/internal/util/InternalUtils.java        | 138 +++--
 .../ioc/internal/util/LockSupport.java          |  89 ----
 .../ioc/internal/util/MessageFormatterImpl.java |  65 ---
 .../ioc/internal/util/MessagesImpl.java         |  74 ---
 .../ioc/modules/TapestryIOCModule.java          | 297 +----------
 .../tapestry5/ioc/util/AbstractMessages.java    |  94 ----
 .../apache/tapestry5/ioc/util/TimeInterval.java | 195 -------
 .../tapestry5/util/StringToEnumCoercion.java    |  91 ----
 60 files changed, 3855 insertions(+), 3665 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/beanmodel/build.gradle
----------------------------------------------------------------------
diff --git a/beanmodel/build.gradle b/beanmodel/build.gradle
index c09ebdd..fba43b7 100644
--- a/beanmodel/build.gradle
+++ b/beanmodel/build.gradle
@@ -26,6 +26,7 @@ dependencies {
        compile project(":plastic")
        compile project(":tapestry5-annotations")
        compile project(":commons")
+       compile "org.slf4j:slf4j-api:${versions.slf4j}"
        
        // Antlr3 tool path used with the antlr3 task
        antlr3 "org.antlr:antlr:3.5.2"

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModelSourceBuilder.java
----------------------------------------------------------------------
diff --git 
a/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModelSourceBuilder.java
 
b/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModelSourceBuilder.java
new file mode 100644
index 0000000..8cef66e
--- /dev/null
+++ 
b/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModelSourceBuilder.java
@@ -0,0 +1,121 @@
+// Copyright 2014 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 org.apache.tapestry5.beaneditor;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import javax.naming.OperationNotSupportedException;
+
+import org.apache.tapestry5.internal.services.BeanModelSourceImpl;
+import org.apache.tapestry5.internal.services.PropertyConduitSourceImpl;
+import org.apache.tapestry5.internal.services.StringInterner;
+import org.apache.tapestry5.internal.services.StringInternerImpl;
+import org.apache.tapestry5.ioc.Configuration;
+import org.apache.tapestry5.ioc.ObjectLocator;
+import org.apache.tapestry5.ioc.internal.BasicTypeCoercions;
+import org.apache.tapestry5.ioc.internal.services.PlasticProxyFactoryImpl;
+import org.apache.tapestry5.ioc.internal.services.PropertyAccessImpl;
+import org.apache.tapestry5.ioc.internal.services.TypeCoercerImpl;
+import org.apache.tapestry5.ioc.services.CoercionTuple;
+import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
+import org.apache.tapestry5.ioc.services.PropertyAccess;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
+import org.apache.tapestry5.services.BeanModelSource;
+import org.apache.tapestry5.services.DataTypeAnalyzer;
+import org.apache.tapestry5.services.PropertyConduitSource;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility class for creating {@link BeanModelSource} instances without
+ * Tapestry-IoC. Usage of Tapestry-IoC is still recommended.
+ */
+public class BeanModelSourceBuilder {
+       
+       private TypeCoercer typeCoercer;
+       private PropertyAccess propertyAccess;
+       private PropertyConduitSource propertyConduitSource;
+       private PlasticProxyFactory plasticProxyFactory;
+       private DataTypeAnalyzer dataTypeAnalyzer;
+       private ObjectLocator objectLocator;
+       private StringInterner stringInterner;
+
+       /**
+        * Sets the {@link TypeCoercer} to be used.
+        */
+       public BeanModelSourceBuilder setTypeCoercer(TypeCoercer typeCoercer) {
+               this.typeCoercer = typeCoercer;
+//             propertyAccess = new PropertyAcc
+               return this;
+       }
+
+       public BeanModelSource build() 
+       {
+               
+               if (typeCoercer == null) 
+               {
+                       createTypeCoercer();
+               }
+               
+               if (propertyAccess == null)
+               {
+                       propertyAccess = new PropertyAccessImpl();
+               }
+               
+               if (stringInterner == null)
+               {
+                       stringInterner = new StringInternerImpl();
+               }
+               
+               if (plasticProxyFactory == null)
+               {
+                       plasticProxyFactory = new 
PlasticProxyFactoryImpl(getClass().getClassLoader(), 
LoggerFactory.getLogger(PlasticProxyFactory.class));
+               }
+               
+               if (propertyConduitSource == null)
+               {
+                       propertyConduitSource = new 
PropertyConduitSourceImpl(propertyAccess, plasticProxyFactory, typeCoercer, 
stringInterner);
+               }
+               
+               return new BeanModelSourceImpl(typeCoercer, propertyAccess, 
propertyConduitSource, plasticProxyFactory, dataTypeAnalyzer, objectLocator);
+               
+       }
+
+       private void createTypeCoercer() {
+               CoercionTupleConfiguration configuration = new 
CoercionTupleConfiguration();
+               BasicTypeCoercions.provideBasicTypeCoercions(configuration);
+               typeCoercer = new TypeCoercerImpl(configuration.getTuples());
+       }
+       
+       final private static class CoercionTupleConfiguration implements 
Configuration<CoercionTuple> {
+               
+               final private Collection<CoercionTuple> tuples = new 
ArrayList<CoercionTuple>();
+
+               @Override
+               public void add(CoercionTuple tuble) {
+                       tuples.add(tuble);
+               }
+
+               @Override
+               public void addInstance(Class<? extends CoercionTuple> clazz) {
+                       throw new RuntimeException("Not implemented");
+               }
+               
+               public Collection<CoercionTuple> getTuples() {
+                       return tuples;
+               }
+               
+       }
+       
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalBeanModelUtils.java
----------------------------------------------------------------------
diff --git 
a/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalBeanModelUtils.java
 
b/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalBeanModelUtils.java
deleted file mode 100644
index 88f4c7f..0000000
--- 
a/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalBeanModelUtils.java
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright 2007, 2008 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 org.apache.tapestry5.internal;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-import java.util.regex.Pattern;
-
-import org.apache.tapestry5.ioc.AnnotationProvider;
-import org.apache.tapestry5.ioc.Messages;
-import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
-import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
-
-/**
- * Some methods broken off tapestry-core's InternalUtils to avoid bringing the 
whole class
- * plus its multiple dependencies to the BeanModel package.
- */
-public class InternalBeanModelUtils {
-       
-       public static final Pattern NON_WORD_PATTERN = 
Pattern.compile("[^\\w]");
-       
-       /**
-        * @since 5.3
-        */
-       private final static AnnotationProvider NULL_ANNOTATION_PROVIDER = new 
NullAnnotationProvider();
-
-       
-    /**
-     * Used to convert a property expression into a key that can be used to 
locate various resources (Blocks, messages,
-     * etc.). Strips out any punctuation characters, leaving just words 
characters (letters, number and the
-     * underscore).
-     *
-     * @param expression a property expression
-     * @return the expression with punctuation removed
-     */
-    public static String extractIdFromPropertyExpression(String expression)
-    {
-        return replace(expression, NON_WORD_PATTERN, "");
-    }
-
-    public static String replace(String input, Pattern pattern, String 
replacement)
-    {
-        return pattern.matcher(input).replaceAll(replacement);
-    }
-    
-    /**
-     * Looks for a label within the messages based on the id. If found, it is 
used, otherwise the name is converted to a
-     * user presentable form.
-     */
-    public static String defaultLabel(String id, Messages messages, String 
propertyExpression)
-    {
-        String key = id + "-label";
-
-        if (messages.contains(key))
-            return messages.get(key);
-
-        return 
toUserPresentable(extractIdFromPropertyExpression(InternalStringUtils.lastTerm(propertyExpression)));
-    }
-    
-    /**
-     * Capitalizes the string, and inserts a space before each upper case 
character (or sequence of upper case
-     * characters). Thus "userId" becomes "User Id", etc. Also, converts 
underscore into space (and capitalizes the
-     * following word), thus "user_id" also becomes "User Id".
-     */
-    public static String toUserPresentable(String id)
-    {
-        StringBuilder builder = new StringBuilder(id.length() * 2);
-
-        char[] chars = id.toCharArray();
-        boolean postSpace = true;
-        boolean upcaseNext = true;
-
-        for (char ch : chars)
-        {
-            if (upcaseNext)
-            {
-                builder.append(Character.toUpperCase(ch));
-                upcaseNext = false;
-
-                continue;
-            }
-
-            if (ch == '_')
-            {
-                builder.append(' ');
-                upcaseNext = true;
-                continue;
-            }
-
-            boolean upperCase = Character.isUpperCase(ch);
-
-            if (upperCase && !postSpace)
-                builder.append(' ');
-
-            builder.append(ch);
-
-            postSpace = upperCase;
-        }
-
-        return builder.toString();
-    }
-    
-    /**
-     * @since 5.3
-     */
-    public static AnnotationProvider toAnnotationProvider(final Class element)
-    {
-        return new AnnotationProvider()
-        {
-            @Override
-            public <T extends Annotation> T getAnnotation(Class<T> 
annotationClass)
-            {
-                return 
annotationClass.cast(element.getAnnotation(annotationClass));
-            }
-        };
-    }
-    
-    public static AnnotationProvider toAnnotationProvider(final Method element)
-    {
-        if (element == null)
-            return NULL_ANNOTATION_PROVIDER;
-
-        return new AnnotationProvider()
-        {
-            @Override
-            public <T extends Annotation> T getAnnotation(Class<T> 
annotationClass)
-            {
-                return element.getAnnotation(annotationClass);
-            }
-        };
-    }
-
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
----------------------------------------------------------------------
diff --git 
a/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
 
b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
index b72a3d6..3b71f0e 100644
--- 
a/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
+++ 
b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
@@ -22,7 +22,7 @@ import 
org.apache.tapestry5.internal.services.CoercingPropertyConduitWrapper;
 import org.apache.tapestry5.ioc.Messages;
 import org.apache.tapestry5.ioc.ObjectLocator;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
 import org.apache.tapestry5.ioc.services.TypeCoercer;
 import org.apache.tapestry5.ioc.util.AvailableValues;
 import org.apache.tapestry5.ioc.util.UnknownValueException;
@@ -93,7 +93,7 @@ public class BeanModelImpl<T> implements BeanModel<T>
 
     private void validateNewPropertyName(String propertyName)
     {
-        assert InternalStringUtils.isNonBlank(propertyName);
+        assert InternalCommonsUtils.isNonBlank(propertyName);
         if (properties.containsKey(propertyName))
             throw new RuntimeException(String.format(
                     "Bean editor model for %s already contains a property 
model for property '%s'.",

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
----------------------------------------------------------------------
diff --git 
a/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
 
b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
index 154ee79..207fb97 100644
--- 
a/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
+++ 
b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
@@ -15,7 +15,7 @@
 package org.apache.tapestry5.internal.beaneditor;
 
 import org.apache.tapestry5.beaneditor.BeanModel;
-import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
 
 /**
  * Utilities used in a few places to modify an existing {@link BeanModel}.
@@ -54,7 +54,7 @@ public final class BeanModelUtils
 
     private static final String join(String firstList, String 
optionalSecondList)
     {
-        if (InternalStringUtils.isBlank(optionalSecondList))
+        if (InternalCommonsUtils.isBlank(optionalSecondList))
             return firstList;
 
         return firstList + "," + optionalSecondList;

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
----------------------------------------------------------------------
diff --git 
a/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
 
b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
index 4632818..24d0b2d 100644
--- 
a/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
+++ 
b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
@@ -20,9 +20,9 @@ import org.apache.tapestry5.PropertyConduit;
 import org.apache.tapestry5.beaneditor.BeanModel;
 import org.apache.tapestry5.beaneditor.PropertyModel;
 import org.apache.tapestry5.beaneditor.Sortable;
-import org.apache.tapestry5.internal.InternalBeanModelUtils;
 import org.apache.tapestry5.ioc.Messages;
-import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
 import org.apache.tapestry5.plastic.PlasticUtils;
 
 @SuppressWarnings("all")
@@ -48,9 +48,9 @@ public class PropertyModelImpl implements PropertyModel
         this.name = name;
         this.conduit = conduit;
 
-        id = InternalBeanModelUtils.extractIdFromPropertyExpression(name);
+        id = InternalCommonsUtils.extractIdFromPropertyExpression(name);
 
-        label = InternalBeanModelUtils.defaultLabel(id, messages, name);
+        label = InternalCommonsUtils.defaultLabel(id, messages, name);
 
         // TAP5-2305
         if (conduit != null)
@@ -87,7 +87,7 @@ public class PropertyModelImpl implements PropertyModel
 
     public PropertyModel label(String label)
     {
-        assert InternalStringUtils.isNonBlank(label);
+        assert InternalCommonsUtils.isNonBlank(label);
         this.label = label;
 
         return this;

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
----------------------------------------------------------------------
diff --git 
a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
 
b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
index 4ce072e..09d234c 100644
--- 
a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
+++ 
b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
@@ -19,7 +19,6 @@ import org.antlr.runtime.CommonTokenStream;
 import org.antlr.runtime.tree.Tree;
 import org.apache.tapestry5.PropertyConduit;
 import org.apache.tapestry5.PropertyConduit2;
-import org.apache.tapestry5.internal.InternalBeanModelUtils;
 import org.apache.tapestry5.internal.InternalPropertyConduit;
 import org.apache.tapestry5.internal.antlr.PropertyExpressionLexer;
 import org.apache.tapestry5.internal.antlr.PropertyExpressionParser;
@@ -30,7 +29,8 @@ import org.apache.tapestry5.ioc.annotations.PostInjection;
 import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.internal.util.GenericsUtils;
-import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
 import org.apache.tapestry5.ioc.services.*;
 import org.apache.tapestry5.ioc.util.AvailableValues;
 import org.apache.tapestry5.ioc.util.ExceptionUtils;
@@ -1107,7 +1107,7 @@ public class PropertyConduitSourceImpl implements 
PropertyConduitSource
 
             String message = String.format("Node %s was type %s, but was 
expected to be (one of) %s.",
                     node.toStringTree(), 
PropertyExpressionParser.tokenNames[node.getType()],
-                    InternalStringUtils.joinSorted(tokenNames));
+                    InternalCommonsUtils.joinSorted(tokenNames));
 
             return new RuntimeException(message);
         }
@@ -1260,7 +1260,7 @@ public class PropertyConduitSourceImpl implements 
PropertyConduitSource
 
             Type returnType = GenericsUtils.extractActualType(activeType, 
method);
 
-            return new Term(returnType, toUniqueId(method), 
InternalBeanModelUtils.toAnnotationProvider(method), new 
InstructionBuilderCallback()
+            return new Term(returnType, toUniqueId(method), 
InternalCommonsUtils.toAnnotationProvider(method), new 
InstructionBuilderCallback()
             {
                 public void doBuild(InstructionBuilder builder)
                 {
@@ -1364,7 +1364,7 @@ public class PropertyConduitSourceImpl implements 
PropertyConduitSource
     public PropertyConduit create(Class rootClass, String expression)
     {
         assert rootClass != null;
-        assert InternalStringUtils.isNonBlank(expression);
+        assert InternalCommonsUtils.isNonBlank(expression);
 
         MultiKey key = new MultiKey(rootClass, expression);
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
----------------------------------------------------------------------
diff --git 
a/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
 
b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
new file mode 100644
index 0000000..5d6dfec
--- /dev/null
+++ 
b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
@@ -0,0 +1,249 @@
+// Copyright 2006, 2007, 2008, 2010, 2011, 2012 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 org.apache.tapestry5.ioc.internal.services;
+
+import static 
org.apache.tapestry5.ioc.internal.util.CollectionFactory.newCaseInsensitiveMap;
+
+import java.beans.PropertyDescriptor;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.GenericsUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
+import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
+import org.apache.tapestry5.ioc.services.PropertyAdapter;
+
+public class ClassPropertyAdapterImpl implements ClassPropertyAdapter
+{
+    private final Map<String, PropertyAdapter> adapters = 
newCaseInsensitiveMap();
+
+    private final Class beanType;
+
+    public ClassPropertyAdapterImpl(Class beanType, List<PropertyDescriptor> 
descriptors)
+    {
+        this.beanType = beanType;
+
+        // lazy init
+        Map<String, List<Method>> nonBridgeMethods = null;
+        
+        for (PropertyDescriptor pd : descriptors)
+        {
+            // Indexed properties will have a null propertyType (and a non-null
+            // indexedPropertyType). We ignore indexed properties.
+
+            final Class<?> thisPropertyType = pd.getPropertyType();
+            if (thisPropertyType == null)
+                continue;
+
+            Method readMethod = pd.getReadMethod();
+            Method writeMethod = pd.getWriteMethod();
+            
+            // TAP5-1493
+            if (readMethod != null && readMethod.isBridge())
+            {
+               if (nonBridgeMethods == null)
+               {
+                       nonBridgeMethods = 
groupNonBridgeMethodsByName(beanType);
+               }
+               readMethod = findMethodWithSameNameAndParamCount(readMethod, 
nonBridgeMethods); 
+            }
+            
+            // TAP5-1548, TAP5-1885: trying to find a getter which 
Introspector missed
+            if (readMethod == null) {
+                final String prefix = thisPropertyType != boolean.class ? 
"get" : "is";
+                try
+                {
+                    Method method = beanType.getMethod(prefix + 
capitalize(pd.getName()));
+                    final Class<?> returnType = method.getReturnType();
+                    if (returnType.equals(thisPropertyType) || 
returnType.isInstance(thisPropertyType)) {
+                        readMethod = method;
+                    }
+                }
+                catch (SecurityException e) {
+                    // getter not usable.
+                }
+                catch (NoSuchMethodException e)
+                {
+                    // getter doesn't exist.
+                }
+            }
+            
+            if (writeMethod != null && writeMethod.isBridge())
+            {
+               if (nonBridgeMethods == null)
+               {
+                       nonBridgeMethods = 
groupNonBridgeMethodsByName(beanType);
+               }
+               writeMethod = findMethodWithSameNameAndParamCount(writeMethod, 
nonBridgeMethods);
+            }
+            
+            // TAP5-1548, TAP5-1885: trying to find a setter which 
Introspector missed
+            if (writeMethod == null) {
+                try
+                {
+                    Method method = beanType.getMethod("set" + 
capitalize(pd.getName()), pd.getPropertyType());
+                    final Class<?> returnType = method.getReturnType();
+                    if (returnType.equals(void.class)) {
+                        writeMethod = method;
+                    }
+                }
+                catch (SecurityException e) {
+                    // setter not usable.
+                }
+                catch (NoSuchMethodException e)
+                {
+                    // setter doesn't exist.
+                }
+            }
+
+            Class propertyType = readMethod == null ? thisPropertyType : 
GenericsUtils.extractGenericReturnType(
+                    beanType, readMethod);
+
+            PropertyAdapter pa = new PropertyAdapterImpl(this, pd.getName(), 
propertyType, readMethod, writeMethod);
+
+            adapters.put(pa.getName(), pa);
+        }
+
+        // Now, add any public fields (even if static) that do not conflict
+
+        for (Field f : beanType.getFields())
+        {
+            String name = f.getName();
+
+            if (!adapters.containsKey(name))
+            {
+                Class propertyType = 
GenericsUtils.extractGenericFieldType(beanType, f);
+                PropertyAdapter pa = new PropertyAdapterImpl(this, name, 
propertyType, f);
+
+                adapters.put(name, pa);
+            }
+        }
+    }
+
+    private static String capitalize(String name)
+    {
+        return Character.toUpperCase(name.charAt(0)) + name.substring(1);
+    }
+
+    /**
+     * Find a replacement for the method (if one exists)
+     * @param method A method
+     * @param groupedMethods Methods mapped by name
+     * @return A method from groupedMethods with the same name / param count 
+     *         (default to providedmethod if none found)
+     */
+    private Method findMethodWithSameNameAndParamCount(Method method, 
Map<String, List<Method>> groupedMethods) {
+       List<Method> methodGroup = groupedMethods.get(method.getName());
+       if (methodGroup != null)
+       {
+               for (Method nonBridgeMethod : methodGroup)
+               {
+                       if (nonBridgeMethod.getParameterTypes().length == 
method.getParameterTypes().length)
+                       {
+                               // return the non-bridge method with the same 
name / argument count
+                               return nonBridgeMethod;
+                       }
+               }
+       }
+       
+       // default to the provided method
+       return method;
+       }
+
+       /**
+     * Find all of the public methods that are not bridge methods and
+     * group them by method name
+     * 
+     * {@see Method#isBridge()}
+     * @param type Bean type
+     * @return
+     */
+    private Map<String, List<Method>> groupNonBridgeMethodsByName(Class type)
+    {
+       Map<String, List<Method>> methodGroupsByName = 
CollectionFactory.newMap();
+       for (Method method : type.getMethods())
+       {
+               if (!method.isBridge())
+               {
+                       List<Method> methodGroup = 
methodGroupsByName.get(method.getName());
+                       if (methodGroup == null)
+                       {
+                               methodGroup = CollectionFactory.newList();
+                               methodGroupsByName.put(method.getName(), 
methodGroup);
+                       }
+                       methodGroup.add(method);
+               }
+       }
+       return methodGroupsByName;
+       }
+
+       @Override
+    public Class getBeanType()
+    {
+        return beanType;
+    }
+
+    @Override
+    public String toString()
+    {
+        String names = InternalCommonsUtils.joinSorted(adapters.keySet());
+
+        return String.format("<ClassPropertyAdaptor %s: %s>", 
beanType.getName(), names);
+    }
+
+    @Override
+    public List<String> getPropertyNames()
+    {
+        return InternalCommonsUtils.sortedKeys(adapters);
+    }
+
+    @Override
+    public PropertyAdapter getPropertyAdapter(String name)
+    {
+        return adapters.get(name);
+    }
+
+    @Override
+    public Object get(Object instance, String propertyName)
+    {
+        return adaptorFor(propertyName).get(instance);
+    }
+
+    @Override
+    public void set(Object instance, String propertyName, Object value)
+    {
+        adaptorFor(propertyName).set(instance, value);
+    }
+
+    @Override
+    public Annotation getAnnotation(Object instance, String propertyName, 
Class<? extends Annotation> annotationClass) {
+    return adaptorFor(propertyName).getAnnotation(annotationClass);
+    }
+
+    private PropertyAdapter adaptorFor(String name)
+    {
+        PropertyAdapter pa = adapters.get(name);
+
+        if (pa == null)
+            throw new 
IllegalArgumentException(ServiceMessages.noSuchProperty(beanType, name));
+
+        return pa;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java
----------------------------------------------------------------------
diff --git 
a/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java
 
b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java
new file mode 100644
index 0000000..8ebdede
--- /dev/null
+++ 
b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java
@@ -0,0 +1,47 @@
+// Copyright 2011 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 org.apache.tapestry5.ioc.internal.services;
+
+import org.apache.tapestry5.plastic.ClassType;
+import org.apache.tapestry5.plastic.PlasticClassEvent;
+import org.apache.tapestry5.plastic.PlasticClassListener;
+import org.slf4j.Logger;
+import org.slf4j.Marker;
+import org.slf4j.MarkerFactory;
+
+public class PlasticClassListenerLogger implements PlasticClassListener
+{
+    private final Logger logger;
+
+    public PlasticClassListenerLogger(Logger logger)
+    {
+        this.logger = logger;
+    }
+
+    @Override
+    public void classWillLoad(PlasticClassEvent event)
+    {
+        if (logger.isDebugEnabled())
+        {
+            Marker marker = 
MarkerFactory.getMarker(event.getPrimaryClassName());
+
+            String extendedClassName = event.getType() == ClassType.PRIMARY ? 
event.getPrimaryClassName() : String
+                    .format("%s (%s for %s)", event.getClassName(), 
event.getType(), event.getPrimaryClassName());
+
+            logger.debug(marker,
+                    String.format("Loading class %s:\n%s", extendedClassName, 
event.getDissasembledBytecode()));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
----------------------------------------------------------------------
diff --git 
a/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
 
b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
new file mode 100644
index 0000000..a23ecec
--- /dev/null
+++ 
b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
@@ -0,0 +1,285 @@
+// Copyright 2011, 2012 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 org.apache.tapestry5.ioc.internal.services;
+
+import org.apache.tapestry5.internal.plastic.PlasticInternalUtils;
+import org.apache.tapestry5.internal.plastic.asm.Type;
+import org.apache.tapestry5.internal.plastic.asm.tree.*;
+import org.apache.tapestry5.ioc.Location;
+import org.apache.tapestry5.ioc.ObjectCreator;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
+import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
+import org.apache.tapestry5.plastic.*;
+import org.slf4j.Logger;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Map;
+
+public class PlasticProxyFactoryImpl implements PlasticProxyFactory
+{
+    public static final String INTERNAL_GET_DELEGATE = 
"_____internalGetDelegate_DONT_CALL_THIS_METHOD_____";
+
+    private final PlasticManager manager;
+
+    private final Map<String, Location> memberToLocation = 
CollectionFactory.newConcurrentMap();
+
+    public PlasticProxyFactoryImpl(ClassLoader parentClassLoader, Logger 
logger)
+    {
+        this(PlasticManager.withClassLoader(parentClassLoader).create(), 
logger);
+    }
+
+    public PlasticProxyFactoryImpl(PlasticManager manager, Logger logger)
+    {
+        assert manager != null;
+
+        this.manager = manager;
+
+        if (logger != null)
+        {
+            manager.addPlasticClassListener(new 
PlasticClassListenerLogger(logger));
+        }
+    }
+
+    @Override
+    public ClassLoader getClassLoader()
+    {
+        return manager.getClassLoader();
+    }
+
+    @Override
+    public <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, 
Class<? extends T> implementationType, PlasticClassTransformer callback)
+    {
+        return manager.createProxy(interfaceType, implementationType, 
callback);
+    }
+    
+    @Override
+    public <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, 
PlasticClassTransformer callback)
+    {
+        return manager.createProxy(interfaceType, callback);
+    }
+    
+    
+    @Override
+    public <T> PlasticClassTransformation<T> 
createProxyTransformation(Class<T> interfaceType,
+            Class<? extends T> implementationType)
+    {
+        return manager.createProxyTransformation(interfaceType, 
implementationType);
+    }
+
+    @Override
+    public <T> PlasticClassTransformation<T> 
createProxyTransformation(Class<T> interfaceType)
+    {
+        return createProxyTransformation(interfaceType, null);
+    }
+
+    @Override
+    public <T> T createProxy(final Class<T> interfaceType, final 
ObjectCreator<T> creator, final String description)
+    {   return createProxy(interfaceType, null, creator, description);
+    }
+    
+    @Override
+    public <T> T createProxy(final Class<T> interfaceType, final Class<? 
extends T> implementationType,
+            final ObjectCreator<T> creator, final String description)
+    {
+        assert creator != null;
+        assert InternalCommonsUtils.isNonBlank(description);
+
+        ClassInstantiator<T> instantiator = createProxy(interfaceType, 
implementationType, new PlasticClassTransformer()
+        {
+            @Override
+            public void transform(PlasticClass plasticClass)
+            {
+                final PlasticField objectCreatorField = 
plasticClass.introduceField(ObjectCreator.class, "creator")
+                        .inject(creator);
+
+                final String interfaceTypeName = interfaceType.getName();
+                PlasticMethod delegateMethod = 
plasticClass.introducePrivateMethod(interfaceTypeName, "delegate",
+                        null, null);
+
+                final InstructionBuilderCallback returnCreateObject = new 
InstructionBuilderCallback()
+                {
+                    @Override
+                    public void doBuild(InstructionBuilder builder)
+                    {
+                        builder.loadThis().getField(objectCreatorField);
+                        builder.invoke(ObjectCreator.class, Object.class, 
"createObject");
+                        builder.checkcast(interfaceType).returnResult();
+                    }
+                };
+                
+                delegateMethod.changeImplementation(returnCreateObject);
+
+                for (Method method : interfaceType.getMethods())
+                {
+                    
plasticClass.introduceMethod(method).delegateTo(delegateMethod);
+                }
+                
+                // TA5-2235
+                MethodDescription getDelegateMethodDescription = 
+                        new MethodDescription(interfaceType.getName(), 
INTERNAL_GET_DELEGATE);
+                plasticClass.introduceMethod(getDelegateMethodDescription, 
returnCreateObject);
+                
+                plasticClass.addToString(description);
+                
+            }
+        });
+
+        return interfaceType.cast(instantiator.newInstance());
+    }
+
+    private ClassNode readClassNode(Class clazz)
+    {
+        byte[] bytecode = 
PlasticInternalUtils.readBytecodeForClass(manager.getClassLoader(), 
clazz.getName(), false);
+
+        return bytecode == null ? null : 
PlasticInternalUtils.convertBytecodeToClassNode(bytecode);
+    }
+
+    @Override
+    public Location getMethodLocation(final Method method)
+    {
+        ObjectCreator<String> descriptionCreator = new ObjectCreator<String>()
+        {
+            @Override
+            public String createObject()
+            {
+                return InternalCommonsUtils.asString(method);
+            }
+        };
+
+        return getMemberLocation(method, method.getName(), 
Type.getMethodDescriptor(method),
+                descriptionCreator);
+    }
+
+    @Override
+    public Location getConstructorLocation(final Constructor constructor)
+    {
+        ObjectCreator<String> descriptionCreator = new ObjectCreator<String>()
+        {
+            @Override
+            public String createObject()
+            {
+                StringBuilder builder = new 
StringBuilder(constructor.getDeclaringClass().getName()).append("(");
+                String sep = "";
+
+                for (Class parameterType : constructor.getParameterTypes())
+                {
+                    builder.append(sep);
+                    builder.append(parameterType.getSimpleName());
+
+                    sep = ", ";
+                }
+
+                builder.append(")");
+
+                return builder.toString();
+            }
+        };
+
+        return getMemberLocation(constructor, "<init>", 
Type.getConstructorDescriptor(constructor),
+                descriptionCreator);
+    }
+
+    @Override
+    public void clearCache()
+    {
+        memberToLocation.clear();
+    }
+
+
+    public Location getMemberLocation(Member member, String methodName, String 
memberTypeDesc, ObjectCreator<String> textDescriptionCreator)
+    {
+        String className = member.getDeclaringClass().getName();
+
+        String key = className + ":" + methodName + ":" + memberTypeDesc;
+
+        Location location = memberToLocation.get(key);
+
+        if (location == null)
+        {
+            location = constructMemberLocation(member, methodName, 
memberTypeDesc, textDescriptionCreator.createObject());
+
+            memberToLocation.put(key, location);
+        }
+
+        return location;
+
+    }
+
+    private Location constructMemberLocation(Member member, String methodName, 
String memberTypeDesc, String textDescription)
+    {
+
+        ClassNode classNode = readClassNode(member.getDeclaringClass());
+
+        if (classNode == null)
+        {
+            throw new RuntimeException(String.format("Unable to read class 
file for %s (to gather line number information).",
+                    textDescription));
+        }
+
+        for (MethodNode mn : (List<MethodNode>) classNode.methods)
+        {
+            if (mn.name.equals(methodName) && mn.desc.equals(memberTypeDesc))
+            {
+                int lineNumber = findFirstLineNumber(mn.instructions);
+
+                // If debugging info is not available, we may lose the line 
number data, in which case,
+                // just generate the Location from the textDescription.
+
+                if (lineNumber < 1)
+                {
+                    break;
+                }
+
+                String description = String.format("%s (at %s:%d)", 
textDescription, classNode.sourceFile, lineNumber);
+
+                return new StringLocation(description, lineNumber);
+            }
+        }
+
+        // Didn't find it. Odd.
+
+        return new StringLocation(textDescription, 0);
+    }
+
+    private int findFirstLineNumber(InsnList instructions)
+    {
+        for (AbstractInsnNode node = instructions.getFirst(); node != null; 
node = node.getNext())
+        {
+            if (node instanceof LineNumberNode)
+            {
+                return ((LineNumberNode) node).line;
+            }
+        }
+
+        return -1;
+    }
+
+    @Override
+    public void addPlasticClassListener(PlasticClassListener listener)
+    {
+        manager.addPlasticClassListener(listener);
+    }
+
+    @Override
+    public void removePlasticClassListener(PlasticClassListener listener)
+    {
+        manager.removePlasticClassListener(listener);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java
----------------------------------------------------------------------
diff --git 
a/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java
 
b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java
new file mode 100644
index 0000000..8dd1e02
--- /dev/null
+++ 
b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java
@@ -0,0 +1,217 @@
+// 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
+//
+// 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 org.apache.tapestry5.ioc.internal.services;
+
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.annotation.Annotation;
+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;
+
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
+import org.apache.tapestry5.ioc.services.PropertyAccess;
+
+@SuppressWarnings("unchecked")
+public class PropertyAccessImpl implements PropertyAccess
+{
+    private final Map<Class, ClassPropertyAdapter> adapters = 
CollectionFactory.newConcurrentMap();
+
+    @Override
+    public Object get(Object instance, String propertyName)
+    {
+        return getAdapter(instance).get(instance, propertyName);
+    }
+
+    @Override
+    public void set(Object instance, String propertyName, Object value)
+    {
+        getAdapter(instance).set(instance, propertyName, value);
+    }
+
+    @Override
+    public Annotation getAnnotation(Object instance, String propertyName, 
Class<? extends Annotation> annotationClass) {
+    return getAdapter(instance).getAnnotation(instance, propertyName, 
annotationClass);
+    }
+
+
+    /**
+     * Clears the cache of adapters and asks the {@link Introspector} to clear 
its cache.
+     */
+    @Override
+    public synchronized void clearCache()
+    {
+        adapters.clear();
+
+        Introspector.flushCaches();
+    }
+
+    @Override
+    public ClassPropertyAdapter getAdapter(Object instance)
+    {
+        return getAdapter(instance.getClass());
+    }
+
+    @Override
+    public ClassPropertyAdapter getAdapter(Class forClass)
+    {
+        ClassPropertyAdapter result = adapters.get(forClass);
+
+        if (result == null)
+        {
+            result = buildAdapter(forClass);
+            adapters.put(forClass, result);
+        }
+
+        return result;
+    }
+
+    /**
+     * Builds a new adapter and updates the _adapters cache. This not only 
guards access to the adapter cache, but also
+     * serializes access to the Java Beans Introspector, which is not thread 
safe. In addition, handles the case where
+     * the class in question is an interface, accumulating properties 
inherited from super-classes.
+     */
+    private synchronized ClassPropertyAdapter buildAdapter(Class forClass)
+    {
+        // In some race conditions, we may hit this method for the same class 
multiple times.
+        // We just let it happen, replacing the old ClassPropertyAdapter with 
a new one.
+
+        try
+        {
+            BeanInfo info = Introspector.getBeanInfo(forClass);
+
+            List<PropertyDescriptor> descriptors = CollectionFactory.newList();
+
+            addAll(descriptors, info.getPropertyDescriptors());
+
+            // TAP5-921 - Introspector misses interface methods not 
implemented in an abstract class
+            if (forClass.isInterface() || 
Modifier.isAbstract(forClass.getModifiers()) )
+                addPropertiesFromExtendedInterfaces(forClass, descriptors);
+
+            addPropertiesFromScala(forClass, descriptors);
+
+            return new ClassPropertyAdapterImpl(forClass, descriptors);
+        }
+        catch (Throwable ex)
+        {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    private <T> void addAll(List<T> list, T[] array)
+    {
+        list.addAll(Arrays.asList(array));
+    }
+
+    private void addPropertiesFromExtendedInterfaces(Class forClass, 
List<PropertyDescriptor> descriptors)
+            throws IntrospectionException
+    {
+        LinkedList<Class> queue = CollectionFactory.newLinkedList();
+
+        // Seed the queue
+        addAll(queue, forClass.getInterfaces());
+
+        while (!queue.isEmpty())
+        {
+            Class c = queue.removeFirst();
+
+            BeanInfo info = Introspector.getBeanInfo(c);
+
+            // Duplicates occur and are filtered out in ClassPropertyAdapter 
which stores
+            // a property name to descriptor map.
+            addAll(descriptors, info.getPropertyDescriptors());
+            addAll(queue, c.getInterfaces());
+        }
+    }
+
+    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;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
----------------------------------------------------------------------
diff --git 
a/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
 
b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
new file mode 100644
index 0000000..97685ef
--- /dev/null
+++ 
b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
@@ -0,0 +1,273 @@
+// Copyright 2006-2013 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 org.apache.tapestry5.ioc.internal.services;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
+import org.apache.tapestry5.ioc.services.PropertyAdapter;
+import org.apache.tapestry5.ioc.util.ExceptionUtils;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.*;
+import java.util.List;
+
+public class PropertyAdapterImpl implements PropertyAdapter
+{
+    private final ClassPropertyAdapter classAdapter;
+
+    private final String name;
+
+    private final Method readMethod;
+
+    private final Method writeMethod;
+
+    private final Class type;
+
+    private final boolean castRequired;
+
+    // Synchronized by this; lazily initialized
+    private AnnotationProvider annotationProvider;
+
+    private final Field field;
+
+    private final Class declaringClass;
+
+    PropertyAdapterImpl(ClassPropertyAdapter classAdapter, String name, Class 
type, Method readMethod,
+                        Method writeMethod)
+    {
+        this.classAdapter = classAdapter;
+        this.name = name;
+        this.type = type;
+
+        this.readMethod = readMethod;
+        this.writeMethod = writeMethod;
+
+        declaringClass = readMethod != null ? readMethod.getDeclaringClass() : 
writeMethod.getDeclaringClass();
+
+        castRequired = readMethod != null && readMethod.getReturnType() != 
type;
+
+        field = null;
+    }
+
+    PropertyAdapterImpl(ClassPropertyAdapter classAdapter, String name, Class 
type, Field field)
+    {
+        this.classAdapter = classAdapter;
+        this.name = name;
+        this.type = type;
+
+        this.field = field;
+
+        declaringClass = field.getDeclaringClass();
+
+        castRequired = field.getType() != type;
+
+        readMethod = null;
+        writeMethod = null;
+    }
+
+    @Override
+    public String getName()
+    {
+        return name;
+    }
+
+    @Override
+    public Method getReadMethod()
+    {
+        return readMethod;
+    }
+
+    @Override
+    public Class getType()
+    {
+        return type;
+    }
+
+    @Override
+    public Method getWriteMethod()
+    {
+        return writeMethod;
+    }
+
+    @Override
+    public boolean isRead()
+    {
+        return field != null || readMethod != null;
+    }
+
+    @Override
+    public boolean isUpdate()
+    {
+        return writeMethod != null || (field != null && !isFinal(field));
+    }
+
+    private boolean isFinal(Member member)
+    {
+        return Modifier.isFinal(member.getModifiers());
+    }
+
+    @Override
+    public Object get(Object instance)
+    {
+        if (field == null && readMethod == null)
+        {
+            throw new UnsupportedOperationException(String.format("Class %s 
does not provide an accessor ('getter') method for property '%s'.", 
toClassName(instance), name));
+        }
+
+        Throwable fail;
+
+        try
+        {
+            if (field == null)
+                return readMethod.invoke(instance);
+            else
+                return field.get(instance);
+        } catch (InvocationTargetException ex)
+        {
+            fail = ex.getTargetException();
+        } catch (Exception ex)
+        {
+            fail = ex;
+        }
+
+        throw new RuntimeException(ServiceMessages.readFailure(name, instance, 
fail), fail);
+    }
+
+    @Override
+    public void set(Object instance, Object value)
+    {
+        if (field == null && writeMethod == null)
+        {
+            throw new UnsupportedOperationException(String.format("Class %s 
does not provide a mutator ('setter') method for property '%s'.",
+                    toClassName(instance),
+                    name
+            ));
+        }
+
+        Throwable fail;
+
+        try
+        {
+            if (field == null)
+                writeMethod.invoke(instance, value);
+            else
+                field.set(instance, value);
+
+            return;
+        } catch (InvocationTargetException ex)
+        {
+            fail = ex.getTargetException();
+        } catch (Exception ex)
+        {
+            fail = ex;
+        }
+
+        throw new RuntimeException(String.format("Error updating property '%s' 
of %s: %s",
+                name, toClassName(instance),
+                ExceptionUtils.toMessage(fail)), fail);
+    }
+
+    private String toClassName(Object instance)
+    {
+        return instance == null ? "<null>" : instance.getClass().getName();
+    }
+
+    @Override
+    public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+    {
+        return getAnnnotationProvider().getAnnotation(annotationClass);
+    }
+
+    /**
+     * Creates (as needed) the annotation provider for this property.
+     */
+    private synchronized AnnotationProvider getAnnnotationProvider()
+    {
+        if (annotationProvider == null)
+        {
+            List<AnnotationProvider> providers = CollectionFactory.newList();
+
+            if (readMethod != null)
+                providers.add(new 
AccessableObjectAnnotationProvider(readMethod));
+
+            if (writeMethod != null)
+                providers.add(new 
AccessableObjectAnnotationProvider(writeMethod));
+
+            // There's an assumption here, that the fields match the property 
name (we ignore case
+            // which leads to a manageable ambiguity) and that the field and 
the getter/setter
+            // are in the same class (i.e., that we don't have a getter 
exposing a protected field inherted
+            // from a base class, or some other oddity).
+
+            Class cursor = getBeanType();
+
+            out:
+            while (cursor != null)
+            {
+                for (Field f : cursor.getDeclaredFields())
+                {
+                    if (f.getName().equalsIgnoreCase(name))
+                    {
+                        providers.add(new 
AccessableObjectAnnotationProvider(f));
+
+                        break out;
+                    }
+                }
+
+                cursor = cursor.getSuperclass();
+            }
+
+            annotationProvider = AnnotationProviderChain.create(providers);
+        }
+
+        return annotationProvider;
+    }
+
+    @Override
+    public boolean isCastRequired()
+    {
+        return castRequired;
+    }
+
+    @Override
+    public ClassPropertyAdapter getClassAdapter()
+    {
+        return classAdapter;
+    }
+
+    @Override
+    public Class getBeanType()
+    {
+        return classAdapter.getBeanType();
+    }
+
+    @Override
+    public boolean isField()
+    {
+        return field != null;
+    }
+
+    @Override
+    public Field getField()
+    {
+        return field;
+    }
+
+    @Override
+    public Class getDeclaringClass()
+    {
+        return declaringClass;
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/commons/build.gradle
----------------------------------------------------------------------
diff --git a/commons/build.gradle b/commons/build.gradle
index 76850ef..98ae8bf 100644
--- a/commons/build.gradle
+++ b/commons/build.gradle
@@ -10,6 +10,7 @@ buildDir = 'target/gradle-build'
 dependencies {
        compile project(":plastic")
        compile project(":tapestry5-annotations")
+       compile project(":tapestry-func")
 }
 
 jar {  

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/commons/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java
----------------------------------------------------------------------
diff --git 
a/commons/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java
 
b/commons/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java
new file mode 100644
index 0000000..fae9ab8
--- /dev/null
+++ 
b/commons/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java
@@ -0,0 +1,54 @@
+// Copyright 2009, 2012 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 org.apache.tapestry5.internal.services;
+
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.services.ComponentClasses;
+import org.apache.tapestry5.services.InvalidationEventHub;
+
+import javax.annotation.PostConstruct;
+
+import java.util.Map;
+
+public class StringInternerImpl implements StringInterner
+{
+    private final Map<String, String> cache = 
CollectionFactory.newConcurrentMap();
+
+    @PostConstruct
+    public void setupInvalidation(@ComponentClasses InvalidationEventHub hub)
+    {
+        hub.clearOnInvalidation(cache);
+    }
+
+    public String intern(String string)
+    {
+        String result = cache.get(string);
+
+        // Not yet in the cache?  Add it.
+
+        if (result == null)
+        {
+            cache.put(string, string);
+            result = string;
+        }
+
+        return result;
+    }
+
+    public String format(String format, Object... arguments)
+    {
+        return intern(String.format(format, arguments));
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/commons/src/main/java/org/apache/tapestry5/ioc/Configuration.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/Configuration.java 
b/commons/src/main/java/org/apache/tapestry5/ioc/Configuration.java
new file mode 100644
index 0000000..03814f5
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/Configuration.java
@@ -0,0 +1,53 @@
+// Copyright 2006, 2008, 2009 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 org.apache.tapestry5.ioc;
+
+/**
+ * Object passed into a service contributor method that allows the method 
provide contributed values to the service's
+ * configuration.
+ * <p/>
+ * A service can <em>collect</em> contributions in three different ways:
+ * <ul>
+ * <li>As an un-ordered collection of values</li>
+ * <li>As an ordered list of values (where each value has a unique id, 
pre-requisites and post-requisites)</li>
+ * <li>As a map of keys and values
+ * </ul>
+ * <p/>
+ * This implementation is used for un-ordered configuration data.
+ * <p/>
+ * The service defines the <em>type</em> of contribution, in terms of a base 
class or service interface. Contributions
+ * must be compatible with the type.
+ */
+public interface Configuration<T>
+{
+    /**
+     * Adds an object to the service's contribution.
+     * 
+     * @param object
+     *            to add to the service's configuration
+     */
+    void add(T object);
+
+    /**
+     * Automatically instantiates an instance of the class, with dependencies 
injected, and adds it to the
+     * configuration. When the configuration type is an interface and the 
class to be contributed is a local file,
+     * then a reloadable proxy for the class will be created and contributed.
+     * 
+     * @param clazz
+     *            what class to instantiate
+     * @since 5.1.0.0
+     */
+    void addInstance(Class<? extends T> clazz);
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/commons/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java
----------------------------------------------------------------------
diff --git 
a/commons/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java 
b/commons/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java
new file mode 100644
index 0000000..47c6026
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java
@@ -0,0 +1,81 @@
+// Copyright 2006, 2008, 2009, 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
+//
+// 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 org.apache.tapestry5.ioc;
+
+/**
+ * Object passed into a service contributor method that allows the method 
provide contributed values to the service's
+ * configuration.
+ * <p/>
+ * A service can <em>collect</em> contributions in three different ways:
+ * <ul>
+ * <li>As an un-ordered collection of values</li>
+ * <li>As an ordered list of values (where each value has a unique id, 
pre-requisites and post-requisites)</li>
+ * <li>As a map of keys and values
+ * </ul>
+ * <p/>
+ * The service defines the <em>type</em> of contribution, in terms of a base 
class or service interface. Contributions
+ * must be compatible with the type.
+ */
+public interface MappedConfiguration<K, V>
+{
+
+    /**
+     * Adds a keyed object to the service's contribution.
+     * 
+     * @param key
+     *            unique id for the value
+     * @param value
+     *            to contribute
+     * @throws IllegalArgumentException
+     *             if key is not unique
+     */
+    void add(K key, V value);
+
+    /**
+     * Overrides an existing contribution by its key.
+     * 
+     * @param key
+     *            unique id of value to override
+     * @param value
+     *            new value, or null to remove the key entirely
+     * @since 5.1.0.0
+     */
+    void override(K key, V value);
+
+    /**
+     * Adds a keyed object as an instantiated instance (with dependencies 
injected) of a class. When the value
+     * type is an interface and the class to be contributed is a local file,
+     * then a reloadable proxy for the value class will be created and 
contributed.
+     * 
+     * @param key
+     *            unique id for the value
+     * @param clazz
+     *            class to instantiate and contribute
+     * @since 5.1.0.0
+     */
+    void addInstance(K key, Class<? extends V> clazz);
+
+    /**
+     * Overrides an existing contribution with a new instance. When the value
+     * type is an interface and the class to be contributed is a local file,
+     * then a reloadable proxy for the value class will be created and 
contributed.
+     * 
+     * @param key
+     *            unique id of value to override
+     * @param clazz
+     *            class to instantiate as override
+     */
+    void overrideInstance(K key, Class<? extends V> clazz);
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/commons/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java
----------------------------------------------------------------------
diff --git 
a/commons/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java 
b/commons/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java
new file mode 100644
index 0000000..9151381
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java
@@ -0,0 +1,84 @@
+// Copyright 2006, 2008, 2009, 2010, 2011 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 org.apache.tapestry5.ioc;
+
+/**
+ * Object passed into a service contributor method that allows the method 
provide contributed values to the service's
+ * configuration.
+ * <p/>
+ * A service can <em>collect</em> contributions in three different ways:
+ * <ul>
+ * <li>As an un-ordered collection of values</li>
+ * <li>As an ordered list of values (where each value has a unique id, 
pre-requisites and post-requisites)</li>
+ * <li>As a map of keys and values
+ * </ul>
+ * <p/>
+ * The service defines the <em>type</em> of contribution, in terms of a base 
class or service interface. Contributions
+ * must be compatible with the type, or be {@linkplain 
org.apache.tapestry5.ioc.services.TypeCoercer coercable} to the type.
+ *
+ * @see org.apache.tapestry5.ioc.annotations.Contribute
+ * @see org.apache.tapestry5.ioc.annotations.UsesConfiguration
+ */
+public interface OrderedConfiguration<T>
+{
+    /**
+     * Adds an ordered object to a service's contribution. Each object has an 
id (which must be unique). Optionally,
+     * pre-requisites (a list of ids that must precede this object) and 
post-requisites (ids that must follow) can be
+     * provided.
+     * <p/>
+     * <p>If no constraints are supplied, then an implicit constraint is 
supplied: after the previously
+     * contributed id <em>within the same contribution method</em>.
+     *
+     * @param id          a unique id for the object; the id will be fully 
qualified with the contributing module's id
+     * @param constraints used to order the object relative to other 
contributed objects
+     * @param object      to add to the service's configuration
+     */
+    void add(String id, T object, String... constraints);
+
+    /**
+     * Overrides a normally contributed object. Each override must match a 
single normally contributed object.
+     *
+     * @param id          identifies object to override
+     * @param object      overriding object (may be null)
+     * @param constraints constraints for the overridden object, replacing 
constraints for the original object (even if
+     *                    omitted, in which case the override object will have 
no ordering constraints)
+     * @since 5.1.0.0
+     */
+    void override(String id, T object, String... constraints);
+
+    /**
+     * Adds an ordered object by instantiating (with dependencies) the 
indicated class. When the configuration type is
+     * an interface and the class to be contributed is a local file,
+     * then a reloadable proxy for the class will be created and contributed.
+     *
+     * @param id          of contribution (used for ordering)
+     * @param clazz       class to instantiate
+     * @param constraints used to order the object relative to other 
contributed objects
+     * @since 5.1.0.0
+     */
+    void addInstance(String id, Class<? extends T> clazz, String... 
constraints);
+
+    /**
+     * Instantiates an object and adds it as an override. When the 
configuration type is an interface and the class to
+     * be contributed is a local file, then a reloadable proxy for the class 
will be created and contributed.
+     *
+     * @param id          of object to override
+     * @param clazz       to instantiate
+     * @param constraints constraints for the overridden object, replacing 
constraints for the original object (even if
+     *                    omitted, in which case the override object will have 
no ordering constraints)
+     * @since 5.1.0.0
+     */
+    void overrideInstance(String id, Class<? extends T> clazz, String... 
constraints);
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/commons/src/main/java/org/apache/tapestry5/ioc/internal/BasicTypeCoercions.java
----------------------------------------------------------------------
diff --git 
a/commons/src/main/java/org/apache/tapestry5/ioc/internal/BasicTypeCoercions.java
 
b/commons/src/main/java/org/apache/tapestry5/ioc/internal/BasicTypeCoercions.java
new file mode 100644
index 0000000..f7bde31
--- /dev/null
+++ 
b/commons/src/main/java/org/apache/tapestry5/ioc/internal/BasicTypeCoercions.java
@@ -0,0 +1,342 @@
+// Copyright 2014 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 org.apache.tapestry5.ioc.internal;
+
+import java.io.File;
+import java.lang.reflect.Array;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.tapestry5.func.Flow;
+import org.apache.tapestry5.ioc.Configuration;
+import org.apache.tapestry5.ioc.services.Coercion;
+import org.apache.tapestry5.ioc.services.CoercionTuple;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
+import org.apache.tapestry5.ioc.util.TimeInterval;
+
+/**
+ * Class that provides Tapestry-IoC's basic type coercions.
+ * @see TypeCoercer
+ * @see Coercion
+ */
+public class BasicTypeCoercions
+{
+    /**
+     * Provides the basic type coercions to a {@link Configuration} instance. 
+     */
+    public static void provideBasicTypeCoercions(Configuration<CoercionTuple> 
configuration)
+    {
+        add(configuration, Object.class, String.class, new Coercion<Object, 
String>()
+        {
+            @Override
+            public String coerce(Object input)
+            {
+                return input.toString();
+            }
+        });
+
+        add(configuration, Object.class, Boolean.class, new Coercion<Object, 
Boolean>()
+        {
+            @Override
+            public Boolean coerce(Object input)
+            {
+                return input != null;
+            }
+        });
+
+        add(configuration, String.class, Double.class, new Coercion<String, 
Double>()
+        {
+            @Override
+            public Double coerce(String input)
+            {
+                return new Double(input);
+            }
+        });
+
+        // String to BigDecimal is important, as String->Double->BigDecimal 
would lose
+        // precision.
+
+        add(configuration, String.class, BigDecimal.class, new 
Coercion<String, BigDecimal>()
+        {
+            @Override
+            public BigDecimal coerce(String input)
+            {
+                return new BigDecimal(input);
+            }
+        });
+
+        add(configuration, BigDecimal.class, Double.class, new 
Coercion<BigDecimal, Double>()
+        {
+            @Override
+            public Double coerce(BigDecimal input)
+            {
+                return input.doubleValue();
+            }
+        });
+
+        add(configuration, String.class, BigInteger.class, new 
Coercion<String, BigInteger>()
+        {
+            @Override
+            public BigInteger coerce(String input)
+            {
+                return new BigInteger(input);
+            }
+        });
+
+        add(configuration, String.class, Long.class, new Coercion<String, 
Long>()
+        {
+            @Override
+            public Long coerce(String input)
+            {
+                return new Long(input);
+            }
+        });
+
+        add(configuration, Long.class, Byte.class, new Coercion<Long, Byte>()
+        {
+            @Override
+            public Byte coerce(Long input)
+            {
+                return input.byteValue();
+            }
+        });
+
+        add(configuration, Long.class, Short.class, new Coercion<Long, Short>()
+        {
+            @Override
+            public Short coerce(Long input)
+            {
+                return input.shortValue();
+            }
+        });
+
+        add(configuration, Long.class, Integer.class, new Coercion<Long, 
Integer>()
+        {
+            @Override
+            public Integer coerce(Long input)
+            {
+                return input.intValue();
+            }
+        });
+
+        add(configuration, Number.class, Long.class, new Coercion<Number, 
Long>()
+        {
+            @Override
+            public Long coerce(Number input)
+            {
+                return input.longValue();
+            }
+        });
+
+        add(configuration, Double.class, Float.class, new Coercion<Double, 
Float>()
+        {
+            @Override
+            public Float coerce(Double input)
+            {
+                return input.floatValue();
+            }
+        });
+
+        add(configuration, Long.class, Double.class, new Coercion<Long, 
Double>()
+        {
+            @Override
+            public Double coerce(Long input)
+            {
+                return input.doubleValue();
+            }
+        });
+
+        add(configuration, String.class, Boolean.class, new Coercion<String, 
Boolean>()
+        {
+            @Override
+            public Boolean coerce(String input)
+            {
+                String trimmed = input == null ? "" : input.trim();
+
+                if (trimmed.equalsIgnoreCase("false") || trimmed.length() == 0)
+                    return false;
+
+                // Any non-blank string but "false"
+
+                return true;
+            }
+        });
+
+        add(configuration, Number.class, Boolean.class, new Coercion<Number, 
Boolean>()
+        {
+            @Override
+            public Boolean coerce(Number input)
+            {
+                return input.longValue() != 0;
+            }
+        });
+
+        add(configuration, Void.class, Boolean.class, new Coercion<Void, 
Boolean>()
+        {
+            @Override
+            public Boolean coerce(Void input)
+            {
+                return false;
+            }
+        });
+
+        add(configuration, Collection.class, Boolean.class, new 
Coercion<Collection, Boolean>()
+        {
+            @Override
+            public Boolean coerce(Collection input)
+            {
+                return !input.isEmpty();
+            }
+        });
+
+        add(configuration, Object.class, List.class, new Coercion<Object, 
List>()
+        {
+            @Override
+            public List coerce(Object input)
+            {
+                return Collections.singletonList(input);
+            }
+        });
+
+        add(configuration, Object[].class, List.class, new Coercion<Object[], 
List>()
+        {
+            @Override
+            public List coerce(Object[] input)
+            {
+                return Arrays.asList(input);
+            }
+        });
+
+        add(configuration, Object[].class, Boolean.class, new 
Coercion<Object[], Boolean>()
+        {
+            @Override
+            public Boolean coerce(Object[] input)
+            {
+                return input != null && input.length > 0;
+            }
+        });
+
+        add(configuration, Float.class, Double.class, new Coercion<Float, 
Double>()
+        {
+            @Override
+            public Double coerce(Float input)
+            {
+                return input.doubleValue();
+            }
+        });
+
+        Coercion primitiveArrayCoercion = new Coercion<Object, List>()
+        {
+            @Override
+            public List<Object> coerce(Object input)
+            {
+                int length = Array.getLength(input);
+                Object[] array = new Object[length];
+                for (int i = 0; i < length; i++)
+                {
+                    array[i] = Array.get(input, i);
+                }
+                return Arrays.asList(array);
+            }
+        };
+
+        add(configuration, byte[].class, List.class, primitiveArrayCoercion);
+        add(configuration, short[].class, List.class, primitiveArrayCoercion);
+        add(configuration, int[].class, List.class, primitiveArrayCoercion);
+        add(configuration, long[].class, List.class, primitiveArrayCoercion);
+        add(configuration, float[].class, List.class, primitiveArrayCoercion);
+        add(configuration, double[].class, List.class, primitiveArrayCoercion);
+        add(configuration, char[].class, List.class, primitiveArrayCoercion);
+        add(configuration, boolean[].class, List.class, 
primitiveArrayCoercion);
+
+        add(configuration, String.class, File.class, new Coercion<String, 
File>()
+        {
+            @Override
+            public File coerce(String input)
+            {
+                return new File(input);
+            }
+        });
+
+        add(configuration, String.class, TimeInterval.class, new 
Coercion<String, TimeInterval>()
+        {
+            @Override
+            public TimeInterval coerce(String input)
+            {
+                return new TimeInterval(input);
+            }
+        });
+
+        add(configuration, TimeInterval.class, Long.class, new 
Coercion<TimeInterval, Long>()
+        {
+            @Override
+            public Long coerce(TimeInterval input)
+            {
+                return input.milliseconds();
+            }
+        });
+
+        add(configuration, Object.class, Object[].class, new Coercion<Object, 
Object[]>()
+        {
+            @Override
+            public Object[] coerce(Object input)
+            {
+                return new Object[]
+                        {input};
+            }
+        });
+
+        add(configuration, Collection.class, Object[].class, new 
Coercion<Collection, Object[]>()
+        {
+            @Override
+            public Object[] coerce(Collection input)
+            {
+                return input.toArray();
+            }
+        });
+        
+        configuration.add(CoercionTuple.create(Flow.class, List.class, new 
Coercion<Flow, List>()
+        {
+            @Override
+            public List coerce(Flow input)
+            {
+                return input.toList();
+            }
+        }));
+
+        configuration.add(CoercionTuple.create(Flow.class, Boolean.class, new 
Coercion<Flow, Boolean>()
+        {
+            @Override
+            public Boolean coerce(Flow input)
+            {
+                return !input.isEmpty();
+            }
+        }));
+        
+
+    }
+
+    private static <S, T> void add(Configuration<CoercionTuple> configuration, 
Class<S> sourceType,
+                                   Class<T> targetType, Coercion<S, T> 
coercion)
+    {
+        configuration.add(CoercionTuple.create(sourceType, targetType, 
coercion));
+    }
+    
+    
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java
----------------------------------------------------------------------
diff --git 
a/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java
 
b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java
new file mode 100644
index 0000000..2acfd0d
--- /dev/null
+++ 
b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java
@@ -0,0 +1,46 @@
+// Copyright 2008 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 org.apache.tapestry5.ioc.internal.services;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AccessibleObject;
+
+/**
+ * Provides access to annotations of an accessable object such as a {@link 
java.lang.reflect.Method} or {@link
+ * java.lang.reflect.Field}.
+ */
+public class AccessableObjectAnnotationProvider implements AnnotationProvider
+{
+    private final AccessibleObject object;
+
+    public AccessableObjectAnnotationProvider(AccessibleObject object)
+    {
+        this.object = object;
+    }
+
+    @Override
+    public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+    {
+        return object.getAnnotation(annotationClass);
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("AnnotationProvider[%s]", object);
+    }
+}

Reply via email to