You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by th...@apache.org on 2014/12/21 20:56:46 UTC

[20/35] tapestry-5 git commit: Fourth pass creating the BeanModel and Commons packages.

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 <th...@apache.org>
Authored: Sat Dec 6 19:45:14 2014 -0200
Committer: Thiago H. de Paula Figueiredo <th...@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);
+    }
+}