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/06 23:30:12 UTC

[01/15] tapestry-5 git commit: First pass creating the BeanModel and Commons packages. Lots of stuff moved around, but no actual code changes so far

Repository: tapestry-5
Updated Branches:
  refs/heads/beanmodel-split [created] 696bc7ae8


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/ExceptionUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/ExceptionUtils.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/ExceptionUtils.java
deleted file mode 100644
index 2feaeca..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/ExceptionUtils.java
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright 2008-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.util;
-
-import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
-import org.apache.tapestry5.ioc.services.PropertyAccess;
-
-/**
- * Contains static methods useful for manipulating exceptions.
- */
-public class ExceptionUtils
-{
-    /**
-     * Locates a particular type of exception, working its way via the cause property of each exception in the exception
-     * stack.
-     *
-     * @param t    the outermost exception
-     * @param type the type of exception to search for
-     * @return the first exception of the given type, if found, or null
-     */
-    public static <T extends Throwable> T findCause(Throwable t, Class<T> type)
-    {
-        Throwable current = t;
-
-        while (current != null)
-        {
-            if (type.isInstance(current))
-            {
-                return type.cast(current);
-            }
-
-            // Not a match, work down.
-
-            current = current.getCause();
-        }
-
-        return null;
-    }
-
-    /**
-     * Locates a particular type of exception, working its way down via any property that returns some type of Exception.
-     * This is more expensive, but more accurate, than {@link #findCause(Throwable, Class)} as it works with older exceptions
-     * that do not properly implement the (relatively new) {@linkplain Throwable#getCause() cause property}.
-     *
-     * @param t      the outermost exception
-     * @param type   the type of exception to search for
-     * @param access used to access properties
-     * @return the first exception of the given type, if found, or null
-     */
-    public static <T extends Throwable> T findCause(Throwable t, Class<T> type, PropertyAccess access)
-    {
-        Throwable current = t;
-
-        while (current != null)
-        {
-            if (type.isInstance(current))
-            {
-                return type.cast(current);
-            }
-
-            Throwable next = null;
-
-            ClassPropertyAdapter adapter = access.getAdapter(current);
-
-            for (String name : adapter.getPropertyNames())
-            {
-
-                Object value = adapter.getPropertyAdapter(name).get(current);
-
-                if (value != null && value != current && value instanceof Throwable)
-                {
-                    next = (Throwable) value;
-                    break;
-                }
-            }
-
-            current = next;
-        }
-
-
-        return null;
-    }
-
-    /**
-     * Extracts the message from an exception. If the exception's message is null, returns the exceptions class name.
-     *
-     * @param exception
-     *         to extract message from
-     * @return message or class name
-     * @since 5.4
-     */
-    public static String toMessage(Throwable exception)
-    {
-        assert exception != null;
-
-        String message = exception.getMessage();
-
-        if (message != null)
-            return message;
-
-        return exception.getClass().getName();
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/UnknownValueException.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/UnknownValueException.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/UnknownValueException.java
deleted file mode 100644
index 470b611..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/UnknownValueException.java
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 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.util;
-
-import org.apache.tapestry5.ioc.internal.util.TapestryException;
-
-/**
- * Special exception used when a value (typically from a map) is referenced that does not exist. Uses a
- * {@link AvailableValues} object
- * to track what the known values are.
- * 
- * @since 5.2.0
- */
-public class UnknownValueException extends TapestryException
-{
-    private final AvailableValues availableValues;
-
-    public UnknownValueException(String message, AvailableValues availableValues)
-    {
-        this(message, null, null, availableValues);
-    }
-
-    public UnknownValueException(String message, Object location, Throwable cause, AvailableValues availableValues)
-    {
-        super(message, location, cause);
-
-        this.availableValues = availableValues;
-    }
-
-    public AvailableValues getAvailableValues()
-    {
-        return availableValues;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry5-annotations/build.gradle
----------------------------------------------------------------------
diff --git a/tapestry5-annotations/build.gradle b/tapestry5-annotations/build.gradle
index 7d7657c..4f411a1 100644
--- a/tapestry5-annotations/build.gradle
+++ b/tapestry5-annotations/build.gradle
@@ -1 +1 @@
-description = "Annotations used with Tapestry applications"
\ No newline at end of file
+description = "Annotations used with Tapestry, Tapestry-IoC and BeanModel applications"
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesConfiguration.java b/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesConfiguration.java
new file mode 100644
index 0000000..2e03557
--- /dev/null
+++ b/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesConfiguration.java
@@ -0,0 +1,34 @@
+//  Copyright 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.annotations;
+
+import java.lang.annotation.*;
+
+
+/**
+ * A documentation-only interface placed on service interfaces for services which have an {@linkplain
+ * org.apache.tapestry5.ioc.Configuration unordered configuration}, to identify the type of contribution.
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.CLASS)
+@Documented
+@UseWith(AnnotationUseContext.SERVICE)
+public @interface UsesConfiguration
+{
+    /**
+     * The type of object which may be contributed into the service's configuration.
+     */
+    Class value();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry5-annotations/src/main/java/org/apache/tapestry5/services/ComponentClasses.java
----------------------------------------------------------------------
diff --git a/tapestry5-annotations/src/main/java/org/apache/tapestry5/services/ComponentClasses.java b/tapestry5-annotations/src/main/java/org/apache/tapestry5/services/ComponentClasses.java
new file mode 100644
index 0000000..c901d3a
--- /dev/null
+++ b/tapestry5-annotations/src/main/java/org/apache/tapestry5/services/ComponentClasses.java
@@ -0,0 +1,35 @@
+// Copyright 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.services;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Marker annotation used to inject the correct {@link org.apache.tapestry5.services.InvalidationEventHub} service
+ * responsible for invalidations when underlying component class files are changed.
+ * 
+ * @since 5.1.0.0
+ */
+@Target(
+{ ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface ComponentClasses
+{
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry5-annotations/src/main/java/org/apache/tapestry5/services/ComponentLayer.java
----------------------------------------------------------------------
diff --git a/tapestry5-annotations/src/main/java/org/apache/tapestry5/services/ComponentLayer.java b/tapestry5-annotations/src/main/java/org/apache/tapestry5/services/ComponentLayer.java
new file mode 100644
index 0000000..e342c3f
--- /dev/null
+++ b/tapestry5-annotations/src/main/java/org/apache/tapestry5/services/ComponentLayer.java
@@ -0,0 +1,37 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.services;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Marker annotation used to identify a service from the component layer that conflicts, in terms of service interface,
+ * with a service from elsewhere. In particular, this is used to disambiguate {@link org.apache.tapestry5.ioc.services.PlasticProxyFactory} which has one implementation (marked with {@link
+ * org.apache.tapestry5.ioc.services.Builtin} and another with this annotation.
+ */
+@Target(
+        {PARAMETER, FIELD})
+@Retention(RUNTIME)
+@Documented
+public @interface ComponentLayer
+{
+
+}


[08/15] tapestry-5 git commit: Second pass creating the BeanModel and Commons packages.

Posted by th...@apache.org.
Second 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/1f36bb20
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/1f36bb20
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/1f36bb20

Branch: refs/heads/beanmodel-split
Commit: 1f36bb203cb0646f912125caa3bd03707aa95083
Parents: f963c7a
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Sat Dec 6 16:40:55 2014 -0200
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Sat Dec 6 16:40:55 2014 -0200

----------------------------------------------------------------------
 .../internal/antlr/PropertyExpressionLexer.g    | 163 +++++++++++++++++
 .../internal/antlr/PropertyExpressionParser.g   | 105 +++++++++++
 .../tapestry5/internal/antlr/BaseLexer.java     |  54 ++++++
 .../tapestry5/internal/antlr/BaseParser.java    |  40 +++++
 .../tapestry5/internal/antlr/package-info.java  |  18 ++
 .../tapestry5/internal/services/Invariant.java  |  28 +++
 .../services/LiteralPropertyConduit.java        |  85 +++++++++
 .../services/PropertyExpressionException.java   |  38 ++++
 .../internal/services/StringInterner.java       |  43 +++++
 .../org/apache/tapestry5/ioc/ObjectCreator.java |  27 +++
 .../ioc/services/PlasticProxyFactory.java       | 159 +++++++++++++++++
 .../org/apache/tapestry5/ioc/util/Stack.java    | 173 +++++++++++++++++++
 .../internal/antlr/PropertyExpressionLexer.g    | 163 -----------------
 .../internal/antlr/PropertyExpressionParser.g   | 105 -----------
 .../tapestry5/internal/antlr/BaseLexer.java     |  54 ------
 .../tapestry5/internal/antlr/BaseParser.java    |  40 -----
 .../tapestry5/internal/antlr/package-info.java  |  18 --
 .../tapestry5/internal/services/Invariant.java  |  28 ---
 .../services/LiteralPropertyConduit.java        |  85 ---------
 .../services/PropertyExpressionException.java   |  38 ----
 .../internal/services/StringInterner.java       |  43 -----
 .../org/apache/tapestry5/ioc/ObjectCreator.java |  27 ---
 .../ioc/annotations/IncompatibleChange.java     |  33 ----
 .../ioc/services/PlasticProxyFactory.java       | 159 -----------------
 .../org/apache/tapestry5/ioc/util/Stack.java    | 173 -------------------
 .../ioc/annotations/IncompatibleChange.java     |  33 ++++
 26 files changed, 966 insertions(+), 966 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g b/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g
new file mode 100644
index 0000000..3b52ba9
--- /dev/null
+++ b/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g
@@ -0,0 +1,163 @@
+// Copyright 2008, 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.
+
+lexer grammar PropertyExpressionLexer;
+
+
+options
+{
+  superClass='org.apache.tapestry5.internal.antlr.BaseLexer';
+}
+
+@header
+{
+package org.apache.tapestry5.internal.antlr;
+}
+
+	
+// Integer constant
+fragment INTEGER
+	:	{this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};	
+	
+// Read a property or invoke a method.
+fragment DEREF 
+	:	{this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};	
+	
+// Range operator, ".." between two integers.	
+fragment RANGEOP
+	:	{this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};	
+	
+// Decimal number	
+fragment DECIMAL
+	:	{this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};	
+			
+fragment LETTER 
+	:	('a'..'z'|'A'..'Z');
+fragment DIGIT 
+	:	'0'..'9';	
+fragment SIGN
+	:	('+'|'-');
+LPAREN 	:	'(';
+RPAREN 	:	')';
+LBRACKET:	'[';
+RBRACKET:	']';
+COMMA	:	',';
+BANG	:	'!';
+LBRACE	:	'{';
+RBRACE	:	'}';
+COLON	:	':';
+
+fragment QUOTE
+	:	'\'';
+
+// Clumsy but effective approach to case-insensitive identifiers.
+
+fragment A
+	:	('a' | 'A');
+fragment E
+	:	('e' | 'E');
+fragment F
+	:	('f' | 'F');	
+fragment H
+	:	('h' | 'H');
+fragment I
+	:	('i' | 'I');
+fragment L 
+	: 	('l' | 'L');
+fragment N 
+	:	('n'|'N');
+fragment R
+	:	('r' | 'R');
+fragment S
+	:	('s' | 'S');
+fragment T 
+	:	('t' | 'T');
+fragment U 
+	:	('u' | 'U');
+
+// Identifiers are case insensitive
+
+NULL 	:	N U L L;
+TRUE	:	T R U E;
+FALSE	:	F A L S E;
+THIS	:	T H I S;
+
+IDENTIFIER 
+    :   JAVA_ID_START (JAVA_ID_PART)*
+    ;
+
+fragment
+JAVA_ID_START
+    :  '\u0024'
+    |  '\u0041'..'\u005a'
+    |  '\u005f'
+    |  '\u0061'..'\u007a'
+    |  '\u00c0'..'\u00d6'
+    |  '\u00d8'..'\u00f6'
+    |  '\u00f8'..'\u00ff'
+    |  '\u0100'..'\u1fff'
+    |  '\u3040'..'\u318f'
+    |  '\u3300'..'\u337f'
+    |  '\u3400'..'\u3d2d'
+    |  '\u4e00'..'\u9fff'
+    |  '\uf900'..'\ufaff'
+    ;
+
+fragment
+JAVA_ID_PART
+    :  JAVA_ID_START
+    |  '\u0030'..'\u0039'
+    ;
+
+
+// The Safe Dereference operator understands not to de-reference through
+// a null.
+
+SAFEDEREF 
+	: 	'?.';
+
+WS 	:	(' '|'\t'|'\n'|'\r')+ { skip(); };
+
+
+// Literal strings are always inside single quotes.
+STRING
+	:	QUOTE (options {greedy=false;} : .)* QUOTE { setText(getText().substring(1, getText().length()-1)); };
+
+
+// Special rule that uses parsing tricks to identify numbers and ranges; it's all about
+// the dot ('.').
+// Recognizes:
+// '.' as DEREF
+// '..' as RANGEOP
+// INTEGER (sign? digit+)
+// DECIMAL (sign? digits* . digits+)
+// Has to watch out for embedded rangeop (i.e. "1..10" is not "1." and ".10").
+
+NUMBER_OR_RANGEOP
+	:	SIGN? DIGIT+
+		(
+			{ input.LA(2) != '.' }? => '.' DIGIT* {   $type = DECIMAL; stripLeadingPlus(); }
+			| {  $type = INTEGER;  stripLeadingPlus(); }
+		)
+		
+	|	SIGN '.' DIGIT+ {  $type = DECIMAL;  stripLeadingPlus(); }
+	
+	|	'.'
+		( 
+			DIGIT+ { $type = DECIMAL; stripLeadingPlus();}
+			| '.' {$type = RANGEOP; }
+			| {$type = DEREF; }
+		)
+	;	
+

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g b/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g
new file mode 100644
index 0000000..14753e6
--- /dev/null
+++ b/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g
@@ -0,0 +1,105 @@
+// Copyright 2008, 2009, 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.
+
+parser grammar PropertyExpressionParser;
+
+
+options
+{
+  superClass='org.apache.tapestry5.internal.antlr.BaseParser';
+  output=AST;		
+  ASTLabelType=CommonTree;
+  tokenVocab=PropertyExpressionLexer;
+  backtrack=true;
+}
+
+tokens
+{	
+	// Parser token representing a method invocation
+    	INVOKE;
+    	// A List (top level, or as method parameter)
+    	LIST;
+		//A Map (top level, or as method parameter)
+		MAP;
+    	// Not operation (invert a boolean)
+    	NOT;
+}
+
+@header
+{
+package org.apache.tapestry5.internal.antlr;
+}
+
+	
+start 	:	expression^ EOF!;
+		
+expression
+	:	keyword
+	|	rangeOp
+	|	constant
+	|	propertyChain
+	|	list
+	|	notOp
+	|	map
+	;
+
+keyword	:	NULL | TRUE | FALSE | THIS;
+
+constant:	INTEGER| DECIMAL | STRING;	
+	
+propertyChain
+	:	term DEREF propertyChain -> ^(DEREF term propertyChain)
+	|	term SAFEDEREF propertyChain -> ^(SAFEDEREF term propertyChain)
+	|	term
+	;	
+	
+term	:	IDENTIFIER
+	|	methodInvocation
+	;
+	
+methodInvocation
+	:	id=IDENTIFIER LPAREN RPAREN -> ^(INVOKE $id)
+	|	id=IDENTIFIER LPAREN expressionList RPAREN -> ^(INVOKE $id expressionList)
+	;	
+	
+expressionList
+	:	expression (COMMA! expression)*
+	;	
+
+rangeOp
+	:	from=rangeopArg  RANGEOP to=rangeopArg -> ^(RANGEOP $from $to)
+	;	
+	
+rangeopArg 
+	:	INTEGER
+	|	propertyChain
+	;	
+	
+list	:	LBRACKET RBRACKET -> ^(LIST)
+	|	LBRACKET expressionList RBRACKET -> ^(LIST expressionList)
+	;	
+	
+notOp 	:	BANG expression -> ^(NOT expression)
+	;
+
+map 	:	LBRACE RBRACE -> ^(MAP)
+	|	LBRACE mapEntryList RBRACE -> ^(MAP mapEntryList)
+    ;
+	
+mapEntryList : mapEntry (COMMA! mapEntry)*;
+
+mapEntry :  mapKey COLON! expression;
+	
+mapKey :	keyword | constant | propertyChain;
+	

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java
new file mode 100644
index 0000000..442240d
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java
@@ -0,0 +1,54 @@
+// Copyright 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.internal.antlr;
+
+import org.antlr.runtime.CharStream;
+import org.antlr.runtime.Lexer;
+import org.antlr.runtime.RecognizerSharedState;
+import org.antlr.runtime.RecognitionException;
+
+public abstract class BaseLexer extends Lexer
+{
+    protected BaseLexer()
+    {
+    }
+
+    protected BaseLexer(CharStream charStream,
+                        RecognizerSharedState recognizerSharedState)
+    {
+        super(charStream, recognizerSharedState);
+    }
+
+    protected void stripLeadingPlus()
+    {
+        String text = getText();
+
+        // For compatibility with Tapestry 5.0, we need to allow a sign of '+', which Long.parseLong()
+        // doesn't accept. To keep things downstream simple, we eliminate the '+' here.
+
+        if (text.startsWith("+"))
+        {
+            setText(text.substring(1));
+        }
+    }
+
+    @Override
+    public void reportError(RecognitionException e)
+    {
+        throw new RuntimeException(String.format("Unable to parse input at character position %d",
+                                                 e.charPositionInLine + 1),
+                                   e);
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java
new file mode 100644
index 0000000..212b782
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java
@@ -0,0 +1,40 @@
+// Copyright 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.internal.antlr;
+
+import org.antlr.runtime.Parser;
+import org.antlr.runtime.TokenStream;
+import org.antlr.runtime.RecognizerSharedState;
+
+public class BaseParser extends Parser
+{
+    public BaseParser(TokenStream tokenStream)
+    {
+        super(tokenStream);
+    }
+
+    public BaseParser(TokenStream tokenStream,
+                      RecognizerSharedState recognizerSharedState)
+    {
+        super(tokenStream, recognizerSharedState);
+    }
+
+    @Override
+    public void emitErrorMessage(String message)
+    {
+        // This is caught and more properly reported later.
+        throw new RuntimeException(message);
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java
new file mode 100644
index 0000000..55be313
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java
@@ -0,0 +1,18 @@
+// Copyright 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.
+
+/**
+ * [INTERNAL USE ONLY] support classes related to Antlr; API subject to change
+ */
+package org.apache.tapestry5.internal.antlr;

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/java/org/apache/tapestry5/internal/services/Invariant.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/Invariant.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/Invariant.java
new file mode 100644
index 0000000..924b570
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/Invariant.java
@@ -0,0 +1,28 @@
+// 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.internal.services;
+
+import java.lang.annotation.*;
+
+/**
+ * Special annotation that is applied to literal {@link org.apache.tapestry5.PropertyConduit}s, to inform {@link
+ * org.apache.tapestry5.internal.bindings.PropBinding} that the value is, in fact, invariant.
+ */
+@Target({ElementType.PARAMETER, ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Invariant
+{
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
new file mode 100644
index 0000000..1fffd4f
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
@@ -0,0 +1,85 @@
+// Copyright 2008, 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.internal.services;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import org.apache.tapestry5.internal.InternalPropertyConduit;
+import org.apache.tapestry5.ioc.AnnotationProvider;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
+
+/**
+ * A PropertyConduit for a literal value in an expression, such as a number, or "true", "false" or "null".
+ */
+public class LiteralPropertyConduit extends PropertyConduitDelegate implements InternalPropertyConduit
+{
+    private final Class propertyType;
+
+    private final AnnotationProvider annotationProvider;
+
+    private final String description;
+
+    private final Object value;
+
+    public LiteralPropertyConduit(TypeCoercer typeCoercer, Class propertyType, AnnotationProvider annotationProvider,
+            String description, Object value)
+    {
+        super(typeCoercer);
+
+        this.propertyType = propertyType;
+        this.annotationProvider = annotationProvider;
+        this.description = description;
+
+        this.value = value;
+    }
+
+    public Object get(Object instance)
+    {
+        return value;
+    }
+
+    public void set(Object instance, Object value)
+    {
+        throw new RuntimeException("Literal values are not updateable.");
+    }
+
+    public Class getPropertyType()
+    {
+        return propertyType;
+    }
+    
+    public Type getPropertyGenericType()
+    {
+    	return propertyType;
+    }
+
+    public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+    {
+        return annotationProvider.getAnnotation(annotationClass);
+    }
+
+    public String getPropertyName()
+    {
+        return null;
+    }
+
+    @Override
+    public String toString()
+    {
+        return description;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java
new file mode 100644
index 0000000..765c0bb
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java
@@ -0,0 +1,38 @@
+// 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.internal.services;
+
+/**
+ * Exception thrown when there is a problem parsing a property expression using the ANTLR property expression grammar.
+ */
+public class PropertyExpressionException extends RuntimeException
+{
+    private final String expression;
+
+    public PropertyExpressionException(String message, String expression, Throwable cause)
+    {
+        super(message, cause);
+
+        this.expression = expression;
+    }
+
+    /**
+     * Returns the property expression containing the error.
+     */
+    public String getExpression()
+    {
+        return expression;
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/commons/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java b/commons/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java
new file mode 100644
index 0000000..78ee5f4
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java
@@ -0,0 +1,43 @@
+// Copyright 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.internal.services;
+
+/**
+ * Creates "interned" strings that are unique for the same content. This is used for common description strings,
+ * particularly those used by {@link org.apache.tapestry5.Binding} instances.  The internal cache of interned strings id
+ * cleared whenever the {@link org.apache.tapestry5.services.ComponentClasses} {@link
+ * org.apache.tapestry5.services.InvalidationEventHub} is invalidated (i.e., when component class files change).
+ *
+ * @since 5.1.0.0
+ */
+public interface StringInterner
+{
+    /**
+     * Interns a string.
+     *
+     * @param string the string to intern
+     * @return the input string, or another string instance with the same content
+     */
+    String intern(String string);
+
+    /**
+     * Formats a string (using {@link String#format(String, Object[])}) and returns the interned result.
+     *
+     * @param format    string format
+     * @param arguments used inside the format
+     * @return formatted and interned string
+     */
+    String format(String format, Object... arguments);
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/commons/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java b/commons/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java
new file mode 100644
index 0000000..e7990fc
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java
@@ -0,0 +1,27 @@
+// Copyright 2006, 2008, 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;
+
+/**
+ * Interface used to encapsulate any strategy used defer the creation of some object until just as needed.
+ */
+public interface ObjectCreator<T>
+{
+    /**
+     * Create and return the object. In some limited circumstances, the implementation may cache the result, returning
+     * the same object for repeated calls.
+     */
+    T createObject();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/commons/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java b/commons/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
new file mode 100644
index 0000000..75e93e4
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
@@ -0,0 +1,159 @@
+// 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.services;
+
+import org.apache.tapestry5.ioc.Location;
+import org.apache.tapestry5.ioc.ObjectCreator;
+import org.apache.tapestry5.ioc.annotations.IncompatibleChange;
+import org.apache.tapestry5.plastic.ClassInstantiator;
+import org.apache.tapestry5.plastic.PlasticClassListenerHub;
+import org.apache.tapestry5.plastic.PlasticClassTransformation;
+import org.apache.tapestry5.plastic.PlasticClassTransformer;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+/**
+ * A service used to create proxies of varying types. As a secondary concern, manages to identify the
+ * location of methods and constructors, which is important for exception reporting.
+ *
+ * @since 5.3
+ */
+public interface PlasticProxyFactory extends PlasticClassListenerHub
+{
+    /**
+     * Returns the class loader used when creating new classes, this is a child class loader
+     * of another class loader (usually, the thread's context class loader).
+     */
+    ClassLoader getClassLoader();
+
+    /**
+     * Creates a proxy object that implements the indicated interface, then invokes the callback to further
+     * configure the proxy.
+     *
+     * @param interfaceType
+     *         interface implemented by proxy
+     * @param callback
+     *         configures the proxy
+     * @return instantiator that can be used to create an instance of the proxy class
+     */
+    <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, PlasticClassTransformer callback);
+
+    /**
+     * Creates a proxy object that implements the indicated interface and indicated service implementation type,
+     * then invokes the callback to further configure the proxy.
+     *
+     * @param interfaceType
+     *         interface implemented by proxy
+     * @param implementationType
+     *         a class that implements the interfaceType. It can be null.
+     * @param callback
+     *         configures the proxy
+     * @return instantiator that can be used to create an instance of the proxy class
+     */
+    @IncompatibleChange(release = "5.4", details = "TAP5-2029")
+    <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, Class<? extends T> implementationType, PlasticClassTransformer callback);
+
+    /**
+     * Creates the underlying {@link PlasticClassTransformation} for an interface proxy. This should only be
+     * used in the cases where encapsulating the PlasticClass construction into a {@linkplain PlasticClassTransformer
+     * callback} is not feasible (which is the case for some of the older APIs inside Tapestry IoC).
+     *
+     * @param interfaceType
+     *         class proxy will extend from
+     * @return transformation from which an instantiator may be created
+     */
+    <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType);
+
+    /**
+     * Creates the underlying {@link PlasticClassTransformation} for an interface proxy with a given
+     * implementation class. This should only be
+     * used in the cases where encapsulating the PlasticClass construction into a {@linkplain PlasticClassTransformer
+     * callback} is not feasible (which is the case for some of the older APIs inside Tapestry IoC).
+     *
+     * @param interfaceType
+     *         class proxy will extend from
+     * @param implementationType
+     *         a class that implements the interfaceType. It can be null.
+     * @return transformation from which an instantiator may be created
+     */
+    @IncompatibleChange(release = "5.4", details = "TAP5-2029")
+    <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType, Class<? extends T> implementationType);
+
+    /**
+     * Creates a proxy instance that delegates all methods through a corresponding
+     * ObjectCreator. Each method invocation on the proxy will route through {@link ObjectCreator#createObject()} (the
+     * creator implementation may decide to
+     * cache the return value as appropriate).
+     *
+     * @param <T>
+     *         type of proxy
+     * @param interfaceType
+     *         interface class for proxy
+     * @param creator
+     *         object responsible for creating the real object
+     * @param description
+     *         the <code>toString()</code> of the proxy
+     * @return proxy instance
+     */
+    <T> T createProxy(Class<T> interfaceType, ObjectCreator<T> creator, String description);
+    
+    /**
+     * Creates a proxy instance that delegates all methods through a corresponding
+     * ObjectCreator. Each method invocation on the proxy will route through {@link ObjectCreator#createObject()} (the
+     * creator implementation may decide to
+     * cache the return value as appropriate).
+     *
+     * @param <T>
+     *         type of proxy
+     * @param interfaceType
+     *         interface class for proxy
+     * @param implementationType
+     *         class that implements the interface type. It may be null
+     * @param creator
+     *         object responsible for creating the real object
+     * @param description
+     *         the <code>toString()</code> of the proxy
+     * @return proxy instance
+     */
+    @IncompatibleChange(release = "5.4", details = "Added for TAP5-2029")
+    <T> T createProxy(Class<T> interfaceType, Class<? extends T> implementationType, ObjectCreator<T> creator, String description);
+
+    /**
+     * Converts a method to a {@link Location}, which includes information about the source file name and line number.
+     *
+     * @param method
+     *         to look up
+     * @return the location (identifying the method and possibly, the line number within the method)
+     */
+    Location getMethodLocation(Method method);
+
+    /**
+     * Return a string representation for the constructor (including class and parameters) and (if available) file name
+     * and line number.
+     *
+     * @return the location (identifying the constructor and possibly, the line number within the method)
+     */
+    Location getConstructorLocation(Constructor constructor);
+
+    /**
+     * Clears any cached information stored by the proxy factory; this is useful in Tapestry development mode
+     * when a class loader may have been discarded (because the proxy factory may indirectly keep references
+     * to classes loaded by the old class loader).
+     *
+     * @since 5.3.3
+     */
+    void clearCache();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/commons/src/main/java/org/apache/tapestry5/ioc/util/Stack.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/Stack.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/Stack.java
new file mode 100644
index 0000000..cfa13a0
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/Stack.java
@@ -0,0 +1,173 @@
+// Copyright 2007, 2008, 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.util;
+
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+
+/**
+ * A simple, streamlined implementation of {@link java.util.Stack}. The implementation is <em>not</em> threadsafe.
+ *
+ * @param <E> the type of elements stored in the map
+ * @see CollectionFactory#newStack()
+ */
+public class Stack<E>
+{
+    private static final int MINIMUM_SIZE = 3;
+
+    private static final int DEFAULT_ARRAY_SIZE = 20;
+
+    private Object[] items;
+
+    private int index = -1;
+
+    /**
+     * Normal constructor supporting an initial size of 20.
+     */
+    public Stack()
+    {
+        this(DEFAULT_ARRAY_SIZE);
+    }
+
+    /**
+     * @param initialSize the initial size of the internal array (which will be expanded as necessary). For best
+     *                    efficiency, set this to the maximum depth of the stack.
+     */
+    public Stack(int initialSize)
+    {
+        items = new Object[Math.max(initialSize, MINIMUM_SIZE)];
+    }
+
+    /**
+     * Returns true if the stack is empty.
+     */
+    public boolean isEmpty()
+    {
+        return index < 0;
+    }
+
+    /**
+     * Returns the number of items currently in the stack.
+     */
+    public int getDepth()
+    {
+        return index + 1;
+    }
+
+    /**
+     * Clears the stack, the same as popping off all elements.
+     */
+    public void clear()
+    {
+        for (int i = 0; i <= index; i++) items[i] = null;
+
+        index = -1;
+    }
+
+    /**
+     * Pushes a new item onto the stack.
+     */
+    public void push(E item)
+    {
+        index++;
+
+        if (index == items.length)
+        {
+            int newCapacity = (items.length * 3) / 2 + 1;
+            Object[] newItems = new Object[newCapacity];
+            System.arraycopy(items, 0, newItems, 0, items.length);
+
+            items = newItems;
+        }
+
+        items[index] = item;
+    }
+
+    /**
+     * Pops the top element off the stack and returns it.
+     *
+     * @return the top element of the stack
+     * @throws IllegalStateException if the stack is empty
+     */
+    @SuppressWarnings("unchecked")
+    public E pop()
+    {
+        checkIfEmpty();
+
+        Object result = items[index];
+
+        items[index] = null;
+
+        index--;
+
+        return (E) result;
+    }
+
+    private void checkIfEmpty()
+    {
+        if (index < 0) throw new IllegalStateException("Stack is empty.");
+    }
+
+    /**
+     * Returns the top element of the stack without affecting the stack.
+     *
+     * @return top element on the stack
+     * @throws IllegalStateException if the stack is empty
+     */
+    @SuppressWarnings("unchecked")
+    public E peek()
+    {
+        checkIfEmpty();
+
+        return (E) items[index];
+    }
+
+    /**
+     * Describes the stack, listing the element in order of depth (top element first).
+     *
+     * @return string description of the stack
+     */
+    @Override
+    public String toString()
+    {
+        StringBuilder builder = new StringBuilder("Stack[");
+
+        for (int i = index; i >= 0; i--)
+        {
+            if (i != index) builder.append(", ");
+
+            builder.append(String.valueOf(items[i]));
+        }
+
+        builder.append("]");
+
+        return builder.toString();
+    }
+
+    /**
+     * Returns a snapshot of the current state of the stack as an array of objects. The first object is the deepest in
+     * the stack, the last object is the most shallowest (most recently pushed onto the stack).  The returned array may
+     * be manipulated (it is a copy).
+     *
+     * @return the stack as an object array
+     */
+    public Object[] getSnapshot()
+    {
+        Object[] result = new Object[index + 1];
+
+        System.arraycopy(items, 0, result, 0, index + 1);
+
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g b/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g
deleted file mode 100644
index 3b52ba9..0000000
--- a/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g
+++ /dev/null
@@ -1,163 +0,0 @@
-// Copyright 2008, 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.
-
-lexer grammar PropertyExpressionLexer;
-
-
-options
-{
-  superClass='org.apache.tapestry5.internal.antlr.BaseLexer';
-}
-
-@header
-{
-package org.apache.tapestry5.internal.antlr;
-}
-
-	
-// Integer constant
-fragment INTEGER
-	:	{this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};	
-	
-// Read a property or invoke a method.
-fragment DEREF 
-	:	{this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};	
-	
-// Range operator, ".." between two integers.	
-fragment RANGEOP
-	:	{this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};	
-	
-// Decimal number	
-fragment DECIMAL
-	:	{this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};	
-			
-fragment LETTER 
-	:	('a'..'z'|'A'..'Z');
-fragment DIGIT 
-	:	'0'..'9';	
-fragment SIGN
-	:	('+'|'-');
-LPAREN 	:	'(';
-RPAREN 	:	')';
-LBRACKET:	'[';
-RBRACKET:	']';
-COMMA	:	',';
-BANG	:	'!';
-LBRACE	:	'{';
-RBRACE	:	'}';
-COLON	:	':';
-
-fragment QUOTE
-	:	'\'';
-
-// Clumsy but effective approach to case-insensitive identifiers.
-
-fragment A
-	:	('a' | 'A');
-fragment E
-	:	('e' | 'E');
-fragment F
-	:	('f' | 'F');	
-fragment H
-	:	('h' | 'H');
-fragment I
-	:	('i' | 'I');
-fragment L 
-	: 	('l' | 'L');
-fragment N 
-	:	('n'|'N');
-fragment R
-	:	('r' | 'R');
-fragment S
-	:	('s' | 'S');
-fragment T 
-	:	('t' | 'T');
-fragment U 
-	:	('u' | 'U');
-
-// Identifiers are case insensitive
-
-NULL 	:	N U L L;
-TRUE	:	T R U E;
-FALSE	:	F A L S E;
-THIS	:	T H I S;
-
-IDENTIFIER 
-    :   JAVA_ID_START (JAVA_ID_PART)*
-    ;
-
-fragment
-JAVA_ID_START
-    :  '\u0024'
-    |  '\u0041'..'\u005a'
-    |  '\u005f'
-    |  '\u0061'..'\u007a'
-    |  '\u00c0'..'\u00d6'
-    |  '\u00d8'..'\u00f6'
-    |  '\u00f8'..'\u00ff'
-    |  '\u0100'..'\u1fff'
-    |  '\u3040'..'\u318f'
-    |  '\u3300'..'\u337f'
-    |  '\u3400'..'\u3d2d'
-    |  '\u4e00'..'\u9fff'
-    |  '\uf900'..'\ufaff'
-    ;
-
-fragment
-JAVA_ID_PART
-    :  JAVA_ID_START
-    |  '\u0030'..'\u0039'
-    ;
-
-
-// The Safe Dereference operator understands not to de-reference through
-// a null.
-
-SAFEDEREF 
-	: 	'?.';
-
-WS 	:	(' '|'\t'|'\n'|'\r')+ { skip(); };
-
-
-// Literal strings are always inside single quotes.
-STRING
-	:	QUOTE (options {greedy=false;} : .)* QUOTE { setText(getText().substring(1, getText().length()-1)); };
-
-
-// Special rule that uses parsing tricks to identify numbers and ranges; it's all about
-// the dot ('.').
-// Recognizes:
-// '.' as DEREF
-// '..' as RANGEOP
-// INTEGER (sign? digit+)
-// DECIMAL (sign? digits* . digits+)
-// Has to watch out for embedded rangeop (i.e. "1..10" is not "1." and ".10").
-
-NUMBER_OR_RANGEOP
-	:	SIGN? DIGIT+
-		(
-			{ input.LA(2) != '.' }? => '.' DIGIT* {   $type = DECIMAL; stripLeadingPlus(); }
-			| {  $type = INTEGER;  stripLeadingPlus(); }
-		)
-		
-	|	SIGN '.' DIGIT+ {  $type = DECIMAL;  stripLeadingPlus(); }
-	
-	|	'.'
-		( 
-			DIGIT+ { $type = DECIMAL; stripLeadingPlus();}
-			| '.' {$type = RANGEOP; }
-			| {$type = DEREF; }
-		)
-	;	
-

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g b/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g
deleted file mode 100644
index 14753e6..0000000
--- a/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright 2008, 2009, 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.
-
-parser grammar PropertyExpressionParser;
-
-
-options
-{
-  superClass='org.apache.tapestry5.internal.antlr.BaseParser';
-  output=AST;		
-  ASTLabelType=CommonTree;
-  tokenVocab=PropertyExpressionLexer;
-  backtrack=true;
-}
-
-tokens
-{	
-	// Parser token representing a method invocation
-    	INVOKE;
-    	// A List (top level, or as method parameter)
-    	LIST;
-		//A Map (top level, or as method parameter)
-		MAP;
-    	// Not operation (invert a boolean)
-    	NOT;
-}
-
-@header
-{
-package org.apache.tapestry5.internal.antlr;
-}
-
-	
-start 	:	expression^ EOF!;
-		
-expression
-	:	keyword
-	|	rangeOp
-	|	constant
-	|	propertyChain
-	|	list
-	|	notOp
-	|	map
-	;
-
-keyword	:	NULL | TRUE | FALSE | THIS;
-
-constant:	INTEGER| DECIMAL | STRING;	
-	
-propertyChain
-	:	term DEREF propertyChain -> ^(DEREF term propertyChain)
-	|	term SAFEDEREF propertyChain -> ^(SAFEDEREF term propertyChain)
-	|	term
-	;	
-	
-term	:	IDENTIFIER
-	|	methodInvocation
-	;
-	
-methodInvocation
-	:	id=IDENTIFIER LPAREN RPAREN -> ^(INVOKE $id)
-	|	id=IDENTIFIER LPAREN expressionList RPAREN -> ^(INVOKE $id expressionList)
-	;	
-	
-expressionList
-	:	expression (COMMA! expression)*
-	;	
-
-rangeOp
-	:	from=rangeopArg  RANGEOP to=rangeopArg -> ^(RANGEOP $from $to)
-	;	
-	
-rangeopArg 
-	:	INTEGER
-	|	propertyChain
-	;	
-	
-list	:	LBRACKET RBRACKET -> ^(LIST)
-	|	LBRACKET expressionList RBRACKET -> ^(LIST expressionList)
-	;	
-	
-notOp 	:	BANG expression -> ^(NOT expression)
-	;
-
-map 	:	LBRACE RBRACE -> ^(MAP)
-	|	LBRACE mapEntryList RBRACE -> ^(MAP mapEntryList)
-    ;
-	
-mapEntryList : mapEntry (COMMA! mapEntry)*;
-
-mapEntry :  mapKey COLON! expression;
-	
-mapKey :	keyword | constant | propertyChain;
-	

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java
deleted file mode 100644
index 442240d..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 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.internal.antlr;
-
-import org.antlr.runtime.CharStream;
-import org.antlr.runtime.Lexer;
-import org.antlr.runtime.RecognizerSharedState;
-import org.antlr.runtime.RecognitionException;
-
-public abstract class BaseLexer extends Lexer
-{
-    protected BaseLexer()
-    {
-    }
-
-    protected BaseLexer(CharStream charStream,
-                        RecognizerSharedState recognizerSharedState)
-    {
-        super(charStream, recognizerSharedState);
-    }
-
-    protected void stripLeadingPlus()
-    {
-        String text = getText();
-
-        // For compatibility with Tapestry 5.0, we need to allow a sign of '+', which Long.parseLong()
-        // doesn't accept. To keep things downstream simple, we eliminate the '+' here.
-
-        if (text.startsWith("+"))
-        {
-            setText(text.substring(1));
-        }
-    }
-
-    @Override
-    public void reportError(RecognitionException e)
-    {
-        throw new RuntimeException(String.format("Unable to parse input at character position %d",
-                                                 e.charPositionInLine + 1),
-                                   e);
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java
deleted file mode 100644
index 212b782..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 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.internal.antlr;
-
-import org.antlr.runtime.Parser;
-import org.antlr.runtime.TokenStream;
-import org.antlr.runtime.RecognizerSharedState;
-
-public class BaseParser extends Parser
-{
-    public BaseParser(TokenStream tokenStream)
-    {
-        super(tokenStream);
-    }
-
-    public BaseParser(TokenStream tokenStream,
-                      RecognizerSharedState recognizerSharedState)
-    {
-        super(tokenStream, recognizerSharedState);
-    }
-
-    @Override
-    public void emitErrorMessage(String message)
-    {
-        // This is caught and more properly reported later.
-        throw new RuntimeException(message);
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java
deleted file mode 100644
index 55be313..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 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.
-
-/**
- * [INTERNAL USE ONLY] support classes related to Antlr; API subject to change
- */
-package org.apache.tapestry5.internal.antlr;

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/Invariant.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/Invariant.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/Invariant.java
deleted file mode 100644
index 924b570..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/Invariant.java
+++ /dev/null
@@ -1,28 +0,0 @@
-// 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.internal.services;
-
-import java.lang.annotation.*;
-
-/**
- * Special annotation that is applied to literal {@link org.apache.tapestry5.PropertyConduit}s, to inform {@link
- * org.apache.tapestry5.internal.bindings.PropBinding} that the value is, in fact, invariant.
- */
-@Target({ElementType.PARAMETER, ElementType.FIELD})
-@Retention(RetentionPolicy.RUNTIME)
-@Documented
-public @interface Invariant
-{
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
deleted file mode 100644
index 1fffd4f..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2008, 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.internal.services;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-
-import org.apache.tapestry5.internal.InternalPropertyConduit;
-import org.apache.tapestry5.ioc.AnnotationProvider;
-import org.apache.tapestry5.ioc.services.TypeCoercer;
-
-/**
- * A PropertyConduit for a literal value in an expression, such as a number, or "true", "false" or "null".
- */
-public class LiteralPropertyConduit extends PropertyConduitDelegate implements InternalPropertyConduit
-{
-    private final Class propertyType;
-
-    private final AnnotationProvider annotationProvider;
-
-    private final String description;
-
-    private final Object value;
-
-    public LiteralPropertyConduit(TypeCoercer typeCoercer, Class propertyType, AnnotationProvider annotationProvider,
-            String description, Object value)
-    {
-        super(typeCoercer);
-
-        this.propertyType = propertyType;
-        this.annotationProvider = annotationProvider;
-        this.description = description;
-
-        this.value = value;
-    }
-
-    public Object get(Object instance)
-    {
-        return value;
-    }
-
-    public void set(Object instance, Object value)
-    {
-        throw new RuntimeException("Literal values are not updateable.");
-    }
-
-    public Class getPropertyType()
-    {
-        return propertyType;
-    }
-    
-    public Type getPropertyGenericType()
-    {
-    	return propertyType;
-    }
-
-    public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
-    {
-        return annotationProvider.getAnnotation(annotationClass);
-    }
-
-    public String getPropertyName()
-    {
-        return null;
-    }
-
-    @Override
-    public String toString()
-    {
-        return description;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java
deleted file mode 100644
index 765c0bb..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java
+++ /dev/null
@@ -1,38 +0,0 @@
-// 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.internal.services;
-
-/**
- * Exception thrown when there is a problem parsing a property expression using the ANTLR property expression grammar.
- */
-public class PropertyExpressionException extends RuntimeException
-{
-    private final String expression;
-
-    public PropertyExpressionException(String message, String expression, Throwable cause)
-    {
-        super(message, cause);
-
-        this.expression = expression;
-    }
-
-    /**
-     * Returns the property expression containing the error.
-     */
-    public String getExpression()
-    {
-        return expression;
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java
deleted file mode 100644
index 78ee5f4..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 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.internal.services;
-
-/**
- * Creates "interned" strings that are unique for the same content. This is used for common description strings,
- * particularly those used by {@link org.apache.tapestry5.Binding} instances.  The internal cache of interned strings id
- * cleared whenever the {@link org.apache.tapestry5.services.ComponentClasses} {@link
- * org.apache.tapestry5.services.InvalidationEventHub} is invalidated (i.e., when component class files change).
- *
- * @since 5.1.0.0
- */
-public interface StringInterner
-{
-    /**
-     * Interns a string.
-     *
-     * @param string the string to intern
-     * @return the input string, or another string instance with the same content
-     */
-    String intern(String string);
-
-    /**
-     * Formats a string (using {@link String#format(String, Object[])}) and returns the interned result.
-     *
-     * @param format    string format
-     * @param arguments used inside the format
-     * @return formatted and interned string
-     */
-    String format(String format, Object... arguments);
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java
deleted file mode 100644
index e7990fc..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2006, 2008, 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;
-
-/**
- * Interface used to encapsulate any strategy used defer the creation of some object until just as needed.
- */
-public interface ObjectCreator<T>
-{
-    /**
-     * Create and return the object. In some limited circumstances, the implementation may cache the result, returning
-     * the same object for repeated calls.
-     */
-    T createObject();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java
deleted file mode 100644
index ffc9490..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java
+++ /dev/null
@@ -1,33 +0,0 @@
-// 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.annotations;
-
-import java.lang.annotation.*;
-
-@Target({ElementType.METHOD, ElementType.FIELD})
-@Retention(RetentionPolicy.CLASS)
-@Documented
-public @interface IncompatibleChange
-{
-    /**
-     * Identifies the release in which the signature of the method was modified.
-     *
-     * @return a release number, e.g., "5.4"
-     */
-    String release();
-
-    /**
-     * Short string describing what changed.
-     */
-    String details();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
deleted file mode 100644
index 75e93e4..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
+++ /dev/null
@@ -1,159 +0,0 @@
-// 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.services;
-
-import org.apache.tapestry5.ioc.Location;
-import org.apache.tapestry5.ioc.ObjectCreator;
-import org.apache.tapestry5.ioc.annotations.IncompatibleChange;
-import org.apache.tapestry5.plastic.ClassInstantiator;
-import org.apache.tapestry5.plastic.PlasticClassListenerHub;
-import org.apache.tapestry5.plastic.PlasticClassTransformation;
-import org.apache.tapestry5.plastic.PlasticClassTransformer;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-
-/**
- * A service used to create proxies of varying types. As a secondary concern, manages to identify the
- * location of methods and constructors, which is important for exception reporting.
- *
- * @since 5.3
- */
-public interface PlasticProxyFactory extends PlasticClassListenerHub
-{
-    /**
-     * Returns the class loader used when creating new classes, this is a child class loader
-     * of another class loader (usually, the thread's context class loader).
-     */
-    ClassLoader getClassLoader();
-
-    /**
-     * Creates a proxy object that implements the indicated interface, then invokes the callback to further
-     * configure the proxy.
-     *
-     * @param interfaceType
-     *         interface implemented by proxy
-     * @param callback
-     *         configures the proxy
-     * @return instantiator that can be used to create an instance of the proxy class
-     */
-    <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, PlasticClassTransformer callback);
-
-    /**
-     * Creates a proxy object that implements the indicated interface and indicated service implementation type,
-     * then invokes the callback to further configure the proxy.
-     *
-     * @param interfaceType
-     *         interface implemented by proxy
-     * @param implementationType
-     *         a class that implements the interfaceType. It can be null.
-     * @param callback
-     *         configures the proxy
-     * @return instantiator that can be used to create an instance of the proxy class
-     */
-    @IncompatibleChange(release = "5.4", details = "TAP5-2029")
-    <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, Class<? extends T> implementationType, PlasticClassTransformer callback);
-
-    /**
-     * Creates the underlying {@link PlasticClassTransformation} for an interface proxy. This should only be
-     * used in the cases where encapsulating the PlasticClass construction into a {@linkplain PlasticClassTransformer
-     * callback} is not feasible (which is the case for some of the older APIs inside Tapestry IoC).
-     *
-     * @param interfaceType
-     *         class proxy will extend from
-     * @return transformation from which an instantiator may be created
-     */
-    <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType);
-
-    /**
-     * Creates the underlying {@link PlasticClassTransformation} for an interface proxy with a given
-     * implementation class. This should only be
-     * used in the cases where encapsulating the PlasticClass construction into a {@linkplain PlasticClassTransformer
-     * callback} is not feasible (which is the case for some of the older APIs inside Tapestry IoC).
-     *
-     * @param interfaceType
-     *         class proxy will extend from
-     * @param implementationType
-     *         a class that implements the interfaceType. It can be null.
-     * @return transformation from which an instantiator may be created
-     */
-    @IncompatibleChange(release = "5.4", details = "TAP5-2029")
-    <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType, Class<? extends T> implementationType);
-
-    /**
-     * Creates a proxy instance that delegates all methods through a corresponding
-     * ObjectCreator. Each method invocation on the proxy will route through {@link ObjectCreator#createObject()} (the
-     * creator implementation may decide to
-     * cache the return value as appropriate).
-     *
-     * @param <T>
-     *         type of proxy
-     * @param interfaceType
-     *         interface class for proxy
-     * @param creator
-     *         object responsible for creating the real object
-     * @param description
-     *         the <code>toString()</code> of the proxy
-     * @return proxy instance
-     */
-    <T> T createProxy(Class<T> interfaceType, ObjectCreator<T> creator, String description);
-    
-    /**
-     * Creates a proxy instance that delegates all methods through a corresponding
-     * ObjectCreator. Each method invocation on the proxy will route through {@link ObjectCreator#createObject()} (the
-     * creator implementation may decide to
-     * cache the return value as appropriate).
-     *
-     * @param <T>
-     *         type of proxy
-     * @param interfaceType
-     *         interface class for proxy
-     * @param implementationType
-     *         class that implements the interface type. It may be null
-     * @param creator
-     *         object responsible for creating the real object
-     * @param description
-     *         the <code>toString()</code> of the proxy
-     * @return proxy instance
-     */
-    @IncompatibleChange(release = "5.4", details = "Added for TAP5-2029")
-    <T> T createProxy(Class<T> interfaceType, Class<? extends T> implementationType, ObjectCreator<T> creator, String description);
-
-    /**
-     * Converts a method to a {@link Location}, which includes information about the source file name and line number.
-     *
-     * @param method
-     *         to look up
-     * @return the location (identifying the method and possibly, the line number within the method)
-     */
-    Location getMethodLocation(Method method);
-
-    /**
-     * Return a string representation for the constructor (including class and parameters) and (if available) file name
-     * and line number.
-     *
-     * @return the location (identifying the constructor and possibly, the line number within the method)
-     */
-    Location getConstructorLocation(Constructor constructor);
-
-    /**
-     * Clears any cached information stored by the proxy factory; this is useful in Tapestry development mode
-     * when a class loader may have been discarded (because the proxy factory may indirectly keep references
-     * to classes loaded by the old class loader).
-     *
-     * @since 5.3.3
-     */
-    void clearCache();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/Stack.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/Stack.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/Stack.java
deleted file mode 100644
index cfa13a0..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/Stack.java
+++ /dev/null
@@ -1,173 +0,0 @@
-// Copyright 2007, 2008, 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.util;
-
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-
-/**
- * A simple, streamlined implementation of {@link java.util.Stack}. The implementation is <em>not</em> threadsafe.
- *
- * @param <E> the type of elements stored in the map
- * @see CollectionFactory#newStack()
- */
-public class Stack<E>
-{
-    private static final int MINIMUM_SIZE = 3;
-
-    private static final int DEFAULT_ARRAY_SIZE = 20;
-
-    private Object[] items;
-
-    private int index = -1;
-
-    /**
-     * Normal constructor supporting an initial size of 20.
-     */
-    public Stack()
-    {
-        this(DEFAULT_ARRAY_SIZE);
-    }
-
-    /**
-     * @param initialSize the initial size of the internal array (which will be expanded as necessary). For best
-     *                    efficiency, set this to the maximum depth of the stack.
-     */
-    public Stack(int initialSize)
-    {
-        items = new Object[Math.max(initialSize, MINIMUM_SIZE)];
-    }
-
-    /**
-     * Returns true if the stack is empty.
-     */
-    public boolean isEmpty()
-    {
-        return index < 0;
-    }
-
-    /**
-     * Returns the number of items currently in the stack.
-     */
-    public int getDepth()
-    {
-        return index + 1;
-    }
-
-    /**
-     * Clears the stack, the same as popping off all elements.
-     */
-    public void clear()
-    {
-        for (int i = 0; i <= index; i++) items[i] = null;
-
-        index = -1;
-    }
-
-    /**
-     * Pushes a new item onto the stack.
-     */
-    public void push(E item)
-    {
-        index++;
-
-        if (index == items.length)
-        {
-            int newCapacity = (items.length * 3) / 2 + 1;
-            Object[] newItems = new Object[newCapacity];
-            System.arraycopy(items, 0, newItems, 0, items.length);
-
-            items = newItems;
-        }
-
-        items[index] = item;
-    }
-
-    /**
-     * Pops the top element off the stack and returns it.
-     *
-     * @return the top element of the stack
-     * @throws IllegalStateException if the stack is empty
-     */
-    @SuppressWarnings("unchecked")
-    public E pop()
-    {
-        checkIfEmpty();
-
-        Object result = items[index];
-
-        items[index] = null;
-
-        index--;
-
-        return (E) result;
-    }
-
-    private void checkIfEmpty()
-    {
-        if (index < 0) throw new IllegalStateException("Stack is empty.");
-    }
-
-    /**
-     * Returns the top element of the stack without affecting the stack.
-     *
-     * @return top element on the stack
-     * @throws IllegalStateException if the stack is empty
-     */
-    @SuppressWarnings("unchecked")
-    public E peek()
-    {
-        checkIfEmpty();
-
-        return (E) items[index];
-    }
-
-    /**
-     * Describes the stack, listing the element in order of depth (top element first).
-     *
-     * @return string description of the stack
-     */
-    @Override
-    public String toString()
-    {
-        StringBuilder builder = new StringBuilder("Stack[");
-
-        for (int i = index; i >= 0; i--)
-        {
-            if (i != index) builder.append(", ");
-
-            builder.append(String.valueOf(items[i]));
-        }
-
-        builder.append("]");
-
-        return builder.toString();
-    }
-
-    /**
-     * Returns a snapshot of the current state of the stack as an array of objects. The first object is the deepest in
-     * the stack, the last object is the most shallowest (most recently pushed onto the stack).  The returned array may
-     * be manipulated (it is a copy).
-     *
-     * @return the stack as an object array
-     */
-    public Object[] getSnapshot()
-    {
-        Object[] result = new Object[index + 1];
-
-        System.arraycopy(items, 0, result, 0, index + 1);
-
-        return result;
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java
----------------------------------------------------------------------
diff --git a/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java b/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java
new file mode 100644
index 0000000..ffc9490
--- /dev/null
+++ b/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java
@@ -0,0 +1,33 @@
+// 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.annotations;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.METHOD, ElementType.FIELD})
+@Retention(RetentionPolicy.CLASS)
+@Documented
+public @interface IncompatibleChange
+{
+    /**
+     * Identifies the release in which the signature of the method was modified.
+     *
+     * @return a release number, e.g., "5.4"
+     */
+    String release();
+
+    /**
+     * Short string describing what changed.
+     */
+    String details();
+}


[15/15] tapestry-5 git commit: Fifth pass creating the BeanModel and Commons packages. Initial testing looks good.

Posted by th...@apache.org.
Fifth pass creating the BeanModel and Commons packages. Initial testing looks good.


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

Branch: refs/heads/beanmodel-split
Commit: 696bc7ae848f4b4f2421ff77ceb4858a2f10465c
Parents: eb7ec86
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Sat Dec 6 20:29:20 2014 -0200
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Sat Dec 6 20:29:20 2014 -0200

----------------------------------------------------------------------
 .../org/apache/tapestry5/PropertyConduit2.java  |   2 +-
 .../beaneditor/BeanModelSourceBuilder.java      | 159 ++---
 .../CoercingPropertyConduitWrapper.java         |   8 +-
 .../services/LiteralPropertyConduit.java        |   2 +-
 .../services/PropertyConduitSourceImpl.java     |  46 +-
 .../services/ClassPropertyAdapterImpl.java      |  92 +--
 .../services/AnnotationDataTypeAnalyzer.java    |  32 +
 .../ioc/internal/BasicDataTypeAnalyzers.java    | 151 +++++
 .../ioc/internal/util/InternalCommonsUtils.java | 608 +++++++++----------
 .../internal/TapestryInternalUtils.java         |   4 +-
 .../internal/bindings/AbstractBinding.java      |   2 +-
 .../internal/bindings/PropBinding.java          |   8 +-
 .../services/AnnotationDataTypeAnalyzer.java    |  32 -
 .../InternalComponentResourcesImpl.java         |   4 +-
 .../tapestry5/modules/TapestryModule.java       |  14 +-
 .../app1/components/GenericTypeDisplay.java     |  34 +-
 .../integration/app1/pages/GenericTypeDemo.java |  24 +-
 .../pages/GridWithSubmitWithContextDemo.java    |   4 +-
 .../integration/app2/base/ChildBasePage.java    |   8 +-
 .../integration/app2/base/ParentBasePage.java   |   2 +-
 .../pagelevel/OverrideMethodsTest.java          |  14 +-
 .../services/PropertyConduitSourceImplTest.java |  34 +-
 .../org/apache/tapestry5/json/JSONArray.java    |   2 +-
 .../org/apache/tapestry5/json/JSONObject.java   |   2 +-
 24 files changed, 723 insertions(+), 565 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit2.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit2.java b/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit2.java
index 839d70f..1577a3d 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit2.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit2.java
@@ -36,5 +36,5 @@ public interface PropertyConduit2 extends PropertyConduit
      * @see java.lang.reflect.Field#getGenericType()
      * 
      */
-	Type getPropertyGenericType();
+    Type getPropertyGenericType();
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/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
index 8cef66e..4ac3373 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModelSourceBuilder.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModelSourceBuilder.java
@@ -15,15 +15,22 @@ package org.apache.tapestry5.beaneditor;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
 
 import javax.naming.OperationNotSupportedException;
+import javax.swing.JFrame;
 
 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.MessageFormatter;
+import org.apache.tapestry5.ioc.Messages;
 import org.apache.tapestry5.ioc.ObjectLocator;
+import org.apache.tapestry5.ioc.internal.BasicDataTypeAnalyzers;
 import org.apache.tapestry5.ioc.internal.BasicTypeCoercions;
 import org.apache.tapestry5.ioc.internal.services.PlasticProxyFactoryImpl;
 import org.apache.tapestry5.ioc.internal.services.PropertyAccessImpl;
@@ -31,6 +38,7 @@ 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.PropertyAdapter;
 import org.apache.tapestry5.ioc.services.TypeCoercer;
 import org.apache.tapestry5.services.BeanModelSource;
 import org.apache.tapestry5.services.DataTypeAnalyzer;
@@ -42,80 +50,89 @@ import org.slf4j.LoggerFactory;
  * 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;
-	}
+    private TypeCoercer typeCoercer;
+    private PropertyAccess propertyAccess;
+    private PropertyConduitSource propertyConduitSource;
+    private PlasticProxyFactory plasticProxyFactory;
+    private DataTypeAnalyzer dataTypeAnalyzer;
+    private ObjectLocator objectLocator;
+    private StringInterner stringInterner;
 
-	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);
-		
-	}
+    /**
+     * Sets the {@link TypeCoercer} to be used.
+     */
+    public BeanModelSourceBuilder setTypeCoercer(TypeCoercer typeCoercer)
+    {
+        this.typeCoercer = typeCoercer;
+        return this;
+    }
 
-	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>();
+    public BeanModelSource build() 
+    {
+        
+        if (typeCoercer == null) 
+        {
+            createTypeCoercer();
+        }
+        
+        if (propertyAccess == null)
+        {
+            propertyAccess = new PropertyAccessImpl();
+        }
+        
+        if (dataTypeAnalyzer == null)
+        {
+            dataTypeAnalyzer = BasicDataTypeAnalyzers.createDefaultDataTypeAnalyzer();
+        }
+        
+        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());
+    }
 
-		@Override
-		public void add(CoercionTuple tuble) {
-			tuples.add(tuble);
-		}
+    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;
+        }
+
+    }
 
-		@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/696bc7ae/beanmodel/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
index 4dbfb2d..2127696 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
@@ -50,10 +50,10 @@ public class CoercingPropertyConduitWrapper implements PropertyConduit2
     
     public Type getPropertyGenericType()
     {
-    	if (conduit instanceof PropertyConduit2) {
-    		return ((PropertyConduit2) conduit).getPropertyGenericType();
-    	}
-    	return conduit.getPropertyType();
+        if (conduit instanceof PropertyConduit2) {
+            return ((PropertyConduit2) conduit).getPropertyGenericType();
+        }
+        return conduit.getPropertyType();
     }
 
     @SuppressWarnings("unchecked")

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
index 1fffd4f..e8cd58f 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
@@ -63,7 +63,7 @@ public class LiteralPropertyConduit extends PropertyConduitDelegate implements I
     
     public Type getPropertyGenericType()
     {
-    	return propertyType;
+        return propertyType;
     }
 
     public <T extends Annotation> T getAnnotation(Class<T> annotationClass)

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/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 09d234c..9148b46 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
@@ -524,28 +524,28 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
 
         private Type getGenericType(PropertyAdapter adapter)
         {
-        	Type genericType = null;
-        	if (adapter.getField() != null)
-        	{
-        		genericType = adapter.getField().getGenericType();
-        	}
-        	else if (adapter.getReadMethod() != null)
-        	{
-        		genericType = adapter.getReadMethod().getGenericReturnType(); 
-        	}
-        	else if (adapter.getWriteMethod() != null)
-        	{
-        		genericType = adapter.getWriteMethod().getGenericParameterTypes()[0];
-        	}
-        	else
-        	{
-        		throw new RuntimeException("Could not find accessor for property " + adapter.getName());
-        	}
-        	
-        	return genericType == null ? adapter.getType() : genericType;
-		}
-
-		private void implementSetter(PropertyAdapter adapter)
+            Type genericType = null;
+            if (adapter.getField() != null)
+            {
+                genericType = adapter.getField().getGenericType();
+            }
+            else if (adapter.getReadMethod() != null)
+            {
+                genericType = adapter.getReadMethod().getGenericReturnType(); 
+            }
+            else if (adapter.getWriteMethod() != null)
+            {
+                genericType = adapter.getWriteMethod().getGenericParameterTypes()[0];
+            }
+            else
+            {
+                throw new RuntimeException("Could not find accessor for property " + adapter.getName());
+            }
+            
+            return genericType == null ? adapter.getType() : genericType;
+        }
+
+        private void implementSetter(PropertyAdapter adapter)
         {
             if (adapter.getWriteMethod() != null)
             {
@@ -1488,7 +1488,7 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
             
             public Type getPropertyGenericType()
             {
-            	return rootClass;
+                return rootClass;
             }
 
             public <T extends Annotation> T getAnnotation(Class<T> annotationClass)

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/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
index 5d6dfec..9c5f36c4 100644
--- 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
@@ -57,11 +57,11 @@ public class ClassPropertyAdapterImpl implements ClassPropertyAdapter
             // TAP5-1493
             if (readMethod != null && readMethod.isBridge())
             {
-            	if (nonBridgeMethods == null)
-            	{
-            		nonBridgeMethods = groupNonBridgeMethodsByName(beanType);
-            	}
-            	readMethod = findMethodWithSameNameAndParamCount(readMethod, nonBridgeMethods); 
+                if (nonBridgeMethods == null)
+                {
+                    nonBridgeMethods = groupNonBridgeMethodsByName(beanType);
+                }
+                readMethod = findMethodWithSameNameAndParamCount(readMethod, nonBridgeMethods); 
             }
             
             // TAP5-1548, TAP5-1885: trying to find a getter which Introspector missed
@@ -86,11 +86,11 @@ public class ClassPropertyAdapterImpl implements ClassPropertyAdapter
             
             if (writeMethod != null && writeMethod.isBridge())
             {
-            	if (nonBridgeMethods == null)
-            	{
-            		nonBridgeMethods = groupNonBridgeMethodsByName(beanType);
-            	}
-            	writeMethod = findMethodWithSameNameAndParamCount(writeMethod, nonBridgeMethods);
+                if (nonBridgeMethods == null)
+                {
+                    nonBridgeMethods = groupNonBridgeMethodsByName(beanType);
+                }
+                writeMethod = findMethodWithSameNameAndParamCount(writeMethod, nonBridgeMethods);
             }
             
             // TAP5-1548, TAP5-1885: trying to find a setter which Introspector missed
@@ -149,24 +149,24 @@ public class ClassPropertyAdapterImpl implements ClassPropertyAdapter
      *         (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;
-	}
-
-	/**
+        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
      * 
@@ -176,24 +176,24 @@ public class ClassPropertyAdapterImpl implements ClassPropertyAdapter
      */
     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
+        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;

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/commons/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java b/commons/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java
new file mode 100644
index 0000000..8b20666
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java
@@ -0,0 +1,32 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.services;
+
+import org.apache.tapestry5.beaneditor.DataType;
+import org.apache.tapestry5.ioc.services.PropertyAdapter;
+import org.apache.tapestry5.services.DataTypeAnalyzer;
+
+/**
+ * Checks for the {@link DataType} annotation, returning its value if present.
+ */
+public class AnnotationDataTypeAnalyzer implements DataTypeAnalyzer
+{
+    public String identifyDataType(PropertyAdapter adapter)
+    {
+        DataType annotation = adapter.getAnnotation(DataType.class);
+
+        return annotation == null ? null : annotation.value();
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/commons/src/main/java/org/apache/tapestry5/ioc/internal/BasicDataTypeAnalyzers.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/BasicDataTypeAnalyzers.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/BasicDataTypeAnalyzers.java
new file mode 100644
index 0000000..df7564f
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/BasicDataTypeAnalyzers.java
@@ -0,0 +1,151 @@
+// 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.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.tapestry5.beaneditor.DataTypeConstants;
+import org.apache.tapestry5.internal.services.AnnotationDataTypeAnalyzer;
+import org.apache.tapestry5.ioc.MappedConfiguration;
+import org.apache.tapestry5.ioc.OrderedConfiguration;
+import org.apache.tapestry5.ioc.services.PropertyAdapter;
+import org.apache.tapestry5.services.DataTypeAnalyzer;
+
+/**
+ * Class that provides Tapestry's basic default data type analyzers.
+ */
+public class BasicDataTypeAnalyzers
+{
+    
+    public static void contributeDataTypeAnalyzer(
+            OrderedConfiguration<DataTypeAnalyzer> configuration,
+            DataTypeAnalyzer defaultDataTypeAnalyzer) {
+        configuration.add("Annotation", new AnnotationDataTypeAnalyzer());
+        if (defaultDataTypeAnalyzer == null)
+        {
+            defaultDataTypeAnalyzer = createDefaultDataTypeAnalyzer();
+        }
+        configuration.add("Default", defaultDataTypeAnalyzer, "after:*");
+    }
+
+    public static DataTypeAnalyzer createDefaultDataTypeAnalyzer() 
+    {
+        DefaultDataTypeAnalyzerMappedConfiguration mappedConfiguration = new DefaultDataTypeAnalyzerMappedConfiguration();
+        provideDefaultDataTypeAnalyzers(mappedConfiguration);
+        return new CombinedDataTypeAnalyzer(new AnnotationDataTypeAnalyzer(), new MapDataTypeAnalyzer(mappedConfiguration.getMap()));
+    }
+    
+    /**
+     * Maps property types to data type names:
+     * <ul>
+     * <li>String --&gt; text
+     * <li>Number --&gt; number
+     * <li>Enum --&gt; enum
+     * <li>Boolean --&gt; boolean
+     * <li>Date --&gt; date
+     * </ul>
+     */
+    public static void provideDefaultDataTypeAnalyzers(MappedConfiguration<Class, String> configuration)
+    {
+        // This is a special case contributed to avoid exceptions when a
+        // property type can't be
+        // matched. DefaultDataTypeAnalyzer converts the empty string to null.
+
+        configuration.add(Object.class, "");
+
+        configuration.add(String.class, DataTypeConstants.TEXT);
+        configuration.add(Number.class, DataTypeConstants.NUMBER);
+        configuration.add(Enum.class, DataTypeConstants.ENUM);
+        configuration.add(Boolean.class, DataTypeConstants.BOOLEAN);
+        configuration.add(Date.class, DataTypeConstants.DATE);
+        configuration.add(Calendar.class, DataTypeConstants.CALENDAR);
+    }
+
+    final private static class DefaultDataTypeAnalyzerMappedConfiguration implements MappedConfiguration<Class, String> 
+    {
+        
+        final Map<Class, String> map = new HashMap<Class, String>();
+
+        @Override
+        public void add(Class key, String value) {
+            map.put(key, value);
+        }
+
+        @Override
+        public void override(Class key, String value) {
+            throw new RuntimeException("Not implemented");
+        }
+
+        @Override
+        public void addInstance(Class key, Class<? extends String> clazz) {
+            throw new RuntimeException("Not implemented");            
+        }
+
+        @Override
+        public void overrideInstance(Class key, Class<? extends String> clazz) {
+            throw new RuntimeException("Not implemented");
+        }
+
+        public Map<Class, String> getMap() {
+            return map;
+        }
+        
+    }
+    
+    final private static class MapDataTypeAnalyzer implements DataTypeAnalyzer
+    {
+        
+        final Map<Class, String> map;
+
+        public MapDataTypeAnalyzer(Map<Class, String> map) {
+            this.map = map;
+        }
+
+        @Override
+        public String identifyDataType(PropertyAdapter adapter) {
+            return map.get(adapter.getType());
+        }
+        
+    }
+    
+    final private static class CombinedDataTypeAnalyzer implements DataTypeAnalyzer 
+    {
+
+        final private DataTypeAnalyzer first, second;
+
+        public CombinedDataTypeAnalyzer(DataTypeAnalyzer first, DataTypeAnalyzer second) 
+        {
+            super();
+            this.first = first;
+            this.second = second;
+        }
+
+        @Override
+        public String identifyDataType(PropertyAdapter adapter) 
+        {
+            String type = first.identifyDataType(adapter);
+            if (type == null) 
+            {
+                type = second.identifyDataType(adapter);
+            }
+            return type;
+        }
+
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
index 3c391e0..2bc33d8 100644
--- a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
@@ -33,11 +33,11 @@ import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
  */
 public class InternalCommonsUtils {
 
-	/**
-	 * @since 5.3
-	 */
-	public final static AnnotationProvider NULL_ANNOTATION_PROVIDER = new NullAnnotationProvider();
-	private static final Pattern NON_WORD_PATTERN = Pattern.compile("[^\\w]");
+    /**
+     * @since 5.3
+     */
+    public final static AnnotationProvider NULL_ANNOTATION_PROVIDER = new NullAnnotationProvider();
+    private static final Pattern NON_WORD_PATTERN = Pattern.compile("[^\\w]");
 
     /**
      * Adds a value to a specially organized map where the values are lists of objects. This somewhat simulates a map
@@ -67,322 +67,322 @@ public class InternalCommonsUtils {
         list.add(value);
     }
 
-	/**
-	 * Sniffs the object to see if it is a {@link Location} or {@link Locatable}. Returns null if null or not
-	 * convertable to a location.
-	 */
-	
-	public static Location locationOf(Object location)
-	{
-	    if (location == null)
-	        return null;
-	
-	    if (location instanceof Location)
-	        return (Location) location;
-	
-	    if (location instanceof Locatable)
-	        return ((Locatable) location).getLocation();
-	
-	    return null;
-	}
+    /**
+     * Sniffs the object to see if it is a {@link Location} or {@link Locatable}. Returns null if null or not
+     * convertable to a location.
+     */
+    
+    public static Location locationOf(Object location)
+    {
+        if (location == null)
+            return null;
+    
+        if (location instanceof Location)
+            return (Location) location;
+    
+        if (location instanceof Locatable)
+            return ((Locatable) location).getLocation();
+    
+        return null;
+    }
 
-	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);
-	        }
-	    };
-	}
+    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);
+            }
+        };
+    }
 
-	/**
-	 * 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, "");
-	}
+    /**
+     * 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);
-	}
+    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(InternalCommonsUtils.lastTerm(propertyExpression)));
-	}
+    /**
+     * 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(InternalCommonsUtils.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();
-	}
+    /**
+     * 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));
-	        }
-	    };
-	}
+    /**
+     * @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));
+            }
+        };
+    }
 
-	/**
-	 * Pattern used to eliminate leading and trailing underscores and dollar signs.
-	 */
-	static final Pattern NAME_PATTERN = Pattern.compile("^[_|$]*([\\p{javaJavaIdentifierPart}]+?)[_|$]*$",
-	        Pattern.CASE_INSENSITIVE);
+    /**
+     * Pattern used to eliminate leading and trailing underscores and dollar signs.
+     */
+    static final Pattern NAME_PATTERN = Pattern.compile("^[_|$]*([\\p{javaJavaIdentifierPart}]+?)[_|$]*$",
+            Pattern.CASE_INSENSITIVE);
 
-	/**
-	 * Converts a method to a user presentable string consisting of the containing class name, the method name, and the
-	 * short form of the parameter list (the class name of each parameter type, shorn of the package name portion).
-	 *
-	 * @param method
-	 * @return short string representation
-	 */
-	public static String asString(Method method)
-	{
-	    StringBuilder buffer = new StringBuilder();
-	
-	    buffer.append(method.getDeclaringClass().getName());
-	    buffer.append(".");
-	    buffer.append(method.getName());
-	    buffer.append("(");
-	
-	    for (int i = 0; i < method.getParameterTypes().length; i++)
-	    {
-	        if (i > 0)
-	            buffer.append(", ");
-	
-	        String name = method.getParameterTypes()[i].getSimpleName();
-	
-	        buffer.append(name);
-	    }
-	
-	    return buffer.append(")").toString();
-	}
+    /**
+     * Converts a method to a user presentable string consisting of the containing class name, the method name, and the
+     * short form of the parameter list (the class name of each parameter type, shorn of the package name portion).
+     *
+     * @param method
+     * @return short string representation
+     */
+    public static String asString(Method method)
+    {
+        StringBuilder buffer = new StringBuilder();
+    
+        buffer.append(method.getDeclaringClass().getName());
+        buffer.append(".");
+        buffer.append(method.getName());
+        buffer.append("(");
+    
+        for (int i = 0; i < method.getParameterTypes().length; i++)
+        {
+            if (i > 0)
+                buffer.append(", ");
+    
+            String name = method.getParameterTypes()[i].getSimpleName();
+    
+            buffer.append(name);
+        }
+    
+        return buffer.append(")").toString();
+    }
 
-	/**
-	 * Strips leading "_" and "$" and trailing "_" from the name.
-	 */
-	public static String stripMemberName(String memberName)
-	{
-	    assert InternalCommonsUtils.isNonBlank(memberName);
-	    Matcher matcher = NAME_PATTERN.matcher(memberName);
-	
-	    if (!matcher.matches())
-	        throw new IllegalArgumentException(String.format("Input '%s' is not a valid Java identifier.", memberName));
-	
-	    return matcher.group(1);
-	}
+    /**
+     * Strips leading "_" and "$" and trailing "_" from the name.
+     */
+    public static String stripMemberName(String memberName)
+    {
+        assert InternalCommonsUtils.isNonBlank(memberName);
+        Matcher matcher = NAME_PATTERN.matcher(memberName);
+    
+        if (!matcher.matches())
+            throw new IllegalArgumentException(String.format("Input '%s' is not a valid Java identifier.", memberName));
+    
+        return matcher.group(1);
+    }
 
-	/**
-	 * Joins together some number of elements to form a comma separated list.
-	 */
-	public static String join(List elements)
-	{
-	    return InternalCommonsUtils.join(elements, ", ");
-	}
+    /**
+     * Joins together some number of elements to form a comma separated list.
+     */
+    public static String join(List elements)
+    {
+        return InternalCommonsUtils.join(elements, ", ");
+    }
 
-	/**
-	 * Joins together some number of elements. If a value in the list is the empty string, it is replaced with the
-	 * string "(blank)".
-	 *
-	 * @param elements
-	 *         objects to be joined together
-	 * @param separator
-	 *         used between elements when joining
-	 */
-	public static String join(List elements, String separator)
-	{
-	    switch (elements.size())
-	    {
-	        case 0:
-	            return "";
-	
-	        case 1:
-	            return elements.get(0).toString();
-	
-	        default:
-	
-	            StringBuilder buffer = new StringBuilder();
-	            boolean first = true;
-	
-	            for (Object o : elements)
-	            {
-	                if (!first)
-	                    buffer.append(separator);
-	
-	                String string = String.valueOf(o);
-	
-	                if (string.equals(""))
-	                    string = "(blank)";
-	
-	                buffer.append(string);
-	
-	                first = false;
-	            }
-	
-	            return buffer.toString();
-	    }
-	}
+    /**
+     * Joins together some number of elements. If a value in the list is the empty string, it is replaced with the
+     * string "(blank)".
+     *
+     * @param elements
+     *         objects to be joined together
+     * @param separator
+     *         used between elements when joining
+     */
+    public static String join(List elements, String separator)
+    {
+        switch (elements.size())
+        {
+            case 0:
+                return "";
+    
+            case 1:
+                return elements.get(0).toString();
+    
+            default:
+    
+                StringBuilder buffer = new StringBuilder();
+                boolean first = true;
+    
+                for (Object o : elements)
+                {
+                    if (!first)
+                        buffer.append(separator);
+    
+                    String string = String.valueOf(o);
+    
+                    if (string.equals(""))
+                        string = "(blank)";
+    
+                    buffer.append(string);
+    
+                    first = false;
+                }
+    
+                return buffer.toString();
+        }
+    }
 
-	/**
-	 * Creates a sorted copy of the provided elements, then turns that into a comma separated list.
-	 *
-	 * @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
-	 *         empty
-	 */
-	public static String joinSorted(Collection elements)
-	{
-	    if (elements == null || elements.isEmpty())
-	        return "(none)";
-	
-	    List<String> list = CollectionFactory.newList();
-	
-	    for (Object o : elements)
-	        list.add(String.valueOf(o));
-	
-	    Collections.sort(list);
-	
-	    return join(list);
-	}
+    /**
+     * Creates a sorted copy of the provided elements, then turns that into a comma separated list.
+     *
+     * @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
+     *         empty
+     */
+    public static String joinSorted(Collection elements)
+    {
+        if (elements == null || elements.isEmpty())
+            return "(none)";
+    
+        List<String> list = CollectionFactory.newList();
+    
+        for (Object o : elements)
+            list.add(String.valueOf(o));
+    
+        Collections.sort(list);
+    
+        return join(list);
+    }
 
-	/**
-	 * Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
-	 */
-	
-	public static boolean isBlank(String input)
-	{
-	    return input == null || input.length() == 0 || input.trim().length() == 0;
-	}
+    /**
+     * Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
+     */
+    
+    public static boolean isBlank(String input)
+    {
+        return input == null || input.length() == 0 || input.trim().length() == 0;
+    }
 
-	/**
-	 * Capitalizes a string, converting the first character to uppercase.
-	 */
-	public static String capitalize(String input)
-	{
-	    if (input.length() == 0)
-	        return input;
-	
-	    return input.substring(0, 1).toUpperCase() + input.substring(1);
-	}
+    /**
+     * Capitalizes a string, converting the first character to uppercase.
+     */
+    public static String capitalize(String input)
+    {
+        if (input.length() == 0)
+            return input;
+    
+        return input.substring(0, 1).toUpperCase() + input.substring(1);
+    }
 
-	public static boolean isNonBlank(String input)
-	{
-	    return !isBlank(input);
-	}
+    public static boolean isNonBlank(String input)
+    {
+        return !isBlank(input);
+    }
 
-	/**
-	 * Return true if the input string contains the marker for symbols that must be expanded.
-	 */
-	public static boolean containsSymbols(String input)
-	{
-	    return input.contains("${");
-	}
+    /**
+     * Return true if the input string contains the marker for symbols that must be expanded.
+     */
+    public static boolean containsSymbols(String input)
+    {
+        return input.contains("${");
+    }
 
-	/**
-	 * Searches the string for the final period ('.') character and returns everything after that. The input string is
-	 * generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
-	 * expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
-	 * character.
-	 */
-	public static String lastTerm(String input)
-	{
-	    assert isNonBlank(input);
-	    int dotx = input.lastIndexOf('.');
-	
-	    if (dotx < 0)
-	        return input;
-	
-	    return input.substring(dotx + 1);
-	}
+    /**
+     * Searches the string for the final period ('.') character and returns everything after that. The input string is
+     * generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
+     * expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
+     * character.
+     */
+    public static String lastTerm(String input)
+    {
+        assert isNonBlank(input);
+        int dotx = input.lastIndexOf('.');
+    
+        if (dotx < 0)
+            return input;
+    
+        return input.substring(dotx + 1);
+    }
 
-	/**
-	 * Extracts the string keys from a map and returns them in sorted order. The keys are converted to strings.
-	 *
-	 * @param map
-	 *         the map to extract keys from (may be null)
-	 * @return the sorted keys, or the empty set if map is null
-	 */
-	
-	public static List<String> sortedKeys(Map map)
-	{
-	    if (map == null)
-	        return Collections.emptyList();
-	
-	    List<String> keys = CollectionFactory.newList();
-	
-	    for (Object o : map.keySet())
-	        keys.add(String.valueOf(o));
-	
-	    Collections.sort(keys);
-	
-	    return keys;
-	}
+    /**
+     * Extracts the string keys from a map and returns them in sorted order. The keys are converted to strings.
+     *
+     * @param map
+     *         the map to extract keys from (may be null)
+     * @return the sorted keys, or the empty set if map is null
+     */
+    
+    public static List<String> sortedKeys(Map map)
+    {
+        if (map == null)
+            return Collections.emptyList();
+    
+        List<String> keys = CollectionFactory.newList();
+    
+        for (Object o : map.keySet())
+            keys.add(String.valueOf(o));
+    
+        Collections.sort(keys);
+    
+        return keys;
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
index e032975..5e4ab42 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
@@ -457,9 +457,9 @@ public class TapestryInternalUtils
             {
                 if (conduit instanceof PropertyConduit2)
                 {
-                	return ((PropertyConduit2) conduit).getPropertyGenericType();
+                    return ((PropertyConduit2) conduit).getPropertyGenericType();
                 }
-            	return conduit.getPropertyType();
+                return conduit.getPropertyType();
             }
             
             public Object get(Object instance)

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/AbstractBinding.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/AbstractBinding.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/AbstractBinding.java
index 8e731b7..572d61a 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/AbstractBinding.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/AbstractBinding.java
@@ -71,7 +71,7 @@ public abstract class AbstractBinding extends BaseLocatable implements Binding2
      */
     public Type getBindingGenericType()
     {
-    	return getBindingType();
+        return getBindingType();
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/PropBinding.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/PropBinding.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/PropBinding.java
index afe63eb..da4c53e 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/PropBinding.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/PropBinding.java
@@ -111,10 +111,10 @@ public class PropBinding extends AbstractBinding implements InternalPropBinding
     @Override
     public Type getBindingGenericType()
     {
-    	if (conduit instanceof PropertyConduit2) {
-    		return ((PropertyConduit2) conduit).getPropertyGenericType();
-    	}
-    	return conduit.getPropertyType();
+        if (conduit instanceof PropertyConduit2) {
+            return ((PropertyConduit2) conduit).getPropertyGenericType();
+        }
+        return conduit.getPropertyType();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java
deleted file mode 100644
index 8b20666..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2007 The Apache Software Foundation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.apache.tapestry5.internal.services;
-
-import org.apache.tapestry5.beaneditor.DataType;
-import org.apache.tapestry5.ioc.services.PropertyAdapter;
-import org.apache.tapestry5.services.DataTypeAnalyzer;
-
-/**
- * Checks for the {@link DataType} annotation, returning its value if present.
- */
-public class AnnotationDataTypeAnalyzer implements DataTypeAnalyzer
-{
-    public String identifyDataType(PropertyAdapter adapter)
-    {
-        DataType annotation = adapter.getAnnotation(DataType.class);
-
-        return annotation == null ? null : annotation.value();
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java
index c51c086..5d0ac16 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java
@@ -351,9 +351,9 @@ public class InternalComponentResourcesImpl extends LockSupport implements Inter
         Binding binding = getBinding(parameterName);
         Type genericType;
         if (binding instanceof Binding2) {
-        	genericType = ((Binding2) binding).getBindingGenericType();
+            genericType = ((Binding2) binding).getBindingGenericType();
         } else {
-        	genericType = binding.getBindingType();
+            genericType = binding.getBindingType();
         }
         return genericType;
     }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
index e3902de..8a72a4d 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
@@ -59,6 +59,7 @@ import org.apache.tapestry5.internal.util.StringRenderable;
 import org.apache.tapestry5.internal.validator.ValidatorMacroImpl;
 import org.apache.tapestry5.ioc.*;
 import org.apache.tapestry5.ioc.annotations.*;
+import org.apache.tapestry5.ioc.internal.BasicDataTypeAnalyzers;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.services.*;
 import org.apache.tapestry5.ioc.util.AvailableValues;
@@ -621,18 +622,7 @@ public final class TapestryModule
      */
     public static void contributeDefaultDataTypeAnalyzer(MappedConfiguration<Class, String> configuration)
     {
-        // This is a special case contributed to avoid exceptions when a
-        // property type can't be
-        // matched. DefaultDataTypeAnalyzer converts the empty string to null.
-
-        configuration.add(Object.class, "");
-
-        configuration.add(String.class, DataTypeConstants.TEXT);
-        configuration.add(Number.class, DataTypeConstants.NUMBER);
-        configuration.add(Enum.class, DataTypeConstants.ENUM);
-        configuration.add(Boolean.class, DataTypeConstants.BOOLEAN);
-        configuration.add(Date.class, DataTypeConstants.DATE);
-        configuration.add(Calendar.class, DataTypeConstants.CALENDAR);
+        BasicDataTypeAnalyzers.provideDefaultDataTypeAnalyzers(configuration);
     }
 
     @Contribute(BeanBlockSource.class)

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/GenericTypeDisplay.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/GenericTypeDisplay.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/GenericTypeDisplay.java
index f6d2aa7..0a9365e 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/GenericTypeDisplay.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/GenericTypeDisplay.java
@@ -25,21 +25,21 @@ import org.apache.tapestry5.ioc.annotations.Inject;
  * Outputs the type and genericType of the 'value' binding in a div
  */
 public class GenericTypeDisplay {
-	@Inject
-	private ComponentResources resources;
-	
-	@Parameter(required=true, defaultPrefix=BindingConstants.LITERAL)
-	private String description;
-	
-	@Parameter(required=true)
-	private Object value;
-	
-	void afterRender(MarkupWriter writer) {
-		writer.element("div");
-		Class<?> type = resources.getBoundType("value");
-		Type genericType = resources.getBoundGenericType("value");
-		String text = String.format("description=%s,type=%s,genericType=%s", description, type.getName(), genericType.toString());
-		writer.write(text);
-		writer.end();
-	}
+    @Inject
+    private ComponentResources resources;
+    
+    @Parameter(required=true, defaultPrefix=BindingConstants.LITERAL)
+    private String description;
+    
+    @Parameter(required=true)
+    private Object value;
+    
+    void afterRender(MarkupWriter writer) {
+        writer.element("div");
+        Class<?> type = resources.getBoundType("value");
+        Type genericType = resources.getBoundGenericType("value");
+        String text = String.format("description=%s,type=%s,genericType=%s", description, type.getName(), genericType.toString());
+        writer.write(text);
+        writer.end();
+    }
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GenericTypeDemo.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GenericTypeDemo.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GenericTypeDemo.java
index 8e9fdd3..4fdc57a 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GenericTypeDemo.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GenericTypeDemo.java
@@ -8,16 +8,16 @@ import java.util.Set;
 import org.apache.tapestry5.annotations.Property;
 
 public class GenericTypeDemo {
-	private Set<Long> setOfLongs;
-	
-	@Property
-	private Map<String, String> mapOfStrings;
-	
-	public List<List<Date>> getListOfListOfDates() {
-		throw new UnsupportedOperationException();
-	}
-	
-	public void setSetOfLongs(Set<Long> setOfLongs) {
-		throw new UnsupportedOperationException();
-	}
+    private Set<Long> setOfLongs;
+    
+    @Property
+    private Map<String, String> mapOfStrings;
+    
+    public List<List<Date>> getListOfListOfDates() {
+        throw new UnsupportedOperationException();
+    }
+    
+    public void setSetOfLongs(Set<Long> setOfLongs) {
+        throw new UnsupportedOperationException();
+    }
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridWithSubmitWithContextDemo.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridWithSubmitWithContextDemo.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridWithSubmitWithContextDemo.java
index 9d4a774..0aac48f 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridWithSubmitWithContextDemo.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridWithSubmitWithContextDemo.java
@@ -45,9 +45,9 @@ public class GridWithSubmitWithContextDemo
     {
         return F.flow(library.getTracks()).sort(new Comparator<Track>(){
 
-			@Override
+            @Override
             public int compare(Track arg0, Track arg1) {
-	            return arg0.getId().compareTo(arg1.getId());
+                return arg0.getId().compareTo(arg1.getId());
             }
 
         });

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ChildBasePage.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ChildBasePage.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ChildBasePage.java
index 44e9aff..5a787e9 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ChildBasePage.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ChildBasePage.java
@@ -1,8 +1,8 @@
 package org.apache.tapestry5.integration.app2.base;
 
 public abstract class ChildBasePage extends ParentBasePage {
-	@Override
-	public String getObject() {
-		return "foobar";
-	}
+    @Override
+    public String getObject() {
+        return "foobar";
+    }
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ParentBasePage.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ParentBasePage.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ParentBasePage.java
index 4030128..6c18c43 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ParentBasePage.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ParentBasePage.java
@@ -1,5 +1,5 @@
 package org.apache.tapestry5.integration.app2.base;
 
 public abstract class ParentBasePage {
-	public abstract Object getObject();
+    public abstract Object getObject();
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/test/java/org/apache/tapestry5/integration/pagelevel/OverrideMethodsTest.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/pagelevel/OverrideMethodsTest.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/pagelevel/OverrideMethodsTest.java
index b612d1f..c8e7d48 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/pagelevel/OverrideMethodsTest.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/pagelevel/OverrideMethodsTest.java
@@ -9,13 +9,13 @@ public class OverrideMethodsTest extends Assert {
     /** TAP5-901 */
     @Test
     public void override_abstract_methods() {
-    	PageTester tester = new PageTester(TestConstants.APP2_PACKAGE, TestConstants.APP2_NAME);
-    	try {
-	        Document doc = tester.renderPage("OverrideAbstractMethods");
-	        assertEquals("6", doc.getElementById("length").getChildMarkup());
-    	} finally {
-    		tester.shutdown();
-    	}
+        PageTester tester = new PageTester(TestConstants.APP2_PACKAGE, TestConstants.APP2_NAME);
+        try {
+            Document doc = tester.renderPage("OverrideAbstractMethods");
+            assertEquals("6", doc.getElementById("length").getChildMarkup());
+        } finally {
+            tester.shutdown();
+        }
     }
 
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java
index af25c62..a861883 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java
@@ -167,15 +167,15 @@ public class PropertyConduitSourceImplTest extends InternalBaseTestCase
     }
 
     static class GenericBean {
-    	public List<Date> dates;
-    	public List<GenericBean> genericBeans;
-    	
-    	public List<Long> getLongs() {
-    		return Collections.emptyList();
-    	}
-    	
-    	public void setMap(Map<String, Integer> map) {
-    	}
+        public List<Date> dates;
+        public List<GenericBean> genericBeans;
+        
+        public List<Long> getLongs() {
+            return Collections.emptyList();
+        }
+        
+        public void setMap(Map<String, Integer> map) {
+        }
     }
     
     @Test
@@ -884,15 +884,15 @@ public class PropertyConduitSourceImplTest extends InternalBaseTestCase
 
         // example from Howard
         try {
-        	assertConduitPropertyType(Foo.class, "bar", Bar.class);
+            assertConduitPropertyType(Foo.class, "bar", Bar.class);
         } catch (AssertionError e) {
-        	List<Method> matches = CollectionFactory.newList();
-        	for (Method method : Foo.class.getMethods()) {
-        		if (method.getName().equals("getBar")) {
-        			matches.add(method);
-        		}
-        	}
-        	fail(String.format("%s (possible candidates %s)", e.getMessage(), matches)); 
+            List<Method> matches = CollectionFactory.newList();
+            for (Method method : Foo.class.getMethods()) {
+                if (method.getName().equals("getBar")) {
+                    matches.add(method);
+                }
+            }
+            fail(String.format("%s (possible candidates %s)", e.getMessage(), matches)); 
         }
         assertConduitPropertyType(AbstractFoo.class, "bar", AbstractBar.class);
         

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONArray.java
----------------------------------------------------------------------
diff --git a/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONArray.java b/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONArray.java
index 76ea531..7cb7d55 100644
--- a/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONArray.java
+++ b/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONArray.java
@@ -386,7 +386,7 @@ public final class JSONArray extends JSONCollection implements Iterable<Object>
      */
     public JSONArray put(Object value)
     {
-    	// now testValidity checks for null values.
+        // now testValidity checks for null values.
         // assert value != null;
 
         JSONObject.testValidity(value);

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java
----------------------------------------------------------------------
diff --git a/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java b/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java
index 7c5ccb4..1392bb8 100644
--- a/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java
+++ b/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java
@@ -913,7 +913,7 @@ public final class JSONObject extends JSONCollection
      */
     static void printValue(JSONPrintSession session, Object value)
     {
-    	
+        
         if (value instanceof JSONObject)
         {
             ((JSONObject) value).print(session);


[05/15] tapestry-5 git commit: First pass creating the BeanModel and Commons packages. Lots of stuff moved around, but no actual code changes so far

Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/Resource.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/Resource.java b/commons/src/main/java/org/apache/tapestry5/ioc/Resource.java
new file mode 100644
index 0000000..b81c1c5
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/Resource.java
@@ -0,0 +1,108 @@
+// 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;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Locale;
+
+/**
+ * Represents a resource on the server that may be used for server side processing, or may be exposed to the client
+ * side. Generally, this represents an abstraction on top of files on the class path and files stored in the web
+ * application context.
+ * <p/>
+ * Resources are often used as map keys; they should be immutable and should implement hashCode() and equals().
+ */
+public interface Resource
+{
+
+    /**
+     * Returns true if the resource exists; if a stream to the content of the file may be opened. A resource exists
+     * if {@link #toURL()} returns a non-null value. Starting in release 5.3.4, the result of this is cached.
+     * <p/>
+     * Starting in 5.4, some "virtual resources", may return true even though {@link #toURL()} returns null.
+     *
+     * @return true if the resource exists, false if it does not
+     */
+    boolean exists();
+
+
+    /**
+     * Returns true if the resource is virtual, meaning this is no underlying file. Many operations are unsupported
+     * on virtual resources, including {@link #toURL()}, {@link #forLocale(java.util.Locale)},
+     * {@link #withExtension(String)}, {@link #getFile()}, {@link #getFolder()}, {@link #getPath()}}; these
+     * operations will throw an {@link java.lang.UnsupportedOperationException}.
+     *
+     * @since 5.4
+     */
+    boolean isVirtual();
+
+    /**
+     * Opens a stream to the content of the resource, or returns null if the resource does not exist. The native
+     * input stream supplied by the resource is wrapped in a {@link java.io.BufferedInputStream}.
+     *
+     * @return an open, buffered stream to the content, if available
+     */
+    InputStream openStream() throws IOException;
+
+    /**
+     * Returns the URL for the resource, or null if it does not exist. This value is lazily computed; starting in 5.3.4, subclasses may cache
+     * the result.  Starting in 5.4, some "virtual resources" may return null.
+     */
+    URL toURL();
+
+    /**
+     * Returns a localized version of the resource. May return null if no such resource exists. Starting in release
+     * 5.3.4, the result of this method is cached internally.
+     */
+    Resource forLocale(Locale locale);
+
+    /**
+     * Returns a Resource based on a relative path, relative to the folder containing the resource. Understands the "."
+     * (current folder) and ".." (parent folder) conventions, and treats multiple sequential slashes as a single slash.
+     * <p/>
+     * Virtual resources (resources fabricated at runtime) return themselves.
+     */
+    Resource forFile(String relativePath);
+
+    /**
+     * Returns a new Resource with the extension changed (or, if the resource does not have an extension, the extension
+     * is added). The new Resource may not exist (that is, {@link #toURL()} may return null.
+     *
+     * @param extension
+     *         to apply to the resource, such as "html" or "properties"
+     * @return the new resource
+     */
+    Resource withExtension(String extension);
+
+    /**
+     * Returns the portion of the path up to the last forward slash; this is the directory or folder portion of the
+     * Resource.
+     */
+    String getFolder();
+
+    /**
+     * Returns the file portion of the Resource path, everything that follows the final forward slash.
+     * <p/>
+     * Starting in 5.4, certain kinds of "virtual resources" may return null here.
+     */
+    String getFile();
+
+    /**
+     * Return the path (the combination of folder and file).
+     * <p/>
+     * Starting in 5.4, certain "virtual resources", may return an arbitrary value here.
+     */
+    String getPath();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java
new file mode 100644
index 0000000..716b7c6
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java
@@ -0,0 +1,35 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.ioc.internal;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * A null implementation of {@link AnnotationProvider}, used when there is not appropriate source of annotations.
+ */
+public class NullAnnotationProvider implements AnnotationProvider
+{
+    /**
+     * Always returns null.
+     */
+    @Override
+    public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+    {
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java
new file mode 100644
index 0000000..6711b1a
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java
@@ -0,0 +1,139 @@
+// Copyright 2006, 2007, 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.util;
+
+import org.apache.tapestry5.ioc.util.CaseInsensitiveMap;
+import org.apache.tapestry5.ioc.util.Stack;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Static factory methods to ease the creation of new collection types (when using generics). Most of these method
+ * leverage the compiler's ability to match generic types by return value. Typical usage (with a static import):
+ * <p/>
+ * <pre>
+ * Map&lt;Foo, Bar&gt; map = newMap();
+ * </pre>
+ * <p/>
+ * <p/>
+ * This is a replacement for:
+ * <p/>
+ * <pre>
+ * Map&lt;Foo, Bar&gt; map = new HashMap&lt;Foo, Bar&gt;();
+ * </pre>
+ */
+public final class CollectionFactory
+{
+    /**
+     * Constructs and returns a generic {@link HashMap} instance.
+     */
+    public static <K, V> Map<K, V> newMap()
+    {
+        return new HashMap<K, V>();
+    }
+
+    /**
+     * Constructs and returns a generic {@link java.util.HashSet} instance.
+     */
+    public static <T> Set<T> newSet()
+    {
+        return new HashSet<T>();
+    }
+
+    /**
+     * Contructs a new {@link HashSet} and initializes it using the provided collection.
+     */
+    public static <T, V extends T> Set<T> newSet(Collection<V> values)
+    {
+        return new HashSet<T>(values);
+    }
+
+    public static <T, V extends T> Set<T> newSet(V... values)
+    {
+        // Was a call to newSet(), but Sun JDK can't handle that. Fucking generics.
+        return new HashSet<T>(Arrays.asList(values));
+    }
+
+    /**
+     * Constructs a new {@link java.util.HashMap} instance by copying an existing Map instance.
+     */
+    public static <K, V> Map<K, V> newMap(Map<? extends K, ? extends V> map)
+    {
+        return new HashMap<K, V>(map);
+    }
+
+    /**
+     * Constructs a new concurrent map, which is safe to access via multiple threads.
+     */
+    public static <K, V> ConcurrentMap<K, V> newConcurrentMap()
+    {
+        return new ConcurrentHashMap<K, V>();
+    }
+
+    /**
+     * Contructs and returns a new generic {@link java.util.ArrayList} instance.
+     */
+    public static <T> List<T> newList()
+    {
+        return new ArrayList<T>();
+    }
+
+    /**
+     * Creates a new, fully modifiable list from an initial set of elements.
+     */
+    public static <T, V extends T> List<T> newList(V... elements)
+    {
+        // Was call to newList(), but Sun JDK can't handle that.
+        return new ArrayList<T>(Arrays.asList(elements));
+    }
+
+    /**
+     * Useful for queues.
+     */
+    public static <T> LinkedList<T> newLinkedList()
+    {
+        return new LinkedList<T>();
+    }
+
+    /**
+     * Constructs and returns a new {@link java.util.ArrayList} as a copy of the provided collection.
+     */
+    public static <T, V extends T> List<T> newList(Collection<V> list)
+    {
+        return new ArrayList<T>(list);
+    }
+
+    /**
+     * Constructs and returns a new {@link java.util.concurrent.CopyOnWriteArrayList}.
+     */
+    public static <T> List<T> newThreadSafeList()
+    {
+        return new CopyOnWriteArrayList<T>();
+    }
+
+    public static <T> Stack<T> newStack()
+    {
+        return new Stack<T>();
+    }
+
+    public static <V> Map<String, V> newCaseInsensitiveMap()
+    {
+        return new CaseInsensitiveMap<V>();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
new file mode 100644
index 0000000..1a6dd80
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
@@ -0,0 +1,615 @@
+// Copyright 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.util;
+
+import java.lang.reflect.*;
+import java.util.LinkedList;
+
+/**
+ * Static methods related to the use of JDK 1.5 generics.
+ */
+@SuppressWarnings("unchecked")
+public class GenericsUtils
+{
+    /**
+     * Analyzes the method in the context of containingClass and returns the Class that is represented by
+     * the method's generic return type. Any parameter information in the generic return type is lost. If you want
+     * to preserve the type parameters of the return type consider using
+     * {@link #extractActualType(java.lang.reflect.Type, java.lang.reflect.Method)}.
+     *
+     * @param containingClass class which either contains or inherited the method
+     * @param method          method from which to extract the return type
+     * @return the class represented by the methods generic return type, resolved based on the context .
+     * @see #extractActualType(java.lang.reflect.Type, java.lang.reflect.Method)
+     * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
+     * @see #asClass(java.lang.reflect.Type)
+     */
+    public static Class<?> extractGenericReturnType(Class<?> containingClass, Method method)
+    {
+        return asClass(resolve(method.getGenericReturnType(), containingClass));
+    }
+
+
+    /**
+     * Analyzes the field in the context of containingClass and returns the Class that is represented by
+     * the field's generic type. Any parameter information in the generic type is lost, if you want
+     * to preserve the type parameters of the return type consider using
+     * {@link #getTypeVariableIndex(java.lang.reflect.TypeVariable)}.
+     *
+     * @param containingClass class which either contains or inherited the field
+     * @param field           field from which to extract the type
+     * @return the class represented by the field's generic type, resolved based on the containingClass.
+     * @see #extractActualType(java.lang.reflect.Type, java.lang.reflect.Field)
+     * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
+     * @see #asClass(java.lang.reflect.Type)
+     */
+    public static Class extractGenericFieldType(Class containingClass, Field field)
+    {
+        return asClass(resolve(field.getGenericType(), containingClass));
+    }
+
+    /**
+     * Analyzes the method in the context of containingClass and returns the Class that is represented by
+     * the method's generic return type. Any parameter information in the generic return type is lost.
+     *
+     * @param containingType Type which is/represents the class that either contains or inherited the method
+     * @param method         method from which to extract the generic return type
+     * @return the generic type represented by the methods generic return type, resolved based on the containingType.
+     * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
+     */
+    public static Type extractActualType(Type containingType, Method method)
+    {
+        return resolve(method.getGenericReturnType(), containingType);
+    }
+
+    /**
+     * Analyzes the method in the context of containingClass and returns the Class that is represented by
+     * the method's generic return type. Any parameter information in the generic return type is lost.
+     *
+     * @param containingType Type which is/represents the class that either contains or inherited the field
+     * @param field          field from which to extract the generic return type
+     * @return the generic type represented by the methods generic return type, resolved based on the containingType.
+     * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
+     */
+    public static Type extractActualType(Type containingType, Field field)
+    {
+        return resolve(field.getGenericType(), containingType);
+    }
+
+    /**
+     * Resolves the type parameter based on the context of the containingType.
+     * <p/>
+     * {@link java.lang.reflect.TypeVariable} will be unwrapped to the type argument resolved form the class
+     * hierarchy. This may be something other than a simple Class if the type argument is a ParameterizedType for
+     * instance (e.g. List&lt;E>; List&lt;Map&lt;Long, String>>, E would be returned as a ParameterizedType with the raw
+     * type Map and type arguments Long and String.
+     * <p/>
+     *
+     * @param type
+     *          the generic type (ParameterizedType, GenericArrayType, WildcardType, TypeVariable) to be resolved
+     * @param containingType
+     *          the type which his
+     * @return
+     *          the type resolved to the best of our ability.
+     * @since 5.2.?
+     */
+    public static Type resolve(final Type type, final Type containingType)
+    {
+        // The type isn't generic. (String, Long, etc)
+        if (type instanceof Class)
+            return type;
+
+        // List<T>, List<String>, List<T extends Number>
+        if (type instanceof ParameterizedType)
+            return resolve((ParameterizedType) type, containingType);
+
+        // T[], List<String>[], List<T>[]
+        if (type instanceof GenericArrayType)
+            return resolve((GenericArrayType) type, containingType);
+
+        // List<? extends T>, List<? extends Object & Comparable & Serializable>
+        if (type instanceof WildcardType)
+            return resolve((WildcardType) type, containingType);
+
+        // T
+        if (type instanceof TypeVariable)
+            return resolve((TypeVariable) type, containingType);
+
+        // I'm leaning towards an exception here.
+        return type;
+    }
+
+
+    /**
+     * Determines if the suspected super type is assignable from the suspected sub type.
+     *
+     * @param suspectedSuperType
+     *          e.g. GenericDAO&lt;Pet, String>
+     * @param suspectedSubType
+     *          e.g. PetDAO extends GenericDAO&lt;Pet,String>
+     * @return
+     *          true if (sourceType)targetClass is a valid cast
+     */
+    public static boolean isAssignableFrom(Type suspectedSuperType, Type suspectedSubType)
+    {
+        final Class suspectedSuperClass = asClass(suspectedSuperType);
+        final Class suspectedSubClass = asClass(suspectedSubType);
+
+        // The raw types need to be compatible.
+        if (!suspectedSuperClass.isAssignableFrom(suspectedSubClass))
+        {
+            return false;
+        }
+
+        // From this point we know that the raw types are assignable.
+        // We need to figure out what the generic parameters in the targetClass are
+        // as they pertain to the sourceType.
+
+        if (suspectedSuperType instanceof WildcardType)
+        {
+            // ? extends Number
+            // needs to match all the bounds (there will only be upper bounds or lower bounds
+            for (Type t : ((WildcardType) suspectedSuperType).getUpperBounds())
+            {
+                if (!isAssignableFrom(t, suspectedSubType)) return false;
+            }
+            for (Type t : ((WildcardType) suspectedSuperType).getLowerBounds())
+            {
+                if (!isAssignableFrom(suspectedSubType, t)) return false;
+            }
+            return true;
+        }
+
+        Type curType = suspectedSubType;
+        Class curClass;
+
+        while (curType != null && !curType.equals(Object.class))
+        {
+            curClass = asClass(curType);
+
+            if (curClass.equals(suspectedSuperClass))
+            {
+                final Type resolved = resolve(curType, suspectedSubType);
+
+                if (suspectedSuperType instanceof Class)
+                {
+                    if ( resolved instanceof Class )
+                        return suspectedSuperType.equals(resolved);
+
+                    // They may represent the same class, but the suspectedSuperType is not parameterized. The parameter
+                    // types default to Object so they must be a match.
+                    // e.g. Pair p = new StringLongPair();
+                    //      Pair p = new Pair<? extends Number, String>
+
+                    return true;
+                }
+
+                if (suspectedSuperType instanceof ParameterizedType)
+                {
+                    if (resolved instanceof ParameterizedType)
+                    {
+                        final Type[] type1Arguments = ((ParameterizedType) suspectedSuperType).getActualTypeArguments();
+                        final Type[] type2Arguments = ((ParameterizedType) resolved).getActualTypeArguments();
+                        if (type1Arguments.length != type2Arguments.length) return false;
+
+                        for (int i = 0; i < type1Arguments.length; ++i)
+                        {
+                            if (!isAssignableFrom(type1Arguments[i], type2Arguments[i])) return false;
+                        }
+                        return true;
+                    }
+                }
+                else if (suspectedSuperType instanceof GenericArrayType)
+                {
+                    if (resolved instanceof GenericArrayType)
+                    {
+                        return isAssignableFrom(
+                                ((GenericArrayType) suspectedSuperType).getGenericComponentType(),
+                                ((GenericArrayType) resolved).getGenericComponentType()
+                        );
+                    }
+                }
+
+                return false;
+            }
+
+            final Type[] types = curClass.getGenericInterfaces();
+            for (Type t : types)
+            {
+                final Type resolved = resolve(t, suspectedSubType);
+                if (isAssignableFrom(suspectedSuperType, resolved))
+                    return true;
+            }
+
+            curType = curClass.getGenericSuperclass();
+        }
+        return false;
+    }
+
+    /**
+     * Get the class represented by the reflected type.
+     * This method is lossy; You cannot recover the type information from the class that is returned.
+     * <p/>
+     * {@code TypeVariable} the first bound is returned. If your type variable extends multiple interfaces that information
+     * is lost.
+     * <p/>
+     * {@code WildcardType} the first lower bound is returned. If the wildcard is defined with upper bounds
+     * then {@code Object} is returned.
+     *
+     * @param actualType
+     *           a Class, ParameterizedType, GenericArrayType
+     * @return the un-parameterized class associated with the type.
+     */
+    public static Class asClass(Type actualType)
+    {
+        if (actualType instanceof Class) return (Class) actualType;
+
+        if (actualType instanceof ParameterizedType)
+        {
+            final Type rawType = ((ParameterizedType) actualType).getRawType();
+            // The sun implementation returns getRawType as Class<?>, but there is room in the interface for it to be
+            // some other Type. We'll assume it's a Class.
+            // TODO: consider logging or throwing our own exception for that day when "something else" causes some confusion
+            return (Class) rawType;
+        }
+
+        if (actualType instanceof GenericArrayType)
+        {
+            final Type type = ((GenericArrayType) actualType).getGenericComponentType();
+            return Array.newInstance(asClass(type), 0).getClass();
+        }
+
+        if (actualType instanceof TypeVariable)
+        {
+            // Support for List<T extends Number>
+            // There is always at least one bound. If no bound is specified in the source then it will be Object.class
+            return asClass(((TypeVariable) actualType).getBounds()[0]);
+        }
+
+        if (actualType instanceof WildcardType)
+        {
+            final WildcardType wildcardType = (WildcardType) actualType;
+            final Type[] bounds = wildcardType.getLowerBounds();
+            if (bounds != null && bounds.length > 0)
+            {
+                return asClass(bounds[0]);
+            }
+            // If there is no lower bounds then the only thing that makes sense is Object.
+            return Object.class;
+        }
+
+        throw new RuntimeException(String.format("Unable to convert %s to Class.", actualType));
+    }
+
+    /**
+     * Convert the type into a string. The string representation approximates the code that would be used to define the
+     * type.
+     *
+     * @param type - the type.
+     * @return a string representation of the type, similar to how it was declared.
+     */
+    public static String toString(Type type)
+    {
+        if ( type instanceof ParameterizedType ) return toString((ParameterizedType)type);
+        if ( type instanceof WildcardType ) return toString((WildcardType)type);
+        if ( type instanceof GenericArrayType) return toString((GenericArrayType)type);
+        if ( type instanceof Class )
+        {
+            final Class theClass = (Class) type;
+            return (theClass.isArray() ? theClass.getName() + "[]" : theClass.getName());
+        }
+        return type.toString();
+    }
+
+    /**
+     * Method to resolve a TypeVariable to its most
+     * <a href="http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#112582">reifiable</a> form.
+     * <p/>
+     * <p/>
+     * How to resolve a TypeVariable:<br/>
+     * All of the TypeVariables defined by a generic class will be given a Type by any class that extends it. The Type
+     * given may or may not be reifiable; it may be another TypeVariable for instance.
+     * <p/>
+     * Consider <br/>
+     * <i>class Pair&gt;A,B> { A getA(){...}; ...}</i><br/>
+     * <i>class StringLongPair extends Pair&gt;String, Long> { }</i><br/>
+     * <p/>
+     * To resolve the actual return type of Pair.getA() you must first resolve the TypeVariable "A".
+     * We can do that by first finding the index of "A" in the Pair.class.getTypeParameters() array of TypeVariables.
+     * <p/>
+     * To get to the Type provided by StringLongPair you access the generics information by calling
+     * StringLongPair.class.getGenericSuperclass; this will be a ParameterizedType. ParameterizedType gives you access
+     * to the actual type arguments provided to Pair by StringLongPair. The array is in the same order as the array in
+     * Pair.class.getTypeParameters so you can use the index we discovered earlier to extract the Type; String.class.
+     * <p/>
+     * When extracting Types we only have to consider the superclass hierarchy and not the interfaces implemented by
+     * the class. When a class implements a generic interface it must provide types for the interface and any generic
+     * methods implemented from the interface will be re-defined by the class with its generic type variables.
+     *
+     * @param typeVariable   - the type variable to resolve.
+     * @param containingType - the shallowest class in the class hierarchy (furthest from Object) where typeVariable is defined.
+     * @return a Type that has had all possible TypeVariables resolved that have been defined between the type variable
+     *         declaration and the containingType.
+     */
+    private static Type resolve(TypeVariable typeVariable, Type containingType)
+    {
+        // The generic declaration is either a Class, Method or Constructor
+        final GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
+
+        if (!(genericDeclaration instanceof Class))
+        {
+            // It's a method or constructor. The best we can do here is try to resolve the bounds
+            // e.g. <T extends E> T getT(T param){} where E is defined by the class.
+            final Type bounds0 = typeVariable.getBounds()[0];
+            return resolve(bounds0, containingType);
+        }
+
+        final Class typeVariableOwner = (Class) genericDeclaration;
+
+        // find the typeOwner in the containingType's hierarchy
+        final LinkedList<Type> stack = new LinkedList<Type>();
+
+        // If you pass a List<Long> as the containingType then the TypeVariable is going to be resolved by the
+        // containingType and not the super class.
+        if (containingType instanceof ParameterizedType)
+        {
+            stack.add(containingType);
+        }
+
+        Class theClass = asClass(containingType);
+        Type genericSuperclass = theClass.getGenericSuperclass();
+        while (genericSuperclass != null && // true for interfaces with no superclass
+                !theClass.equals(Object.class) &&
+                !theClass.equals(typeVariableOwner))
+        {
+            stack.addFirst(genericSuperclass);
+            theClass = asClass(genericSuperclass);
+            genericSuperclass = theClass.getGenericSuperclass();
+        }
+
+        int i = getTypeVariableIndex(typeVariable);
+        Type resolved = typeVariable;
+        for (Type t : stack)
+        {
+            if (t instanceof ParameterizedType)
+            {
+                resolved = ((ParameterizedType) t).getActualTypeArguments()[i];
+                if (resolved instanceof Class) return resolved;
+                if (resolved instanceof TypeVariable)
+                {
+                    // Need to look at the next class in the hierarchy
+                    i = getTypeVariableIndex((TypeVariable) resolved);
+                    continue;
+                }
+                return resolve(resolved, containingType);
+            }
+        }
+
+        // the only way we get here is if resolved is still a TypeVariable, otherwise an
+        // exception is thrown or a value is returned.
+        return ((TypeVariable) resolved).getBounds()[0];
+    }
+
+    /**
+     * @param type           - something like List&lt;T>[] or List&lt;? extends T>[] or T[]
+     * @param containingType - the shallowest type in the hierarchy where type is defined.
+     * @return either the passed type if no changes required or a copy with a best effort resolve of the component type.
+     */
+    private static GenericArrayType resolve(GenericArrayType type, Type containingType)
+    {
+        final Type componentType = type.getGenericComponentType();
+
+        if (!(componentType instanceof Class))
+        {
+            final Type resolved = resolve(componentType, containingType);
+            return create(resolved);
+        }
+
+        return type;
+    }
+
+    /**
+     * @param type           - something like List&lt;T>, List&lt;T extends Number>
+     * @param containingType - the shallowest type in the hierarchy where type is defined.
+     * @return the passed type if nothing to resolve or a copy of the type with the type arguments resolved.
+     */
+    private static ParameterizedType resolve(ParameterizedType type, Type containingType)
+    {
+        // Use a copy because we're going to modify it.
+        final Type[] types = type.getActualTypeArguments().clone();
+
+        boolean modified = resolve(types, containingType);
+        return modified ? create(type.getRawType(), type.getOwnerType(), types) : type;
+    }
+
+    /**
+     * @param type           - something like List&lt;? super T>, List<&lt;? extends T>, List&lt;? extends T & Comparable&lt? super T>>
+     * @param containingType - the shallowest type in the hierarchy where type is defined.
+     * @return the passed type if nothing to resolve or a copy of the type with the upper and lower bounds resolved.
+     */
+    private static WildcardType resolve(WildcardType type, Type containingType)
+    {
+        // Use a copy because we're going to modify them.
+        final Type[] upper = type.getUpperBounds().clone();
+        final Type[] lower = type.getLowerBounds().clone();
+
+        boolean modified = resolve(upper, containingType);
+        modified = modified || resolve(lower, containingType);
+
+        return modified ? create(upper, lower) : type;
+    }
+
+    /**
+     * @param types          - Array of types to resolve. The unresolved type is replaced in the array with the resolved type.
+     * @param containingType - the shallowest type in the hierarchy where type is defined.
+     * @return true if any of the types were resolved.
+     */
+    private static boolean resolve(Type[] types, Type containingType)
+    {
+        boolean modified = false;
+        for (int i = 0; i < types.length; ++i)
+        {
+            Type t = types[i];
+            if (!(t instanceof Class))
+            {
+                modified = true;
+                final Type resolved = resolve(t, containingType);
+                if (!resolved.equals(t))
+                {
+                    types[i] = resolved;
+                    modified = true;
+                }
+            }
+        }
+        return modified;
+    }
+
+    /**
+     * @param rawType       - the un-parameterized type.
+     * @param ownerType     - the outer class or null if the class is not defined within another class.
+     * @param typeArguments - type arguments.
+     * @return a copy of the type with the typeArguments replaced.
+     */
+    static ParameterizedType create(final Type rawType, final Type ownerType, final Type[] typeArguments)
+    {
+        return new ParameterizedType()
+        {
+            @Override
+            public Type[] getActualTypeArguments()
+            {
+                return typeArguments;
+            }
+
+            @Override
+            public Type getRawType()
+            {
+                return rawType;
+            }
+
+            @Override
+            public Type getOwnerType()
+            {
+                return ownerType;
+            }
+
+            @Override
+            public String toString()
+            {
+                return GenericsUtils.toString(this);
+            }
+        };
+    }
+
+    static GenericArrayType create(final Type componentType)
+    {
+        return new GenericArrayType()
+        {
+            @Override
+            public Type getGenericComponentType()
+            {
+                return componentType;
+            }
+
+            @Override
+            public String toString()
+            {
+                return GenericsUtils.toString(this);
+            }
+        };
+    }
+
+    /**
+     * @param upperBounds - e.g. ? extends Number
+     * @param lowerBounds - e.g. ? super Long
+     * @return An new copy of the type with the upper and lower bounds replaced.
+     */
+    static WildcardType create(final Type[] upperBounds, final Type[] lowerBounds)
+    {
+
+        return new WildcardType()
+        {
+            @Override
+            public Type[] getUpperBounds()
+            {
+                return upperBounds;
+            }
+
+            @Override
+            public Type[] getLowerBounds()
+            {
+                return lowerBounds;
+            }
+
+            @Override
+            public String toString()
+            {
+                return GenericsUtils.toString(this);
+            }
+        };
+    }
+
+    static String toString(ParameterizedType pt)
+    {
+        String s = toString(pt.getActualTypeArguments());
+        return String.format("%s<%s>", toString(pt.getRawType()), s);
+    }
+
+    static String toString(GenericArrayType gat)
+    {
+        return String.format("%s[]", toString(gat.getGenericComponentType()));
+    }
+
+    static String toString(WildcardType wt)
+    {
+        final boolean isSuper = wt.getLowerBounds().length > 0;
+        return String.format("? %s %s",
+                isSuper ? "super" : "extends",
+                isSuper ? toString(wt.getLowerBounds()) : toString(wt.getLowerBounds()));
+    }
+
+    static String toString(Type[] types)
+    {
+        StringBuilder sb = new StringBuilder();
+        for ( Type t : types )
+        {
+            sb.append(toString(t)).append(", ");
+        }
+        return sb.substring(0, sb.length() - 2);// drop last ,
+    }
+
+    /**
+     * Find the index of the TypeVariable in the classes parameters. The offset can be used on a subclass to find
+     * the actual type.
+     *
+     * @param typeVariable - the type variable in question.
+     * @return the index of the type variable in its declaring class/method/constructor's type parameters.
+     */
+    private static int getTypeVariableIndex(final TypeVariable typeVariable)
+    {
+        // the label from the class (the T in List<T>, the K or V in Map<K,V>, etc)
+        final String typeVarName = typeVariable.getName();
+        final TypeVariable[] typeParameters = typeVariable.getGenericDeclaration().getTypeParameters();
+        for (int typeArgumentIndex = 0; typeArgumentIndex < typeParameters.length; typeArgumentIndex++)
+        {
+            // The .equals for TypeVariable may not be compatible, a name check should be sufficient.
+            if (typeParameters[typeArgumentIndex].getName().equals(typeVarName))
+                return typeArgumentIndex;
+        }
+
+        // The only way this could happen is if the TypeVariable is hand built incorrectly, or it's corrupted.
+        throw new RuntimeException(
+                String.format("%s does not have a TypeVariable matching %s", typeVariable.getGenericDeclaration(), typeVariable));
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
new file mode 100644
index 0000000..ef217cb
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
@@ -0,0 +1,75 @@
+// Copyright 2006 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.util;
+
+import org.apache.tapestry5.ioc.Locatable;
+import org.apache.tapestry5.ioc.Location;
+
+/**
+ * Exception class used as a replacement for {@link java.lang.RuntimeException} when the exception is related to a
+ * particular location.
+ */
+public class TapestryException extends RuntimeException implements Locatable
+{
+    private static final long serialVersionUID = 6396903640977182682L;
+
+    private transient final Location location;
+
+    /**
+     * @param message  a message (may be null)
+     * @param location implements {@link Location} or {@link Locatable}
+     * @param cause    if not null, the root cause of the exception
+     */
+    public TapestryException(String message, Object location, Throwable cause)
+    {
+        this(message, InternalUtils.locationOf(location), cause);
+    }
+
+    /**
+     * @param message a message (may be null)
+     * @param cause   if not null, the root cause of the exception, also used to set the location
+     */
+    public TapestryException(String message, Throwable cause)
+    {
+        this(message, cause, cause);
+    }
+
+    /**
+     * @param message  a message (may be null)
+     * @param location location to associated with the exception, or null if not known
+     * @param cause    if not null, the root cause of the exception
+     */
+    public TapestryException(String message, Location location, Throwable cause)
+    {
+        super(message, cause);
+
+        this.location = location;
+    }
+
+    @Override
+    public Location getLocation()
+    {
+        return location;
+    }
+
+    @Override
+    public String toString()
+    {
+        if (location == null) return super.toString();
+
+        return String.format("%s [at %s]", super.toString(), location);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java b/commons/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java
new file mode 100644
index 0000000..6159ed3
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java
@@ -0,0 +1,79 @@
+// Copyright 2006, 2007, 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.services;
+
+import java.lang.annotation.Annotation;
+import java.util.List;
+
+/**
+ * Organizes all {@link org.apache.tapestry5.ioc.services.PropertyAdapter}s for a particular class.
+ * <p/>
+ * Only provides access to <em>simple</em> properties. Indexed properties are ignored.
+ * <p/>
+ * When accessing properties by name, the case of the name is ignored.
+ */
+public interface ClassPropertyAdapter
+{
+    /**
+     * Returns the names of all properties, sorted into alphabetic order. This includes true properties
+     * (as defined in the JavaBeans specification), but also public fields. Starting in Tapestry 5.3, even public static fields are included.
+     */
+    List<String> getPropertyNames();
+
+    /**
+     * Returns the type of bean this adapter provides properties for.
+     */
+    Class getBeanType();
+
+    /**
+     * Returns the property adapter with the given name, or null if no such adapter exists.
+     *
+     * @param name of the property (case is ignored)
+     */
+    PropertyAdapter getPropertyAdapter(String name);
+
+    /**
+     * Reads the value of a property.
+     *
+     * @param instance     the object to read a value from
+     * @param propertyName the name of the property to read (case is ignored)
+     * @throws UnsupportedOperationException if the property is write only
+     * @throws IllegalArgumentException      if property does not exist
+     */
+    Object get(Object instance, String propertyName);
+
+    /**
+     * Updates the value of a property.
+     *
+     * @param instance     the object to update
+     * @param propertyName the name of the property to update (case is ignored)
+     * @throws UnsupportedOperationException if the property is read only
+     * @throws IllegalArgumentException      if property does not exist
+     */
+    void set(Object instance, String propertyName, Object value);
+
+    /**
+     * Returns the annotation of a given property for the specified type if such an annotation is present, else null.
+     *
+     * @param instance     the object to read a value from
+     * @param propertyName the name of the property to read (case is ignored)
+     * @param annotationClass the type of annotation to return
+     *
+     * @throws IllegalArgumentException      if property does not exist
+     *
+     * @since 5.4
+     */
+    Annotation getAnnotation(Object instance, String propertyName, Class<? extends Annotation> annotationClass);
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java b/commons/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java
new file mode 100644
index 0000000..b7a4cc8
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java
@@ -0,0 +1,31 @@
+// Copyright 2006 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.services;
+
+/**
+ * Responsible for converting from one type to another. This is used primarily around component parameters.
+ *
+ * @param <S> the source type (input)
+ * @param <T> the target type (output)
+ */
+public interface Coercion<S, T>
+{
+    /**
+     * Converts an input value.
+     *
+     * @param input the input value
+     */
+    T coerce(S input);
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java b/commons/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java
new file mode 100644
index 0000000..746de1e
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java
@@ -0,0 +1,145 @@
+// 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.services;
+
+import org.apache.tapestry5.plastic.PlasticUtils;
+
+/**
+ * An immutable object that represents a mapping from one type to another. This is also the contribution type when
+ * building the {@link org.apache.tapestry5.ioc.services.TypeCoercer} service. Wraps a
+ * {@link org.apache.tapestry5.ioc.services.Coercion} object that performs the work with additional properties that
+ * describe
+ * the input and output types of the coercion, needed when searching for an appropriate coercion (or sequence of
+ * coercions).
+ *
+ * @param <S>
+ *         source (input) type
+ * @param <T>
+ *         target (output) type
+ */
+public final class CoercionTuple<S, T>
+{
+    private final Class<S> sourceType;
+
+    private final Class<T> targetType;
+
+    private final Coercion<S, T> coercion;
+
+    /**
+     * Wraps an arbitrary coercion with an implementation of toString() that identifies the source and target types.
+     */
+    private class CoercionWrapper<WS, WT> implements Coercion<WS, WT>
+    {
+        private final Coercion<WS, WT> coercion;
+
+        public CoercionWrapper(Coercion<WS, WT> coercion)
+        {
+            this.coercion = coercion;
+        }
+
+        @Override
+        public WT coerce(WS input)
+        {
+            return coercion.coerce(input);
+        }
+
+        @Override
+        public String toString()
+        {
+            return String.format("%s --> %s", convert(sourceType), convert(targetType));
+        }
+    }
+
+    private String convert(Class type)
+    {
+        if (Void.class.equals(type))
+            return "null";
+
+        String name = PlasticUtils.toTypeName(type);
+
+        int dotx = name.lastIndexOf('.');
+
+        // Strip off a package name of "java.lang"
+
+        if (dotx > 0 && name.substring(0, dotx).equals("java.lang"))
+            return name.substring(dotx + 1);
+
+        return name;
+    }
+
+    /**
+     * Standard constructor, which defaults wrap to true.
+     */
+    public CoercionTuple(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion)
+    {
+        this(sourceType, targetType, coercion, true);
+    }
+
+    /**
+     * Convenience constructor to help with generics.
+     *
+     * @since 5.2.0
+     */
+    public static <S, T> CoercionTuple<S, T> create(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion)
+    {
+        return new CoercionTuple<S, T>(sourceType, targetType, coercion);
+    }
+
+    /**
+     * Internal-use constructor.
+     *
+     * @param sourceType
+     *         the source (or input) type of the coercion, may be Void.class to indicate a coercion from null
+     * @param targetType
+     *         the target (or output) type of the coercion
+     * @param coercion
+     *         the object that performs the coercion
+     * @param wrap
+     *         if true, the coercion is wrapped to provide a useful toString()
+     */
+    @SuppressWarnings("unchecked")
+    public CoercionTuple(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion, boolean wrap)
+    {
+        assert sourceType != null;
+        assert targetType != null;
+        assert coercion != null;
+
+        this.sourceType = PlasticUtils.toWrapperType(sourceType);
+        this.targetType = PlasticUtils.toWrapperType(targetType);
+        this.coercion = wrap ? new CoercionWrapper<S, T>(coercion) : coercion;
+    }
+
+    @Override
+    public String toString()
+    {
+        return coercion.toString();
+    }
+
+    public Coercion<S, T> getCoercion()
+    {
+        return coercion;
+    }
+
+    public Class<S> getSourceType()
+    {
+        return sourceType;
+    }
+
+    public Class<T> getTargetType()
+    {
+        return targetType;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java b/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java
new file mode 100644
index 0000000..ae542c5
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java
@@ -0,0 +1,77 @@
+// Copyright 2006, 2010, 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.services;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * A wrapper around the JavaBean Introspector that allows more manageable access to JavaBean properties of objects.
+ * <p/>
+ * Only provides access to <em>simple</em> properties. Indexed properties are ignored.
+ * <p>
+ * Starting in Tapestry 5.2, public fields can now be accessed as if they were properly JavaBean properties. Where there
+ * is a name conflict, the true property will be favored over the field access.
+ */
+public interface PropertyAccess
+{
+    /**
+     * Reads the value of a property.
+     *
+     * @throws UnsupportedOperationException
+     *             if the property is write only
+     * @throws IllegalArgumentException
+     *             if property does not exist
+     */
+    Object get(Object instance, String propertyName);
+
+    /**
+     * Updates the value of a property.
+     *
+     * @throws UnsupportedOperationException
+     *             if the property is read only
+     * @throws IllegalArgumentException
+     *             if property does not exist
+     */
+    void set(Object instance, String propertyName, Object value);
+
+    /**
+     * Returns the annotation of a given property for the specified type if such an annotation is present, else null.
+     * A convenience over invoking {@link #getAdapter(Object)}.{@link ClassPropertyAdapter#getPropertyAdapter(String)}.{@link PropertyAdapter#getAnnotation(Class)}
+     *
+     * @param instance     the object to read a value from
+     * @param propertyName the name of the property to read (case is ignored)
+     * @param annotationClass the type of annotation to return
+     * @throws IllegalArgumentException
+     *             if property does not exist
+     *
+     * @since 5.4
+     */
+    Annotation getAnnotation(Object instance, String propertyName, Class<? extends Annotation> annotationClass);
+
+    /**
+     * Returns the adapter for a particular object instance. A convienience over invoking {@link #getAdapter(Class)}.
+     */
+    ClassPropertyAdapter getAdapter(Object instance);
+
+    /**
+     * Returns the adapter used to access properties within the indicated class.
+     */
+    ClassPropertyAdapter getAdapter(Class forClass);
+
+    /**
+     * Discards all stored property access information, discarding all created class adapters.
+     */
+    void clearCache();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java b/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java
new file mode 100644
index 0000000..947535e
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java
@@ -0,0 +1,121 @@
+// Copyright 2006, 2008, 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.services;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * Provides access to a single property within a class. Acts as an {@link org.apache.tapestry5.ioc.AnnotationProvider};
+ * when searching for annotations, the read method (if present) is checked first, followed by the write method, followed
+ * by the underlying field (when the property name matches the field name).
+ * <p/>
+ * Starting in release 5.2, this property may actually be a public field. In 5.3, it may be a public static field.
+ *
+ * @see org.apache.tapestry5.ioc.services.ClassPropertyAdapter
+ */
+@SuppressWarnings("unchecked")
+public interface PropertyAdapter extends AnnotationProvider
+{
+    /**
+     * Returns the name of the property (or public field).
+     */
+    String getName();
+
+    /**
+     * Returns true if the property is readable (i.e., has a getter method or is a public field).
+     */
+    boolean isRead();
+
+    /**
+     * Returns the method used to read the property, or null if the property is not readable (or is a public field).
+     */
+    public Method getReadMethod();
+
+    /**
+     * Returns true if the property is writeable (i.e., has a setter method or is a non-final field).
+     */
+    boolean isUpdate();
+
+    /**
+     * Returns the method used to update the property, or null if the property is not writeable (or a public field).
+     */
+    public Method getWriteMethod();
+
+    /**
+     * Reads the property value.
+     *
+     * @param instance to read from
+     * @throws UnsupportedOperationException if the property is write only
+     */
+    Object get(Object instance);
+
+    /**
+     * Updates the property value. The provided value must not be null if the property type is primitive, and must
+     * otherwise be of the proper type.
+     *
+     * @param instance to update
+     * @param value    new value for the property
+     * @throws UnsupportedOperationException if the property is read only
+     */
+    void set(Object instance, Object value);
+
+    /**
+     * Returns the type of the property.
+     */
+    Class getType();
+
+    /**
+     * Returns true if the return type of the read method is not the same as the property type. This can occur when the
+     * property has been defined using generics, in which case, the method's type may be Object when the property type
+     * is something more specific. This method is primarily used when generating runtime code related to the property.
+     */
+    boolean isCastRequired();
+
+    /**
+     * Returns the {@link org.apache.tapestry5.ioc.services.ClassPropertyAdapter} that provides access to other
+     * properties defined by the same class.
+     */
+    ClassPropertyAdapter getClassAdapter();
+
+    /**
+     * Returns the type of bean to which this property belongs. This is the same as
+     * {@link org.apache.tapestry5.ioc.services.ClassPropertyAdapter#getBeanType()}.
+     */
+    Class getBeanType();
+
+    /**
+     * Returns true if the property is actually a public field (possibly, a public static field).
+     *
+     * @since 5.2
+     */
+    boolean isField();
+
+    /**
+     * Returns the field if the property is a public field or null if the property is accessed via the read method.
+     *
+     * @since 5.2
+     */
+    Field getField();
+
+    /**
+     * The class in which the property (or public field) is defined.
+     *
+     * @since 5.2
+     */
+    Class getDeclaringClass();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java b/commons/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java
new file mode 100644
index 0000000..ec8eaad
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java
@@ -0,0 +1,88 @@
+// Copyright 2006, 2007, 2008, 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.services;
+
+import org.apache.tapestry5.ioc.annotations.UsesConfiguration;
+
+/**
+ * Makes use of {@link org.apache.tapestry5.ioc.services.Coercion}s to convert between an input value (of some specific
+ * type) and a desired output type. Smart about coercing, even if it requires multiple coercion steps (i.e., via an
+ * intermediate type, such as String).
+ */
+@UsesConfiguration(CoercionTuple.class)
+public interface TypeCoercer
+{
+    /**
+     * Performs a coercion from an input type to a desired output type. When the target type is a primitive, the actual
+     * conversion will be to the equivalent wrapper type. In some cases, the TypeCoercer will need to search for an
+     * appropriate coercion, and may even combine existing coercions to form new ones; in those cases, the results of
+     * the search are cached.
+     * <p/>
+     * The TypeCoercer also caches the results of a coercion search.
+     * 
+     * @param <S>
+     *            source type (input)
+     * @param <T>
+     *            target type (output)
+     * @param input
+     * @param targetType
+     *            defines the target type
+     * @return the coerced value
+     * @throws RuntimeException
+     *             if the input can not be coerced
+     */
+    <S, T> T coerce(S input, Class<T> targetType);
+
+    /**
+     * Given a source and target type, computes the coercion that will be used.
+     * <p>
+     * Note: holding the returned coercion past the time when {@linkplain #clearCache() the cache is cleared} can cause
+     * a memory leak, especially in the context of live reloading (wherein holding a reference to a single class make
+     * keep an entire ClassLoader from being reclaimed).
+     * 
+     * @since 5.2.0
+     * @param <S>
+     *            source type (input)
+     * @param <T>
+     *            target type (output)
+     * @param sourceType
+     *            type to coerce from
+     * @param targetType
+     *            defines the target type
+     * @return the coercion that will ultimately be used
+     */
+    <S, T> Coercion<S, T> getCoercion(Class<S> sourceType, Class<T> targetType);
+
+    /**
+     * Used primarily inside test suites, this method performs the same steps as {@link #coerce(Object, Class)}, but
+     * returns a string describing the series of coercions, such as "Object --&gt; String --&gt; Long --&gt; Integer".
+     * 
+     * @param <S>
+     *            source type (input)
+     * @param <T>
+     *            target type (output)
+     * @param sourceType
+     *            the source coercion type (use void.class for coercions from null)
+     * @param targetType
+     *            defines the target type
+     * @return a string identifying the series of coercions, or the empty string if no coercion is necessary
+     */
+    <S, T> String explain(Class<S> sourceType, Class<T> targetType);
+
+    /**
+     * Clears cached information stored by the TypeCoercer.
+     */
+    void clearCache();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
new file mode 100644
index 0000000..c4c5c6d
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
@@ -0,0 +1,87 @@
+// Copyright 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.util;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+
+/**
+ * Used (as part of a {@link UnknownValueException} to identify what available values
+ * are present.
+ * 
+ * @since 5.2.0
+ */
+public class AvailableValues
+{
+    private final String valueType;
+
+    private final List<String> values;
+
+    /**
+     * @param valueType
+     *            a word or phrase that describes what the values are such as "component types" or "service ids"
+     *@param values
+     *            a set of objects defining the values; the values will be converted to strings and sorted into
+     *            ascending order
+     */
+    public AvailableValues(String valueType, Collection<?> values)
+    {
+        this.valueType = valueType;
+        this.values = sortValues(values);
+    }
+
+    public AvailableValues(String valueType, Map<?, ?> map)
+    {
+        this(valueType, map.keySet());
+    }
+
+    private static List<String> sortValues(Collection<?> values)
+    {
+        List<String> result = CollectionFactory.newList();
+
+        for (Object v : values)
+        {
+            result.add(String.valueOf(v));
+        }
+
+        Collections.sort(result);
+
+        return Collections.unmodifiableList(result);
+    }
+
+    /** The type of value, i.e., "component types" or "service ids". */
+    public String getValueType()
+    {
+        return valueType;
+    }
+
+    /** The values, as strings, in sorted order. */
+    public List<String> getValues()
+    {
+        return values;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("AvailableValues[%s: %s]", valueType, InternalUtils.join(values));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java
new file mode 100644
index 0000000..f5aff7e
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java
@@ -0,0 +1,499 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.ioc.util;
+
+import java.io.Serializable;
+import java.util.*;
+
+/**
+ * An mapped collection where the keys are always strings and access to values is case-insensitive. The case of keys in
+ * the map is <em>maintained</em>, but on any access to a key (directly or indirectly), all key comparisons are
+ * performed in a case-insensitive manner. The map implementation is intended to support a reasonably finite number
+ * (dozens or hundreds, not thousands or millions of key/value pairs. Unlike HashMap, it is based on a sorted list of
+ * entries rather than hash bucket. It is also geared towards a largely static map, one that is created and then used
+ * without modification.
+ *
+ * @param <V> the type of value stored
+ */
+public class CaseInsensitiveMap<V> extends AbstractMap<String, V> implements Serializable
+{
+    private static final long serialVersionUID = 3362718337611953298L;
+
+    private static final int NULL_HASH = Integer.MIN_VALUE;
+
+    private static final int DEFAULT_SIZE = 20;
+
+    private static class CIMEntry<V> implements Map.Entry<String, V>, Serializable
+    {
+        private static final long serialVersionUID = 6713986085221148350L;
+
+        private String key;
+
+        private final int hashCode;
+
+        V value;
+
+        public CIMEntry(final String key, final int hashCode, V value)
+        {
+            this.key = key;
+            this.hashCode = hashCode;
+            this.value = value;
+        }
+
+        @Override
+        public String getKey()
+        {
+            return key;
+        }
+
+        @Override
+        public V getValue()
+        {
+            return value;
+        }
+
+        @Override
+        public V setValue(V value)
+        {
+            V result = this.value;
+
+            this.value = value;
+
+            return result;
+        }
+
+        /**
+         * Returns true if both keys are null, or if the provided key is the same as, or case-insensitively equal to,
+         * the entrie's key.
+         *
+         * @param key to compare against
+         * @return true if equal
+         */
+        @SuppressWarnings({ "StringEquality" })
+        boolean matches(String key)
+        {
+            return key == this.key || (key != null && key.equalsIgnoreCase(this.key));
+        }
+
+        boolean valueMatches(Object value)
+        {
+            return value == this.value || (value != null && value.equals(this.value));
+        }
+    }
+
+    private class EntrySetIterator implements Iterator
+    {
+        int expectedModCount = modCount;
+
+        int index;
+
+        int current = -1;
+
+        @Override
+        public boolean hasNext()
+        {
+            return index < size;
+        }
+
+        @Override
+        public Object next()
+        {
+            check();
+
+            if (index >= size) throw new NoSuchElementException();
+
+            current = index++;
+
+            return entries[current];
+        }
+
+        @Override
+        public void remove()
+        {
+            check();
+
+            if (current < 0) throw new NoSuchElementException();
+
+            new Position(current, true).remove();
+
+            expectedModCount = modCount;
+        }
+
+        private void check()
+        {
+            if (expectedModCount != modCount) throw new ConcurrentModificationException();
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private class EntrySet extends AbstractSet
+    {
+        @Override
+        public Iterator iterator()
+        {
+            return new EntrySetIterator();
+        }
+
+        @Override
+        public int size()
+        {
+            return size;
+        }
+
+        @Override
+        public void clear()
+        {
+            CaseInsensitiveMap.this.clear();
+        }
+
+        @Override
+        public boolean contains(Object o)
+        {
+            if (!(o instanceof Map.Entry)) return false;
+
+            Map.Entry e = (Map.Entry) o;
+
+            Position position = select(e.getKey());
+
+            return position.isFound() && position.entry().valueMatches(e.getValue());
+        }
+
+        @Override
+        public boolean remove(Object o)
+        {
+            if (!(o instanceof Map.Entry)) return false;
+
+            Map.Entry e = (Map.Entry) o;
+
+            Position position = select(e.getKey());
+
+            if (position.isFound() && position.entry().valueMatches(e.getValue()))
+            {
+                position.remove();
+                return true;
+            }
+
+            return false;
+        }
+
+    }
+
+    private class Position
+    {
+        private final int cursor;
+
+        private final boolean found;
+
+        Position(int cursor, boolean found)
+        {
+            this.cursor = cursor;
+            this.found = found;
+        }
+
+        boolean isFound()
+        {
+            return found;
+        }
+
+        CIMEntry<V> entry()
+        {
+            return entries[cursor];
+        }
+
+        V get()
+        {
+            return found ? entries[cursor].value : null;
+        }
+
+        V remove()
+        {
+            if (!found) return null;
+
+            V result = entries[cursor].value;
+
+            // Remove the entry by shifting everything else down.
+
+            System.arraycopy(entries, cursor + 1, entries, cursor, size - cursor - 1);
+
+            // We shifted down, leaving one (now duplicate) entry behind.
+
+            entries[--size] = null;
+
+            // A structural change for sure
+
+            modCount++;
+
+            return result;
+        }
+
+        @SuppressWarnings("unchecked")
+        V put(String key, int hashCode, V newValue)
+        {
+            if (found)
+            {
+                CIMEntry<V> e = entries[cursor];
+
+                V result = e.value;
+
+                // Not a structural change, so no change to modCount
+
+                // Update the key (to maintain case). By definition, the hash code
+                // will not change.
+
+                e.key = key;
+                e.value = newValue;
+
+                return result;
+            }
+
+            // Not found, we're going to add it.
+
+            int newSize = size + 1;
+
+            if (newSize == entries.length)
+            {
+                // Time to expand!
+
+                int newCapacity = (size * 3) / 2 + 1;
+
+                CIMEntry<V>[] newEntries = new CIMEntry[newCapacity];
+
+                System.arraycopy(entries, 0, newEntries, 0, cursor);
+
+                System.arraycopy(entries, cursor, newEntries, cursor + 1, size - cursor);
+
+                entries = newEntries;
+            }
+            else
+            {
+                // Open up a space for the new entry
+
+                System.arraycopy(entries, cursor, entries, cursor + 1, size - cursor);
+            }
+
+            CIMEntry<V> newEntry = new CIMEntry<V>(key, hashCode, newValue);
+            entries[cursor] = newEntry;
+
+            size++;
+
+            // This is definately a structural change
+
+            modCount++;
+
+            return null;
+        }
+
+    }
+
+    // The list of entries. This is kept sorted by hash code. In some cases, there may be different
+    // keys with the same hash code in adjacent indexes.
+    private CIMEntry<V>[] entries;
+
+    private int size = 0;
+
+    // Used by iterators to check for concurrent modifications
+
+    private transient int modCount = 0;
+
+    private transient Set<Map.Entry<String, V>> entrySet;
+
+    public CaseInsensitiveMap()
+    {
+        this(DEFAULT_SIZE);
+    }
+
+    @SuppressWarnings("unchecked")
+    public CaseInsensitiveMap(int size)
+    {
+        entries = new CIMEntry[Math.max(size, 3)];
+    }
+
+    public CaseInsensitiveMap(Map<String, ? extends V> map)
+    {
+        this(map.size());
+
+        for (Map.Entry<String, ? extends V> entry : map.entrySet())
+        {
+            put(entry.getKey(), entry.getValue());
+        }
+    }
+
+    @Override
+    public void clear()
+    {
+        for (int i = 0; i < size; i++)
+            entries[i] = null;
+
+        size = 0;
+        modCount++;
+    }
+
+    @Override
+    public boolean isEmpty()
+    {
+        return size == 0;
+    }
+
+    @Override
+    public int size()
+    {
+        return size;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public V put(String key, V value)
+    {
+        int hashCode = caseInsenitiveHashCode(key);
+
+        return select(key, hashCode).put(key, hashCode, value);
+    }
+
+    @Override
+    public boolean containsKey(Object key)
+    {
+        return select(key).isFound();
+    }
+
+    @Override
+    public V get(Object key)
+    {
+        return select(key).get();
+    }
+
+    @Override
+    public V remove(Object key)
+    {
+        return select(key).remove();
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public Set<Map.Entry<String, V>> entrySet()
+    {
+        if (entrySet == null) entrySet = new EntrySet();
+
+        return entrySet;
+    }
+
+    private Position select(Object key)
+    {
+        if (key == null || key instanceof String)
+        {
+            String keyString = (String) key;
+            return select(keyString, caseInsenitiveHashCode(keyString));
+        }
+
+        return new Position(0, false);
+    }
+
+    /**
+     * Searches the elements for the index of the indicated key and (case insensitive) hash code. Sets the _cursor and
+     * _found attributes.
+     */
+    private Position select(String key, int hashCode)
+    {
+        if (size == 0) return new Position(0, false);
+
+        int low = 0;
+        int high = size - 1;
+
+        int cursor;
+
+        while (low <= high)
+        {
+            cursor = (low + high) >> 1;
+
+            CIMEntry e = entries[cursor];
+
+            if (e.hashCode < hashCode)
+            {
+                low = cursor + 1;
+                continue;
+            }
+
+            if (e.hashCode > hashCode)
+            {
+                high = cursor - 1;
+                continue;
+            }
+
+            return tunePosition(key, hashCode, cursor);
+        }
+
+        return new Position(low, false);
+    }
+
+    /**
+     * select() has located a matching hashCode, but there's an outlying possibility that multiple keys share the same
+     * hashCode. Backup the cursor until we get to locate the initial hashCode match, then march forward until the key
+     * is located, or the hashCode stops matching.
+     *
+     * @param key
+     * @param hashCode
+     */
+    private Position tunePosition(String key, int hashCode, int cursor)
+    {
+        boolean found = false;
+
+        while (cursor > 0)
+        {
+            if (entries[cursor - 1].hashCode != hashCode) break;
+
+            cursor--;
+        }
+
+        while (true)
+        {
+            if (entries[cursor].matches(key))
+            {
+                found = true;
+                break;
+            }
+
+            // Advance to the next entry.
+
+            cursor++;
+
+            // If out of entries,
+            if (cursor >= size || entries[cursor].hashCode != hashCode) break;
+        }
+
+        return new Position(cursor, found);
+    }
+
+    static int caseInsenitiveHashCode(String input)
+    {
+        if (input == null) return NULL_HASH;
+
+        int length = input.length();
+        int hash = 0;
+
+        // This should end up more or less equal to input.toLowerCase().hashCode(), unless String
+        // changes its implementation. Let's hope this is reasonably fast.
+
+        for (int i = 0; i < length; i++)
+        {
+            int ch = input.charAt(i);
+
+            int caselessCh = Character.toLowerCase(ch);
+
+            hash = 31 * hash + caselessCh;
+        }
+
+        return hash;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/util/ExceptionUtils.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/ExceptionUtils.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/ExceptionUtils.java
new file mode 100644
index 0000000..2feaeca
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/ExceptionUtils.java
@@ -0,0 +1,115 @@
+// Copyright 2008-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.util;
+
+import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
+import org.apache.tapestry5.ioc.services.PropertyAccess;
+
+/**
+ * Contains static methods useful for manipulating exceptions.
+ */
+public class ExceptionUtils
+{
+    /**
+     * Locates a particular type of exception, working its way via the cause property of each exception in the exception
+     * stack.
+     *
+     * @param t    the outermost exception
+     * @param type the type of exception to search for
+     * @return the first exception of the given type, if found, or null
+     */
+    public static <T extends Throwable> T findCause(Throwable t, Class<T> type)
+    {
+        Throwable current = t;
+
+        while (current != null)
+        {
+            if (type.isInstance(current))
+            {
+                return type.cast(current);
+            }
+
+            // Not a match, work down.
+
+            current = current.getCause();
+        }
+
+        return null;
+    }
+
+    /**
+     * Locates a particular type of exception, working its way down via any property that returns some type of Exception.
+     * This is more expensive, but more accurate, than {@link #findCause(Throwable, Class)} as it works with older exceptions
+     * that do not properly implement the (relatively new) {@linkplain Throwable#getCause() cause property}.
+     *
+     * @param t      the outermost exception
+     * @param type   the type of exception to search for
+     * @param access used to access properties
+     * @return the first exception of the given type, if found, or null
+     */
+    public static <T extends Throwable> T findCause(Throwable t, Class<T> type, PropertyAccess access)
+    {
+        Throwable current = t;
+
+        while (current != null)
+        {
+            if (type.isInstance(current))
+            {
+                return type.cast(current);
+            }
+
+            Throwable next = null;
+
+            ClassPropertyAdapter adapter = access.getAdapter(current);
+
+            for (String name : adapter.getPropertyNames())
+            {
+
+                Object value = adapter.getPropertyAdapter(name).get(current);
+
+                if (value != null && value != current && value instanceof Throwable)
+                {
+                    next = (Throwable) value;
+                    break;
+                }
+            }
+
+            current = next;
+        }
+
+
+        return null;
+    }
+
+    /**
+     * Extracts the message from an exception. If the exception's message is null, returns the exceptions class name.
+     *
+     * @param exception
+     *         to extract message from
+     * @return message or class name
+     * @since 5.4
+     */
+    public static String toMessage(Throwable exception)
+    {
+        assert exception != null;
+
+        String message = exception.getMessage();
+
+        if (message != null)
+            return message;
+
+        return exception.getClass().getName();
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/util/UnknownValueException.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/UnknownValueException.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/UnknownValueException.java
new file mode 100644
index 0000000..470b611
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/UnknownValueException.java
@@ -0,0 +1,47 @@
+// Copyright 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.util;
+
+import org.apache.tapestry5.ioc.internal.util.TapestryException;
+
+/**
+ * Special exception used when a value (typically from a map) is referenced that does not exist. Uses a
+ * {@link AvailableValues} object
+ * to track what the known values are.
+ * 
+ * @since 5.2.0
+ */
+public class UnknownValueException extends TapestryException
+{
+    private final AvailableValues availableValues;
+
+    public UnknownValueException(String message, AvailableValues availableValues)
+    {
+        this(message, null, null, availableValues);
+    }
+
+    public UnknownValueException(String message, Object location, Throwable cause, AvailableValues availableValues)
+    {
+        super(message, location, cause);
+
+        this.availableValues = availableValues;
+    }
+
+    public AvailableValues getAvailableValues()
+    {
+        return availableValues;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java b/commons/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java
new file mode 100644
index 0000000..77b028e
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java
@@ -0,0 +1,60 @@
+// Copyright 2006, 2007, 2008, 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.services;
+
+import java.util.Map;
+
+/**
+ * An object which manages a list of {@link org.apache.tapestry5.services.InvalidationListener}s. There are multiple
+ * event hub services implementing this interface, each with a specific marker annotation; each can register listeners
+ * and fire events; these are based on the type of resource that has been invalidated. Tapestry has built-in support
+ * for:
+ * <dl>
+ * <dt>message catalog resources
+ * <dd>{@link org.apache.tapestry5.services.ComponentMessages} marker annotation
+ * <dt>component templates
+ * <dd>{@link org.apache.tapestry5.services.ComponentTemplates} marker annotation
+ * <dt>component classes
+ * <dd>{@link org.apache.tapestry5.services.ComponentClasses} marker annotation
+ * </dl>
+ * <p/>
+ * Starting in Tapestry 5.3, these services are disabled in production (it does nothing).
+ *
+ * @since 5.1.0.0
+ */
+public interface InvalidationEventHub
+{
+    /**
+     * Adds a listener, who needs to know when an underlying resource of a given category has changed (so that the
+     * receiver may discard any cached data that may have been invalidated). Does nothing in production mode.
+     *
+     * @deprecated in 5.4, use {@link #addInvalidationCallback(Runnable)} instead}
+     */
+    void addInvalidationListener(InvalidationListener listener);
+
+    /**
+     * Adds a callback that is invoked when an underlying tracked resource has changed. Does nothing in production mode.
+     *
+     * @since  5.4
+     */
+    void addInvalidationCallback(Runnable callback);
+
+    /**
+     * Adds a callback that clears the map.
+     *
+     * @since 5.4
+     */
+    void clearOnInvalidation(Map<?,?> map);
+}


[07/15] tapestry-5 git commit: First pass creating the BeanModel and Commons packages. Lots of stuff moved around, but no actual code changes so far

Posted by th...@apache.org.
First pass creating the BeanModel and Commons packages. Lots of stuff moved around, but no actual code changes so far


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

Branch: refs/heads/beanmodel-split
Commit: f963c7ab7ebaf1b4b0349c9875a5490a85d75dd0
Parents: 09a011c
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Sat Dec 6 15:16:02 2014 -0200
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Sat Dec 6 15:16:02 2014 -0200

----------------------------------------------------------------------
 beanmodel/build.gradle                          |   27 +
 .../org/apache/tapestry5/PropertyConduit.java   |   45 +
 .../org/apache/tapestry5/PropertyConduit2.java  |   40 +
 .../apache/tapestry5/beaneditor/BeanModel.java  |  169 ++
 .../tapestry5/beaneditor/PropertyModel.java     |   97 ++
 .../internal/InternalPropertyConduit.java       |   37 +
 .../internal/beaneditor/BeanModelImpl.java      |  289 ++++
 .../internal/beaneditor/PropertyModelImpl.java  |  139 ++
 .../CoercingPropertyConduitWrapper.java         |   67 +
 .../services/PropertyConduitDelegate.java       |   53 +
 .../services/PropertyConduitSourceImpl.java     | 1563 ++++++++++++++++++
 .../tapestry5/services/BeanModelSource.java     |   70 +
 .../services/PropertyConduitSource.java         |   41 +
 commons/build.gradle                            |   18 +
 .../tapestry5/internal/util/IntegerRange.java   |  125 ++
 .../tapestry5/internal/util/MultiKey.java       |   86 +
 .../tapestry5/ioc/AnnotationProvider.java       |   33 +
 .../org/apache/tapestry5/ioc/Locatable.java     |   27 +
 .../java/org/apache/tapestry5/ioc/Location.java |   38 +
 .../apache/tapestry5/ioc/MessageFormatter.java  |   32 +
 .../java/org/apache/tapestry5/ioc/Messages.java |   61 +
 .../org/apache/tapestry5/ioc/ObjectLocator.java |  143 ++
 .../java/org/apache/tapestry5/ioc/Resource.java |  108 ++
 .../ioc/internal/NullAnnotationProvider.java    |   35 +
 .../ioc/internal/util/CollectionFactory.java    |  139 ++
 .../ioc/internal/util/GenericsUtils.java        |  615 +++++++
 .../ioc/internal/util/TapestryException.java    |   75 +
 .../ioc/services/ClassPropertyAdapter.java      |   79 +
 .../apache/tapestry5/ioc/services/Coercion.java |   31 +
 .../tapestry5/ioc/services/CoercionTuple.java   |  145 ++
 .../tapestry5/ioc/services/PropertyAccess.java  |   77 +
 .../tapestry5/ioc/services/PropertyAdapter.java |  121 ++
 .../tapestry5/ioc/services/TypeCoercer.java     |   88 +
 .../tapestry5/ioc/util/AvailableValues.java     |   87 +
 .../tapestry5/ioc/util/CaseInsensitiveMap.java  |  499 ++++++
 .../tapestry5/ioc/util/ExceptionUtils.java      |  115 ++
 .../ioc/util/UnknownValueException.java         |   47 +
 .../services/InvalidationEventHub.java          |   60 +
 .../services/InvalidationListener.java          |   33 +
 settings.gradle                                 |    2 +-
 tapestry-core/build.gradle                      |    6 +-
 .../org/apache/tapestry5/PropertyConduit.java   |   45 -
 .../org/apache/tapestry5/PropertyConduit2.java  |   40 -
 .../apache/tapestry5/beaneditor/BeanModel.java  |  169 --
 .../tapestry5/beaneditor/PropertyModel.java     |   97 --
 .../internal/InternalPropertyConduit.java       |   37 -
 .../internal/beaneditor/BeanModelImpl.java      |  289 ----
 .../internal/beaneditor/PropertyModelImpl.java  |  139 --
 .../CoercingPropertyConduitWrapper.java         |   67 -
 .../services/PropertyConduitDelegate.java       |   53 -
 .../services/PropertyConduitSourceImpl.java     | 1563 ------------------
 .../tapestry5/internal/util/IntegerRange.java   |  125 --
 .../tapestry5/internal/util/MultiKey.java       |   86 -
 .../tapestry5/services/BeanModelSource.java     |   70 -
 .../tapestry5/services/ComponentClasses.java    |   35 -
 .../tapestry5/services/ComponentLayer.java      |   37 -
 .../services/InvalidationEventHub.java          |   60 -
 .../services/InvalidationListener.java          |   33 -
 .../services/PropertyConduitSource.java         |   41 -
 tapestry-ioc/build.gradle                       |    1 +
 .../tapestry5/ioc/AnnotationProvider.java       |   33 -
 .../org/apache/tapestry5/ioc/Locatable.java     |   27 -
 .../java/org/apache/tapestry5/ioc/Location.java |   38 -
 .../apache/tapestry5/ioc/MessageFormatter.java  |   32 -
 .../java/org/apache/tapestry5/ioc/Messages.java |   61 -
 .../org/apache/tapestry5/ioc/ObjectLocator.java |  143 --
 .../java/org/apache/tapestry5/ioc/Resource.java |  108 --
 .../ioc/annotations/UsesConfiguration.java      |   34 -
 .../ioc/internal/NullAnnotationProvider.java    |   35 -
 .../ioc/internal/util/CollectionFactory.java    |  139 --
 .../ioc/internal/util/GenericsUtils.java        |  615 -------
 .../ioc/internal/util/TapestryException.java    |   75 -
 .../ioc/services/ClassPropertyAdapter.java      |   79 -
 .../apache/tapestry5/ioc/services/Coercion.java |   31 -
 .../tapestry5/ioc/services/CoercionTuple.java   |  145 --
 .../tapestry5/ioc/services/PropertyAccess.java  |   77 -
 .../tapestry5/ioc/services/PropertyAdapter.java |  121 --
 .../tapestry5/ioc/services/TypeCoercer.java     |   88 -
 .../tapestry5/ioc/util/AvailableValues.java     |   87 -
 .../tapestry5/ioc/util/CaseInsensitiveMap.java  |  499 ------
 .../tapestry5/ioc/util/ExceptionUtils.java      |  115 --
 .../ioc/util/UnknownValueException.java         |   47 -
 tapestry5-annotations/build.gradle              |    2 +-
 .../ioc/annotations/UsesConfiguration.java      |   34 +
 .../tapestry5/services/ComponentClasses.java    |   35 +
 .../tapestry5/services/ComponentLayer.java      |   37 +
 86 files changed, 5664 insertions(+), 5622 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/beanmodel/build.gradle
----------------------------------------------------------------------
diff --git a/beanmodel/build.gradle b/beanmodel/build.gradle
new file mode 100644
index 0000000..ccdeb37
--- /dev/null
+++ b/beanmodel/build.gradle
@@ -0,0 +1,27 @@
+import org.gradle.plugins.ide.idea.model.*
+import t5build.*
+
+description = "Fast class property discovery, reading and writing library based on bytecode generation. Extracted from Apache Tapestry, but not dependent on the Web framework (tapestry-core) not the IoC one (tapestry-ioc)."
+
+//apply plugin: JavaPlugin
+
+buildDir = 'target/gradle-build'
+       
+project.ext.libraryVersions = [
+	jcache: '1.0.0',
+]
+
+dependencies {
+	compile project(":plastic")
+	compile project(":tapestry5-annotations")
+	compile project(":commons")
+	// Transitive will bring in the unwanted string template library as well
+	compile "org.antlr:antlr-runtime:3.5.2", {
+		exclude group: "org.antlr", module: "stringtemplate"
+	}
+}
+
+jar {	
+	manifest {	
+	}
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit.java b/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit.java
new file mode 100644
index 0000000..3dbb0c0
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit.java
@@ -0,0 +1,45 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+
+/**
+ * Used to read or update the value associated with a property. A PropertyConduit provides access to the annotations on
+ * the underlying getter and/or setter methods.
+ */
+public interface PropertyConduit extends AnnotationProvider
+{
+    /**
+     * Reads the property from the instance.
+     *
+     * @param instance object containing the property
+     * @return the current value of the property
+     */
+    Object get(Object instance);
+
+    /**
+     * Changes the current value of the property.
+     *
+     * @param instance object containing the property
+     * @param value    to change the property to
+     */
+    void set(Object instance, Object value);
+
+    /**
+     * Returns the type of the property read or updated by the conduit.
+     */
+    Class getPropertyType();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit2.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit2.java b/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit2.java
new file mode 100644
index 0000000..839d70f
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit2.java
@@ -0,0 +1,40 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+
+import org.apache.tapestry5.services.PropertyConduitSource;
+
+
+/**
+ * Extension to {@link PropertyConduit} that adds a method to access the generic property type.
+ * {@link PropertyConduitSource} instances should ideally return PropertyConduit2 objects, not PropertyConduit.
+ * This is only primarily of interest to {@link Binding2}.
+ * 
+ * @since 5.4
+ */
+public interface PropertyConduit2 extends PropertyConduit
+{
+    /**
+     * Returns the generic type of the property
+     * 
+     * @see Method#getGenericReturnType()
+     * @see java.lang.reflect.Field#getGenericType()
+     * 
+     */
+	Type getPropertyGenericType();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModel.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModel.java b/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModel.java
new file mode 100644
index 0000000..0a60fd7
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModel.java
@@ -0,0 +1,169 @@
+// Copyright 2007, 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.beaneditor;
+
+import org.apache.tapestry5.PropertyConduit;
+
+import java.util.List;
+
+/**
+ * Provides the information necessary to build a user interface to view, create or edit an instance of a particular
+ * type.
+ * <p/>
+ * BeanModels are not thread-safe, they are also not serializable.
+ * <p/>
+ * Here, and in {@link org.apache.tapestry5.beaneditor.PropertyModel}, the term "propertyName" is used for simplicitly.
+ * However, a full {@linkplain org.apache.tapestry5.services.PropertyConduitSource#create(Class, String) property
+ * expression} may be utilized when {@linkplain #add(String) adding new properties to an existing BeanModel}.
+ *
+ * @see org.apache.tapestry5.services.BeanModelSource
+ */
+public interface BeanModel<T>
+{
+    /**
+     * Returns the type of bean for which this model was initially created.
+     */
+    Class<T> getBeanType();
+
+
+    /**
+     * Creates a new bean instance.  This is based on {@link org.apache.tapestry5.ioc.ObjectLocator#autobuild(Class)},
+     * so a public constructor will be used, and dependencies injected.
+     *
+     * @return new instance of the bean
+     */
+    T newInstance();
+
+    /**
+     * Returns a list of the editable properties of the bean, in <em>presentation</em> order.
+     */
+    List<String> getPropertyNames();
+
+    /**
+     * Returns the named model.
+     *
+     * @param propertyName name of property to retrieve model for (case is ignored)
+     * @return the model for the property
+     * @throws RuntimeException if the bean editor model does not have a property model for the provided name
+     */
+    PropertyModel get(String propertyName);
+
+    /**
+     * Returns the identified model.  Property ids are a stripped version of the property name. Case is ignored.
+     *
+     * @param propertyId matched caselessly against {@link org.apache.tapestry5.beaneditor.PropertyModel#getId()}
+     * @throws RuntimeException if the bean editor model does not have a property model with the indicated id
+     */
+    PropertyModel getById(String propertyId);
+
+    /**
+     * Adds a new property to the model, returning its mutable model for further refinement. The property is added to
+     * the <em>end</em> of the list of properties. The property must be real (but may have been excluded if there was no
+     * {@linkplain org.apache.tapestry5.beaneditor.DataType datatype} associated with the property). To add a synthetic
+     * property, use {@link #add(String, org.apache.tapestry5.PropertyConduit)}
+     *
+     * @param propertyName name of property to add
+     * @return the new property model (for further configuration)
+     * @throws RuntimeException if the property already exists
+     */
+    PropertyModel add(String propertyName);
+
+
+    /**
+     * Adds a new synthetic property to the model, returning its mutable model for further refinement. The property is added to
+     * the <em>end</em> of the list of properties.
+     *
+     * @param propertyName name of property to add
+     * @param expression   expression for the property
+     * @return the new property model (for further configuration)
+     * @throws RuntimeException if the property already exists
+     * @since 5.3
+     */
+    PropertyModel addExpression(String propertyName, String expression);
+
+    /**
+     * Adds an empty property (one with no property conduit).
+     *
+     * @param propertyName name of property to add
+     * @return the new property model (for further configuration)
+     * @throws RuntimeException if the property already exists
+     * @since 5.3
+     */
+    PropertyModel addEmpty(String propertyName);
+
+    /**
+     * Adds a new property to the model (as with {@link #add(String)}), ordered before or after an existing property.
+     *
+     * @param position             controls whether the new property is ordered before or after the existing property
+     * @param existingPropertyName the name of an existing property (this must exist)
+     * @param propertyName         the new property to add
+     * @return the new property model (for further configuration)
+     * @throws RuntimeException if the existing property does not exist, or if the new property already does exist
+     */
+    PropertyModel add(RelativePosition position, String existingPropertyName, String propertyName);
+
+    /**
+     * Adds a new property to the model, ordered before or after an existing property.
+     *
+     * @param position             controls whether the new property is ordered before or after the existing property
+     * @param existingPropertyName the name of an existing property (this must exist)
+     * @param propertyName         the new property to add
+     * @param conduit              conduit used to read or update the property; this may be null for a synthetic or
+     *                             placeholder property
+     * @return the new property model (for further configuration)
+     * @throws RuntimeException if the existing property does not exist, or if the new property already does exist
+     */
+    PropertyModel add(RelativePosition position, String existingPropertyName, String propertyName,
+                      PropertyConduit conduit);
+
+    /**
+     * Adds a new, synthetic property to the model, returning its mutable model for further refinement.
+     *
+     * @param propertyName name of property to add
+     * @param conduit      the conduit used to read or update the property; this may be null for a synthetic or
+     *                     placeholder property.  Instead of passing null, please invoke {@link #addEmpty(String)}.
+     * @return the model for the property
+     * @throws RuntimeException if the property already exists
+     * @see #addExpression(String, String)
+     */
+    PropertyModel add(String propertyName, PropertyConduit conduit);
+
+    /**
+     * Removes the named properties from the model, if present. It is not considered an error to remove a property that
+     * does not exist.
+     *
+     * @param propertyNames the names of properties to be removed (case insensitive)
+     * @return the model for further modifications
+     */
+    BeanModel<T> exclude(String... propertyNames);
+
+    /**
+     * Re-orders the properties of the model into the specified order. Existing properties that are not indicated are
+     * retained, but ordered to the end of the list.
+     *
+     * @param propertyNames property names in order they should be displayed (case insensitive)
+     * @return the model for further modifications
+     */
+    BeanModel<T> reorder(String... propertyNames);
+
+    /**
+     * Re-orders the properties of the model into the specified order. Existing properties that are not indicated are
+     * <<removed>>.
+     *
+     * @param propertyNames the names of properties to be retained
+     * @return the model for further modifications
+     */
+    BeanModel<T> include(String... propertyNames);
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/PropertyModel.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/PropertyModel.java b/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/PropertyModel.java
new file mode 100644
index 0000000..6095fb9
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/PropertyModel.java
@@ -0,0 +1,97 @@
+// 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.beaneditor;
+
+import org.apache.tapestry5.PropertyConduit;
+import org.apache.tapestry5.ioc.AnnotationProvider;
+
+/**
+ * Part of a {@link org.apache.tapestry5.beaneditor.BeanModel} that defines the attributes of a single property of a
+ * bean.
+ * <p/>
+ * <p/>
+ * A PropertyModel is also an {@link AnnotationProvider}, as long as the {@link org.apache.tapestry5.PropertyConduit} is
+ * non-null.  When there is no property conduit, then {@link org.apache.tapestry5.ioc.AnnotationProvider#getAnnotation(Class)}
+ * will return null.
+ */
+public interface PropertyModel extends AnnotationProvider
+{
+    /**
+     * Returns the name of the property (which may, in fact, be a property expression).
+     */
+    String getPropertyName();
+
+    /**
+     * Returns the id used to access other resources (this is based on the property name, but with any excess
+     * punctuation stripped out).
+     */
+    String getId();
+
+    /**
+     * Returns a user-presentable label for the property.
+     */
+    String getLabel();
+
+    /**
+     * Returns the type of the property.
+     */
+    Class getPropertyType();
+
+    /**
+     * Returns a logical name for the type of UI needed to view or edit the property. This is initially determined from
+     * the property type.
+     */
+    String getDataType();
+
+    /**
+     * Changes the data type for the property.
+     *
+     * @param dataType
+     * @return the property model, for further changes
+     */
+    PropertyModel dataType(String dataType);
+
+    /**
+     * Returns an object used to read or update the property. For virtual properties (properties that do not actually
+     * exist on the bean), the conduit may be null.
+     */
+    PropertyConduit getConduit();
+
+    /**
+     * Changes the label for the property to the provided value.
+     *
+     * @param label new label for property
+     * @return the property model, for further changes
+     */
+    PropertyModel label(String label);
+
+    /**
+     * Returns the containing model, often used for "fluent" construction of the model.
+     */
+    BeanModel model();
+
+    /**
+     * Returns true if the property can be used for sorting. By default, this is true only if the property type
+     * implements Comparable.
+     */
+    boolean isSortable();
+
+    /**
+     * Updates sortable and returns the model for further changes.
+     *
+     * @return the property model, for further changes
+     */
+    PropertyModel sortable(boolean sortable);
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalPropertyConduit.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalPropertyConduit.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalPropertyConduit.java
new file mode 100644
index 0000000..315b372
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalPropertyConduit.java
@@ -0,0 +1,37 @@
+// Copyright 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.internal;
+
+import org.apache.tapestry5.PropertyConduit2;
+
+
+/**
+ * Extension to {@link org.apache.tapestry5.PropertyConduit2} that adds a method to determine the name of the property.
+ * 
+ * @since 5.2.0
+ *
+ */
+public interface InternalPropertyConduit extends PropertyConduit2
+{
+    /**
+     * Returns the name of the property read or updated by the conduit or null. 
+     * If the expression points to a property on a bean (e.g. user.name) this method returns the last property in the chain. 
+     * Otherwise this method returns {@code null}.
+     * 
+     * @return property name or {@code null}
+     * 
+     */
+    String getPropertyName();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/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
new file mode 100644
index 0000000..26eb309
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
@@ -0,0 +1,289 @@
+// Copyright 2007, 2008, 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.internal.beaneditor;
+
+import org.apache.tapestry5.PropertyConduit;
+import org.apache.tapestry5.beaneditor.BeanModel;
+import org.apache.tapestry5.beaneditor.PropertyModel;
+import org.apache.tapestry5.beaneditor.RelativePosition;
+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.InternalUtils;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
+import org.apache.tapestry5.ioc.util.AvailableValues;
+import org.apache.tapestry5.ioc.util.UnknownValueException;
+import org.apache.tapestry5.plastic.PlasticUtils;
+import org.apache.tapestry5.services.PropertyConduitSource;
+
+import java.util.List;
+import java.util.Map;
+
+public class BeanModelImpl<T> implements BeanModel<T>
+{
+    private final Class<T> beanType;
+
+    private final PropertyConduitSource propertyConduitSource;
+
+    private final TypeCoercer typeCoercer;
+
+    private final Messages messages;
+
+    private final ObjectLocator locator;
+
+    private final Map<String, PropertyModel> properties = CollectionFactory.newCaseInsensitiveMap();
+
+    // The list of property names, in desired order (generally not alphabetical order).
+
+    private final List<String> propertyNames = CollectionFactory.newList();
+
+    private static PropertyConduit NULL_PROPERTY_CONDUIT = null;
+
+    public BeanModelImpl(Class<T> beanType, PropertyConduitSource propertyConduitSource, TypeCoercer typeCoercer,
+                         Messages messages, ObjectLocator locator)
+
+    {
+        this.beanType = beanType;
+        this.propertyConduitSource = propertyConduitSource;
+        this.typeCoercer = typeCoercer;
+        this.messages = messages;
+        this.locator = locator;
+    }
+
+    public Class<T> getBeanType()
+    {
+        return beanType;
+    }
+
+    public T newInstance()
+    {
+        return locator.autobuild("Instantiating new instance of " + beanType.getName(), beanType);
+    }
+
+    public PropertyModel add(String propertyName)
+    {
+        return addExpression(propertyName, propertyName);
+    }
+
+    public PropertyModel addEmpty(String propertyName)
+    {
+        return add(propertyName, NULL_PROPERTY_CONDUIT);
+    }
+
+    public PropertyModel addExpression(String propertyName, String expression)
+    {
+        PropertyConduit conduit = createConduit(expression);
+
+        return add(propertyName, conduit);
+
+    }
+
+    private void validateNewPropertyName(String propertyName)
+    {
+        assert InternalUtils.isNonBlank(propertyName);
+        if (properties.containsKey(propertyName))
+            throw new RuntimeException(String.format(
+                    "Bean editor model for %s already contains a property model for property '%s'.",
+                    beanType.getName(), propertyName));
+    }
+
+    public PropertyModel add(RelativePosition position, String existingPropertyName, String propertyName,
+                             PropertyConduit conduit)
+    {
+        assert position != null;
+        validateNewPropertyName(propertyName);
+
+        // Locate the existing one.
+
+        PropertyModel existing = get(existingPropertyName);
+
+        // Use the case normalized property name.
+
+        int pos = propertyNames.indexOf(existing.getPropertyName());
+
+        PropertyModel newModel = new PropertyModelImpl(this, propertyName, conduit, messages);
+
+        properties.put(propertyName, newModel);
+
+        int offset = position == RelativePosition.AFTER ? 1 : 0;
+
+        propertyNames.add(pos + offset, propertyName);
+
+        return newModel;
+    }
+
+    public PropertyModel add(RelativePosition position, String existingPropertyName, String propertyName)
+    {
+        PropertyConduit conduit = createConduit(propertyName);
+
+        return add(position, existingPropertyName, propertyName, conduit);
+    }
+
+    public PropertyModel add(String propertyName, PropertyConduit conduit)
+    {
+        validateNewPropertyName(propertyName);
+
+        PropertyModel propertyModel = new PropertyModelImpl(this, propertyName, conduit, messages);
+
+        properties.put(propertyName, propertyModel);
+
+        // Remember the order in which the properties were added.
+
+        propertyNames.add(propertyName);
+
+        return propertyModel;
+    }
+
+    private CoercingPropertyConduitWrapper createConduit(String propertyName)
+    {
+        return new CoercingPropertyConduitWrapper(propertyConduitSource.create(beanType, propertyName), typeCoercer);
+    }
+
+    public PropertyModel get(String propertyName)
+    {
+        PropertyModel propertyModel = properties.get(propertyName);
+
+        if (propertyModel == null)
+            throw new UnknownValueException(String.format(
+                    "Bean editor model for %s does not contain a property named '%s'.", beanType.getName(),
+                    propertyName), new AvailableValues("Defined properties", propertyNames));
+
+        return propertyModel;
+    }
+
+    public PropertyModel getById(String propertyId)
+    {
+        for (PropertyModel model : properties.values())
+        {
+            if (model.getId().equalsIgnoreCase(propertyId))
+                return model;
+        }
+
+        // Not found, so we throw an exception. A bit of work to set
+        // up the exception however.
+
+        List<String> ids = CollectionFactory.newList();
+
+        for (PropertyModel model : properties.values())
+        {
+            ids.add(model.getId());
+        }
+
+        throw new UnknownValueException(String.format(
+                "Bean editor model for %s does not contain a property with id '%s'.", beanType.getName(), propertyId),
+                new AvailableValues("Defined property ids", ids));
+    }
+
+    public List<String> getPropertyNames()
+    {
+        return CollectionFactory.newList(propertyNames);
+    }
+
+    public BeanModel<T> exclude(String... propertyNames)
+    {
+        for (String propertyName : propertyNames)
+        {
+            PropertyModel model = properties.get(propertyName);
+
+            if (model == null)
+                continue;
+
+            // De-referencing from the model is needed because the name provided may not be a
+            // case-exact match, so we get the normalized or canonical name from the model because
+            // that's the one in propertyNames.
+
+            this.propertyNames.remove(model.getPropertyName());
+
+            properties.remove(propertyName);
+        }
+
+        return this;
+    }
+
+    public BeanModel<T> reorder(String... propertyNames)
+    {
+        List<String> remainingPropertyNames = CollectionFactory.newList(this.propertyNames);
+        List<String> reorderedPropertyNames = CollectionFactory.newList();
+
+        for (String name : propertyNames)
+        {
+            PropertyModel model = get(name);
+
+            // Get the canonical form (which may differ from name in terms of case)
+            String canonical = model.getPropertyName();
+
+            reorderedPropertyNames.add(canonical);
+
+            remainingPropertyNames.remove(canonical);
+        }
+
+        this.propertyNames.clear();
+        this.propertyNames.addAll(reorderedPropertyNames);
+
+        // Any unspecified names are ordered to the end. Don't want them? Remove them instead.
+        this.propertyNames.addAll(remainingPropertyNames);
+
+        return this;
+    }
+
+    public BeanModel<T> include(String... propertyNames)
+    {
+        List<String> reorderedPropertyNames = CollectionFactory.newList();
+        Map<String, PropertyModel> reduced = CollectionFactory.newCaseInsensitiveMap();
+
+        for (String name : propertyNames)
+        {
+
+            PropertyModel model = get(name);
+
+            String canonical = model.getPropertyName();
+
+            reorderedPropertyNames.add(canonical);
+            reduced.put(canonical, model);
+
+        }
+
+        this.propertyNames.clear();
+        this.propertyNames.addAll(reorderedPropertyNames);
+
+        properties.clear();
+        properties.putAll(reduced);
+
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        StringBuilder builder = new StringBuilder("BeanModel[");
+        builder.append(PlasticUtils.toTypeName(beanType));
+
+        builder.append(" properties:");
+        String sep = "";
+
+        for (String name : propertyNames)
+        {
+            builder.append(sep);
+            builder.append(name);
+
+            sep = ", ";
+        }
+
+        builder.append("]");
+
+        return builder.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/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
new file mode 100644
index 0000000..703ce44
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
@@ -0,0 +1,139 @@
+// Copyright 2007, 2008, 2010, 2011, 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.internal.beaneditor;
+
+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.TapestryInternalUtils;
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.plastic.PlasticUtils;
+
+import java.lang.annotation.Annotation;
+
+@SuppressWarnings("all")
+public class PropertyModelImpl implements PropertyModel
+{
+    private final BeanModel model;
+
+    private final String name;
+
+    private final PropertyConduit conduit;
+
+    private final String id;
+
+    private String label;
+
+    private String dataType;
+
+    private boolean sortable;
+
+    public PropertyModelImpl(BeanModel model, String name, PropertyConduit conduit, Messages messages)
+    {
+        this.model = model;
+        this.name = name;
+        this.conduit = conduit;
+
+        id = TapestryInternalUtils.extractIdFromPropertyExpression(name);
+
+        label = TapestryInternalUtils.defaultLabel(id, messages, name);
+
+        // TAP5-2305
+        if (conduit != null)
+        {
+            Sortable sortableAnnotation = conduit.getAnnotation(Sortable.class);
+            if (sortableAnnotation != null)
+            {
+                sortable = sortableAnnotation.value();
+            }
+            else
+            {
+                // Primitive types need to be converted to wrapper types before checking to see
+                // if they are sortable.
+                Class wrapperType = PlasticUtils.toWrapperType(getPropertyType());
+                sortable = Comparable.class.isAssignableFrom(wrapperType);
+            }
+        }
+    }
+
+    public String getId()
+    {
+        return id;
+    }
+
+    public Class getPropertyType()
+    {
+        return conduit == null ? Object.class : conduit.getPropertyType();
+    }
+
+    public PropertyConduit getConduit()
+    {
+        return conduit;
+    }
+
+    public PropertyModel label(String label)
+    {
+        assert InternalUtils.isNonBlank(label);
+        this.label = label;
+
+        return this;
+    }
+
+    public String getLabel()
+    {
+        return label;
+    }
+
+    public String getPropertyName()
+    {
+        return name;
+    }
+
+    public BeanModel model()
+    {
+        return model;
+    }
+
+    public PropertyModel dataType(String dataType)
+    {
+        this.dataType = dataType;
+
+        return this;
+    }
+
+    public String getDataType()
+    {
+        return dataType;
+    }
+
+    public boolean isSortable()
+    {
+        return sortable;
+    }
+
+    public PropertyModel sortable(boolean sortable)
+    {
+        this.sortable = sortable;
+
+        return this;
+    }
+
+    public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+    {
+        return conduit == null ? null : conduit.getAnnotation(annotationClass);
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/beanmodel/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
new file mode 100644
index 0000000..4dbfb2d
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
@@ -0,0 +1,67 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.services;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import org.apache.tapestry5.PropertyConduit;
+import org.apache.tapestry5.PropertyConduit2;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
+
+public class CoercingPropertyConduitWrapper implements PropertyConduit2
+{
+    private final PropertyConduit conduit;
+
+    private final TypeCoercer coercer;
+
+    public CoercingPropertyConduitWrapper(final PropertyConduit conduit, final TypeCoercer coercer)
+    {
+        this.conduit = conduit;
+        this.coercer = coercer;
+    }
+
+    public Object get(Object instance)
+    {
+        return conduit.get(instance);
+    }
+
+    public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+    {
+        return conduit.getAnnotation(annotationClass);
+    }
+
+    public Class getPropertyType()
+    {
+        return conduit.getPropertyType();
+    }
+    
+    public Type getPropertyGenericType()
+    {
+    	if (conduit instanceof PropertyConduit2) {
+    		return ((PropertyConduit2) conduit).getPropertyGenericType();
+    	}
+    	return conduit.getPropertyType();
+    }
+
+    @SuppressWarnings("unchecked")
+    public void set(Object instance, Object value)
+    {
+        Object coerced = coercer.coerce(value, getPropertyType());
+
+        conduit.set(instance, coerced);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
new file mode 100644
index 0000000..1242031
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
@@ -0,0 +1,53 @@
+// Copyright 2007, 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.internal.services;
+
+import java.lang.annotation.Annotation;
+
+import org.apache.tapestry5.internal.InternalPropertyConduit;
+import org.apache.tapestry5.internal.util.IntegerRange;
+import org.apache.tapestry5.ioc.AnnotationProvider;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
+
+/**
+ * Companion class for {@link org.apache.tapestry5.PropertyConduit} instances created by the
+ * {@link org.apache.tapestry5.services.PropertyConduitSource}.
+ */
+@SuppressWarnings("all")
+public class PropertyConduitDelegate
+{
+    private final TypeCoercer typeCoercer;
+
+    public PropertyConduitDelegate(TypeCoercer typeCoercer)
+    {
+        this.typeCoercer = typeCoercer;
+    }
+
+    public final IntegerRange range(int from, int to)
+    {
+        return new IntegerRange(from, to);
+    }
+
+    public final <T> T coerce(Object value, Class<T> type)
+    {
+        return typeCoercer.coerce(value, type);
+    }
+
+    public final boolean invert(Object value)
+    {
+        return coerce(value, Boolean.class).equals(Boolean.FALSE);
+    }
+}


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

Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java
new file mode 100644
index 0000000..49b0b15
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java
@@ -0,0 +1,59 @@
+// 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.util.List;
+
+/**
+ * Chain of command for {@link org.apache.tapestry5.ioc.AnnotationProvider}.
+ */
+public class AnnotationProviderChain implements AnnotationProvider
+{
+    private final AnnotationProvider[] providers;
+
+    public AnnotationProviderChain(AnnotationProvider[] providers)
+    {
+        this.providers = providers;
+    }
+
+    /**
+     * Creates an AnnotationProvider from the list of providers.  Returns either an {@link AnnotationProviderChain} or
+     * the sole element in the list.
+     */
+    public static AnnotationProvider create(List<AnnotationProvider> providers)
+    {
+        int size = providers.size();
+
+        if (size == 1) return providers.get(0);
+
+        return new AnnotationProviderChain(providers.toArray(new AnnotationProvider[providers.size()]));
+    }
+
+    @Override
+    public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+    {
+        for (AnnotationProvider p : providers)
+        {
+            T result = p.getAnnotation(annotationClass);
+
+            if (result != null) return result;
+        }
+
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java
new file mode 100644
index 0000000..4a5dece
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java
@@ -0,0 +1,54 @@
+// Copyright 2006, 2007 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.ioc.internal.services;
+
+import org.apache.tapestry5.ioc.services.Coercion;
+
+/**
+ * Combines two coercions to create a coercion through an intermediate type.
+ *
+ * @param <S> The source (input) type
+ * @param <I> The intermediate type
+ * @param <T> The target (output) type
+ */
+public class CompoundCoercion<S, I, T> implements Coercion<S, T>
+{
+    private final Coercion<S, I> op1;
+
+    private final Coercion<I, T> op2;
+
+    public CompoundCoercion(Coercion<S, I> op1, Coercion<I, T> op2)
+    {
+        this.op1 = op1;
+        this.op2 = op2;
+    }
+
+    @Override
+    public T coerce(S input)
+    {
+        // Run the input through the first operation (S --> I), then run the result of that through
+        // the second operation (I --> T).
+
+        I intermediate = op1.coerce(input);
+
+        return op2.coerce(intermediate);
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%s, %s", op1, op2);
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
new file mode 100644
index 0000000..e92ef2d
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
@@ -0,0 +1,68 @@
+// Copyright 2006, 2007, 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.ioc.Messages;
+import org.apache.tapestry5.ioc.internal.util.MessagesImpl;
+import org.apache.tapestry5.ioc.services.Coercion;
+import org.apache.tapestry5.plastic.PlasticUtils;
+
+public class ServiceMessages
+{
+    private final static Messages MESSAGES = MessagesImpl.forClass(ServiceMessages.class);
+
+    private ServiceMessages()
+    {
+    }
+
+    public static String noSuchProperty(Class clazz, String propertyName)
+    {
+        return MESSAGES.format("no-such-property", clazz.getName(), propertyName);
+    }
+
+
+    public static String readFailure(String propertyName, Object instance, Throwable cause)
+    {
+        return MESSAGES.format("read-failure", propertyName, instance, cause);
+    }
+
+    public static String propertyTypeMismatch(String propertyName, Class sourceClass, Class propertyType,
+                                              Class expectedType)
+    {
+        return MESSAGES.format("property-type-mismatch", propertyName, sourceClass.getName(), propertyType.getName(),
+                expectedType.getName());
+    }
+
+    public static String shutdownListenerError(Object listener, Throwable cause)
+    {
+        return MESSAGES.format("shutdown-listener-error", listener, cause);
+    }
+
+    public static String failedCoercion(Object input, Class targetType, Coercion coercion, Throwable cause)
+    {
+        return MESSAGES.format("failed-coercion", String.valueOf(input), PlasticUtils.toTypeName(targetType),
+                coercion, cause);
+    }
+
+    public static String registryShutdown(String serviceId)
+    {
+        return MESSAGES.format("registry-shutdown", serviceId);
+    }
+
+    public static String serviceBuildFailure(String serviceId, Throwable cause)
+    {
+        return MESSAGES.format("service-build-failure", serviceId, cause);
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java
new file mode 100644
index 0000000..0769b7e
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java
@@ -0,0 +1,65 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.ioc.internal.services;
+
+import org.apache.tapestry5.ioc.Location;
+import org.apache.tapestry5.ioc.Resource;
+
+/**
+ * Implementation of {@link Location} used when the underlying resource isn't really known.
+ */
+public final class StringLocation implements Location
+{
+    private final String description;
+
+    private final int line;
+
+    public StringLocation(String description, int line)
+    {
+        this.description = description;
+        this.line = line;
+    }
+
+    @Override
+    public String toString()
+    {
+        return description;
+    }
+
+    /**
+     * Returns 0.
+     */
+    @Override
+    public int getColumn()
+    {
+        return 0;
+    }
+
+    @Override
+    public int getLine()
+    {
+        return line;
+    }
+
+    /**
+     * Returns null; we don't know where the file really is (it's probably a class on the class path).
+     */
+    @Override
+    public Resource getResource()
+    {
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
new file mode 100644
index 0000000..6481384
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
@@ -0,0 +1,508 @@
+// Copyright 2006, 2007, 2008, 2010, 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.func.F;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InheritanceSearch;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
+import org.apache.tapestry5.ioc.internal.util.LockSupport;
+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.AvailableValues;
+import org.apache.tapestry5.ioc.util.UnknownValueException;
+import org.apache.tapestry5.plastic.PlasticUtils;
+import org.apache.tapestry5.util.StringToEnumCoercion;
+
+import java.util.*;
+
+@SuppressWarnings("all")
+public class TypeCoercerImpl extends LockSupport implements TypeCoercer
+{
+    // Constructed from the service's configuration.
+
+    private final Map<Class, List<CoercionTuple>> sourceTypeToTuple = CollectionFactory.newMap();
+
+    /**
+     * A coercion to a specific target type. Manages a cache of coercions to specific types.
+     */
+    private class TargetCoercion
+    {
+        private final Class type;
+
+        private final Map<Class, Coercion> cache = CollectionFactory.newConcurrentMap();
+
+        TargetCoercion(Class type)
+        {
+            this.type = type;
+        }
+
+        void clearCache()
+        {
+            cache.clear();
+        }
+
+        Object coerce(Object input)
+        {
+            Class sourceType = input != null ? input.getClass() : Void.class;
+
+            if (type.isAssignableFrom(sourceType))
+            {
+                return input;
+            }
+
+            Coercion c = getCoercion(sourceType);
+
+            try
+            {
+                return type.cast(c.coerce(input));
+            } catch (Exception ex)
+            {
+                throw new RuntimeException(ServiceMessages.failedCoercion(input, type, c, ex), ex);
+            }
+        }
+
+        String explain(Class sourceType)
+        {
+            return getCoercion(sourceType).toString();
+        }
+
+        private Coercion getCoercion(Class sourceType)
+        {
+            Coercion c = cache.get(sourceType);
+
+            if (c == null)
+            {
+                c = findOrCreateCoercion(sourceType, type);
+                cache.put(sourceType, c);
+            }
+
+            return c;
+        }
+    }
+
+    /**
+     * Map from a target type to a TargetCoercion for that type.
+     */
+    private final Map<Class, TargetCoercion> typeToTargetCoercion = new WeakHashMap<Class, TargetCoercion>();
+
+    private static final Coercion NO_COERCION = new Coercion<Object, Object>()
+    {
+        @Override
+        public Object coerce(Object input)
+        {
+            return input;
+        }
+    };
+
+    private static final Coercion COERCION_NULL_TO_OBJECT = new Coercion<Void, Object>()
+    {
+        @Override
+        public Object coerce(Void input)
+        {
+            return null;
+        }
+
+        @Override
+        public String toString()
+        {
+            return "null --> null";
+        }
+    };
+
+    public TypeCoercerImpl(Collection<CoercionTuple> tuples)
+    {
+        for (CoercionTuple tuple : tuples)
+        {
+            Class key = tuple.getSourceType();
+
+            InternalCommonsUtils.addToMapList(sourceTypeToTuple, key, tuple);
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public Object coerce(Object input, Class targetType)
+    {
+        assert targetType != null;
+
+        Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
+
+        if (effectiveTargetType.isInstance(input))
+        {
+            return input;
+        }
+
+
+        return getTargetCoercion(effectiveTargetType).coerce(input);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <S, T> Coercion<S, T> getCoercion(Class<S> sourceType, Class<T> targetType)
+    {
+        assert sourceType != null;
+        assert targetType != null;
+
+        Class effectiveSourceType = PlasticUtils.toWrapperType(sourceType);
+        Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
+
+        if (effectiveTargetType.isAssignableFrom(effectiveSourceType))
+        {
+            return NO_COERCION;
+        }
+
+        return getTargetCoercion(effectiveTargetType).getCoercion(effectiveSourceType);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <S, T> String explain(Class<S> sourceType, Class<T> targetType)
+    {
+        assert sourceType != null;
+        assert targetType != null;
+
+        Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
+        Class effectiveSourceType = PlasticUtils.toWrapperType(sourceType);
+
+        // Is a coercion even necessary? Not if the target type is assignable from the
+        // input value.
+
+        if (effectiveTargetType.isAssignableFrom(effectiveSourceType))
+        {
+            return "";
+        }
+
+        return getTargetCoercion(effectiveTargetType).explain(effectiveSourceType);
+    }
+
+    private TargetCoercion getTargetCoercion(Class targetType)
+    {
+        try
+        {
+            acquireReadLock();
+
+            TargetCoercion tc = typeToTargetCoercion.get(targetType);
+
+            return tc != null ? tc : createAndStoreNewTargetCoercion(targetType);
+        } finally
+        {
+            releaseReadLock();
+        }
+    }
+
+    private TargetCoercion createAndStoreNewTargetCoercion(Class targetType)
+    {
+        try
+        {
+            upgradeReadLockToWriteLock();
+
+            // Inner check since some other thread may have beat us to it.
+
+            TargetCoercion tc = typeToTargetCoercion.get(targetType);
+
+            if (tc == null)
+            {
+                tc = new TargetCoercion(targetType);
+                typeToTargetCoercion.put(targetType, tc);
+            }
+
+            return tc;
+        } finally
+        {
+            downgradeWriteLockToReadLock();
+        }
+    }
+
+    @Override
+    public void clearCache()
+    {
+        try
+        {
+            acquireReadLock();
+
+            // There's no need to clear the typeToTargetCoercion map, as it is a WeakHashMap and
+            // will release the keys for classes that are no longer in existence. On the other hand,
+            // there's likely all sorts of references to unloaded classes inside each TargetCoercion's
+            // individual cache, so clear all those.
+
+            for (TargetCoercion tc : typeToTargetCoercion.values())
+            {
+                // Can tc ever be null?
+
+                tc.clearCache();
+            }
+        } finally
+        {
+            releaseReadLock();
+        }
+    }
+
+    /**
+     * Here's the real meat; we do a search of the space to find coercions, or a system of
+     * coercions, that accomplish
+     * the desired coercion.
+     * <p/>
+     * There's <strong>TREMENDOUS</strong> room to improve this algorithm. For example, inheritance lists could be
+     * cached. Further, there's probably more ways to early prune the search. However, even with dozens or perhaps
+     * hundreds of tuples, I suspect the search will still grind to a conclusion quickly.
+     * <p/>
+     * The order of operations should help ensure that the most efficient tuple chain is located. If you think about how
+     * tuples are added to the queue, there are two factors: size (the number of steps in the coercion) and
+     * "class distance" (that is, number of steps up the inheritance hiearchy). All the appropriate 1 step coercions
+     * will be considered first, in class distance order. Along the way, we'll queue up all the 2 step coercions, again
+     * in class distance order. By the time we reach some of those, we'll have begun queueing up the 3 step coercions, and
+     * so forth, until we run out of input tuples we can use to fabricate multi-step compound coercions, or reach a
+     * final response.
+     * <p/>
+     * This does create a good number of short lived temporary objects (the compound tuples), but that's what the GC is
+     * really good at.
+     *
+     * @param sourceType
+     * @param targetType
+     * @return coercer from sourceType to targetType
+     */
+    @SuppressWarnings("unchecked")
+    private Coercion findOrCreateCoercion(Class sourceType, Class targetType)
+    {
+        if (sourceType == Void.class)
+        {
+            return searchForNullCoercion(targetType);
+        }
+
+        // These are instance variables because this method may be called concurrently.
+        // On a true race, we may go to the work of seeking out and/or fabricating
+        // a tuple twice, but it's more likely that different threads are looking
+        // for different source/target coercions.
+
+        Set<CoercionTuple> consideredTuples = CollectionFactory.newSet();
+        LinkedList<CoercionTuple> queue = CollectionFactory.newLinkedList();
+
+        seedQueue(sourceType, targetType, consideredTuples, queue);
+
+        while (!queue.isEmpty())
+        {
+            CoercionTuple tuple = queue.removeFirst();
+
+            // If the tuple results in a value type that is assignable to the desired target type,
+            // we're done! Later, we may add a concept of "cost" (i.e. number of steps) or
+            // "quality" (how close is the tuple target type to the desired target type). Cost
+            // is currently implicit, as compound tuples are stored deeper in the queue,
+            // so simpler coercions will be located earlier.
+
+            Class tupleTargetType = tuple.getTargetType();
+
+            if (targetType.isAssignableFrom(tupleTargetType))
+            {
+                return tuple.getCoercion();
+            }
+
+            // So .. this tuple doesn't get us directly to the target type.
+            // However, it *may* get us part of the way. Each of these
+            // represents a coercion from the source type to an intermediate type.
+            // Now we're going to look for conversions from the intermediate type
+            // to some other type.
+
+            queueIntermediates(sourceType, targetType, tuple, consideredTuples, queue);
+        }
+
+        // Not found anywhere. Identify the source and target type and a (sorted) list of
+        // all the known coercions.
+
+        throw new UnknownValueException(String.format("Could not find a coercion from type %s to type %s.",
+                sourceType.getName(), targetType.getName()), buildCoercionCatalog());
+    }
+
+    /**
+     * Coercion from null is special; we match based on the target type and its not a spanning
+     * search. In many cases, we
+     * return a pass-thru that leaves the value as null.
+     *
+     * @param targetType
+     *         desired type
+     * @return the coercion
+     */
+    private Coercion searchForNullCoercion(Class targetType)
+    {
+        List<CoercionTuple> tuples = getTuples(Void.class, targetType);
+
+        for (CoercionTuple tuple : tuples)
+        {
+            Class tupleTargetType = tuple.getTargetType();
+
+            if (targetType.equals(tupleTargetType))
+                return tuple.getCoercion();
+        }
+
+        // Typical case: no match, this coercion passes the null through
+        // as null.
+
+        return COERCION_NULL_TO_OBJECT;
+    }
+
+    /**
+     * Builds a string listing all the coercions configured for the type coercer, sorted
+     * alphabetically.
+     */
+    @SuppressWarnings("unchecked")
+    private AvailableValues buildCoercionCatalog()
+    {
+        List<CoercionTuple> masterList = CollectionFactory.newList();
+
+        for (List<CoercionTuple> list : sourceTypeToTuple.values())
+        {
+            masterList.addAll(list);
+        }
+
+        return new AvailableValues("Configured coercions", masterList);
+    }
+
+    /**
+     * Seeds the pool with the initial set of coercions for the given type.
+     */
+    private void seedQueue(Class sourceType, Class targetType, Set<CoercionTuple> consideredTuples,
+                           LinkedList<CoercionTuple> queue)
+    {
+        // Work from the source type up looking for tuples
+
+        for (Class c : new InheritanceSearch(sourceType))
+        {
+            List<CoercionTuple> tuples = getTuples(c, targetType);
+
+            if (tuples == null)
+            {
+                continue;
+            }
+
+            for (CoercionTuple tuple : tuples)
+            {
+                queue.addLast(tuple);
+                consideredTuples.add(tuple);
+            }
+
+            // Don't pull in Object -> type coercions when doing
+            // a search from null.
+
+            if (sourceType == Void.class)
+            {
+                return;
+            }
+        }
+    }
+
+    /**
+     * Creates and adds to the pool a new set of coercions based on an intermediate tuple. Adds
+     * compound coercion tuples
+     * to the end of the queue.
+     *
+     * @param sourceType
+     *         the source type of the coercion
+     * @param targetType
+     *         TODO
+     * @param intermediateTuple
+     *         a tuple that converts from the source type to some intermediate type (that is not
+     *         assignable to the target type)
+     * @param consideredTuples
+     *         set of tuples that have already been added to the pool (directly, or as a compound
+     *         coercion)
+     * @param queue
+     *         the work queue of tuples
+     */
+    @SuppressWarnings("unchecked")
+    private void queueIntermediates(Class sourceType, Class targetType, CoercionTuple intermediateTuple,
+                                    Set<CoercionTuple> consideredTuples, LinkedList<CoercionTuple> queue)
+    {
+        Class intermediateType = intermediateTuple.getTargetType();
+
+        for (Class c : new InheritanceSearch(intermediateType))
+        {
+            for (CoercionTuple tuple : getTuples(c, targetType))
+            {
+                if (consideredTuples.contains(tuple))
+                {
+                    continue;
+                }
+
+                Class newIntermediateType = tuple.getTargetType();
+
+                // If this tuple is for coercing from an intermediate type back towards our
+                // initial source type, then ignore it. This should only be an optimization,
+                // as branches that loop back towards the source type will
+                // eventually be considered and discarded.
+
+                if (sourceType.isAssignableFrom(newIntermediateType))
+                {
+                    continue;
+                }
+
+                // The intermediateTuple coercer gets from S --> I1 (an intermediate type).
+                // The current tuple's coercer gets us from I2 --> X. where I2 is assignable
+                // from I1 (i.e., I2 is a superclass/superinterface of I1) and X is a new
+                // intermediate type, hopefully closer to our eventual target type.
+
+                Coercion compoundCoercer = new CompoundCoercion(intermediateTuple.getCoercion(), tuple.getCoercion());
+
+                CoercionTuple compoundTuple = new CoercionTuple(sourceType, newIntermediateType, compoundCoercer, false);
+
+                // So, every tuple that is added to the queue can take as input the sourceType.
+                // The target type may be another intermediate type, or may be something
+                // assignable to the target type, which will bring the search to a successful
+                // conclusion.
+
+                queue.addLast(compoundTuple);
+                consideredTuples.add(tuple);
+            }
+        }
+    }
+
+    /**
+     * Returns a non-null list of the tuples from the source type.
+     *
+     * @param sourceType
+     *         used to locate tuples
+     * @param targetType
+     *         used to add synthetic tuples
+     * @return non-null list of tuples
+     */
+    private List<CoercionTuple> getTuples(Class sourceType, Class targetType)
+    {
+        List<CoercionTuple> tuples = sourceTypeToTuple.get(sourceType);
+
+        if (tuples == null)
+        {
+            tuples = Collections.emptyList();
+        }
+
+        // So, when we see String and an Enum type, we add an additional synthetic tuple to the end
+        // of the real list. This is the easiest way to accomplish this is a thread-safe and class-reloading
+        // safe way (i.e., what if the Enum is defined by a class loader that gets discarded?  Don't want to cause
+        // memory leaks by retaining an instance). In any case, there are edge cases where we may create
+        // the tuple unnecessarily (such as when an explicit string-to-enum coercion is part of the TypeCoercer
+        // configuration), but on the whole, this is cheap and works.
+
+        if (sourceType == String.class && Enum.class.isAssignableFrom(targetType))
+        {
+            tuples = extend(tuples, new CoercionTuple(sourceType, targetType, new StringToEnumCoercion(targetType)));
+        }
+
+        return tuples;
+    }
+
+    private static <T> List<T> extend(List<T> list, T extraValue)
+    {
+        return F.flow(list).append(extraValue).toList();
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
new file mode 100644
index 0000000..f1830a7
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
@@ -0,0 +1,159 @@
+// Copyright 2006 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.util;
+
+import org.apache.tapestry5.plastic.PlasticUtils;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Set;
+
+/**
+ * Used to search from a particular class up the inheritance hierarchy of extended classes and implemented interfaces.
+ * <p/>
+ * The search starts with the initial class (provided in the constructor). It progresses up the inheritance chain, but
+ * skips java.lang.Object.
+ * <p/>
+ * Once classes are exhausted, the inheritance hierarchy is searched. This is a breadth-first search, rooted in the
+ * interfaces implemented by the initial class at its super classes.
+ * <p/>
+ * Once all interfaces are exhausted, java.lang.Object is returned (it is always returned last).
+ * <p/>
+ * Two minor tweak to normal inheritance rules: <ul> <li> Normally, the parent class of an <em>object</em> array is
+ * java.lang.Object, which is odd because FooService[] is assignable to Object[]. Thus, we tweak the search so that the
+ * effective super class of FooService[] is Object[]. <li> The "super class" of a primtive type is its <em>wrapper type</em>,
+ * with the exception of void, whose "super class" is left at its normal value (Object.class) </ul>
+ * <p/>
+ * This class implements the {@link Iterable} interface, so it can be used directly in a for loop: <code> for (Class
+ * search : new InheritanceSearch(startClass)) { ... } </code>
+ * <p/>
+ * This class is not thread-safe.
+ */
+public class InheritanceSearch implements Iterator<Class>, Iterable<Class>
+{
+    private Class searchClass;
+
+    private final Set<Class> addedInterfaces = CollectionFactory.newSet();
+
+    private final LinkedList<Class> interfaceQueue = CollectionFactory.newLinkedList();
+
+    private enum State
+    {
+        CLASS, INTERFACE, DONE
+    }
+
+    private State state;
+
+    public InheritanceSearch(Class searchClass)
+    {
+        this.searchClass = searchClass;
+
+        queueInterfaces(searchClass);
+
+        state = searchClass == Object.class ? State.INTERFACE : State.CLASS;
+    }
+
+    private void queueInterfaces(Class searchClass)
+    {
+        for (Class intf : searchClass.getInterfaces())
+        {
+            if (addedInterfaces.contains(intf)) continue;
+
+            interfaceQueue.addLast(intf);
+            addedInterfaces.add(intf);
+        }
+    }
+
+    @Override
+    public Iterator<Class> iterator()
+    {
+        return this;
+    }
+
+    @Override
+    public boolean hasNext()
+    {
+        return state != State.DONE;
+    }
+
+    @Override
+    public Class next()
+    {
+        switch (state)
+        {
+            case CLASS:
+
+                Class result = searchClass;
+
+                searchClass = parentOf(searchClass);
+
+                if (searchClass == null) state = State.INTERFACE;
+                else queueInterfaces(searchClass);
+
+                return result;
+
+            case INTERFACE:
+
+                if (interfaceQueue.isEmpty())
+                {
+                    state = State.DONE;
+                    return Object.class;
+                }
+
+                Class intf = interfaceQueue.removeFirst();
+
+                queueInterfaces(intf);
+
+                return intf;
+
+            default:
+                throw new IllegalStateException();
+        }
+
+    }
+
+    /**
+     * Returns the parent of the given class. Tweaks inheritance for object arrays. Returns null instead of
+     * Object.class.
+     */
+    private Class parentOf(Class clazz)
+    {
+        if (clazz != void.class && clazz.isPrimitive()) return PlasticUtils.toWrapperType(clazz);
+
+        if (clazz.isArray() && clazz != Object[].class)
+        {
+            Class componentType = clazz.getComponentType();
+
+            while (componentType.isArray()) componentType = componentType.getComponentType();
+
+            if (!componentType.isPrimitive()) return Object[].class;
+        }
+
+        Class parent = clazz.getSuperclass();
+
+        return parent != Object.class ? parent : null;
+    }
+
+    /**
+     * @throws UnsupportedOperationException
+     *         always
+     */
+    @Override
+    public void remove()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
new file mode 100644
index 0000000..3c391e0
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
@@ -0,0 +1,388 @@
+// Copyright 2006-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.util;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+import org.apache.tapestry5.ioc.Locatable;
+import org.apache.tapestry5.ioc.Location;
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
+
+/**
+ * Utility methods class for the Commons package.
+ */
+public class InternalCommonsUtils {
+
+	/**
+	 * @since 5.3
+	 */
+	public final static AnnotationProvider NULL_ANNOTATION_PROVIDER = new NullAnnotationProvider();
+	private static final Pattern NON_WORD_PATTERN = Pattern.compile("[^\\w]");
+
+    /**
+     * Adds a value to a specially organized map where the values are lists of objects. This somewhat simulates a map
+     * that allows multiple values for the same key.
+     *
+     * @param map
+     *         to store value into
+     * @param key
+     *         for which a value is added
+     * @param value
+     *         to add
+     * @param <K>
+     *         the type of key
+     * @param <V>
+     *         the type of the list
+     */
+    public static <K, V> void addToMapList(Map<K, List<V>> map, K key, V value)
+    {
+        List<V> list = map.get(key);
+
+        if (list == null)
+        {
+            list = CollectionFactory.newList();
+            map.put(key, list);
+        }
+
+        list.add(value);
+    }
+
+	/**
+	 * Sniffs the object to see if it is a {@link Location} or {@link Locatable}. Returns null if null or not
+	 * convertable to a location.
+	 */
+	
+	public static Location locationOf(Object location)
+	{
+	    if (location == null)
+	        return null;
+	
+	    if (location instanceof Location)
+	        return (Location) location;
+	
+	    if (location instanceof Locatable)
+	        return ((Locatable) location).getLocation();
+	
+	    return null;
+	}
+
+	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);
+	        }
+	    };
+	}
+
+	/**
+	 * 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(InternalCommonsUtils.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));
+	        }
+	    };
+	}
+
+	/**
+	 * Pattern used to eliminate leading and trailing underscores and dollar signs.
+	 */
+	static final Pattern NAME_PATTERN = Pattern.compile("^[_|$]*([\\p{javaJavaIdentifierPart}]+?)[_|$]*$",
+	        Pattern.CASE_INSENSITIVE);
+
+	/**
+	 * Converts a method to a user presentable string consisting of the containing class name, the method name, and the
+	 * short form of the parameter list (the class name of each parameter type, shorn of the package name portion).
+	 *
+	 * @param method
+	 * @return short string representation
+	 */
+	public static String asString(Method method)
+	{
+	    StringBuilder buffer = new StringBuilder();
+	
+	    buffer.append(method.getDeclaringClass().getName());
+	    buffer.append(".");
+	    buffer.append(method.getName());
+	    buffer.append("(");
+	
+	    for (int i = 0; i < method.getParameterTypes().length; i++)
+	    {
+	        if (i > 0)
+	            buffer.append(", ");
+	
+	        String name = method.getParameterTypes()[i].getSimpleName();
+	
+	        buffer.append(name);
+	    }
+	
+	    return buffer.append(")").toString();
+	}
+
+	/**
+	 * Strips leading "_" and "$" and trailing "_" from the name.
+	 */
+	public static String stripMemberName(String memberName)
+	{
+	    assert InternalCommonsUtils.isNonBlank(memberName);
+	    Matcher matcher = NAME_PATTERN.matcher(memberName);
+	
+	    if (!matcher.matches())
+	        throw new IllegalArgumentException(String.format("Input '%s' is not a valid Java identifier.", memberName));
+	
+	    return matcher.group(1);
+	}
+
+	/**
+	 * Joins together some number of elements to form a comma separated list.
+	 */
+	public static String join(List elements)
+	{
+	    return InternalCommonsUtils.join(elements, ", ");
+	}
+
+	/**
+	 * Joins together some number of elements. If a value in the list is the empty string, it is replaced with the
+	 * string "(blank)".
+	 *
+	 * @param elements
+	 *         objects to be joined together
+	 * @param separator
+	 *         used between elements when joining
+	 */
+	public static String join(List elements, String separator)
+	{
+	    switch (elements.size())
+	    {
+	        case 0:
+	            return "";
+	
+	        case 1:
+	            return elements.get(0).toString();
+	
+	        default:
+	
+	            StringBuilder buffer = new StringBuilder();
+	            boolean first = true;
+	
+	            for (Object o : elements)
+	            {
+	                if (!first)
+	                    buffer.append(separator);
+	
+	                String string = String.valueOf(o);
+	
+	                if (string.equals(""))
+	                    string = "(blank)";
+	
+	                buffer.append(string);
+	
+	                first = false;
+	            }
+	
+	            return buffer.toString();
+	    }
+	}
+
+	/**
+	 * Creates a sorted copy of the provided elements, then turns that into a comma separated list.
+	 *
+	 * @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
+	 *         empty
+	 */
+	public static String joinSorted(Collection elements)
+	{
+	    if (elements == null || elements.isEmpty())
+	        return "(none)";
+	
+	    List<String> list = CollectionFactory.newList();
+	
+	    for (Object o : elements)
+	        list.add(String.valueOf(o));
+	
+	    Collections.sort(list);
+	
+	    return join(list);
+	}
+
+	/**
+	 * Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
+	 */
+	
+	public static boolean isBlank(String input)
+	{
+	    return input == null || input.length() == 0 || input.trim().length() == 0;
+	}
+
+	/**
+	 * Capitalizes a string, converting the first character to uppercase.
+	 */
+	public static String capitalize(String input)
+	{
+	    if (input.length() == 0)
+	        return input;
+	
+	    return input.substring(0, 1).toUpperCase() + input.substring(1);
+	}
+
+	public static boolean isNonBlank(String input)
+	{
+	    return !isBlank(input);
+	}
+
+	/**
+	 * Return true if the input string contains the marker for symbols that must be expanded.
+	 */
+	public static boolean containsSymbols(String input)
+	{
+	    return input.contains("${");
+	}
+
+	/**
+	 * Searches the string for the final period ('.') character and returns everything after that. The input string is
+	 * generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
+	 * expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
+	 * character.
+	 */
+	public static String lastTerm(String input)
+	{
+	    assert isNonBlank(input);
+	    int dotx = input.lastIndexOf('.');
+	
+	    if (dotx < 0)
+	        return input;
+	
+	    return input.substring(dotx + 1);
+	}
+
+	/**
+	 * Extracts the string keys from a map and returns them in sorted order. The keys are converted to strings.
+	 *
+	 * @param map
+	 *         the map to extract keys from (may be null)
+	 * @return the sorted keys, or the empty set if map is null
+	 */
+	
+	public static List<String> sortedKeys(Map map)
+	{
+	    if (map == null)
+	        return Collections.emptyList();
+	
+	    List<String> keys = CollectionFactory.newList();
+	
+	    for (Object o : map.keySet())
+	        keys.add(String.valueOf(o));
+	
+	    Collections.sort(keys);
+	
+	    return keys;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java
deleted file mode 100644
index e345593..0000000
--- a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright 2006-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.util;
-
-import java.lang.reflect.Method;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * String-related utilities used within various internal implementations of the Apache Tapestry subprojects.
- * Broken off Tapestry-IoC's InternalUtils.
- */
-@SuppressWarnings("all")
-public class InternalStringUtils
-{
-	
-    /**
-     * Pattern used to eliminate leading and trailing underscores and dollar signs.
-     */
-    private static final Pattern NAME_PATTERN = Pattern.compile("^[_|$]*([\\p{javaJavaIdentifierPart}]+?)[_|$]*$",
-            Pattern.CASE_INSENSITIVE);
-
-    /**
-     * Converts a method to a user presentable string consisting of the containing class name, the method name, and the
-     * short form of the parameter list (the class name of each parameter type, shorn of the package name portion).
-     *
-     * @param method
-     * @return short string representation
-     */
-    public static String asString(Method method)
-    {
-        StringBuilder buffer = new StringBuilder();
-
-        buffer.append(method.getDeclaringClass().getName());
-        buffer.append(".");
-        buffer.append(method.getName());
-        buffer.append("(");
-
-        for (int i = 0; i < method.getParameterTypes().length; i++)
-        {
-            if (i > 0)
-                buffer.append(", ");
-
-            String name = method.getParameterTypes()[i].getSimpleName();
-
-            buffer.append(name);
-        }
-
-        return buffer.append(")").toString();
-    }
-
-    /**
-     * Strips leading "_" and "$" and trailing "_" from the name.
-     */
-    public static String stripMemberName(String memberName)
-    {
-        assert isNonBlank(memberName);
-        Matcher matcher = NAME_PATTERN.matcher(memberName);
-
-        if (!matcher.matches())
-            throw new IllegalArgumentException(String.format("Input '%s' is not a valid Java identifier.", memberName));
-
-        return matcher.group(1);
-    }
-
-    /**
-     * Joins together some number of elements to form a comma separated list.
-     */
-    public static String join(List elements)
-    {
-        return join(elements, ", ");
-    }
-
-    /**
-     * Joins together some number of elements. If a value in the list is the empty string, it is replaced with the
-     * string "(blank)".
-     *
-     * @param elements
-     *         objects to be joined together
-     * @param separator
-     *         used between elements when joining
-     */
-    public static String join(List elements, String separator)
-    {
-        switch (elements.size())
-        {
-            case 0:
-                return "";
-
-            case 1:
-                return elements.get(0).toString();
-
-            default:
-
-                StringBuilder buffer = new StringBuilder();
-                boolean first = true;
-
-                for (Object o : elements)
-                {
-                    if (!first)
-                        buffer.append(separator);
-
-                    String string = String.valueOf(o);
-
-                    if (string.equals(""))
-                        string = "(blank)";
-
-                    buffer.append(string);
-
-                    first = false;
-                }
-
-                return buffer.toString();
-        }
-    }
-
-    /**
-     * Creates a sorted copy of the provided elements, then turns that into a comma separated list.
-     *
-     * @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
-     *         empty
-     */
-    public static String joinSorted(Collection elements)
-    {
-        if (elements == null || elements.isEmpty())
-            return "(none)";
-
-        List<String> list = CollectionFactory.newList();
-
-        for (Object o : elements)
-            list.add(String.valueOf(o));
-
-        Collections.sort(list);
-
-        return join(list);
-    }
-
-    /**
-     * Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
-     */
-
-    public static boolean isBlank(String input)
-    {
-        return input == null || input.length() == 0 || input.trim().length() == 0;
-    }
-
-    public static boolean isNonBlank(String input)
-    {
-        return !isBlank(input);
-    }
-
-    /**
-     * Capitalizes a string, converting the first character to uppercase.
-     */
-    public static String capitalize(String input)
-    {
-        if (input.length() == 0)
-            return input;
-
-        return input.substring(0, 1).toUpperCase() + input.substring(1);
-    }
-
-    /**
-     * Return true if the input string contains the marker for symbols that must be expanded.
-     */
-    public static boolean containsSymbols(String input)
-    {
-        return input.contains("${");
-    }
-
-    /**
-     * Searches the string for the final period ('.') character and returns everything after that. The input string is
-     * generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
-     * expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
-     * character.
-     */
-    public static String lastTerm(String input)
-    {
-        assert isNonBlank(input);
-        int dotx = input.lastIndexOf('.');
-
-        if (dotx < 0)
-            return input;
-
-        return input.substring(dotx + 1);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
new file mode 100644
index 0000000..41de363
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
@@ -0,0 +1,89 @@
+// Copyright 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.util;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * Base class for classes that need to manage a ReadWriteLock.
+ */
+public abstract class LockSupport
+{
+    private final Lock readLock, writeLock;
+
+    protected LockSupport()
+    {
+        ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
+
+        readLock = lock.readLock();
+        writeLock = lock.writeLock();
+    }
+
+    /**
+     * Locks the shared read lock. Any number of threads may lock the read lock at the same time.
+     */
+    protected final void acquireReadLock()
+    {
+        readLock.lock();
+    }
+
+    /**
+     * Takes the exclusive write lock. Once started, no other thread lock the read or write lock. When this method returns,
+     * this thread will have locked the write lock and no other thread will have either the read or write lock.
+     * Note that this thread must first drop the read lock (if it has it) before attempting to take the write lock, or this method will block forever.
+     */
+    protected final void takeWriteLock()
+    {
+        writeLock.lock();
+    }
+
+    /**
+     * Releases the shared read lock.
+     */
+    protected final void releaseReadLock()
+    {
+        readLock.unlock();
+    }
+
+    /**
+     * Releases the  exclusive read lock.
+     */
+    protected final void releaseWriteLock()
+    {
+        writeLock.unlock();
+    }
+
+    /**
+     * Releases the read lock, then takes the write lock. There's a short window where the thread will have neither lock:
+     * during that window, some other thread may have a chance to take the write lock. In code, you'll often see a second check
+     * inside the code that has the write lock to see if the update to perform is still necessary.
+     */
+    protected final void upgradeReadLockToWriteLock()
+    {
+        releaseReadLock();
+        // This is that instant where another thread may grab the write lock. Very rare, but possible.
+        takeWriteLock();
+    }
+
+    /**
+     * Takes the read lock then releases the write lock.
+     */
+    protected final void downgradeWriteLockToReadLock()
+    {
+        acquireReadLock();
+        releaseWriteLock();
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java
new file mode 100644
index 0000000..f4d8949
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java
@@ -0,0 +1,65 @@
+// 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.util;
+
+import org.apache.tapestry5.ioc.MessageFormatter;
+import org.apache.tapestry5.ioc.util.ExceptionUtils;
+
+import java.util.Locale;
+
+
+public class MessageFormatterImpl implements MessageFormatter
+{
+    private final String format;
+
+    private final Locale locale;
+
+    public MessageFormatterImpl(String format, Locale locale)
+    {
+        this.format = format;
+        this.locale = locale;
+    }
+
+    @Override
+    public String format(Object... args)
+    {
+        for (int i = 0; i < args.length; i++)
+        {
+            Object arg = args[i];
+
+            if (Throwable.class.isInstance(arg))
+            {
+                args[i] = ExceptionUtils.toMessage((Throwable) arg);
+            }
+        }
+
+        // Might be tempting to create a Formatter object and just keep reusing it ... but
+        // Formatters are not threadsafe.
+
+        return String.format(locale, format, args);
+    }
+
+    /**
+     * Returns the underlying format string for this formatter.
+     *
+     * @since 5.4
+     */
+    @Override
+    public String toString()
+    {
+        return format;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
new file mode 100644
index 0000000..c06ef90
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
@@ -0,0 +1,74 @@
+// Copyright 2006, 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.util;
+
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.util.AbstractMessages;
+
+import java.util.*;
+
+/**
+ * Implementation of {@link org.apache.tapestry5.ioc.Messages} based around a {@link java.util.ResourceBundle}.
+ */
+public class MessagesImpl extends AbstractMessages
+{
+    private final Map<String, String> properties = CollectionFactory.newCaseInsensitiveMap();
+
+    /**
+     * Finds the messages for a given Messages utility class. Strings the trailing "Messages" and replaces it with
+     * "Strings" to form the base path. Loads the bundle using the default locale, and the class' class loader.
+     *
+     * @param forClass
+     * @return Messages for the class
+     */
+    public static Messages forClass(Class forClass)
+    {
+        String className = forClass.getName();
+        String stringsClassName = className.replaceAll("Messages$", "Strings");
+
+        Locale locale = Locale.getDefault();
+
+        ResourceBundle bundle = ResourceBundle.getBundle(stringsClassName, locale, forClass.getClassLoader());
+
+        return new MessagesImpl(locale, bundle);
+    }
+
+    public MessagesImpl(Locale locale, ResourceBundle bundle)
+    {
+        super(locale);
+
+        // Our best (threadsafe) chance to determine all the available keys.
+        Enumeration<String> e = bundle.getKeys();
+        while (e.hasMoreElements())
+        {
+            String key = e.nextElement();
+            String value = bundle.getString(key);
+
+            properties.put(key, value);
+        }
+    }
+
+    @Override
+    protected String valueForKey(String key)
+    {
+        return properties.get(key);
+    }
+
+    @Override
+    public Set<String> getKeys()
+    {
+        return properties.keySet();
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
index d8d8018..6e23c5b 100644
--- a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
@@ -34,7 +34,7 @@ public class TapestryException extends RuntimeException implements Locatable
      */
     public TapestryException(String message, Object location, Throwable cause)
     {
-        this(message, locationOf(location), cause);
+        this(message, InternalCommonsUtils.locationOf(location), cause);
     }
 
     /**
@@ -71,26 +71,5 @@ public class TapestryException extends RuntimeException implements Locatable
 
         return String.format("%s [at %s]", super.toString(), location);
     }
-    
-    /**
-     * Sniffs the object to see if it is a {@link Location} or {@link Locatable}. Returns null if null or not
-     * convertable to a location.
-     * Copied from InternalUtils to avoid having it moved to BeanModel or Commons subprojects.
-     */
-
-    private static Location locationOf(Object location)
-    {
-        if (location == null)
-            return null;
-
-        if (location instanceof Location)
-            return (Location) location;
-
-        if (location instanceof Locatable)
-            return ((Locatable) location).getLocation();
-
-        return null;
-    }
-
 
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java
new file mode 100644
index 0000000..590c337
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java
@@ -0,0 +1,94 @@
+// Copyright 2006, 2009, 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.util;
+
+import org.apache.tapestry5.ioc.MessageFormatter;
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.MessageFormatterImpl;
+
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Abstract implementation of {@link Messages} that doesn't know where values come from (that information is supplied in
+ * a subclass, via the {@link #valueForKey(String)} method).
+ */
+public abstract class AbstractMessages implements Messages
+{
+    /**
+     * String key to MF instance.
+     */
+    private final Map<String, MessageFormatter> cache = CollectionFactory.newConcurrentMap();
+
+    private final Locale locale;
+
+    protected AbstractMessages(Locale locale)
+    {
+        this.locale = locale;
+    }
+
+    /**
+     * Invoked to provide the value for a particular key. This may be invoked multiple times even for the same key. The
+     * implementation should <em>ignore the case of the key</em>.
+     *
+     * @param key the key to obtain a value for (case insensitive)
+     * @return the value for the key, or null if this instance can not provide the value
+     */
+    protected abstract String valueForKey(String key);
+
+
+    @Override
+    public boolean contains(String key)
+    {
+        return valueForKey(key) != null;
+    }
+
+    @Override
+    public String get(String key)
+    {
+        if (contains(key)) return valueForKey(key);
+
+        return String.format("[[missing key: %s]]", key);
+    }
+
+    @Override
+    public MessageFormatter getFormatter(String key)
+    {
+        MessageFormatter result = cache.get(key);
+
+        if (result == null)
+        {
+            result = buildMessageFormatter(key);
+            cache.put(key, result);
+        }
+
+        return result;
+    }
+
+    private MessageFormatter buildMessageFormatter(String key)
+    {
+        String format = get(key);
+
+        return new MessageFormatterImpl(format, locale);
+    }
+
+    @Override
+    public String format(String key, Object... args)
+    {
+        return getFormatter(key).format(args);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
index 8c9cb3f..b2f1386 100644
--- a/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
@@ -20,7 +20,7 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
 
 /**
  * Used (as part of a {@link UnknownValueException} to identify what available values
@@ -81,7 +81,7 @@ public class AvailableValues
     @Override
     public String toString()
     {
-        return String.format("AvailableValues[%s: %s]", valueType, InternalStringUtils.join(values));
+        return String.format("AvailableValues[%s: %s]", valueType, InternalCommonsUtils.join(values));
     }
 
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java
new file mode 100644
index 0000000..01ef99e
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java
@@ -0,0 +1,195 @@
+// Copyright 2007, 2008, 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.util;
+
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
+
+/**
+ * Used to represent a period of time, specifically as a configuration value. This is often used to specify timeouts.
+ * <p/>
+ * TimePeriods are parsed from strings.
+ * <p/>
+ * The string specifys a number of terms. The values of all the terms are summed together to form the total time period.
+ * Each term consists of a number followed by a unit. Units (from largest to smallest) are: <dl> <dt>y <dd>year <dt>d
+ * <dd>day <dt>h <dd>hour <dt>m <dd>minute <dt>s <dd>second <dt>ms <dd>millisecond </dl> <p>  Example: "2 h 30 m". By
+ * convention, terms are specified largest to smallest.  A term without a unit is assumed to be milliseconds.  Units are
+ * case insensitive ("h" or "H" are treated the same).
+ */
+public class TimeInterval
+{
+    private static final Map<String, Long> UNITS = CollectionFactory.newCaseInsensitiveMap();
+
+    private static final long MILLISECOND = 1000l;
+
+    static
+    {
+        UNITS.put("ms", 1l);
+        UNITS.put("s", MILLISECOND);
+        UNITS.put("m", 60 * MILLISECOND);
+        UNITS.put("h", 60 * UNITS.get("m"));
+        UNITS.put("d", 24 * UNITS.get("h"));
+        UNITS.put("y", 365 * UNITS.get("d"));
+    }
+
+    /**
+     * The unit keys, sorted in descending order.
+     */
+    private static final String[] UNIT_KEYS =
+    { "y", "d", "h", "m", "s", "ms" };
+
+    private static final Pattern PATTERN = Pattern.compile("\\s*(\\d+)\\s*([a-z]*)", Pattern.CASE_INSENSITIVE);
+
+    private final long milliseconds;
+
+    /**
+     * Creates a TimeInterval for a string.
+     * 
+     * @param input
+     *            the string specifying the amount of time in the period
+     */
+    public TimeInterval(String input)
+    {
+        this(parseMilliseconds(input));
+    }
+
+    public TimeInterval(long milliseconds)
+    {
+        this.milliseconds = milliseconds;
+    }
+
+    public long milliseconds()
+    {
+        return milliseconds;
+    }
+
+    public long seconds()
+    {
+        return milliseconds / MILLISECOND;
+    }
+
+    /**
+     * Converts the milliseconds back into a string (compatible with {@link #TimeInterval(String)}).
+     * 
+     * @since 5.2.0
+     */
+    public String toDescription()
+    {
+        StringBuilder builder = new StringBuilder();
+
+        String sep = "";
+
+        long remainder = milliseconds;
+
+        for (String key : UNIT_KEYS)
+        {
+            if (remainder == 0)
+                break;
+
+            long value = UNITS.get(key);
+
+            long units = remainder / value;
+
+            if (units > 0)
+            {
+                builder.append(sep);
+                builder.append(units);
+                builder.append(key);
+
+                sep = " ";
+
+                remainder = remainder % value;
+            }
+        }
+
+        return builder.toString();
+    }
+
+    static long parseMilliseconds(String input)
+    {
+        long milliseconds = 0l;
+
+        Matcher matcher = PATTERN.matcher(input);
+
+        matcher.useAnchoringBounds(true);
+
+        // TODO: Notice non matching characters and reject input, including at end
+
+        int lastMatchEnd = -1;
+
+        while (matcher.find())
+        {
+            int start = matcher.start();
+
+            if (lastMatchEnd + 1 < start)
+            {
+                String invalid = input.substring(lastMatchEnd + 1, start);
+                throw new RuntimeException(String.format("Unexpected string '%s' (in time interval '%s').", invalid, input));
+            }
+
+            lastMatchEnd = matcher.end();
+
+            long count = Long.parseLong(matcher.group(1));
+            String units = matcher.group(2);
+
+            if (units.length() == 0)
+            {
+                milliseconds += count;
+                continue;
+            }
+
+            Long unitValue = UNITS.get(units);
+
+            if (unitValue == null)
+                throw new RuntimeException(String.format("Unknown time interval unit '%s' (in '%s').  Defined units: %s.", units, input, InternalCommonsUtils.joinSorted(UNITS.keySet())));
+
+            milliseconds += count * unitValue;
+        }
+
+        if (lastMatchEnd + 1 < input.length())
+        {
+            String invalid = input.substring(lastMatchEnd + 1);
+            throw new RuntimeException(String.format("Unexpected string '%s' (in time interval '%s').", invalid, input));
+        }
+
+        return milliseconds;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("TimeInterval[%d ms]", milliseconds);
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (obj == null)
+            return false;
+
+        if (obj instanceof TimeInterval)
+        {
+            TimeInterval tp = (TimeInterval) obj;
+
+            return milliseconds == tp.milliseconds;
+        }
+
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java b/commons/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java
new file mode 100644
index 0000000..bdde866
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java
@@ -0,0 +1,91 @@
+// Copyright 2007, 2008, 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.util;
+
+import java.util.Map;
+
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
+import org.apache.tapestry5.ioc.services.Coercion;
+import org.apache.tapestry5.ioc.util.AvailableValues;
+import org.apache.tapestry5.ioc.util.UnknownValueException;
+
+/**
+ * A {@link org.apache.tapestry5.ioc.services.Coercion} for converting strings into an instance of a particular
+ * enumerated type. The {@link Enum#name() name} is used as the key to identify the enum instance, in a case-insensitive
+ * fashion.
+ * <p>
+ * Moved from tapestry-core to tapestry-ioc is release 5.3, but kept in same package for compatibility.
+ * 
+ * @param <T>
+ *            the type of enumeration
+ */
+public final class StringToEnumCoercion<T extends Enum> implements Coercion<String, T>
+{
+    private final Class<T> enumClass;
+
+    private final Map<String, T> stringToEnum = CollectionFactory.newCaseInsensitiveMap();
+
+    public StringToEnumCoercion(Class<T> enumClass)
+    {
+        this(enumClass, enumClass.getEnumConstants());
+    }
+
+    public StringToEnumCoercion(Class<T> enumClass, T... values)
+    {
+        this.enumClass = enumClass;
+
+        for (T value : values)
+            stringToEnum.put(value.name(), value);
+    }
+
+    @Override
+    public T coerce(String input)
+    {
+        if (InternalCommonsUtils.isBlank(input))
+            return null;
+
+        T result = stringToEnum.get(input);
+
+        if (result == null)
+        {
+            String message = String.format("Input '%s' does not identify a value from enumerated type %s.", input,
+                    enumClass.getName());
+
+            throw new UnknownValueException(message, new AvailableValues(enumClass.getName() + " enum constants",
+                    stringToEnum));
+        }
+
+        return result;
+    }
+
+    /**
+     * Allows an alias value (alternate) string to reference a value.
+     * 
+     * @since 5.2.2
+     */
+    public StringToEnumCoercion<T> addAlias(String alias, T value)
+    {
+        stringToEnum.put(alias, value);
+
+        return this;
+    }
+
+    public static <T extends Enum> StringToEnumCoercion<T> create(Class<T> enumClass)
+    {
+        return new StringToEnumCoercion<T>(enumClass);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
index e69377f..e032975 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
@@ -59,7 +59,7 @@ public class TapestryInternalUtils
      */
     public static String toUserPresentable(String id)
     {
-        return InternalBeanModelUtils.toUserPresentable(id);
+        return InternalUtils.toUserPresentable(id);
     }
 
     public static Map<String, String> mapFromKeysAndValues(String... keysAndValues)
@@ -228,7 +228,7 @@ public class TapestryInternalUtils
      */
     public static String extractIdFromPropertyExpression(String expression)
     {
-        return InternalBeanModelUtils.extractIdFromPropertyExpression(expression);
+        return InternalUtils.extractIdFromPropertyExpression(expression);
     }
 
     /**
@@ -237,7 +237,7 @@ public class TapestryInternalUtils
      */
     public static String defaultLabel(String id, Messages messages, String propertyExpression)
     {
-        return InternalBeanModelUtils.defaultLabel(id, messages, propertyExpression);
+        return InternalUtils.defaultLabel(id, messages, propertyExpression);
     }
 
     /**
@@ -304,7 +304,7 @@ public class TapestryInternalUtils
 
     private static String replace(String input, Pattern pattern, String replacement)
     {
-        return InternalBeanModelUtils.replace(input, pattern, replacement);
+        return InternalUtils.replace(input, pattern, replacement);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java
deleted file mode 100644
index 43519dc..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java
+++ /dev/null
@@ -1,53 +0,0 @@
-// 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/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Configuration.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Configuration.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Configuration.java
deleted file mode 100644
index 03814f5..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Configuration.java
+++ /dev/null
@@ -1,53 +0,0 @@
-// 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/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java
deleted file mode 100644
index 47c6026..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java
+++ /dev/null
@@ -1,81 +0,0 @@
-// 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);
-}


[08/15] tapestry-5 git commit: Second pass creating the BeanModel and Commons packages.

Posted by th...@apache.org.
Second 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/1f36bb20
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/1f36bb20
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/1f36bb20

Branch: refs/heads/beanmodel-split
Commit: 1f36bb203cb0646f912125caa3bd03707aa95083
Parents: f963c7a
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Sat Dec 6 16:40:55 2014 -0200
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Sat Dec 6 16:40:55 2014 -0200

----------------------------------------------------------------------
 .../internal/antlr/PropertyExpressionLexer.g    | 163 +++++++++++++++++
 .../internal/antlr/PropertyExpressionParser.g   | 105 +++++++++++
 .../tapestry5/internal/antlr/BaseLexer.java     |  54 ++++++
 .../tapestry5/internal/antlr/BaseParser.java    |  40 +++++
 .../tapestry5/internal/antlr/package-info.java  |  18 ++
 .../tapestry5/internal/services/Invariant.java  |  28 +++
 .../services/LiteralPropertyConduit.java        |  85 +++++++++
 .../services/PropertyExpressionException.java   |  38 ++++
 .../internal/services/StringInterner.java       |  43 +++++
 .../org/apache/tapestry5/ioc/ObjectCreator.java |  27 +++
 .../ioc/services/PlasticProxyFactory.java       | 159 +++++++++++++++++
 .../org/apache/tapestry5/ioc/util/Stack.java    | 173 +++++++++++++++++++
 .../internal/antlr/PropertyExpressionLexer.g    | 163 -----------------
 .../internal/antlr/PropertyExpressionParser.g   | 105 -----------
 .../tapestry5/internal/antlr/BaseLexer.java     |  54 ------
 .../tapestry5/internal/antlr/BaseParser.java    |  40 -----
 .../tapestry5/internal/antlr/package-info.java  |  18 --
 .../tapestry5/internal/services/Invariant.java  |  28 ---
 .../services/LiteralPropertyConduit.java        |  85 ---------
 .../services/PropertyExpressionException.java   |  38 ----
 .../internal/services/StringInterner.java       |  43 -----
 .../org/apache/tapestry5/ioc/ObjectCreator.java |  27 ---
 .../ioc/annotations/IncompatibleChange.java     |  33 ----
 .../ioc/services/PlasticProxyFactory.java       | 159 -----------------
 .../org/apache/tapestry5/ioc/util/Stack.java    | 173 -------------------
 .../ioc/annotations/IncompatibleChange.java     |  33 ++++
 26 files changed, 966 insertions(+), 966 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g b/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g
new file mode 100644
index 0000000..3b52ba9
--- /dev/null
+++ b/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g
@@ -0,0 +1,163 @@
+// Copyright 2008, 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.
+
+lexer grammar PropertyExpressionLexer;
+
+
+options
+{
+  superClass='org.apache.tapestry5.internal.antlr.BaseLexer';
+}
+
+@header
+{
+package org.apache.tapestry5.internal.antlr;
+}
+
+	
+// Integer constant
+fragment INTEGER
+	:	{this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};	
+	
+// Read a property or invoke a method.
+fragment DEREF 
+	:	{this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};	
+	
+// Range operator, ".." between two integers.	
+fragment RANGEOP
+	:	{this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};	
+	
+// Decimal number	
+fragment DECIMAL
+	:	{this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};	
+			
+fragment LETTER 
+	:	('a'..'z'|'A'..'Z');
+fragment DIGIT 
+	:	'0'..'9';	
+fragment SIGN
+	:	('+'|'-');
+LPAREN 	:	'(';
+RPAREN 	:	')';
+LBRACKET:	'[';
+RBRACKET:	']';
+COMMA	:	',';
+BANG	:	'!';
+LBRACE	:	'{';
+RBRACE	:	'}';
+COLON	:	':';
+
+fragment QUOTE
+	:	'\'';
+
+// Clumsy but effective approach to case-insensitive identifiers.
+
+fragment A
+	:	('a' | 'A');
+fragment E
+	:	('e' | 'E');
+fragment F
+	:	('f' | 'F');	
+fragment H
+	:	('h' | 'H');
+fragment I
+	:	('i' | 'I');
+fragment L 
+	: 	('l' | 'L');
+fragment N 
+	:	('n'|'N');
+fragment R
+	:	('r' | 'R');
+fragment S
+	:	('s' | 'S');
+fragment T 
+	:	('t' | 'T');
+fragment U 
+	:	('u' | 'U');
+
+// Identifiers are case insensitive
+
+NULL 	:	N U L L;
+TRUE	:	T R U E;
+FALSE	:	F A L S E;
+THIS	:	T H I S;
+
+IDENTIFIER 
+    :   JAVA_ID_START (JAVA_ID_PART)*
+    ;
+
+fragment
+JAVA_ID_START
+    :  '\u0024'
+    |  '\u0041'..'\u005a'
+    |  '\u005f'
+    |  '\u0061'..'\u007a'
+    |  '\u00c0'..'\u00d6'
+    |  '\u00d8'..'\u00f6'
+    |  '\u00f8'..'\u00ff'
+    |  '\u0100'..'\u1fff'
+    |  '\u3040'..'\u318f'
+    |  '\u3300'..'\u337f'
+    |  '\u3400'..'\u3d2d'
+    |  '\u4e00'..'\u9fff'
+    |  '\uf900'..'\ufaff'
+    ;
+
+fragment
+JAVA_ID_PART
+    :  JAVA_ID_START
+    |  '\u0030'..'\u0039'
+    ;
+
+
+// The Safe Dereference operator understands not to de-reference through
+// a null.
+
+SAFEDEREF 
+	: 	'?.';
+
+WS 	:	(' '|'\t'|'\n'|'\r')+ { skip(); };
+
+
+// Literal strings are always inside single quotes.
+STRING
+	:	QUOTE (options {greedy=false;} : .)* QUOTE { setText(getText().substring(1, getText().length()-1)); };
+
+
+// Special rule that uses parsing tricks to identify numbers and ranges; it's all about
+// the dot ('.').
+// Recognizes:
+// '.' as DEREF
+// '..' as RANGEOP
+// INTEGER (sign? digit+)
+// DECIMAL (sign? digits* . digits+)
+// Has to watch out for embedded rangeop (i.e. "1..10" is not "1." and ".10").
+
+NUMBER_OR_RANGEOP
+	:	SIGN? DIGIT+
+		(
+			{ input.LA(2) != '.' }? => '.' DIGIT* {   $type = DECIMAL; stripLeadingPlus(); }
+			| {  $type = INTEGER;  stripLeadingPlus(); }
+		)
+		
+	|	SIGN '.' DIGIT+ {  $type = DECIMAL;  stripLeadingPlus(); }
+	
+	|	'.'
+		( 
+			DIGIT+ { $type = DECIMAL; stripLeadingPlus();}
+			| '.' {$type = RANGEOP; }
+			| {$type = DEREF; }
+		)
+	;	
+

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g b/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g
new file mode 100644
index 0000000..14753e6
--- /dev/null
+++ b/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g
@@ -0,0 +1,105 @@
+// Copyright 2008, 2009, 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.
+
+parser grammar PropertyExpressionParser;
+
+
+options
+{
+  superClass='org.apache.tapestry5.internal.antlr.BaseParser';
+  output=AST;		
+  ASTLabelType=CommonTree;
+  tokenVocab=PropertyExpressionLexer;
+  backtrack=true;
+}
+
+tokens
+{	
+	// Parser token representing a method invocation
+    	INVOKE;
+    	// A List (top level, or as method parameter)
+    	LIST;
+		//A Map (top level, or as method parameter)
+		MAP;
+    	// Not operation (invert a boolean)
+    	NOT;
+}
+
+@header
+{
+package org.apache.tapestry5.internal.antlr;
+}
+
+	
+start 	:	expression^ EOF!;
+		
+expression
+	:	keyword
+	|	rangeOp
+	|	constant
+	|	propertyChain
+	|	list
+	|	notOp
+	|	map
+	;
+
+keyword	:	NULL | TRUE | FALSE | THIS;
+
+constant:	INTEGER| DECIMAL | STRING;	
+	
+propertyChain
+	:	term DEREF propertyChain -> ^(DEREF term propertyChain)
+	|	term SAFEDEREF propertyChain -> ^(SAFEDEREF term propertyChain)
+	|	term
+	;	
+	
+term	:	IDENTIFIER
+	|	methodInvocation
+	;
+	
+methodInvocation
+	:	id=IDENTIFIER LPAREN RPAREN -> ^(INVOKE $id)
+	|	id=IDENTIFIER LPAREN expressionList RPAREN -> ^(INVOKE $id expressionList)
+	;	
+	
+expressionList
+	:	expression (COMMA! expression)*
+	;	
+
+rangeOp
+	:	from=rangeopArg  RANGEOP to=rangeopArg -> ^(RANGEOP $from $to)
+	;	
+	
+rangeopArg 
+	:	INTEGER
+	|	propertyChain
+	;	
+	
+list	:	LBRACKET RBRACKET -> ^(LIST)
+	|	LBRACKET expressionList RBRACKET -> ^(LIST expressionList)
+	;	
+	
+notOp 	:	BANG expression -> ^(NOT expression)
+	;
+
+map 	:	LBRACE RBRACE -> ^(MAP)
+	|	LBRACE mapEntryList RBRACE -> ^(MAP mapEntryList)
+    ;
+	
+mapEntryList : mapEntry (COMMA! mapEntry)*;
+
+mapEntry :  mapKey COLON! expression;
+	
+mapKey :	keyword | constant | propertyChain;
+	

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java
new file mode 100644
index 0000000..442240d
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java
@@ -0,0 +1,54 @@
+// Copyright 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.internal.antlr;
+
+import org.antlr.runtime.CharStream;
+import org.antlr.runtime.Lexer;
+import org.antlr.runtime.RecognizerSharedState;
+import org.antlr.runtime.RecognitionException;
+
+public abstract class BaseLexer extends Lexer
+{
+    protected BaseLexer()
+    {
+    }
+
+    protected BaseLexer(CharStream charStream,
+                        RecognizerSharedState recognizerSharedState)
+    {
+        super(charStream, recognizerSharedState);
+    }
+
+    protected void stripLeadingPlus()
+    {
+        String text = getText();
+
+        // For compatibility with Tapestry 5.0, we need to allow a sign of '+', which Long.parseLong()
+        // doesn't accept. To keep things downstream simple, we eliminate the '+' here.
+
+        if (text.startsWith("+"))
+        {
+            setText(text.substring(1));
+        }
+    }
+
+    @Override
+    public void reportError(RecognitionException e)
+    {
+        throw new RuntimeException(String.format("Unable to parse input at character position %d",
+                                                 e.charPositionInLine + 1),
+                                   e);
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java
new file mode 100644
index 0000000..212b782
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java
@@ -0,0 +1,40 @@
+// Copyright 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.internal.antlr;
+
+import org.antlr.runtime.Parser;
+import org.antlr.runtime.TokenStream;
+import org.antlr.runtime.RecognizerSharedState;
+
+public class BaseParser extends Parser
+{
+    public BaseParser(TokenStream tokenStream)
+    {
+        super(tokenStream);
+    }
+
+    public BaseParser(TokenStream tokenStream,
+                      RecognizerSharedState recognizerSharedState)
+    {
+        super(tokenStream, recognizerSharedState);
+    }
+
+    @Override
+    public void emitErrorMessage(String message)
+    {
+        // This is caught and more properly reported later.
+        throw new RuntimeException(message);
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java
new file mode 100644
index 0000000..55be313
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java
@@ -0,0 +1,18 @@
+// Copyright 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.
+
+/**
+ * [INTERNAL USE ONLY] support classes related to Antlr; API subject to change
+ */
+package org.apache.tapestry5.internal.antlr;

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/java/org/apache/tapestry5/internal/services/Invariant.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/Invariant.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/Invariant.java
new file mode 100644
index 0000000..924b570
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/Invariant.java
@@ -0,0 +1,28 @@
+// 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.internal.services;
+
+import java.lang.annotation.*;
+
+/**
+ * Special annotation that is applied to literal {@link org.apache.tapestry5.PropertyConduit}s, to inform {@link
+ * org.apache.tapestry5.internal.bindings.PropBinding} that the value is, in fact, invariant.
+ */
+@Target({ElementType.PARAMETER, ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Invariant
+{
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
new file mode 100644
index 0000000..1fffd4f
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
@@ -0,0 +1,85 @@
+// Copyright 2008, 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.internal.services;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import org.apache.tapestry5.internal.InternalPropertyConduit;
+import org.apache.tapestry5.ioc.AnnotationProvider;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
+
+/**
+ * A PropertyConduit for a literal value in an expression, such as a number, or "true", "false" or "null".
+ */
+public class LiteralPropertyConduit extends PropertyConduitDelegate implements InternalPropertyConduit
+{
+    private final Class propertyType;
+
+    private final AnnotationProvider annotationProvider;
+
+    private final String description;
+
+    private final Object value;
+
+    public LiteralPropertyConduit(TypeCoercer typeCoercer, Class propertyType, AnnotationProvider annotationProvider,
+            String description, Object value)
+    {
+        super(typeCoercer);
+
+        this.propertyType = propertyType;
+        this.annotationProvider = annotationProvider;
+        this.description = description;
+
+        this.value = value;
+    }
+
+    public Object get(Object instance)
+    {
+        return value;
+    }
+
+    public void set(Object instance, Object value)
+    {
+        throw new RuntimeException("Literal values are not updateable.");
+    }
+
+    public Class getPropertyType()
+    {
+        return propertyType;
+    }
+    
+    public Type getPropertyGenericType()
+    {
+    	return propertyType;
+    }
+
+    public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+    {
+        return annotationProvider.getAnnotation(annotationClass);
+    }
+
+    public String getPropertyName()
+    {
+        return null;
+    }
+
+    @Override
+    public String toString()
+    {
+        return description;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java
new file mode 100644
index 0000000..765c0bb
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java
@@ -0,0 +1,38 @@
+// 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.internal.services;
+
+/**
+ * Exception thrown when there is a problem parsing a property expression using the ANTLR property expression grammar.
+ */
+public class PropertyExpressionException extends RuntimeException
+{
+    private final String expression;
+
+    public PropertyExpressionException(String message, String expression, Throwable cause)
+    {
+        super(message, cause);
+
+        this.expression = expression;
+    }
+
+    /**
+     * Returns the property expression containing the error.
+     */
+    public String getExpression()
+    {
+        return expression;
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/commons/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java b/commons/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java
new file mode 100644
index 0000000..78ee5f4
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java
@@ -0,0 +1,43 @@
+// Copyright 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.internal.services;
+
+/**
+ * Creates "interned" strings that are unique for the same content. This is used for common description strings,
+ * particularly those used by {@link org.apache.tapestry5.Binding} instances.  The internal cache of interned strings id
+ * cleared whenever the {@link org.apache.tapestry5.services.ComponentClasses} {@link
+ * org.apache.tapestry5.services.InvalidationEventHub} is invalidated (i.e., when component class files change).
+ *
+ * @since 5.1.0.0
+ */
+public interface StringInterner
+{
+    /**
+     * Interns a string.
+     *
+     * @param string the string to intern
+     * @return the input string, or another string instance with the same content
+     */
+    String intern(String string);
+
+    /**
+     * Formats a string (using {@link String#format(String, Object[])}) and returns the interned result.
+     *
+     * @param format    string format
+     * @param arguments used inside the format
+     * @return formatted and interned string
+     */
+    String format(String format, Object... arguments);
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/commons/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java b/commons/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java
new file mode 100644
index 0000000..e7990fc
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java
@@ -0,0 +1,27 @@
+// Copyright 2006, 2008, 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;
+
+/**
+ * Interface used to encapsulate any strategy used defer the creation of some object until just as needed.
+ */
+public interface ObjectCreator<T>
+{
+    /**
+     * Create and return the object. In some limited circumstances, the implementation may cache the result, returning
+     * the same object for repeated calls.
+     */
+    T createObject();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/commons/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java b/commons/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
new file mode 100644
index 0000000..75e93e4
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
@@ -0,0 +1,159 @@
+// 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.services;
+
+import org.apache.tapestry5.ioc.Location;
+import org.apache.tapestry5.ioc.ObjectCreator;
+import org.apache.tapestry5.ioc.annotations.IncompatibleChange;
+import org.apache.tapestry5.plastic.ClassInstantiator;
+import org.apache.tapestry5.plastic.PlasticClassListenerHub;
+import org.apache.tapestry5.plastic.PlasticClassTransformation;
+import org.apache.tapestry5.plastic.PlasticClassTransformer;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+/**
+ * A service used to create proxies of varying types. As a secondary concern, manages to identify the
+ * location of methods and constructors, which is important for exception reporting.
+ *
+ * @since 5.3
+ */
+public interface PlasticProxyFactory extends PlasticClassListenerHub
+{
+    /**
+     * Returns the class loader used when creating new classes, this is a child class loader
+     * of another class loader (usually, the thread's context class loader).
+     */
+    ClassLoader getClassLoader();
+
+    /**
+     * Creates a proxy object that implements the indicated interface, then invokes the callback to further
+     * configure the proxy.
+     *
+     * @param interfaceType
+     *         interface implemented by proxy
+     * @param callback
+     *         configures the proxy
+     * @return instantiator that can be used to create an instance of the proxy class
+     */
+    <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, PlasticClassTransformer callback);
+
+    /**
+     * Creates a proxy object that implements the indicated interface and indicated service implementation type,
+     * then invokes the callback to further configure the proxy.
+     *
+     * @param interfaceType
+     *         interface implemented by proxy
+     * @param implementationType
+     *         a class that implements the interfaceType. It can be null.
+     * @param callback
+     *         configures the proxy
+     * @return instantiator that can be used to create an instance of the proxy class
+     */
+    @IncompatibleChange(release = "5.4", details = "TAP5-2029")
+    <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, Class<? extends T> implementationType, PlasticClassTransformer callback);
+
+    /**
+     * Creates the underlying {@link PlasticClassTransformation} for an interface proxy. This should only be
+     * used in the cases where encapsulating the PlasticClass construction into a {@linkplain PlasticClassTransformer
+     * callback} is not feasible (which is the case for some of the older APIs inside Tapestry IoC).
+     *
+     * @param interfaceType
+     *         class proxy will extend from
+     * @return transformation from which an instantiator may be created
+     */
+    <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType);
+
+    /**
+     * Creates the underlying {@link PlasticClassTransformation} for an interface proxy with a given
+     * implementation class. This should only be
+     * used in the cases where encapsulating the PlasticClass construction into a {@linkplain PlasticClassTransformer
+     * callback} is not feasible (which is the case for some of the older APIs inside Tapestry IoC).
+     *
+     * @param interfaceType
+     *         class proxy will extend from
+     * @param implementationType
+     *         a class that implements the interfaceType. It can be null.
+     * @return transformation from which an instantiator may be created
+     */
+    @IncompatibleChange(release = "5.4", details = "TAP5-2029")
+    <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType, Class<? extends T> implementationType);
+
+    /**
+     * Creates a proxy instance that delegates all methods through a corresponding
+     * ObjectCreator. Each method invocation on the proxy will route through {@link ObjectCreator#createObject()} (the
+     * creator implementation may decide to
+     * cache the return value as appropriate).
+     *
+     * @param <T>
+     *         type of proxy
+     * @param interfaceType
+     *         interface class for proxy
+     * @param creator
+     *         object responsible for creating the real object
+     * @param description
+     *         the <code>toString()</code> of the proxy
+     * @return proxy instance
+     */
+    <T> T createProxy(Class<T> interfaceType, ObjectCreator<T> creator, String description);
+    
+    /**
+     * Creates a proxy instance that delegates all methods through a corresponding
+     * ObjectCreator. Each method invocation on the proxy will route through {@link ObjectCreator#createObject()} (the
+     * creator implementation may decide to
+     * cache the return value as appropriate).
+     *
+     * @param <T>
+     *         type of proxy
+     * @param interfaceType
+     *         interface class for proxy
+     * @param implementationType
+     *         class that implements the interface type. It may be null
+     * @param creator
+     *         object responsible for creating the real object
+     * @param description
+     *         the <code>toString()</code> of the proxy
+     * @return proxy instance
+     */
+    @IncompatibleChange(release = "5.4", details = "Added for TAP5-2029")
+    <T> T createProxy(Class<T> interfaceType, Class<? extends T> implementationType, ObjectCreator<T> creator, String description);
+
+    /**
+     * Converts a method to a {@link Location}, which includes information about the source file name and line number.
+     *
+     * @param method
+     *         to look up
+     * @return the location (identifying the method and possibly, the line number within the method)
+     */
+    Location getMethodLocation(Method method);
+
+    /**
+     * Return a string representation for the constructor (including class and parameters) and (if available) file name
+     * and line number.
+     *
+     * @return the location (identifying the constructor and possibly, the line number within the method)
+     */
+    Location getConstructorLocation(Constructor constructor);
+
+    /**
+     * Clears any cached information stored by the proxy factory; this is useful in Tapestry development mode
+     * when a class loader may have been discarded (because the proxy factory may indirectly keep references
+     * to classes loaded by the old class loader).
+     *
+     * @since 5.3.3
+     */
+    void clearCache();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/commons/src/main/java/org/apache/tapestry5/ioc/util/Stack.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/Stack.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/Stack.java
new file mode 100644
index 0000000..cfa13a0
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/Stack.java
@@ -0,0 +1,173 @@
+// Copyright 2007, 2008, 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.util;
+
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+
+/**
+ * A simple, streamlined implementation of {@link java.util.Stack}. The implementation is <em>not</em> threadsafe.
+ *
+ * @param <E> the type of elements stored in the map
+ * @see CollectionFactory#newStack()
+ */
+public class Stack<E>
+{
+    private static final int MINIMUM_SIZE = 3;
+
+    private static final int DEFAULT_ARRAY_SIZE = 20;
+
+    private Object[] items;
+
+    private int index = -1;
+
+    /**
+     * Normal constructor supporting an initial size of 20.
+     */
+    public Stack()
+    {
+        this(DEFAULT_ARRAY_SIZE);
+    }
+
+    /**
+     * @param initialSize the initial size of the internal array (which will be expanded as necessary). For best
+     *                    efficiency, set this to the maximum depth of the stack.
+     */
+    public Stack(int initialSize)
+    {
+        items = new Object[Math.max(initialSize, MINIMUM_SIZE)];
+    }
+
+    /**
+     * Returns true if the stack is empty.
+     */
+    public boolean isEmpty()
+    {
+        return index < 0;
+    }
+
+    /**
+     * Returns the number of items currently in the stack.
+     */
+    public int getDepth()
+    {
+        return index + 1;
+    }
+
+    /**
+     * Clears the stack, the same as popping off all elements.
+     */
+    public void clear()
+    {
+        for (int i = 0; i <= index; i++) items[i] = null;
+
+        index = -1;
+    }
+
+    /**
+     * Pushes a new item onto the stack.
+     */
+    public void push(E item)
+    {
+        index++;
+
+        if (index == items.length)
+        {
+            int newCapacity = (items.length * 3) / 2 + 1;
+            Object[] newItems = new Object[newCapacity];
+            System.arraycopy(items, 0, newItems, 0, items.length);
+
+            items = newItems;
+        }
+
+        items[index] = item;
+    }
+
+    /**
+     * Pops the top element off the stack and returns it.
+     *
+     * @return the top element of the stack
+     * @throws IllegalStateException if the stack is empty
+     */
+    @SuppressWarnings("unchecked")
+    public E pop()
+    {
+        checkIfEmpty();
+
+        Object result = items[index];
+
+        items[index] = null;
+
+        index--;
+
+        return (E) result;
+    }
+
+    private void checkIfEmpty()
+    {
+        if (index < 0) throw new IllegalStateException("Stack is empty.");
+    }
+
+    /**
+     * Returns the top element of the stack without affecting the stack.
+     *
+     * @return top element on the stack
+     * @throws IllegalStateException if the stack is empty
+     */
+    @SuppressWarnings("unchecked")
+    public E peek()
+    {
+        checkIfEmpty();
+
+        return (E) items[index];
+    }
+
+    /**
+     * Describes the stack, listing the element in order of depth (top element first).
+     *
+     * @return string description of the stack
+     */
+    @Override
+    public String toString()
+    {
+        StringBuilder builder = new StringBuilder("Stack[");
+
+        for (int i = index; i >= 0; i--)
+        {
+            if (i != index) builder.append(", ");
+
+            builder.append(String.valueOf(items[i]));
+        }
+
+        builder.append("]");
+
+        return builder.toString();
+    }
+
+    /**
+     * Returns a snapshot of the current state of the stack as an array of objects. The first object is the deepest in
+     * the stack, the last object is the most shallowest (most recently pushed onto the stack).  The returned array may
+     * be manipulated (it is a copy).
+     *
+     * @return the stack as an object array
+     */
+    public Object[] getSnapshot()
+    {
+        Object[] result = new Object[index + 1];
+
+        System.arraycopy(items, 0, result, 0, index + 1);
+
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g b/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g
deleted file mode 100644
index 3b52ba9..0000000
--- a/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g
+++ /dev/null
@@ -1,163 +0,0 @@
-// Copyright 2008, 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.
-
-lexer grammar PropertyExpressionLexer;
-
-
-options
-{
-  superClass='org.apache.tapestry5.internal.antlr.BaseLexer';
-}
-
-@header
-{
-package org.apache.tapestry5.internal.antlr;
-}
-
-	
-// Integer constant
-fragment INTEGER
-	:	{this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};	
-	
-// Read a property or invoke a method.
-fragment DEREF 
-	:	{this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};	
-	
-// Range operator, ".." between two integers.	
-fragment RANGEOP
-	:	{this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};	
-	
-// Decimal number	
-fragment DECIMAL
-	:	{this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};	
-			
-fragment LETTER 
-	:	('a'..'z'|'A'..'Z');
-fragment DIGIT 
-	:	'0'..'9';	
-fragment SIGN
-	:	('+'|'-');
-LPAREN 	:	'(';
-RPAREN 	:	')';
-LBRACKET:	'[';
-RBRACKET:	']';
-COMMA	:	',';
-BANG	:	'!';
-LBRACE	:	'{';
-RBRACE	:	'}';
-COLON	:	':';
-
-fragment QUOTE
-	:	'\'';
-
-// Clumsy but effective approach to case-insensitive identifiers.
-
-fragment A
-	:	('a' | 'A');
-fragment E
-	:	('e' | 'E');
-fragment F
-	:	('f' | 'F');	
-fragment H
-	:	('h' | 'H');
-fragment I
-	:	('i' | 'I');
-fragment L 
-	: 	('l' | 'L');
-fragment N 
-	:	('n'|'N');
-fragment R
-	:	('r' | 'R');
-fragment S
-	:	('s' | 'S');
-fragment T 
-	:	('t' | 'T');
-fragment U 
-	:	('u' | 'U');
-
-// Identifiers are case insensitive
-
-NULL 	:	N U L L;
-TRUE	:	T R U E;
-FALSE	:	F A L S E;
-THIS	:	T H I S;
-
-IDENTIFIER 
-    :   JAVA_ID_START (JAVA_ID_PART)*
-    ;
-
-fragment
-JAVA_ID_START
-    :  '\u0024'
-    |  '\u0041'..'\u005a'
-    |  '\u005f'
-    |  '\u0061'..'\u007a'
-    |  '\u00c0'..'\u00d6'
-    |  '\u00d8'..'\u00f6'
-    |  '\u00f8'..'\u00ff'
-    |  '\u0100'..'\u1fff'
-    |  '\u3040'..'\u318f'
-    |  '\u3300'..'\u337f'
-    |  '\u3400'..'\u3d2d'
-    |  '\u4e00'..'\u9fff'
-    |  '\uf900'..'\ufaff'
-    ;
-
-fragment
-JAVA_ID_PART
-    :  JAVA_ID_START
-    |  '\u0030'..'\u0039'
-    ;
-
-
-// The Safe Dereference operator understands not to de-reference through
-// a null.
-
-SAFEDEREF 
-	: 	'?.';
-
-WS 	:	(' '|'\t'|'\n'|'\r')+ { skip(); };
-
-
-// Literal strings are always inside single quotes.
-STRING
-	:	QUOTE (options {greedy=false;} : .)* QUOTE { setText(getText().substring(1, getText().length()-1)); };
-
-
-// Special rule that uses parsing tricks to identify numbers and ranges; it's all about
-// the dot ('.').
-// Recognizes:
-// '.' as DEREF
-// '..' as RANGEOP
-// INTEGER (sign? digit+)
-// DECIMAL (sign? digits* . digits+)
-// Has to watch out for embedded rangeop (i.e. "1..10" is not "1." and ".10").
-
-NUMBER_OR_RANGEOP
-	:	SIGN? DIGIT+
-		(
-			{ input.LA(2) != '.' }? => '.' DIGIT* {   $type = DECIMAL; stripLeadingPlus(); }
-			| {  $type = INTEGER;  stripLeadingPlus(); }
-		)
-		
-	|	SIGN '.' DIGIT+ {  $type = DECIMAL;  stripLeadingPlus(); }
-	
-	|	'.'
-		( 
-			DIGIT+ { $type = DECIMAL; stripLeadingPlus();}
-			| '.' {$type = RANGEOP; }
-			| {$type = DEREF; }
-		)
-	;	
-

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g b/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g
deleted file mode 100644
index 14753e6..0000000
--- a/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright 2008, 2009, 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.
-
-parser grammar PropertyExpressionParser;
-
-
-options
-{
-  superClass='org.apache.tapestry5.internal.antlr.BaseParser';
-  output=AST;		
-  ASTLabelType=CommonTree;
-  tokenVocab=PropertyExpressionLexer;
-  backtrack=true;
-}
-
-tokens
-{	
-	// Parser token representing a method invocation
-    	INVOKE;
-    	// A List (top level, or as method parameter)
-    	LIST;
-		//A Map (top level, or as method parameter)
-		MAP;
-    	// Not operation (invert a boolean)
-    	NOT;
-}
-
-@header
-{
-package org.apache.tapestry5.internal.antlr;
-}
-
-	
-start 	:	expression^ EOF!;
-		
-expression
-	:	keyword
-	|	rangeOp
-	|	constant
-	|	propertyChain
-	|	list
-	|	notOp
-	|	map
-	;
-
-keyword	:	NULL | TRUE | FALSE | THIS;
-
-constant:	INTEGER| DECIMAL | STRING;	
-	
-propertyChain
-	:	term DEREF propertyChain -> ^(DEREF term propertyChain)
-	|	term SAFEDEREF propertyChain -> ^(SAFEDEREF term propertyChain)
-	|	term
-	;	
-	
-term	:	IDENTIFIER
-	|	methodInvocation
-	;
-	
-methodInvocation
-	:	id=IDENTIFIER LPAREN RPAREN -> ^(INVOKE $id)
-	|	id=IDENTIFIER LPAREN expressionList RPAREN -> ^(INVOKE $id expressionList)
-	;	
-	
-expressionList
-	:	expression (COMMA! expression)*
-	;	
-
-rangeOp
-	:	from=rangeopArg  RANGEOP to=rangeopArg -> ^(RANGEOP $from $to)
-	;	
-	
-rangeopArg 
-	:	INTEGER
-	|	propertyChain
-	;	
-	
-list	:	LBRACKET RBRACKET -> ^(LIST)
-	|	LBRACKET expressionList RBRACKET -> ^(LIST expressionList)
-	;	
-	
-notOp 	:	BANG expression -> ^(NOT expression)
-	;
-
-map 	:	LBRACE RBRACE -> ^(MAP)
-	|	LBRACE mapEntryList RBRACE -> ^(MAP mapEntryList)
-    ;
-	
-mapEntryList : mapEntry (COMMA! mapEntry)*;
-
-mapEntry :  mapKey COLON! expression;
-	
-mapKey :	keyword | constant | propertyChain;
-	

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java
deleted file mode 100644
index 442240d..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 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.internal.antlr;
-
-import org.antlr.runtime.CharStream;
-import org.antlr.runtime.Lexer;
-import org.antlr.runtime.RecognizerSharedState;
-import org.antlr.runtime.RecognitionException;
-
-public abstract class BaseLexer extends Lexer
-{
-    protected BaseLexer()
-    {
-    }
-
-    protected BaseLexer(CharStream charStream,
-                        RecognizerSharedState recognizerSharedState)
-    {
-        super(charStream, recognizerSharedState);
-    }
-
-    protected void stripLeadingPlus()
-    {
-        String text = getText();
-
-        // For compatibility with Tapestry 5.0, we need to allow a sign of '+', which Long.parseLong()
-        // doesn't accept. To keep things downstream simple, we eliminate the '+' here.
-
-        if (text.startsWith("+"))
-        {
-            setText(text.substring(1));
-        }
-    }
-
-    @Override
-    public void reportError(RecognitionException e)
-    {
-        throw new RuntimeException(String.format("Unable to parse input at character position %d",
-                                                 e.charPositionInLine + 1),
-                                   e);
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java
deleted file mode 100644
index 212b782..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 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.internal.antlr;
-
-import org.antlr.runtime.Parser;
-import org.antlr.runtime.TokenStream;
-import org.antlr.runtime.RecognizerSharedState;
-
-public class BaseParser extends Parser
-{
-    public BaseParser(TokenStream tokenStream)
-    {
-        super(tokenStream);
-    }
-
-    public BaseParser(TokenStream tokenStream,
-                      RecognizerSharedState recognizerSharedState)
-    {
-        super(tokenStream, recognizerSharedState);
-    }
-
-    @Override
-    public void emitErrorMessage(String message)
-    {
-        // This is caught and more properly reported later.
-        throw new RuntimeException(message);
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java
deleted file mode 100644
index 55be313..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 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.
-
-/**
- * [INTERNAL USE ONLY] support classes related to Antlr; API subject to change
- */
-package org.apache.tapestry5.internal.antlr;

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/Invariant.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/Invariant.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/Invariant.java
deleted file mode 100644
index 924b570..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/Invariant.java
+++ /dev/null
@@ -1,28 +0,0 @@
-// 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.internal.services;
-
-import java.lang.annotation.*;
-
-/**
- * Special annotation that is applied to literal {@link org.apache.tapestry5.PropertyConduit}s, to inform {@link
- * org.apache.tapestry5.internal.bindings.PropBinding} that the value is, in fact, invariant.
- */
-@Target({ElementType.PARAMETER, ElementType.FIELD})
-@Retention(RetentionPolicy.RUNTIME)
-@Documented
-public @interface Invariant
-{
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
deleted file mode 100644
index 1fffd4f..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2008, 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.internal.services;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-
-import org.apache.tapestry5.internal.InternalPropertyConduit;
-import org.apache.tapestry5.ioc.AnnotationProvider;
-import org.apache.tapestry5.ioc.services.TypeCoercer;
-
-/**
- * A PropertyConduit for a literal value in an expression, such as a number, or "true", "false" or "null".
- */
-public class LiteralPropertyConduit extends PropertyConduitDelegate implements InternalPropertyConduit
-{
-    private final Class propertyType;
-
-    private final AnnotationProvider annotationProvider;
-
-    private final String description;
-
-    private final Object value;
-
-    public LiteralPropertyConduit(TypeCoercer typeCoercer, Class propertyType, AnnotationProvider annotationProvider,
-            String description, Object value)
-    {
-        super(typeCoercer);
-
-        this.propertyType = propertyType;
-        this.annotationProvider = annotationProvider;
-        this.description = description;
-
-        this.value = value;
-    }
-
-    public Object get(Object instance)
-    {
-        return value;
-    }
-
-    public void set(Object instance, Object value)
-    {
-        throw new RuntimeException("Literal values are not updateable.");
-    }
-
-    public Class getPropertyType()
-    {
-        return propertyType;
-    }
-    
-    public Type getPropertyGenericType()
-    {
-    	return propertyType;
-    }
-
-    public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
-    {
-        return annotationProvider.getAnnotation(annotationClass);
-    }
-
-    public String getPropertyName()
-    {
-        return null;
-    }
-
-    @Override
-    public String toString()
-    {
-        return description;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java
deleted file mode 100644
index 765c0bb..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java
+++ /dev/null
@@ -1,38 +0,0 @@
-// 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.internal.services;
-
-/**
- * Exception thrown when there is a problem parsing a property expression using the ANTLR property expression grammar.
- */
-public class PropertyExpressionException extends RuntimeException
-{
-    private final String expression;
-
-    public PropertyExpressionException(String message, String expression, Throwable cause)
-    {
-        super(message, cause);
-
-        this.expression = expression;
-    }
-
-    /**
-     * Returns the property expression containing the error.
-     */
-    public String getExpression()
-    {
-        return expression;
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java
deleted file mode 100644
index 78ee5f4..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 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.internal.services;
-
-/**
- * Creates "interned" strings that are unique for the same content. This is used for common description strings,
- * particularly those used by {@link org.apache.tapestry5.Binding} instances.  The internal cache of interned strings id
- * cleared whenever the {@link org.apache.tapestry5.services.ComponentClasses} {@link
- * org.apache.tapestry5.services.InvalidationEventHub} is invalidated (i.e., when component class files change).
- *
- * @since 5.1.0.0
- */
-public interface StringInterner
-{
-    /**
-     * Interns a string.
-     *
-     * @param string the string to intern
-     * @return the input string, or another string instance with the same content
-     */
-    String intern(String string);
-
-    /**
-     * Formats a string (using {@link String#format(String, Object[])}) and returns the interned result.
-     *
-     * @param format    string format
-     * @param arguments used inside the format
-     * @return formatted and interned string
-     */
-    String format(String format, Object... arguments);
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java
deleted file mode 100644
index e7990fc..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2006, 2008, 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;
-
-/**
- * Interface used to encapsulate any strategy used defer the creation of some object until just as needed.
- */
-public interface ObjectCreator<T>
-{
-    /**
-     * Create and return the object. In some limited circumstances, the implementation may cache the result, returning
-     * the same object for repeated calls.
-     */
-    T createObject();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java
deleted file mode 100644
index ffc9490..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java
+++ /dev/null
@@ -1,33 +0,0 @@
-// 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.annotations;
-
-import java.lang.annotation.*;
-
-@Target({ElementType.METHOD, ElementType.FIELD})
-@Retention(RetentionPolicy.CLASS)
-@Documented
-public @interface IncompatibleChange
-{
-    /**
-     * Identifies the release in which the signature of the method was modified.
-     *
-     * @return a release number, e.g., "5.4"
-     */
-    String release();
-
-    /**
-     * Short string describing what changed.
-     */
-    String details();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
deleted file mode 100644
index 75e93e4..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
+++ /dev/null
@@ -1,159 +0,0 @@
-// 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.services;
-
-import org.apache.tapestry5.ioc.Location;
-import org.apache.tapestry5.ioc.ObjectCreator;
-import org.apache.tapestry5.ioc.annotations.IncompatibleChange;
-import org.apache.tapestry5.plastic.ClassInstantiator;
-import org.apache.tapestry5.plastic.PlasticClassListenerHub;
-import org.apache.tapestry5.plastic.PlasticClassTransformation;
-import org.apache.tapestry5.plastic.PlasticClassTransformer;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-
-/**
- * A service used to create proxies of varying types. As a secondary concern, manages to identify the
- * location of methods and constructors, which is important for exception reporting.
- *
- * @since 5.3
- */
-public interface PlasticProxyFactory extends PlasticClassListenerHub
-{
-    /**
-     * Returns the class loader used when creating new classes, this is a child class loader
-     * of another class loader (usually, the thread's context class loader).
-     */
-    ClassLoader getClassLoader();
-
-    /**
-     * Creates a proxy object that implements the indicated interface, then invokes the callback to further
-     * configure the proxy.
-     *
-     * @param interfaceType
-     *         interface implemented by proxy
-     * @param callback
-     *         configures the proxy
-     * @return instantiator that can be used to create an instance of the proxy class
-     */
-    <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, PlasticClassTransformer callback);
-
-    /**
-     * Creates a proxy object that implements the indicated interface and indicated service implementation type,
-     * then invokes the callback to further configure the proxy.
-     *
-     * @param interfaceType
-     *         interface implemented by proxy
-     * @param implementationType
-     *         a class that implements the interfaceType. It can be null.
-     * @param callback
-     *         configures the proxy
-     * @return instantiator that can be used to create an instance of the proxy class
-     */
-    @IncompatibleChange(release = "5.4", details = "TAP5-2029")
-    <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, Class<? extends T> implementationType, PlasticClassTransformer callback);
-
-    /**
-     * Creates the underlying {@link PlasticClassTransformation} for an interface proxy. This should only be
-     * used in the cases where encapsulating the PlasticClass construction into a {@linkplain PlasticClassTransformer
-     * callback} is not feasible (which is the case for some of the older APIs inside Tapestry IoC).
-     *
-     * @param interfaceType
-     *         class proxy will extend from
-     * @return transformation from which an instantiator may be created
-     */
-    <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType);
-
-    /**
-     * Creates the underlying {@link PlasticClassTransformation} for an interface proxy with a given
-     * implementation class. This should only be
-     * used in the cases where encapsulating the PlasticClass construction into a {@linkplain PlasticClassTransformer
-     * callback} is not feasible (which is the case for some of the older APIs inside Tapestry IoC).
-     *
-     * @param interfaceType
-     *         class proxy will extend from
-     * @param implementationType
-     *         a class that implements the interfaceType. It can be null.
-     * @return transformation from which an instantiator may be created
-     */
-    @IncompatibleChange(release = "5.4", details = "TAP5-2029")
-    <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType, Class<? extends T> implementationType);
-
-    /**
-     * Creates a proxy instance that delegates all methods through a corresponding
-     * ObjectCreator. Each method invocation on the proxy will route through {@link ObjectCreator#createObject()} (the
-     * creator implementation may decide to
-     * cache the return value as appropriate).
-     *
-     * @param <T>
-     *         type of proxy
-     * @param interfaceType
-     *         interface class for proxy
-     * @param creator
-     *         object responsible for creating the real object
-     * @param description
-     *         the <code>toString()</code> of the proxy
-     * @return proxy instance
-     */
-    <T> T createProxy(Class<T> interfaceType, ObjectCreator<T> creator, String description);
-    
-    /**
-     * Creates a proxy instance that delegates all methods through a corresponding
-     * ObjectCreator. Each method invocation on the proxy will route through {@link ObjectCreator#createObject()} (the
-     * creator implementation may decide to
-     * cache the return value as appropriate).
-     *
-     * @param <T>
-     *         type of proxy
-     * @param interfaceType
-     *         interface class for proxy
-     * @param implementationType
-     *         class that implements the interface type. It may be null
-     * @param creator
-     *         object responsible for creating the real object
-     * @param description
-     *         the <code>toString()</code> of the proxy
-     * @return proxy instance
-     */
-    @IncompatibleChange(release = "5.4", details = "Added for TAP5-2029")
-    <T> T createProxy(Class<T> interfaceType, Class<? extends T> implementationType, ObjectCreator<T> creator, String description);
-
-    /**
-     * Converts a method to a {@link Location}, which includes information about the source file name and line number.
-     *
-     * @param method
-     *         to look up
-     * @return the location (identifying the method and possibly, the line number within the method)
-     */
-    Location getMethodLocation(Method method);
-
-    /**
-     * Return a string representation for the constructor (including class and parameters) and (if available) file name
-     * and line number.
-     *
-     * @return the location (identifying the constructor and possibly, the line number within the method)
-     */
-    Location getConstructorLocation(Constructor constructor);
-
-    /**
-     * Clears any cached information stored by the proxy factory; this is useful in Tapestry development mode
-     * when a class loader may have been discarded (because the proxy factory may indirectly keep references
-     * to classes loaded by the old class loader).
-     *
-     * @since 5.3.3
-     */
-    void clearCache();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/Stack.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/Stack.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/Stack.java
deleted file mode 100644
index cfa13a0..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/Stack.java
+++ /dev/null
@@ -1,173 +0,0 @@
-// Copyright 2007, 2008, 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.util;
-
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-
-/**
- * A simple, streamlined implementation of {@link java.util.Stack}. The implementation is <em>not</em> threadsafe.
- *
- * @param <E> the type of elements stored in the map
- * @see CollectionFactory#newStack()
- */
-public class Stack<E>
-{
-    private static final int MINIMUM_SIZE = 3;
-
-    private static final int DEFAULT_ARRAY_SIZE = 20;
-
-    private Object[] items;
-
-    private int index = -1;
-
-    /**
-     * Normal constructor supporting an initial size of 20.
-     */
-    public Stack()
-    {
-        this(DEFAULT_ARRAY_SIZE);
-    }
-
-    /**
-     * @param initialSize the initial size of the internal array (which will be expanded as necessary). For best
-     *                    efficiency, set this to the maximum depth of the stack.
-     */
-    public Stack(int initialSize)
-    {
-        items = new Object[Math.max(initialSize, MINIMUM_SIZE)];
-    }
-
-    /**
-     * Returns true if the stack is empty.
-     */
-    public boolean isEmpty()
-    {
-        return index < 0;
-    }
-
-    /**
-     * Returns the number of items currently in the stack.
-     */
-    public int getDepth()
-    {
-        return index + 1;
-    }
-
-    /**
-     * Clears the stack, the same as popping off all elements.
-     */
-    public void clear()
-    {
-        for (int i = 0; i <= index; i++) items[i] = null;
-
-        index = -1;
-    }
-
-    /**
-     * Pushes a new item onto the stack.
-     */
-    public void push(E item)
-    {
-        index++;
-
-        if (index == items.length)
-        {
-            int newCapacity = (items.length * 3) / 2 + 1;
-            Object[] newItems = new Object[newCapacity];
-            System.arraycopy(items, 0, newItems, 0, items.length);
-
-            items = newItems;
-        }
-
-        items[index] = item;
-    }
-
-    /**
-     * Pops the top element off the stack and returns it.
-     *
-     * @return the top element of the stack
-     * @throws IllegalStateException if the stack is empty
-     */
-    @SuppressWarnings("unchecked")
-    public E pop()
-    {
-        checkIfEmpty();
-
-        Object result = items[index];
-
-        items[index] = null;
-
-        index--;
-
-        return (E) result;
-    }
-
-    private void checkIfEmpty()
-    {
-        if (index < 0) throw new IllegalStateException("Stack is empty.");
-    }
-
-    /**
-     * Returns the top element of the stack without affecting the stack.
-     *
-     * @return top element on the stack
-     * @throws IllegalStateException if the stack is empty
-     */
-    @SuppressWarnings("unchecked")
-    public E peek()
-    {
-        checkIfEmpty();
-
-        return (E) items[index];
-    }
-
-    /**
-     * Describes the stack, listing the element in order of depth (top element first).
-     *
-     * @return string description of the stack
-     */
-    @Override
-    public String toString()
-    {
-        StringBuilder builder = new StringBuilder("Stack[");
-
-        for (int i = index; i >= 0; i--)
-        {
-            if (i != index) builder.append(", ");
-
-            builder.append(String.valueOf(items[i]));
-        }
-
-        builder.append("]");
-
-        return builder.toString();
-    }
-
-    /**
-     * Returns a snapshot of the current state of the stack as an array of objects. The first object is the deepest in
-     * the stack, the last object is the most shallowest (most recently pushed onto the stack).  The returned array may
-     * be manipulated (it is a copy).
-     *
-     * @return the stack as an object array
-     */
-    public Object[] getSnapshot()
-    {
-        Object[] result = new Object[index + 1];
-
-        System.arraycopy(items, 0, result, 0, index + 1);
-
-        return result;
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java
----------------------------------------------------------------------
diff --git a/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java b/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java
new file mode 100644
index 0000000..ffc9490
--- /dev/null
+++ b/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java
@@ -0,0 +1,33 @@
+// 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.annotations;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.METHOD, ElementType.FIELD})
+@Retention(RetentionPolicy.CLASS)
+@Documented
+public @interface IncompatibleChange
+{
+    /**
+     * Identifies the release in which the signature of the method was modified.
+     *
+     * @return a release number, e.g., "5.4"
+     */
+    String release();
+
+    /**
+     * Short string describing what changed.
+     */
+    String details();
+}


[09/15] tapestry-5 git commit: Second pass creating the BeanModel and Commons packages.

Posted by th...@apache.org.
Second 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/c9e97d64
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/c9e97d64
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/c9e97d64

Branch: refs/heads/beanmodel-split
Commit: c9e97d64a51b25c875d5daa94d2f607e4ed299f3
Parents: 1f36bb2
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Sat Dec 6 16:42:10 2014 -0200
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Sat Dec 6 16:42:10 2014 -0200

----------------------------------------------------------------------
 beanmodel/.gitignore                            |   4 +
 beanmodel/build.gradle                          |  51 ++++-
 .../tapestry5/internal/BeanModelUtils.java      | 145 +++++++++++++
 .../internal/beaneditor/BeanModelImpl.java      |   4 +-
 .../internal/beaneditor/PropertyModelImpl.java  |  14 +-
 .../services/PropertyConduitDelegate.java       |   1 -
 .../services/PropertyConduitSourceImpl.java     |  10 +-
 .../org/apache/tapestry5/ioc/ObjectLocator.java |   3 +-
 .../ioc/internal/util/InternalStringUtils.java  | 203 +++++++++++++++++++
 .../ioc/internal/util/TapestryException.java    |  23 ++-
 .../tapestry5/ioc/util/AvailableValues.java     |   4 +-
 tapestry-core/build.gradle                      |  37 ----
 .../internal/TapestryInternalUtils.java         |  46 +----
 .../ioc/internal/util/InternalUtils.java        | 142 +++----------
 14 files changed, 472 insertions(+), 215 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/beanmodel/.gitignore
----------------------------------------------------------------------
diff --git a/beanmodel/.gitignore b/beanmodel/.gitignore
new file mode 100644
index 0000000..f739972
--- /dev/null
+++ b/beanmodel/.gitignore
@@ -0,0 +1,4 @@
+docs
+/.externalToolBuilders
+src/main/generated
+src/test/generated

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/beanmodel/build.gradle
----------------------------------------------------------------------
diff --git a/beanmodel/build.gradle b/beanmodel/build.gradle
index ccdeb37..c09ebdd 100644
--- a/beanmodel/build.gradle
+++ b/beanmodel/build.gradle
@@ -6,7 +6,18 @@ description = "Fast class property discovery, reading and writing library based
 //apply plugin: JavaPlugin
 
 buildDir = 'target/gradle-build'
-       
+
+project.ext {
+	antlrSource = "src/main/antlr"
+	mainGeneratedDir = "src/main/generated"
+	testGeneratedDir = "src/test/generated"
+	antlrOutput = "$mainGeneratedDir/antlr"
+}
+
+configurations {
+	antlr3
+}
+      
 project.ext.libraryVersions = [
 	jcache: '1.0.0',
 ]
@@ -15,12 +26,50 @@ dependencies {
 	compile project(":plastic")
 	compile project(":tapestry5-annotations")
 	compile project(":commons")
+	
+	// Antlr3 tool path used with the antlr3 task
+	antlr3 "org.antlr:antlr:3.5.2"
+
 	// Transitive will bring in the unwanted string template library as well
 	compile "org.antlr:antlr-runtime:3.5.2", {
 		exclude group: "org.antlr", module: "stringtemplate"
 	}
 }
 
+// This may spin out as a plugin once we've got the details down pat
+
+task generateGrammarSource(type: JavaExec) {
+	description "Generates Java sources from Antlr3 grammars."
+	inputs.source fileTree(dir: antlrSource, include: "**/*.g")
+	outputs.dir file(antlrOutput)
+
+	classpath configurations.antlr3
+
+	main "org.antlr.Tool"
+	args "-o", "${antlrOutput}/org/apache/tapestry5/internal/antlr"
+	args inputs.sourceFiles
+
+	doFirst {
+		logger.info "Executing Antlr3 grammar generation:\n${commandLine.join(' ')}"
+	}
+}
+
+sourceSets {
+	main {
+		output.dir(antlrOutput, builtBy: generateGrammarSource)
+		java {
+			srcDir antlrOutput
+		}
+	}
+}
+
+clean.delete mainGeneratedDir, testGeneratedDir
+
+compileJava {
+	dependsOn generateGrammarSource
+	options.fork(memoryMaximumSize: '512m')
+}
+
 jar {	
 	manifest {	
 	}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java
new file mode 100644
index 0000000..08cb88a
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java
@@ -0,0 +1,145 @@
+// 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 BeanModelUtils {
+	
+	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/c9e97d64/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 26eb309..b72a3d6 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.InternalUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
 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 InternalUtils.isNonBlank(propertyName);
+        assert InternalStringUtils.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/c9e97d64/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 703ce44..b21e5bb 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
@@ -14,17 +14,17 @@
 
 package org.apache.tapestry5.internal.beaneditor;
 
+import java.lang.annotation.Annotation;
+
 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.TapestryInternalUtils;
+import org.apache.tapestry5.internal.BeanModelUtils;
 import org.apache.tapestry5.ioc.Messages;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
 import org.apache.tapestry5.plastic.PlasticUtils;
 
-import java.lang.annotation.Annotation;
-
 @SuppressWarnings("all")
 public class PropertyModelImpl implements PropertyModel
 {
@@ -48,9 +48,9 @@ public class PropertyModelImpl implements PropertyModel
         this.name = name;
         this.conduit = conduit;
 
-        id = TapestryInternalUtils.extractIdFromPropertyExpression(name);
+        id = BeanModelUtils.extractIdFromPropertyExpression(name);
 
-        label = TapestryInternalUtils.defaultLabel(id, messages, name);
+        label = BeanModelUtils.defaultLabel(id, messages, name);
 
         // TAP5-2305
         if (conduit != null)
@@ -87,7 +87,7 @@ public class PropertyModelImpl implements PropertyModel
 
     public PropertyModel label(String label)
     {
-        assert InternalUtils.isNonBlank(label);
+        assert InternalStringUtils.isNonBlank(label);
         this.label = label;
 
         return this;

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
index 1242031..3849103 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
@@ -19,7 +19,6 @@ import java.lang.annotation.Annotation;
 import org.apache.tapestry5.internal.InternalPropertyConduit;
 import org.apache.tapestry5.internal.util.IntegerRange;
 import org.apache.tapestry5.ioc.AnnotationProvider;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
 import org.apache.tapestry5.ioc.services.TypeCoercer;
 
 /**

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/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 701420f..83f67fa 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,6 +19,7 @@ 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.BeanModelUtils;
 import org.apache.tapestry5.internal.InternalPropertyConduit;
 import org.apache.tapestry5.internal.antlr.PropertyExpressionLexer;
 import org.apache.tapestry5.internal.antlr.PropertyExpressionParser;
@@ -29,7 +30,7 @@ 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.InternalUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
 import org.apache.tapestry5.ioc.services.*;
 import org.apache.tapestry5.ioc.util.AvailableValues;
 import org.apache.tapestry5.ioc.util.ExceptionUtils;
@@ -1106,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()],
-                    InternalUtils.joinSorted(tokenNames));
+                    InternalStringUtils.joinSorted(tokenNames));
 
             return new RuntimeException(message);
         }
@@ -1259,7 +1260,7 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
 
             Type returnType = GenericsUtils.extractActualType(activeType, method);
 
-            return new Term(returnType, toUniqueId(method), InternalUtils.toAnnotationProvider(method), new InstructionBuilderCallback()
+            return new Term(returnType, toUniqueId(method), BeanModelUtils.toAnnotationProvider(method), new InstructionBuilderCallback()
             {
                 public void doBuild(InstructionBuilder builder)
                 {
@@ -1363,7 +1364,7 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
     public PropertyConduit create(Class rootClass, String expression)
     {
         assert rootClass != null;
-        assert InternalUtils.isNonBlank(expression);
+        assert InternalStringUtils.isNonBlank(expression);
 
         MultiKey key = new MultiKey(rootClass, expression);
 
@@ -1560,4 +1561,5 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
 
         return builder.append(")").toString();
     }
+    
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java b/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
index 81d1f77..e60c0d9 100644
--- a/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2010, 2011 The Apache Software Foundation
+// Copyright 2006, 2007, 2010, 2011, 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.
@@ -15,7 +15,6 @@
 package org.apache.tapestry5.ioc;
 
 import org.apache.tapestry5.ioc.annotations.Inject;
-import org.apache.tapestry5.ioc.services.MasterObjectProvider;
 
 import java.lang.annotation.Annotation;
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java
new file mode 100644
index 0000000..e345593
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java
@@ -0,0 +1,203 @@
+// Copyright 2006-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.util;
+
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * String-related utilities used within various internal implementations of the Apache Tapestry subprojects.
+ * Broken off Tapestry-IoC's InternalUtils.
+ */
+@SuppressWarnings("all")
+public class InternalStringUtils
+{
+	
+    /**
+     * Pattern used to eliminate leading and trailing underscores and dollar signs.
+     */
+    private static final Pattern NAME_PATTERN = Pattern.compile("^[_|$]*([\\p{javaJavaIdentifierPart}]+?)[_|$]*$",
+            Pattern.CASE_INSENSITIVE);
+
+    /**
+     * Converts a method to a user presentable string consisting of the containing class name, the method name, and the
+     * short form of the parameter list (the class name of each parameter type, shorn of the package name portion).
+     *
+     * @param method
+     * @return short string representation
+     */
+    public static String asString(Method method)
+    {
+        StringBuilder buffer = new StringBuilder();
+
+        buffer.append(method.getDeclaringClass().getName());
+        buffer.append(".");
+        buffer.append(method.getName());
+        buffer.append("(");
+
+        for (int i = 0; i < method.getParameterTypes().length; i++)
+        {
+            if (i > 0)
+                buffer.append(", ");
+
+            String name = method.getParameterTypes()[i].getSimpleName();
+
+            buffer.append(name);
+        }
+
+        return buffer.append(")").toString();
+    }
+
+    /**
+     * Strips leading "_" and "$" and trailing "_" from the name.
+     */
+    public static String stripMemberName(String memberName)
+    {
+        assert isNonBlank(memberName);
+        Matcher matcher = NAME_PATTERN.matcher(memberName);
+
+        if (!matcher.matches())
+            throw new IllegalArgumentException(String.format("Input '%s' is not a valid Java identifier.", memberName));
+
+        return matcher.group(1);
+    }
+
+    /**
+     * Joins together some number of elements to form a comma separated list.
+     */
+    public static String join(List elements)
+    {
+        return join(elements, ", ");
+    }
+
+    /**
+     * Joins together some number of elements. If a value in the list is the empty string, it is replaced with the
+     * string "(blank)".
+     *
+     * @param elements
+     *         objects to be joined together
+     * @param separator
+     *         used between elements when joining
+     */
+    public static String join(List elements, String separator)
+    {
+        switch (elements.size())
+        {
+            case 0:
+                return "";
+
+            case 1:
+                return elements.get(0).toString();
+
+            default:
+
+                StringBuilder buffer = new StringBuilder();
+                boolean first = true;
+
+                for (Object o : elements)
+                {
+                    if (!first)
+                        buffer.append(separator);
+
+                    String string = String.valueOf(o);
+
+                    if (string.equals(""))
+                        string = "(blank)";
+
+                    buffer.append(string);
+
+                    first = false;
+                }
+
+                return buffer.toString();
+        }
+    }
+
+    /**
+     * Creates a sorted copy of the provided elements, then turns that into a comma separated list.
+     *
+     * @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
+     *         empty
+     */
+    public static String joinSorted(Collection elements)
+    {
+        if (elements == null || elements.isEmpty())
+            return "(none)";
+
+        List<String> list = CollectionFactory.newList();
+
+        for (Object o : elements)
+            list.add(String.valueOf(o));
+
+        Collections.sort(list);
+
+        return join(list);
+    }
+
+    /**
+     * Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
+     */
+
+    public static boolean isBlank(String input)
+    {
+        return input == null || input.length() == 0 || input.trim().length() == 0;
+    }
+
+    public static boolean isNonBlank(String input)
+    {
+        return !isBlank(input);
+    }
+
+    /**
+     * Capitalizes a string, converting the first character to uppercase.
+     */
+    public static String capitalize(String input)
+    {
+        if (input.length() == 0)
+            return input;
+
+        return input.substring(0, 1).toUpperCase() + input.substring(1);
+    }
+
+    /**
+     * Return true if the input string contains the marker for symbols that must be expanded.
+     */
+    public static boolean containsSymbols(String input)
+    {
+        return input.contains("${");
+    }
+
+    /**
+     * Searches the string for the final period ('.') character and returns everything after that. The input string is
+     * generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
+     * expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
+     * character.
+     */
+    public static String lastTerm(String input)
+    {
+        assert isNonBlank(input);
+        int dotx = input.lastIndexOf('.');
+
+        if (dotx < 0)
+            return input;
+
+        return input.substring(dotx + 1);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
index ef217cb..d8d8018 100644
--- a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
@@ -34,7 +34,7 @@ public class TapestryException extends RuntimeException implements Locatable
      */
     public TapestryException(String message, Object location, Throwable cause)
     {
-        this(message, InternalUtils.locationOf(location), cause);
+        this(message, locationOf(location), cause);
     }
 
     /**
@@ -71,5 +71,26 @@ public class TapestryException extends RuntimeException implements Locatable
 
         return String.format("%s [at %s]", super.toString(), location);
     }
+    
+    /**
+     * Sniffs the object to see if it is a {@link Location} or {@link Locatable}. Returns null if null or not
+     * convertable to a location.
+     * Copied from InternalUtils to avoid having it moved to BeanModel or Commons subprojects.
+     */
+
+    private static Location locationOf(Object location)
+    {
+        if (location == null)
+            return null;
+
+        if (location instanceof Location)
+            return (Location) location;
+
+        if (location instanceof Locatable)
+            return ((Locatable) location).getLocation();
+
+        return null;
+    }
+
 
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
index c4c5c6d..8c9cb3f 100644
--- a/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
@@ -20,7 +20,7 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
 
 /**
  * Used (as part of a {@link UnknownValueException} to identify what available values
@@ -81,7 +81,7 @@ public class AvailableValues
     @Override
     public String toString()
     {
-        return String.format("AvailableValues[%s: %s]", valueType, InternalUtils.join(values));
+        return String.format("AvailableValues[%s: %s]", valueType, InternalStringUtils.join(values));
     }
 
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/tapestry-core/build.gradle
----------------------------------------------------------------------
diff --git a/tapestry-core/build.gradle b/tapestry-core/build.gradle
index 584200a..d35c166 100644
--- a/tapestry-core/build.gradle
+++ b/tapestry-core/build.gradle
@@ -8,11 +8,6 @@ project.ext {
     antlrSource = "src/main/antlr"
     mainGeneratedDir = "src/main/generated"
     testGeneratedDir = "src/test/generated"
-    antlrOutput = "$mainGeneratedDir/antlr"
-}
-
-configurations {
-    antlr3
 }
 
 dependencies {
@@ -27,30 +22,9 @@ dependencies {
 
     compile "commons-codec:commons-codec:1.5"
 
-    // Antlr3 tool path used with the antlr3 task
-    antlr3 "org.antlr:antlr:3.5.2"
-
     testRuntime "org.hsqldb:hsqldb:1.8.0.10"
 }
 
-// This may spin out as a plugin once we've got the details down pat
-
-task generateGrammarSource(type: JavaExec) {
-    description "Generates Java sources from Antlr3 grammars."
-    inputs.source fileTree(dir: antlrSource, include: "**/*.g")
-    outputs.dir file(antlrOutput)
-
-    classpath configurations.antlr3
-
-    main "org.antlr.Tool"
-    args "-o", "${antlrOutput}/org/apache/tapestry5/internal/antlr"
-    args inputs.sourceFiles
-
-    doFirst {
-        logger.info "Executing Antlr3 grammar generation:\n${commandLine.join(' ')}"
-    }
-}
-
 task preprocessCoffeeScript(type: PreprocessCoffeeScript) {
 }
 
@@ -73,23 +47,12 @@ sourceSets {
     main {
         output.dir(compileCoffeeScript.outputDir, builtBy: compileCoffeeScript)
         output.dir(compileProcessedCoffeescript.outputDir, builtBy: compileProcessedCoffeescript)
-        output.dir(antlrOutput, builtBy: generateGrammarSource)
-        java {
-            srcDir antlrOutput
-        }
     }
     test {
         output.dir(compileTestCoffeeScript.outputDir, builtBy: compileTestCoffeeScript)
     }
 }
 
-clean.delete mainGeneratedDir, testGeneratedDir
-
-compileJava {
-    dependsOn generateGrammarSource
-    options.fork(memoryMaximumSize: '512m')
-}
-
 // Not sure why this is necessary:
 compileTestGroovy.dependsOn compileTestJava
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
index 3435d64..aba7225 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
@@ -59,40 +59,7 @@ public class TapestryInternalUtils
      */
     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();
+        return BeanModelUtils.toUserPresentable(id);
     }
 
     public static Map<String, String> mapFromKeysAndValues(String... keysAndValues)
@@ -261,7 +228,7 @@ public class TapestryInternalUtils
      */
     public static String extractIdFromPropertyExpression(String expression)
     {
-        return replace(expression, NON_WORD_PATTERN, "");
+        return BeanModelUtils.extractIdFromPropertyExpression(expression);
     }
 
     /**
@@ -270,12 +237,7 @@ public class TapestryInternalUtils
      */
     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(lastTerm(propertyExpression)));
+        return BeanModelUtils.defaultLabel(id, messages, propertyExpression);
     }
 
     /**
@@ -342,7 +304,7 @@ public class TapestryInternalUtils
 
     private static String replace(String input, Pattern pattern, String replacement)
     {
-        return pattern.matcher(input).replaceAll(replacement);
+        return BeanModelUtils.replace(input, pattern, replacement);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
index e9e7806..a40f984 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
@@ -17,16 +17,16 @@ package org.apache.tapestry5.ioc.internal.util;
 import org.apache.tapestry5.func.F;
 import org.apache.tapestry5.func.Mapper;
 import org.apache.tapestry5.func.Predicate;
+import org.apache.tapestry5.internal.BeanModelUtils;
 import org.apache.tapestry5.internal.plastic.PlasticInternalUtils;
 import org.apache.tapestry5.ioc.*;
 import org.apache.tapestry5.ioc.annotations.*;
 import org.apache.tapestry5.ioc.def.*;
-import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
 import org.apache.tapestry5.ioc.internal.ServiceDefImpl;
 import org.apache.tapestry5.ioc.services.Coercion;
-import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
 import org.apache.tapestry5.ioc.util.ExceptionUtils;
 import org.apache.tapestry5.plastic.PlasticUtils;
+import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
 import org.slf4j.Logger;
 
 import javax.annotation.PostConstruct;
@@ -56,18 +56,6 @@ public class InternalUtils
     public static final boolean SERVICE_CLASS_RELOADING_ENABLED = Boolean.parseBoolean(System.getProperty(
             IOCConstants.SERVICE_CLASS_RELOADING_ENABLED, "true"));
 
-
-    /**
-     * Pattern used to eliminate leading and trailing underscores and dollar signs.
-     */
-    private static final Pattern NAME_PATTERN = Pattern.compile("^[_|$]*([\\p{javaJavaIdentifierPart}]+?)[_|$]*$",
-            Pattern.CASE_INSENSITIVE);
-
-    /**
-     * @since 5.3
-     */
-    public static AnnotationProvider NULL_ANNOTATION_PROVIDER = new NullAnnotationProvider();
-
     /**
      * Converts a method to a user presentable string using a {@link PlasticProxyFactory} to obtain a {@link Location}
      * (where possible). {@link #asString(Method)} is used under the covers, to present a detailed, but not excessive,
@@ -92,27 +80,11 @@ public class InternalUtils
      *
      * @param method
      * @return short string representation
+     * @deprecated use {@link InternalStringUtils#asString(Method)} instead.
      */
     public static String asString(Method method)
     {
-        StringBuilder buffer = new StringBuilder();
-
-        buffer.append(method.getDeclaringClass().getName());
-        buffer.append(".");
-        buffer.append(method.getName());
-        buffer.append("(");
-
-        for (int i = 0; i < method.getParameterTypes().length; i++)
-        {
-            if (i > 0)
-                buffer.append(", ");
-
-            String name = method.getParameterTypes()[i].getSimpleName();
-
-            buffer.append(name);
-        }
-
-        return buffer.append(")").toString();
+        return InternalStringUtils.asString(method);
     }
 
     /**
@@ -131,16 +103,11 @@ public class InternalUtils
 
     /**
      * Strips leading "_" and "$" and trailing "_" from the name.
+     * @deprecated use {@link InternalStringUtils#stripMemberName(String)} instead.
      */
     public static String stripMemberName(String memberName)
     {
-        assert InternalUtils.isNonBlank(memberName);
-        Matcher matcher = NAME_PATTERN.matcher(memberName);
-
-        if (!matcher.matches())
-            throw new IllegalArgumentException(String.format("Input '%s' is not a valid Java identifier.", memberName));
-
-        return matcher.group(1);
+        return InternalStringUtils.stripMemberName(memberName);
     }
 
     /**
@@ -425,10 +392,11 @@ public class InternalUtils
 
     /**
      * Joins together some number of elements to form a comma separated list.
+     * @deprecated use {@link InternalStringUtils#join(List)} instead.
      */
     public static String join(List elements)
     {
-        return join(elements, ", ");
+        return InternalStringUtils.join(elements);
     }
 
     /**
@@ -439,39 +407,11 @@ public class InternalUtils
      *         objects to be joined together
      * @param separator
      *         used between elements when joining
+     * @deprecated use {@link InternalStringUtils#asString(Method, String)} instead.
      */
     public static String join(List elements, String separator)
     {
-        switch (elements.size())
-        {
-            case 0:
-                return "";
-
-            case 1:
-                return elements.get(0).toString();
-
-            default:
-
-                StringBuilder buffer = new StringBuilder();
-                boolean first = true;
-
-                for (Object o : elements)
-                {
-                    if (!first)
-                        buffer.append(separator);
-
-                    String string = String.valueOf(o);
-
-                    if (string.equals(""))
-                        string = "(blank)";
-
-                    buffer.append(string);
-
-                    first = false;
-                }
-
-                return buffer.toString();
-        }
+        return InternalStringUtils.join(elements, separator);
     }
 
     /**
@@ -479,29 +419,21 @@ public class InternalUtils
      *
      * @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
      *         empty
+     * @deprecated use {@link InternalStringUtils#joinSorted(Collection)} instead.
      */
     public static String joinSorted(Collection elements)
     {
-        if (elements == null || elements.isEmpty())
-            return "(none)";
-
-        List<String> list = CollectionFactory.newList();
-
-        for (Object o : elements)
-            list.add(String.valueOf(o));
-
-        Collections.sort(list);
-
-        return join(list);
+        return InternalStringUtils.joinSorted(elements);
     }
 
     /**
      * Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
+     * @deprecated use {@link InternalStringUtils#isBlank(String)} instead.
      */
 
     public static boolean isBlank(String input)
     {
-        return input == null || input.length() == 0 || input.trim().length() == 0;
+        return InternalStringUtils.isBlank(input);
     }
 
     /**
@@ -518,20 +450,21 @@ public class InternalUtils
         return false;
     }
 
+    /**
+     * @deprecated use {@link InternalStringUtils#isNonBlank(String)} instead.
+     */
     public static boolean isNonBlank(String input)
     {
-        return !isBlank(input);
+        return InternalStringUtils.isNonBlank(input);
     }
 
     /**
      * Capitalizes a string, converting the first character to uppercase.
+     * @deprecated use {@link InternalStringUtils#capitalize(String)} instead.
      */
     public static String capitalize(String input)
     {
-        if (input.length() == 0)
-            return input;
-
-        return input.substring(0, 1).toUpperCase() + input.substring(1);
+        return InternalStringUtils.capitalize(input);
     }
 
     /**
@@ -639,10 +572,11 @@ public class InternalUtils
 
     /**
      * Return true if the input string contains the marker for symbols that must be expanded.
+     * @deprecated use {@link InternalStringUtils#containsSymbols(String)} instead.
      */
     public static boolean containsSymbols(String input)
     {
-        return input.contains("${");
+        return InternalStringUtils.containsSymbols(input);
     }
 
     /**
@@ -650,16 +584,11 @@ public class InternalUtils
      * generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
      * expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
      * character.
+     * @deprecated use {@link InternalStringUtils#lastTerm(String)} instead.
      */
     public static String lastTerm(String input)
     {
-        assert InternalUtils.isNonBlank(input);
-        int dotx = input.lastIndexOf('.');
-
-        if (dotx < 0)
-            return input;
-
-        return input.substring(dotx + 1);
+        return InternalStringUtils.lastTerm(input);
     }
 
     /**
@@ -848,18 +777,9 @@ public class InternalUtils
      */
     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));
-            }
-        };
+        return BeanModelUtils.toAnnotationProvider(element);
     }
 
-    ;
-
     /**
      * @since 5.3
      */
@@ -1484,17 +1404,7 @@ public class InternalUtils
 
     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);
-            }
-        };
+        return BeanModelUtils.toAnnotationProvider(element);
     }
 
     public static <T> ObjectCreator<T> createConstructorConstructionPlan(final OperationTracker tracker, final ObjectLocator locator,


[02/15] tapestry-5 git commit: First pass creating the BeanModel and Commons packages. Lots of stuff moved around, but no actual code changes so far

Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
deleted file mode 100644
index 81d1f77..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright 2006, 2007, 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;
-
-import org.apache.tapestry5.ioc.annotations.Inject;
-import org.apache.tapestry5.ioc.services.MasterObjectProvider;
-
-import java.lang.annotation.Annotation;
-
-/**
- * Defines an object which can provide access to services defined within a {@link org.apache.tapestry5.ioc.Registry}, or
- * to objects or object instances available by other means. Services are accessed via service id, or
- * (when appropriate)
- * by just service interface. The Registry itself implements this interface, as does
- * {@link org.apache.tapestry5.ioc.ServiceResources}.
- */
-public interface ObjectLocator
-{
-    /**
-     * Obtains a service via its unique service id. Returns the service's proxy. The service proxy
-     * implements the same
-     * interface as the actual service, and is used to instantiate the actual service only as needed
-     * (this is
-     * transparent to the application).
-     *
-     * @param <T>
-     * @param serviceId        unique Service id used to locate the service object (may contain <em>symbols</em>,
-     *                         which
-     *                         will be expanded), case is ignored
-     * @param serviceInterface the interface implemented by the service (or an interface extended by the service
-     *                         interface)
-     * @return the service instance
-     * @throws RuntimeException if the service is not defined, or if an error occurs instantiating it
-     */
-    <T> T getService(String serviceId, Class<T> serviceInterface);
-
-    /**
-     * Locates a service given a service interface and (optionally) some marker annotation types. A single service must implement the service
-     * interface (which                                                   * can be hard to guarantee) and by marked by all the marker types. The search takes into account inheritance of the service interface
-     * (not the service <em>implementation</em>), which may result in a failure due to extra
-     * matches.
-     *
-     * @param serviceInterface the interface the service implements
-     * @return the service's proxy
-     * @throws RuntimeException if the service does not exist (this is considered programmer error), or multiple
-     *                          services directly implement, or extend from, the service interface
-     * @see org.apache.tapestry5.ioc.annotations.Marker
-     */
-    <T> T getService(Class<T> serviceInterface);
-
-    /**
-     * Locates a service given a service interface and (optionally) some marker annotation types. A single service must implement the service
-     * interface (which                                                   * can be hard to guarantee) and by marked by all the marker types. The search takes into account inheritance of the service interface
-     * (not the service <em>implementation</em>), which may result in a failure due to extra
-     * matches.        The ability to specify marker annotation types was added in 5.3
-     *
-     * @param serviceInterface the interface the service implements
-     * @param markerTypes      Markers used to select a specific service that implements the interface
-     * @return the service's proxy
-     * @throws RuntimeException if the service does not exist (this is considered programmer error), or multiple
-     *                          services directly implement, or extend from, the service interface
-     * @see org.apache.tapestry5.ioc.annotations.Marker
-     * @since 5.3
-     */
-    <T> T getService(Class<T> serviceInterface, Class<? extends Annotation>... markerTypes);
-
-    /**
-     * Obtains an object indirectly, using the {@link org.apache.tapestry5.ioc.services.MasterObjectProvider} service.
-     *
-     * @param objectType         the type of object to be returned
-     * @param annotationProvider provides access to annotations on the field or parameter for which a value is to
-     *                           be
-     *                           obtained, which may be utilized in selecting an appropriate object, use
-     *                           <strong>null</strong> when annotations are not available (in which case, selection
-     *                           will
-     *                           be based only on the object type)
-     * @param <T>
-     * @return the requested object
-     * @see ObjectProvider
-     */
-    <T> T getObject(Class<T> objectType, AnnotationProvider annotationProvider);
-
-    /**
-     * Autobuilds a class by finding the public constructor with the most parameters. Services and other resources or
-     * dependencies will be injected into the parameters of the constructor and into private fields marked with the
-     * {@link Inject} annotation. There are two cases: constructing a service implementation, and constructing
-     * an arbitrary object. In the former case, many <em>service resources</em> are also available for injection, not
-     * just dependencies or objects provided via
-     * {@link MasterObjectProvider#provide(Class, AnnotationProvider, ObjectLocator, boolean)}.
-     *
-     * @param <T>
-     * @param clazz the type of object to instantiate
-     * @return the instantiated instance
-     * @throws RuntimeException if the autobuild fails
-     * @see MasterObjectProvider
-     */
-    <T> T autobuild(Class<T> clazz);
-
-    /**
-     * Preferred version of {@link #autobuild(Class)} that tracks the operation using
-     * {@link OperationTracker#invoke(String, Invokable)}.
-     *
-     * @param <T>
-     * @param description description used with {@link OperationTracker}
-     * @param clazz       the type of object to instantiate
-     * @return the instantiated instance
-     * @throws RuntimeException if the autobuild fails
-     * @see MasterObjectProvider
-     * @since 5.2.0
-     */
-    <T> T autobuild(String description, Class<T> clazz);
-
-    /**
-     * Creates a proxy. The proxy will defer invocation of {@link #autobuild(Class)} until
-     * just-in-time (that is, first method invocation). In a limited number of cases, it is necessary to use such a
-     * proxy to prevent service construction cycles, particularly when contributing (directly or indirectly) to the
-     * {@link org.apache.tapestry5.ioc.services.MasterObjectProvider} (which is itself at the heart
-     * of autobuilding).
-     * <p/>
-     * If the class file for the class is a file on the file system (not a file packaged in a JAR), then the proxy will
-     * <em>autoreload</em>: changing the class file will result in the new class being reloaded and re-instantiated
-     * (with dependencies).
-     *
-     * @param <T>
-     * @param interfaceClass      the interface implemented by the proxy
-     * @param implementationClass a concrete class that implements the interface
-     * @return a proxy
-     * @see #autobuild(Class)
-     */
-    <T> T proxy(Class<T> interfaceClass, Class<? extends T> implementationClass);
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Resource.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Resource.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Resource.java
deleted file mode 100644
index b81c1c5..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Resource.java
+++ /dev/null
@@ -1,108 +0,0 @@
-// 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;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.Locale;
-
-/**
- * Represents a resource on the server that may be used for server side processing, or may be exposed to the client
- * side. Generally, this represents an abstraction on top of files on the class path and files stored in the web
- * application context.
- * <p/>
- * Resources are often used as map keys; they should be immutable and should implement hashCode() and equals().
- */
-public interface Resource
-{
-
-    /**
-     * Returns true if the resource exists; if a stream to the content of the file may be opened. A resource exists
-     * if {@link #toURL()} returns a non-null value. Starting in release 5.3.4, the result of this is cached.
-     * <p/>
-     * Starting in 5.4, some "virtual resources", may return true even though {@link #toURL()} returns null.
-     *
-     * @return true if the resource exists, false if it does not
-     */
-    boolean exists();
-
-
-    /**
-     * Returns true if the resource is virtual, meaning this is no underlying file. Many operations are unsupported
-     * on virtual resources, including {@link #toURL()}, {@link #forLocale(java.util.Locale)},
-     * {@link #withExtension(String)}, {@link #getFile()}, {@link #getFolder()}, {@link #getPath()}}; these
-     * operations will throw an {@link java.lang.UnsupportedOperationException}.
-     *
-     * @since 5.4
-     */
-    boolean isVirtual();
-
-    /**
-     * Opens a stream to the content of the resource, or returns null if the resource does not exist. The native
-     * input stream supplied by the resource is wrapped in a {@link java.io.BufferedInputStream}.
-     *
-     * @return an open, buffered stream to the content, if available
-     */
-    InputStream openStream() throws IOException;
-
-    /**
-     * Returns the URL for the resource, or null if it does not exist. This value is lazily computed; starting in 5.3.4, subclasses may cache
-     * the result.  Starting in 5.4, some "virtual resources" may return null.
-     */
-    URL toURL();
-
-    /**
-     * Returns a localized version of the resource. May return null if no such resource exists. Starting in release
-     * 5.3.4, the result of this method is cached internally.
-     */
-    Resource forLocale(Locale locale);
-
-    /**
-     * Returns a Resource based on a relative path, relative to the folder containing the resource. Understands the "."
-     * (current folder) and ".." (parent folder) conventions, and treats multiple sequential slashes as a single slash.
-     * <p/>
-     * Virtual resources (resources fabricated at runtime) return themselves.
-     */
-    Resource forFile(String relativePath);
-
-    /**
-     * Returns a new Resource with the extension changed (or, if the resource does not have an extension, the extension
-     * is added). The new Resource may not exist (that is, {@link #toURL()} may return null.
-     *
-     * @param extension
-     *         to apply to the resource, such as "html" or "properties"
-     * @return the new resource
-     */
-    Resource withExtension(String extension);
-
-    /**
-     * Returns the portion of the path up to the last forward slash; this is the directory or folder portion of the
-     * Resource.
-     */
-    String getFolder();
-
-    /**
-     * Returns the file portion of the Resource path, everything that follows the final forward slash.
-     * <p/>
-     * Starting in 5.4, certain kinds of "virtual resources" may return null here.
-     */
-    String getFile();
-
-    /**
-     * Return the path (the combination of folder and file).
-     * <p/>
-     * Starting in 5.4, certain "virtual resources", may return an arbitrary value here.
-     */
-    String getPath();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesConfiguration.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesConfiguration.java
deleted file mode 100644
index 2e03557..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesConfiguration.java
+++ /dev/null
@@ -1,34 +0,0 @@
-//  Copyright 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.annotations;
-
-import java.lang.annotation.*;
-
-
-/**
- * A documentation-only interface placed on service interfaces for services which have an {@linkplain
- * org.apache.tapestry5.ioc.Configuration unordered configuration}, to identify the type of contribution.
- */
-@Target(ElementType.TYPE)
-@Retention(RetentionPolicy.CLASS)
-@Documented
-@UseWith(AnnotationUseContext.SERVICE)
-public @interface UsesConfiguration
-{
-    /**
-     * The type of object which may be contributed into the service's configuration.
-     */
-    Class value();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java
deleted file mode 100644
index 716b7c6..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2007 The Apache Software Foundation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.apache.tapestry5.ioc.internal;
-
-import org.apache.tapestry5.ioc.AnnotationProvider;
-
-import java.lang.annotation.Annotation;
-
-/**
- * A null implementation of {@link AnnotationProvider}, used when there is not appropriate source of annotations.
- */
-public class NullAnnotationProvider implements AnnotationProvider
-{
-    /**
-     * Always returns null.
-     */
-    @Override
-    public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
-    {
-        return null;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java
deleted file mode 100644
index 6711b1a..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright 2006, 2007, 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.util;
-
-import org.apache.tapestry5.ioc.util.CaseInsensitiveMap;
-import org.apache.tapestry5.ioc.util.Stack;
-
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-/**
- * Static factory methods to ease the creation of new collection types (when using generics). Most of these method
- * leverage the compiler's ability to match generic types by return value. Typical usage (with a static import):
- * <p/>
- * <pre>
- * Map&lt;Foo, Bar&gt; map = newMap();
- * </pre>
- * <p/>
- * <p/>
- * This is a replacement for:
- * <p/>
- * <pre>
- * Map&lt;Foo, Bar&gt; map = new HashMap&lt;Foo, Bar&gt;();
- * </pre>
- */
-public final class CollectionFactory
-{
-    /**
-     * Constructs and returns a generic {@link HashMap} instance.
-     */
-    public static <K, V> Map<K, V> newMap()
-    {
-        return new HashMap<K, V>();
-    }
-
-    /**
-     * Constructs and returns a generic {@link java.util.HashSet} instance.
-     */
-    public static <T> Set<T> newSet()
-    {
-        return new HashSet<T>();
-    }
-
-    /**
-     * Contructs a new {@link HashSet} and initializes it using the provided collection.
-     */
-    public static <T, V extends T> Set<T> newSet(Collection<V> values)
-    {
-        return new HashSet<T>(values);
-    }
-
-    public static <T, V extends T> Set<T> newSet(V... values)
-    {
-        // Was a call to newSet(), but Sun JDK can't handle that. Fucking generics.
-        return new HashSet<T>(Arrays.asList(values));
-    }
-
-    /**
-     * Constructs a new {@link java.util.HashMap} instance by copying an existing Map instance.
-     */
-    public static <K, V> Map<K, V> newMap(Map<? extends K, ? extends V> map)
-    {
-        return new HashMap<K, V>(map);
-    }
-
-    /**
-     * Constructs a new concurrent map, which is safe to access via multiple threads.
-     */
-    public static <K, V> ConcurrentMap<K, V> newConcurrentMap()
-    {
-        return new ConcurrentHashMap<K, V>();
-    }
-
-    /**
-     * Contructs and returns a new generic {@link java.util.ArrayList} instance.
-     */
-    public static <T> List<T> newList()
-    {
-        return new ArrayList<T>();
-    }
-
-    /**
-     * Creates a new, fully modifiable list from an initial set of elements.
-     */
-    public static <T, V extends T> List<T> newList(V... elements)
-    {
-        // Was call to newList(), but Sun JDK can't handle that.
-        return new ArrayList<T>(Arrays.asList(elements));
-    }
-
-    /**
-     * Useful for queues.
-     */
-    public static <T> LinkedList<T> newLinkedList()
-    {
-        return new LinkedList<T>();
-    }
-
-    /**
-     * Constructs and returns a new {@link java.util.ArrayList} as a copy of the provided collection.
-     */
-    public static <T, V extends T> List<T> newList(Collection<V> list)
-    {
-        return new ArrayList<T>(list);
-    }
-
-    /**
-     * Constructs and returns a new {@link java.util.concurrent.CopyOnWriteArrayList}.
-     */
-    public static <T> List<T> newThreadSafeList()
-    {
-        return new CopyOnWriteArrayList<T>();
-    }
-
-    public static <T> Stack<T> newStack()
-    {
-        return new Stack<T>();
-    }
-
-    public static <V> Map<String, V> newCaseInsensitiveMap()
-    {
-        return new CaseInsensitiveMap<V>();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
deleted file mode 100644
index 1a6dd80..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
+++ /dev/null
@@ -1,615 +0,0 @@
-// Copyright 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.util;
-
-import java.lang.reflect.*;
-import java.util.LinkedList;
-
-/**
- * Static methods related to the use of JDK 1.5 generics.
- */
-@SuppressWarnings("unchecked")
-public class GenericsUtils
-{
-    /**
-     * Analyzes the method in the context of containingClass and returns the Class that is represented by
-     * the method's generic return type. Any parameter information in the generic return type is lost. If you want
-     * to preserve the type parameters of the return type consider using
-     * {@link #extractActualType(java.lang.reflect.Type, java.lang.reflect.Method)}.
-     *
-     * @param containingClass class which either contains or inherited the method
-     * @param method          method from which to extract the return type
-     * @return the class represented by the methods generic return type, resolved based on the context .
-     * @see #extractActualType(java.lang.reflect.Type, java.lang.reflect.Method)
-     * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
-     * @see #asClass(java.lang.reflect.Type)
-     */
-    public static Class<?> extractGenericReturnType(Class<?> containingClass, Method method)
-    {
-        return asClass(resolve(method.getGenericReturnType(), containingClass));
-    }
-
-
-    /**
-     * Analyzes the field in the context of containingClass and returns the Class that is represented by
-     * the field's generic type. Any parameter information in the generic type is lost, if you want
-     * to preserve the type parameters of the return type consider using
-     * {@link #getTypeVariableIndex(java.lang.reflect.TypeVariable)}.
-     *
-     * @param containingClass class which either contains or inherited the field
-     * @param field           field from which to extract the type
-     * @return the class represented by the field's generic type, resolved based on the containingClass.
-     * @see #extractActualType(java.lang.reflect.Type, java.lang.reflect.Field)
-     * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
-     * @see #asClass(java.lang.reflect.Type)
-     */
-    public static Class extractGenericFieldType(Class containingClass, Field field)
-    {
-        return asClass(resolve(field.getGenericType(), containingClass));
-    }
-
-    /**
-     * Analyzes the method in the context of containingClass and returns the Class that is represented by
-     * the method's generic return type. Any parameter information in the generic return type is lost.
-     *
-     * @param containingType Type which is/represents the class that either contains or inherited the method
-     * @param method         method from which to extract the generic return type
-     * @return the generic type represented by the methods generic return type, resolved based on the containingType.
-     * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
-     */
-    public static Type extractActualType(Type containingType, Method method)
-    {
-        return resolve(method.getGenericReturnType(), containingType);
-    }
-
-    /**
-     * Analyzes the method in the context of containingClass and returns the Class that is represented by
-     * the method's generic return type. Any parameter information in the generic return type is lost.
-     *
-     * @param containingType Type which is/represents the class that either contains or inherited the field
-     * @param field          field from which to extract the generic return type
-     * @return the generic type represented by the methods generic return type, resolved based on the containingType.
-     * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
-     */
-    public static Type extractActualType(Type containingType, Field field)
-    {
-        return resolve(field.getGenericType(), containingType);
-    }
-
-    /**
-     * Resolves the type parameter based on the context of the containingType.
-     * <p/>
-     * {@link java.lang.reflect.TypeVariable} will be unwrapped to the type argument resolved form the class
-     * hierarchy. This may be something other than a simple Class if the type argument is a ParameterizedType for
-     * instance (e.g. List&lt;E>; List&lt;Map&lt;Long, String>>, E would be returned as a ParameterizedType with the raw
-     * type Map and type arguments Long and String.
-     * <p/>
-     *
-     * @param type
-     *          the generic type (ParameterizedType, GenericArrayType, WildcardType, TypeVariable) to be resolved
-     * @param containingType
-     *          the type which his
-     * @return
-     *          the type resolved to the best of our ability.
-     * @since 5.2.?
-     */
-    public static Type resolve(final Type type, final Type containingType)
-    {
-        // The type isn't generic. (String, Long, etc)
-        if (type instanceof Class)
-            return type;
-
-        // List<T>, List<String>, List<T extends Number>
-        if (type instanceof ParameterizedType)
-            return resolve((ParameterizedType) type, containingType);
-
-        // T[], List<String>[], List<T>[]
-        if (type instanceof GenericArrayType)
-            return resolve((GenericArrayType) type, containingType);
-
-        // List<? extends T>, List<? extends Object & Comparable & Serializable>
-        if (type instanceof WildcardType)
-            return resolve((WildcardType) type, containingType);
-
-        // T
-        if (type instanceof TypeVariable)
-            return resolve((TypeVariable) type, containingType);
-
-        // I'm leaning towards an exception here.
-        return type;
-    }
-
-
-    /**
-     * Determines if the suspected super type is assignable from the suspected sub type.
-     *
-     * @param suspectedSuperType
-     *          e.g. GenericDAO&lt;Pet, String>
-     * @param suspectedSubType
-     *          e.g. PetDAO extends GenericDAO&lt;Pet,String>
-     * @return
-     *          true if (sourceType)targetClass is a valid cast
-     */
-    public static boolean isAssignableFrom(Type suspectedSuperType, Type suspectedSubType)
-    {
-        final Class suspectedSuperClass = asClass(suspectedSuperType);
-        final Class suspectedSubClass = asClass(suspectedSubType);
-
-        // The raw types need to be compatible.
-        if (!suspectedSuperClass.isAssignableFrom(suspectedSubClass))
-        {
-            return false;
-        }
-
-        // From this point we know that the raw types are assignable.
-        // We need to figure out what the generic parameters in the targetClass are
-        // as they pertain to the sourceType.
-
-        if (suspectedSuperType instanceof WildcardType)
-        {
-            // ? extends Number
-            // needs to match all the bounds (there will only be upper bounds or lower bounds
-            for (Type t : ((WildcardType) suspectedSuperType).getUpperBounds())
-            {
-                if (!isAssignableFrom(t, suspectedSubType)) return false;
-            }
-            for (Type t : ((WildcardType) suspectedSuperType).getLowerBounds())
-            {
-                if (!isAssignableFrom(suspectedSubType, t)) return false;
-            }
-            return true;
-        }
-
-        Type curType = suspectedSubType;
-        Class curClass;
-
-        while (curType != null && !curType.equals(Object.class))
-        {
-            curClass = asClass(curType);
-
-            if (curClass.equals(suspectedSuperClass))
-            {
-                final Type resolved = resolve(curType, suspectedSubType);
-
-                if (suspectedSuperType instanceof Class)
-                {
-                    if ( resolved instanceof Class )
-                        return suspectedSuperType.equals(resolved);
-
-                    // They may represent the same class, but the suspectedSuperType is not parameterized. The parameter
-                    // types default to Object so they must be a match.
-                    // e.g. Pair p = new StringLongPair();
-                    //      Pair p = new Pair<? extends Number, String>
-
-                    return true;
-                }
-
-                if (suspectedSuperType instanceof ParameterizedType)
-                {
-                    if (resolved instanceof ParameterizedType)
-                    {
-                        final Type[] type1Arguments = ((ParameterizedType) suspectedSuperType).getActualTypeArguments();
-                        final Type[] type2Arguments = ((ParameterizedType) resolved).getActualTypeArguments();
-                        if (type1Arguments.length != type2Arguments.length) return false;
-
-                        for (int i = 0; i < type1Arguments.length; ++i)
-                        {
-                            if (!isAssignableFrom(type1Arguments[i], type2Arguments[i])) return false;
-                        }
-                        return true;
-                    }
-                }
-                else if (suspectedSuperType instanceof GenericArrayType)
-                {
-                    if (resolved instanceof GenericArrayType)
-                    {
-                        return isAssignableFrom(
-                                ((GenericArrayType) suspectedSuperType).getGenericComponentType(),
-                                ((GenericArrayType) resolved).getGenericComponentType()
-                        );
-                    }
-                }
-
-                return false;
-            }
-
-            final Type[] types = curClass.getGenericInterfaces();
-            for (Type t : types)
-            {
-                final Type resolved = resolve(t, suspectedSubType);
-                if (isAssignableFrom(suspectedSuperType, resolved))
-                    return true;
-            }
-
-            curType = curClass.getGenericSuperclass();
-        }
-        return false;
-    }
-
-    /**
-     * Get the class represented by the reflected type.
-     * This method is lossy; You cannot recover the type information from the class that is returned.
-     * <p/>
-     * {@code TypeVariable} the first bound is returned. If your type variable extends multiple interfaces that information
-     * is lost.
-     * <p/>
-     * {@code WildcardType} the first lower bound is returned. If the wildcard is defined with upper bounds
-     * then {@code Object} is returned.
-     *
-     * @param actualType
-     *           a Class, ParameterizedType, GenericArrayType
-     * @return the un-parameterized class associated with the type.
-     */
-    public static Class asClass(Type actualType)
-    {
-        if (actualType instanceof Class) return (Class) actualType;
-
-        if (actualType instanceof ParameterizedType)
-        {
-            final Type rawType = ((ParameterizedType) actualType).getRawType();
-            // The sun implementation returns getRawType as Class<?>, but there is room in the interface for it to be
-            // some other Type. We'll assume it's a Class.
-            // TODO: consider logging or throwing our own exception for that day when "something else" causes some confusion
-            return (Class) rawType;
-        }
-
-        if (actualType instanceof GenericArrayType)
-        {
-            final Type type = ((GenericArrayType) actualType).getGenericComponentType();
-            return Array.newInstance(asClass(type), 0).getClass();
-        }
-
-        if (actualType instanceof TypeVariable)
-        {
-            // Support for List<T extends Number>
-            // There is always at least one bound. If no bound is specified in the source then it will be Object.class
-            return asClass(((TypeVariable) actualType).getBounds()[0]);
-        }
-
-        if (actualType instanceof WildcardType)
-        {
-            final WildcardType wildcardType = (WildcardType) actualType;
-            final Type[] bounds = wildcardType.getLowerBounds();
-            if (bounds != null && bounds.length > 0)
-            {
-                return asClass(bounds[0]);
-            }
-            // If there is no lower bounds then the only thing that makes sense is Object.
-            return Object.class;
-        }
-
-        throw new RuntimeException(String.format("Unable to convert %s to Class.", actualType));
-    }
-
-    /**
-     * Convert the type into a string. The string representation approximates the code that would be used to define the
-     * type.
-     *
-     * @param type - the type.
-     * @return a string representation of the type, similar to how it was declared.
-     */
-    public static String toString(Type type)
-    {
-        if ( type instanceof ParameterizedType ) return toString((ParameterizedType)type);
-        if ( type instanceof WildcardType ) return toString((WildcardType)type);
-        if ( type instanceof GenericArrayType) return toString((GenericArrayType)type);
-        if ( type instanceof Class )
-        {
-            final Class theClass = (Class) type;
-            return (theClass.isArray() ? theClass.getName() + "[]" : theClass.getName());
-        }
-        return type.toString();
-    }
-
-    /**
-     * Method to resolve a TypeVariable to its most
-     * <a href="http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#112582">reifiable</a> form.
-     * <p/>
-     * <p/>
-     * How to resolve a TypeVariable:<br/>
-     * All of the TypeVariables defined by a generic class will be given a Type by any class that extends it. The Type
-     * given may or may not be reifiable; it may be another TypeVariable for instance.
-     * <p/>
-     * Consider <br/>
-     * <i>class Pair&gt;A,B> { A getA(){...}; ...}</i><br/>
-     * <i>class StringLongPair extends Pair&gt;String, Long> { }</i><br/>
-     * <p/>
-     * To resolve the actual return type of Pair.getA() you must first resolve the TypeVariable "A".
-     * We can do that by first finding the index of "A" in the Pair.class.getTypeParameters() array of TypeVariables.
-     * <p/>
-     * To get to the Type provided by StringLongPair you access the generics information by calling
-     * StringLongPair.class.getGenericSuperclass; this will be a ParameterizedType. ParameterizedType gives you access
-     * to the actual type arguments provided to Pair by StringLongPair. The array is in the same order as the array in
-     * Pair.class.getTypeParameters so you can use the index we discovered earlier to extract the Type; String.class.
-     * <p/>
-     * When extracting Types we only have to consider the superclass hierarchy and not the interfaces implemented by
-     * the class. When a class implements a generic interface it must provide types for the interface and any generic
-     * methods implemented from the interface will be re-defined by the class with its generic type variables.
-     *
-     * @param typeVariable   - the type variable to resolve.
-     * @param containingType - the shallowest class in the class hierarchy (furthest from Object) where typeVariable is defined.
-     * @return a Type that has had all possible TypeVariables resolved that have been defined between the type variable
-     *         declaration and the containingType.
-     */
-    private static Type resolve(TypeVariable typeVariable, Type containingType)
-    {
-        // The generic declaration is either a Class, Method or Constructor
-        final GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
-
-        if (!(genericDeclaration instanceof Class))
-        {
-            // It's a method or constructor. The best we can do here is try to resolve the bounds
-            // e.g. <T extends E> T getT(T param){} where E is defined by the class.
-            final Type bounds0 = typeVariable.getBounds()[0];
-            return resolve(bounds0, containingType);
-        }
-
-        final Class typeVariableOwner = (Class) genericDeclaration;
-
-        // find the typeOwner in the containingType's hierarchy
-        final LinkedList<Type> stack = new LinkedList<Type>();
-
-        // If you pass a List<Long> as the containingType then the TypeVariable is going to be resolved by the
-        // containingType and not the super class.
-        if (containingType instanceof ParameterizedType)
-        {
-            stack.add(containingType);
-        }
-
-        Class theClass = asClass(containingType);
-        Type genericSuperclass = theClass.getGenericSuperclass();
-        while (genericSuperclass != null && // true for interfaces with no superclass
-                !theClass.equals(Object.class) &&
-                !theClass.equals(typeVariableOwner))
-        {
-            stack.addFirst(genericSuperclass);
-            theClass = asClass(genericSuperclass);
-            genericSuperclass = theClass.getGenericSuperclass();
-        }
-
-        int i = getTypeVariableIndex(typeVariable);
-        Type resolved = typeVariable;
-        for (Type t : stack)
-        {
-            if (t instanceof ParameterizedType)
-            {
-                resolved = ((ParameterizedType) t).getActualTypeArguments()[i];
-                if (resolved instanceof Class) return resolved;
-                if (resolved instanceof TypeVariable)
-                {
-                    // Need to look at the next class in the hierarchy
-                    i = getTypeVariableIndex((TypeVariable) resolved);
-                    continue;
-                }
-                return resolve(resolved, containingType);
-            }
-        }
-
-        // the only way we get here is if resolved is still a TypeVariable, otherwise an
-        // exception is thrown or a value is returned.
-        return ((TypeVariable) resolved).getBounds()[0];
-    }
-
-    /**
-     * @param type           - something like List&lt;T>[] or List&lt;? extends T>[] or T[]
-     * @param containingType - the shallowest type in the hierarchy where type is defined.
-     * @return either the passed type if no changes required or a copy with a best effort resolve of the component type.
-     */
-    private static GenericArrayType resolve(GenericArrayType type, Type containingType)
-    {
-        final Type componentType = type.getGenericComponentType();
-
-        if (!(componentType instanceof Class))
-        {
-            final Type resolved = resolve(componentType, containingType);
-            return create(resolved);
-        }
-
-        return type;
-    }
-
-    /**
-     * @param type           - something like List&lt;T>, List&lt;T extends Number>
-     * @param containingType - the shallowest type in the hierarchy where type is defined.
-     * @return the passed type if nothing to resolve or a copy of the type with the type arguments resolved.
-     */
-    private static ParameterizedType resolve(ParameterizedType type, Type containingType)
-    {
-        // Use a copy because we're going to modify it.
-        final Type[] types = type.getActualTypeArguments().clone();
-
-        boolean modified = resolve(types, containingType);
-        return modified ? create(type.getRawType(), type.getOwnerType(), types) : type;
-    }
-
-    /**
-     * @param type           - something like List&lt;? super T>, List<&lt;? extends T>, List&lt;? extends T & Comparable&lt? super T>>
-     * @param containingType - the shallowest type in the hierarchy where type is defined.
-     * @return the passed type if nothing to resolve or a copy of the type with the upper and lower bounds resolved.
-     */
-    private static WildcardType resolve(WildcardType type, Type containingType)
-    {
-        // Use a copy because we're going to modify them.
-        final Type[] upper = type.getUpperBounds().clone();
-        final Type[] lower = type.getLowerBounds().clone();
-
-        boolean modified = resolve(upper, containingType);
-        modified = modified || resolve(lower, containingType);
-
-        return modified ? create(upper, lower) : type;
-    }
-
-    /**
-     * @param types          - Array of types to resolve. The unresolved type is replaced in the array with the resolved type.
-     * @param containingType - the shallowest type in the hierarchy where type is defined.
-     * @return true if any of the types were resolved.
-     */
-    private static boolean resolve(Type[] types, Type containingType)
-    {
-        boolean modified = false;
-        for (int i = 0; i < types.length; ++i)
-        {
-            Type t = types[i];
-            if (!(t instanceof Class))
-            {
-                modified = true;
-                final Type resolved = resolve(t, containingType);
-                if (!resolved.equals(t))
-                {
-                    types[i] = resolved;
-                    modified = true;
-                }
-            }
-        }
-        return modified;
-    }
-
-    /**
-     * @param rawType       - the un-parameterized type.
-     * @param ownerType     - the outer class or null if the class is not defined within another class.
-     * @param typeArguments - type arguments.
-     * @return a copy of the type with the typeArguments replaced.
-     */
-    static ParameterizedType create(final Type rawType, final Type ownerType, final Type[] typeArguments)
-    {
-        return new ParameterizedType()
-        {
-            @Override
-            public Type[] getActualTypeArguments()
-            {
-                return typeArguments;
-            }
-
-            @Override
-            public Type getRawType()
-            {
-                return rawType;
-            }
-
-            @Override
-            public Type getOwnerType()
-            {
-                return ownerType;
-            }
-
-            @Override
-            public String toString()
-            {
-                return GenericsUtils.toString(this);
-            }
-        };
-    }
-
-    static GenericArrayType create(final Type componentType)
-    {
-        return new GenericArrayType()
-        {
-            @Override
-            public Type getGenericComponentType()
-            {
-                return componentType;
-            }
-
-            @Override
-            public String toString()
-            {
-                return GenericsUtils.toString(this);
-            }
-        };
-    }
-
-    /**
-     * @param upperBounds - e.g. ? extends Number
-     * @param lowerBounds - e.g. ? super Long
-     * @return An new copy of the type with the upper and lower bounds replaced.
-     */
-    static WildcardType create(final Type[] upperBounds, final Type[] lowerBounds)
-    {
-
-        return new WildcardType()
-        {
-            @Override
-            public Type[] getUpperBounds()
-            {
-                return upperBounds;
-            }
-
-            @Override
-            public Type[] getLowerBounds()
-            {
-                return lowerBounds;
-            }
-
-            @Override
-            public String toString()
-            {
-                return GenericsUtils.toString(this);
-            }
-        };
-    }
-
-    static String toString(ParameterizedType pt)
-    {
-        String s = toString(pt.getActualTypeArguments());
-        return String.format("%s<%s>", toString(pt.getRawType()), s);
-    }
-
-    static String toString(GenericArrayType gat)
-    {
-        return String.format("%s[]", toString(gat.getGenericComponentType()));
-    }
-
-    static String toString(WildcardType wt)
-    {
-        final boolean isSuper = wt.getLowerBounds().length > 0;
-        return String.format("? %s %s",
-                isSuper ? "super" : "extends",
-                isSuper ? toString(wt.getLowerBounds()) : toString(wt.getLowerBounds()));
-    }
-
-    static String toString(Type[] types)
-    {
-        StringBuilder sb = new StringBuilder();
-        for ( Type t : types )
-        {
-            sb.append(toString(t)).append(", ");
-        }
-        return sb.substring(0, sb.length() - 2);// drop last ,
-    }
-
-    /**
-     * Find the index of the TypeVariable in the classes parameters. The offset can be used on a subclass to find
-     * the actual type.
-     *
-     * @param typeVariable - the type variable in question.
-     * @return the index of the type variable in its declaring class/method/constructor's type parameters.
-     */
-    private static int getTypeVariableIndex(final TypeVariable typeVariable)
-    {
-        // the label from the class (the T in List<T>, the K or V in Map<K,V>, etc)
-        final String typeVarName = typeVariable.getName();
-        final TypeVariable[] typeParameters = typeVariable.getGenericDeclaration().getTypeParameters();
-        for (int typeArgumentIndex = 0; typeArgumentIndex < typeParameters.length; typeArgumentIndex++)
-        {
-            // The .equals for TypeVariable may not be compatible, a name check should be sufficient.
-            if (typeParameters[typeArgumentIndex].getName().equals(typeVarName))
-                return typeArgumentIndex;
-        }
-
-        // The only way this could happen is if the TypeVariable is hand built incorrectly, or it's corrupted.
-        throw new RuntimeException(
-                String.format("%s does not have a TypeVariable matching %s", typeVariable.getGenericDeclaration(), typeVariable));
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
deleted file mode 100644
index ef217cb..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2006 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.util;
-
-import org.apache.tapestry5.ioc.Locatable;
-import org.apache.tapestry5.ioc.Location;
-
-/**
- * Exception class used as a replacement for {@link java.lang.RuntimeException} when the exception is related to a
- * particular location.
- */
-public class TapestryException extends RuntimeException implements Locatable
-{
-    private static final long serialVersionUID = 6396903640977182682L;
-
-    private transient final Location location;
-
-    /**
-     * @param message  a message (may be null)
-     * @param location implements {@link Location} or {@link Locatable}
-     * @param cause    if not null, the root cause of the exception
-     */
-    public TapestryException(String message, Object location, Throwable cause)
-    {
-        this(message, InternalUtils.locationOf(location), cause);
-    }
-
-    /**
-     * @param message a message (may be null)
-     * @param cause   if not null, the root cause of the exception, also used to set the location
-     */
-    public TapestryException(String message, Throwable cause)
-    {
-        this(message, cause, cause);
-    }
-
-    /**
-     * @param message  a message (may be null)
-     * @param location location to associated with the exception, or null if not known
-     * @param cause    if not null, the root cause of the exception
-     */
-    public TapestryException(String message, Location location, Throwable cause)
-    {
-        super(message, cause);
-
-        this.location = location;
-    }
-
-    @Override
-    public Location getLocation()
-    {
-        return location;
-    }
-
-    @Override
-    public String toString()
-    {
-        if (location == null) return super.toString();
-
-        return String.format("%s [at %s]", super.toString(), location);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java
deleted file mode 100644
index 6159ed3..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2006, 2007, 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.services;
-
-import java.lang.annotation.Annotation;
-import java.util.List;
-
-/**
- * Organizes all {@link org.apache.tapestry5.ioc.services.PropertyAdapter}s for a particular class.
- * <p/>
- * Only provides access to <em>simple</em> properties. Indexed properties are ignored.
- * <p/>
- * When accessing properties by name, the case of the name is ignored.
- */
-public interface ClassPropertyAdapter
-{
-    /**
-     * Returns the names of all properties, sorted into alphabetic order. This includes true properties
-     * (as defined in the JavaBeans specification), but also public fields. Starting in Tapestry 5.3, even public static fields are included.
-     */
-    List<String> getPropertyNames();
-
-    /**
-     * Returns the type of bean this adapter provides properties for.
-     */
-    Class getBeanType();
-
-    /**
-     * Returns the property adapter with the given name, or null if no such adapter exists.
-     *
-     * @param name of the property (case is ignored)
-     */
-    PropertyAdapter getPropertyAdapter(String name);
-
-    /**
-     * Reads the value of a property.
-     *
-     * @param instance     the object to read a value from
-     * @param propertyName the name of the property to read (case is ignored)
-     * @throws UnsupportedOperationException if the property is write only
-     * @throws IllegalArgumentException      if property does not exist
-     */
-    Object get(Object instance, String propertyName);
-
-    /**
-     * Updates the value of a property.
-     *
-     * @param instance     the object to update
-     * @param propertyName the name of the property to update (case is ignored)
-     * @throws UnsupportedOperationException if the property is read only
-     * @throws IllegalArgumentException      if property does not exist
-     */
-    void set(Object instance, String propertyName, Object value);
-
-    /**
-     * Returns the annotation of a given property for the specified type if such an annotation is present, else null.
-     *
-     * @param instance     the object to read a value from
-     * @param propertyName the name of the property to read (case is ignored)
-     * @param annotationClass the type of annotation to return
-     *
-     * @throws IllegalArgumentException      if property does not exist
-     *
-     * @since 5.4
-     */
-    Annotation getAnnotation(Object instance, String propertyName, Class<? extends Annotation> annotationClass);
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java
deleted file mode 100644
index b7a4cc8..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2006 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.services;
-
-/**
- * Responsible for converting from one type to another. This is used primarily around component parameters.
- *
- * @param <S> the source type (input)
- * @param <T> the target type (output)
- */
-public interface Coercion<S, T>
-{
-    /**
-     * Converts an input value.
-     *
-     * @param input the input value
-     */
-    T coerce(S input);
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java
deleted file mode 100644
index 746de1e..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java
+++ /dev/null
@@ -1,145 +0,0 @@
-// 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.services;
-
-import org.apache.tapestry5.plastic.PlasticUtils;
-
-/**
- * An immutable object that represents a mapping from one type to another. This is also the contribution type when
- * building the {@link org.apache.tapestry5.ioc.services.TypeCoercer} service. Wraps a
- * {@link org.apache.tapestry5.ioc.services.Coercion} object that performs the work with additional properties that
- * describe
- * the input and output types of the coercion, needed when searching for an appropriate coercion (or sequence of
- * coercions).
- *
- * @param <S>
- *         source (input) type
- * @param <T>
- *         target (output) type
- */
-public final class CoercionTuple<S, T>
-{
-    private final Class<S> sourceType;
-
-    private final Class<T> targetType;
-
-    private final Coercion<S, T> coercion;
-
-    /**
-     * Wraps an arbitrary coercion with an implementation of toString() that identifies the source and target types.
-     */
-    private class CoercionWrapper<WS, WT> implements Coercion<WS, WT>
-    {
-        private final Coercion<WS, WT> coercion;
-
-        public CoercionWrapper(Coercion<WS, WT> coercion)
-        {
-            this.coercion = coercion;
-        }
-
-        @Override
-        public WT coerce(WS input)
-        {
-            return coercion.coerce(input);
-        }
-
-        @Override
-        public String toString()
-        {
-            return String.format("%s --> %s", convert(sourceType), convert(targetType));
-        }
-    }
-
-    private String convert(Class type)
-    {
-        if (Void.class.equals(type))
-            return "null";
-
-        String name = PlasticUtils.toTypeName(type);
-
-        int dotx = name.lastIndexOf('.');
-
-        // Strip off a package name of "java.lang"
-
-        if (dotx > 0 && name.substring(0, dotx).equals("java.lang"))
-            return name.substring(dotx + 1);
-
-        return name;
-    }
-
-    /**
-     * Standard constructor, which defaults wrap to true.
-     */
-    public CoercionTuple(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion)
-    {
-        this(sourceType, targetType, coercion, true);
-    }
-
-    /**
-     * Convenience constructor to help with generics.
-     *
-     * @since 5.2.0
-     */
-    public static <S, T> CoercionTuple<S, T> create(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion)
-    {
-        return new CoercionTuple<S, T>(sourceType, targetType, coercion);
-    }
-
-    /**
-     * Internal-use constructor.
-     *
-     * @param sourceType
-     *         the source (or input) type of the coercion, may be Void.class to indicate a coercion from null
-     * @param targetType
-     *         the target (or output) type of the coercion
-     * @param coercion
-     *         the object that performs the coercion
-     * @param wrap
-     *         if true, the coercion is wrapped to provide a useful toString()
-     */
-    @SuppressWarnings("unchecked")
-    public CoercionTuple(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion, boolean wrap)
-    {
-        assert sourceType != null;
-        assert targetType != null;
-        assert coercion != null;
-
-        this.sourceType = PlasticUtils.toWrapperType(sourceType);
-        this.targetType = PlasticUtils.toWrapperType(targetType);
-        this.coercion = wrap ? new CoercionWrapper<S, T>(coercion) : coercion;
-    }
-
-    @Override
-    public String toString()
-    {
-        return coercion.toString();
-    }
-
-    public Coercion<S, T> getCoercion()
-    {
-        return coercion;
-    }
-
-    public Class<S> getSourceType()
-    {
-        return sourceType;
-    }
-
-    public Class<T> getTargetType()
-    {
-        return targetType;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java
deleted file mode 100644
index ae542c5..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2006, 2010, 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.services;
-
-import java.lang.annotation.Annotation;
-
-/**
- * A wrapper around the JavaBean Introspector that allows more manageable access to JavaBean properties of objects.
- * <p/>
- * Only provides access to <em>simple</em> properties. Indexed properties are ignored.
- * <p>
- * Starting in Tapestry 5.2, public fields can now be accessed as if they were properly JavaBean properties. Where there
- * is a name conflict, the true property will be favored over the field access.
- */
-public interface PropertyAccess
-{
-    /**
-     * Reads the value of a property.
-     *
-     * @throws UnsupportedOperationException
-     *             if the property is write only
-     * @throws IllegalArgumentException
-     *             if property does not exist
-     */
-    Object get(Object instance, String propertyName);
-
-    /**
-     * Updates the value of a property.
-     *
-     * @throws UnsupportedOperationException
-     *             if the property is read only
-     * @throws IllegalArgumentException
-     *             if property does not exist
-     */
-    void set(Object instance, String propertyName, Object value);
-
-    /**
-     * Returns the annotation of a given property for the specified type if such an annotation is present, else null.
-     * A convenience over invoking {@link #getAdapter(Object)}.{@link ClassPropertyAdapter#getPropertyAdapter(String)}.{@link PropertyAdapter#getAnnotation(Class)}
-     *
-     * @param instance     the object to read a value from
-     * @param propertyName the name of the property to read (case is ignored)
-     * @param annotationClass the type of annotation to return
-     * @throws IllegalArgumentException
-     *             if property does not exist
-     *
-     * @since 5.4
-     */
-    Annotation getAnnotation(Object instance, String propertyName, Class<? extends Annotation> annotationClass);
-
-    /**
-     * Returns the adapter for a particular object instance. A convienience over invoking {@link #getAdapter(Class)}.
-     */
-    ClassPropertyAdapter getAdapter(Object instance);
-
-    /**
-     * Returns the adapter used to access properties within the indicated class.
-     */
-    ClassPropertyAdapter getAdapter(Class forClass);
-
-    /**
-     * Discards all stored property access information, discarding all created class adapters.
-     */
-    void clearCache();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java
deleted file mode 100644
index 947535e..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright 2006, 2008, 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.services;
-
-import org.apache.tapestry5.ioc.AnnotationProvider;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-
-/**
- * Provides access to a single property within a class. Acts as an {@link org.apache.tapestry5.ioc.AnnotationProvider};
- * when searching for annotations, the read method (if present) is checked first, followed by the write method, followed
- * by the underlying field (when the property name matches the field name).
- * <p/>
- * Starting in release 5.2, this property may actually be a public field. In 5.3, it may be a public static field.
- *
- * @see org.apache.tapestry5.ioc.services.ClassPropertyAdapter
- */
-@SuppressWarnings("unchecked")
-public interface PropertyAdapter extends AnnotationProvider
-{
-    /**
-     * Returns the name of the property (or public field).
-     */
-    String getName();
-
-    /**
-     * Returns true if the property is readable (i.e., has a getter method or is a public field).
-     */
-    boolean isRead();
-
-    /**
-     * Returns the method used to read the property, or null if the property is not readable (or is a public field).
-     */
-    public Method getReadMethod();
-
-    /**
-     * Returns true if the property is writeable (i.e., has a setter method or is a non-final field).
-     */
-    boolean isUpdate();
-
-    /**
-     * Returns the method used to update the property, or null if the property is not writeable (or a public field).
-     */
-    public Method getWriteMethod();
-
-    /**
-     * Reads the property value.
-     *
-     * @param instance to read from
-     * @throws UnsupportedOperationException if the property is write only
-     */
-    Object get(Object instance);
-
-    /**
-     * Updates the property value. The provided value must not be null if the property type is primitive, and must
-     * otherwise be of the proper type.
-     *
-     * @param instance to update
-     * @param value    new value for the property
-     * @throws UnsupportedOperationException if the property is read only
-     */
-    void set(Object instance, Object value);
-
-    /**
-     * Returns the type of the property.
-     */
-    Class getType();
-
-    /**
-     * Returns true if the return type of the read method is not the same as the property type. This can occur when the
-     * property has been defined using generics, in which case, the method's type may be Object when the property type
-     * is something more specific. This method is primarily used when generating runtime code related to the property.
-     */
-    boolean isCastRequired();
-
-    /**
-     * Returns the {@link org.apache.tapestry5.ioc.services.ClassPropertyAdapter} that provides access to other
-     * properties defined by the same class.
-     */
-    ClassPropertyAdapter getClassAdapter();
-
-    /**
-     * Returns the type of bean to which this property belongs. This is the same as
-     * {@link org.apache.tapestry5.ioc.services.ClassPropertyAdapter#getBeanType()}.
-     */
-    Class getBeanType();
-
-    /**
-     * Returns true if the property is actually a public field (possibly, a public static field).
-     *
-     * @since 5.2
-     */
-    boolean isField();
-
-    /**
-     * Returns the field if the property is a public field or null if the property is accessed via the read method.
-     *
-     * @since 5.2
-     */
-    Field getField();
-
-    /**
-     * The class in which the property (or public field) is defined.
-     *
-     * @since 5.2
-     */
-    Class getDeclaringClass();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java
deleted file mode 100644
index ec8eaad..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2006, 2007, 2008, 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.services;
-
-import org.apache.tapestry5.ioc.annotations.UsesConfiguration;
-
-/**
- * Makes use of {@link org.apache.tapestry5.ioc.services.Coercion}s to convert between an input value (of some specific
- * type) and a desired output type. Smart about coercing, even if it requires multiple coercion steps (i.e., via an
- * intermediate type, such as String).
- */
-@UsesConfiguration(CoercionTuple.class)
-public interface TypeCoercer
-{
-    /**
-     * Performs a coercion from an input type to a desired output type. When the target type is a primitive, the actual
-     * conversion will be to the equivalent wrapper type. In some cases, the TypeCoercer will need to search for an
-     * appropriate coercion, and may even combine existing coercions to form new ones; in those cases, the results of
-     * the search are cached.
-     * <p/>
-     * The TypeCoercer also caches the results of a coercion search.
-     * 
-     * @param <S>
-     *            source type (input)
-     * @param <T>
-     *            target type (output)
-     * @param input
-     * @param targetType
-     *            defines the target type
-     * @return the coerced value
-     * @throws RuntimeException
-     *             if the input can not be coerced
-     */
-    <S, T> T coerce(S input, Class<T> targetType);
-
-    /**
-     * Given a source and target type, computes the coercion that will be used.
-     * <p>
-     * Note: holding the returned coercion past the time when {@linkplain #clearCache() the cache is cleared} can cause
-     * a memory leak, especially in the context of live reloading (wherein holding a reference to a single class make
-     * keep an entire ClassLoader from being reclaimed).
-     * 
-     * @since 5.2.0
-     * @param <S>
-     *            source type (input)
-     * @param <T>
-     *            target type (output)
-     * @param sourceType
-     *            type to coerce from
-     * @param targetType
-     *            defines the target type
-     * @return the coercion that will ultimately be used
-     */
-    <S, T> Coercion<S, T> getCoercion(Class<S> sourceType, Class<T> targetType);
-
-    /**
-     * Used primarily inside test suites, this method performs the same steps as {@link #coerce(Object, Class)}, but
-     * returns a string describing the series of coercions, such as "Object --&gt; String --&gt; Long --&gt; Integer".
-     * 
-     * @param <S>
-     *            source type (input)
-     * @param <T>
-     *            target type (output)
-     * @param sourceType
-     *            the source coercion type (use void.class for coercions from null)
-     * @param targetType
-     *            defines the target type
-     * @return a string identifying the series of coercions, or the empty string if no coercion is necessary
-     */
-    <S, T> String explain(Class<S> sourceType, Class<T> targetType);
-
-    /**
-     * Clears cached information stored by the TypeCoercer.
-     */
-    void clearCache();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
deleted file mode 100644
index c4c5c6d..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 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.util;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-
-/**
- * Used (as part of a {@link UnknownValueException} to identify what available values
- * are present.
- * 
- * @since 5.2.0
- */
-public class AvailableValues
-{
-    private final String valueType;
-
-    private final List<String> values;
-
-    /**
-     * @param valueType
-     *            a word or phrase that describes what the values are such as "component types" or "service ids"
-     *@param values
-     *            a set of objects defining the values; the values will be converted to strings and sorted into
-     *            ascending order
-     */
-    public AvailableValues(String valueType, Collection<?> values)
-    {
-        this.valueType = valueType;
-        this.values = sortValues(values);
-    }
-
-    public AvailableValues(String valueType, Map<?, ?> map)
-    {
-        this(valueType, map.keySet());
-    }
-
-    private static List<String> sortValues(Collection<?> values)
-    {
-        List<String> result = CollectionFactory.newList();
-
-        for (Object v : values)
-        {
-            result.add(String.valueOf(v));
-        }
-
-        Collections.sort(result);
-
-        return Collections.unmodifiableList(result);
-    }
-
-    /** The type of value, i.e., "component types" or "service ids". */
-    public String getValueType()
-    {
-        return valueType;
-    }
-
-    /** The values, as strings, in sorted order. */
-    public List<String> getValues()
-    {
-        return values;
-    }
-
-    @Override
-    public String toString()
-    {
-        return String.format("AvailableValues[%s: %s]", valueType, InternalUtils.join(values));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java
deleted file mode 100644
index f5aff7e..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java
+++ /dev/null
@@ -1,499 +0,0 @@
-// Copyright 2007 The Apache Software Foundation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.apache.tapestry5.ioc.util;
-
-import java.io.Serializable;
-import java.util.*;
-
-/**
- * An mapped collection where the keys are always strings and access to values is case-insensitive. The case of keys in
- * the map is <em>maintained</em>, but on any access to a key (directly or indirectly), all key comparisons are
- * performed in a case-insensitive manner. The map implementation is intended to support a reasonably finite number
- * (dozens or hundreds, not thousands or millions of key/value pairs. Unlike HashMap, it is based on a sorted list of
- * entries rather than hash bucket. It is also geared towards a largely static map, one that is created and then used
- * without modification.
- *
- * @param <V> the type of value stored
- */
-public class CaseInsensitiveMap<V> extends AbstractMap<String, V> implements Serializable
-{
-    private static final long serialVersionUID = 3362718337611953298L;
-
-    private static final int NULL_HASH = Integer.MIN_VALUE;
-
-    private static final int DEFAULT_SIZE = 20;
-
-    private static class CIMEntry<V> implements Map.Entry<String, V>, Serializable
-    {
-        private static final long serialVersionUID = 6713986085221148350L;
-
-        private String key;
-
-        private final int hashCode;
-
-        V value;
-
-        public CIMEntry(final String key, final int hashCode, V value)
-        {
-            this.key = key;
-            this.hashCode = hashCode;
-            this.value = value;
-        }
-
-        @Override
-        public String getKey()
-        {
-            return key;
-        }
-
-        @Override
-        public V getValue()
-        {
-            return value;
-        }
-
-        @Override
-        public V setValue(V value)
-        {
-            V result = this.value;
-
-            this.value = value;
-
-            return result;
-        }
-
-        /**
-         * Returns true if both keys are null, or if the provided key is the same as, or case-insensitively equal to,
-         * the entrie's key.
-         *
-         * @param key to compare against
-         * @return true if equal
-         */
-        @SuppressWarnings({ "StringEquality" })
-        boolean matches(String key)
-        {
-            return key == this.key || (key != null && key.equalsIgnoreCase(this.key));
-        }
-
-        boolean valueMatches(Object value)
-        {
-            return value == this.value || (value != null && value.equals(this.value));
-        }
-    }
-
-    private class EntrySetIterator implements Iterator
-    {
-        int expectedModCount = modCount;
-
-        int index;
-
-        int current = -1;
-
-        @Override
-        public boolean hasNext()
-        {
-            return index < size;
-        }
-
-        @Override
-        public Object next()
-        {
-            check();
-
-            if (index >= size) throw new NoSuchElementException();
-
-            current = index++;
-
-            return entries[current];
-        }
-
-        @Override
-        public void remove()
-        {
-            check();
-
-            if (current < 0) throw new NoSuchElementException();
-
-            new Position(current, true).remove();
-
-            expectedModCount = modCount;
-        }
-
-        private void check()
-        {
-            if (expectedModCount != modCount) throw new ConcurrentModificationException();
-        }
-    }
-
-    @SuppressWarnings("unchecked")
-    private class EntrySet extends AbstractSet
-    {
-        @Override
-        public Iterator iterator()
-        {
-            return new EntrySetIterator();
-        }
-
-        @Override
-        public int size()
-        {
-            return size;
-        }
-
-        @Override
-        public void clear()
-        {
-            CaseInsensitiveMap.this.clear();
-        }
-
-        @Override
-        public boolean contains(Object o)
-        {
-            if (!(o instanceof Map.Entry)) return false;
-
-            Map.Entry e = (Map.Entry) o;
-
-            Position position = select(e.getKey());
-
-            return position.isFound() && position.entry().valueMatches(e.getValue());
-        }
-
-        @Override
-        public boolean remove(Object o)
-        {
-            if (!(o instanceof Map.Entry)) return false;
-
-            Map.Entry e = (Map.Entry) o;
-
-            Position position = select(e.getKey());
-
-            if (position.isFound() && position.entry().valueMatches(e.getValue()))
-            {
-                position.remove();
-                return true;
-            }
-
-            return false;
-        }
-
-    }
-
-    private class Position
-    {
-        private final int cursor;
-
-        private final boolean found;
-
-        Position(int cursor, boolean found)
-        {
-            this.cursor = cursor;
-            this.found = found;
-        }
-
-        boolean isFound()
-        {
-            return found;
-        }
-
-        CIMEntry<V> entry()
-        {
-            return entries[cursor];
-        }
-
-        V get()
-        {
-            return found ? entries[cursor].value : null;
-        }
-
-        V remove()
-        {
-            if (!found) return null;
-
-            V result = entries[cursor].value;
-
-            // Remove the entry by shifting everything else down.
-
-            System.arraycopy(entries, cursor + 1, entries, cursor, size - cursor - 1);
-
-            // We shifted down, leaving one (now duplicate) entry behind.
-
-            entries[--size] = null;
-
-            // A structural change for sure
-
-            modCount++;
-
-            return result;
-        }
-
-        @SuppressWarnings("unchecked")
-        V put(String key, int hashCode, V newValue)
-        {
-            if (found)
-            {
-                CIMEntry<V> e = entries[cursor];
-
-                V result = e.value;
-
-                // Not a structural change, so no change to modCount
-
-                // Update the key (to maintain case). By definition, the hash code
-                // will not change.
-
-                e.key = key;
-                e.value = newValue;
-
-                return result;
-            }
-
-            // Not found, we're going to add it.
-
-            int newSize = size + 1;
-
-            if (newSize == entries.length)
-            {
-                // Time to expand!
-
-                int newCapacity = (size * 3) / 2 + 1;
-
-                CIMEntry<V>[] newEntries = new CIMEntry[newCapacity];
-
-                System.arraycopy(entries, 0, newEntries, 0, cursor);
-
-                System.arraycopy(entries, cursor, newEntries, cursor + 1, size - cursor);
-
-                entries = newEntries;
-            }
-            else
-            {
-                // Open up a space for the new entry
-
-                System.arraycopy(entries, cursor, entries, cursor + 1, size - cursor);
-            }
-
-            CIMEntry<V> newEntry = new CIMEntry<V>(key, hashCode, newValue);
-            entries[cursor] = newEntry;
-
-            size++;
-
-            // This is definately a structural change
-
-            modCount++;
-
-            return null;
-        }
-
-    }
-
-    // The list of entries. This is kept sorted by hash code. In some cases, there may be different
-    // keys with the same hash code in adjacent indexes.
-    private CIMEntry<V>[] entries;
-
-    private int size = 0;
-
-    // Used by iterators to check for concurrent modifications
-
-    private transient int modCount = 0;
-
-    private transient Set<Map.Entry<String, V>> entrySet;
-
-    public CaseInsensitiveMap()
-    {
-        this(DEFAULT_SIZE);
-    }
-
-    @SuppressWarnings("unchecked")
-    public CaseInsensitiveMap(int size)
-    {
-        entries = new CIMEntry[Math.max(size, 3)];
-    }
-
-    public CaseInsensitiveMap(Map<String, ? extends V> map)
-    {
-        this(map.size());
-
-        for (Map.Entry<String, ? extends V> entry : map.entrySet())
-        {
-            put(entry.getKey(), entry.getValue());
-        }
-    }
-
-    @Override
-    public void clear()
-    {
-        for (int i = 0; i < size; i++)
-            entries[i] = null;
-
-        size = 0;
-        modCount++;
-    }
-
-    @Override
-    public boolean isEmpty()
-    {
-        return size == 0;
-    }
-
-    @Override
-    public int size()
-    {
-        return size;
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public V put(String key, V value)
-    {
-        int hashCode = caseInsenitiveHashCode(key);
-
-        return select(key, hashCode).put(key, hashCode, value);
-    }
-
-    @Override
-    public boolean containsKey(Object key)
-    {
-        return select(key).isFound();
-    }
-
-    @Override
-    public V get(Object key)
-    {
-        return select(key).get();
-    }
-
-    @Override
-    public V remove(Object key)
-    {
-        return select(key).remove();
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public Set<Map.Entry<String, V>> entrySet()
-    {
-        if (entrySet == null) entrySet = new EntrySet();
-
-        return entrySet;
-    }
-
-    private Position select(Object key)
-    {
-        if (key == null || key instanceof String)
-        {
-            String keyString = (String) key;
-            return select(keyString, caseInsenitiveHashCode(keyString));
-        }
-
-        return new Position(0, false);
-    }
-
-    /**
-     * Searches the elements for the index of the indicated key and (case insensitive) hash code. Sets the _cursor and
-     * _found attributes.
-     */
-    private Position select(String key, int hashCode)
-    {
-        if (size == 0) return new Position(0, false);
-
-        int low = 0;
-        int high = size - 1;
-
-        int cursor;
-
-        while (low <= high)
-        {
-            cursor = (low + high) >> 1;
-
-            CIMEntry e = entries[cursor];
-
-            if (e.hashCode < hashCode)
-            {
-                low = cursor + 1;
-                continue;
-            }
-
-            if (e.hashCode > hashCode)
-            {
-                high = cursor - 1;
-                continue;
-            }
-
-            return tunePosition(key, hashCode, cursor);
-        }
-
-        return new Position(low, false);
-    }
-
-    /**
-     * select() has located a matching hashCode, but there's an outlying possibility that multiple keys share the same
-     * hashCode. Backup the cursor until we get to locate the initial hashCode match, then march forward until the key
-     * is located, or the hashCode stops matching.
-     *
-     * @param key
-     * @param hashCode
-     */
-    private Position tunePosition(String key, int hashCode, int cursor)
-    {
-        boolean found = false;
-
-        while (cursor > 0)
-        {
-            if (entries[cursor - 1].hashCode != hashCode) break;
-
-            cursor--;
-        }
-
-        while (true)
-        {
-            if (entries[cursor].matches(key))
-            {
-                found = true;
-                break;
-            }
-
-            // Advance to the next entry.
-
-            cursor++;
-
-            // If out of entries,
-            if (cursor >= size || entries[cursor].hashCode != hashCode) break;
-        }
-
-        return new Position(cursor, found);
-    }
-
-    static int caseInsenitiveHashCode(String input)
-    {
-        if (input == null) return NULL_HASH;
-
-        int length = input.length();
-        int hash = 0;
-
-        // This should end up more or less equal to input.toLowerCase().hashCode(), unless String
-        // changes its implementation. Let's hope this is reasonably fast.
-
-        for (int i = 0; i < length; i++)
-        {
-            int ch = input.charAt(i);
-
-            int caselessCh = Character.toLowerCase(ch);
-
-            hash = 31 * hash + caselessCh;
-        }
-
-        return hash;
-    }
-
-}


[04/15] tapestry-5 git commit: First pass creating the BeanModel and Commons packages. Lots of stuff moved around, but no actual code changes so far

Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/services/InvalidationListener.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/services/InvalidationListener.java b/commons/src/main/java/org/apache/tapestry5/services/InvalidationListener.java
new file mode 100644
index 0000000..b9b4aa3
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/services/InvalidationListener.java
@@ -0,0 +1,33 @@
+// Copyright 2006, 2007, 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.services;
+
+/**
+ * Interface for objects that may cache information that can be invalidated. Invalidation occurs when external files,
+ * from which in-memory data is cached, is determined to have changed. Granularity is very limited; when any external
+ * file is found to have changed, the event is fired (with the expectation that the cleared cache will be repopulated as
+ * necessary).
+ *
+ * @see org.apache.tapestry5.services.InvalidationEventHub
+ * @since 5.1.0.0
+ * @deprecated In 5.4; use {@link InvalidationEventHub#addInvalidationCallback(Runnable)} instead
+ */
+public interface InvalidationListener
+{
+    /**
+     * Invoked to indicate that some object is invalid. The receiver should clear its cache.
+     */
+    void objectWasInvalidated();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/settings.gradle
----------------------------------------------------------------------
diff --git a/settings.gradle b/settings.gradle
index 6397777..593c3a4 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -4,5 +4,5 @@ include "tapestry-beanvalidator", "tapestry-jpa", "tapestry-kaptcha"
 include "tapestry-javadoc", "quickstart", "tapestry-clojure", "tapestry-mongodb"
 include "tapestry-test-data", 'tapestry-internal-test', "tapestry-ioc-junit"
 include "tapestry-webresources", "tapestry-runner", "tapestry-test-constants"
-include "tapestry-ioc-jcache"
+include "tapestry-ioc-jcache", "beanmodel", "commons"
 // include "tapestry-cdi"

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/build.gradle
----------------------------------------------------------------------
diff --git a/tapestry-core/build.gradle b/tapestry-core/build.gradle
index c16cd48..584200a 100644
--- a/tapestry-core/build.gradle
+++ b/tapestry-core/build.gradle
@@ -18,6 +18,7 @@ configurations {
 dependencies {
     compile project(':tapestry-ioc')
     compile project(':tapestry-json')
+    compile project(':beanmodel')
 
     provided project(":tapestry-test")
     provided project(":tapestry-test-constants")
@@ -26,11 +27,6 @@ dependencies {
 
     compile "commons-codec:commons-codec:1.5"
 
-    // Transitive will bring in the unwanted string template library as well
-    compile "org.antlr:antlr-runtime:3.5.2", {
-        exclude group: "org.antlr", module: "stringtemplate"
-    }
-
     // 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/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit.java b/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit.java
deleted file mode 100644
index 3dbb0c0..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit.java
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2007 The Apache Software Foundation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.apache.tapestry5;
-
-import org.apache.tapestry5.ioc.AnnotationProvider;
-
-/**
- * Used to read or update the value associated with a property. A PropertyConduit provides access to the annotations on
- * the underlying getter and/or setter methods.
- */
-public interface PropertyConduit extends AnnotationProvider
-{
-    /**
-     * Reads the property from the instance.
-     *
-     * @param instance object containing the property
-     * @return the current value of the property
-     */
-    Object get(Object instance);
-
-    /**
-     * Changes the current value of the property.
-     *
-     * @param instance object containing the property
-     * @param value    to change the property to
-     */
-    void set(Object instance, Object value);
-
-    /**
-     * Returns the type of the property read or updated by the conduit.
-     */
-    Class getPropertyType();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit2.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit2.java b/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit2.java
deleted file mode 100644
index 839d70f..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit2.java
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2007 The Apache Software Foundation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.apache.tapestry5;
-
-import java.lang.reflect.Method;
-import java.lang.reflect.Type;
-
-import org.apache.tapestry5.services.PropertyConduitSource;
-
-
-/**
- * Extension to {@link PropertyConduit} that adds a method to access the generic property type.
- * {@link PropertyConduitSource} instances should ideally return PropertyConduit2 objects, not PropertyConduit.
- * This is only primarily of interest to {@link Binding2}.
- * 
- * @since 5.4
- */
-public interface PropertyConduit2 extends PropertyConduit
-{
-    /**
-     * Returns the generic type of the property
-     * 
-     * @see Method#getGenericReturnType()
-     * @see java.lang.reflect.Field#getGenericType()
-     * 
-     */
-	Type getPropertyGenericType();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/BeanModel.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/BeanModel.java b/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/BeanModel.java
deleted file mode 100644
index 0a60fd7..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/BeanModel.java
+++ /dev/null
@@ -1,169 +0,0 @@
-// Copyright 2007, 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.beaneditor;
-
-import org.apache.tapestry5.PropertyConduit;
-
-import java.util.List;
-
-/**
- * Provides the information necessary to build a user interface to view, create or edit an instance of a particular
- * type.
- * <p/>
- * BeanModels are not thread-safe, they are also not serializable.
- * <p/>
- * Here, and in {@link org.apache.tapestry5.beaneditor.PropertyModel}, the term "propertyName" is used for simplicitly.
- * However, a full {@linkplain org.apache.tapestry5.services.PropertyConduitSource#create(Class, String) property
- * expression} may be utilized when {@linkplain #add(String) adding new properties to an existing BeanModel}.
- *
- * @see org.apache.tapestry5.services.BeanModelSource
- */
-public interface BeanModel<T>
-{
-    /**
-     * Returns the type of bean for which this model was initially created.
-     */
-    Class<T> getBeanType();
-
-
-    /**
-     * Creates a new bean instance.  This is based on {@link org.apache.tapestry5.ioc.ObjectLocator#autobuild(Class)},
-     * so a public constructor will be used, and dependencies injected.
-     *
-     * @return new instance of the bean
-     */
-    T newInstance();
-
-    /**
-     * Returns a list of the editable properties of the bean, in <em>presentation</em> order.
-     */
-    List<String> getPropertyNames();
-
-    /**
-     * Returns the named model.
-     *
-     * @param propertyName name of property to retrieve model for (case is ignored)
-     * @return the model for the property
-     * @throws RuntimeException if the bean editor model does not have a property model for the provided name
-     */
-    PropertyModel get(String propertyName);
-
-    /**
-     * Returns the identified model.  Property ids are a stripped version of the property name. Case is ignored.
-     *
-     * @param propertyId matched caselessly against {@link org.apache.tapestry5.beaneditor.PropertyModel#getId()}
-     * @throws RuntimeException if the bean editor model does not have a property model with the indicated id
-     */
-    PropertyModel getById(String propertyId);
-
-    /**
-     * Adds a new property to the model, returning its mutable model for further refinement. The property is added to
-     * the <em>end</em> of the list of properties. The property must be real (but may have been excluded if there was no
-     * {@linkplain org.apache.tapestry5.beaneditor.DataType datatype} associated with the property). To add a synthetic
-     * property, use {@link #add(String, org.apache.tapestry5.PropertyConduit)}
-     *
-     * @param propertyName name of property to add
-     * @return the new property model (for further configuration)
-     * @throws RuntimeException if the property already exists
-     */
-    PropertyModel add(String propertyName);
-
-
-    /**
-     * Adds a new synthetic property to the model, returning its mutable model for further refinement. The property is added to
-     * the <em>end</em> of the list of properties.
-     *
-     * @param propertyName name of property to add
-     * @param expression   expression for the property
-     * @return the new property model (for further configuration)
-     * @throws RuntimeException if the property already exists
-     * @since 5.3
-     */
-    PropertyModel addExpression(String propertyName, String expression);
-
-    /**
-     * Adds an empty property (one with no property conduit).
-     *
-     * @param propertyName name of property to add
-     * @return the new property model (for further configuration)
-     * @throws RuntimeException if the property already exists
-     * @since 5.3
-     */
-    PropertyModel addEmpty(String propertyName);
-
-    /**
-     * Adds a new property to the model (as with {@link #add(String)}), ordered before or after an existing property.
-     *
-     * @param position             controls whether the new property is ordered before or after the existing property
-     * @param existingPropertyName the name of an existing property (this must exist)
-     * @param propertyName         the new property to add
-     * @return the new property model (for further configuration)
-     * @throws RuntimeException if the existing property does not exist, or if the new property already does exist
-     */
-    PropertyModel add(RelativePosition position, String existingPropertyName, String propertyName);
-
-    /**
-     * Adds a new property to the model, ordered before or after an existing property.
-     *
-     * @param position             controls whether the new property is ordered before or after the existing property
-     * @param existingPropertyName the name of an existing property (this must exist)
-     * @param propertyName         the new property to add
-     * @param conduit              conduit used to read or update the property; this may be null for a synthetic or
-     *                             placeholder property
-     * @return the new property model (for further configuration)
-     * @throws RuntimeException if the existing property does not exist, or if the new property already does exist
-     */
-    PropertyModel add(RelativePosition position, String existingPropertyName, String propertyName,
-                      PropertyConduit conduit);
-
-    /**
-     * Adds a new, synthetic property to the model, returning its mutable model for further refinement.
-     *
-     * @param propertyName name of property to add
-     * @param conduit      the conduit used to read or update the property; this may be null for a synthetic or
-     *                     placeholder property.  Instead of passing null, please invoke {@link #addEmpty(String)}.
-     * @return the model for the property
-     * @throws RuntimeException if the property already exists
-     * @see #addExpression(String, String)
-     */
-    PropertyModel add(String propertyName, PropertyConduit conduit);
-
-    /**
-     * Removes the named properties from the model, if present. It is not considered an error to remove a property that
-     * does not exist.
-     *
-     * @param propertyNames the names of properties to be removed (case insensitive)
-     * @return the model for further modifications
-     */
-    BeanModel<T> exclude(String... propertyNames);
-
-    /**
-     * Re-orders the properties of the model into the specified order. Existing properties that are not indicated are
-     * retained, but ordered to the end of the list.
-     *
-     * @param propertyNames property names in order they should be displayed (case insensitive)
-     * @return the model for further modifications
-     */
-    BeanModel<T> reorder(String... propertyNames);
-
-    /**
-     * Re-orders the properties of the model into the specified order. Existing properties that are not indicated are
-     * <<removed>>.
-     *
-     * @param propertyNames the names of properties to be retained
-     * @return the model for further modifications
-     */
-    BeanModel<T> include(String... propertyNames);
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/PropertyModel.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/PropertyModel.java b/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/PropertyModel.java
deleted file mode 100644
index 6095fb9..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/PropertyModel.java
+++ /dev/null
@@ -1,97 +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.beaneditor;
-
-import org.apache.tapestry5.PropertyConduit;
-import org.apache.tapestry5.ioc.AnnotationProvider;
-
-/**
- * Part of a {@link org.apache.tapestry5.beaneditor.BeanModel} that defines the attributes of a single property of a
- * bean.
- * <p/>
- * <p/>
- * A PropertyModel is also an {@link AnnotationProvider}, as long as the {@link org.apache.tapestry5.PropertyConduit} is
- * non-null.  When there is no property conduit, then {@link org.apache.tapestry5.ioc.AnnotationProvider#getAnnotation(Class)}
- * will return null.
- */
-public interface PropertyModel extends AnnotationProvider
-{
-    /**
-     * Returns the name of the property (which may, in fact, be a property expression).
-     */
-    String getPropertyName();
-
-    /**
-     * Returns the id used to access other resources (this is based on the property name, but with any excess
-     * punctuation stripped out).
-     */
-    String getId();
-
-    /**
-     * Returns a user-presentable label for the property.
-     */
-    String getLabel();
-
-    /**
-     * Returns the type of the property.
-     */
-    Class getPropertyType();
-
-    /**
-     * Returns a logical name for the type of UI needed to view or edit the property. This is initially determined from
-     * the property type.
-     */
-    String getDataType();
-
-    /**
-     * Changes the data type for the property.
-     *
-     * @param dataType
-     * @return the property model, for further changes
-     */
-    PropertyModel dataType(String dataType);
-
-    /**
-     * Returns an object used to read or update the property. For virtual properties (properties that do not actually
-     * exist on the bean), the conduit may be null.
-     */
-    PropertyConduit getConduit();
-
-    /**
-     * Changes the label for the property to the provided value.
-     *
-     * @param label new label for property
-     * @return the property model, for further changes
-     */
-    PropertyModel label(String label);
-
-    /**
-     * Returns the containing model, often used for "fluent" construction of the model.
-     */
-    BeanModel model();
-
-    /**
-     * Returns true if the property can be used for sorting. By default, this is true only if the property type
-     * implements Comparable.
-     */
-    boolean isSortable();
-
-    /**
-     * Updates sortable and returns the model for further changes.
-     *
-     * @return the property model, for further changes
-     */
-    PropertyModel sortable(boolean sortable);
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalPropertyConduit.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalPropertyConduit.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalPropertyConduit.java
deleted file mode 100644
index 315b372..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalPropertyConduit.java
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 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.internal;
-
-import org.apache.tapestry5.PropertyConduit2;
-
-
-/**
- * Extension to {@link org.apache.tapestry5.PropertyConduit2} that adds a method to determine the name of the property.
- * 
- * @since 5.2.0
- *
- */
-public interface InternalPropertyConduit extends PropertyConduit2
-{
-    /**
-     * Returns the name of the property read or updated by the conduit or null. 
-     * If the expression points to a property on a bean (e.g. user.name) this method returns the last property in the chain. 
-     * Otherwise this method returns {@code null}.
-     * 
-     * @return property name or {@code null}
-     * 
-     */
-    String getPropertyName();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
deleted file mode 100644
index 26eb309..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
+++ /dev/null
@@ -1,289 +0,0 @@
-// Copyright 2007, 2008, 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.internal.beaneditor;
-
-import org.apache.tapestry5.PropertyConduit;
-import org.apache.tapestry5.beaneditor.BeanModel;
-import org.apache.tapestry5.beaneditor.PropertyModel;
-import org.apache.tapestry5.beaneditor.RelativePosition;
-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.InternalUtils;
-import org.apache.tapestry5.ioc.services.TypeCoercer;
-import org.apache.tapestry5.ioc.util.AvailableValues;
-import org.apache.tapestry5.ioc.util.UnknownValueException;
-import org.apache.tapestry5.plastic.PlasticUtils;
-import org.apache.tapestry5.services.PropertyConduitSource;
-
-import java.util.List;
-import java.util.Map;
-
-public class BeanModelImpl<T> implements BeanModel<T>
-{
-    private final Class<T> beanType;
-
-    private final PropertyConduitSource propertyConduitSource;
-
-    private final TypeCoercer typeCoercer;
-
-    private final Messages messages;
-
-    private final ObjectLocator locator;
-
-    private final Map<String, PropertyModel> properties = CollectionFactory.newCaseInsensitiveMap();
-
-    // The list of property names, in desired order (generally not alphabetical order).
-
-    private final List<String> propertyNames = CollectionFactory.newList();
-
-    private static PropertyConduit NULL_PROPERTY_CONDUIT = null;
-
-    public BeanModelImpl(Class<T> beanType, PropertyConduitSource propertyConduitSource, TypeCoercer typeCoercer,
-                         Messages messages, ObjectLocator locator)
-
-    {
-        this.beanType = beanType;
-        this.propertyConduitSource = propertyConduitSource;
-        this.typeCoercer = typeCoercer;
-        this.messages = messages;
-        this.locator = locator;
-    }
-
-    public Class<T> getBeanType()
-    {
-        return beanType;
-    }
-
-    public T newInstance()
-    {
-        return locator.autobuild("Instantiating new instance of " + beanType.getName(), beanType);
-    }
-
-    public PropertyModel add(String propertyName)
-    {
-        return addExpression(propertyName, propertyName);
-    }
-
-    public PropertyModel addEmpty(String propertyName)
-    {
-        return add(propertyName, NULL_PROPERTY_CONDUIT);
-    }
-
-    public PropertyModel addExpression(String propertyName, String expression)
-    {
-        PropertyConduit conduit = createConduit(expression);
-
-        return add(propertyName, conduit);
-
-    }
-
-    private void validateNewPropertyName(String propertyName)
-    {
-        assert InternalUtils.isNonBlank(propertyName);
-        if (properties.containsKey(propertyName))
-            throw new RuntimeException(String.format(
-                    "Bean editor model for %s already contains a property model for property '%s'.",
-                    beanType.getName(), propertyName));
-    }
-
-    public PropertyModel add(RelativePosition position, String existingPropertyName, String propertyName,
-                             PropertyConduit conduit)
-    {
-        assert position != null;
-        validateNewPropertyName(propertyName);
-
-        // Locate the existing one.
-
-        PropertyModel existing = get(existingPropertyName);
-
-        // Use the case normalized property name.
-
-        int pos = propertyNames.indexOf(existing.getPropertyName());
-
-        PropertyModel newModel = new PropertyModelImpl(this, propertyName, conduit, messages);
-
-        properties.put(propertyName, newModel);
-
-        int offset = position == RelativePosition.AFTER ? 1 : 0;
-
-        propertyNames.add(pos + offset, propertyName);
-
-        return newModel;
-    }
-
-    public PropertyModel add(RelativePosition position, String existingPropertyName, String propertyName)
-    {
-        PropertyConduit conduit = createConduit(propertyName);
-
-        return add(position, existingPropertyName, propertyName, conduit);
-    }
-
-    public PropertyModel add(String propertyName, PropertyConduit conduit)
-    {
-        validateNewPropertyName(propertyName);
-
-        PropertyModel propertyModel = new PropertyModelImpl(this, propertyName, conduit, messages);
-
-        properties.put(propertyName, propertyModel);
-
-        // Remember the order in which the properties were added.
-
-        propertyNames.add(propertyName);
-
-        return propertyModel;
-    }
-
-    private CoercingPropertyConduitWrapper createConduit(String propertyName)
-    {
-        return new CoercingPropertyConduitWrapper(propertyConduitSource.create(beanType, propertyName), typeCoercer);
-    }
-
-    public PropertyModel get(String propertyName)
-    {
-        PropertyModel propertyModel = properties.get(propertyName);
-
-        if (propertyModel == null)
-            throw new UnknownValueException(String.format(
-                    "Bean editor model for %s does not contain a property named '%s'.", beanType.getName(),
-                    propertyName), new AvailableValues("Defined properties", propertyNames));
-
-        return propertyModel;
-    }
-
-    public PropertyModel getById(String propertyId)
-    {
-        for (PropertyModel model : properties.values())
-        {
-            if (model.getId().equalsIgnoreCase(propertyId))
-                return model;
-        }
-
-        // Not found, so we throw an exception. A bit of work to set
-        // up the exception however.
-
-        List<String> ids = CollectionFactory.newList();
-
-        for (PropertyModel model : properties.values())
-        {
-            ids.add(model.getId());
-        }
-
-        throw new UnknownValueException(String.format(
-                "Bean editor model for %s does not contain a property with id '%s'.", beanType.getName(), propertyId),
-                new AvailableValues("Defined property ids", ids));
-    }
-
-    public List<String> getPropertyNames()
-    {
-        return CollectionFactory.newList(propertyNames);
-    }
-
-    public BeanModel<T> exclude(String... propertyNames)
-    {
-        for (String propertyName : propertyNames)
-        {
-            PropertyModel model = properties.get(propertyName);
-
-            if (model == null)
-                continue;
-
-            // De-referencing from the model is needed because the name provided may not be a
-            // case-exact match, so we get the normalized or canonical name from the model because
-            // that's the one in propertyNames.
-
-            this.propertyNames.remove(model.getPropertyName());
-
-            properties.remove(propertyName);
-        }
-
-        return this;
-    }
-
-    public BeanModel<T> reorder(String... propertyNames)
-    {
-        List<String> remainingPropertyNames = CollectionFactory.newList(this.propertyNames);
-        List<String> reorderedPropertyNames = CollectionFactory.newList();
-
-        for (String name : propertyNames)
-        {
-            PropertyModel model = get(name);
-
-            // Get the canonical form (which may differ from name in terms of case)
-            String canonical = model.getPropertyName();
-
-            reorderedPropertyNames.add(canonical);
-
-            remainingPropertyNames.remove(canonical);
-        }
-
-        this.propertyNames.clear();
-        this.propertyNames.addAll(reorderedPropertyNames);
-
-        // Any unspecified names are ordered to the end. Don't want them? Remove them instead.
-        this.propertyNames.addAll(remainingPropertyNames);
-
-        return this;
-    }
-
-    public BeanModel<T> include(String... propertyNames)
-    {
-        List<String> reorderedPropertyNames = CollectionFactory.newList();
-        Map<String, PropertyModel> reduced = CollectionFactory.newCaseInsensitiveMap();
-
-        for (String name : propertyNames)
-        {
-
-            PropertyModel model = get(name);
-
-            String canonical = model.getPropertyName();
-
-            reorderedPropertyNames.add(canonical);
-            reduced.put(canonical, model);
-
-        }
-
-        this.propertyNames.clear();
-        this.propertyNames.addAll(reorderedPropertyNames);
-
-        properties.clear();
-        properties.putAll(reduced);
-
-        return this;
-    }
-
-    @Override
-    public String toString()
-    {
-        StringBuilder builder = new StringBuilder("BeanModel[");
-        builder.append(PlasticUtils.toTypeName(beanType));
-
-        builder.append(" properties:");
-        String sep = "";
-
-        for (String name : propertyNames)
-        {
-            builder.append(sep);
-            builder.append(name);
-
-            sep = ", ";
-        }
-
-        builder.append("]");
-
-        return builder.toString();
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
deleted file mode 100644
index 703ce44..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright 2007, 2008, 2010, 2011, 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.internal.beaneditor;
-
-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.TapestryInternalUtils;
-import org.apache.tapestry5.ioc.Messages;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.plastic.PlasticUtils;
-
-import java.lang.annotation.Annotation;
-
-@SuppressWarnings("all")
-public class PropertyModelImpl implements PropertyModel
-{
-    private final BeanModel model;
-
-    private final String name;
-
-    private final PropertyConduit conduit;
-
-    private final String id;
-
-    private String label;
-
-    private String dataType;
-
-    private boolean sortable;
-
-    public PropertyModelImpl(BeanModel model, String name, PropertyConduit conduit, Messages messages)
-    {
-        this.model = model;
-        this.name = name;
-        this.conduit = conduit;
-
-        id = TapestryInternalUtils.extractIdFromPropertyExpression(name);
-
-        label = TapestryInternalUtils.defaultLabel(id, messages, name);
-
-        // TAP5-2305
-        if (conduit != null)
-        {
-            Sortable sortableAnnotation = conduit.getAnnotation(Sortable.class);
-            if (sortableAnnotation != null)
-            {
-                sortable = sortableAnnotation.value();
-            }
-            else
-            {
-                // Primitive types need to be converted to wrapper types before checking to see
-                // if they are sortable.
-                Class wrapperType = PlasticUtils.toWrapperType(getPropertyType());
-                sortable = Comparable.class.isAssignableFrom(wrapperType);
-            }
-        }
-    }
-
-    public String getId()
-    {
-        return id;
-    }
-
-    public Class getPropertyType()
-    {
-        return conduit == null ? Object.class : conduit.getPropertyType();
-    }
-
-    public PropertyConduit getConduit()
-    {
-        return conduit;
-    }
-
-    public PropertyModel label(String label)
-    {
-        assert InternalUtils.isNonBlank(label);
-        this.label = label;
-
-        return this;
-    }
-
-    public String getLabel()
-    {
-        return label;
-    }
-
-    public String getPropertyName()
-    {
-        return name;
-    }
-
-    public BeanModel model()
-    {
-        return model;
-    }
-
-    public PropertyModel dataType(String dataType)
-    {
-        this.dataType = dataType;
-
-        return this;
-    }
-
-    public String getDataType()
-    {
-        return dataType;
-    }
-
-    public boolean isSortable()
-    {
-        return sortable;
-    }
-
-    public PropertyModel sortable(boolean sortable)
-    {
-        this.sortable = sortable;
-
-        return this;
-    }
-
-    public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
-    {
-        return conduit == null ? null : conduit.getAnnotation(annotationClass);
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
deleted file mode 100644
index 4dbfb2d..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2007 The Apache Software Foundation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.apache.tapestry5.internal.services;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-
-import org.apache.tapestry5.PropertyConduit;
-import org.apache.tapestry5.PropertyConduit2;
-import org.apache.tapestry5.ioc.services.TypeCoercer;
-
-public class CoercingPropertyConduitWrapper implements PropertyConduit2
-{
-    private final PropertyConduit conduit;
-
-    private final TypeCoercer coercer;
-
-    public CoercingPropertyConduitWrapper(final PropertyConduit conduit, final TypeCoercer coercer)
-    {
-        this.conduit = conduit;
-        this.coercer = coercer;
-    }
-
-    public Object get(Object instance)
-    {
-        return conduit.get(instance);
-    }
-
-    public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
-    {
-        return conduit.getAnnotation(annotationClass);
-    }
-
-    public Class getPropertyType()
-    {
-        return conduit.getPropertyType();
-    }
-    
-    public Type getPropertyGenericType()
-    {
-    	if (conduit instanceof PropertyConduit2) {
-    		return ((PropertyConduit2) conduit).getPropertyGenericType();
-    	}
-    	return conduit.getPropertyType();
-    }
-
-    @SuppressWarnings("unchecked")
-    public void set(Object instance, Object value)
-    {
-        Object coerced = coercer.coerce(value, getPropertyType());
-
-        conduit.set(instance, coerced);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
deleted file mode 100644
index 1242031..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2007, 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.internal.services;
-
-import java.lang.annotation.Annotation;
-
-import org.apache.tapestry5.internal.InternalPropertyConduit;
-import org.apache.tapestry5.internal.util.IntegerRange;
-import org.apache.tapestry5.ioc.AnnotationProvider;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.ioc.services.TypeCoercer;
-
-/**
- * Companion class for {@link org.apache.tapestry5.PropertyConduit} instances created by the
- * {@link org.apache.tapestry5.services.PropertyConduitSource}.
- */
-@SuppressWarnings("all")
-public class PropertyConduitDelegate
-{
-    private final TypeCoercer typeCoercer;
-
-    public PropertyConduitDelegate(TypeCoercer typeCoercer)
-    {
-        this.typeCoercer = typeCoercer;
-    }
-
-    public final IntegerRange range(int from, int to)
-    {
-        return new IntegerRange(from, to);
-    }
-
-    public final <T> T coerce(Object value, Class<T> type)
-    {
-        return typeCoercer.coerce(value, type);
-    }
-
-    public final boolean invert(Object value)
-    {
-        return coerce(value, Boolean.class).equals(Boolean.FALSE);
-    }
-}


[02/15] tapestry-5 git commit: First pass creating the BeanModel and Commons packages. Lots of stuff moved around, but no actual code changes so far

Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
deleted file mode 100644
index 81d1f77..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright 2006, 2007, 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;
-
-import org.apache.tapestry5.ioc.annotations.Inject;
-import org.apache.tapestry5.ioc.services.MasterObjectProvider;
-
-import java.lang.annotation.Annotation;
-
-/**
- * Defines an object which can provide access to services defined within a {@link org.apache.tapestry5.ioc.Registry}, or
- * to objects or object instances available by other means. Services are accessed via service id, or
- * (when appropriate)
- * by just service interface. The Registry itself implements this interface, as does
- * {@link org.apache.tapestry5.ioc.ServiceResources}.
- */
-public interface ObjectLocator
-{
-    /**
-     * Obtains a service via its unique service id. Returns the service's proxy. The service proxy
-     * implements the same
-     * interface as the actual service, and is used to instantiate the actual service only as needed
-     * (this is
-     * transparent to the application).
-     *
-     * @param <T>
-     * @param serviceId        unique Service id used to locate the service object (may contain <em>symbols</em>,
-     *                         which
-     *                         will be expanded), case is ignored
-     * @param serviceInterface the interface implemented by the service (or an interface extended by the service
-     *                         interface)
-     * @return the service instance
-     * @throws RuntimeException if the service is not defined, or if an error occurs instantiating it
-     */
-    <T> T getService(String serviceId, Class<T> serviceInterface);
-
-    /**
-     * Locates a service given a service interface and (optionally) some marker annotation types. A single service must implement the service
-     * interface (which                                                   * can be hard to guarantee) and by marked by all the marker types. The search takes into account inheritance of the service interface
-     * (not the service <em>implementation</em>), which may result in a failure due to extra
-     * matches.
-     *
-     * @param serviceInterface the interface the service implements
-     * @return the service's proxy
-     * @throws RuntimeException if the service does not exist (this is considered programmer error), or multiple
-     *                          services directly implement, or extend from, the service interface
-     * @see org.apache.tapestry5.ioc.annotations.Marker
-     */
-    <T> T getService(Class<T> serviceInterface);
-
-    /**
-     * Locates a service given a service interface and (optionally) some marker annotation types. A single service must implement the service
-     * interface (which                                                   * can be hard to guarantee) and by marked by all the marker types. The search takes into account inheritance of the service interface
-     * (not the service <em>implementation</em>), which may result in a failure due to extra
-     * matches.        The ability to specify marker annotation types was added in 5.3
-     *
-     * @param serviceInterface the interface the service implements
-     * @param markerTypes      Markers used to select a specific service that implements the interface
-     * @return the service's proxy
-     * @throws RuntimeException if the service does not exist (this is considered programmer error), or multiple
-     *                          services directly implement, or extend from, the service interface
-     * @see org.apache.tapestry5.ioc.annotations.Marker
-     * @since 5.3
-     */
-    <T> T getService(Class<T> serviceInterface, Class<? extends Annotation>... markerTypes);
-
-    /**
-     * Obtains an object indirectly, using the {@link org.apache.tapestry5.ioc.services.MasterObjectProvider} service.
-     *
-     * @param objectType         the type of object to be returned
-     * @param annotationProvider provides access to annotations on the field or parameter for which a value is to
-     *                           be
-     *                           obtained, which may be utilized in selecting an appropriate object, use
-     *                           <strong>null</strong> when annotations are not available (in which case, selection
-     *                           will
-     *                           be based only on the object type)
-     * @param <T>
-     * @return the requested object
-     * @see ObjectProvider
-     */
-    <T> T getObject(Class<T> objectType, AnnotationProvider annotationProvider);
-
-    /**
-     * Autobuilds a class by finding the public constructor with the most parameters. Services and other resources or
-     * dependencies will be injected into the parameters of the constructor and into private fields marked with the
-     * {@link Inject} annotation. There are two cases: constructing a service implementation, and constructing
-     * an arbitrary object. In the former case, many <em>service resources</em> are also available for injection, not
-     * just dependencies or objects provided via
-     * {@link MasterObjectProvider#provide(Class, AnnotationProvider, ObjectLocator, boolean)}.
-     *
-     * @param <T>
-     * @param clazz the type of object to instantiate
-     * @return the instantiated instance
-     * @throws RuntimeException if the autobuild fails
-     * @see MasterObjectProvider
-     */
-    <T> T autobuild(Class<T> clazz);
-
-    /**
-     * Preferred version of {@link #autobuild(Class)} that tracks the operation using
-     * {@link OperationTracker#invoke(String, Invokable)}.
-     *
-     * @param <T>
-     * @param description description used with {@link OperationTracker}
-     * @param clazz       the type of object to instantiate
-     * @return the instantiated instance
-     * @throws RuntimeException if the autobuild fails
-     * @see MasterObjectProvider
-     * @since 5.2.0
-     */
-    <T> T autobuild(String description, Class<T> clazz);
-
-    /**
-     * Creates a proxy. The proxy will defer invocation of {@link #autobuild(Class)} until
-     * just-in-time (that is, first method invocation). In a limited number of cases, it is necessary to use such a
-     * proxy to prevent service construction cycles, particularly when contributing (directly or indirectly) to the
-     * {@link org.apache.tapestry5.ioc.services.MasterObjectProvider} (which is itself at the heart
-     * of autobuilding).
-     * <p/>
-     * If the class file for the class is a file on the file system (not a file packaged in a JAR), then the proxy will
-     * <em>autoreload</em>: changing the class file will result in the new class being reloaded and re-instantiated
-     * (with dependencies).
-     *
-     * @param <T>
-     * @param interfaceClass      the interface implemented by the proxy
-     * @param implementationClass a concrete class that implements the interface
-     * @return a proxy
-     * @see #autobuild(Class)
-     */
-    <T> T proxy(Class<T> interfaceClass, Class<? extends T> implementationClass);
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Resource.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Resource.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Resource.java
deleted file mode 100644
index b81c1c5..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Resource.java
+++ /dev/null
@@ -1,108 +0,0 @@
-// 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;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.Locale;
-
-/**
- * Represents a resource on the server that may be used for server side processing, or may be exposed to the client
- * side. Generally, this represents an abstraction on top of files on the class path and files stored in the web
- * application context.
- * <p/>
- * Resources are often used as map keys; they should be immutable and should implement hashCode() and equals().
- */
-public interface Resource
-{
-
-    /**
-     * Returns true if the resource exists; if a stream to the content of the file may be opened. A resource exists
-     * if {@link #toURL()} returns a non-null value. Starting in release 5.3.4, the result of this is cached.
-     * <p/>
-     * Starting in 5.4, some "virtual resources", may return true even though {@link #toURL()} returns null.
-     *
-     * @return true if the resource exists, false if it does not
-     */
-    boolean exists();
-
-
-    /**
-     * Returns true if the resource is virtual, meaning this is no underlying file. Many operations are unsupported
-     * on virtual resources, including {@link #toURL()}, {@link #forLocale(java.util.Locale)},
-     * {@link #withExtension(String)}, {@link #getFile()}, {@link #getFolder()}, {@link #getPath()}}; these
-     * operations will throw an {@link java.lang.UnsupportedOperationException}.
-     *
-     * @since 5.4
-     */
-    boolean isVirtual();
-
-    /**
-     * Opens a stream to the content of the resource, or returns null if the resource does not exist. The native
-     * input stream supplied by the resource is wrapped in a {@link java.io.BufferedInputStream}.
-     *
-     * @return an open, buffered stream to the content, if available
-     */
-    InputStream openStream() throws IOException;
-
-    /**
-     * Returns the URL for the resource, or null if it does not exist. This value is lazily computed; starting in 5.3.4, subclasses may cache
-     * the result.  Starting in 5.4, some "virtual resources" may return null.
-     */
-    URL toURL();
-
-    /**
-     * Returns a localized version of the resource. May return null if no such resource exists. Starting in release
-     * 5.3.4, the result of this method is cached internally.
-     */
-    Resource forLocale(Locale locale);
-
-    /**
-     * Returns a Resource based on a relative path, relative to the folder containing the resource. Understands the "."
-     * (current folder) and ".." (parent folder) conventions, and treats multiple sequential slashes as a single slash.
-     * <p/>
-     * Virtual resources (resources fabricated at runtime) return themselves.
-     */
-    Resource forFile(String relativePath);
-
-    /**
-     * Returns a new Resource with the extension changed (or, if the resource does not have an extension, the extension
-     * is added). The new Resource may not exist (that is, {@link #toURL()} may return null.
-     *
-     * @param extension
-     *         to apply to the resource, such as "html" or "properties"
-     * @return the new resource
-     */
-    Resource withExtension(String extension);
-
-    /**
-     * Returns the portion of the path up to the last forward slash; this is the directory or folder portion of the
-     * Resource.
-     */
-    String getFolder();
-
-    /**
-     * Returns the file portion of the Resource path, everything that follows the final forward slash.
-     * <p/>
-     * Starting in 5.4, certain kinds of "virtual resources" may return null here.
-     */
-    String getFile();
-
-    /**
-     * Return the path (the combination of folder and file).
-     * <p/>
-     * Starting in 5.4, certain "virtual resources", may return an arbitrary value here.
-     */
-    String getPath();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesConfiguration.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesConfiguration.java
deleted file mode 100644
index 2e03557..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesConfiguration.java
+++ /dev/null
@@ -1,34 +0,0 @@
-//  Copyright 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.annotations;
-
-import java.lang.annotation.*;
-
-
-/**
- * A documentation-only interface placed on service interfaces for services which have an {@linkplain
- * org.apache.tapestry5.ioc.Configuration unordered configuration}, to identify the type of contribution.
- */
-@Target(ElementType.TYPE)
-@Retention(RetentionPolicy.CLASS)
-@Documented
-@UseWith(AnnotationUseContext.SERVICE)
-public @interface UsesConfiguration
-{
-    /**
-     * The type of object which may be contributed into the service's configuration.
-     */
-    Class value();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java
deleted file mode 100644
index 716b7c6..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2007 The Apache Software Foundation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.apache.tapestry5.ioc.internal;
-
-import org.apache.tapestry5.ioc.AnnotationProvider;
-
-import java.lang.annotation.Annotation;
-
-/**
- * A null implementation of {@link AnnotationProvider}, used when there is not appropriate source of annotations.
- */
-public class NullAnnotationProvider implements AnnotationProvider
-{
-    /**
-     * Always returns null.
-     */
-    @Override
-    public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
-    {
-        return null;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java
deleted file mode 100644
index 6711b1a..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright 2006, 2007, 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.util;
-
-import org.apache.tapestry5.ioc.util.CaseInsensitiveMap;
-import org.apache.tapestry5.ioc.util.Stack;
-
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-/**
- * Static factory methods to ease the creation of new collection types (when using generics). Most of these method
- * leverage the compiler's ability to match generic types by return value. Typical usage (with a static import):
- * <p/>
- * <pre>
- * Map&lt;Foo, Bar&gt; map = newMap();
- * </pre>
- * <p/>
- * <p/>
- * This is a replacement for:
- * <p/>
- * <pre>
- * Map&lt;Foo, Bar&gt; map = new HashMap&lt;Foo, Bar&gt;();
- * </pre>
- */
-public final class CollectionFactory
-{
-    /**
-     * Constructs and returns a generic {@link HashMap} instance.
-     */
-    public static <K, V> Map<K, V> newMap()
-    {
-        return new HashMap<K, V>();
-    }
-
-    /**
-     * Constructs and returns a generic {@link java.util.HashSet} instance.
-     */
-    public static <T> Set<T> newSet()
-    {
-        return new HashSet<T>();
-    }
-
-    /**
-     * Contructs a new {@link HashSet} and initializes it using the provided collection.
-     */
-    public static <T, V extends T> Set<T> newSet(Collection<V> values)
-    {
-        return new HashSet<T>(values);
-    }
-
-    public static <T, V extends T> Set<T> newSet(V... values)
-    {
-        // Was a call to newSet(), but Sun JDK can't handle that. Fucking generics.
-        return new HashSet<T>(Arrays.asList(values));
-    }
-
-    /**
-     * Constructs a new {@link java.util.HashMap} instance by copying an existing Map instance.
-     */
-    public static <K, V> Map<K, V> newMap(Map<? extends K, ? extends V> map)
-    {
-        return new HashMap<K, V>(map);
-    }
-
-    /**
-     * Constructs a new concurrent map, which is safe to access via multiple threads.
-     */
-    public static <K, V> ConcurrentMap<K, V> newConcurrentMap()
-    {
-        return new ConcurrentHashMap<K, V>();
-    }
-
-    /**
-     * Contructs and returns a new generic {@link java.util.ArrayList} instance.
-     */
-    public static <T> List<T> newList()
-    {
-        return new ArrayList<T>();
-    }
-
-    /**
-     * Creates a new, fully modifiable list from an initial set of elements.
-     */
-    public static <T, V extends T> List<T> newList(V... elements)
-    {
-        // Was call to newList(), but Sun JDK can't handle that.
-        return new ArrayList<T>(Arrays.asList(elements));
-    }
-
-    /**
-     * Useful for queues.
-     */
-    public static <T> LinkedList<T> newLinkedList()
-    {
-        return new LinkedList<T>();
-    }
-
-    /**
-     * Constructs and returns a new {@link java.util.ArrayList} as a copy of the provided collection.
-     */
-    public static <T, V extends T> List<T> newList(Collection<V> list)
-    {
-        return new ArrayList<T>(list);
-    }
-
-    /**
-     * Constructs and returns a new {@link java.util.concurrent.CopyOnWriteArrayList}.
-     */
-    public static <T> List<T> newThreadSafeList()
-    {
-        return new CopyOnWriteArrayList<T>();
-    }
-
-    public static <T> Stack<T> newStack()
-    {
-        return new Stack<T>();
-    }
-
-    public static <V> Map<String, V> newCaseInsensitiveMap()
-    {
-        return new CaseInsensitiveMap<V>();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
deleted file mode 100644
index 1a6dd80..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
+++ /dev/null
@@ -1,615 +0,0 @@
-// Copyright 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.util;
-
-import java.lang.reflect.*;
-import java.util.LinkedList;
-
-/**
- * Static methods related to the use of JDK 1.5 generics.
- */
-@SuppressWarnings("unchecked")
-public class GenericsUtils
-{
-    /**
-     * Analyzes the method in the context of containingClass and returns the Class that is represented by
-     * the method's generic return type. Any parameter information in the generic return type is lost. If you want
-     * to preserve the type parameters of the return type consider using
-     * {@link #extractActualType(java.lang.reflect.Type, java.lang.reflect.Method)}.
-     *
-     * @param containingClass class which either contains or inherited the method
-     * @param method          method from which to extract the return type
-     * @return the class represented by the methods generic return type, resolved based on the context .
-     * @see #extractActualType(java.lang.reflect.Type, java.lang.reflect.Method)
-     * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
-     * @see #asClass(java.lang.reflect.Type)
-     */
-    public static Class<?> extractGenericReturnType(Class<?> containingClass, Method method)
-    {
-        return asClass(resolve(method.getGenericReturnType(), containingClass));
-    }
-
-
-    /**
-     * Analyzes the field in the context of containingClass and returns the Class that is represented by
-     * the field's generic type. Any parameter information in the generic type is lost, if you want
-     * to preserve the type parameters of the return type consider using
-     * {@link #getTypeVariableIndex(java.lang.reflect.TypeVariable)}.
-     *
-     * @param containingClass class which either contains or inherited the field
-     * @param field           field from which to extract the type
-     * @return the class represented by the field's generic type, resolved based on the containingClass.
-     * @see #extractActualType(java.lang.reflect.Type, java.lang.reflect.Field)
-     * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
-     * @see #asClass(java.lang.reflect.Type)
-     */
-    public static Class extractGenericFieldType(Class containingClass, Field field)
-    {
-        return asClass(resolve(field.getGenericType(), containingClass));
-    }
-
-    /**
-     * Analyzes the method in the context of containingClass and returns the Class that is represented by
-     * the method's generic return type. Any parameter information in the generic return type is lost.
-     *
-     * @param containingType Type which is/represents the class that either contains or inherited the method
-     * @param method         method from which to extract the generic return type
-     * @return the generic type represented by the methods generic return type, resolved based on the containingType.
-     * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
-     */
-    public static Type extractActualType(Type containingType, Method method)
-    {
-        return resolve(method.getGenericReturnType(), containingType);
-    }
-
-    /**
-     * Analyzes the method in the context of containingClass and returns the Class that is represented by
-     * the method's generic return type. Any parameter information in the generic return type is lost.
-     *
-     * @param containingType Type which is/represents the class that either contains or inherited the field
-     * @param field          field from which to extract the generic return type
-     * @return the generic type represented by the methods generic return type, resolved based on the containingType.
-     * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
-     */
-    public static Type extractActualType(Type containingType, Field field)
-    {
-        return resolve(field.getGenericType(), containingType);
-    }
-
-    /**
-     * Resolves the type parameter based on the context of the containingType.
-     * <p/>
-     * {@link java.lang.reflect.TypeVariable} will be unwrapped to the type argument resolved form the class
-     * hierarchy. This may be something other than a simple Class if the type argument is a ParameterizedType for
-     * instance (e.g. List&lt;E>; List&lt;Map&lt;Long, String>>, E would be returned as a ParameterizedType with the raw
-     * type Map and type arguments Long and String.
-     * <p/>
-     *
-     * @param type
-     *          the generic type (ParameterizedType, GenericArrayType, WildcardType, TypeVariable) to be resolved
-     * @param containingType
-     *          the type which his
-     * @return
-     *          the type resolved to the best of our ability.
-     * @since 5.2.?
-     */
-    public static Type resolve(final Type type, final Type containingType)
-    {
-        // The type isn't generic. (String, Long, etc)
-        if (type instanceof Class)
-            return type;
-
-        // List<T>, List<String>, List<T extends Number>
-        if (type instanceof ParameterizedType)
-            return resolve((ParameterizedType) type, containingType);
-
-        // T[], List<String>[], List<T>[]
-        if (type instanceof GenericArrayType)
-            return resolve((GenericArrayType) type, containingType);
-
-        // List<? extends T>, List<? extends Object & Comparable & Serializable>
-        if (type instanceof WildcardType)
-            return resolve((WildcardType) type, containingType);
-
-        // T
-        if (type instanceof TypeVariable)
-            return resolve((TypeVariable) type, containingType);
-
-        // I'm leaning towards an exception here.
-        return type;
-    }
-
-
-    /**
-     * Determines if the suspected super type is assignable from the suspected sub type.
-     *
-     * @param suspectedSuperType
-     *          e.g. GenericDAO&lt;Pet, String>
-     * @param suspectedSubType
-     *          e.g. PetDAO extends GenericDAO&lt;Pet,String>
-     * @return
-     *          true if (sourceType)targetClass is a valid cast
-     */
-    public static boolean isAssignableFrom(Type suspectedSuperType, Type suspectedSubType)
-    {
-        final Class suspectedSuperClass = asClass(suspectedSuperType);
-        final Class suspectedSubClass = asClass(suspectedSubType);
-
-        // The raw types need to be compatible.
-        if (!suspectedSuperClass.isAssignableFrom(suspectedSubClass))
-        {
-            return false;
-        }
-
-        // From this point we know that the raw types are assignable.
-        // We need to figure out what the generic parameters in the targetClass are
-        // as they pertain to the sourceType.
-
-        if (suspectedSuperType instanceof WildcardType)
-        {
-            // ? extends Number
-            // needs to match all the bounds (there will only be upper bounds or lower bounds
-            for (Type t : ((WildcardType) suspectedSuperType).getUpperBounds())
-            {
-                if (!isAssignableFrom(t, suspectedSubType)) return false;
-            }
-            for (Type t : ((WildcardType) suspectedSuperType).getLowerBounds())
-            {
-                if (!isAssignableFrom(suspectedSubType, t)) return false;
-            }
-            return true;
-        }
-
-        Type curType = suspectedSubType;
-        Class curClass;
-
-        while (curType != null && !curType.equals(Object.class))
-        {
-            curClass = asClass(curType);
-
-            if (curClass.equals(suspectedSuperClass))
-            {
-                final Type resolved = resolve(curType, suspectedSubType);
-
-                if (suspectedSuperType instanceof Class)
-                {
-                    if ( resolved instanceof Class )
-                        return suspectedSuperType.equals(resolved);
-
-                    // They may represent the same class, but the suspectedSuperType is not parameterized. The parameter
-                    // types default to Object so they must be a match.
-                    // e.g. Pair p = new StringLongPair();
-                    //      Pair p = new Pair<? extends Number, String>
-
-                    return true;
-                }
-
-                if (suspectedSuperType instanceof ParameterizedType)
-                {
-                    if (resolved instanceof ParameterizedType)
-                    {
-                        final Type[] type1Arguments = ((ParameterizedType) suspectedSuperType).getActualTypeArguments();
-                        final Type[] type2Arguments = ((ParameterizedType) resolved).getActualTypeArguments();
-                        if (type1Arguments.length != type2Arguments.length) return false;
-
-                        for (int i = 0; i < type1Arguments.length; ++i)
-                        {
-                            if (!isAssignableFrom(type1Arguments[i], type2Arguments[i])) return false;
-                        }
-                        return true;
-                    }
-                }
-                else if (suspectedSuperType instanceof GenericArrayType)
-                {
-                    if (resolved instanceof GenericArrayType)
-                    {
-                        return isAssignableFrom(
-                                ((GenericArrayType) suspectedSuperType).getGenericComponentType(),
-                                ((GenericArrayType) resolved).getGenericComponentType()
-                        );
-                    }
-                }
-
-                return false;
-            }
-
-            final Type[] types = curClass.getGenericInterfaces();
-            for (Type t : types)
-            {
-                final Type resolved = resolve(t, suspectedSubType);
-                if (isAssignableFrom(suspectedSuperType, resolved))
-                    return true;
-            }
-
-            curType = curClass.getGenericSuperclass();
-        }
-        return false;
-    }
-
-    /**
-     * Get the class represented by the reflected type.
-     * This method is lossy; You cannot recover the type information from the class that is returned.
-     * <p/>
-     * {@code TypeVariable} the first bound is returned. If your type variable extends multiple interfaces that information
-     * is lost.
-     * <p/>
-     * {@code WildcardType} the first lower bound is returned. If the wildcard is defined with upper bounds
-     * then {@code Object} is returned.
-     *
-     * @param actualType
-     *           a Class, ParameterizedType, GenericArrayType
-     * @return the un-parameterized class associated with the type.
-     */
-    public static Class asClass(Type actualType)
-    {
-        if (actualType instanceof Class) return (Class) actualType;
-
-        if (actualType instanceof ParameterizedType)
-        {
-            final Type rawType = ((ParameterizedType) actualType).getRawType();
-            // The sun implementation returns getRawType as Class<?>, but there is room in the interface for it to be
-            // some other Type. We'll assume it's a Class.
-            // TODO: consider logging or throwing our own exception for that day when "something else" causes some confusion
-            return (Class) rawType;
-        }
-
-        if (actualType instanceof GenericArrayType)
-        {
-            final Type type = ((GenericArrayType) actualType).getGenericComponentType();
-            return Array.newInstance(asClass(type), 0).getClass();
-        }
-
-        if (actualType instanceof TypeVariable)
-        {
-            // Support for List<T extends Number>
-            // There is always at least one bound. If no bound is specified in the source then it will be Object.class
-            return asClass(((TypeVariable) actualType).getBounds()[0]);
-        }
-
-        if (actualType instanceof WildcardType)
-        {
-            final WildcardType wildcardType = (WildcardType) actualType;
-            final Type[] bounds = wildcardType.getLowerBounds();
-            if (bounds != null && bounds.length > 0)
-            {
-                return asClass(bounds[0]);
-            }
-            // If there is no lower bounds then the only thing that makes sense is Object.
-            return Object.class;
-        }
-
-        throw new RuntimeException(String.format("Unable to convert %s to Class.", actualType));
-    }
-
-    /**
-     * Convert the type into a string. The string representation approximates the code that would be used to define the
-     * type.
-     *
-     * @param type - the type.
-     * @return a string representation of the type, similar to how it was declared.
-     */
-    public static String toString(Type type)
-    {
-        if ( type instanceof ParameterizedType ) return toString((ParameterizedType)type);
-        if ( type instanceof WildcardType ) return toString((WildcardType)type);
-        if ( type instanceof GenericArrayType) return toString((GenericArrayType)type);
-        if ( type instanceof Class )
-        {
-            final Class theClass = (Class) type;
-            return (theClass.isArray() ? theClass.getName() + "[]" : theClass.getName());
-        }
-        return type.toString();
-    }
-
-    /**
-     * Method to resolve a TypeVariable to its most
-     * <a href="http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#112582">reifiable</a> form.
-     * <p/>
-     * <p/>
-     * How to resolve a TypeVariable:<br/>
-     * All of the TypeVariables defined by a generic class will be given a Type by any class that extends it. The Type
-     * given may or may not be reifiable; it may be another TypeVariable for instance.
-     * <p/>
-     * Consider <br/>
-     * <i>class Pair&gt;A,B> { A getA(){...}; ...}</i><br/>
-     * <i>class StringLongPair extends Pair&gt;String, Long> { }</i><br/>
-     * <p/>
-     * To resolve the actual return type of Pair.getA() you must first resolve the TypeVariable "A".
-     * We can do that by first finding the index of "A" in the Pair.class.getTypeParameters() array of TypeVariables.
-     * <p/>
-     * To get to the Type provided by StringLongPair you access the generics information by calling
-     * StringLongPair.class.getGenericSuperclass; this will be a ParameterizedType. ParameterizedType gives you access
-     * to the actual type arguments provided to Pair by StringLongPair. The array is in the same order as the array in
-     * Pair.class.getTypeParameters so you can use the index we discovered earlier to extract the Type; String.class.
-     * <p/>
-     * When extracting Types we only have to consider the superclass hierarchy and not the interfaces implemented by
-     * the class. When a class implements a generic interface it must provide types for the interface and any generic
-     * methods implemented from the interface will be re-defined by the class with its generic type variables.
-     *
-     * @param typeVariable   - the type variable to resolve.
-     * @param containingType - the shallowest class in the class hierarchy (furthest from Object) where typeVariable is defined.
-     * @return a Type that has had all possible TypeVariables resolved that have been defined between the type variable
-     *         declaration and the containingType.
-     */
-    private static Type resolve(TypeVariable typeVariable, Type containingType)
-    {
-        // The generic declaration is either a Class, Method or Constructor
-        final GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
-
-        if (!(genericDeclaration instanceof Class))
-        {
-            // It's a method or constructor. The best we can do here is try to resolve the bounds
-            // e.g. <T extends E> T getT(T param){} where E is defined by the class.
-            final Type bounds0 = typeVariable.getBounds()[0];
-            return resolve(bounds0, containingType);
-        }
-
-        final Class typeVariableOwner = (Class) genericDeclaration;
-
-        // find the typeOwner in the containingType's hierarchy
-        final LinkedList<Type> stack = new LinkedList<Type>();
-
-        // If you pass a List<Long> as the containingType then the TypeVariable is going to be resolved by the
-        // containingType and not the super class.
-        if (containingType instanceof ParameterizedType)
-        {
-            stack.add(containingType);
-        }
-
-        Class theClass = asClass(containingType);
-        Type genericSuperclass = theClass.getGenericSuperclass();
-        while (genericSuperclass != null && // true for interfaces with no superclass
-                !theClass.equals(Object.class) &&
-                !theClass.equals(typeVariableOwner))
-        {
-            stack.addFirst(genericSuperclass);
-            theClass = asClass(genericSuperclass);
-            genericSuperclass = theClass.getGenericSuperclass();
-        }
-
-        int i = getTypeVariableIndex(typeVariable);
-        Type resolved = typeVariable;
-        for (Type t : stack)
-        {
-            if (t instanceof ParameterizedType)
-            {
-                resolved = ((ParameterizedType) t).getActualTypeArguments()[i];
-                if (resolved instanceof Class) return resolved;
-                if (resolved instanceof TypeVariable)
-                {
-                    // Need to look at the next class in the hierarchy
-                    i = getTypeVariableIndex((TypeVariable) resolved);
-                    continue;
-                }
-                return resolve(resolved, containingType);
-            }
-        }
-
-        // the only way we get here is if resolved is still a TypeVariable, otherwise an
-        // exception is thrown or a value is returned.
-        return ((TypeVariable) resolved).getBounds()[0];
-    }
-
-    /**
-     * @param type           - something like List&lt;T>[] or List&lt;? extends T>[] or T[]
-     * @param containingType - the shallowest type in the hierarchy where type is defined.
-     * @return either the passed type if no changes required or a copy with a best effort resolve of the component type.
-     */
-    private static GenericArrayType resolve(GenericArrayType type, Type containingType)
-    {
-        final Type componentType = type.getGenericComponentType();
-
-        if (!(componentType instanceof Class))
-        {
-            final Type resolved = resolve(componentType, containingType);
-            return create(resolved);
-        }
-
-        return type;
-    }
-
-    /**
-     * @param type           - something like List&lt;T>, List&lt;T extends Number>
-     * @param containingType - the shallowest type in the hierarchy where type is defined.
-     * @return the passed type if nothing to resolve or a copy of the type with the type arguments resolved.
-     */
-    private static ParameterizedType resolve(ParameterizedType type, Type containingType)
-    {
-        // Use a copy because we're going to modify it.
-        final Type[] types = type.getActualTypeArguments().clone();
-
-        boolean modified = resolve(types, containingType);
-        return modified ? create(type.getRawType(), type.getOwnerType(), types) : type;
-    }
-
-    /**
-     * @param type           - something like List&lt;? super T>, List<&lt;? extends T>, List&lt;? extends T & Comparable&lt? super T>>
-     * @param containingType - the shallowest type in the hierarchy where type is defined.
-     * @return the passed type if nothing to resolve or a copy of the type with the upper and lower bounds resolved.
-     */
-    private static WildcardType resolve(WildcardType type, Type containingType)
-    {
-        // Use a copy because we're going to modify them.
-        final Type[] upper = type.getUpperBounds().clone();
-        final Type[] lower = type.getLowerBounds().clone();
-
-        boolean modified = resolve(upper, containingType);
-        modified = modified || resolve(lower, containingType);
-
-        return modified ? create(upper, lower) : type;
-    }
-
-    /**
-     * @param types          - Array of types to resolve. The unresolved type is replaced in the array with the resolved type.
-     * @param containingType - the shallowest type in the hierarchy where type is defined.
-     * @return true if any of the types were resolved.
-     */
-    private static boolean resolve(Type[] types, Type containingType)
-    {
-        boolean modified = false;
-        for (int i = 0; i < types.length; ++i)
-        {
-            Type t = types[i];
-            if (!(t instanceof Class))
-            {
-                modified = true;
-                final Type resolved = resolve(t, containingType);
-                if (!resolved.equals(t))
-                {
-                    types[i] = resolved;
-                    modified = true;
-                }
-            }
-        }
-        return modified;
-    }
-
-    /**
-     * @param rawType       - the un-parameterized type.
-     * @param ownerType     - the outer class or null if the class is not defined within another class.
-     * @param typeArguments - type arguments.
-     * @return a copy of the type with the typeArguments replaced.
-     */
-    static ParameterizedType create(final Type rawType, final Type ownerType, final Type[] typeArguments)
-    {
-        return new ParameterizedType()
-        {
-            @Override
-            public Type[] getActualTypeArguments()
-            {
-                return typeArguments;
-            }
-
-            @Override
-            public Type getRawType()
-            {
-                return rawType;
-            }
-
-            @Override
-            public Type getOwnerType()
-            {
-                return ownerType;
-            }
-
-            @Override
-            public String toString()
-            {
-                return GenericsUtils.toString(this);
-            }
-        };
-    }
-
-    static GenericArrayType create(final Type componentType)
-    {
-        return new GenericArrayType()
-        {
-            @Override
-            public Type getGenericComponentType()
-            {
-                return componentType;
-            }
-
-            @Override
-            public String toString()
-            {
-                return GenericsUtils.toString(this);
-            }
-        };
-    }
-
-    /**
-     * @param upperBounds - e.g. ? extends Number
-     * @param lowerBounds - e.g. ? super Long
-     * @return An new copy of the type with the upper and lower bounds replaced.
-     */
-    static WildcardType create(final Type[] upperBounds, final Type[] lowerBounds)
-    {
-
-        return new WildcardType()
-        {
-            @Override
-            public Type[] getUpperBounds()
-            {
-                return upperBounds;
-            }
-
-            @Override
-            public Type[] getLowerBounds()
-            {
-                return lowerBounds;
-            }
-
-            @Override
-            public String toString()
-            {
-                return GenericsUtils.toString(this);
-            }
-        };
-    }
-
-    static String toString(ParameterizedType pt)
-    {
-        String s = toString(pt.getActualTypeArguments());
-        return String.format("%s<%s>", toString(pt.getRawType()), s);
-    }
-
-    static String toString(GenericArrayType gat)
-    {
-        return String.format("%s[]", toString(gat.getGenericComponentType()));
-    }
-
-    static String toString(WildcardType wt)
-    {
-        final boolean isSuper = wt.getLowerBounds().length > 0;
-        return String.format("? %s %s",
-                isSuper ? "super" : "extends",
-                isSuper ? toString(wt.getLowerBounds()) : toString(wt.getLowerBounds()));
-    }
-
-    static String toString(Type[] types)
-    {
-        StringBuilder sb = new StringBuilder();
-        for ( Type t : types )
-        {
-            sb.append(toString(t)).append(", ");
-        }
-        return sb.substring(0, sb.length() - 2);// drop last ,
-    }
-
-    /**
-     * Find the index of the TypeVariable in the classes parameters. The offset can be used on a subclass to find
-     * the actual type.
-     *
-     * @param typeVariable - the type variable in question.
-     * @return the index of the type variable in its declaring class/method/constructor's type parameters.
-     */
-    private static int getTypeVariableIndex(final TypeVariable typeVariable)
-    {
-        // the label from the class (the T in List<T>, the K or V in Map<K,V>, etc)
-        final String typeVarName = typeVariable.getName();
-        final TypeVariable[] typeParameters = typeVariable.getGenericDeclaration().getTypeParameters();
-        for (int typeArgumentIndex = 0; typeArgumentIndex < typeParameters.length; typeArgumentIndex++)
-        {
-            // The .equals for TypeVariable may not be compatible, a name check should be sufficient.
-            if (typeParameters[typeArgumentIndex].getName().equals(typeVarName))
-                return typeArgumentIndex;
-        }
-
-        // The only way this could happen is if the TypeVariable is hand built incorrectly, or it's corrupted.
-        throw new RuntimeException(
-                String.format("%s does not have a TypeVariable matching %s", typeVariable.getGenericDeclaration(), typeVariable));
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
deleted file mode 100644
index ef217cb..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2006 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.util;
-
-import org.apache.tapestry5.ioc.Locatable;
-import org.apache.tapestry5.ioc.Location;
-
-/**
- * Exception class used as a replacement for {@link java.lang.RuntimeException} when the exception is related to a
- * particular location.
- */
-public class TapestryException extends RuntimeException implements Locatable
-{
-    private static final long serialVersionUID = 6396903640977182682L;
-
-    private transient final Location location;
-
-    /**
-     * @param message  a message (may be null)
-     * @param location implements {@link Location} or {@link Locatable}
-     * @param cause    if not null, the root cause of the exception
-     */
-    public TapestryException(String message, Object location, Throwable cause)
-    {
-        this(message, InternalUtils.locationOf(location), cause);
-    }
-
-    /**
-     * @param message a message (may be null)
-     * @param cause   if not null, the root cause of the exception, also used to set the location
-     */
-    public TapestryException(String message, Throwable cause)
-    {
-        this(message, cause, cause);
-    }
-
-    /**
-     * @param message  a message (may be null)
-     * @param location location to associated with the exception, or null if not known
-     * @param cause    if not null, the root cause of the exception
-     */
-    public TapestryException(String message, Location location, Throwable cause)
-    {
-        super(message, cause);
-
-        this.location = location;
-    }
-
-    @Override
-    public Location getLocation()
-    {
-        return location;
-    }
-
-    @Override
-    public String toString()
-    {
-        if (location == null) return super.toString();
-
-        return String.format("%s [at %s]", super.toString(), location);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java
deleted file mode 100644
index 6159ed3..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2006, 2007, 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.services;
-
-import java.lang.annotation.Annotation;
-import java.util.List;
-
-/**
- * Organizes all {@link org.apache.tapestry5.ioc.services.PropertyAdapter}s for a particular class.
- * <p/>
- * Only provides access to <em>simple</em> properties. Indexed properties are ignored.
- * <p/>
- * When accessing properties by name, the case of the name is ignored.
- */
-public interface ClassPropertyAdapter
-{
-    /**
-     * Returns the names of all properties, sorted into alphabetic order. This includes true properties
-     * (as defined in the JavaBeans specification), but also public fields. Starting in Tapestry 5.3, even public static fields are included.
-     */
-    List<String> getPropertyNames();
-
-    /**
-     * Returns the type of bean this adapter provides properties for.
-     */
-    Class getBeanType();
-
-    /**
-     * Returns the property adapter with the given name, or null if no such adapter exists.
-     *
-     * @param name of the property (case is ignored)
-     */
-    PropertyAdapter getPropertyAdapter(String name);
-
-    /**
-     * Reads the value of a property.
-     *
-     * @param instance     the object to read a value from
-     * @param propertyName the name of the property to read (case is ignored)
-     * @throws UnsupportedOperationException if the property is write only
-     * @throws IllegalArgumentException      if property does not exist
-     */
-    Object get(Object instance, String propertyName);
-
-    /**
-     * Updates the value of a property.
-     *
-     * @param instance     the object to update
-     * @param propertyName the name of the property to update (case is ignored)
-     * @throws UnsupportedOperationException if the property is read only
-     * @throws IllegalArgumentException      if property does not exist
-     */
-    void set(Object instance, String propertyName, Object value);
-
-    /**
-     * Returns the annotation of a given property for the specified type if such an annotation is present, else null.
-     *
-     * @param instance     the object to read a value from
-     * @param propertyName the name of the property to read (case is ignored)
-     * @param annotationClass the type of annotation to return
-     *
-     * @throws IllegalArgumentException      if property does not exist
-     *
-     * @since 5.4
-     */
-    Annotation getAnnotation(Object instance, String propertyName, Class<? extends Annotation> annotationClass);
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java
deleted file mode 100644
index b7a4cc8..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2006 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.services;
-
-/**
- * Responsible for converting from one type to another. This is used primarily around component parameters.
- *
- * @param <S> the source type (input)
- * @param <T> the target type (output)
- */
-public interface Coercion<S, T>
-{
-    /**
-     * Converts an input value.
-     *
-     * @param input the input value
-     */
-    T coerce(S input);
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java
deleted file mode 100644
index 746de1e..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java
+++ /dev/null
@@ -1,145 +0,0 @@
-// 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.services;
-
-import org.apache.tapestry5.plastic.PlasticUtils;
-
-/**
- * An immutable object that represents a mapping from one type to another. This is also the contribution type when
- * building the {@link org.apache.tapestry5.ioc.services.TypeCoercer} service. Wraps a
- * {@link org.apache.tapestry5.ioc.services.Coercion} object that performs the work with additional properties that
- * describe
- * the input and output types of the coercion, needed when searching for an appropriate coercion (or sequence of
- * coercions).
- *
- * @param <S>
- *         source (input) type
- * @param <T>
- *         target (output) type
- */
-public final class CoercionTuple<S, T>
-{
-    private final Class<S> sourceType;
-
-    private final Class<T> targetType;
-
-    private final Coercion<S, T> coercion;
-
-    /**
-     * Wraps an arbitrary coercion with an implementation of toString() that identifies the source and target types.
-     */
-    private class CoercionWrapper<WS, WT> implements Coercion<WS, WT>
-    {
-        private final Coercion<WS, WT> coercion;
-
-        public CoercionWrapper(Coercion<WS, WT> coercion)
-        {
-            this.coercion = coercion;
-        }
-
-        @Override
-        public WT coerce(WS input)
-        {
-            return coercion.coerce(input);
-        }
-
-        @Override
-        public String toString()
-        {
-            return String.format("%s --> %s", convert(sourceType), convert(targetType));
-        }
-    }
-
-    private String convert(Class type)
-    {
-        if (Void.class.equals(type))
-            return "null";
-
-        String name = PlasticUtils.toTypeName(type);
-
-        int dotx = name.lastIndexOf('.');
-
-        // Strip off a package name of "java.lang"
-
-        if (dotx > 0 && name.substring(0, dotx).equals("java.lang"))
-            return name.substring(dotx + 1);
-
-        return name;
-    }
-
-    /**
-     * Standard constructor, which defaults wrap to true.
-     */
-    public CoercionTuple(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion)
-    {
-        this(sourceType, targetType, coercion, true);
-    }
-
-    /**
-     * Convenience constructor to help with generics.
-     *
-     * @since 5.2.0
-     */
-    public static <S, T> CoercionTuple<S, T> create(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion)
-    {
-        return new CoercionTuple<S, T>(sourceType, targetType, coercion);
-    }
-
-    /**
-     * Internal-use constructor.
-     *
-     * @param sourceType
-     *         the source (or input) type of the coercion, may be Void.class to indicate a coercion from null
-     * @param targetType
-     *         the target (or output) type of the coercion
-     * @param coercion
-     *         the object that performs the coercion
-     * @param wrap
-     *         if true, the coercion is wrapped to provide a useful toString()
-     */
-    @SuppressWarnings("unchecked")
-    public CoercionTuple(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion, boolean wrap)
-    {
-        assert sourceType != null;
-        assert targetType != null;
-        assert coercion != null;
-
-        this.sourceType = PlasticUtils.toWrapperType(sourceType);
-        this.targetType = PlasticUtils.toWrapperType(targetType);
-        this.coercion = wrap ? new CoercionWrapper<S, T>(coercion) : coercion;
-    }
-
-    @Override
-    public String toString()
-    {
-        return coercion.toString();
-    }
-
-    public Coercion<S, T> getCoercion()
-    {
-        return coercion;
-    }
-
-    public Class<S> getSourceType()
-    {
-        return sourceType;
-    }
-
-    public Class<T> getTargetType()
-    {
-        return targetType;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java
deleted file mode 100644
index ae542c5..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2006, 2010, 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.services;
-
-import java.lang.annotation.Annotation;
-
-/**
- * A wrapper around the JavaBean Introspector that allows more manageable access to JavaBean properties of objects.
- * <p/>
- * Only provides access to <em>simple</em> properties. Indexed properties are ignored.
- * <p>
- * Starting in Tapestry 5.2, public fields can now be accessed as if they were properly JavaBean properties. Where there
- * is a name conflict, the true property will be favored over the field access.
- */
-public interface PropertyAccess
-{
-    /**
-     * Reads the value of a property.
-     *
-     * @throws UnsupportedOperationException
-     *             if the property is write only
-     * @throws IllegalArgumentException
-     *             if property does not exist
-     */
-    Object get(Object instance, String propertyName);
-
-    /**
-     * Updates the value of a property.
-     *
-     * @throws UnsupportedOperationException
-     *             if the property is read only
-     * @throws IllegalArgumentException
-     *             if property does not exist
-     */
-    void set(Object instance, String propertyName, Object value);
-
-    /**
-     * Returns the annotation of a given property for the specified type if such an annotation is present, else null.
-     * A convenience over invoking {@link #getAdapter(Object)}.{@link ClassPropertyAdapter#getPropertyAdapter(String)}.{@link PropertyAdapter#getAnnotation(Class)}
-     *
-     * @param instance     the object to read a value from
-     * @param propertyName the name of the property to read (case is ignored)
-     * @param annotationClass the type of annotation to return
-     * @throws IllegalArgumentException
-     *             if property does not exist
-     *
-     * @since 5.4
-     */
-    Annotation getAnnotation(Object instance, String propertyName, Class<? extends Annotation> annotationClass);
-
-    /**
-     * Returns the adapter for a particular object instance. A convienience over invoking {@link #getAdapter(Class)}.
-     */
-    ClassPropertyAdapter getAdapter(Object instance);
-
-    /**
-     * Returns the adapter used to access properties within the indicated class.
-     */
-    ClassPropertyAdapter getAdapter(Class forClass);
-
-    /**
-     * Discards all stored property access information, discarding all created class adapters.
-     */
-    void clearCache();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java
deleted file mode 100644
index 947535e..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright 2006, 2008, 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.services;
-
-import org.apache.tapestry5.ioc.AnnotationProvider;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-
-/**
- * Provides access to a single property within a class. Acts as an {@link org.apache.tapestry5.ioc.AnnotationProvider};
- * when searching for annotations, the read method (if present) is checked first, followed by the write method, followed
- * by the underlying field (when the property name matches the field name).
- * <p/>
- * Starting in release 5.2, this property may actually be a public field. In 5.3, it may be a public static field.
- *
- * @see org.apache.tapestry5.ioc.services.ClassPropertyAdapter
- */
-@SuppressWarnings("unchecked")
-public interface PropertyAdapter extends AnnotationProvider
-{
-    /**
-     * Returns the name of the property (or public field).
-     */
-    String getName();
-
-    /**
-     * Returns true if the property is readable (i.e., has a getter method or is a public field).
-     */
-    boolean isRead();
-
-    /**
-     * Returns the method used to read the property, or null if the property is not readable (or is a public field).
-     */
-    public Method getReadMethod();
-
-    /**
-     * Returns true if the property is writeable (i.e., has a setter method or is a non-final field).
-     */
-    boolean isUpdate();
-
-    /**
-     * Returns the method used to update the property, or null if the property is not writeable (or a public field).
-     */
-    public Method getWriteMethod();
-
-    /**
-     * Reads the property value.
-     *
-     * @param instance to read from
-     * @throws UnsupportedOperationException if the property is write only
-     */
-    Object get(Object instance);
-
-    /**
-     * Updates the property value. The provided value must not be null if the property type is primitive, and must
-     * otherwise be of the proper type.
-     *
-     * @param instance to update
-     * @param value    new value for the property
-     * @throws UnsupportedOperationException if the property is read only
-     */
-    void set(Object instance, Object value);
-
-    /**
-     * Returns the type of the property.
-     */
-    Class getType();
-
-    /**
-     * Returns true if the return type of the read method is not the same as the property type. This can occur when the
-     * property has been defined using generics, in which case, the method's type may be Object when the property type
-     * is something more specific. This method is primarily used when generating runtime code related to the property.
-     */
-    boolean isCastRequired();
-
-    /**
-     * Returns the {@link org.apache.tapestry5.ioc.services.ClassPropertyAdapter} that provides access to other
-     * properties defined by the same class.
-     */
-    ClassPropertyAdapter getClassAdapter();
-
-    /**
-     * Returns the type of bean to which this property belongs. This is the same as
-     * {@link org.apache.tapestry5.ioc.services.ClassPropertyAdapter#getBeanType()}.
-     */
-    Class getBeanType();
-
-    /**
-     * Returns true if the property is actually a public field (possibly, a public static field).
-     *
-     * @since 5.2
-     */
-    boolean isField();
-
-    /**
-     * Returns the field if the property is a public field or null if the property is accessed via the read method.
-     *
-     * @since 5.2
-     */
-    Field getField();
-
-    /**
-     * The class in which the property (or public field) is defined.
-     *
-     * @since 5.2
-     */
-    Class getDeclaringClass();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java
deleted file mode 100644
index ec8eaad..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2006, 2007, 2008, 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.services;
-
-import org.apache.tapestry5.ioc.annotations.UsesConfiguration;
-
-/**
- * Makes use of {@link org.apache.tapestry5.ioc.services.Coercion}s to convert between an input value (of some specific
- * type) and a desired output type. Smart about coercing, even if it requires multiple coercion steps (i.e., via an
- * intermediate type, such as String).
- */
-@UsesConfiguration(CoercionTuple.class)
-public interface TypeCoercer
-{
-    /**
-     * Performs a coercion from an input type to a desired output type. When the target type is a primitive, the actual
-     * conversion will be to the equivalent wrapper type. In some cases, the TypeCoercer will need to search for an
-     * appropriate coercion, and may even combine existing coercions to form new ones; in those cases, the results of
-     * the search are cached.
-     * <p/>
-     * The TypeCoercer also caches the results of a coercion search.
-     * 
-     * @param <S>
-     *            source type (input)
-     * @param <T>
-     *            target type (output)
-     * @param input
-     * @param targetType
-     *            defines the target type
-     * @return the coerced value
-     * @throws RuntimeException
-     *             if the input can not be coerced
-     */
-    <S, T> T coerce(S input, Class<T> targetType);
-
-    /**
-     * Given a source and target type, computes the coercion that will be used.
-     * <p>
-     * Note: holding the returned coercion past the time when {@linkplain #clearCache() the cache is cleared} can cause
-     * a memory leak, especially in the context of live reloading (wherein holding a reference to a single class make
-     * keep an entire ClassLoader from being reclaimed).
-     * 
-     * @since 5.2.0
-     * @param <S>
-     *            source type (input)
-     * @param <T>
-     *            target type (output)
-     * @param sourceType
-     *            type to coerce from
-     * @param targetType
-     *            defines the target type
-     * @return the coercion that will ultimately be used
-     */
-    <S, T> Coercion<S, T> getCoercion(Class<S> sourceType, Class<T> targetType);
-
-    /**
-     * Used primarily inside test suites, this method performs the same steps as {@link #coerce(Object, Class)}, but
-     * returns a string describing the series of coercions, such as "Object --&gt; String --&gt; Long --&gt; Integer".
-     * 
-     * @param <S>
-     *            source type (input)
-     * @param <T>
-     *            target type (output)
-     * @param sourceType
-     *            the source coercion type (use void.class for coercions from null)
-     * @param targetType
-     *            defines the target type
-     * @return a string identifying the series of coercions, or the empty string if no coercion is necessary
-     */
-    <S, T> String explain(Class<S> sourceType, Class<T> targetType);
-
-    /**
-     * Clears cached information stored by the TypeCoercer.
-     */
-    void clearCache();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
deleted file mode 100644
index c4c5c6d..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 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.util;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-
-/**
- * Used (as part of a {@link UnknownValueException} to identify what available values
- * are present.
- * 
- * @since 5.2.0
- */
-public class AvailableValues
-{
-    private final String valueType;
-
-    private final List<String> values;
-
-    /**
-     * @param valueType
-     *            a word or phrase that describes what the values are such as "component types" or "service ids"
-     *@param values
-     *            a set of objects defining the values; the values will be converted to strings and sorted into
-     *            ascending order
-     */
-    public AvailableValues(String valueType, Collection<?> values)
-    {
-        this.valueType = valueType;
-        this.values = sortValues(values);
-    }
-
-    public AvailableValues(String valueType, Map<?, ?> map)
-    {
-        this(valueType, map.keySet());
-    }
-
-    private static List<String> sortValues(Collection<?> values)
-    {
-        List<String> result = CollectionFactory.newList();
-
-        for (Object v : values)
-        {
-            result.add(String.valueOf(v));
-        }
-
-        Collections.sort(result);
-
-        return Collections.unmodifiableList(result);
-    }
-
-    /** The type of value, i.e., "component types" or "service ids". */
-    public String getValueType()
-    {
-        return valueType;
-    }
-
-    /** The values, as strings, in sorted order. */
-    public List<String> getValues()
-    {
-        return values;
-    }
-
-    @Override
-    public String toString()
-    {
-        return String.format("AvailableValues[%s: %s]", valueType, InternalUtils.join(values));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java
deleted file mode 100644
index f5aff7e..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java
+++ /dev/null
@@ -1,499 +0,0 @@
-// Copyright 2007 The Apache Software Foundation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.apache.tapestry5.ioc.util;
-
-import java.io.Serializable;
-import java.util.*;
-
-/**
- * An mapped collection where the keys are always strings and access to values is case-insensitive. The case of keys in
- * the map is <em>maintained</em>, but on any access to a key (directly or indirectly), all key comparisons are
- * performed in a case-insensitive manner. The map implementation is intended to support a reasonably finite number
- * (dozens or hundreds, not thousands or millions of key/value pairs. Unlike HashMap, it is based on a sorted list of
- * entries rather than hash bucket. It is also geared towards a largely static map, one that is created and then used
- * without modification.
- *
- * @param <V> the type of value stored
- */
-public class CaseInsensitiveMap<V> extends AbstractMap<String, V> implements Serializable
-{
-    private static final long serialVersionUID = 3362718337611953298L;
-
-    private static final int NULL_HASH = Integer.MIN_VALUE;
-
-    private static final int DEFAULT_SIZE = 20;
-
-    private static class CIMEntry<V> implements Map.Entry<String, V>, Serializable
-    {
-        private static final long serialVersionUID = 6713986085221148350L;
-
-        private String key;
-
-        private final int hashCode;
-
-        V value;
-
-        public CIMEntry(final String key, final int hashCode, V value)
-        {
-            this.key = key;
-            this.hashCode = hashCode;
-            this.value = value;
-        }
-
-        @Override
-        public String getKey()
-        {
-            return key;
-        }
-
-        @Override
-        public V getValue()
-        {
-            return value;
-        }
-
-        @Override
-        public V setValue(V value)
-        {
-            V result = this.value;
-
-            this.value = value;
-
-            return result;
-        }
-
-        /**
-         * Returns true if both keys are null, or if the provided key is the same as, or case-insensitively equal to,
-         * the entrie's key.
-         *
-         * @param key to compare against
-         * @return true if equal
-         */
-        @SuppressWarnings({ "StringEquality" })
-        boolean matches(String key)
-        {
-            return key == this.key || (key != null && key.equalsIgnoreCase(this.key));
-        }
-
-        boolean valueMatches(Object value)
-        {
-            return value == this.value || (value != null && value.equals(this.value));
-        }
-    }
-
-    private class EntrySetIterator implements Iterator
-    {
-        int expectedModCount = modCount;
-
-        int index;
-
-        int current = -1;
-
-        @Override
-        public boolean hasNext()
-        {
-            return index < size;
-        }
-
-        @Override
-        public Object next()
-        {
-            check();
-
-            if (index >= size) throw new NoSuchElementException();
-
-            current = index++;
-
-            return entries[current];
-        }
-
-        @Override
-        public void remove()
-        {
-            check();
-
-            if (current < 0) throw new NoSuchElementException();
-
-            new Position(current, true).remove();
-
-            expectedModCount = modCount;
-        }
-
-        private void check()
-        {
-            if (expectedModCount != modCount) throw new ConcurrentModificationException();
-        }
-    }
-
-    @SuppressWarnings("unchecked")
-    private class EntrySet extends AbstractSet
-    {
-        @Override
-        public Iterator iterator()
-        {
-            return new EntrySetIterator();
-        }
-
-        @Override
-        public int size()
-        {
-            return size;
-        }
-
-        @Override
-        public void clear()
-        {
-            CaseInsensitiveMap.this.clear();
-        }
-
-        @Override
-        public boolean contains(Object o)
-        {
-            if (!(o instanceof Map.Entry)) return false;
-
-            Map.Entry e = (Map.Entry) o;
-
-            Position position = select(e.getKey());
-
-            return position.isFound() && position.entry().valueMatches(e.getValue());
-        }
-
-        @Override
-        public boolean remove(Object o)
-        {
-            if (!(o instanceof Map.Entry)) return false;
-
-            Map.Entry e = (Map.Entry) o;
-
-            Position position = select(e.getKey());
-
-            if (position.isFound() && position.entry().valueMatches(e.getValue()))
-            {
-                position.remove();
-                return true;
-            }
-
-            return false;
-        }
-
-    }
-
-    private class Position
-    {
-        private final int cursor;
-
-        private final boolean found;
-
-        Position(int cursor, boolean found)
-        {
-            this.cursor = cursor;
-            this.found = found;
-        }
-
-        boolean isFound()
-        {
-            return found;
-        }
-
-        CIMEntry<V> entry()
-        {
-            return entries[cursor];
-        }
-
-        V get()
-        {
-            return found ? entries[cursor].value : null;
-        }
-
-        V remove()
-        {
-            if (!found) return null;
-
-            V result = entries[cursor].value;
-
-            // Remove the entry by shifting everything else down.
-
-            System.arraycopy(entries, cursor + 1, entries, cursor, size - cursor - 1);
-
-            // We shifted down, leaving one (now duplicate) entry behind.
-
-            entries[--size] = null;
-
-            // A structural change for sure
-
-            modCount++;
-
-            return result;
-        }
-
-        @SuppressWarnings("unchecked")
-        V put(String key, int hashCode, V newValue)
-        {
-            if (found)
-            {
-                CIMEntry<V> e = entries[cursor];
-
-                V result = e.value;
-
-                // Not a structural change, so no change to modCount
-
-                // Update the key (to maintain case). By definition, the hash code
-                // will not change.
-
-                e.key = key;
-                e.value = newValue;
-
-                return result;
-            }
-
-            // Not found, we're going to add it.
-
-            int newSize = size + 1;
-
-            if (newSize == entries.length)
-            {
-                // Time to expand!
-
-                int newCapacity = (size * 3) / 2 + 1;
-
-                CIMEntry<V>[] newEntries = new CIMEntry[newCapacity];
-
-                System.arraycopy(entries, 0, newEntries, 0, cursor);
-
-                System.arraycopy(entries, cursor, newEntries, cursor + 1, size - cursor);
-
-                entries = newEntries;
-            }
-            else
-            {
-                // Open up a space for the new entry
-
-                System.arraycopy(entries, cursor, entries, cursor + 1, size - cursor);
-            }
-
-            CIMEntry<V> newEntry = new CIMEntry<V>(key, hashCode, newValue);
-            entries[cursor] = newEntry;
-
-            size++;
-
-            // This is definately a structural change
-
-            modCount++;
-
-            return null;
-        }
-
-    }
-
-    // The list of entries. This is kept sorted by hash code. In some cases, there may be different
-    // keys with the same hash code in adjacent indexes.
-    private CIMEntry<V>[] entries;
-
-    private int size = 0;
-
-    // Used by iterators to check for concurrent modifications
-
-    private transient int modCount = 0;
-
-    private transient Set<Map.Entry<String, V>> entrySet;
-
-    public CaseInsensitiveMap()
-    {
-        this(DEFAULT_SIZE);
-    }
-
-    @SuppressWarnings("unchecked")
-    public CaseInsensitiveMap(int size)
-    {
-        entries = new CIMEntry[Math.max(size, 3)];
-    }
-
-    public CaseInsensitiveMap(Map<String, ? extends V> map)
-    {
-        this(map.size());
-
-        for (Map.Entry<String, ? extends V> entry : map.entrySet())
-        {
-            put(entry.getKey(), entry.getValue());
-        }
-    }
-
-    @Override
-    public void clear()
-    {
-        for (int i = 0; i < size; i++)
-            entries[i] = null;
-
-        size = 0;
-        modCount++;
-    }
-
-    @Override
-    public boolean isEmpty()
-    {
-        return size == 0;
-    }
-
-    @Override
-    public int size()
-    {
-        return size;
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public V put(String key, V value)
-    {
-        int hashCode = caseInsenitiveHashCode(key);
-
-        return select(key, hashCode).put(key, hashCode, value);
-    }
-
-    @Override
-    public boolean containsKey(Object key)
-    {
-        return select(key).isFound();
-    }
-
-    @Override
-    public V get(Object key)
-    {
-        return select(key).get();
-    }
-
-    @Override
-    public V remove(Object key)
-    {
-        return select(key).remove();
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public Set<Map.Entry<String, V>> entrySet()
-    {
-        if (entrySet == null) entrySet = new EntrySet();
-
-        return entrySet;
-    }
-
-    private Position select(Object key)
-    {
-        if (key == null || key instanceof String)
-        {
-            String keyString = (String) key;
-            return select(keyString, caseInsenitiveHashCode(keyString));
-        }
-
-        return new Position(0, false);
-    }
-
-    /**
-     * Searches the elements for the index of the indicated key and (case insensitive) hash code. Sets the _cursor and
-     * _found attributes.
-     */
-    private Position select(String key, int hashCode)
-    {
-        if (size == 0) return new Position(0, false);
-
-        int low = 0;
-        int high = size - 1;
-
-        int cursor;
-
-        while (low <= high)
-        {
-            cursor = (low + high) >> 1;
-
-            CIMEntry e = entries[cursor];
-
-            if (e.hashCode < hashCode)
-            {
-                low = cursor + 1;
-                continue;
-            }
-
-            if (e.hashCode > hashCode)
-            {
-                high = cursor - 1;
-                continue;
-            }
-
-            return tunePosition(key, hashCode, cursor);
-        }
-
-        return new Position(low, false);
-    }
-
-    /**
-     * select() has located a matching hashCode, but there's an outlying possibility that multiple keys share the same
-     * hashCode. Backup the cursor until we get to locate the initial hashCode match, then march forward until the key
-     * is located, or the hashCode stops matching.
-     *
-     * @param key
-     * @param hashCode
-     */
-    private Position tunePosition(String key, int hashCode, int cursor)
-    {
-        boolean found = false;
-
-        while (cursor > 0)
-        {
-            if (entries[cursor - 1].hashCode != hashCode) break;
-
-            cursor--;
-        }
-
-        while (true)
-        {
-            if (entries[cursor].matches(key))
-            {
-                found = true;
-                break;
-            }
-
-            // Advance to the next entry.
-
-            cursor++;
-
-            // If out of entries,
-            if (cursor >= size || entries[cursor].hashCode != hashCode) break;
-        }
-
-        return new Position(cursor, found);
-    }
-
-    static int caseInsenitiveHashCode(String input)
-    {
-        if (input == null) return NULL_HASH;
-
-        int length = input.length();
-        int hash = 0;
-
-        // This should end up more or less equal to input.toLowerCase().hashCode(), unless String
-        // changes its implementation. Let's hope this is reasonably fast.
-
-        for (int i = 0; i < length; i++)
-        {
-            int ch = input.charAt(i);
-
-            int caselessCh = Character.toLowerCase(ch);
-
-            hash = 31 * hash + caselessCh;
-        }
-
-        return hash;
-    }
-
-}


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

Posted by th...@apache.org.
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/eb7ec86e
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/eb7ec86e
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/eb7ec86e

Branch: refs/heads/beanmodel-split
Commit: eb7ec86e3368e4a4e20d88c8f009d88fd1d37740
Parents: dd95846
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 19:45:14 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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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);
+    }
+}


[10/15] tapestry-5 git commit: Third pass creating the BeanModel and Commons packages.

Posted by th...@apache.org.
Third 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/dd958465
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/dd958465
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/dd958465

Branch: refs/heads/beanmodel-split
Commit: dd9584659823c87f014a1cf57c7be592eedfa4c6
Parents: c9e97d6
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Sat Dec 6 17:33:54 2014 -0200
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Sat Dec 6 17:33:54 2014 -0200

----------------------------------------------------------------------
 .../tapestry5/internal/BeanModelUtils.java      | 145 ------------
 .../internal/InternalBeanModelUtils.java        | 145 ++++++++++++
 .../internal/beaneditor/BeanModelUtils.java     | 120 ++++++++++
 .../internal/beaneditor/PropertyModelImpl.java  |   6 +-
 .../internal/services/BeanModelSourceImpl.java  | 222 +++++++++++++++++++
 .../services/PropertyConduitSourceImpl.java     |   4 +-
 .../tapestry5/services/DataTypeAnalyzer.java    |  48 ++++
 .../internal/TapestryInternalUtils.java         |   8 +-
 .../internal/beaneditor/BeanModelUtils.java     | 119 ----------
 .../internal/services/BeanModelSourceImpl.java  | 222 -------------------
 .../tapestry5/services/DataTypeAnalyzer.java    |  48 ----
 .../annotations/UsesMappedConfiguration.java    |  41 ----
 .../annotations/UsesOrderedConfiguration.java   |  33 ---
 .../ioc/internal/util/InternalUtils.java        |   6 +-
 .../annotations/UsesMappedConfiguration.java    |  41 ++++
 .../annotations/UsesOrderedConfiguration.java   |  33 +++
 16 files changed, 621 insertions(+), 620 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java
deleted file mode 100644
index 08cb88a..0000000
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.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 BeanModelUtils {
-	
-	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/dd958465/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
new file mode 100644
index 0000000..88f4c7f
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalBeanModelUtils.java
@@ -0,0 +1,145 @@
+// 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/dd958465/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
new file mode 100644
index 0000000..154ee79
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
@@ -0,0 +1,120 @@
+// Copyright 2007, 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.internal.beaneditor;
+
+import org.apache.tapestry5.beaneditor.BeanModel;
+import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
+
+/**
+ * Utilities used in a few places to modify an existing {@link BeanModel}.
+ */
+public final class BeanModelUtils
+{
+
+    final private static String[] EMPTY_STRING_ARRAY = new String[0];
+
+    /**
+     * Performs standard set of modifications to a {@link org.apache.tapestry5.beaneditor.BeanModel}
+     * . First new
+     * properties may be added, then properties removed, then properties reordered.
+     *
+     * @param model                to modifiy
+     * @param addPropertyNames     comma seperated list of property names to add, or null
+     * @param includePropertyNames comma seperated list of property names to include
+     * @param excludePropertyNames comma seperated list of property names to exclude, or null
+     * @param reorderPropertyNames comma seperated list of property names to reorder, or null
+     */
+    public static void modify(BeanModel model, String addPropertyNames,
+                              String includePropertyNames, String excludePropertyNames, String reorderPropertyNames)
+    {
+        if (addPropertyNames != null)
+            add(model, addPropertyNames);
+
+        if (includePropertyNames != null)
+            include(model, join(includePropertyNames, addPropertyNames));
+
+        if (excludePropertyNames != null)
+            exclude(model, excludePropertyNames);
+
+        if (reorderPropertyNames != null)
+            reorder(model, reorderPropertyNames);
+    }
+
+    private static final String join(String firstList, String optionalSecondList)
+    {
+        if (InternalStringUtils.isBlank(optionalSecondList))
+            return firstList;
+
+        return firstList + "," + optionalSecondList;
+    }
+
+    /**
+     * Adds empty properties to the bean model. New properties are added with a <em>null</em>
+     * {@link org.apache.tapestry5.PropertyConduit}. `
+     *
+     * @param model         to be modified
+     * @param propertyNames comma-separated list of property names
+     * @see BeanModel#addEmpty(String)
+     */
+    public static void add(BeanModel model, String propertyNames)
+    {
+        for (String name : split(propertyNames))
+        {
+            model.addEmpty(name);
+        }
+    }
+
+    /**
+     * Removes properties from the bean model.
+     *
+     * @param model
+     * @param propertyNames comma-separated list of property names
+     * @see BeanModel#exclude(String...)
+     */
+    public static void exclude(BeanModel model, String propertyNames)
+    {
+        model.exclude(split(propertyNames));
+    }
+
+    /**
+     * Selects a subset of the properties to keep, and reorders them.
+     */
+    public static void include(BeanModel model, String propertyNames)
+    {
+        model.include(split(propertyNames));
+    }
+
+    /**
+     * Reorders properties within the bean model.
+     *
+     * @param model
+     * @param propertyNames comma-separated list of property names
+     * @see BeanModel#reorder(String...)
+     */
+    public static void reorder(BeanModel model, String propertyNames)
+    {
+        model.reorder(split(propertyNames));
+    }
+    
+    static String[] split(String propertyNames)
+    {
+        String trimmed = propertyNames.trim();
+
+        if (trimmed.length() == 0)
+            return EMPTY_STRING_ARRAY;
+
+        return trimmed.split("\\s*,\\s*");
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/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 b21e5bb..4632818 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,7 +20,7 @@ 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.BeanModelUtils;
+import org.apache.tapestry5.internal.InternalBeanModelUtils;
 import org.apache.tapestry5.ioc.Messages;
 import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
 import org.apache.tapestry5.plastic.PlasticUtils;
@@ -48,9 +48,9 @@ public class PropertyModelImpl implements PropertyModel
         this.name = name;
         this.conduit = conduit;
 
-        id = BeanModelUtils.extractIdFromPropertyExpression(name);
+        id = InternalBeanModelUtils.extractIdFromPropertyExpression(name);
 
-        label = BeanModelUtils.defaultLabel(id, messages, name);
+        label = InternalBeanModelUtils.defaultLabel(id, messages, name);
 
         // TAP5-2305
         if (conduit != null)

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/beanmodel/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java
new file mode 100644
index 0000000..bb20de0
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java
@@ -0,0 +1,222 @@
+// Copyright 2007, 2008, 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.internal.services;
+
+import org.apache.tapestry5.beaneditor.BeanModel;
+import org.apache.tapestry5.beaneditor.NonVisual;
+import org.apache.tapestry5.beaneditor.ReorderProperties;
+import org.apache.tapestry5.internal.beaneditor.BeanModelImpl;
+import org.apache.tapestry5.internal.beaneditor.BeanModelUtils;
+import org.apache.tapestry5.ioc.Location;
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.ObjectLocator;
+import org.apache.tapestry5.ioc.annotations.Primary;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.services.*;
+import org.apache.tapestry5.services.BeanModelSource;
+import org.apache.tapestry5.services.ComponentLayer;
+import org.apache.tapestry5.services.DataTypeAnalyzer;
+import org.apache.tapestry5.services.PropertyConduitSource;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Collections;
+import java.util.List;
+
+public class BeanModelSourceImpl implements BeanModelSource
+{
+    private final TypeCoercer typeCoercer;
+
+    private final PropertyAccess propertyAccess;
+
+    private final PropertyConduitSource propertyConduitSource;
+
+    private final PlasticProxyFactory proxyFactory;
+
+    private final DataTypeAnalyzer dataTypeAnalyzer;
+
+    private final ObjectLocator locator;
+
+    private static class PropertyOrder implements Comparable<PropertyOrder>
+    {
+        final String propertyName;
+
+        final int classDepth;
+
+        final int sortKey;
+
+        public PropertyOrder(final String propertyName, int classDepth, int sortKey)
+        {
+            this.propertyName = propertyName;
+            this.classDepth = classDepth;
+            this.sortKey = sortKey;
+        }
+
+        public int compareTo(PropertyOrder o)
+        {
+            int result = classDepth - o.classDepth;
+
+            if (result == 0)
+                result = sortKey - o.sortKey;
+
+            if (result == 0)
+                result = propertyName.compareTo(o.propertyName);
+
+            return result;
+        }
+    }
+
+    /**
+     * @param classAdapter  defines the bean that contains the properties
+     * @param propertyNames the initial set of property names, which will be rebuilt in the correct order
+     */
+    private void orderProperties(ClassPropertyAdapter classAdapter, List<String> propertyNames)
+    {
+        List<PropertyOrder> properties = CollectionFactory.newList();
+
+        for (String name : propertyNames)
+        {
+            PropertyAdapter pa = classAdapter.getPropertyAdapter(name);
+
+            Method readMethod = pa.getReadMethod();
+
+            Location location = readMethod == null ? null : proxyFactory.getMethodLocation(readMethod);
+
+            int line = location == null ? -1 : location.getLine();
+
+            properties.add(new PropertyOrder(name, computeDepth(pa), line));
+        }
+
+        Collections.sort(properties);
+
+        propertyNames.clear();
+
+        for (PropertyOrder po : properties)
+        {
+            propertyNames.add(po.propertyName);
+        }
+    }
+
+    private static int computeDepth(PropertyAdapter pa)
+    {
+        int depth = 0;
+        Class c = pa.getDeclaringClass();
+
+        // When the method originates in an interface, the parent may be null, not Object.
+
+        while (c != null && c != Object.class)
+        {
+            depth++;
+            c = c.getSuperclass();
+        }
+
+        return depth;
+    }
+
+    public BeanModelSourceImpl(TypeCoercer typeCoercer, PropertyAccess propertyAccess,
+                               PropertyConduitSource propertyConduitSource,
+                               @ComponentLayer
+                               PlasticProxyFactory proxyFactory,
+                               @Primary
+                               DataTypeAnalyzer dataTypeAnalyzer, ObjectLocator locator)
+    {
+        this.typeCoercer = typeCoercer;
+        this.propertyAccess = propertyAccess;
+        this.propertyConduitSource = propertyConduitSource;
+        this.proxyFactory = proxyFactory;
+        this.dataTypeAnalyzer = dataTypeAnalyzer;
+        this.locator = locator;
+    }
+
+    public <T> BeanModel<T> createDisplayModel(Class<T> beanClass, Messages messages)
+    {
+        return create(beanClass, false, messages);
+    }
+
+    public <T> BeanModel<T> createEditModel(Class<T> beanClass, Messages messages)
+    {
+        return create(beanClass, true, messages);
+    }
+
+    public <T> BeanModel<T> create(Class<T> beanClass, boolean filterReadOnlyProperties, Messages messages)
+    {
+        assert beanClass != null;
+        assert messages != null;
+        ClassPropertyAdapter adapter = propertyAccess.getAdapter(beanClass);
+
+        BeanModel<T> model = new BeanModelImpl<T>(beanClass, propertyConduitSource, typeCoercer, messages, locator);
+
+        for (final String propertyName : adapter.getPropertyNames())
+        {
+            PropertyAdapter pa = adapter.getPropertyAdapter(propertyName);
+
+            if (!pa.isRead())
+            {
+                continue;
+            }
+
+            if (isStaticFieldProperty(pa))
+            {
+                continue;
+            }
+
+            if (pa.getAnnotation(NonVisual.class) != null)
+            {
+                continue;
+            }
+
+            if (filterReadOnlyProperties && !pa.isUpdate())
+            {
+                continue;
+            }
+
+            final String dataType = dataTypeAnalyzer.identifyDataType(pa);
+
+            // If an unregistered type, then ignore the property.
+
+            if (dataType == null)
+            {
+                continue;
+            }
+
+            model.add(propertyName).dataType(dataType);
+        }
+
+        // First, order the properties based on the location of the getter method
+        // within the class.
+
+        List<String> propertyNames = model.getPropertyNames();
+
+        orderProperties(adapter, propertyNames);
+
+        model.reorder(propertyNames.toArray(new String[propertyNames.size()]));
+
+        // Next, check for an annotation with specific ordering information.
+
+        ReorderProperties reorderAnnotation = beanClass.getAnnotation(ReorderProperties.class);
+
+        if (reorderAnnotation != null)
+        {
+            BeanModelUtils.reorder(model, reorderAnnotation.value());
+        }
+
+        return model;
+    }
+
+    private boolean isStaticFieldProperty(PropertyAdapter adapter)
+    {
+        return adapter.isField() && Modifier.isStatic(adapter.getField().getModifiers());
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/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 83f67fa..4ce072e 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,7 @@ 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.BeanModelUtils;
+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;
@@ -1260,7 +1260,7 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
 
             Type returnType = GenericsUtils.extractActualType(activeType, method);
 
-            return new Term(returnType, toUniqueId(method), BeanModelUtils.toAnnotationProvider(method), new InstructionBuilderCallback()
+            return new Term(returnType, toUniqueId(method), InternalBeanModelUtils.toAnnotationProvider(method), new InstructionBuilderCallback()
             {
                 public void doBuild(InstructionBuilder builder)
                 {

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/commons/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java b/commons/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java
new file mode 100644
index 0000000..ba7e995
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java
@@ -0,0 +1,48 @@
+// Copyright 2007, 2008, 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.services;
+
+import org.apache.tapestry5.ioc.annotations.UsesMappedConfiguration;
+import org.apache.tapestry5.ioc.annotations.UsesOrderedConfiguration;
+import org.apache.tapestry5.ioc.services.PropertyAdapter;
+
+/**
+ * Used by {@link BeanModelSource} to identify the type of data associated with a particular property (represented as a
+ * {@link PropertyAdapter}). The data type is a string used to determine what kind of interface to use for displaying
+ * the value of the property, or what kind of interface to use for editing the value of the property. Common property
+ * types are "text", "enum", "checkbox", but the list is extensible.
+ * <p/>
+ * Different strategies for identifying the data type are encapsulated in the DataTypeAnalyzer service, forming a
+ * chain of command.
+ * <p/>
+ * The DefaultDataTypeAnalyzer service maps property types to data type names.
+ * <p/>
+ * The DataTypeAnalyzer service is an extensible {@linkplain org.apache.tapestry5.ioc.services.ChainBuilder chain of
+ * command}), that (by default) includes {@link org.apache.tapestry5.internal.services.AnnotationDataTypeAnalyzer} and
+ * the {@link org.apache.tapestry5.internal.services.DefaultDataTypeAnalyzer} service (ordered last).   It uses an ordered configuration.
+ *
+ * @see org.apache.tapestry5.corelib.components.Grid
+ * @see org.apache.tapestry5.corelib.components.BeanEditForm
+ * @see BeanBlockSource
+ */
+@UsesOrderedConfiguration(DataTypeAnalyzer.class)
+@UsesMappedConfiguration(key = Class.class, value = String.class)
+public interface DataTypeAnalyzer
+{
+    /**
+     * Identifies the data type, if known, or returns null if not known.
+     */
+    String identifyDataType(PropertyAdapter adapter);
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
index aba7225..e69377f 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
@@ -59,7 +59,7 @@ public class TapestryInternalUtils
      */
     public static String toUserPresentable(String id)
     {
-        return BeanModelUtils.toUserPresentable(id);
+        return InternalBeanModelUtils.toUserPresentable(id);
     }
 
     public static Map<String, String> mapFromKeysAndValues(String... keysAndValues)
@@ -228,7 +228,7 @@ public class TapestryInternalUtils
      */
     public static String extractIdFromPropertyExpression(String expression)
     {
-        return BeanModelUtils.extractIdFromPropertyExpression(expression);
+        return InternalBeanModelUtils.extractIdFromPropertyExpression(expression);
     }
 
     /**
@@ -237,7 +237,7 @@ public class TapestryInternalUtils
      */
     public static String defaultLabel(String id, Messages messages, String propertyExpression)
     {
-        return BeanModelUtils.defaultLabel(id, messages, propertyExpression);
+        return InternalBeanModelUtils.defaultLabel(id, messages, propertyExpression);
     }
 
     /**
@@ -304,7 +304,7 @@ public class TapestryInternalUtils
 
     private static String replace(String input, Pattern pattern, String replacement)
     {
-        return BeanModelUtils.replace(input, pattern, replacement);
+        return InternalBeanModelUtils.replace(input, pattern, replacement);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
deleted file mode 100644
index 6a79b6e..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2007, 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.internal.beaneditor;
-
-import org.apache.tapestry5.beaneditor.BeanModel;
-import org.apache.tapestry5.internal.InternalConstants;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-
-/**
- * Utilities used in a few places to modify an existing {@link BeanModel}.
- */
-public final class BeanModelUtils
-{
-
-    /**
-     * Performs standard set of modifications to a {@link org.apache.tapestry5.beaneditor.BeanModel}
-     * . First new
-     * properties may be added, then properties removed, then properties reordered.
-     *
-     * @param model                to modifiy
-     * @param addPropertyNames     comma seperated list of property names to add, or null
-     * @param includePropertyNames comma seperated list of property names to include
-     * @param excludePropertyNames comma seperated list of property names to exclude, or null
-     * @param reorderPropertyNames comma seperated list of property names to reorder, or null
-     */
-    public static void modify(BeanModel model, String addPropertyNames,
-                              String includePropertyNames, String excludePropertyNames, String reorderPropertyNames)
-    {
-        if (addPropertyNames != null)
-            add(model, addPropertyNames);
-
-        if (includePropertyNames != null)
-            include(model, join(includePropertyNames, addPropertyNames));
-
-        if (excludePropertyNames != null)
-            exclude(model, excludePropertyNames);
-
-        if (reorderPropertyNames != null)
-            reorder(model, reorderPropertyNames);
-    }
-
-    private static final String join(String firstList, String optionalSecondList)
-    {
-        if (InternalUtils.isBlank(optionalSecondList))
-            return firstList;
-
-        return firstList + "," + optionalSecondList;
-    }
-
-    /**
-     * Adds empty properties to the bean model. New properties are added with a <em>null</em>
-     * {@link org.apache.tapestry5.PropertyConduit}. `
-     *
-     * @param model         to be modified
-     * @param propertyNames comma-separated list of property names
-     * @see BeanModel#addEmpty(String)
-     */
-    public static void add(BeanModel model, String propertyNames)
-    {
-        for (String name : split(propertyNames))
-        {
-            model.addEmpty(name);
-        }
-    }
-
-    /**
-     * Removes properties from the bean model.
-     *
-     * @param model
-     * @param propertyNames comma-separated list of property names
-     * @see BeanModel#exclude(String...)
-     */
-    public static void exclude(BeanModel model, String propertyNames)
-    {
-        model.exclude(split(propertyNames));
-    }
-
-    /**
-     * Selects a subset of the properties to keep, and reorders them.
-     */
-    public static void include(BeanModel model, String propertyNames)
-    {
-        model.include(split(propertyNames));
-    }
-
-    /**
-     * Reorders properties within the bean model.
-     *
-     * @param model
-     * @param propertyNames comma-separated list of property names
-     * @see BeanModel#reorder(String...)
-     */
-    public static void reorder(BeanModel model, String propertyNames)
-    {
-        model.reorder(split(propertyNames));
-    }
-
-    static String[] split(String propertyNames)
-    {
-        String trimmed = propertyNames.trim();
-
-        if (trimmed.length() == 0)
-            return InternalConstants.EMPTY_STRING_ARRAY;
-
-        return trimmed.split("\\s*,\\s*");
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java
deleted file mode 100644
index bb20de0..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java
+++ /dev/null
@@ -1,222 +0,0 @@
-// Copyright 2007, 2008, 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.internal.services;
-
-import org.apache.tapestry5.beaneditor.BeanModel;
-import org.apache.tapestry5.beaneditor.NonVisual;
-import org.apache.tapestry5.beaneditor.ReorderProperties;
-import org.apache.tapestry5.internal.beaneditor.BeanModelImpl;
-import org.apache.tapestry5.internal.beaneditor.BeanModelUtils;
-import org.apache.tapestry5.ioc.Location;
-import org.apache.tapestry5.ioc.Messages;
-import org.apache.tapestry5.ioc.ObjectLocator;
-import org.apache.tapestry5.ioc.annotations.Primary;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.services.*;
-import org.apache.tapestry5.services.BeanModelSource;
-import org.apache.tapestry5.services.ComponentLayer;
-import org.apache.tapestry5.services.DataTypeAnalyzer;
-import org.apache.tapestry5.services.PropertyConduitSource;
-
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Collections;
-import java.util.List;
-
-public class BeanModelSourceImpl implements BeanModelSource
-{
-    private final TypeCoercer typeCoercer;
-
-    private final PropertyAccess propertyAccess;
-
-    private final PropertyConduitSource propertyConduitSource;
-
-    private final PlasticProxyFactory proxyFactory;
-
-    private final DataTypeAnalyzer dataTypeAnalyzer;
-
-    private final ObjectLocator locator;
-
-    private static class PropertyOrder implements Comparable<PropertyOrder>
-    {
-        final String propertyName;
-
-        final int classDepth;
-
-        final int sortKey;
-
-        public PropertyOrder(final String propertyName, int classDepth, int sortKey)
-        {
-            this.propertyName = propertyName;
-            this.classDepth = classDepth;
-            this.sortKey = sortKey;
-        }
-
-        public int compareTo(PropertyOrder o)
-        {
-            int result = classDepth - o.classDepth;
-
-            if (result == 0)
-                result = sortKey - o.sortKey;
-
-            if (result == 0)
-                result = propertyName.compareTo(o.propertyName);
-
-            return result;
-        }
-    }
-
-    /**
-     * @param classAdapter  defines the bean that contains the properties
-     * @param propertyNames the initial set of property names, which will be rebuilt in the correct order
-     */
-    private void orderProperties(ClassPropertyAdapter classAdapter, List<String> propertyNames)
-    {
-        List<PropertyOrder> properties = CollectionFactory.newList();
-
-        for (String name : propertyNames)
-        {
-            PropertyAdapter pa = classAdapter.getPropertyAdapter(name);
-
-            Method readMethod = pa.getReadMethod();
-
-            Location location = readMethod == null ? null : proxyFactory.getMethodLocation(readMethod);
-
-            int line = location == null ? -1 : location.getLine();
-
-            properties.add(new PropertyOrder(name, computeDepth(pa), line));
-        }
-
-        Collections.sort(properties);
-
-        propertyNames.clear();
-
-        for (PropertyOrder po : properties)
-        {
-            propertyNames.add(po.propertyName);
-        }
-    }
-
-    private static int computeDepth(PropertyAdapter pa)
-    {
-        int depth = 0;
-        Class c = pa.getDeclaringClass();
-
-        // When the method originates in an interface, the parent may be null, not Object.
-
-        while (c != null && c != Object.class)
-        {
-            depth++;
-            c = c.getSuperclass();
-        }
-
-        return depth;
-    }
-
-    public BeanModelSourceImpl(TypeCoercer typeCoercer, PropertyAccess propertyAccess,
-                               PropertyConduitSource propertyConduitSource,
-                               @ComponentLayer
-                               PlasticProxyFactory proxyFactory,
-                               @Primary
-                               DataTypeAnalyzer dataTypeAnalyzer, ObjectLocator locator)
-    {
-        this.typeCoercer = typeCoercer;
-        this.propertyAccess = propertyAccess;
-        this.propertyConduitSource = propertyConduitSource;
-        this.proxyFactory = proxyFactory;
-        this.dataTypeAnalyzer = dataTypeAnalyzer;
-        this.locator = locator;
-    }
-
-    public <T> BeanModel<T> createDisplayModel(Class<T> beanClass, Messages messages)
-    {
-        return create(beanClass, false, messages);
-    }
-
-    public <T> BeanModel<T> createEditModel(Class<T> beanClass, Messages messages)
-    {
-        return create(beanClass, true, messages);
-    }
-
-    public <T> BeanModel<T> create(Class<T> beanClass, boolean filterReadOnlyProperties, Messages messages)
-    {
-        assert beanClass != null;
-        assert messages != null;
-        ClassPropertyAdapter adapter = propertyAccess.getAdapter(beanClass);
-
-        BeanModel<T> model = new BeanModelImpl<T>(beanClass, propertyConduitSource, typeCoercer, messages, locator);
-
-        for (final String propertyName : adapter.getPropertyNames())
-        {
-            PropertyAdapter pa = adapter.getPropertyAdapter(propertyName);
-
-            if (!pa.isRead())
-            {
-                continue;
-            }
-
-            if (isStaticFieldProperty(pa))
-            {
-                continue;
-            }
-
-            if (pa.getAnnotation(NonVisual.class) != null)
-            {
-                continue;
-            }
-
-            if (filterReadOnlyProperties && !pa.isUpdate())
-            {
-                continue;
-            }
-
-            final String dataType = dataTypeAnalyzer.identifyDataType(pa);
-
-            // If an unregistered type, then ignore the property.
-
-            if (dataType == null)
-            {
-                continue;
-            }
-
-            model.add(propertyName).dataType(dataType);
-        }
-
-        // First, order the properties based on the location of the getter method
-        // within the class.
-
-        List<String> propertyNames = model.getPropertyNames();
-
-        orderProperties(adapter, propertyNames);
-
-        model.reorder(propertyNames.toArray(new String[propertyNames.size()]));
-
-        // Next, check for an annotation with specific ordering information.
-
-        ReorderProperties reorderAnnotation = beanClass.getAnnotation(ReorderProperties.class);
-
-        if (reorderAnnotation != null)
-        {
-            BeanModelUtils.reorder(model, reorderAnnotation.value());
-        }
-
-        return model;
-    }
-
-    private boolean isStaticFieldProperty(PropertyAdapter adapter)
-    {
-        return adapter.isField() && Modifier.isStatic(adapter.getField().getModifiers());
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry-core/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java
deleted file mode 100644
index ba7e995..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2007, 2008, 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.services;
-
-import org.apache.tapestry5.ioc.annotations.UsesMappedConfiguration;
-import org.apache.tapestry5.ioc.annotations.UsesOrderedConfiguration;
-import org.apache.tapestry5.ioc.services.PropertyAdapter;
-
-/**
- * Used by {@link BeanModelSource} to identify the type of data associated with a particular property (represented as a
- * {@link PropertyAdapter}). The data type is a string used to determine what kind of interface to use for displaying
- * the value of the property, or what kind of interface to use for editing the value of the property. Common property
- * types are "text", "enum", "checkbox", but the list is extensible.
- * <p/>
- * Different strategies for identifying the data type are encapsulated in the DataTypeAnalyzer service, forming a
- * chain of command.
- * <p/>
- * The DefaultDataTypeAnalyzer service maps property types to data type names.
- * <p/>
- * The DataTypeAnalyzer service is an extensible {@linkplain org.apache.tapestry5.ioc.services.ChainBuilder chain of
- * command}), that (by default) includes {@link org.apache.tapestry5.internal.services.AnnotationDataTypeAnalyzer} and
- * the {@link org.apache.tapestry5.internal.services.DefaultDataTypeAnalyzer} service (ordered last).   It uses an ordered configuration.
- *
- * @see org.apache.tapestry5.corelib.components.Grid
- * @see org.apache.tapestry5.corelib.components.BeanEditForm
- * @see BeanBlockSource
- */
-@UsesOrderedConfiguration(DataTypeAnalyzer.class)
-@UsesMappedConfiguration(key = Class.class, value = String.class)
-public interface DataTypeAnalyzer
-{
-    /**
-     * Identifies the data type, if known, or returns null if not known.
-     */
-    String identifyDataType(PropertyAdapter adapter);
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java
deleted file mode 100644
index a336365..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java
+++ /dev/null
@@ -1,41 +0,0 @@
-//  Copyright 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.annotations;
-
-import java.lang.annotation.*;
-
-/**
- * A documentation-only interface placed on service interfaces for services which have a {@linkplain
- * org.apache.tapestry5.ioc.MappedConfiguration mapped configuration}, to identify the type of key (often, a String),
- * and type ofcontribution.
- * <p/>
- * Remember that when the key type is String, the map will be case-insensitive.
- */
-@Target(ElementType.TYPE)
-@Retention(RetentionPolicy.CLASS)
-@Documented
-@UseWith(AnnotationUseContext.SERVICE)
-public @interface UsesMappedConfiguration
-{
-    /**
-     * The type of key used to identify contribution values.
-     */
-    Class key() default String.class;
-
-    /**
-     * The type of object which may be contributed into the service's configuration.
-     */
-    Class value();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java
deleted file mode 100644
index 7c608f6..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java
+++ /dev/null
@@ -1,33 +0,0 @@
-//  Copyright 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.annotations;
-
-import java.lang.annotation.*;
-
-/**
- * A documentation-only interface placed on service interfaces for services which have an {@linkplain
- * org.apache.tapestry5.ioc.OrderedConfiguration ordered configuration}, to identify the type of contribution.
- */
-@Target(ElementType.TYPE)
-@Retention(RetentionPolicy.CLASS)
-@Documented
-@UseWith(AnnotationUseContext.SERVICE)
-public @interface UsesOrderedConfiguration
-{
-    /**
-     * The type of object which may be contributed into the service's configuration.
-     */
-    Class value();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
index a40f984..8f1f7b6 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
@@ -17,7 +17,7 @@ package org.apache.tapestry5.ioc.internal.util;
 import org.apache.tapestry5.func.F;
 import org.apache.tapestry5.func.Mapper;
 import org.apache.tapestry5.func.Predicate;
-import org.apache.tapestry5.internal.BeanModelUtils;
+import org.apache.tapestry5.internal.InternalBeanModelUtils;
 import org.apache.tapestry5.internal.plastic.PlasticInternalUtils;
 import org.apache.tapestry5.ioc.*;
 import org.apache.tapestry5.ioc.annotations.*;
@@ -777,7 +777,7 @@ public class InternalUtils
      */
     public static AnnotationProvider toAnnotationProvider(final Class element)
     {
-        return BeanModelUtils.toAnnotationProvider(element);
+        return InternalBeanModelUtils.toAnnotationProvider(element);
     }
 
     /**
@@ -1404,7 +1404,7 @@ public class InternalUtils
 
     public static AnnotationProvider toAnnotationProvider(final Method element)
     {
-        return BeanModelUtils.toAnnotationProvider(element);
+        return InternalBeanModelUtils.toAnnotationProvider(element);
     }
 
     public static <T> ObjectCreator<T> createConstructorConstructionPlan(final OperationTracker tracker, final ObjectLocator locator,

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java b/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java
new file mode 100644
index 0000000..a336365
--- /dev/null
+++ b/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java
@@ -0,0 +1,41 @@
+//  Copyright 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.annotations;
+
+import java.lang.annotation.*;
+
+/**
+ * A documentation-only interface placed on service interfaces for services which have a {@linkplain
+ * org.apache.tapestry5.ioc.MappedConfiguration mapped configuration}, to identify the type of key (often, a String),
+ * and type ofcontribution.
+ * <p/>
+ * Remember that when the key type is String, the map will be case-insensitive.
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.CLASS)
+@Documented
+@UseWith(AnnotationUseContext.SERVICE)
+public @interface UsesMappedConfiguration
+{
+    /**
+     * The type of key used to identify contribution values.
+     */
+    Class key() default String.class;
+
+    /**
+     * The type of object which may be contributed into the service's configuration.
+     */
+    Class value();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java b/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java
new file mode 100644
index 0000000..7c608f6
--- /dev/null
+++ b/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java
@@ -0,0 +1,33 @@
+//  Copyright 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.annotations;
+
+import java.lang.annotation.*;
+
+/**
+ * A documentation-only interface placed on service interfaces for services which have an {@linkplain
+ * org.apache.tapestry5.ioc.OrderedConfiguration ordered configuration}, to identify the type of contribution.
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.CLASS)
+@Documented
+@UseWith(AnnotationUseContext.SERVICE)
+public @interface UsesOrderedConfiguration
+{
+    /**
+     * The type of object which may be contributed into the service's configuration.
+     */
+    Class value();
+}


[15/15] tapestry-5 git commit: Fifth pass creating the BeanModel and Commons packages. Initial testing looks good.

Posted by th...@apache.org.
Fifth pass creating the BeanModel and Commons packages. Initial testing looks good.


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

Branch: refs/heads/beanmodel-split
Commit: 696bc7ae848f4b4f2421ff77ceb4858a2f10465c
Parents: eb7ec86
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Sat Dec 6 20:29:20 2014 -0200
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Sat Dec 6 20:29:20 2014 -0200

----------------------------------------------------------------------
 .../org/apache/tapestry5/PropertyConduit2.java  |   2 +-
 .../beaneditor/BeanModelSourceBuilder.java      | 159 ++---
 .../CoercingPropertyConduitWrapper.java         |   8 +-
 .../services/LiteralPropertyConduit.java        |   2 +-
 .../services/PropertyConduitSourceImpl.java     |  46 +-
 .../services/ClassPropertyAdapterImpl.java      |  92 +--
 .../services/AnnotationDataTypeAnalyzer.java    |  32 +
 .../ioc/internal/BasicDataTypeAnalyzers.java    | 151 +++++
 .../ioc/internal/util/InternalCommonsUtils.java | 608 +++++++++----------
 .../internal/TapestryInternalUtils.java         |   4 +-
 .../internal/bindings/AbstractBinding.java      |   2 +-
 .../internal/bindings/PropBinding.java          |   8 +-
 .../services/AnnotationDataTypeAnalyzer.java    |  32 -
 .../InternalComponentResourcesImpl.java         |   4 +-
 .../tapestry5/modules/TapestryModule.java       |  14 +-
 .../app1/components/GenericTypeDisplay.java     |  34 +-
 .../integration/app1/pages/GenericTypeDemo.java |  24 +-
 .../pages/GridWithSubmitWithContextDemo.java    |   4 +-
 .../integration/app2/base/ChildBasePage.java    |   8 +-
 .../integration/app2/base/ParentBasePage.java   |   2 +-
 .../pagelevel/OverrideMethodsTest.java          |  14 +-
 .../services/PropertyConduitSourceImplTest.java |  34 +-
 .../org/apache/tapestry5/json/JSONArray.java    |   2 +-
 .../org/apache/tapestry5/json/JSONObject.java   |   2 +-
 24 files changed, 723 insertions(+), 565 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit2.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit2.java b/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit2.java
index 839d70f..1577a3d 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit2.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit2.java
@@ -36,5 +36,5 @@ public interface PropertyConduit2 extends PropertyConduit
      * @see java.lang.reflect.Field#getGenericType()
      * 
      */
-	Type getPropertyGenericType();
+    Type getPropertyGenericType();
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/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
index 8cef66e..4ac3373 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModelSourceBuilder.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModelSourceBuilder.java
@@ -15,15 +15,22 @@ package org.apache.tapestry5.beaneditor;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
 
 import javax.naming.OperationNotSupportedException;
+import javax.swing.JFrame;
 
 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.MessageFormatter;
+import org.apache.tapestry5.ioc.Messages;
 import org.apache.tapestry5.ioc.ObjectLocator;
+import org.apache.tapestry5.ioc.internal.BasicDataTypeAnalyzers;
 import org.apache.tapestry5.ioc.internal.BasicTypeCoercions;
 import org.apache.tapestry5.ioc.internal.services.PlasticProxyFactoryImpl;
 import org.apache.tapestry5.ioc.internal.services.PropertyAccessImpl;
@@ -31,6 +38,7 @@ 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.PropertyAdapter;
 import org.apache.tapestry5.ioc.services.TypeCoercer;
 import org.apache.tapestry5.services.BeanModelSource;
 import org.apache.tapestry5.services.DataTypeAnalyzer;
@@ -42,80 +50,89 @@ import org.slf4j.LoggerFactory;
  * 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;
-	}
+    private TypeCoercer typeCoercer;
+    private PropertyAccess propertyAccess;
+    private PropertyConduitSource propertyConduitSource;
+    private PlasticProxyFactory plasticProxyFactory;
+    private DataTypeAnalyzer dataTypeAnalyzer;
+    private ObjectLocator objectLocator;
+    private StringInterner stringInterner;
 
-	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);
-		
-	}
+    /**
+     * Sets the {@link TypeCoercer} to be used.
+     */
+    public BeanModelSourceBuilder setTypeCoercer(TypeCoercer typeCoercer)
+    {
+        this.typeCoercer = typeCoercer;
+        return this;
+    }
 
-	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>();
+    public BeanModelSource build() 
+    {
+        
+        if (typeCoercer == null) 
+        {
+            createTypeCoercer();
+        }
+        
+        if (propertyAccess == null)
+        {
+            propertyAccess = new PropertyAccessImpl();
+        }
+        
+        if (dataTypeAnalyzer == null)
+        {
+            dataTypeAnalyzer = BasicDataTypeAnalyzers.createDefaultDataTypeAnalyzer();
+        }
+        
+        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());
+    }
 
-		@Override
-		public void add(CoercionTuple tuble) {
-			tuples.add(tuble);
-		}
+    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;
+        }
+
+    }
 
-		@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/696bc7ae/beanmodel/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
index 4dbfb2d..2127696 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
@@ -50,10 +50,10 @@ public class CoercingPropertyConduitWrapper implements PropertyConduit2
     
     public Type getPropertyGenericType()
     {
-    	if (conduit instanceof PropertyConduit2) {
-    		return ((PropertyConduit2) conduit).getPropertyGenericType();
-    	}
-    	return conduit.getPropertyType();
+        if (conduit instanceof PropertyConduit2) {
+            return ((PropertyConduit2) conduit).getPropertyGenericType();
+        }
+        return conduit.getPropertyType();
     }
 
     @SuppressWarnings("unchecked")

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
index 1fffd4f..e8cd58f 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
@@ -63,7 +63,7 @@ public class LiteralPropertyConduit extends PropertyConduitDelegate implements I
     
     public Type getPropertyGenericType()
     {
-    	return propertyType;
+        return propertyType;
     }
 
     public <T extends Annotation> T getAnnotation(Class<T> annotationClass)

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/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 09d234c..9148b46 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
@@ -524,28 +524,28 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
 
         private Type getGenericType(PropertyAdapter adapter)
         {
-        	Type genericType = null;
-        	if (adapter.getField() != null)
-        	{
-        		genericType = adapter.getField().getGenericType();
-        	}
-        	else if (adapter.getReadMethod() != null)
-        	{
-        		genericType = adapter.getReadMethod().getGenericReturnType(); 
-        	}
-        	else if (adapter.getWriteMethod() != null)
-        	{
-        		genericType = adapter.getWriteMethod().getGenericParameterTypes()[0];
-        	}
-        	else
-        	{
-        		throw new RuntimeException("Could not find accessor for property " + adapter.getName());
-        	}
-        	
-        	return genericType == null ? adapter.getType() : genericType;
-		}
-
-		private void implementSetter(PropertyAdapter adapter)
+            Type genericType = null;
+            if (adapter.getField() != null)
+            {
+                genericType = adapter.getField().getGenericType();
+            }
+            else if (adapter.getReadMethod() != null)
+            {
+                genericType = adapter.getReadMethod().getGenericReturnType(); 
+            }
+            else if (adapter.getWriteMethod() != null)
+            {
+                genericType = adapter.getWriteMethod().getGenericParameterTypes()[0];
+            }
+            else
+            {
+                throw new RuntimeException("Could not find accessor for property " + adapter.getName());
+            }
+            
+            return genericType == null ? adapter.getType() : genericType;
+        }
+
+        private void implementSetter(PropertyAdapter adapter)
         {
             if (adapter.getWriteMethod() != null)
             {
@@ -1488,7 +1488,7 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
             
             public Type getPropertyGenericType()
             {
-            	return rootClass;
+                return rootClass;
             }
 
             public <T extends Annotation> T getAnnotation(Class<T> annotationClass)

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/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
index 5d6dfec..9c5f36c4 100644
--- 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
@@ -57,11 +57,11 @@ public class ClassPropertyAdapterImpl implements ClassPropertyAdapter
             // TAP5-1493
             if (readMethod != null && readMethod.isBridge())
             {
-            	if (nonBridgeMethods == null)
-            	{
-            		nonBridgeMethods = groupNonBridgeMethodsByName(beanType);
-            	}
-            	readMethod = findMethodWithSameNameAndParamCount(readMethod, nonBridgeMethods); 
+                if (nonBridgeMethods == null)
+                {
+                    nonBridgeMethods = groupNonBridgeMethodsByName(beanType);
+                }
+                readMethod = findMethodWithSameNameAndParamCount(readMethod, nonBridgeMethods); 
             }
             
             // TAP5-1548, TAP5-1885: trying to find a getter which Introspector missed
@@ -86,11 +86,11 @@ public class ClassPropertyAdapterImpl implements ClassPropertyAdapter
             
             if (writeMethod != null && writeMethod.isBridge())
             {
-            	if (nonBridgeMethods == null)
-            	{
-            		nonBridgeMethods = groupNonBridgeMethodsByName(beanType);
-            	}
-            	writeMethod = findMethodWithSameNameAndParamCount(writeMethod, nonBridgeMethods);
+                if (nonBridgeMethods == null)
+                {
+                    nonBridgeMethods = groupNonBridgeMethodsByName(beanType);
+                }
+                writeMethod = findMethodWithSameNameAndParamCount(writeMethod, nonBridgeMethods);
             }
             
             // TAP5-1548, TAP5-1885: trying to find a setter which Introspector missed
@@ -149,24 +149,24 @@ public class ClassPropertyAdapterImpl implements ClassPropertyAdapter
      *         (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;
-	}
-
-	/**
+        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
      * 
@@ -176,24 +176,24 @@ public class ClassPropertyAdapterImpl implements ClassPropertyAdapter
      */
     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
+        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;

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/commons/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java b/commons/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java
new file mode 100644
index 0000000..8b20666
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java
@@ -0,0 +1,32 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.services;
+
+import org.apache.tapestry5.beaneditor.DataType;
+import org.apache.tapestry5.ioc.services.PropertyAdapter;
+import org.apache.tapestry5.services.DataTypeAnalyzer;
+
+/**
+ * Checks for the {@link DataType} annotation, returning its value if present.
+ */
+public class AnnotationDataTypeAnalyzer implements DataTypeAnalyzer
+{
+    public String identifyDataType(PropertyAdapter adapter)
+    {
+        DataType annotation = adapter.getAnnotation(DataType.class);
+
+        return annotation == null ? null : annotation.value();
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/commons/src/main/java/org/apache/tapestry5/ioc/internal/BasicDataTypeAnalyzers.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/BasicDataTypeAnalyzers.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/BasicDataTypeAnalyzers.java
new file mode 100644
index 0000000..df7564f
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/BasicDataTypeAnalyzers.java
@@ -0,0 +1,151 @@
+// 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.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.tapestry5.beaneditor.DataTypeConstants;
+import org.apache.tapestry5.internal.services.AnnotationDataTypeAnalyzer;
+import org.apache.tapestry5.ioc.MappedConfiguration;
+import org.apache.tapestry5.ioc.OrderedConfiguration;
+import org.apache.tapestry5.ioc.services.PropertyAdapter;
+import org.apache.tapestry5.services.DataTypeAnalyzer;
+
+/**
+ * Class that provides Tapestry's basic default data type analyzers.
+ */
+public class BasicDataTypeAnalyzers
+{
+    
+    public static void contributeDataTypeAnalyzer(
+            OrderedConfiguration<DataTypeAnalyzer> configuration,
+            DataTypeAnalyzer defaultDataTypeAnalyzer) {
+        configuration.add("Annotation", new AnnotationDataTypeAnalyzer());
+        if (defaultDataTypeAnalyzer == null)
+        {
+            defaultDataTypeAnalyzer = createDefaultDataTypeAnalyzer();
+        }
+        configuration.add("Default", defaultDataTypeAnalyzer, "after:*");
+    }
+
+    public static DataTypeAnalyzer createDefaultDataTypeAnalyzer() 
+    {
+        DefaultDataTypeAnalyzerMappedConfiguration mappedConfiguration = new DefaultDataTypeAnalyzerMappedConfiguration();
+        provideDefaultDataTypeAnalyzers(mappedConfiguration);
+        return new CombinedDataTypeAnalyzer(new AnnotationDataTypeAnalyzer(), new MapDataTypeAnalyzer(mappedConfiguration.getMap()));
+    }
+    
+    /**
+     * Maps property types to data type names:
+     * <ul>
+     * <li>String --&gt; text
+     * <li>Number --&gt; number
+     * <li>Enum --&gt; enum
+     * <li>Boolean --&gt; boolean
+     * <li>Date --&gt; date
+     * </ul>
+     */
+    public static void provideDefaultDataTypeAnalyzers(MappedConfiguration<Class, String> configuration)
+    {
+        // This is a special case contributed to avoid exceptions when a
+        // property type can't be
+        // matched. DefaultDataTypeAnalyzer converts the empty string to null.
+
+        configuration.add(Object.class, "");
+
+        configuration.add(String.class, DataTypeConstants.TEXT);
+        configuration.add(Number.class, DataTypeConstants.NUMBER);
+        configuration.add(Enum.class, DataTypeConstants.ENUM);
+        configuration.add(Boolean.class, DataTypeConstants.BOOLEAN);
+        configuration.add(Date.class, DataTypeConstants.DATE);
+        configuration.add(Calendar.class, DataTypeConstants.CALENDAR);
+    }
+
+    final private static class DefaultDataTypeAnalyzerMappedConfiguration implements MappedConfiguration<Class, String> 
+    {
+        
+        final Map<Class, String> map = new HashMap<Class, String>();
+
+        @Override
+        public void add(Class key, String value) {
+            map.put(key, value);
+        }
+
+        @Override
+        public void override(Class key, String value) {
+            throw new RuntimeException("Not implemented");
+        }
+
+        @Override
+        public void addInstance(Class key, Class<? extends String> clazz) {
+            throw new RuntimeException("Not implemented");            
+        }
+
+        @Override
+        public void overrideInstance(Class key, Class<? extends String> clazz) {
+            throw new RuntimeException("Not implemented");
+        }
+
+        public Map<Class, String> getMap() {
+            return map;
+        }
+        
+    }
+    
+    final private static class MapDataTypeAnalyzer implements DataTypeAnalyzer
+    {
+        
+        final Map<Class, String> map;
+
+        public MapDataTypeAnalyzer(Map<Class, String> map) {
+            this.map = map;
+        }
+
+        @Override
+        public String identifyDataType(PropertyAdapter adapter) {
+            return map.get(adapter.getType());
+        }
+        
+    }
+    
+    final private static class CombinedDataTypeAnalyzer implements DataTypeAnalyzer 
+    {
+
+        final private DataTypeAnalyzer first, second;
+
+        public CombinedDataTypeAnalyzer(DataTypeAnalyzer first, DataTypeAnalyzer second) 
+        {
+            super();
+            this.first = first;
+            this.second = second;
+        }
+
+        @Override
+        public String identifyDataType(PropertyAdapter adapter) 
+        {
+            String type = first.identifyDataType(adapter);
+            if (type == null) 
+            {
+                type = second.identifyDataType(adapter);
+            }
+            return type;
+        }
+
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
index 3c391e0..2bc33d8 100644
--- a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
@@ -33,11 +33,11 @@ import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
  */
 public class InternalCommonsUtils {
 
-	/**
-	 * @since 5.3
-	 */
-	public final static AnnotationProvider NULL_ANNOTATION_PROVIDER = new NullAnnotationProvider();
-	private static final Pattern NON_WORD_PATTERN = Pattern.compile("[^\\w]");
+    /**
+     * @since 5.3
+     */
+    public final static AnnotationProvider NULL_ANNOTATION_PROVIDER = new NullAnnotationProvider();
+    private static final Pattern NON_WORD_PATTERN = Pattern.compile("[^\\w]");
 
     /**
      * Adds a value to a specially organized map where the values are lists of objects. This somewhat simulates a map
@@ -67,322 +67,322 @@ public class InternalCommonsUtils {
         list.add(value);
     }
 
-	/**
-	 * Sniffs the object to see if it is a {@link Location} or {@link Locatable}. Returns null if null or not
-	 * convertable to a location.
-	 */
-	
-	public static Location locationOf(Object location)
-	{
-	    if (location == null)
-	        return null;
-	
-	    if (location instanceof Location)
-	        return (Location) location;
-	
-	    if (location instanceof Locatable)
-	        return ((Locatable) location).getLocation();
-	
-	    return null;
-	}
+    /**
+     * Sniffs the object to see if it is a {@link Location} or {@link Locatable}. Returns null if null or not
+     * convertable to a location.
+     */
+    
+    public static Location locationOf(Object location)
+    {
+        if (location == null)
+            return null;
+    
+        if (location instanceof Location)
+            return (Location) location;
+    
+        if (location instanceof Locatable)
+            return ((Locatable) location).getLocation();
+    
+        return null;
+    }
 
-	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);
-	        }
-	    };
-	}
+    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);
+            }
+        };
+    }
 
-	/**
-	 * 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, "");
-	}
+    /**
+     * 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);
-	}
+    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(InternalCommonsUtils.lastTerm(propertyExpression)));
-	}
+    /**
+     * 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(InternalCommonsUtils.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();
-	}
+    /**
+     * 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));
-	        }
-	    };
-	}
+    /**
+     * @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));
+            }
+        };
+    }
 
-	/**
-	 * Pattern used to eliminate leading and trailing underscores and dollar signs.
-	 */
-	static final Pattern NAME_PATTERN = Pattern.compile("^[_|$]*([\\p{javaJavaIdentifierPart}]+?)[_|$]*$",
-	        Pattern.CASE_INSENSITIVE);
+    /**
+     * Pattern used to eliminate leading and trailing underscores and dollar signs.
+     */
+    static final Pattern NAME_PATTERN = Pattern.compile("^[_|$]*([\\p{javaJavaIdentifierPart}]+?)[_|$]*$",
+            Pattern.CASE_INSENSITIVE);
 
-	/**
-	 * Converts a method to a user presentable string consisting of the containing class name, the method name, and the
-	 * short form of the parameter list (the class name of each parameter type, shorn of the package name portion).
-	 *
-	 * @param method
-	 * @return short string representation
-	 */
-	public static String asString(Method method)
-	{
-	    StringBuilder buffer = new StringBuilder();
-	
-	    buffer.append(method.getDeclaringClass().getName());
-	    buffer.append(".");
-	    buffer.append(method.getName());
-	    buffer.append("(");
-	
-	    for (int i = 0; i < method.getParameterTypes().length; i++)
-	    {
-	        if (i > 0)
-	            buffer.append(", ");
-	
-	        String name = method.getParameterTypes()[i].getSimpleName();
-	
-	        buffer.append(name);
-	    }
-	
-	    return buffer.append(")").toString();
-	}
+    /**
+     * Converts a method to a user presentable string consisting of the containing class name, the method name, and the
+     * short form of the parameter list (the class name of each parameter type, shorn of the package name portion).
+     *
+     * @param method
+     * @return short string representation
+     */
+    public static String asString(Method method)
+    {
+        StringBuilder buffer = new StringBuilder();
+    
+        buffer.append(method.getDeclaringClass().getName());
+        buffer.append(".");
+        buffer.append(method.getName());
+        buffer.append("(");
+    
+        for (int i = 0; i < method.getParameterTypes().length; i++)
+        {
+            if (i > 0)
+                buffer.append(", ");
+    
+            String name = method.getParameterTypes()[i].getSimpleName();
+    
+            buffer.append(name);
+        }
+    
+        return buffer.append(")").toString();
+    }
 
-	/**
-	 * Strips leading "_" and "$" and trailing "_" from the name.
-	 */
-	public static String stripMemberName(String memberName)
-	{
-	    assert InternalCommonsUtils.isNonBlank(memberName);
-	    Matcher matcher = NAME_PATTERN.matcher(memberName);
-	
-	    if (!matcher.matches())
-	        throw new IllegalArgumentException(String.format("Input '%s' is not a valid Java identifier.", memberName));
-	
-	    return matcher.group(1);
-	}
+    /**
+     * Strips leading "_" and "$" and trailing "_" from the name.
+     */
+    public static String stripMemberName(String memberName)
+    {
+        assert InternalCommonsUtils.isNonBlank(memberName);
+        Matcher matcher = NAME_PATTERN.matcher(memberName);
+    
+        if (!matcher.matches())
+            throw new IllegalArgumentException(String.format("Input '%s' is not a valid Java identifier.", memberName));
+    
+        return matcher.group(1);
+    }
 
-	/**
-	 * Joins together some number of elements to form a comma separated list.
-	 */
-	public static String join(List elements)
-	{
-	    return InternalCommonsUtils.join(elements, ", ");
-	}
+    /**
+     * Joins together some number of elements to form a comma separated list.
+     */
+    public static String join(List elements)
+    {
+        return InternalCommonsUtils.join(elements, ", ");
+    }
 
-	/**
-	 * Joins together some number of elements. If a value in the list is the empty string, it is replaced with the
-	 * string "(blank)".
-	 *
-	 * @param elements
-	 *         objects to be joined together
-	 * @param separator
-	 *         used between elements when joining
-	 */
-	public static String join(List elements, String separator)
-	{
-	    switch (elements.size())
-	    {
-	        case 0:
-	            return "";
-	
-	        case 1:
-	            return elements.get(0).toString();
-	
-	        default:
-	
-	            StringBuilder buffer = new StringBuilder();
-	            boolean first = true;
-	
-	            for (Object o : elements)
-	            {
-	                if (!first)
-	                    buffer.append(separator);
-	
-	                String string = String.valueOf(o);
-	
-	                if (string.equals(""))
-	                    string = "(blank)";
-	
-	                buffer.append(string);
-	
-	                first = false;
-	            }
-	
-	            return buffer.toString();
-	    }
-	}
+    /**
+     * Joins together some number of elements. If a value in the list is the empty string, it is replaced with the
+     * string "(blank)".
+     *
+     * @param elements
+     *         objects to be joined together
+     * @param separator
+     *         used between elements when joining
+     */
+    public static String join(List elements, String separator)
+    {
+        switch (elements.size())
+        {
+            case 0:
+                return "";
+    
+            case 1:
+                return elements.get(0).toString();
+    
+            default:
+    
+                StringBuilder buffer = new StringBuilder();
+                boolean first = true;
+    
+                for (Object o : elements)
+                {
+                    if (!first)
+                        buffer.append(separator);
+    
+                    String string = String.valueOf(o);
+    
+                    if (string.equals(""))
+                        string = "(blank)";
+    
+                    buffer.append(string);
+    
+                    first = false;
+                }
+    
+                return buffer.toString();
+        }
+    }
 
-	/**
-	 * Creates a sorted copy of the provided elements, then turns that into a comma separated list.
-	 *
-	 * @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
-	 *         empty
-	 */
-	public static String joinSorted(Collection elements)
-	{
-	    if (elements == null || elements.isEmpty())
-	        return "(none)";
-	
-	    List<String> list = CollectionFactory.newList();
-	
-	    for (Object o : elements)
-	        list.add(String.valueOf(o));
-	
-	    Collections.sort(list);
-	
-	    return join(list);
-	}
+    /**
+     * Creates a sorted copy of the provided elements, then turns that into a comma separated list.
+     *
+     * @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
+     *         empty
+     */
+    public static String joinSorted(Collection elements)
+    {
+        if (elements == null || elements.isEmpty())
+            return "(none)";
+    
+        List<String> list = CollectionFactory.newList();
+    
+        for (Object o : elements)
+            list.add(String.valueOf(o));
+    
+        Collections.sort(list);
+    
+        return join(list);
+    }
 
-	/**
-	 * Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
-	 */
-	
-	public static boolean isBlank(String input)
-	{
-	    return input == null || input.length() == 0 || input.trim().length() == 0;
-	}
+    /**
+     * Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
+     */
+    
+    public static boolean isBlank(String input)
+    {
+        return input == null || input.length() == 0 || input.trim().length() == 0;
+    }
 
-	/**
-	 * Capitalizes a string, converting the first character to uppercase.
-	 */
-	public static String capitalize(String input)
-	{
-	    if (input.length() == 0)
-	        return input;
-	
-	    return input.substring(0, 1).toUpperCase() + input.substring(1);
-	}
+    /**
+     * Capitalizes a string, converting the first character to uppercase.
+     */
+    public static String capitalize(String input)
+    {
+        if (input.length() == 0)
+            return input;
+    
+        return input.substring(0, 1).toUpperCase() + input.substring(1);
+    }
 
-	public static boolean isNonBlank(String input)
-	{
-	    return !isBlank(input);
-	}
+    public static boolean isNonBlank(String input)
+    {
+        return !isBlank(input);
+    }
 
-	/**
-	 * Return true if the input string contains the marker for symbols that must be expanded.
-	 */
-	public static boolean containsSymbols(String input)
-	{
-	    return input.contains("${");
-	}
+    /**
+     * Return true if the input string contains the marker for symbols that must be expanded.
+     */
+    public static boolean containsSymbols(String input)
+    {
+        return input.contains("${");
+    }
 
-	/**
-	 * Searches the string for the final period ('.') character and returns everything after that. The input string is
-	 * generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
-	 * expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
-	 * character.
-	 */
-	public static String lastTerm(String input)
-	{
-	    assert isNonBlank(input);
-	    int dotx = input.lastIndexOf('.');
-	
-	    if (dotx < 0)
-	        return input;
-	
-	    return input.substring(dotx + 1);
-	}
+    /**
+     * Searches the string for the final period ('.') character and returns everything after that. The input string is
+     * generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
+     * expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
+     * character.
+     */
+    public static String lastTerm(String input)
+    {
+        assert isNonBlank(input);
+        int dotx = input.lastIndexOf('.');
+    
+        if (dotx < 0)
+            return input;
+    
+        return input.substring(dotx + 1);
+    }
 
-	/**
-	 * Extracts the string keys from a map and returns them in sorted order. The keys are converted to strings.
-	 *
-	 * @param map
-	 *         the map to extract keys from (may be null)
-	 * @return the sorted keys, or the empty set if map is null
-	 */
-	
-	public static List<String> sortedKeys(Map map)
-	{
-	    if (map == null)
-	        return Collections.emptyList();
-	
-	    List<String> keys = CollectionFactory.newList();
-	
-	    for (Object o : map.keySet())
-	        keys.add(String.valueOf(o));
-	
-	    Collections.sort(keys);
-	
-	    return keys;
-	}
+    /**
+     * Extracts the string keys from a map and returns them in sorted order. The keys are converted to strings.
+     *
+     * @param map
+     *         the map to extract keys from (may be null)
+     * @return the sorted keys, or the empty set if map is null
+     */
+    
+    public static List<String> sortedKeys(Map map)
+    {
+        if (map == null)
+            return Collections.emptyList();
+    
+        List<String> keys = CollectionFactory.newList();
+    
+        for (Object o : map.keySet())
+            keys.add(String.valueOf(o));
+    
+        Collections.sort(keys);
+    
+        return keys;
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
index e032975..5e4ab42 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
@@ -457,9 +457,9 @@ public class TapestryInternalUtils
             {
                 if (conduit instanceof PropertyConduit2)
                 {
-                	return ((PropertyConduit2) conduit).getPropertyGenericType();
+                    return ((PropertyConduit2) conduit).getPropertyGenericType();
                 }
-            	return conduit.getPropertyType();
+                return conduit.getPropertyType();
             }
             
             public Object get(Object instance)

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/AbstractBinding.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/AbstractBinding.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/AbstractBinding.java
index 8e731b7..572d61a 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/AbstractBinding.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/AbstractBinding.java
@@ -71,7 +71,7 @@ public abstract class AbstractBinding extends BaseLocatable implements Binding2
      */
     public Type getBindingGenericType()
     {
-    	return getBindingType();
+        return getBindingType();
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/PropBinding.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/PropBinding.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/PropBinding.java
index afe63eb..da4c53e 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/PropBinding.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/PropBinding.java
@@ -111,10 +111,10 @@ public class PropBinding extends AbstractBinding implements InternalPropBinding
     @Override
     public Type getBindingGenericType()
     {
-    	if (conduit instanceof PropertyConduit2) {
-    		return ((PropertyConduit2) conduit).getPropertyGenericType();
-    	}
-    	return conduit.getPropertyType();
+        if (conduit instanceof PropertyConduit2) {
+            return ((PropertyConduit2) conduit).getPropertyGenericType();
+        }
+        return conduit.getPropertyType();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java
deleted file mode 100644
index 8b20666..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2007 The Apache Software Foundation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.apache.tapestry5.internal.services;
-
-import org.apache.tapestry5.beaneditor.DataType;
-import org.apache.tapestry5.ioc.services.PropertyAdapter;
-import org.apache.tapestry5.services.DataTypeAnalyzer;
-
-/**
- * Checks for the {@link DataType} annotation, returning its value if present.
- */
-public class AnnotationDataTypeAnalyzer implements DataTypeAnalyzer
-{
-    public String identifyDataType(PropertyAdapter adapter)
-    {
-        DataType annotation = adapter.getAnnotation(DataType.class);
-
-        return annotation == null ? null : annotation.value();
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java
index c51c086..5d0ac16 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java
@@ -351,9 +351,9 @@ public class InternalComponentResourcesImpl extends LockSupport implements Inter
         Binding binding = getBinding(parameterName);
         Type genericType;
         if (binding instanceof Binding2) {
-        	genericType = ((Binding2) binding).getBindingGenericType();
+            genericType = ((Binding2) binding).getBindingGenericType();
         } else {
-        	genericType = binding.getBindingType();
+            genericType = binding.getBindingType();
         }
         return genericType;
     }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
index e3902de..8a72a4d 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
@@ -59,6 +59,7 @@ import org.apache.tapestry5.internal.util.StringRenderable;
 import org.apache.tapestry5.internal.validator.ValidatorMacroImpl;
 import org.apache.tapestry5.ioc.*;
 import org.apache.tapestry5.ioc.annotations.*;
+import org.apache.tapestry5.ioc.internal.BasicDataTypeAnalyzers;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.services.*;
 import org.apache.tapestry5.ioc.util.AvailableValues;
@@ -621,18 +622,7 @@ public final class TapestryModule
      */
     public static void contributeDefaultDataTypeAnalyzer(MappedConfiguration<Class, String> configuration)
     {
-        // This is a special case contributed to avoid exceptions when a
-        // property type can't be
-        // matched. DefaultDataTypeAnalyzer converts the empty string to null.
-
-        configuration.add(Object.class, "");
-
-        configuration.add(String.class, DataTypeConstants.TEXT);
-        configuration.add(Number.class, DataTypeConstants.NUMBER);
-        configuration.add(Enum.class, DataTypeConstants.ENUM);
-        configuration.add(Boolean.class, DataTypeConstants.BOOLEAN);
-        configuration.add(Date.class, DataTypeConstants.DATE);
-        configuration.add(Calendar.class, DataTypeConstants.CALENDAR);
+        BasicDataTypeAnalyzers.provideDefaultDataTypeAnalyzers(configuration);
     }
 
     @Contribute(BeanBlockSource.class)

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/GenericTypeDisplay.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/GenericTypeDisplay.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/GenericTypeDisplay.java
index f6d2aa7..0a9365e 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/GenericTypeDisplay.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/GenericTypeDisplay.java
@@ -25,21 +25,21 @@ import org.apache.tapestry5.ioc.annotations.Inject;
  * Outputs the type and genericType of the 'value' binding in a div
  */
 public class GenericTypeDisplay {
-	@Inject
-	private ComponentResources resources;
-	
-	@Parameter(required=true, defaultPrefix=BindingConstants.LITERAL)
-	private String description;
-	
-	@Parameter(required=true)
-	private Object value;
-	
-	void afterRender(MarkupWriter writer) {
-		writer.element("div");
-		Class<?> type = resources.getBoundType("value");
-		Type genericType = resources.getBoundGenericType("value");
-		String text = String.format("description=%s,type=%s,genericType=%s", description, type.getName(), genericType.toString());
-		writer.write(text);
-		writer.end();
-	}
+    @Inject
+    private ComponentResources resources;
+    
+    @Parameter(required=true, defaultPrefix=BindingConstants.LITERAL)
+    private String description;
+    
+    @Parameter(required=true)
+    private Object value;
+    
+    void afterRender(MarkupWriter writer) {
+        writer.element("div");
+        Class<?> type = resources.getBoundType("value");
+        Type genericType = resources.getBoundGenericType("value");
+        String text = String.format("description=%s,type=%s,genericType=%s", description, type.getName(), genericType.toString());
+        writer.write(text);
+        writer.end();
+    }
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GenericTypeDemo.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GenericTypeDemo.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GenericTypeDemo.java
index 8e9fdd3..4fdc57a 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GenericTypeDemo.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GenericTypeDemo.java
@@ -8,16 +8,16 @@ import java.util.Set;
 import org.apache.tapestry5.annotations.Property;
 
 public class GenericTypeDemo {
-	private Set<Long> setOfLongs;
-	
-	@Property
-	private Map<String, String> mapOfStrings;
-	
-	public List<List<Date>> getListOfListOfDates() {
-		throw new UnsupportedOperationException();
-	}
-	
-	public void setSetOfLongs(Set<Long> setOfLongs) {
-		throw new UnsupportedOperationException();
-	}
+    private Set<Long> setOfLongs;
+    
+    @Property
+    private Map<String, String> mapOfStrings;
+    
+    public List<List<Date>> getListOfListOfDates() {
+        throw new UnsupportedOperationException();
+    }
+    
+    public void setSetOfLongs(Set<Long> setOfLongs) {
+        throw new UnsupportedOperationException();
+    }
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridWithSubmitWithContextDemo.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridWithSubmitWithContextDemo.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridWithSubmitWithContextDemo.java
index 9d4a774..0aac48f 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridWithSubmitWithContextDemo.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridWithSubmitWithContextDemo.java
@@ -45,9 +45,9 @@ public class GridWithSubmitWithContextDemo
     {
         return F.flow(library.getTracks()).sort(new Comparator<Track>(){
 
-			@Override
+            @Override
             public int compare(Track arg0, Track arg1) {
-	            return arg0.getId().compareTo(arg1.getId());
+                return arg0.getId().compareTo(arg1.getId());
             }
 
         });

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ChildBasePage.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ChildBasePage.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ChildBasePage.java
index 44e9aff..5a787e9 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ChildBasePage.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ChildBasePage.java
@@ -1,8 +1,8 @@
 package org.apache.tapestry5.integration.app2.base;
 
 public abstract class ChildBasePage extends ParentBasePage {
-	@Override
-	public String getObject() {
-		return "foobar";
-	}
+    @Override
+    public String getObject() {
+        return "foobar";
+    }
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ParentBasePage.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ParentBasePage.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ParentBasePage.java
index 4030128..6c18c43 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ParentBasePage.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ParentBasePage.java
@@ -1,5 +1,5 @@
 package org.apache.tapestry5.integration.app2.base;
 
 public abstract class ParentBasePage {
-	public abstract Object getObject();
+    public abstract Object getObject();
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/test/java/org/apache/tapestry5/integration/pagelevel/OverrideMethodsTest.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/pagelevel/OverrideMethodsTest.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/pagelevel/OverrideMethodsTest.java
index b612d1f..c8e7d48 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/pagelevel/OverrideMethodsTest.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/pagelevel/OverrideMethodsTest.java
@@ -9,13 +9,13 @@ public class OverrideMethodsTest extends Assert {
     /** TAP5-901 */
     @Test
     public void override_abstract_methods() {
-    	PageTester tester = new PageTester(TestConstants.APP2_PACKAGE, TestConstants.APP2_NAME);
-    	try {
-	        Document doc = tester.renderPage("OverrideAbstractMethods");
-	        assertEquals("6", doc.getElementById("length").getChildMarkup());
-    	} finally {
-    		tester.shutdown();
-    	}
+        PageTester tester = new PageTester(TestConstants.APP2_PACKAGE, TestConstants.APP2_NAME);
+        try {
+            Document doc = tester.renderPage("OverrideAbstractMethods");
+            assertEquals("6", doc.getElementById("length").getChildMarkup());
+        } finally {
+            tester.shutdown();
+        }
     }
 
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java
index af25c62..a861883 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java
@@ -167,15 +167,15 @@ public class PropertyConduitSourceImplTest extends InternalBaseTestCase
     }
 
     static class GenericBean {
-    	public List<Date> dates;
-    	public List<GenericBean> genericBeans;
-    	
-    	public List<Long> getLongs() {
-    		return Collections.emptyList();
-    	}
-    	
-    	public void setMap(Map<String, Integer> map) {
-    	}
+        public List<Date> dates;
+        public List<GenericBean> genericBeans;
+        
+        public List<Long> getLongs() {
+            return Collections.emptyList();
+        }
+        
+        public void setMap(Map<String, Integer> map) {
+        }
     }
     
     @Test
@@ -884,15 +884,15 @@ public class PropertyConduitSourceImplTest extends InternalBaseTestCase
 
         // example from Howard
         try {
-        	assertConduitPropertyType(Foo.class, "bar", Bar.class);
+            assertConduitPropertyType(Foo.class, "bar", Bar.class);
         } catch (AssertionError e) {
-        	List<Method> matches = CollectionFactory.newList();
-        	for (Method method : Foo.class.getMethods()) {
-        		if (method.getName().equals("getBar")) {
-        			matches.add(method);
-        		}
-        	}
-        	fail(String.format("%s (possible candidates %s)", e.getMessage(), matches)); 
+            List<Method> matches = CollectionFactory.newList();
+            for (Method method : Foo.class.getMethods()) {
+                if (method.getName().equals("getBar")) {
+                    matches.add(method);
+                }
+            }
+            fail(String.format("%s (possible candidates %s)", e.getMessage(), matches)); 
         }
         assertConduitPropertyType(AbstractFoo.class, "bar", AbstractBar.class);
         

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONArray.java
----------------------------------------------------------------------
diff --git a/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONArray.java b/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONArray.java
index 76ea531..7cb7d55 100644
--- a/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONArray.java
+++ b/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONArray.java
@@ -386,7 +386,7 @@ public final class JSONArray extends JSONCollection implements Iterable<Object>
      */
     public JSONArray put(Object value)
     {
-    	// now testValidity checks for null values.
+        // now testValidity checks for null values.
         // assert value != null;
 
         JSONObject.testValidity(value);

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java
----------------------------------------------------------------------
diff --git a/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java b/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java
index 7c5ccb4..1392bb8 100644
--- a/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java
+++ b/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java
@@ -913,7 +913,7 @@ public final class JSONObject extends JSONCollection
      */
     static void printValue(JSONPrintSession session, Object value)
     {
-    	
+        
         if (value instanceof JSONObject)
         {
             ((JSONObject) value).print(session);


[03/15] tapestry-5 git commit: First pass creating the BeanModel and Commons packages. Lots of stuff moved around, but no actual code changes so far

Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
deleted file mode 100644
index 701420f..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
+++ /dev/null
@@ -1,1563 +0,0 @@
-// Copyright 2007-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.internal.services;
-
-import org.antlr.runtime.ANTLRInputStream;
-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.InternalPropertyConduit;
-import org.apache.tapestry5.internal.antlr.PropertyExpressionLexer;
-import org.apache.tapestry5.internal.antlr.PropertyExpressionParser;
-import org.apache.tapestry5.internal.util.IntegerRange;
-import org.apache.tapestry5.internal.util.MultiKey;
-import org.apache.tapestry5.ioc.AnnotationProvider;
-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.InternalUtils;
-import org.apache.tapestry5.ioc.services.*;
-import org.apache.tapestry5.ioc.util.AvailableValues;
-import org.apache.tapestry5.ioc.util.ExceptionUtils;
-import org.apache.tapestry5.ioc.util.UnknownValueException;
-import org.apache.tapestry5.plastic.*;
-import org.apache.tapestry5.services.ComponentClasses;
-import org.apache.tapestry5.services.ComponentLayer;
-import org.apache.tapestry5.services.InvalidationEventHub;
-import org.apache.tapestry5.services.PropertyConduitSource;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.*;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.*;
-
-public class PropertyConduitSourceImpl implements PropertyConduitSource
-{
-    static class ConduitMethods
-    {
-        private static final MethodDescription GET = getMethodDescription(PropertyConduit.class, "get", Object.class);
-
-        private static final MethodDescription SET = getMethodDescription(PropertyConduit.class, "set", Object.class,
-                Object.class);
-
-        private static final MethodDescription GET_PROPERTY_TYPE = getMethodDescription(PropertyConduit.class,
-                "getPropertyType");
-
-        private static final MethodDescription GET_PROPERTY_GENERIC_TYPE = getMethodDescription(PropertyConduit2.class,
-                "getPropertyGenericType");
-        
-        private static final MethodDescription GET_PROPERTY_NAME = getMethodDescription(InternalPropertyConduit.class,
-                "getPropertyName");
-        
-        private static final MethodDescription GET_ANNOTATION = getMethodDescription(AnnotationProvider.class,
-                "getAnnotation", Class.class);
-
-    }
-
-    static class DelegateMethods
-    {
-        static final Method INVERT = getMethod(PropertyConduitDelegate.class, "invert", Object.class);
-
-        static final Method RANGE = getMethod(PropertyConduitDelegate.class, "range", int.class, int.class);
-
-        static final Method COERCE = getMethod(PropertyConduitDelegate.class, "coerce", Object.class, Class.class);
-    }
-
-    static class ArrayListMethods
-    {
-        static final Method ADD = getMethod(ArrayList.class, "add", Object.class);
-    }
-
-    static class HashMapMethods
-    {
-        static final Method PUT = getMethod(HashMap.class, "put", Object.class, Object.class);
-    }
-
-    private static InstructionBuilderCallback RETURN_NULL = new InstructionBuilderCallback()
-    {
-        public void doBuild(InstructionBuilder builder)
-        {
-            builder.loadNull().returnResult();
-        }
-    };
-
-    private static final String[] SINGLE_OBJECT_ARGUMENT = new String[]
-            {Object.class.getName()};
-
-    @SuppressWarnings("unchecked")
-    private static Method getMethod(Class containingClass, String name, Class... parameterTypes)
-    {
-        try
-        {
-            return containingClass.getMethod(name, parameterTypes);
-        } catch (NoSuchMethodException ex)
-        {
-            throw new IllegalArgumentException(ex);
-        }
-    }
-
-    private static MethodDescription getMethodDescription(Class containingClass, String name, Class... parameterTypes)
-    {
-        return new MethodDescription(getMethod(containingClass, name, parameterTypes));
-    }
-
-    private final AnnotationProvider nullAnnotationProvider = new NullAnnotationProvider();
-
-    /**
-     * How are null values in intermdiate terms to be handled?
-     */
-    private enum NullHandling
-    {
-        /**
-         * Add code to check for null and throw exception if null.
-         */
-        FORBID,
-
-        /**
-         * Add code to check for null and short-circuit (i.e., the "?."
-         * safe-dereference operator)
-         */
-        ALLOW
-    }
-
-    /**
-     * One term in an expression. Expressions start with some root type and each term advances
-     * to a new type.
-     */
-    private class Term
-    {
-        /**
-         * The generic type of the term.
-         */
-        final Type type;
-
-        final Class genericType;
-
-        /**
-         * Describes the term, for use in error messages.
-         */
-        final String description;
-
-        final AnnotationProvider annotationProvider;
-
-        /**
-         * Callback that will implement the term.
-         */
-        final InstructionBuilderCallback callback;
-
-        Term(Type type, Class genericType, String description, AnnotationProvider annotationProvider,
-             InstructionBuilderCallback callback)
-        {
-            this.type = type;
-            this.genericType = genericType;
-            this.description = description;
-            this.annotationProvider = annotationProvider;
-            this.callback = callback;
-        }
-
-        Term(Type type, String description, AnnotationProvider annotationProvider, InstructionBuilderCallback callback)
-        {
-            this(type, GenericsUtils.asClass(type), description, annotationProvider, callback);
-        }
-
-        Term(Type type, String description, InstructionBuilderCallback callback)
-        {
-            this(type, description, null, callback);
-        }
-
-        /**
-         * Returns a clone of this Term with a new callback.
-         */
-        Term withCallback(InstructionBuilderCallback newCallback)
-        {
-            return new Term(type, genericType, description, annotationProvider, newCallback);
-        }
-    }
-
-    private final PropertyAccess access;
-
-    private final PlasticProxyFactory proxyFactory;
-
-    private final TypeCoercer typeCoercer;
-
-    private final StringInterner interner;
-
-    /**
-     * Keyed on combination of root class and expression.
-     */
-    private final Map<MultiKey, PropertyConduit> cache = CollectionFactory.newConcurrentMap();
-
-    private final Invariant invariantAnnotation = new Invariant()
-    {
-        public Class<? extends Annotation> annotationType()
-        {
-            return Invariant.class;
-        }
-    };
-
-    private final AnnotationProvider invariantAnnotationProvider = new AnnotationProvider()
-    {
-        public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
-        {
-            if (annotationClass == Invariant.class)
-                return annotationClass.cast(invariantAnnotation);
-
-            return null;
-        }
-    };
-
-    private final PropertyConduit literalTrue;
-
-    private final PropertyConduit literalFalse;
-
-    private final PropertyConduit literalNull;
-
-    private final PropertyConduitDelegate sharedDelegate;
-
-    /**
-     * Encapsulates the process of building a PropertyConduit instance from an
-     * expression, as an {@link PlasticClassTransformer}.
-     */
-    class PropertyConduitBuilder implements PlasticClassTransformer
-    {
-        private final Class rootType;
-
-        private final String expression;
-
-        private final Tree tree;
-
-        private Class conduitPropertyType;
-
-        private Type conduitPropertyGenericType;
-
-        private String conduitPropertyName;
-
-        private AnnotationProvider annotationProvider = nullAnnotationProvider;
-
-        private PlasticField delegateField;
-
-        private PlasticClass plasticClass;
-
-        private PlasticMethod getRootMethod, navMethod;
-
-        PropertyConduitBuilder(Class rootType, String expression, Tree tree)
-        {
-            this.rootType = rootType;
-            this.expression = expression;
-            this.tree = tree;
-        }
-
-        public void transform(PlasticClass plasticClass)
-        {
-            this.plasticClass = plasticClass;
-
-            // Create the various methods; also determine the conduit's property type, property name and identify
-            // the annotation provider.
-
-            implementNavMethodAndAccessors();
-
-            implementOtherMethods();
-
-            plasticClass.addToString(String.format("PropertyConduit[%s %s]", rootType.getName(), expression));
-        }
-
-        private void implementOtherMethods()
-        {
-            PlasticField annotationProviderField = plasticClass.introduceField(AnnotationProvider.class,
-                    "annotationProvider").inject(annotationProvider);
-
-            plasticClass.introduceMethod(ConduitMethods.GET_ANNOTATION).delegateTo(annotationProviderField);
-
-            plasticClass.introduceMethod(ConduitMethods.GET_PROPERTY_NAME, new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    builder.loadConstant(conduitPropertyName).returnResult();
-                }
-            });
-
-            final PlasticField propertyTypeField = plasticClass.introduceField(Class.class, "propertyType").inject(
-                    conduitPropertyType);
-
-            plasticClass.introduceMethod(ConduitMethods.GET_PROPERTY_TYPE, new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    builder.loadThis().getField(propertyTypeField).returnResult();
-                }
-            });
-
-            final PlasticField propertyGenericTypeField = plasticClass.introduceField(Type.class, "propertyGenericType").inject(
-                    conduitPropertyGenericType);
-
-            plasticClass.introduceMethod(ConduitMethods.GET_PROPERTY_GENERIC_TYPE, new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    builder.loadThis().getField(propertyGenericTypeField).returnResult();
-                }
-            });
-        }
-
-        /**
-         * Creates a method that does a conversion from Object to the expected root type, with
-         * a null check.
-         */
-        private void implementGetRoot()
-        {
-            getRootMethod = plasticClass.introducePrivateMethod(PlasticUtils.toTypeName(rootType), "getRoot",
-                    SINGLE_OBJECT_ARGUMENT, null);
-
-            getRootMethod.changeImplementation(new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    builder.loadArgument(0).dupe().when(Condition.NULL, new InstructionBuilderCallback()
-                    {
-                        public void doBuild(InstructionBuilder builder)
-                        {
-                            builder.throwException(NullPointerException.class,
-                                    String.format("Root object of property expression '%s' is null.", expression));
-                        }
-                    });
-
-                    builder.checkcast(rootType).returnResult();
-                }
-            });
-        }
-
-        private boolean isLeaf(Tree node)
-        {
-            int type = node.getType();
-
-            return type != DEREF && type != SAFEDEREF;
-        }
-
-        private void implementNavMethodAndAccessors()
-        {
-            implementGetRoot();
-
-            // First, create the navigate method.
-
-            final List<InstructionBuilderCallback> callbacks = CollectionFactory.newList();
-
-            Type activeType = rootType;
-
-            Tree node = tree;
-
-            while (!isLeaf(node))
-            {
-                Term term = analyzeDerefNode(activeType, node);
-
-                callbacks.add(term.callback);
-
-                activeType = term.type;
-
-                // Second term is the continuation, possibly another chained
-                // DEREF, etc.
-                node = node.getChild(1);
-            }
-
-            Class activeClass = GenericsUtils.asClass(activeType);
-
-            if (callbacks.isEmpty())
-            {
-                navMethod = getRootMethod;
-            } else
-            {
-                navMethod = plasticClass.introducePrivateMethod(PlasticUtils.toTypeName(activeClass), "navigate",
-                        SINGLE_OBJECT_ARGUMENT, null);
-
-                navMethod.changeImplementation(new InstructionBuilderCallback()
-                {
-                    public void doBuild(InstructionBuilder builder)
-                    {
-                        builder.loadThis().loadArgument(0).invokeVirtual(getRootMethod);
-
-                        for (InstructionBuilderCallback callback : callbacks)
-                        {
-                            callback.doBuild(builder);
-                        }
-
-                        builder.returnResult();
-                    }
-                });
-            }
-
-            implementAccessors(activeType, node);
-        }
-
-        private void implementAccessors(Type activeType, Tree node)
-        {
-            switch (node.getType())
-            {
-                case IDENTIFIER:
-
-                    implementPropertyAccessors(activeType, node);
-
-                    return;
-
-                case INVOKE:
-
-                    // So, at this point, we have the navigation method written
-                    // and it covers all but the terminal
-                    // de-reference. node is an IDENTIFIER or INVOKE. We're
-                    // ready to use the navigation
-                    // method to implement get() and set().
-
-                    implementMethodAccessors(activeType, node);
-
-                    return;
-
-                case RANGEOP:
-
-                    // As currently implemented, RANGEOP can only appear as the
-                    // top level, which
-                    // means we didn't need the navigate method after all.
-
-                    implementRangeOpGetter(node);
-                    implementNoOpSetter();
-
-                    conduitPropertyType = IntegerRange.class;
-                    conduitPropertyGenericType = IntegerRange.class;
-
-                    return;
-
-                case LIST:
-
-                    implementListGetter(node);
-                    implementNoOpSetter();
-
-                    conduitPropertyType = List.class;
-                    conduitPropertyGenericType = List.class;
-                    
-                    return;
-
-                case MAP:
-                    implementMapGetter(node);
-                    implementNoOpSetter();
-
-                    conduitPropertyType = Map.class;
-                    conduitPropertyGenericType = Map.class;
-
-                    return;
-
-
-                case NOT:
-                    implementNotOpGetter(node);
-                    implementNoOpSetter();
-
-                    conduitPropertyType = boolean.class;
-                    conduitPropertyGenericType = boolean.class;
-
-                    return;
-
-                default:
-                    throw unexpectedNodeType(node, IDENTIFIER, INVOKE, RANGEOP, LIST, NOT);
-            }
-        }
-
-        public void implementMethodAccessors(final Type activeType, final Tree invokeNode)
-        {
-            final Term term = buildInvokeTerm(activeType, invokeNode);
-
-            implementNoOpSetter();
-
-            conduitPropertyName = term.description;
-            conduitPropertyType = term.genericType;
-            conduitPropertyGenericType = term.genericType;
-            annotationProvider = term.annotationProvider;
-
-            plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    invokeNavigateMethod(builder);
-
-                    term.callback.doBuild(builder);
-
-                    boxIfPrimitive(builder, conduitPropertyType);
-
-                    builder.returnResult();
-                }
-            });
-
-            implementNoOpSetter();
-        }
-
-        public void implementPropertyAccessors(Type activeType, Tree identifierNode)
-        {
-            String propertyName = identifierNode.getText();
-
-            PropertyAdapter adapter = findPropertyAdapter(activeType, propertyName);
-
-            conduitPropertyName = propertyName;
-            conduitPropertyType = adapter.getType();
-            conduitPropertyGenericType = getGenericType(adapter);
-            annotationProvider = adapter;
-
-            implementGetter(adapter);
-            implementSetter(adapter);
-        }
-
-        private Type getGenericType(PropertyAdapter adapter)
-        {
-        	Type genericType = null;
-        	if (adapter.getField() != null)
-        	{
-        		genericType = adapter.getField().getGenericType();
-        	}
-        	else if (adapter.getReadMethod() != null)
-        	{
-        		genericType = adapter.getReadMethod().getGenericReturnType(); 
-        	}
-        	else if (adapter.getWriteMethod() != null)
-        	{
-        		genericType = adapter.getWriteMethod().getGenericParameterTypes()[0];
-        	}
-        	else
-        	{
-        		throw new RuntimeException("Could not find accessor for property " + adapter.getName());
-        	}
-        	
-        	return genericType == null ? adapter.getType() : genericType;
-		}
-
-		private void implementSetter(PropertyAdapter adapter)
-        {
-            if (adapter.getWriteMethod() != null)
-            {
-                implementSetter(adapter.getWriteMethod());
-                return;
-            }
-
-            if (adapter.getField() != null && adapter.isUpdate())
-            {
-                implementSetter(adapter.getField());
-                return;
-            }
-
-            implementNoOpMethod(ConduitMethods.SET, "Expression '%s' for class %s is read-only.", expression,
-                    rootType.getName());
-        }
-
-        private boolean isStatic(Member member)
-        {
-            return Modifier.isStatic(member.getModifiers());
-        }
-
-        private void implementSetter(final Field field)
-        {
-            if (isStatic(field))
-            {
-                plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback()
-                {
-                    public void doBuild(InstructionBuilder builder)
-                    {
-                        builder.loadArgument(1).castOrUnbox(PlasticUtils.toTypeName(field.getType()));
-
-                        builder.putStaticField(field.getDeclaringClass().getName(), field.getName(), field.getType());
-
-                        builder.returnResult();
-                    }
-                });
-
-                return;
-            }
-
-            plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    invokeNavigateMethod(builder);
-
-                    builder.loadArgument(1).castOrUnbox(PlasticUtils.toTypeName(field.getType()));
-
-                    builder.putField(field.getDeclaringClass().getName(), field.getName(), field.getType());
-
-                    builder.returnResult();
-                }
-            });
-        }
-
-        private void implementSetter(final Method writeMethod)
-        {
-            plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    invokeNavigateMethod(builder);
-
-                    Class propertyType = writeMethod.getParameterTypes()[0];
-                    String propertyTypeName = PlasticUtils.toTypeName(propertyType);
-
-                    builder.loadArgument(1).castOrUnbox(propertyTypeName);
-
-                    builder.invoke(writeMethod);
-
-                    builder.returnResult();
-                }
-            });
-        }
-
-        private void implementGetter(PropertyAdapter adapter)
-        {
-            if (adapter.getReadMethod() != null)
-            {
-                implementGetter(adapter.getReadMethod());
-                return;
-            }
-
-            if (adapter.getField() != null)
-            {
-                implementGetter(adapter.getField());
-                return;
-            }
-
-            implementNoOpMethod(ConduitMethods.GET, "Expression '%s' for class %s is write-only.", expression,
-                    rootType.getName());
-        }
-
-        private void implementGetter(final Field field)
-        {
-            if (isStatic(field))
-            {
-                plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
-                {
-                    public void doBuild(InstructionBuilder builder)
-                    {
-                        builder.getStaticField(field.getDeclaringClass().getName(), field.getName(), field.getType());
-
-                        // Cast not necessary here since the return type of get() is Object
-
-                        boxIfPrimitive(builder, field.getType());
-
-                        builder.returnResult();
-                    }
-                });
-
-                return;
-            }
-
-            plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    invokeNavigateMethod(builder);
-
-                    builder.getField(field.getDeclaringClass().getName(), field.getName(), field.getType());
-
-                    // Cast not necessary here since the return type of get() is Object
-
-                    boxIfPrimitive(builder, field.getType());
-
-                    builder.returnResult();
-                }
-            });
-        }
-
-        private void implementGetter(final Method readMethod)
-        {
-            plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    invokeNavigateMethod(builder);
-
-                    invokeMethod(builder, readMethod, null, 0);
-
-                    boxIfPrimitive(builder, conduitPropertyType);
-
-                    builder.returnResult();
-                }
-            });
-        }
-
-        private void implementRangeOpGetter(final Tree rangeNode)
-        {
-            plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    // Put the delegate on top of the stack
-
-                    builder.loadThis().getField(getDelegateField());
-
-                    invokeMethod(builder, DelegateMethods.RANGE, rangeNode, 0);
-
-                    builder.returnResult();
-                }
-            });
-        }
-
-        /**
-         * @param node
-         *         subexpression to invert
-         */
-        private void implementNotOpGetter(final Tree node)
-        {
-            // Implement get() as navigate, then do a method invocation based on node
-            // then, then pass (wrapped) result to delegate.invert()
-
-            plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    Type expressionType = implementNotExpression(builder, node);
-
-                    // Yes, we know this will always be the case, for now.
-
-                    boxIfPrimitive(builder, expressionType);
-
-                    builder.returnResult();
-                }
-            });
-        }
-
-        /**
-         * The first part of any implementation of get() or set(): invoke the navigation method
-         * and if the result is null, return immediately.
-         */
-        private void invokeNavigateMethod(InstructionBuilder builder)
-        {
-            builder.loadThis().loadArgument(0).invokeVirtual(navMethod);
-
-            builder.dupe().when(Condition.NULL, RETURN_NULL);
-        }
-
-        /**
-         * Uses the builder to add instructions for a subexpression.
-         *
-         * @param builder
-         *         used to add instructions
-         * @param activeType
-         *         type of value on top of the stack when this code will execute, or null if no value on stack
-         * @param node
-         *         defines the expression
-         * @return the expression type
-         */
-        private Type implementSubexpression(InstructionBuilder builder, Type activeType, Tree node)
-        {
-            Term term;
-
-            while (true)
-            {
-                switch (node.getType())
-                {
-                    case IDENTIFIER:
-                    case INVOKE:
-
-                        if (activeType == null)
-                        {
-                            invokeGetRootMethod(builder);
-
-                            activeType = rootType;
-                        }
-
-                        term = buildTerm(activeType, node);
-
-                        term.callback.doBuild(builder);
-
-                        return term.type;
-
-                    case INTEGER:
-
-                        builder.loadConstant(new Long(node.getText()));
-
-                        return long.class;
-
-                    case DECIMAL:
-
-                        builder.loadConstant(new Double(node.getText()));
-
-                        return double.class;
-
-                    case STRING:
-
-                        builder.loadConstant(node.getText());
-
-                        return String.class;
-
-                    case DEREF:
-                    case SAFEDEREF:
-
-                        if (activeType == null)
-                        {
-                            invokeGetRootMethod(builder);
-
-                            activeType = rootType;
-                        }
-
-                        term = analyzeDerefNode(activeType, node);
-
-                        term.callback.doBuild(builder);
-
-                        activeType = GenericsUtils.asClass(term.type);
-
-                        node = node.getChild(1);
-
-                        break;
-
-                    case TRUE:
-                    case FALSE:
-
-                        builder.loadConstant(node.getType() == TRUE ? 1 : 0);
-
-                        return boolean.class;
-
-                    case LIST:
-
-                        return implementListConstructor(builder, node);
-
-                    case MAP:
-                        return implementMapConstructor(builder, node);
-
-                    case NOT:
-
-                        return implementNotExpression(builder, node);
-
-                    case THIS:
-
-                        invokeGetRootMethod(builder);
-
-                        return rootType;
-
-                    case NULL:
-
-                        builder.loadNull();
-
-                        return Void.class;
-
-                    default:
-                        throw unexpectedNodeType(node, TRUE, FALSE, INTEGER, DECIMAL, STRING, DEREF, SAFEDEREF,
-                                IDENTIFIER, INVOKE, LIST, NOT, THIS, NULL);
-                }
-            }
-        }
-
-        public void invokeGetRootMethod(InstructionBuilder builder)
-        {
-            builder.loadThis().loadArgument(0).invokeVirtual(getRootMethod);
-        }
-
-        private void implementListGetter(final Tree listNode)
-        {
-            plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    implementListConstructor(builder, listNode);
-
-                    builder.returnResult();
-                }
-            });
-        }
-
-        private Type implementListConstructor(InstructionBuilder builder, Tree listNode)
-        {
-            // First, create an empty instance of ArrayList
-
-            int count = listNode.getChildCount();
-
-            builder.newInstance(ArrayList.class);
-            builder.dupe().loadConstant(count).invokeConstructor(ArrayList.class, int.class);
-
-            for (int i = 0; i < count; i++)
-            {
-                builder.dupe(); // the ArrayList
-
-                Type expressionType = implementSubexpression(builder, null, listNode.getChild(i));
-
-                boxIfPrimitive(builder, GenericsUtils.asClass(expressionType));
-
-                // Add the value to the array, then pop off the returned boolean
-                builder.invoke(ArrayListMethods.ADD).pop();
-            }
-
-            return ArrayList.class;
-        }
-
-        private void implementMapGetter(final Tree mapNode)
-        {
-            plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    implementMapConstructor(builder, mapNode);
-
-                    builder.returnResult();
-                }
-            });
-        }
-
-        private Type implementMapConstructor(InstructionBuilder builder, Tree mapNode)
-        {
-            int count = mapNode.getChildCount();
-            builder.newInstance(HashMap.class);
-            builder.dupe().loadConstant(count).invokeConstructor(HashMap.class, int.class);
-
-            for (int i = 0; i < count; i += 2)
-            {
-                builder.dupe();
-
-                //build the key:
-                Type keyType = implementSubexpression(builder, null, mapNode.getChild(i));
-                boxIfPrimitive(builder, GenericsUtils.asClass(keyType));
-
-                //and the value:
-                Type valueType = implementSubexpression(builder, null, mapNode.getChild(i + 1));
-                boxIfPrimitive(builder, GenericsUtils.asClass(valueType));
-
-                //put the value into the array, then pop off the returned object.
-                builder.invoke(HashMapMethods.PUT).pop();
-
-            }
-
-            return HashMap.class;
-        }
-
-
-        private void implementNoOpSetter()
-        {
-            implementNoOpMethod(ConduitMethods.SET, "Expression '%s' for class %s is read-only.", expression,
-                    rootType.getName());
-        }
-
-        public void implementNoOpMethod(MethodDescription method, String format, Object... arguments)
-        {
-            final String message = String.format(format, arguments);
-
-            plasticClass.introduceMethod(method).changeImplementation(new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    builder.throwException(RuntimeException.class, message);
-                }
-            });
-        }
-
-        /**
-         * Invokes a method that may take parameters. The children of the invokeNode are subexpressions
-         * to be evaluated, and potentially coerced, so that they may be passed to the method.
-         *
-         * @param builder
-         *         constructs code
-         * @param method
-         *         method to invoke
-         * @param node
-         *         INVOKE or RANGEOP node
-         * @param childOffset
-         *         offset within the node to the first child expression (1 in an INVOKE node because the
-         *         first child is the method name, 0 in a RANGEOP node)
-         */
-        private void invokeMethod(InstructionBuilder builder, Method method, Tree node, int childOffset)
-        {
-            // We start with the target object for the method on top of the stack.
-            // Next, we have to push each method parameter, which may include boxing/deboxing
-            // and coercion. Once the code is in good shape, there's a lot of room to optimize
-            // the bytecode (a bit too much boxing/deboxing occurs, as well as some unnecessary
-            // trips through TypeCoercer). We might also want to have a local variable to store
-            // the root object (result of getRoot()).
-
-            Class[] parameterTypes = method.getParameterTypes();
-
-            for (int i = 0; i < parameterTypes.length; i++)
-            {
-                Type expressionType = implementSubexpression(builder, null, node.getChild(i + childOffset));
-
-                // The value left on the stack is not primitive, and expressionType represents
-                // its real type.
-
-                Class parameterType = parameterTypes[i];
-
-                if (!parameterType.isAssignableFrom(GenericsUtils.asClass(expressionType)))
-                {
-                    boxIfPrimitive(builder, expressionType);
-
-                    builder.loadThis().getField(getDelegateField());
-                    builder.swap().loadTypeConstant(PlasticUtils.toWrapperType(parameterType));
-                    builder.invoke(DelegateMethods.COERCE);
-
-                    if (parameterType.isPrimitive())
-                    {
-                        builder.castOrUnbox(parameterType.getName());
-                    } else
-                    {
-                        builder.checkcast(parameterType);
-                    }
-                }
-
-                // And that should leave an object of the correct type on the stack,
-                // ready for the method invocation.
-            }
-
-            // Now the target object and all parameters are in place.
-
-            builder.invoke(method.getDeclaringClass(), method.getReturnType(), method.getName(),
-                    method.getParameterTypes());
-        }
-
-        /**
-         * Analyzes a DEREF or SAFEDEREF node, proving back a term that identifies its type and provides a callback to
-         * peform the dereference.
-         *
-         * @return a term indicating the type of the expression to this point, and a {@link InstructionBuilderCallback}
-         *         to advance the evaluation of the expression form the previous value to the current
-         */
-        private Term analyzeDerefNode(Type activeType, Tree node)
-        {
-            // The first child is the term.
-
-            Tree term = node.getChild(0);
-
-            boolean allowNull = node.getType() == SAFEDEREF;
-
-            return buildTerm(activeType, term, allowNull ? NullHandling.ALLOW : NullHandling.FORBID);
-        }
-
-        private Term buildTerm(Type activeType, Tree term, final NullHandling nullHandling)
-        {
-            assertNodeType(term, IDENTIFIER, INVOKE);
-
-            final Term simpleTerm = buildTerm(activeType, term);
-
-            if (simpleTerm.genericType.isPrimitive())
-                return simpleTerm;
-
-            return simpleTerm.withCallback(new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    simpleTerm.callback.doBuild(builder);
-
-                    builder.dupe().when(Condition.NULL, new InstructionBuilderCallback()
-                    {
-                        public void doBuild(InstructionBuilder builder)
-                        {
-                            switch (nullHandling)
-                            {
-                                // It is necessary to load a null onto the stack (even if there's already one
-                                // there) because of the verifier. It sees the return when the stack contains an
-                                // intermediate value (along the navigation chain) and thinks the method is
-                                // returning a value of the wrong type.
-
-                                case ALLOW:
-                                    builder.loadNull().returnResult();
-
-                                case FORBID:
-
-                                    builder.loadConstant(simpleTerm.description);
-                                    builder.loadConstant(expression);
-                                    builder.loadArgument(0);
-
-                                    builder.invokeStatic(PropertyConduitSourceImpl.class, NullPointerException.class,
-                                            "nullTerm", String.class, String.class, Object.class);
-                                    builder.throwException();
-
-                                    break;
-
-                            }
-                        }
-                    });
-                }
-            });
-        }
-
-        private void assertNodeType(Tree node, int... expected)
-        {
-            int type = node.getType();
-
-            for (int e : expected)
-            {
-                if (type == e)
-                    return;
-            }
-
-            throw unexpectedNodeType(node, expected);
-        }
-
-        private RuntimeException unexpectedNodeType(Tree node, int... expected)
-        {
-            List<String> tokenNames = CollectionFactory.newList();
-
-            for (int i = 0; i < expected.length; i++)
-                tokenNames.add(PropertyExpressionParser.tokenNames[expected[i]]);
-
-            String message = String.format("Node %s was type %s, but was expected to be (one of) %s.",
-                    node.toStringTree(), PropertyExpressionParser.tokenNames[node.getType()],
-                    InternalUtils.joinSorted(tokenNames));
-
-            return new RuntimeException(message);
-        }
-
-        private Term buildTerm(Type activeType, Tree termNode)
-        {
-            switch (termNode.getType())
-            {
-                case INVOKE:
-
-                    return buildInvokeTerm(activeType, termNode);
-
-                case IDENTIFIER:
-
-                    return buildPropertyAccessTerm(activeType, termNode);
-
-                default:
-                    throw unexpectedNodeType(termNode, INVOKE, IDENTIFIER);
-            }
-        }
-
-        private Term buildPropertyAccessTerm(Type activeType, Tree termNode)
-        {
-            String propertyName = termNode.getText();
-
-            PropertyAdapter adapter = findPropertyAdapter(activeType, propertyName);
-
-            // Prefer the accessor over the field
-
-            if (adapter.getReadMethod() != null)
-            {
-                return buildGetterMethodAccessTerm(activeType, propertyName,
-                        adapter.getReadMethod());
-            }
-
-            if (adapter.getField() != null)
-            {
-                return buildPublicFieldAccessTerm(activeType, propertyName,
-                        adapter.getField());
-            }
-
-            throw new RuntimeException(String.format(
-                    "Property '%s' of class %s is not readable (it has no read accessor method).", adapter.getName(),
-                    adapter.getBeanType().getName()));
-        }
-
-        public PropertyAdapter findPropertyAdapter(Type activeType, String propertyName)
-        {
-            Class activeClass = GenericsUtils.asClass(activeType);
-
-            ClassPropertyAdapter classAdapter = access.getAdapter(activeClass);
-            PropertyAdapter adapter = classAdapter.getPropertyAdapter(propertyName);
-
-            if (adapter == null)
-            {
-                final List<String> names = classAdapter.getPropertyNames();
-                final String className = activeClass.getName();
-                throw new UnknownValueException(String.format(
-                        "Class %s does not contain a property (or public field) named '%s'.", className, propertyName),
-                        new AvailableValues("Properties (and public fields)", names));
-            }
-            return adapter;
-        }
-
-        private Term buildGetterMethodAccessTerm(final Type activeType, String propertyName, final Method readMethod)
-        {
-            Type returnType = GenericsUtils.extractActualType(activeType, readMethod);
-
-            return new Term(returnType, propertyName, new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    invokeMethod(builder, readMethod, null, 0);
-
-                    Type genericType = GenericsUtils.extractActualType(activeType, readMethod);
-
-                    castToGenericType(builder, readMethod.getReturnType(), genericType);
-                }
-            });
-        }
-
-        private Term buildPublicFieldAccessTerm(Type activeType, String propertyName, final Field field)
-        {
-            final Type fieldType = GenericsUtils.extractActualType(activeType, field);
-
-            return new Term(fieldType, propertyName, new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    Class rawFieldType = field.getType();
-
-                    String rawTypeName = PlasticUtils.toTypeName(rawFieldType);
-                    String containingClassName = field.getDeclaringClass().getName();
-                    String fieldName = field.getName();
-
-                    if (isStatic(field))
-                    {
-                        // We've gone to the trouble of loading the root object, or navigated to some other object,
-                        // but we don't need or want the instance, since it's a static field we're accessing.
-                        // Ideally, we would optimize this, and only generate and invoke the getRoot() and nav() methods as needed, but
-                        // access to public fields is relatively rare, and the cost is just the unused bytecode.
-
-                        builder.pop();
-
-                        builder.getStaticField(containingClassName, fieldName, rawTypeName);
-
-                    } else
-                    {
-                        builder.getField(containingClassName, fieldName, rawTypeName);
-                    }
-
-                    castToGenericType(builder, rawFieldType, fieldType);
-                }
-
-            });
-        }
-
-        /**
-         * Casts the results of a field read or method invocation based on generic information.
-         *
-         * @param builder
-         *         used to add instructions
-         * @param rawType
-         *         the simple type (often Object) of the field (or method return type)
-         * @param genericType
-         *         the generic Type, from which parameterizations can be determined
-         */
-        private void castToGenericType(InstructionBuilder builder, Class rawType, final Type genericType)
-        {
-            if (!genericType.equals(rawType))
-            {
-                Class castType = GenericsUtils.asClass(genericType);
-                builder.checkcast(castType);
-            }
-        }
-
-        private Term buildInvokeTerm(final Type activeType, final Tree invokeNode)
-        {
-            String methodName = invokeNode.getChild(0).getText();
-
-            int parameterCount = invokeNode.getChildCount() - 1;
-
-            Class activeClass = GenericsUtils.asClass(activeType);
-
-            final Method method = findMethod(activeClass, methodName, parameterCount);
-
-            if (method.getReturnType().equals(void.class))
-                throw new RuntimeException(String.format("Method %s.%s() returns void.", activeClass.getName(),
-                        methodName));
-
-            Type returnType = GenericsUtils.extractActualType(activeType, method);
-
-            return new Term(returnType, toUniqueId(method), InternalUtils.toAnnotationProvider(method), new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    invokeMethod(builder, method, invokeNode, 1);
-
-                    Type genericType = GenericsUtils.extractActualType(activeType, method);
-
-                    castToGenericType(builder, method.getReturnType(), genericType);
-                }
-            }
-            );
-        }
-
-        private Method findMethod(Class activeType, String methodName, int parameterCount)
-        {
-            Class searchType = activeType;
-
-            while (true)
-            {
-
-                for (Method method : searchType.getMethods())
-                {
-                    if (method.getParameterTypes().length == parameterCount
-                            && method.getName().equalsIgnoreCase(methodName))
-                        return method;
-                }
-
-                // TAP5-330
-                if (searchType != Object.class)
-                {
-                    searchType = Object.class;
-                } else
-                {
-                    throw new RuntimeException(String.format("Class %s does not contain a public method named '%s()'.",
-                            activeType.getName(), methodName));
-                }
-            }
-        }
-
-        public void boxIfPrimitive(InstructionBuilder builder, Type termType)
-        {
-            boxIfPrimitive(builder, GenericsUtils.asClass(termType));
-        }
-
-        public void boxIfPrimitive(InstructionBuilder builder, Class termType)
-        {
-            if (termType.isPrimitive())
-                builder.boxPrimitive(termType.getName());
-        }
-
-        public Class implementNotExpression(InstructionBuilder builder, final Tree notNode)
-        {
-            Type expressionType = implementSubexpression(builder, null, notNode.getChild(0));
-
-            boxIfPrimitive(builder, expressionType);
-
-            // Now invoke the delegate invert() method
-
-            builder.loadThis().getField(getDelegateField());
-
-            builder.swap().invoke(DelegateMethods.INVERT);
-
-            return boolean.class;
-        }
-
-        /**
-         * Defer creation of the delegate field unless actually needed.
-         */
-        private PlasticField getDelegateField()
-        {
-            if (delegateField == null)
-                delegateField = plasticClass.introduceField(PropertyConduitDelegate.class, "delegate").inject(
-                        sharedDelegate);
-
-            return delegateField;
-        }
-    }
-
-    public PropertyConduitSourceImpl(PropertyAccess access, @ComponentLayer
-    PlasticProxyFactory proxyFactory, TypeCoercer typeCoercer, StringInterner interner)
-    {
-        this.access = access;
-        this.proxyFactory = proxyFactory;
-        this.typeCoercer = typeCoercer;
-        this.interner = interner;
-
-        literalTrue = createLiteralConduit(Boolean.class, true);
-        literalFalse = createLiteralConduit(Boolean.class, false);
-        literalNull = createLiteralConduit(Void.class, null);
-
-        sharedDelegate = new PropertyConduitDelegate(typeCoercer);
-    }
-
-    @PostInjection
-    public void listenForInvalidations(@ComponentClasses InvalidationEventHub hub)
-    {
-        hub.clearOnInvalidation(cache);
-    }
-
-
-    public PropertyConduit create(Class rootClass, String expression)
-    {
-        assert rootClass != null;
-        assert InternalUtils.isNonBlank(expression);
-
-        MultiKey key = new MultiKey(rootClass, expression);
-
-        PropertyConduit result = cache.get(key);
-
-        if (result == null)
-        {
-            result = build(rootClass, expression);
-            cache.put(key, result);
-        }
-
-        return result;
-    }
-
-    /**
-     * Builds a subclass of {@link PropertyConduitDelegate} that implements the
-     * get() and set() methods and overrides the
-     * constructor. In a worst-case race condition, we may build two (or more)
-     * conduits for the same
-     * rootClass/expression, and it will get sorted out when the conduit is
-     * stored into the cache.
-     *
-     * @param rootClass
-     *         class of root object for expression evaluation
-     * @param expression
-     *         expression to be evaluated
-     * @return the conduit
-     */
-    private PropertyConduit build(final Class rootClass, String expression)
-    {
-        Tree tree = parse(expression);
-
-        try
-        {
-            switch (tree.getType())
-            {
-                case TRUE:
-
-                    return literalTrue;
-
-                case FALSE:
-
-                    return literalFalse;
-
-                case NULL:
-
-                    return literalNull;
-
-                case INTEGER:
-
-                    // Leading '+' may screw this up.
-                    // TODO: Singleton instance for "0", maybe "1"?
-
-                    return createLiteralConduit(Long.class, new Long(tree.getText()));
-
-                case DECIMAL:
-
-                    // Leading '+' may screw this up.
-                    // TODO: Singleton instance for "0.0"?
-
-                    return createLiteralConduit(Double.class, new Double(tree.getText()));
-
-                case STRING:
-
-                    return createLiteralConduit(String.class, tree.getText());
-
-                case RANGEOP:
-
-                    Tree fromNode = tree.getChild(0);
-                    Tree toNode = tree.getChild(1);
-
-                    // If the range is defined as integers (not properties, etc.)
-                    // then it is possible to calculate the value here, once, and not
-                    // build a new class.
-
-                    if (fromNode.getType() != INTEGER || toNode.getType() != INTEGER)
-                        break;
-
-                    int from = Integer.parseInt(fromNode.getText());
-                    int to = Integer.parseInt(toNode.getText());
-
-                    IntegerRange ir = new IntegerRange(from, to);
-
-                    return createLiteralConduit(IntegerRange.class, ir);
-
-                case THIS:
-
-                    return createLiteralThisPropertyConduit(rootClass);
-
-                default:
-                    break;
-            }
-
-            return proxyFactory.createProxy(InternalPropertyConduit.class,
-                    new PropertyConduitBuilder(rootClass, expression, tree)).newInstance();
-        } catch (Exception ex)
-        {
-            throw new PropertyExpressionException(String.format("Exception generating conduit for expression '%s': %s",
-                    expression, ExceptionUtils.toMessage(ex)), expression, ex);
-        }
-    }
-
-    private PropertyConduit createLiteralThisPropertyConduit(final Class rootClass)
-    {
-        return new PropertyConduit()
-        {
-            public Object get(Object instance)
-            {
-                return instance;
-            }
-
-            public void set(Object instance, Object value)
-            {
-                throw new RuntimeException("Literal values are not updateable.");
-            }
-
-            public Class getPropertyType()
-            {
-                return rootClass;
-            }
-            
-            public Type getPropertyGenericType()
-            {
-            	return rootClass;
-            }
-
-            public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
-            {
-                return invariantAnnotationProvider.getAnnotation(annotationClass);
-            }
-        };
-    }
-
-    private <T> PropertyConduit createLiteralConduit(Class<T> type, T value)
-    {
-        return new LiteralPropertyConduit(typeCoercer, type, invariantAnnotationProvider, interner.format(
-                "LiteralPropertyConduit[%s]", value), value);
-    }
-
-    private Tree parse(String expression)
-    {
-        InputStream is = new ByteArrayInputStream(expression.getBytes());
-
-        ANTLRInputStream ais;
-
-        try
-        {
-            ais = new ANTLRInputStream(is);
-        } catch (IOException ex)
-        {
-            throw new RuntimeException(ex);
-        }
-
-        PropertyExpressionLexer lexer = new PropertyExpressionLexer(ais);
-
-        CommonTokenStream tokens = new CommonTokenStream(lexer);
-
-        PropertyExpressionParser parser = new PropertyExpressionParser(tokens);
-
-        try
-        {
-            return (Tree) parser.start().getTree();
-        } catch (Exception ex)
-        {
-            throw new RuntimeException(String.format("Error parsing property expression '%s': %s.", expression,
-                    ex.getMessage()), ex);
-        }
-    }
-
-    /**
-     * May be invoked from fabricated PropertyConduit instances.
-     */
-    @SuppressWarnings("unused")
-    public static NullPointerException nullTerm(String term, String expression, Object root)
-    {
-        String message = String.format("Property '%s' (within property expression '%s', of %s) is null.", term,
-                expression, root);
-
-        return new NullPointerException(message);
-    }
-
-    private static String toUniqueId(Method method)
-    {
-        StringBuilder builder = new StringBuilder(method.getName()).append("(");
-        String sep = "";
-
-        for (Class parameterType : method.getParameterTypes())
-        {
-            builder.append(sep);
-            builder.append(PlasticUtils.toTypeName(parameterType));
-
-            sep = ",";
-        }
-
-        return builder.append(")").toString();
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java
deleted file mode 100644
index 7b2b7ab..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright 2006 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.util;
-
-import java.util.Iterator;
-
-/**
- * Represents a sequence of integer values, either ascending or descending. The sequence is always inclusive (of the
- * finish value).
- */
-public final class IntegerRange implements Iterable<Integer>
-{
-    private final int start;
-
-    private final int finish;
-
-    private class RangeIterator implements Iterator<Integer>
-    {
-        private final int increment;
-
-        private int value = start;
-
-        private boolean hasNext = true;
-
-        RangeIterator()
-        {
-            increment = start < finish ? +1 : -1;
-        }
-
-        public boolean hasNext()
-        {
-            return hasNext;
-        }
-
-        public Integer next()
-        {
-            if (!hasNext) throw new IllegalStateException();
-
-            int result = value;
-
-            hasNext = value != finish;
-
-            value += increment;
-
-            return result;
-        }
-
-        public void remove()
-        {
-            throw new UnsupportedOperationException();
-        }
-
-    }
-
-    public IntegerRange(final int start, final int finish)
-    {
-        this.start = start;
-        this.finish = finish;
-    }
-
-    public int getFinish()
-    {
-        return finish;
-    }
-
-    public int getStart()
-    {
-        return start;
-    }
-
-    @Override
-    public String toString()
-    {
-        return String.format("%d..%d", start, finish);
-    }
-
-    /**
-     * The main puprose of a range object is to produce an Iterator. Since IntegerRange is iterable, it is useful with
-     * the Tapestry Loop component, but also with the Java for loop!
-     */
-    public Iterator<Integer> iterator()
-    {
-        return new RangeIterator();
-    }
-
-    @Override
-    public int hashCode()
-    {
-        final int PRIME = 31;
-
-        int result = PRIME + finish;
-
-        result = PRIME * result + start;
-
-        return result;
-    }
-
-    /**
-     * Returns true if the other object is an IntegerRange with the same start and finish values.
-     */
-    @Override
-    public boolean equals(Object obj)
-    {
-        if (this == obj) return true;
-        if (obj == null) return false;
-        if (getClass() != obj.getClass()) return false;
-        final IntegerRange other = (IntegerRange) obj;
-        if (finish != other.finish) return false;
-
-        return start == other.start;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java
deleted file mode 100644
index 503bb1f..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2006 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.util;
-
-import java.util.Arrays;
-
-/**
- * Combines multiple values to form a single composite key. MultiKey can often be used as an alternative to nested
- * maps.
- */
-public final class MultiKey
-{
-    private static final int PRIME = 31;
-
-    private final Object[] values;
-
-    private final int hashCode;
-
-    /**
-     * Creates a new instance from the provided values. It is assumed that the values provided are good map keys
-     * themselves -- immutable, with proper implementations of equals() and hashCode().
-     *
-     * @param values
-     */
-    public MultiKey(Object... values)
-    {
-        this.values = values;
-
-        hashCode = PRIME * Arrays.hashCode(this.values);
-    }
-
-    @Override
-    public int hashCode()
-    {
-        return hashCode;
-    }
-
-    @Override
-    public boolean equals(Object obj)
-    {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        final MultiKey other = (MultiKey) obj;
-
-        return Arrays.equals(values, other.values);
-    }
-
-    @Override
-    public String toString()
-    {
-        StringBuilder builder = new StringBuilder("MultiKey[");
-
-        boolean first = true;
-
-        for (Object o : values)
-        {
-            if (!first)
-                builder.append(", ");
-
-            builder.append(o);
-
-            first = false;
-        }
-
-        builder.append("]");
-
-        return builder.toString();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/services/BeanModelSource.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/BeanModelSource.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/BeanModelSource.java
deleted file mode 100644
index 16b4fca..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/BeanModelSource.java
+++ /dev/null
@@ -1,70 +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.services;
-
-import org.apache.tapestry5.beaneditor.BeanModel;
-import org.apache.tapestry5.ioc.Messages;
-
-/**
- * Used by a component to create a default {@link org.apache.tapestry5.beaneditor.BeanModel} for a particular bean
- * class. Also provides support to the model by generating validation information for individual fields.
- * <p/>
- * BeanModels are the basis for the {@link org.apache.tapestry5.corelib.components.BeanEditor} and {@link
- * org.apache.tapestry5.corelib.components.Grid} comopnents.
- *
- * @see org.apache.tapestry5.services.PropertyConduitSource
- */
-public interface BeanModelSource
-{
-    /**
-     * Creates a new model used for editing the indicated bean class. The model will represent all read/write properties
-     * of the bean. The order of properties is determined from the order of the getter methods in the code, and can be
-     * overridden with the {@link org.apache.tapestry5.beaneditor.ReorderProperties} annotation. The labels for the
-     * properties are derived from the property names, but if the component's message catalog has keys of the form
-     * <code>propertyName-label</code>, then those will be used instead.
-     * <p/>
-     * Models are <em>mutable</em>, so they are not cached, a fresh instance is created each time.
-     *
-     * @param beanClass                class of object to be edited
-     * @param filterReadOnlyProperties if true, then properties that are read-only will be skipped (leaving only
-     *                                 read-write properties, appropriate for {@link org.apache.tapestry5.corelib.components.BeanEditForm},
-     *                                 etc.). If false, then both read-only and read-write properties will be included
-     *                                 (appropriate for {@link org.apache.tapestry5.corelib.components.Grid} or {@link
-     *                                 org.apache.tapestry5.corelib.components.BeanDisplay}).
-     * @param messages                 Used to find explicit overrides of
-     * @return a model
-     * @deprecated use {@link #createDisplayModel(Class, org.apache.tapestry5.ioc.Messages)} or {@link
-     *             #createEditModel(Class, org.apache.tapestry5.ioc.Messages)}
-     */
-    <T> BeanModel<T> create(Class<T> beanClass, boolean filterReadOnlyProperties, Messages messages);
-
-    /**
-     * Creates a model for display purposes; this may include properties which are read-only.
-     *
-     * @param beanClass class of object to be edited
-     * @param messages
-     * @return a model containing properties that can be presented to the user
-     */
-    <T> BeanModel<T> createDisplayModel(Class<T> beanClass, Messages messages);
-
-    /**
-     * Creates a model for edit and update purposes, only properties that are fully read-write are included.
-     *
-     * @param beanClass class of object to be edited
-     * @param messages
-     * @return a model containing properties that can be presented to the user
-     */
-    <T> BeanModel<T> createEditModel(Class<T> beanClass, Messages messages);
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClasses.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClasses.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClasses.java
deleted file mode 100644
index c901d3a..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClasses.java
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 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.services;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Marker annotation used to inject the correct {@link org.apache.tapestry5.services.InvalidationEventHub} service
- * responsible for invalidations when underlying component class files are changed.
- * 
- * @since 5.1.0.0
- */
-@Target(
-{ ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD })
-@Retention(RetentionPolicy.RUNTIME)
-@Documented
-public @interface ComponentClasses
-{
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentLayer.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentLayer.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentLayer.java
deleted file mode 100644
index e342c3f..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentLayer.java
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2007 The Apache Software Foundation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.apache.tapestry5.services;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.PARAMETER;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-/**
- * Marker annotation used to identify a service from the component layer that conflicts, in terms of service interface,
- * with a service from elsewhere. In particular, this is used to disambiguate {@link org.apache.tapestry5.ioc.services.PlasticProxyFactory} which has one implementation (marked with {@link
- * org.apache.tapestry5.ioc.services.Builtin} and another with this annotation.
- */
-@Target(
-        {PARAMETER, FIELD})
-@Retention(RUNTIME)
-@Documented
-public @interface ComponentLayer
-{
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java
deleted file mode 100644
index 77b028e..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2006, 2007, 2008, 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.services;
-
-import java.util.Map;
-
-/**
- * An object which manages a list of {@link org.apache.tapestry5.services.InvalidationListener}s. There are multiple
- * event hub services implementing this interface, each with a specific marker annotation; each can register listeners
- * and fire events; these are based on the type of resource that has been invalidated. Tapestry has built-in support
- * for:
- * <dl>
- * <dt>message catalog resources
- * <dd>{@link org.apache.tapestry5.services.ComponentMessages} marker annotation
- * <dt>component templates
- * <dd>{@link org.apache.tapestry5.services.ComponentTemplates} marker annotation
- * <dt>component classes
- * <dd>{@link org.apache.tapestry5.services.ComponentClasses} marker annotation
- * </dl>
- * <p/>
- * Starting in Tapestry 5.3, these services are disabled in production (it does nothing).
- *
- * @since 5.1.0.0
- */
-public interface InvalidationEventHub
-{
-    /**
-     * Adds a listener, who needs to know when an underlying resource of a given category has changed (so that the
-     * receiver may discard any cached data that may have been invalidated). Does nothing in production mode.
-     *
-     * @deprecated in 5.4, use {@link #addInvalidationCallback(Runnable)} instead}
-     */
-    void addInvalidationListener(InvalidationListener listener);
-
-    /**
-     * Adds a callback that is invoked when an underlying tracked resource has changed. Does nothing in production mode.
-     *
-     * @since  5.4
-     */
-    void addInvalidationCallback(Runnable callback);
-
-    /**
-     * Adds a callback that clears the map.
-     *
-     * @since 5.4
-     */
-    void clearOnInvalidation(Map<?,?> map);
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationListener.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationListener.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationListener.java
deleted file mode 100644
index b9b4aa3..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationListener.java
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2006, 2007, 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.services;
-
-/**
- * Interface for objects that may cache information that can be invalidated. Invalidation occurs when external files,
- * from which in-memory data is cached, is determined to have changed. Granularity is very limited; when any external
- * file is found to have changed, the event is fired (with the expectation that the cleared cache will be repopulated as
- * necessary).
- *
- * @see org.apache.tapestry5.services.InvalidationEventHub
- * @since 5.1.0.0
- * @deprecated In 5.4; use {@link InvalidationEventHub#addInvalidationCallback(Runnable)} instead
- */
-public interface InvalidationListener
-{
-    /**
-     * Invoked to indicate that some object is invalid. The receiver should clear its cache.
-     */
-    void objectWasInvalidated();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java
deleted file mode 100644
index 312cd60..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2007, 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.services;
-
-import org.apache.tapestry5.PropertyConduit;
-
-/**
- * A source for {@link org.apache.tapestry5.PropertyConduit}s, which can be thought of as a compiled property path
- * expression. PropertyConduits are the basis of the "prop:" binding factory, thus this service defines the expression
- * format used by the {@link org.apache.tapestry5.internal.bindings.PropBindingFactory}.
- */
-public interface PropertyConduitSource
-{
-    /**
-     * Returns a property conduit instance for the given expression. PropertyConduitSource caches the conduits it
-     * returns, so despite the name, this method does not always create a <em>new</em> conduit. The cache is cleared if
-     * a change to component classes is observed.
-     * <p/>
-     * Callers of this method should observe notifications from the {@link org.apache.tapestry5.services.InvalidationEventHub}
-     * for {@link org.apache.tapestry5.services.ComponentClasses} and discard any aquired conduits; failure to do so
-     * will create memory leaks whenever component classes change (the conduits will keep references to the old classes
-     * and classloaders).
-     *
-     * @param rootType   the type of the root object to which the expression is applied
-     * @param expression expression to be evaluated on instances of the root class
-     * @return RuntimeException if the expression is invalid (poorly formed, references non-existent properties, etc.)
-     */
-    PropertyConduit create(Class rootType, String expression);
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/build.gradle
----------------------------------------------------------------------
diff --git a/tapestry-ioc/build.gradle b/tapestry-ioc/build.gradle
index e890f7e..5a5321f 100644
--- a/tapestry-ioc/build.gradle
+++ b/tapestry-ioc/build.gradle
@@ -4,6 +4,7 @@ dependencies {
     compile project(':tapestry-func')
     compile project(':tapestry5-annotations')
     compile project(":plastic")
+    compile project(":beanmodel")
 
     provided project(':tapestry-test')
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java
deleted file mode 100644
index 1f0e744..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2007, 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;
-
-import java.lang.annotation.Annotation;
-
-/**
- * A source of annotations. This interface is used to mask where the annotations come from (for example, from a Method,
- * a Class, or some other source).
- */
-public interface AnnotationProvider
-{
-    /**
-     * Searches for the specified annotation, returning the matching annotation instance.
-     *
-     * @param <T>
-     * @param annotationClass used to select the annotation to return
-     * @return the annotation, or null if not found
-     */
-    <T extends Annotation> T getAnnotation(Class<T> annotationClass);
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Locatable.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Locatable.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Locatable.java
deleted file mode 100644
index 37b6551..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Locatable.java
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2006, 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;
-
-/**
- * Interface implemented by objects which carry a location tag. Defines a readable property, location.
- */
-@SuppressWarnings({"JavaDoc"})
-public interface Locatable
-{
-    /**
-     * Returns the location associated with this object for error reporting purposes.
-     */
-    Location getLocation();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Location.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Location.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Location.java
deleted file mode 100644
index e6688c2..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Location.java
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2006 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;
-
-/**
- * A kind of tag applied to other objects to identify where they came from, in terms of a file (the resource), a line
- * number, and a column number. This is part of "line precise exception reporting", whereby errors at runtime can be
- * tracked backwards to the files from which they were parsed or otherwise constructed.
- */
-public interface Location
-{
-    /**
-     * The resource from which the object tagged with a location was derived.
-     */
-    Resource getResource();
-
-    /**
-     * The line number within the resource, if known, or -1 otherwise.
-     */
-    int getLine();
-
-    /**
-     * The column number within the line if known, or -1 otherwise.
-     */
-    int getColumn();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java
deleted file mode 100644
index e90eb65..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2006 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;
-
-/**
- * Obtained from a {@link org.apache.tapestry5.ioc.Messages}, used to format messages for a specific localized message
- * key.
- */
-public interface MessageFormatter
-{
-    /**
-     * Formats the message. The arguments are passed to {@link java.util.Formatter} as is with one exception: Object of
-     * type {@link Throwable} are converted to their {@link Throwable#getMessage()} (or, if that is null, to the name of
-     * the class).
-     *
-     * @param args
-     * @return formatted string
-     */
-    String format(Object... args);
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Messages.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Messages.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Messages.java
deleted file mode 100644
index ba7452c..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Messages.java
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2006, 2007, 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;
-
-import java.util.Set;
-
-/**
- * Provides access to a messages catalog, a set of properties files that provide localized messages for a particular
- * locale. The message catalog consists of keys and values and follows the semantics of a Java {@link
- * java.util.ResourceBundle} with some changes.
- */
-public interface Messages
-{
-    /**
-     * Returns true if the bundle contains the named key.
-     */
-    boolean contains(String key);
-
-    /**
-     * Returns the localized message for the given key. If catalog does not contain such a key, then a modified version
-     * of the key is returned (converted to upper case and enclosed in brackets).
-     *
-     * @param key
-     * @return localized message for key, or placeholder
-     */
-    String get(String key);
-
-    /**
-     * Returns a formatter for the message, which can be used to substitute arguments (as per {@link
-     * java.util.Formatter}).
-     *
-     * @param key
-     * @return formattable object
-     */
-    MessageFormatter getFormatter(String key);
-
-    /**
-     * Convenience for accessing a formatter and formatting a localized message with arguments.
-     */
-    String format(String key, Object... args);
-
-    /**
-     * Returns a set of all the keys for which this instance may provide a value.
-     *
-     * @return set of keys
-     * @since 5.4
-     */
-    Set<String> getKeys();
-}


[07/15] tapestry-5 git commit: First pass creating the BeanModel and Commons packages. Lots of stuff moved around, but no actual code changes so far

Posted by th...@apache.org.
First pass creating the BeanModel and Commons packages. Lots of stuff moved around, but no actual code changes so far


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

Branch: refs/heads/beanmodel-split
Commit: f963c7ab7ebaf1b4b0349c9875a5490a85d75dd0
Parents: 09a011c
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Sat Dec 6 15:16:02 2014 -0200
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Sat Dec 6 15:16:02 2014 -0200

----------------------------------------------------------------------
 beanmodel/build.gradle                          |   27 +
 .../org/apache/tapestry5/PropertyConduit.java   |   45 +
 .../org/apache/tapestry5/PropertyConduit2.java  |   40 +
 .../apache/tapestry5/beaneditor/BeanModel.java  |  169 ++
 .../tapestry5/beaneditor/PropertyModel.java     |   97 ++
 .../internal/InternalPropertyConduit.java       |   37 +
 .../internal/beaneditor/BeanModelImpl.java      |  289 ++++
 .../internal/beaneditor/PropertyModelImpl.java  |  139 ++
 .../CoercingPropertyConduitWrapper.java         |   67 +
 .../services/PropertyConduitDelegate.java       |   53 +
 .../services/PropertyConduitSourceImpl.java     | 1563 ++++++++++++++++++
 .../tapestry5/services/BeanModelSource.java     |   70 +
 .../services/PropertyConduitSource.java         |   41 +
 commons/build.gradle                            |   18 +
 .../tapestry5/internal/util/IntegerRange.java   |  125 ++
 .../tapestry5/internal/util/MultiKey.java       |   86 +
 .../tapestry5/ioc/AnnotationProvider.java       |   33 +
 .../org/apache/tapestry5/ioc/Locatable.java     |   27 +
 .../java/org/apache/tapestry5/ioc/Location.java |   38 +
 .../apache/tapestry5/ioc/MessageFormatter.java  |   32 +
 .../java/org/apache/tapestry5/ioc/Messages.java |   61 +
 .../org/apache/tapestry5/ioc/ObjectLocator.java |  143 ++
 .../java/org/apache/tapestry5/ioc/Resource.java |  108 ++
 .../ioc/internal/NullAnnotationProvider.java    |   35 +
 .../ioc/internal/util/CollectionFactory.java    |  139 ++
 .../ioc/internal/util/GenericsUtils.java        |  615 +++++++
 .../ioc/internal/util/TapestryException.java    |   75 +
 .../ioc/services/ClassPropertyAdapter.java      |   79 +
 .../apache/tapestry5/ioc/services/Coercion.java |   31 +
 .../tapestry5/ioc/services/CoercionTuple.java   |  145 ++
 .../tapestry5/ioc/services/PropertyAccess.java  |   77 +
 .../tapestry5/ioc/services/PropertyAdapter.java |  121 ++
 .../tapestry5/ioc/services/TypeCoercer.java     |   88 +
 .../tapestry5/ioc/util/AvailableValues.java     |   87 +
 .../tapestry5/ioc/util/CaseInsensitiveMap.java  |  499 ++++++
 .../tapestry5/ioc/util/ExceptionUtils.java      |  115 ++
 .../ioc/util/UnknownValueException.java         |   47 +
 .../services/InvalidationEventHub.java          |   60 +
 .../services/InvalidationListener.java          |   33 +
 settings.gradle                                 |    2 +-
 tapestry-core/build.gradle                      |    6 +-
 .../org/apache/tapestry5/PropertyConduit.java   |   45 -
 .../org/apache/tapestry5/PropertyConduit2.java  |   40 -
 .../apache/tapestry5/beaneditor/BeanModel.java  |  169 --
 .../tapestry5/beaneditor/PropertyModel.java     |   97 --
 .../internal/InternalPropertyConduit.java       |   37 -
 .../internal/beaneditor/BeanModelImpl.java      |  289 ----
 .../internal/beaneditor/PropertyModelImpl.java  |  139 --
 .../CoercingPropertyConduitWrapper.java         |   67 -
 .../services/PropertyConduitDelegate.java       |   53 -
 .../services/PropertyConduitSourceImpl.java     | 1563 ------------------
 .../tapestry5/internal/util/IntegerRange.java   |  125 --
 .../tapestry5/internal/util/MultiKey.java       |   86 -
 .../tapestry5/services/BeanModelSource.java     |   70 -
 .../tapestry5/services/ComponentClasses.java    |   35 -
 .../tapestry5/services/ComponentLayer.java      |   37 -
 .../services/InvalidationEventHub.java          |   60 -
 .../services/InvalidationListener.java          |   33 -
 .../services/PropertyConduitSource.java         |   41 -
 tapestry-ioc/build.gradle                       |    1 +
 .../tapestry5/ioc/AnnotationProvider.java       |   33 -
 .../org/apache/tapestry5/ioc/Locatable.java     |   27 -
 .../java/org/apache/tapestry5/ioc/Location.java |   38 -
 .../apache/tapestry5/ioc/MessageFormatter.java  |   32 -
 .../java/org/apache/tapestry5/ioc/Messages.java |   61 -
 .../org/apache/tapestry5/ioc/ObjectLocator.java |  143 --
 .../java/org/apache/tapestry5/ioc/Resource.java |  108 --
 .../ioc/annotations/UsesConfiguration.java      |   34 -
 .../ioc/internal/NullAnnotationProvider.java    |   35 -
 .../ioc/internal/util/CollectionFactory.java    |  139 --
 .../ioc/internal/util/GenericsUtils.java        |  615 -------
 .../ioc/internal/util/TapestryException.java    |   75 -
 .../ioc/services/ClassPropertyAdapter.java      |   79 -
 .../apache/tapestry5/ioc/services/Coercion.java |   31 -
 .../tapestry5/ioc/services/CoercionTuple.java   |  145 --
 .../tapestry5/ioc/services/PropertyAccess.java  |   77 -
 .../tapestry5/ioc/services/PropertyAdapter.java |  121 --
 .../tapestry5/ioc/services/TypeCoercer.java     |   88 -
 .../tapestry5/ioc/util/AvailableValues.java     |   87 -
 .../tapestry5/ioc/util/CaseInsensitiveMap.java  |  499 ------
 .../tapestry5/ioc/util/ExceptionUtils.java      |  115 --
 .../ioc/util/UnknownValueException.java         |   47 -
 tapestry5-annotations/build.gradle              |    2 +-
 .../ioc/annotations/UsesConfiguration.java      |   34 +
 .../tapestry5/services/ComponentClasses.java    |   35 +
 .../tapestry5/services/ComponentLayer.java      |   37 +
 86 files changed, 5664 insertions(+), 5622 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/beanmodel/build.gradle
----------------------------------------------------------------------
diff --git a/beanmodel/build.gradle b/beanmodel/build.gradle
new file mode 100644
index 0000000..ccdeb37
--- /dev/null
+++ b/beanmodel/build.gradle
@@ -0,0 +1,27 @@
+import org.gradle.plugins.ide.idea.model.*
+import t5build.*
+
+description = "Fast class property discovery, reading and writing library based on bytecode generation. Extracted from Apache Tapestry, but not dependent on the Web framework (tapestry-core) not the IoC one (tapestry-ioc)."
+
+//apply plugin: JavaPlugin
+
+buildDir = 'target/gradle-build'
+       
+project.ext.libraryVersions = [
+	jcache: '1.0.0',
+]
+
+dependencies {
+	compile project(":plastic")
+	compile project(":tapestry5-annotations")
+	compile project(":commons")
+	// Transitive will bring in the unwanted string template library as well
+	compile "org.antlr:antlr-runtime:3.5.2", {
+		exclude group: "org.antlr", module: "stringtemplate"
+	}
+}
+
+jar {	
+	manifest {	
+	}
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit.java b/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit.java
new file mode 100644
index 0000000..3dbb0c0
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit.java
@@ -0,0 +1,45 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+
+/**
+ * Used to read or update the value associated with a property. A PropertyConduit provides access to the annotations on
+ * the underlying getter and/or setter methods.
+ */
+public interface PropertyConduit extends AnnotationProvider
+{
+    /**
+     * Reads the property from the instance.
+     *
+     * @param instance object containing the property
+     * @return the current value of the property
+     */
+    Object get(Object instance);
+
+    /**
+     * Changes the current value of the property.
+     *
+     * @param instance object containing the property
+     * @param value    to change the property to
+     */
+    void set(Object instance, Object value);
+
+    /**
+     * Returns the type of the property read or updated by the conduit.
+     */
+    Class getPropertyType();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit2.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit2.java b/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit2.java
new file mode 100644
index 0000000..839d70f
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit2.java
@@ -0,0 +1,40 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+
+import org.apache.tapestry5.services.PropertyConduitSource;
+
+
+/**
+ * Extension to {@link PropertyConduit} that adds a method to access the generic property type.
+ * {@link PropertyConduitSource} instances should ideally return PropertyConduit2 objects, not PropertyConduit.
+ * This is only primarily of interest to {@link Binding2}.
+ * 
+ * @since 5.4
+ */
+public interface PropertyConduit2 extends PropertyConduit
+{
+    /**
+     * Returns the generic type of the property
+     * 
+     * @see Method#getGenericReturnType()
+     * @see java.lang.reflect.Field#getGenericType()
+     * 
+     */
+	Type getPropertyGenericType();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModel.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModel.java b/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModel.java
new file mode 100644
index 0000000..0a60fd7
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModel.java
@@ -0,0 +1,169 @@
+// Copyright 2007, 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.beaneditor;
+
+import org.apache.tapestry5.PropertyConduit;
+
+import java.util.List;
+
+/**
+ * Provides the information necessary to build a user interface to view, create or edit an instance of a particular
+ * type.
+ * <p/>
+ * BeanModels are not thread-safe, they are also not serializable.
+ * <p/>
+ * Here, and in {@link org.apache.tapestry5.beaneditor.PropertyModel}, the term "propertyName" is used for simplicitly.
+ * However, a full {@linkplain org.apache.tapestry5.services.PropertyConduitSource#create(Class, String) property
+ * expression} may be utilized when {@linkplain #add(String) adding new properties to an existing BeanModel}.
+ *
+ * @see org.apache.tapestry5.services.BeanModelSource
+ */
+public interface BeanModel<T>
+{
+    /**
+     * Returns the type of bean for which this model was initially created.
+     */
+    Class<T> getBeanType();
+
+
+    /**
+     * Creates a new bean instance.  This is based on {@link org.apache.tapestry5.ioc.ObjectLocator#autobuild(Class)},
+     * so a public constructor will be used, and dependencies injected.
+     *
+     * @return new instance of the bean
+     */
+    T newInstance();
+
+    /**
+     * Returns a list of the editable properties of the bean, in <em>presentation</em> order.
+     */
+    List<String> getPropertyNames();
+
+    /**
+     * Returns the named model.
+     *
+     * @param propertyName name of property to retrieve model for (case is ignored)
+     * @return the model for the property
+     * @throws RuntimeException if the bean editor model does not have a property model for the provided name
+     */
+    PropertyModel get(String propertyName);
+
+    /**
+     * Returns the identified model.  Property ids are a stripped version of the property name. Case is ignored.
+     *
+     * @param propertyId matched caselessly against {@link org.apache.tapestry5.beaneditor.PropertyModel#getId()}
+     * @throws RuntimeException if the bean editor model does not have a property model with the indicated id
+     */
+    PropertyModel getById(String propertyId);
+
+    /**
+     * Adds a new property to the model, returning its mutable model for further refinement. The property is added to
+     * the <em>end</em> of the list of properties. The property must be real (but may have been excluded if there was no
+     * {@linkplain org.apache.tapestry5.beaneditor.DataType datatype} associated with the property). To add a synthetic
+     * property, use {@link #add(String, org.apache.tapestry5.PropertyConduit)}
+     *
+     * @param propertyName name of property to add
+     * @return the new property model (for further configuration)
+     * @throws RuntimeException if the property already exists
+     */
+    PropertyModel add(String propertyName);
+
+
+    /**
+     * Adds a new synthetic property to the model, returning its mutable model for further refinement. The property is added to
+     * the <em>end</em> of the list of properties.
+     *
+     * @param propertyName name of property to add
+     * @param expression   expression for the property
+     * @return the new property model (for further configuration)
+     * @throws RuntimeException if the property already exists
+     * @since 5.3
+     */
+    PropertyModel addExpression(String propertyName, String expression);
+
+    /**
+     * Adds an empty property (one with no property conduit).
+     *
+     * @param propertyName name of property to add
+     * @return the new property model (for further configuration)
+     * @throws RuntimeException if the property already exists
+     * @since 5.3
+     */
+    PropertyModel addEmpty(String propertyName);
+
+    /**
+     * Adds a new property to the model (as with {@link #add(String)}), ordered before or after an existing property.
+     *
+     * @param position             controls whether the new property is ordered before or after the existing property
+     * @param existingPropertyName the name of an existing property (this must exist)
+     * @param propertyName         the new property to add
+     * @return the new property model (for further configuration)
+     * @throws RuntimeException if the existing property does not exist, or if the new property already does exist
+     */
+    PropertyModel add(RelativePosition position, String existingPropertyName, String propertyName);
+
+    /**
+     * Adds a new property to the model, ordered before or after an existing property.
+     *
+     * @param position             controls whether the new property is ordered before or after the existing property
+     * @param existingPropertyName the name of an existing property (this must exist)
+     * @param propertyName         the new property to add
+     * @param conduit              conduit used to read or update the property; this may be null for a synthetic or
+     *                             placeholder property
+     * @return the new property model (for further configuration)
+     * @throws RuntimeException if the existing property does not exist, or if the new property already does exist
+     */
+    PropertyModel add(RelativePosition position, String existingPropertyName, String propertyName,
+                      PropertyConduit conduit);
+
+    /**
+     * Adds a new, synthetic property to the model, returning its mutable model for further refinement.
+     *
+     * @param propertyName name of property to add
+     * @param conduit      the conduit used to read or update the property; this may be null for a synthetic or
+     *                     placeholder property.  Instead of passing null, please invoke {@link #addEmpty(String)}.
+     * @return the model for the property
+     * @throws RuntimeException if the property already exists
+     * @see #addExpression(String, String)
+     */
+    PropertyModel add(String propertyName, PropertyConduit conduit);
+
+    /**
+     * Removes the named properties from the model, if present. It is not considered an error to remove a property that
+     * does not exist.
+     *
+     * @param propertyNames the names of properties to be removed (case insensitive)
+     * @return the model for further modifications
+     */
+    BeanModel<T> exclude(String... propertyNames);
+
+    /**
+     * Re-orders the properties of the model into the specified order. Existing properties that are not indicated are
+     * retained, but ordered to the end of the list.
+     *
+     * @param propertyNames property names in order they should be displayed (case insensitive)
+     * @return the model for further modifications
+     */
+    BeanModel<T> reorder(String... propertyNames);
+
+    /**
+     * Re-orders the properties of the model into the specified order. Existing properties that are not indicated are
+     * <<removed>>.
+     *
+     * @param propertyNames the names of properties to be retained
+     * @return the model for further modifications
+     */
+    BeanModel<T> include(String... propertyNames);
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/PropertyModel.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/PropertyModel.java b/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/PropertyModel.java
new file mode 100644
index 0000000..6095fb9
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/PropertyModel.java
@@ -0,0 +1,97 @@
+// 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.beaneditor;
+
+import org.apache.tapestry5.PropertyConduit;
+import org.apache.tapestry5.ioc.AnnotationProvider;
+
+/**
+ * Part of a {@link org.apache.tapestry5.beaneditor.BeanModel} that defines the attributes of a single property of a
+ * bean.
+ * <p/>
+ * <p/>
+ * A PropertyModel is also an {@link AnnotationProvider}, as long as the {@link org.apache.tapestry5.PropertyConduit} is
+ * non-null.  When there is no property conduit, then {@link org.apache.tapestry5.ioc.AnnotationProvider#getAnnotation(Class)}
+ * will return null.
+ */
+public interface PropertyModel extends AnnotationProvider
+{
+    /**
+     * Returns the name of the property (which may, in fact, be a property expression).
+     */
+    String getPropertyName();
+
+    /**
+     * Returns the id used to access other resources (this is based on the property name, but with any excess
+     * punctuation stripped out).
+     */
+    String getId();
+
+    /**
+     * Returns a user-presentable label for the property.
+     */
+    String getLabel();
+
+    /**
+     * Returns the type of the property.
+     */
+    Class getPropertyType();
+
+    /**
+     * Returns a logical name for the type of UI needed to view or edit the property. This is initially determined from
+     * the property type.
+     */
+    String getDataType();
+
+    /**
+     * Changes the data type for the property.
+     *
+     * @param dataType
+     * @return the property model, for further changes
+     */
+    PropertyModel dataType(String dataType);
+
+    /**
+     * Returns an object used to read or update the property. For virtual properties (properties that do not actually
+     * exist on the bean), the conduit may be null.
+     */
+    PropertyConduit getConduit();
+
+    /**
+     * Changes the label for the property to the provided value.
+     *
+     * @param label new label for property
+     * @return the property model, for further changes
+     */
+    PropertyModel label(String label);
+
+    /**
+     * Returns the containing model, often used for "fluent" construction of the model.
+     */
+    BeanModel model();
+
+    /**
+     * Returns true if the property can be used for sorting. By default, this is true only if the property type
+     * implements Comparable.
+     */
+    boolean isSortable();
+
+    /**
+     * Updates sortable and returns the model for further changes.
+     *
+     * @return the property model, for further changes
+     */
+    PropertyModel sortable(boolean sortable);
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalPropertyConduit.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalPropertyConduit.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalPropertyConduit.java
new file mode 100644
index 0000000..315b372
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalPropertyConduit.java
@@ -0,0 +1,37 @@
+// Copyright 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.internal;
+
+import org.apache.tapestry5.PropertyConduit2;
+
+
+/**
+ * Extension to {@link org.apache.tapestry5.PropertyConduit2} that adds a method to determine the name of the property.
+ * 
+ * @since 5.2.0
+ *
+ */
+public interface InternalPropertyConduit extends PropertyConduit2
+{
+    /**
+     * Returns the name of the property read or updated by the conduit or null. 
+     * If the expression points to a property on a bean (e.g. user.name) this method returns the last property in the chain. 
+     * Otherwise this method returns {@code null}.
+     * 
+     * @return property name or {@code null}
+     * 
+     */
+    String getPropertyName();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/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
new file mode 100644
index 0000000..26eb309
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
@@ -0,0 +1,289 @@
+// Copyright 2007, 2008, 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.internal.beaneditor;
+
+import org.apache.tapestry5.PropertyConduit;
+import org.apache.tapestry5.beaneditor.BeanModel;
+import org.apache.tapestry5.beaneditor.PropertyModel;
+import org.apache.tapestry5.beaneditor.RelativePosition;
+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.InternalUtils;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
+import org.apache.tapestry5.ioc.util.AvailableValues;
+import org.apache.tapestry5.ioc.util.UnknownValueException;
+import org.apache.tapestry5.plastic.PlasticUtils;
+import org.apache.tapestry5.services.PropertyConduitSource;
+
+import java.util.List;
+import java.util.Map;
+
+public class BeanModelImpl<T> implements BeanModel<T>
+{
+    private final Class<T> beanType;
+
+    private final PropertyConduitSource propertyConduitSource;
+
+    private final TypeCoercer typeCoercer;
+
+    private final Messages messages;
+
+    private final ObjectLocator locator;
+
+    private final Map<String, PropertyModel> properties = CollectionFactory.newCaseInsensitiveMap();
+
+    // The list of property names, in desired order (generally not alphabetical order).
+
+    private final List<String> propertyNames = CollectionFactory.newList();
+
+    private static PropertyConduit NULL_PROPERTY_CONDUIT = null;
+
+    public BeanModelImpl(Class<T> beanType, PropertyConduitSource propertyConduitSource, TypeCoercer typeCoercer,
+                         Messages messages, ObjectLocator locator)
+
+    {
+        this.beanType = beanType;
+        this.propertyConduitSource = propertyConduitSource;
+        this.typeCoercer = typeCoercer;
+        this.messages = messages;
+        this.locator = locator;
+    }
+
+    public Class<T> getBeanType()
+    {
+        return beanType;
+    }
+
+    public T newInstance()
+    {
+        return locator.autobuild("Instantiating new instance of " + beanType.getName(), beanType);
+    }
+
+    public PropertyModel add(String propertyName)
+    {
+        return addExpression(propertyName, propertyName);
+    }
+
+    public PropertyModel addEmpty(String propertyName)
+    {
+        return add(propertyName, NULL_PROPERTY_CONDUIT);
+    }
+
+    public PropertyModel addExpression(String propertyName, String expression)
+    {
+        PropertyConduit conduit = createConduit(expression);
+
+        return add(propertyName, conduit);
+
+    }
+
+    private void validateNewPropertyName(String propertyName)
+    {
+        assert InternalUtils.isNonBlank(propertyName);
+        if (properties.containsKey(propertyName))
+            throw new RuntimeException(String.format(
+                    "Bean editor model for %s already contains a property model for property '%s'.",
+                    beanType.getName(), propertyName));
+    }
+
+    public PropertyModel add(RelativePosition position, String existingPropertyName, String propertyName,
+                             PropertyConduit conduit)
+    {
+        assert position != null;
+        validateNewPropertyName(propertyName);
+
+        // Locate the existing one.
+
+        PropertyModel existing = get(existingPropertyName);
+
+        // Use the case normalized property name.
+
+        int pos = propertyNames.indexOf(existing.getPropertyName());
+
+        PropertyModel newModel = new PropertyModelImpl(this, propertyName, conduit, messages);
+
+        properties.put(propertyName, newModel);
+
+        int offset = position == RelativePosition.AFTER ? 1 : 0;
+
+        propertyNames.add(pos + offset, propertyName);
+
+        return newModel;
+    }
+
+    public PropertyModel add(RelativePosition position, String existingPropertyName, String propertyName)
+    {
+        PropertyConduit conduit = createConduit(propertyName);
+
+        return add(position, existingPropertyName, propertyName, conduit);
+    }
+
+    public PropertyModel add(String propertyName, PropertyConduit conduit)
+    {
+        validateNewPropertyName(propertyName);
+
+        PropertyModel propertyModel = new PropertyModelImpl(this, propertyName, conduit, messages);
+
+        properties.put(propertyName, propertyModel);
+
+        // Remember the order in which the properties were added.
+
+        propertyNames.add(propertyName);
+
+        return propertyModel;
+    }
+
+    private CoercingPropertyConduitWrapper createConduit(String propertyName)
+    {
+        return new CoercingPropertyConduitWrapper(propertyConduitSource.create(beanType, propertyName), typeCoercer);
+    }
+
+    public PropertyModel get(String propertyName)
+    {
+        PropertyModel propertyModel = properties.get(propertyName);
+
+        if (propertyModel == null)
+            throw new UnknownValueException(String.format(
+                    "Bean editor model for %s does not contain a property named '%s'.", beanType.getName(),
+                    propertyName), new AvailableValues("Defined properties", propertyNames));
+
+        return propertyModel;
+    }
+
+    public PropertyModel getById(String propertyId)
+    {
+        for (PropertyModel model : properties.values())
+        {
+            if (model.getId().equalsIgnoreCase(propertyId))
+                return model;
+        }
+
+        // Not found, so we throw an exception. A bit of work to set
+        // up the exception however.
+
+        List<String> ids = CollectionFactory.newList();
+
+        for (PropertyModel model : properties.values())
+        {
+            ids.add(model.getId());
+        }
+
+        throw new UnknownValueException(String.format(
+                "Bean editor model for %s does not contain a property with id '%s'.", beanType.getName(), propertyId),
+                new AvailableValues("Defined property ids", ids));
+    }
+
+    public List<String> getPropertyNames()
+    {
+        return CollectionFactory.newList(propertyNames);
+    }
+
+    public BeanModel<T> exclude(String... propertyNames)
+    {
+        for (String propertyName : propertyNames)
+        {
+            PropertyModel model = properties.get(propertyName);
+
+            if (model == null)
+                continue;
+
+            // De-referencing from the model is needed because the name provided may not be a
+            // case-exact match, so we get the normalized or canonical name from the model because
+            // that's the one in propertyNames.
+
+            this.propertyNames.remove(model.getPropertyName());
+
+            properties.remove(propertyName);
+        }
+
+        return this;
+    }
+
+    public BeanModel<T> reorder(String... propertyNames)
+    {
+        List<String> remainingPropertyNames = CollectionFactory.newList(this.propertyNames);
+        List<String> reorderedPropertyNames = CollectionFactory.newList();
+
+        for (String name : propertyNames)
+        {
+            PropertyModel model = get(name);
+
+            // Get the canonical form (which may differ from name in terms of case)
+            String canonical = model.getPropertyName();
+
+            reorderedPropertyNames.add(canonical);
+
+            remainingPropertyNames.remove(canonical);
+        }
+
+        this.propertyNames.clear();
+        this.propertyNames.addAll(reorderedPropertyNames);
+
+        // Any unspecified names are ordered to the end. Don't want them? Remove them instead.
+        this.propertyNames.addAll(remainingPropertyNames);
+
+        return this;
+    }
+
+    public BeanModel<T> include(String... propertyNames)
+    {
+        List<String> reorderedPropertyNames = CollectionFactory.newList();
+        Map<String, PropertyModel> reduced = CollectionFactory.newCaseInsensitiveMap();
+
+        for (String name : propertyNames)
+        {
+
+            PropertyModel model = get(name);
+
+            String canonical = model.getPropertyName();
+
+            reorderedPropertyNames.add(canonical);
+            reduced.put(canonical, model);
+
+        }
+
+        this.propertyNames.clear();
+        this.propertyNames.addAll(reorderedPropertyNames);
+
+        properties.clear();
+        properties.putAll(reduced);
+
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        StringBuilder builder = new StringBuilder("BeanModel[");
+        builder.append(PlasticUtils.toTypeName(beanType));
+
+        builder.append(" properties:");
+        String sep = "";
+
+        for (String name : propertyNames)
+        {
+            builder.append(sep);
+            builder.append(name);
+
+            sep = ", ";
+        }
+
+        builder.append("]");
+
+        return builder.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/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
new file mode 100644
index 0000000..703ce44
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
@@ -0,0 +1,139 @@
+// Copyright 2007, 2008, 2010, 2011, 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.internal.beaneditor;
+
+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.TapestryInternalUtils;
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.plastic.PlasticUtils;
+
+import java.lang.annotation.Annotation;
+
+@SuppressWarnings("all")
+public class PropertyModelImpl implements PropertyModel
+{
+    private final BeanModel model;
+
+    private final String name;
+
+    private final PropertyConduit conduit;
+
+    private final String id;
+
+    private String label;
+
+    private String dataType;
+
+    private boolean sortable;
+
+    public PropertyModelImpl(BeanModel model, String name, PropertyConduit conduit, Messages messages)
+    {
+        this.model = model;
+        this.name = name;
+        this.conduit = conduit;
+
+        id = TapestryInternalUtils.extractIdFromPropertyExpression(name);
+
+        label = TapestryInternalUtils.defaultLabel(id, messages, name);
+
+        // TAP5-2305
+        if (conduit != null)
+        {
+            Sortable sortableAnnotation = conduit.getAnnotation(Sortable.class);
+            if (sortableAnnotation != null)
+            {
+                sortable = sortableAnnotation.value();
+            }
+            else
+            {
+                // Primitive types need to be converted to wrapper types before checking to see
+                // if they are sortable.
+                Class wrapperType = PlasticUtils.toWrapperType(getPropertyType());
+                sortable = Comparable.class.isAssignableFrom(wrapperType);
+            }
+        }
+    }
+
+    public String getId()
+    {
+        return id;
+    }
+
+    public Class getPropertyType()
+    {
+        return conduit == null ? Object.class : conduit.getPropertyType();
+    }
+
+    public PropertyConduit getConduit()
+    {
+        return conduit;
+    }
+
+    public PropertyModel label(String label)
+    {
+        assert InternalUtils.isNonBlank(label);
+        this.label = label;
+
+        return this;
+    }
+
+    public String getLabel()
+    {
+        return label;
+    }
+
+    public String getPropertyName()
+    {
+        return name;
+    }
+
+    public BeanModel model()
+    {
+        return model;
+    }
+
+    public PropertyModel dataType(String dataType)
+    {
+        this.dataType = dataType;
+
+        return this;
+    }
+
+    public String getDataType()
+    {
+        return dataType;
+    }
+
+    public boolean isSortable()
+    {
+        return sortable;
+    }
+
+    public PropertyModel sortable(boolean sortable)
+    {
+        this.sortable = sortable;
+
+        return this;
+    }
+
+    public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+    {
+        return conduit == null ? null : conduit.getAnnotation(annotationClass);
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/beanmodel/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
new file mode 100644
index 0000000..4dbfb2d
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
@@ -0,0 +1,67 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.services;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import org.apache.tapestry5.PropertyConduit;
+import org.apache.tapestry5.PropertyConduit2;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
+
+public class CoercingPropertyConduitWrapper implements PropertyConduit2
+{
+    private final PropertyConduit conduit;
+
+    private final TypeCoercer coercer;
+
+    public CoercingPropertyConduitWrapper(final PropertyConduit conduit, final TypeCoercer coercer)
+    {
+        this.conduit = conduit;
+        this.coercer = coercer;
+    }
+
+    public Object get(Object instance)
+    {
+        return conduit.get(instance);
+    }
+
+    public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+    {
+        return conduit.getAnnotation(annotationClass);
+    }
+
+    public Class getPropertyType()
+    {
+        return conduit.getPropertyType();
+    }
+    
+    public Type getPropertyGenericType()
+    {
+    	if (conduit instanceof PropertyConduit2) {
+    		return ((PropertyConduit2) conduit).getPropertyGenericType();
+    	}
+    	return conduit.getPropertyType();
+    }
+
+    @SuppressWarnings("unchecked")
+    public void set(Object instance, Object value)
+    {
+        Object coerced = coercer.coerce(value, getPropertyType());
+
+        conduit.set(instance, coerced);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
new file mode 100644
index 0000000..1242031
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
@@ -0,0 +1,53 @@
+// Copyright 2007, 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.internal.services;
+
+import java.lang.annotation.Annotation;
+
+import org.apache.tapestry5.internal.InternalPropertyConduit;
+import org.apache.tapestry5.internal.util.IntegerRange;
+import org.apache.tapestry5.ioc.AnnotationProvider;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
+
+/**
+ * Companion class for {@link org.apache.tapestry5.PropertyConduit} instances created by the
+ * {@link org.apache.tapestry5.services.PropertyConduitSource}.
+ */
+@SuppressWarnings("all")
+public class PropertyConduitDelegate
+{
+    private final TypeCoercer typeCoercer;
+
+    public PropertyConduitDelegate(TypeCoercer typeCoercer)
+    {
+        this.typeCoercer = typeCoercer;
+    }
+
+    public final IntegerRange range(int from, int to)
+    {
+        return new IntegerRange(from, to);
+    }
+
+    public final <T> T coerce(Object value, Class<T> type)
+    {
+        return typeCoercer.coerce(value, type);
+    }
+
+    public final boolean invert(Object value)
+    {
+        return coerce(value, Boolean.class).equals(Boolean.FALSE);
+    }
+}


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

Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
index 8f1f7b6..a5f55b7 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
@@ -17,7 +17,6 @@ package org.apache.tapestry5.ioc.internal.util;
 import org.apache.tapestry5.func.F;
 import org.apache.tapestry5.func.Mapper;
 import org.apache.tapestry5.func.Predicate;
-import org.apache.tapestry5.internal.InternalBeanModelUtils;
 import org.apache.tapestry5.internal.plastic.PlasticInternalUtils;
 import org.apache.tapestry5.ioc.*;
 import org.apache.tapestry5.ioc.annotations.*;
@@ -80,11 +79,10 @@ public class InternalUtils
      *
      * @param method
      * @return short string representation
-     * @deprecated use {@link InternalStringUtils#asString(Method)} instead.
      */
     public static String asString(Method method)
     {
-        return InternalStringUtils.asString(method);
+        return InternalCommonsUtils.asString(method);
     }
 
     /**
@@ -103,11 +101,10 @@ public class InternalUtils
 
     /**
      * Strips leading "_" and "$" and trailing "_" from the name.
-     * @deprecated use {@link InternalStringUtils#stripMemberName(String)} instead.
      */
     public static String stripMemberName(String memberName)
     {
-        return InternalStringUtils.stripMemberName(memberName);
+        return InternalCommonsUtils.stripMemberName(memberName);
     }
 
     /**
@@ -392,11 +389,10 @@ public class InternalUtils
 
     /**
      * Joins together some number of elements to form a comma separated list.
-     * @deprecated use {@link InternalStringUtils#join(List)} instead.
      */
     public static String join(List elements)
     {
-        return InternalStringUtils.join(elements);
+        return InternalCommonsUtils.join(elements);
     }
 
     /**
@@ -407,11 +403,10 @@ public class InternalUtils
      *         objects to be joined together
      * @param separator
      *         used between elements when joining
-     * @deprecated use {@link InternalStringUtils#asString(Method, String)} instead.
      */
     public static String join(List elements, String separator)
     {
-        return InternalStringUtils.join(elements, separator);
+        return InternalCommonsUtils.join(elements, separator);
     }
 
     /**
@@ -419,21 +414,19 @@ public class InternalUtils
      *
      * @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
      *         empty
-     * @deprecated use {@link InternalStringUtils#joinSorted(Collection)} instead.
      */
     public static String joinSorted(Collection elements)
     {
-        return InternalStringUtils.joinSorted(elements);
+        return InternalCommonsUtils.joinSorted(elements);
     }
 
     /**
      * Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
-     * @deprecated use {@link InternalStringUtils#isBlank(String)} instead.
      */
 
     public static boolean isBlank(String input)
     {
-        return InternalStringUtils.isBlank(input);
+        return InternalCommonsUtils.isBlank(input);
     }
 
     /**
@@ -450,63 +443,27 @@ public class InternalUtils
         return false;
     }
 
-    /**
-     * @deprecated use {@link InternalStringUtils#isNonBlank(String)} instead.
-     */
     public static boolean isNonBlank(String input)
     {
-        return InternalStringUtils.isNonBlank(input);
+        return InternalCommonsUtils.isNonBlank(input);
     }
 
     /**
      * Capitalizes a string, converting the first character to uppercase.
-     * @deprecated use {@link InternalStringUtils#capitalize(String)} instead.
      */
     public static String capitalize(String input)
     {
-        return InternalStringUtils.capitalize(input);
+        return InternalCommonsUtils.capitalize(input);
     }
 
     /**
      * Sniffs the object to see if it is a {@link Location} or {@link Locatable}. Returns null if null or not
      * convertable to a location.
      */
-
+    
     public static Location locationOf(Object location)
     {
-        if (location == null)
-            return null;
-
-        if (location instanceof Location)
-            return (Location) location;
-
-        if (location instanceof Locatable)
-            return ((Locatable) location).getLocation();
-
-        return null;
-    }
-
-    /**
-     * Extracts the string keys from a map and returns them in sorted order. The keys are converted to strings.
-     *
-     * @param map
-     *         the map to extract keys from (may be null)
-     * @return the sorted keys, or the empty set if map is null
-     */
-
-    public static List<String> sortedKeys(Map map)
-    {
-        if (map == null)
-            return Collections.emptyList();
-
-        List<String> keys = CollectionFactory.newList();
-
-        for (Object o : map.keySet())
-            keys.add(String.valueOf(o));
-
-        Collections.sort(keys);
-
-        return keys;
+        return InternalCommonsUtils.locationOf(location);
     }
 
     public static <K, V> Set<K> keys(Map<K, V> map)
@@ -572,11 +529,10 @@ public class InternalUtils
 
     /**
      * Return true if the input string contains the marker for symbols that must be expanded.
-     * @deprecated use {@link InternalStringUtils#containsSymbols(String)} instead.
      */
     public static boolean containsSymbols(String input)
     {
-        return InternalStringUtils.containsSymbols(input);
+        return InternalCommonsUtils.containsSymbols(input);
     }
 
     /**
@@ -584,11 +540,10 @@ public class InternalUtils
      * generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
      * expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
      * character.
-     * @deprecated use {@link InternalStringUtils#lastTerm(String)} instead.
      */
     public static String lastTerm(String input)
     {
-        return InternalStringUtils.lastTerm(input);
+        return InternalCommonsUtils.lastTerm(input);
     }
 
     /**
@@ -684,15 +639,7 @@ public class InternalUtils
      */
     public static <K, V> void addToMapList(Map<K, List<V>> map, K key, V value)
     {
-        List<V> list = map.get(key);
-
-        if (list == null)
-        {
-            list = CollectionFactory.newList();
-            map.put(key, list);
-        }
-
-        list.add(value);
+        InternalCommonsUtils.addToMapList(map, key, value);
     }
 
     /**
@@ -777,7 +724,7 @@ public class InternalUtils
      */
     public static AnnotationProvider toAnnotationProvider(final Class element)
     {
-        return InternalBeanModelUtils.toAnnotationProvider(element);
+        return InternalCommonsUtils.toAnnotationProvider(element);
     }
 
     /**
@@ -1392,7 +1339,7 @@ public class InternalUtils
         {
             String value = namedAnnotation.value();
 
-            if (InternalUtils.isNonBlank(value))
+            if (InternalCommonsUtils.isNonBlank(value))
             {
                 return value;
             }
@@ -1404,7 +1351,7 @@ public class InternalUtils
 
     public static AnnotationProvider toAnnotationProvider(final Method element)
     {
-        return InternalBeanModelUtils.toAnnotationProvider(element);
+        return InternalCommonsUtils.toAnnotationProvider(element);
     }
 
     public static <T> ObjectCreator<T> createConstructorConstructionPlan(final OperationTracker tracker, final ObjectLocator locator,
@@ -1567,7 +1514,7 @@ public class InternalUtils
                     @Override
                     public void run()
                     {
-                        final ObjectCreator[] parameters = InternalUtils.calculateParametersForMethod(method, locator,
+                        final ObjectCreator[] parameters = calculateParametersForMethod(method, locator,
                                 resources, tracker);
 
                         plan.add(new InitializationPlan<Object>()
@@ -1651,4 +1598,55 @@ public class InternalUtils
     {
         return F.flow(creators).map(CREATE_OBJECT).toArray(Object.class);
     }
+
+    /**
+     * Extracts the string keys from a map and returns them in sorted order. The keys are converted to strings.
+     *
+     * @param map
+     *         the map to extract keys from (may be null)
+     * @return the sorted keys, or the empty set if map is null
+     */
+    
+    public static List<String> sortedKeys(Map map)
+    {
+        return InternalCommonsUtils.sortedKeys(map);
+    }
+    
+    /**
+     * 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)
+    {
+        return InternalCommonsUtils.toUserPresentable(id);
+    }
+
+    /**
+     * 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 InternalCommonsUtils.extractIdFromPropertyExpression(expression);
+    }
+    
+    /**
+     * 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)
+    {
+        return InternalCommonsUtils.defaultLabel(id, messages, propertyExpression);
+    }
+
+    public static String replace(String input, Pattern pattern, String replacement)
+    {
+        return InternalCommonsUtils.replace(input, pattern, replacement);
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
deleted file mode 100644
index 41de363..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 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.util;
-
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-/**
- * Base class for classes that need to manage a ReadWriteLock.
- */
-public abstract class LockSupport
-{
-    private final Lock readLock, writeLock;
-
-    protected LockSupport()
-    {
-        ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
-
-        readLock = lock.readLock();
-        writeLock = lock.writeLock();
-    }
-
-    /**
-     * Locks the shared read lock. Any number of threads may lock the read lock at the same time.
-     */
-    protected final void acquireReadLock()
-    {
-        readLock.lock();
-    }
-
-    /**
-     * Takes the exclusive write lock. Once started, no other thread lock the read or write lock. When this method returns,
-     * this thread will have locked the write lock and no other thread will have either the read or write lock.
-     * Note that this thread must first drop the read lock (if it has it) before attempting to take the write lock, or this method will block forever.
-     */
-    protected final void takeWriteLock()
-    {
-        writeLock.lock();
-    }
-
-    /**
-     * Releases the shared read lock.
-     */
-    protected final void releaseReadLock()
-    {
-        readLock.unlock();
-    }
-
-    /**
-     * Releases the  exclusive read lock.
-     */
-    protected final void releaseWriteLock()
-    {
-        writeLock.unlock();
-    }
-
-    /**
-     * Releases the read lock, then takes the write lock. There's a short window where the thread will have neither lock:
-     * during that window, some other thread may have a chance to take the write lock. In code, you'll often see a second check
-     * inside the code that has the write lock to see if the update to perform is still necessary.
-     */
-    protected final void upgradeReadLockToWriteLock()
-    {
-        releaseReadLock();
-        // This is that instant where another thread may grab the write lock. Very rare, but possible.
-        takeWriteLock();
-    }
-
-    /**
-     * Takes the read lock then releases the write lock.
-     */
-    protected final void downgradeWriteLockToReadLock()
-    {
-        acquireReadLock();
-        releaseWriteLock();
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java
deleted file mode 100644
index f4d8949..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java
+++ /dev/null
@@ -1,65 +0,0 @@
-// 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.util;
-
-import org.apache.tapestry5.ioc.MessageFormatter;
-import org.apache.tapestry5.ioc.util.ExceptionUtils;
-
-import java.util.Locale;
-
-
-public class MessageFormatterImpl implements MessageFormatter
-{
-    private final String format;
-
-    private final Locale locale;
-
-    public MessageFormatterImpl(String format, Locale locale)
-    {
-        this.format = format;
-        this.locale = locale;
-    }
-
-    @Override
-    public String format(Object... args)
-    {
-        for (int i = 0; i < args.length; i++)
-        {
-            Object arg = args[i];
-
-            if (Throwable.class.isInstance(arg))
-            {
-                args[i] = ExceptionUtils.toMessage((Throwable) arg);
-            }
-        }
-
-        // Might be tempting to create a Formatter object and just keep reusing it ... but
-        // Formatters are not threadsafe.
-
-        return String.format(locale, format, args);
-    }
-
-    /**
-     * Returns the underlying format string for this formatter.
-     *
-     * @since 5.4
-     */
-    @Override
-    public String toString()
-    {
-        return format;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
deleted file mode 100644
index c06ef90..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2006, 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.util;
-
-import org.apache.tapestry5.ioc.Messages;
-import org.apache.tapestry5.ioc.util.AbstractMessages;
-
-import java.util.*;
-
-/**
- * Implementation of {@link org.apache.tapestry5.ioc.Messages} based around a {@link java.util.ResourceBundle}.
- */
-public class MessagesImpl extends AbstractMessages
-{
-    private final Map<String, String> properties = CollectionFactory.newCaseInsensitiveMap();
-
-    /**
-     * Finds the messages for a given Messages utility class. Strings the trailing "Messages" and replaces it with
-     * "Strings" to form the base path. Loads the bundle using the default locale, and the class' class loader.
-     *
-     * @param forClass
-     * @return Messages for the class
-     */
-    public static Messages forClass(Class forClass)
-    {
-        String className = forClass.getName();
-        String stringsClassName = className.replaceAll("Messages$", "Strings");
-
-        Locale locale = Locale.getDefault();
-
-        ResourceBundle bundle = ResourceBundle.getBundle(stringsClassName, locale, forClass.getClassLoader());
-
-        return new MessagesImpl(locale, bundle);
-    }
-
-    public MessagesImpl(Locale locale, ResourceBundle bundle)
-    {
-        super(locale);
-
-        // Our best (threadsafe) chance to determine all the available keys.
-        Enumeration<String> e = bundle.getKeys();
-        while (e.hasMoreElements())
-        {
-            String key = e.nextElement();
-            String value = bundle.getString(key);
-
-            properties.put(key, value);
-        }
-    }
-
-    @Override
-    protected String valueForKey(String key)
-    {
-        return properties.get(key);
-    }
-
-    @Override
-    public Set<String> getKeys()
-    {
-        return properties.keySet();
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/modules/TapestryIOCModule.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/modules/TapestryIOCModule.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/modules/TapestryIOCModule.java
index a9af358..6d13d66 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/modules/TapestryIOCModule.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/modules/TapestryIOCModule.java
@@ -17,6 +17,7 @@ package org.apache.tapestry5.ioc.modules;
 import org.apache.tapestry5.func.Flow;
 import org.apache.tapestry5.ioc.*;
 import org.apache.tapestry5.ioc.annotations.*;
+import org.apache.tapestry5.ioc.internal.BasicTypeCoercions;
 import org.apache.tapestry5.ioc.internal.services.*;
 import org.apache.tapestry5.ioc.internal.services.cron.PeriodicExecutorImpl;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
@@ -189,301 +190,9 @@ public final class TapestryIOCModule
     @Contribute(TypeCoercer.class)
     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();
-            }
-        });
-
-        add(configuration, Flow.class, List.class, new Coercion<Flow, List>()
-        {
-            @Override
-            public List coerce(Flow input)
-            {
-                return input.toList();
-            }
-        });
-
-        add(configuration, Flow.class, Boolean.class, new Coercion<Flow, Boolean>()
-        {
-            @Override
-            public Boolean coerce(Flow input)
-            {
-                return !input.isEmpty();
-            }
-        });
-
+        BasicTypeCoercions.provideBasicTypeCoercions(configuration);
     }
-
-    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));
-    }
-
+    
     /**
      * <dl>
      * <dt>SystemProperties</dt>

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java
deleted file mode 100644
index 590c337..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright 2006, 2009, 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.util;
-
-import org.apache.tapestry5.ioc.MessageFormatter;
-import org.apache.tapestry5.ioc.Messages;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.MessageFormatterImpl;
-
-import java.util.Locale;
-import java.util.Map;
-
-/**
- * Abstract implementation of {@link Messages} that doesn't know where values come from (that information is supplied in
- * a subclass, via the {@link #valueForKey(String)} method).
- */
-public abstract class AbstractMessages implements Messages
-{
-    /**
-     * String key to MF instance.
-     */
-    private final Map<String, MessageFormatter> cache = CollectionFactory.newConcurrentMap();
-
-    private final Locale locale;
-
-    protected AbstractMessages(Locale locale)
-    {
-        this.locale = locale;
-    }
-
-    /**
-     * Invoked to provide the value for a particular key. This may be invoked multiple times even for the same key. The
-     * implementation should <em>ignore the case of the key</em>.
-     *
-     * @param key the key to obtain a value for (case insensitive)
-     * @return the value for the key, or null if this instance can not provide the value
-     */
-    protected abstract String valueForKey(String key);
-
-
-    @Override
-    public boolean contains(String key)
-    {
-        return valueForKey(key) != null;
-    }
-
-    @Override
-    public String get(String key)
-    {
-        if (contains(key)) return valueForKey(key);
-
-        return String.format("[[missing key: %s]]", key);
-    }
-
-    @Override
-    public MessageFormatter getFormatter(String key)
-    {
-        MessageFormatter result = cache.get(key);
-
-        if (result == null)
-        {
-            result = buildMessageFormatter(key);
-            cache.put(key, result);
-        }
-
-        return result;
-    }
-
-    private MessageFormatter buildMessageFormatter(String key)
-    {
-        String format = get(key);
-
-        return new MessageFormatterImpl(format, locale);
-    }
-
-    @Override
-    public String format(String key, Object... args)
-    {
-        return getFormatter(key).format(args);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java
deleted file mode 100644
index eaffe46..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java
+++ /dev/null
@@ -1,195 +0,0 @@
-// Copyright 2007, 2008, 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.util;
-
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Used to represent a period of time, specifically as a configuration value. This is often used to specify timeouts.
- * <p/>
- * TimePeriods are parsed from strings.
- * <p/>
- * The string specifys a number of terms. The values of all the terms are summed together to form the total time period.
- * Each term consists of a number followed by a unit. Units (from largest to smallest) are: <dl> <dt>y <dd>year <dt>d
- * <dd>day <dt>h <dd>hour <dt>m <dd>minute <dt>s <dd>second <dt>ms <dd>millisecond </dl> <p>  Example: "2 h 30 m". By
- * convention, terms are specified largest to smallest.  A term without a unit is assumed to be milliseconds.  Units are
- * case insensitive ("h" or "H" are treated the same).
- */
-public class TimeInterval
-{
-    private static final Map<String, Long> UNITS = CollectionFactory.newCaseInsensitiveMap();
-
-    private static final long MILLISECOND = 1000l;
-
-    static
-    {
-        UNITS.put("ms", 1l);
-        UNITS.put("s", MILLISECOND);
-        UNITS.put("m", 60 * MILLISECOND);
-        UNITS.put("h", 60 * UNITS.get("m"));
-        UNITS.put("d", 24 * UNITS.get("h"));
-        UNITS.put("y", 365 * UNITS.get("d"));
-    }
-
-    /**
-     * The unit keys, sorted in descending order.
-     */
-    private static final String[] UNIT_KEYS =
-    { "y", "d", "h", "m", "s", "ms" };
-
-    private static final Pattern PATTERN = Pattern.compile("\\s*(\\d+)\\s*([a-z]*)", Pattern.CASE_INSENSITIVE);
-
-    private final long milliseconds;
-
-    /**
-     * Creates a TimeInterval for a string.
-     * 
-     * @param input
-     *            the string specifying the amount of time in the period
-     */
-    public TimeInterval(String input)
-    {
-        this(parseMilliseconds(input));
-    }
-
-    public TimeInterval(long milliseconds)
-    {
-        this.milliseconds = milliseconds;
-    }
-
-    public long milliseconds()
-    {
-        return milliseconds;
-    }
-
-    public long seconds()
-    {
-        return milliseconds / MILLISECOND;
-    }
-
-    /**
-     * Converts the milliseconds back into a string (compatible with {@link #TimeInterval(String)}).
-     * 
-     * @since 5.2.0
-     */
-    public String toDescription()
-    {
-        StringBuilder builder = new StringBuilder();
-
-        String sep = "";
-
-        long remainder = milliseconds;
-
-        for (String key : UNIT_KEYS)
-        {
-            if (remainder == 0)
-                break;
-
-            long value = UNITS.get(key);
-
-            long units = remainder / value;
-
-            if (units > 0)
-            {
-                builder.append(sep);
-                builder.append(units);
-                builder.append(key);
-
-                sep = " ";
-
-                remainder = remainder % value;
-            }
-        }
-
-        return builder.toString();
-    }
-
-    static long parseMilliseconds(String input)
-    {
-        long milliseconds = 0l;
-
-        Matcher matcher = PATTERN.matcher(input);
-
-        matcher.useAnchoringBounds(true);
-
-        // TODO: Notice non matching characters and reject input, including at end
-
-        int lastMatchEnd = -1;
-
-        while (matcher.find())
-        {
-            int start = matcher.start();
-
-            if (lastMatchEnd + 1 < start)
-            {
-                String invalid = input.substring(lastMatchEnd + 1, start);
-                throw new RuntimeException(String.format("Unexpected string '%s' (in time interval '%s').", invalid, input));
-            }
-
-            lastMatchEnd = matcher.end();
-
-            long count = Long.parseLong(matcher.group(1));
-            String units = matcher.group(2);
-
-            if (units.length() == 0)
-            {
-                milliseconds += count;
-                continue;
-            }
-
-            Long unitValue = UNITS.get(units);
-
-            if (unitValue == null)
-                throw new RuntimeException(String.format("Unknown time interval unit '%s' (in '%s').  Defined units: %s.", units, input, InternalUtils.joinSorted(UNITS.keySet())));
-
-            milliseconds += count * unitValue;
-        }
-
-        if (lastMatchEnd + 1 < input.length())
-        {
-            String invalid = input.substring(lastMatchEnd + 1);
-            throw new RuntimeException(String.format("Unexpected string '%s' (in time interval '%s').", invalid, input));
-        }
-
-        return milliseconds;
-    }
-
-    @Override
-    public String toString()
-    {
-        return String.format("TimeInterval[%d ms]", milliseconds);
-    }
-
-    @Override
-    public boolean equals(Object obj)
-    {
-        if (obj == null)
-            return false;
-
-        if (obj instanceof TimeInterval)
-        {
-            TimeInterval tp = (TimeInterval) obj;
-
-            return milliseconds == tp.milliseconds;
-        }
-
-        return false;
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java
deleted file mode 100644
index 77c9a8d..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2007, 2008, 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.util;
-
-import java.util.Map;
-
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.ioc.services.Coercion;
-import org.apache.tapestry5.ioc.util.AvailableValues;
-import org.apache.tapestry5.ioc.util.UnknownValueException;
-
-/**
- * A {@link org.apache.tapestry5.ioc.services.Coercion} for converting strings into an instance of a particular
- * enumerated type. The {@link Enum#name() name} is used as the key to identify the enum instance, in a case-insensitive
- * fashion.
- * <p>
- * Moved from tapestry-core to tapestry-ioc is release 5.3, but kept in same package for compatibility.
- * 
- * @param <T>
- *            the type of enumeration
- */
-public final class StringToEnumCoercion<T extends Enum> implements Coercion<String, T>
-{
-    private final Class<T> enumClass;
-
-    private final Map<String, T> stringToEnum = CollectionFactory.newCaseInsensitiveMap();
-
-    public StringToEnumCoercion(Class<T> enumClass)
-    {
-        this(enumClass, enumClass.getEnumConstants());
-    }
-
-    public StringToEnumCoercion(Class<T> enumClass, T... values)
-    {
-        this.enumClass = enumClass;
-
-        for (T value : values)
-            stringToEnum.put(value.name(), value);
-    }
-
-    @Override
-    public T coerce(String input)
-    {
-        if (InternalUtils.isBlank(input))
-            return null;
-
-        T result = stringToEnum.get(input);
-
-        if (result == null)
-        {
-            String message = String.format("Input '%s' does not identify a value from enumerated type %s.", input,
-                    enumClass.getName());
-
-            throw new UnknownValueException(message, new AvailableValues(enumClass.getName() + " enum constants",
-                    stringToEnum));
-        }
-
-        return result;
-    }
-
-    /**
-     * Allows an alias value (alternate) string to reference a value.
-     * 
-     * @since 5.2.2
-     */
-    public StringToEnumCoercion<T> addAlias(String alias, T value)
-    {
-        stringToEnum.put(alias, value);
-
-        return this;
-    }
-
-    public static <T extends Enum> StringToEnumCoercion<T> create(Class<T> enumClass)
-    {
-        return new StringToEnumCoercion<T>(enumClass);
-    }
-
-}


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

Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
index 8f1f7b6..a5f55b7 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
@@ -17,7 +17,6 @@ package org.apache.tapestry5.ioc.internal.util;
 import org.apache.tapestry5.func.F;
 import org.apache.tapestry5.func.Mapper;
 import org.apache.tapestry5.func.Predicate;
-import org.apache.tapestry5.internal.InternalBeanModelUtils;
 import org.apache.tapestry5.internal.plastic.PlasticInternalUtils;
 import org.apache.tapestry5.ioc.*;
 import org.apache.tapestry5.ioc.annotations.*;
@@ -80,11 +79,10 @@ public class InternalUtils
      *
      * @param method
      * @return short string representation
-     * @deprecated use {@link InternalStringUtils#asString(Method)} instead.
      */
     public static String asString(Method method)
     {
-        return InternalStringUtils.asString(method);
+        return InternalCommonsUtils.asString(method);
     }
 
     /**
@@ -103,11 +101,10 @@ public class InternalUtils
 
     /**
      * Strips leading "_" and "$" and trailing "_" from the name.
-     * @deprecated use {@link InternalStringUtils#stripMemberName(String)} instead.
      */
     public static String stripMemberName(String memberName)
     {
-        return InternalStringUtils.stripMemberName(memberName);
+        return InternalCommonsUtils.stripMemberName(memberName);
     }
 
     /**
@@ -392,11 +389,10 @@ public class InternalUtils
 
     /**
      * Joins together some number of elements to form a comma separated list.
-     * @deprecated use {@link InternalStringUtils#join(List)} instead.
      */
     public static String join(List elements)
     {
-        return InternalStringUtils.join(elements);
+        return InternalCommonsUtils.join(elements);
     }
 
     /**
@@ -407,11 +403,10 @@ public class InternalUtils
      *         objects to be joined together
      * @param separator
      *         used between elements when joining
-     * @deprecated use {@link InternalStringUtils#asString(Method, String)} instead.
      */
     public static String join(List elements, String separator)
     {
-        return InternalStringUtils.join(elements, separator);
+        return InternalCommonsUtils.join(elements, separator);
     }
 
     /**
@@ -419,21 +414,19 @@ public class InternalUtils
      *
      * @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
      *         empty
-     * @deprecated use {@link InternalStringUtils#joinSorted(Collection)} instead.
      */
     public static String joinSorted(Collection elements)
     {
-        return InternalStringUtils.joinSorted(elements);
+        return InternalCommonsUtils.joinSorted(elements);
     }
 
     /**
      * Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
-     * @deprecated use {@link InternalStringUtils#isBlank(String)} instead.
      */
 
     public static boolean isBlank(String input)
     {
-        return InternalStringUtils.isBlank(input);
+        return InternalCommonsUtils.isBlank(input);
     }
 
     /**
@@ -450,63 +443,27 @@ public class InternalUtils
         return false;
     }
 
-    /**
-     * @deprecated use {@link InternalStringUtils#isNonBlank(String)} instead.
-     */
     public static boolean isNonBlank(String input)
     {
-        return InternalStringUtils.isNonBlank(input);
+        return InternalCommonsUtils.isNonBlank(input);
     }
 
     /**
      * Capitalizes a string, converting the first character to uppercase.
-     * @deprecated use {@link InternalStringUtils#capitalize(String)} instead.
      */
     public static String capitalize(String input)
     {
-        return InternalStringUtils.capitalize(input);
+        return InternalCommonsUtils.capitalize(input);
     }
 
     /**
      * Sniffs the object to see if it is a {@link Location} or {@link Locatable}. Returns null if null or not
      * convertable to a location.
      */
-
+    
     public static Location locationOf(Object location)
     {
-        if (location == null)
-            return null;
-
-        if (location instanceof Location)
-            return (Location) location;
-
-        if (location instanceof Locatable)
-            return ((Locatable) location).getLocation();
-
-        return null;
-    }
-
-    /**
-     * Extracts the string keys from a map and returns them in sorted order. The keys are converted to strings.
-     *
-     * @param map
-     *         the map to extract keys from (may be null)
-     * @return the sorted keys, or the empty set if map is null
-     */
-
-    public static List<String> sortedKeys(Map map)
-    {
-        if (map == null)
-            return Collections.emptyList();
-
-        List<String> keys = CollectionFactory.newList();
-
-        for (Object o : map.keySet())
-            keys.add(String.valueOf(o));
-
-        Collections.sort(keys);
-
-        return keys;
+        return InternalCommonsUtils.locationOf(location);
     }
 
     public static <K, V> Set<K> keys(Map<K, V> map)
@@ -572,11 +529,10 @@ public class InternalUtils
 
     /**
      * Return true if the input string contains the marker for symbols that must be expanded.
-     * @deprecated use {@link InternalStringUtils#containsSymbols(String)} instead.
      */
     public static boolean containsSymbols(String input)
     {
-        return InternalStringUtils.containsSymbols(input);
+        return InternalCommonsUtils.containsSymbols(input);
     }
 
     /**
@@ -584,11 +540,10 @@ public class InternalUtils
      * generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
      * expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
      * character.
-     * @deprecated use {@link InternalStringUtils#lastTerm(String)} instead.
      */
     public static String lastTerm(String input)
     {
-        return InternalStringUtils.lastTerm(input);
+        return InternalCommonsUtils.lastTerm(input);
     }
 
     /**
@@ -684,15 +639,7 @@ public class InternalUtils
      */
     public static <K, V> void addToMapList(Map<K, List<V>> map, K key, V value)
     {
-        List<V> list = map.get(key);
-
-        if (list == null)
-        {
-            list = CollectionFactory.newList();
-            map.put(key, list);
-        }
-
-        list.add(value);
+        InternalCommonsUtils.addToMapList(map, key, value);
     }
 
     /**
@@ -777,7 +724,7 @@ public class InternalUtils
      */
     public static AnnotationProvider toAnnotationProvider(final Class element)
     {
-        return InternalBeanModelUtils.toAnnotationProvider(element);
+        return InternalCommonsUtils.toAnnotationProvider(element);
     }
 
     /**
@@ -1392,7 +1339,7 @@ public class InternalUtils
         {
             String value = namedAnnotation.value();
 
-            if (InternalUtils.isNonBlank(value))
+            if (InternalCommonsUtils.isNonBlank(value))
             {
                 return value;
             }
@@ -1404,7 +1351,7 @@ public class InternalUtils
 
     public static AnnotationProvider toAnnotationProvider(final Method element)
     {
-        return InternalBeanModelUtils.toAnnotationProvider(element);
+        return InternalCommonsUtils.toAnnotationProvider(element);
     }
 
     public static <T> ObjectCreator<T> createConstructorConstructionPlan(final OperationTracker tracker, final ObjectLocator locator,
@@ -1567,7 +1514,7 @@ public class InternalUtils
                     @Override
                     public void run()
                     {
-                        final ObjectCreator[] parameters = InternalUtils.calculateParametersForMethod(method, locator,
+                        final ObjectCreator[] parameters = calculateParametersForMethod(method, locator,
                                 resources, tracker);
 
                         plan.add(new InitializationPlan<Object>()
@@ -1651,4 +1598,55 @@ public class InternalUtils
     {
         return F.flow(creators).map(CREATE_OBJECT).toArray(Object.class);
     }
+
+    /**
+     * Extracts the string keys from a map and returns them in sorted order. The keys are converted to strings.
+     *
+     * @param map
+     *         the map to extract keys from (may be null)
+     * @return the sorted keys, or the empty set if map is null
+     */
+    
+    public static List<String> sortedKeys(Map map)
+    {
+        return InternalCommonsUtils.sortedKeys(map);
+    }
+    
+    /**
+     * 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)
+    {
+        return InternalCommonsUtils.toUserPresentable(id);
+    }
+
+    /**
+     * 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 InternalCommonsUtils.extractIdFromPropertyExpression(expression);
+    }
+    
+    /**
+     * 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)
+    {
+        return InternalCommonsUtils.defaultLabel(id, messages, propertyExpression);
+    }
+
+    public static String replace(String input, Pattern pattern, String replacement)
+    {
+        return InternalCommonsUtils.replace(input, pattern, replacement);
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
deleted file mode 100644
index 41de363..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 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.util;
-
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-/**
- * Base class for classes that need to manage a ReadWriteLock.
- */
-public abstract class LockSupport
-{
-    private final Lock readLock, writeLock;
-
-    protected LockSupport()
-    {
-        ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
-
-        readLock = lock.readLock();
-        writeLock = lock.writeLock();
-    }
-
-    /**
-     * Locks the shared read lock. Any number of threads may lock the read lock at the same time.
-     */
-    protected final void acquireReadLock()
-    {
-        readLock.lock();
-    }
-
-    /**
-     * Takes the exclusive write lock. Once started, no other thread lock the read or write lock. When this method returns,
-     * this thread will have locked the write lock and no other thread will have either the read or write lock.
-     * Note that this thread must first drop the read lock (if it has it) before attempting to take the write lock, or this method will block forever.
-     */
-    protected final void takeWriteLock()
-    {
-        writeLock.lock();
-    }
-
-    /**
-     * Releases the shared read lock.
-     */
-    protected final void releaseReadLock()
-    {
-        readLock.unlock();
-    }
-
-    /**
-     * Releases the  exclusive read lock.
-     */
-    protected final void releaseWriteLock()
-    {
-        writeLock.unlock();
-    }
-
-    /**
-     * Releases the read lock, then takes the write lock. There's a short window where the thread will have neither lock:
-     * during that window, some other thread may have a chance to take the write lock. In code, you'll often see a second check
-     * inside the code that has the write lock to see if the update to perform is still necessary.
-     */
-    protected final void upgradeReadLockToWriteLock()
-    {
-        releaseReadLock();
-        // This is that instant where another thread may grab the write lock. Very rare, but possible.
-        takeWriteLock();
-    }
-
-    /**
-     * Takes the read lock then releases the write lock.
-     */
-    protected final void downgradeWriteLockToReadLock()
-    {
-        acquireReadLock();
-        releaseWriteLock();
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java
deleted file mode 100644
index f4d8949..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java
+++ /dev/null
@@ -1,65 +0,0 @@
-// 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.util;
-
-import org.apache.tapestry5.ioc.MessageFormatter;
-import org.apache.tapestry5.ioc.util.ExceptionUtils;
-
-import java.util.Locale;
-
-
-public class MessageFormatterImpl implements MessageFormatter
-{
-    private final String format;
-
-    private final Locale locale;
-
-    public MessageFormatterImpl(String format, Locale locale)
-    {
-        this.format = format;
-        this.locale = locale;
-    }
-
-    @Override
-    public String format(Object... args)
-    {
-        for (int i = 0; i < args.length; i++)
-        {
-            Object arg = args[i];
-
-            if (Throwable.class.isInstance(arg))
-            {
-                args[i] = ExceptionUtils.toMessage((Throwable) arg);
-            }
-        }
-
-        // Might be tempting to create a Formatter object and just keep reusing it ... but
-        // Formatters are not threadsafe.
-
-        return String.format(locale, format, args);
-    }
-
-    /**
-     * Returns the underlying format string for this formatter.
-     *
-     * @since 5.4
-     */
-    @Override
-    public String toString()
-    {
-        return format;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
deleted file mode 100644
index c06ef90..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2006, 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.util;
-
-import org.apache.tapestry5.ioc.Messages;
-import org.apache.tapestry5.ioc.util.AbstractMessages;
-
-import java.util.*;
-
-/**
- * Implementation of {@link org.apache.tapestry5.ioc.Messages} based around a {@link java.util.ResourceBundle}.
- */
-public class MessagesImpl extends AbstractMessages
-{
-    private final Map<String, String> properties = CollectionFactory.newCaseInsensitiveMap();
-
-    /**
-     * Finds the messages for a given Messages utility class. Strings the trailing "Messages" and replaces it with
-     * "Strings" to form the base path. Loads the bundle using the default locale, and the class' class loader.
-     *
-     * @param forClass
-     * @return Messages for the class
-     */
-    public static Messages forClass(Class forClass)
-    {
-        String className = forClass.getName();
-        String stringsClassName = className.replaceAll("Messages$", "Strings");
-
-        Locale locale = Locale.getDefault();
-
-        ResourceBundle bundle = ResourceBundle.getBundle(stringsClassName, locale, forClass.getClassLoader());
-
-        return new MessagesImpl(locale, bundle);
-    }
-
-    public MessagesImpl(Locale locale, ResourceBundle bundle)
-    {
-        super(locale);
-
-        // Our best (threadsafe) chance to determine all the available keys.
-        Enumeration<String> e = bundle.getKeys();
-        while (e.hasMoreElements())
-        {
-            String key = e.nextElement();
-            String value = bundle.getString(key);
-
-            properties.put(key, value);
-        }
-    }
-
-    @Override
-    protected String valueForKey(String key)
-    {
-        return properties.get(key);
-    }
-
-    @Override
-    public Set<String> getKeys()
-    {
-        return properties.keySet();
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/modules/TapestryIOCModule.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/modules/TapestryIOCModule.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/modules/TapestryIOCModule.java
index a9af358..6d13d66 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/modules/TapestryIOCModule.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/modules/TapestryIOCModule.java
@@ -17,6 +17,7 @@ package org.apache.tapestry5.ioc.modules;
 import org.apache.tapestry5.func.Flow;
 import org.apache.tapestry5.ioc.*;
 import org.apache.tapestry5.ioc.annotations.*;
+import org.apache.tapestry5.ioc.internal.BasicTypeCoercions;
 import org.apache.tapestry5.ioc.internal.services.*;
 import org.apache.tapestry5.ioc.internal.services.cron.PeriodicExecutorImpl;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
@@ -189,301 +190,9 @@ public final class TapestryIOCModule
     @Contribute(TypeCoercer.class)
     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();
-            }
-        });
-
-        add(configuration, Flow.class, List.class, new Coercion<Flow, List>()
-        {
-            @Override
-            public List coerce(Flow input)
-            {
-                return input.toList();
-            }
-        });
-
-        add(configuration, Flow.class, Boolean.class, new Coercion<Flow, Boolean>()
-        {
-            @Override
-            public Boolean coerce(Flow input)
-            {
-                return !input.isEmpty();
-            }
-        });
-
+        BasicTypeCoercions.provideBasicTypeCoercions(configuration);
     }
-
-    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));
-    }
-
+    
     /**
      * <dl>
      * <dt>SystemProperties</dt>

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java
deleted file mode 100644
index 590c337..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright 2006, 2009, 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.util;
-
-import org.apache.tapestry5.ioc.MessageFormatter;
-import org.apache.tapestry5.ioc.Messages;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.MessageFormatterImpl;
-
-import java.util.Locale;
-import java.util.Map;
-
-/**
- * Abstract implementation of {@link Messages} that doesn't know where values come from (that information is supplied in
- * a subclass, via the {@link #valueForKey(String)} method).
- */
-public abstract class AbstractMessages implements Messages
-{
-    /**
-     * String key to MF instance.
-     */
-    private final Map<String, MessageFormatter> cache = CollectionFactory.newConcurrentMap();
-
-    private final Locale locale;
-
-    protected AbstractMessages(Locale locale)
-    {
-        this.locale = locale;
-    }
-
-    /**
-     * Invoked to provide the value for a particular key. This may be invoked multiple times even for the same key. The
-     * implementation should <em>ignore the case of the key</em>.
-     *
-     * @param key the key to obtain a value for (case insensitive)
-     * @return the value for the key, or null if this instance can not provide the value
-     */
-    protected abstract String valueForKey(String key);
-
-
-    @Override
-    public boolean contains(String key)
-    {
-        return valueForKey(key) != null;
-    }
-
-    @Override
-    public String get(String key)
-    {
-        if (contains(key)) return valueForKey(key);
-
-        return String.format("[[missing key: %s]]", key);
-    }
-
-    @Override
-    public MessageFormatter getFormatter(String key)
-    {
-        MessageFormatter result = cache.get(key);
-
-        if (result == null)
-        {
-            result = buildMessageFormatter(key);
-            cache.put(key, result);
-        }
-
-        return result;
-    }
-
-    private MessageFormatter buildMessageFormatter(String key)
-    {
-        String format = get(key);
-
-        return new MessageFormatterImpl(format, locale);
-    }
-
-    @Override
-    public String format(String key, Object... args)
-    {
-        return getFormatter(key).format(args);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java
deleted file mode 100644
index eaffe46..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java
+++ /dev/null
@@ -1,195 +0,0 @@
-// Copyright 2007, 2008, 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.util;
-
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Used to represent a period of time, specifically as a configuration value. This is often used to specify timeouts.
- * <p/>
- * TimePeriods are parsed from strings.
- * <p/>
- * The string specifys a number of terms. The values of all the terms are summed together to form the total time period.
- * Each term consists of a number followed by a unit. Units (from largest to smallest) are: <dl> <dt>y <dd>year <dt>d
- * <dd>day <dt>h <dd>hour <dt>m <dd>minute <dt>s <dd>second <dt>ms <dd>millisecond </dl> <p>  Example: "2 h 30 m". By
- * convention, terms are specified largest to smallest.  A term without a unit is assumed to be milliseconds.  Units are
- * case insensitive ("h" or "H" are treated the same).
- */
-public class TimeInterval
-{
-    private static final Map<String, Long> UNITS = CollectionFactory.newCaseInsensitiveMap();
-
-    private static final long MILLISECOND = 1000l;
-
-    static
-    {
-        UNITS.put("ms", 1l);
-        UNITS.put("s", MILLISECOND);
-        UNITS.put("m", 60 * MILLISECOND);
-        UNITS.put("h", 60 * UNITS.get("m"));
-        UNITS.put("d", 24 * UNITS.get("h"));
-        UNITS.put("y", 365 * UNITS.get("d"));
-    }
-
-    /**
-     * The unit keys, sorted in descending order.
-     */
-    private static final String[] UNIT_KEYS =
-    { "y", "d", "h", "m", "s", "ms" };
-
-    private static final Pattern PATTERN = Pattern.compile("\\s*(\\d+)\\s*([a-z]*)", Pattern.CASE_INSENSITIVE);
-
-    private final long milliseconds;
-
-    /**
-     * Creates a TimeInterval for a string.
-     * 
-     * @param input
-     *            the string specifying the amount of time in the period
-     */
-    public TimeInterval(String input)
-    {
-        this(parseMilliseconds(input));
-    }
-
-    public TimeInterval(long milliseconds)
-    {
-        this.milliseconds = milliseconds;
-    }
-
-    public long milliseconds()
-    {
-        return milliseconds;
-    }
-
-    public long seconds()
-    {
-        return milliseconds / MILLISECOND;
-    }
-
-    /**
-     * Converts the milliseconds back into a string (compatible with {@link #TimeInterval(String)}).
-     * 
-     * @since 5.2.0
-     */
-    public String toDescription()
-    {
-        StringBuilder builder = new StringBuilder();
-
-        String sep = "";
-
-        long remainder = milliseconds;
-
-        for (String key : UNIT_KEYS)
-        {
-            if (remainder == 0)
-                break;
-
-            long value = UNITS.get(key);
-
-            long units = remainder / value;
-
-            if (units > 0)
-            {
-                builder.append(sep);
-                builder.append(units);
-                builder.append(key);
-
-                sep = " ";
-
-                remainder = remainder % value;
-            }
-        }
-
-        return builder.toString();
-    }
-
-    static long parseMilliseconds(String input)
-    {
-        long milliseconds = 0l;
-
-        Matcher matcher = PATTERN.matcher(input);
-
-        matcher.useAnchoringBounds(true);
-
-        // TODO: Notice non matching characters and reject input, including at end
-
-        int lastMatchEnd = -1;
-
-        while (matcher.find())
-        {
-            int start = matcher.start();
-
-            if (lastMatchEnd + 1 < start)
-            {
-                String invalid = input.substring(lastMatchEnd + 1, start);
-                throw new RuntimeException(String.format("Unexpected string '%s' (in time interval '%s').", invalid, input));
-            }
-
-            lastMatchEnd = matcher.end();
-
-            long count = Long.parseLong(matcher.group(1));
-            String units = matcher.group(2);
-
-            if (units.length() == 0)
-            {
-                milliseconds += count;
-                continue;
-            }
-
-            Long unitValue = UNITS.get(units);
-
-            if (unitValue == null)
-                throw new RuntimeException(String.format("Unknown time interval unit '%s' (in '%s').  Defined units: %s.", units, input, InternalUtils.joinSorted(UNITS.keySet())));
-
-            milliseconds += count * unitValue;
-        }
-
-        if (lastMatchEnd + 1 < input.length())
-        {
-            String invalid = input.substring(lastMatchEnd + 1);
-            throw new RuntimeException(String.format("Unexpected string '%s' (in time interval '%s').", invalid, input));
-        }
-
-        return milliseconds;
-    }
-
-    @Override
-    public String toString()
-    {
-        return String.format("TimeInterval[%d ms]", milliseconds);
-    }
-
-    @Override
-    public boolean equals(Object obj)
-    {
-        if (obj == null)
-            return false;
-
-        if (obj instanceof TimeInterval)
-        {
-            TimeInterval tp = (TimeInterval) obj;
-
-            return milliseconds == tp.milliseconds;
-        }
-
-        return false;
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java
deleted file mode 100644
index 77c9a8d..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2007, 2008, 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.util;
-
-import java.util.Map;
-
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.ioc.services.Coercion;
-import org.apache.tapestry5.ioc.util.AvailableValues;
-import org.apache.tapestry5.ioc.util.UnknownValueException;
-
-/**
- * A {@link org.apache.tapestry5.ioc.services.Coercion} for converting strings into an instance of a particular
- * enumerated type. The {@link Enum#name() name} is used as the key to identify the enum instance, in a case-insensitive
- * fashion.
- * <p>
- * Moved from tapestry-core to tapestry-ioc is release 5.3, but kept in same package for compatibility.
- * 
- * @param <T>
- *            the type of enumeration
- */
-public final class StringToEnumCoercion<T extends Enum> implements Coercion<String, T>
-{
-    private final Class<T> enumClass;
-
-    private final Map<String, T> stringToEnum = CollectionFactory.newCaseInsensitiveMap();
-
-    public StringToEnumCoercion(Class<T> enumClass)
-    {
-        this(enumClass, enumClass.getEnumConstants());
-    }
-
-    public StringToEnumCoercion(Class<T> enumClass, T... values)
-    {
-        this.enumClass = enumClass;
-
-        for (T value : values)
-            stringToEnum.put(value.name(), value);
-    }
-
-    @Override
-    public T coerce(String input)
-    {
-        if (InternalUtils.isBlank(input))
-            return null;
-
-        T result = stringToEnum.get(input);
-
-        if (result == null)
-        {
-            String message = String.format("Input '%s' does not identify a value from enumerated type %s.", input,
-                    enumClass.getName());
-
-            throw new UnknownValueException(message, new AvailableValues(enumClass.getName() + " enum constants",
-                    stringToEnum));
-        }
-
-        return result;
-    }
-
-    /**
-     * Allows an alias value (alternate) string to reference a value.
-     * 
-     * @since 5.2.2
-     */
-    public StringToEnumCoercion<T> addAlias(String alias, T value)
-    {
-        stringToEnum.put(alias, value);
-
-        return this;
-    }
-
-    public static <T extends Enum> StringToEnumCoercion<T> create(Class<T> enumClass)
-    {
-        return new StringToEnumCoercion<T>(enumClass);
-    }
-
-}


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

Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java
deleted file mode 100644
index 9151381..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java
+++ /dev/null
@@ -1,84 +0,0 @@
-// 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/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java
deleted file mode 100644
index 2acfd0d..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java
+++ /dev/null
@@ -1,46 +0,0 @@
-// 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);
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java
deleted file mode 100644
index 49b0b15..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java
+++ /dev/null
@@ -1,59 +0,0 @@
-// 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.util.List;
-
-/**
- * Chain of command for {@link org.apache.tapestry5.ioc.AnnotationProvider}.
- */
-public class AnnotationProviderChain implements AnnotationProvider
-{
-    private final AnnotationProvider[] providers;
-
-    public AnnotationProviderChain(AnnotationProvider[] providers)
-    {
-        this.providers = providers;
-    }
-
-    /**
-     * Creates an AnnotationProvider from the list of providers.  Returns either an {@link AnnotationProviderChain} or
-     * the sole element in the list.
-     */
-    public static AnnotationProvider create(List<AnnotationProvider> providers)
-    {
-        int size = providers.size();
-
-        if (size == 1) return providers.get(0);
-
-        return new AnnotationProviderChain(providers.toArray(new AnnotationProvider[providers.size()]));
-    }
-
-    @Override
-    public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
-    {
-        for (AnnotationProvider p : providers)
-        {
-            T result = p.getAnnotation(annotationClass);
-
-            if (result != null) return result;
-        }
-
-        return null;
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
deleted file mode 100644
index af4bd7d..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
+++ /dev/null
@@ -1,250 +0,0 @@
-// 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.ArrayList;
-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.InternalUtils;
-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 = InternalUtils.joinSorted(adapters.keySet());
-
-        return String.format("<ClassPropertyAdaptor %s: %s>", beanType.getName(), names);
-    }
-
-    @Override
-    public List<String> getPropertyNames()
-    {
-        return InternalUtils.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/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java
deleted file mode 100644
index 4a5dece..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2006, 2007 The Apache Software Foundation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.apache.tapestry5.ioc.internal.services;
-
-import org.apache.tapestry5.ioc.services.Coercion;
-
-/**
- * Combines two coercions to create a coercion through an intermediate type.
- *
- * @param <S> The source (input) type
- * @param <I> The intermediate type
- * @param <T> The target (output) type
- */
-public class CompoundCoercion<S, I, T> implements Coercion<S, T>
-{
-    private final Coercion<S, I> op1;
-
-    private final Coercion<I, T> op2;
-
-    public CompoundCoercion(Coercion<S, I> op1, Coercion<I, T> op2)
-    {
-        this.op1 = op1;
-        this.op2 = op2;
-    }
-
-    @Override
-    public T coerce(S input)
-    {
-        // Run the input through the first operation (S --> I), then run the result of that through
-        // the second operation (I --> T).
-
-        I intermediate = op1.coerce(input);
-
-        return op2.coerce(intermediate);
-    }
-
-    @Override
-    public String toString()
-    {
-        return String.format("%s, %s", op1, op2);
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java
deleted file mode 100644
index 8ebdede..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java
+++ /dev/null
@@ -1,47 +0,0 @@
-// 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/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
deleted file mode 100644
index 112e29d..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
+++ /dev/null
@@ -1,286 +0,0 @@
-// 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.annotations.IncompatibleChange;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-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 InternalUtils.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 InternalUtils.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/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java
deleted file mode 100644
index 8dd1e02..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java
+++ /dev/null
@@ -1,217 +0,0 @@
-// 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/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
deleted file mode 100644
index 97685ef..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
+++ /dev/null
@@ -1,273 +0,0 @@
-// 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/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
deleted file mode 100644
index e92ef2d..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2006, 2007, 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.ioc.Messages;
-import org.apache.tapestry5.ioc.internal.util.MessagesImpl;
-import org.apache.tapestry5.ioc.services.Coercion;
-import org.apache.tapestry5.plastic.PlasticUtils;
-
-public class ServiceMessages
-{
-    private final static Messages MESSAGES = MessagesImpl.forClass(ServiceMessages.class);
-
-    private ServiceMessages()
-    {
-    }
-
-    public static String noSuchProperty(Class clazz, String propertyName)
-    {
-        return MESSAGES.format("no-such-property", clazz.getName(), propertyName);
-    }
-
-
-    public static String readFailure(String propertyName, Object instance, Throwable cause)
-    {
-        return MESSAGES.format("read-failure", propertyName, instance, cause);
-    }
-
-    public static String propertyTypeMismatch(String propertyName, Class sourceClass, Class propertyType,
-                                              Class expectedType)
-    {
-        return MESSAGES.format("property-type-mismatch", propertyName, sourceClass.getName(), propertyType.getName(),
-                expectedType.getName());
-    }
-
-    public static String shutdownListenerError(Object listener, Throwable cause)
-    {
-        return MESSAGES.format("shutdown-listener-error", listener, cause);
-    }
-
-    public static String failedCoercion(Object input, Class targetType, Coercion coercion, Throwable cause)
-    {
-        return MESSAGES.format("failed-coercion", String.valueOf(input), PlasticUtils.toTypeName(targetType),
-                coercion, cause);
-    }
-
-    public static String registryShutdown(String serviceId)
-    {
-        return MESSAGES.format("registry-shutdown", serviceId);
-    }
-
-    public static String serviceBuildFailure(String serviceId, Throwable cause)
-    {
-        return MESSAGES.format("service-build-failure", serviceId, cause);
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java
deleted file mode 100644
index 0769b7e..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2007 The Apache Software Foundation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.apache.tapestry5.ioc.internal.services;
-
-import org.apache.tapestry5.ioc.Location;
-import org.apache.tapestry5.ioc.Resource;
-
-/**
- * Implementation of {@link Location} used when the underlying resource isn't really known.
- */
-public final class StringLocation implements Location
-{
-    private final String description;
-
-    private final int line;
-
-    public StringLocation(String description, int line)
-    {
-        this.description = description;
-        this.line = line;
-    }
-
-    @Override
-    public String toString()
-    {
-        return description;
-    }
-
-    /**
-     * Returns 0.
-     */
-    @Override
-    public int getColumn()
-    {
-        return 0;
-    }
-
-    @Override
-    public int getLine()
-    {
-        return line;
-    }
-
-    /**
-     * Returns null; we don't know where the file really is (it's probably a class on the class path).
-     */
-    @Override
-    public Resource getResource()
-    {
-        return null;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
deleted file mode 100644
index 46f1c0a..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
+++ /dev/null
@@ -1,508 +0,0 @@
-// Copyright 2006, 2007, 2008, 2010, 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.func.F;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InheritanceSearch;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.ioc.internal.util.LockSupport;
-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.AvailableValues;
-import org.apache.tapestry5.ioc.util.UnknownValueException;
-import org.apache.tapestry5.plastic.PlasticUtils;
-import org.apache.tapestry5.util.StringToEnumCoercion;
-
-import java.util.*;
-
-@SuppressWarnings("all")
-public class TypeCoercerImpl extends LockSupport implements TypeCoercer
-{
-    // Constructed from the service's configuration.
-
-    private final Map<Class, List<CoercionTuple>> sourceTypeToTuple = CollectionFactory.newMap();
-
-    /**
-     * A coercion to a specific target type. Manages a cache of coercions to specific types.
-     */
-    private class TargetCoercion
-    {
-        private final Class type;
-
-        private final Map<Class, Coercion> cache = CollectionFactory.newConcurrentMap();
-
-        TargetCoercion(Class type)
-        {
-            this.type = type;
-        }
-
-        void clearCache()
-        {
-            cache.clear();
-        }
-
-        Object coerce(Object input)
-        {
-            Class sourceType = input != null ? input.getClass() : Void.class;
-
-            if (type.isAssignableFrom(sourceType))
-            {
-                return input;
-            }
-
-            Coercion c = getCoercion(sourceType);
-
-            try
-            {
-                return type.cast(c.coerce(input));
-            } catch (Exception ex)
-            {
-                throw new RuntimeException(ServiceMessages.failedCoercion(input, type, c, ex), ex);
-            }
-        }
-
-        String explain(Class sourceType)
-        {
-            return getCoercion(sourceType).toString();
-        }
-
-        private Coercion getCoercion(Class sourceType)
-        {
-            Coercion c = cache.get(sourceType);
-
-            if (c == null)
-            {
-                c = findOrCreateCoercion(sourceType, type);
-                cache.put(sourceType, c);
-            }
-
-            return c;
-        }
-    }
-
-    /**
-     * Map from a target type to a TargetCoercion for that type.
-     */
-    private final Map<Class, TargetCoercion> typeToTargetCoercion = new WeakHashMap<Class, TargetCoercion>();
-
-    private static final Coercion NO_COERCION = new Coercion<Object, Object>()
-    {
-        @Override
-        public Object coerce(Object input)
-        {
-            return input;
-        }
-    };
-
-    private static final Coercion COERCION_NULL_TO_OBJECT = new Coercion<Void, Object>()
-    {
-        @Override
-        public Object coerce(Void input)
-        {
-            return null;
-        }
-
-        @Override
-        public String toString()
-        {
-            return "null --> null";
-        }
-    };
-
-    public TypeCoercerImpl(Collection<CoercionTuple> tuples)
-    {
-        for (CoercionTuple tuple : tuples)
-        {
-            Class key = tuple.getSourceType();
-
-            InternalUtils.addToMapList(sourceTypeToTuple, key, tuple);
-        }
-    }
-
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object coerce(Object input, Class targetType)
-    {
-        assert targetType != null;
-
-        Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
-
-        if (effectiveTargetType.isInstance(input))
-        {
-            return input;
-        }
-
-
-        return getTargetCoercion(effectiveTargetType).coerce(input);
-    }
-
-    @Override
-    @SuppressWarnings("unchecked")
-    public <S, T> Coercion<S, T> getCoercion(Class<S> sourceType, Class<T> targetType)
-    {
-        assert sourceType != null;
-        assert targetType != null;
-
-        Class effectiveSourceType = PlasticUtils.toWrapperType(sourceType);
-        Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
-
-        if (effectiveTargetType.isAssignableFrom(effectiveSourceType))
-        {
-            return NO_COERCION;
-        }
-
-        return getTargetCoercion(effectiveTargetType).getCoercion(effectiveSourceType);
-    }
-
-    @Override
-    @SuppressWarnings("unchecked")
-    public <S, T> String explain(Class<S> sourceType, Class<T> targetType)
-    {
-        assert sourceType != null;
-        assert targetType != null;
-
-        Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
-        Class effectiveSourceType = PlasticUtils.toWrapperType(sourceType);
-
-        // Is a coercion even necessary? Not if the target type is assignable from the
-        // input value.
-
-        if (effectiveTargetType.isAssignableFrom(effectiveSourceType))
-        {
-            return "";
-        }
-
-        return getTargetCoercion(effectiveTargetType).explain(effectiveSourceType);
-    }
-
-    private TargetCoercion getTargetCoercion(Class targetType)
-    {
-        try
-        {
-            acquireReadLock();
-
-            TargetCoercion tc = typeToTargetCoercion.get(targetType);
-
-            return tc != null ? tc : createAndStoreNewTargetCoercion(targetType);
-        } finally
-        {
-            releaseReadLock();
-        }
-    }
-
-    private TargetCoercion createAndStoreNewTargetCoercion(Class targetType)
-    {
-        try
-        {
-            upgradeReadLockToWriteLock();
-
-            // Inner check since some other thread may have beat us to it.
-
-            TargetCoercion tc = typeToTargetCoercion.get(targetType);
-
-            if (tc == null)
-            {
-                tc = new TargetCoercion(targetType);
-                typeToTargetCoercion.put(targetType, tc);
-            }
-
-            return tc;
-        } finally
-        {
-            downgradeWriteLockToReadLock();
-        }
-    }
-
-    @Override
-    public void clearCache()
-    {
-        try
-        {
-            acquireReadLock();
-
-            // There's no need to clear the typeToTargetCoercion map, as it is a WeakHashMap and
-            // will release the keys for classes that are no longer in existence. On the other hand,
-            // there's likely all sorts of references to unloaded classes inside each TargetCoercion's
-            // individual cache, so clear all those.
-
-            for (TargetCoercion tc : typeToTargetCoercion.values())
-            {
-                // Can tc ever be null?
-
-                tc.clearCache();
-            }
-        } finally
-        {
-            releaseReadLock();
-        }
-    }
-
-    /**
-     * Here's the real meat; we do a search of the space to find coercions, or a system of
-     * coercions, that accomplish
-     * the desired coercion.
-     * <p/>
-     * There's <strong>TREMENDOUS</strong> room to improve this algorithm. For example, inheritance lists could be
-     * cached. Further, there's probably more ways to early prune the search. However, even with dozens or perhaps
-     * hundreds of tuples, I suspect the search will still grind to a conclusion quickly.
-     * <p/>
-     * The order of operations should help ensure that the most efficient tuple chain is located. If you think about how
-     * tuples are added to the queue, there are two factors: size (the number of steps in the coercion) and
-     * "class distance" (that is, number of steps up the inheritance hiearchy). All the appropriate 1 step coercions
-     * will be considered first, in class distance order. Along the way, we'll queue up all the 2 step coercions, again
-     * in class distance order. By the time we reach some of those, we'll have begun queueing up the 3 step coercions, and
-     * so forth, until we run out of input tuples we can use to fabricate multi-step compound coercions, or reach a
-     * final response.
-     * <p/>
-     * This does create a good number of short lived temporary objects (the compound tuples), but that's what the GC is
-     * really good at.
-     *
-     * @param sourceType
-     * @param targetType
-     * @return coercer from sourceType to targetType
-     */
-    @SuppressWarnings("unchecked")
-    private Coercion findOrCreateCoercion(Class sourceType, Class targetType)
-    {
-        if (sourceType == Void.class)
-        {
-            return searchForNullCoercion(targetType);
-        }
-
-        // These are instance variables because this method may be called concurrently.
-        // On a true race, we may go to the work of seeking out and/or fabricating
-        // a tuple twice, but it's more likely that different threads are looking
-        // for different source/target coercions.
-
-        Set<CoercionTuple> consideredTuples = CollectionFactory.newSet();
-        LinkedList<CoercionTuple> queue = CollectionFactory.newLinkedList();
-
-        seedQueue(sourceType, targetType, consideredTuples, queue);
-
-        while (!queue.isEmpty())
-        {
-            CoercionTuple tuple = queue.removeFirst();
-
-            // If the tuple results in a value type that is assignable to the desired target type,
-            // we're done! Later, we may add a concept of "cost" (i.e. number of steps) or
-            // "quality" (how close is the tuple target type to the desired target type). Cost
-            // is currently implicit, as compound tuples are stored deeper in the queue,
-            // so simpler coercions will be located earlier.
-
-            Class tupleTargetType = tuple.getTargetType();
-
-            if (targetType.isAssignableFrom(tupleTargetType))
-            {
-                return tuple.getCoercion();
-            }
-
-            // So .. this tuple doesn't get us directly to the target type.
-            // However, it *may* get us part of the way. Each of these
-            // represents a coercion from the source type to an intermediate type.
-            // Now we're going to look for conversions from the intermediate type
-            // to some other type.
-
-            queueIntermediates(sourceType, targetType, tuple, consideredTuples, queue);
-        }
-
-        // Not found anywhere. Identify the source and target type and a (sorted) list of
-        // all the known coercions.
-
-        throw new UnknownValueException(String.format("Could not find a coercion from type %s to type %s.",
-                sourceType.getName(), targetType.getName()), buildCoercionCatalog());
-    }
-
-    /**
-     * Coercion from null is special; we match based on the target type and its not a spanning
-     * search. In many cases, we
-     * return a pass-thru that leaves the value as null.
-     *
-     * @param targetType
-     *         desired type
-     * @return the coercion
-     */
-    private Coercion searchForNullCoercion(Class targetType)
-    {
-        List<CoercionTuple> tuples = getTuples(Void.class, targetType);
-
-        for (CoercionTuple tuple : tuples)
-        {
-            Class tupleTargetType = tuple.getTargetType();
-
-            if (targetType.equals(tupleTargetType))
-                return tuple.getCoercion();
-        }
-
-        // Typical case: no match, this coercion passes the null through
-        // as null.
-
-        return COERCION_NULL_TO_OBJECT;
-    }
-
-    /**
-     * Builds a string listing all the coercions configured for the type coercer, sorted
-     * alphabetically.
-     */
-    @SuppressWarnings("unchecked")
-    private AvailableValues buildCoercionCatalog()
-    {
-        List<CoercionTuple> masterList = CollectionFactory.newList();
-
-        for (List<CoercionTuple> list : sourceTypeToTuple.values())
-        {
-            masterList.addAll(list);
-        }
-
-        return new AvailableValues("Configured coercions", masterList);
-    }
-
-    /**
-     * Seeds the pool with the initial set of coercions for the given type.
-     */
-    private void seedQueue(Class sourceType, Class targetType, Set<CoercionTuple> consideredTuples,
-                           LinkedList<CoercionTuple> queue)
-    {
-        // Work from the source type up looking for tuples
-
-        for (Class c : new InheritanceSearch(sourceType))
-        {
-            List<CoercionTuple> tuples = getTuples(c, targetType);
-
-            if (tuples == null)
-            {
-                continue;
-            }
-
-            for (CoercionTuple tuple : tuples)
-            {
-                queue.addLast(tuple);
-                consideredTuples.add(tuple);
-            }
-
-            // Don't pull in Object -> type coercions when doing
-            // a search from null.
-
-            if (sourceType == Void.class)
-            {
-                return;
-            }
-        }
-    }
-
-    /**
-     * Creates and adds to the pool a new set of coercions based on an intermediate tuple. Adds
-     * compound coercion tuples
-     * to the end of the queue.
-     *
-     * @param sourceType
-     *         the source type of the coercion
-     * @param targetType
-     *         TODO
-     * @param intermediateTuple
-     *         a tuple that converts from the source type to some intermediate type (that is not
-     *         assignable to the target type)
-     * @param consideredTuples
-     *         set of tuples that have already been added to the pool (directly, or as a compound
-     *         coercion)
-     * @param queue
-     *         the work queue of tuples
-     */
-    @SuppressWarnings("unchecked")
-    private void queueIntermediates(Class sourceType, Class targetType, CoercionTuple intermediateTuple,
-                                    Set<CoercionTuple> consideredTuples, LinkedList<CoercionTuple> queue)
-    {
-        Class intermediateType = intermediateTuple.getTargetType();
-
-        for (Class c : new InheritanceSearch(intermediateType))
-        {
-            for (CoercionTuple tuple : getTuples(c, targetType))
-            {
-                if (consideredTuples.contains(tuple))
-                {
-                    continue;
-                }
-
-                Class newIntermediateType = tuple.getTargetType();
-
-                // If this tuple is for coercing from an intermediate type back towards our
-                // initial source type, then ignore it. This should only be an optimization,
-                // as branches that loop back towards the source type will
-                // eventually be considered and discarded.
-
-                if (sourceType.isAssignableFrom(newIntermediateType))
-                {
-                    continue;
-                }
-
-                // The intermediateTuple coercer gets from S --> I1 (an intermediate type).
-                // The current tuple's coercer gets us from I2 --> X. where I2 is assignable
-                // from I1 (i.e., I2 is a superclass/superinterface of I1) and X is a new
-                // intermediate type, hopefully closer to our eventual target type.
-
-                Coercion compoundCoercer = new CompoundCoercion(intermediateTuple.getCoercion(), tuple.getCoercion());
-
-                CoercionTuple compoundTuple = new CoercionTuple(sourceType, newIntermediateType, compoundCoercer, false);
-
-                // So, every tuple that is added to the queue can take as input the sourceType.
-                // The target type may be another intermediate type, or may be something
-                // assignable to the target type, which will bring the search to a successful
-                // conclusion.
-
-                queue.addLast(compoundTuple);
-                consideredTuples.add(tuple);
-            }
-        }
-    }
-
-    /**
-     * Returns a non-null list of the tuples from the source type.
-     *
-     * @param sourceType
-     *         used to locate tuples
-     * @param targetType
-     *         used to add synthetic tuples
-     * @return non-null list of tuples
-     */
-    private List<CoercionTuple> getTuples(Class sourceType, Class targetType)
-    {
-        List<CoercionTuple> tuples = sourceTypeToTuple.get(sourceType);
-
-        if (tuples == null)
-        {
-            tuples = Collections.emptyList();
-        }
-
-        // So, when we see String and an Enum type, we add an additional synthetic tuple to the end
-        // of the real list. This is the easiest way to accomplish this is a thread-safe and class-reloading
-        // safe way (i.e., what if the Enum is defined by a class loader that gets discarded?  Don't want to cause
-        // memory leaks by retaining an instance). In any case, there are edge cases where we may create
-        // the tuple unnecessarily (such as when an explicit string-to-enum coercion is part of the TypeCoercer
-        // configuration), but on the whole, this is cheap and works.
-
-        if (sourceType == String.class && Enum.class.isAssignableFrom(targetType))
-        {
-            tuples = extend(tuples, new CoercionTuple(sourceType, targetType, new StringToEnumCoercion(targetType)));
-        }
-
-        return tuples;
-    }
-
-    private static <T> List<T> extend(List<T> list, T extraValue)
-    {
-        return F.flow(list).append(extraValue).toList();
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
deleted file mode 100644
index f1830a7..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright 2006 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.util;
-
-import org.apache.tapestry5.plastic.PlasticUtils;
-
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.Set;
-
-/**
- * Used to search from a particular class up the inheritance hierarchy of extended classes and implemented interfaces.
- * <p/>
- * The search starts with the initial class (provided in the constructor). It progresses up the inheritance chain, but
- * skips java.lang.Object.
- * <p/>
- * Once classes are exhausted, the inheritance hierarchy is searched. This is a breadth-first search, rooted in the
- * interfaces implemented by the initial class at its super classes.
- * <p/>
- * Once all interfaces are exhausted, java.lang.Object is returned (it is always returned last).
- * <p/>
- * Two minor tweak to normal inheritance rules: <ul> <li> Normally, the parent class of an <em>object</em> array is
- * java.lang.Object, which is odd because FooService[] is assignable to Object[]. Thus, we tweak the search so that the
- * effective super class of FooService[] is Object[]. <li> The "super class" of a primtive type is its <em>wrapper type</em>,
- * with the exception of void, whose "super class" is left at its normal value (Object.class) </ul>
- * <p/>
- * This class implements the {@link Iterable} interface, so it can be used directly in a for loop: <code> for (Class
- * search : new InheritanceSearch(startClass)) { ... } </code>
- * <p/>
- * This class is not thread-safe.
- */
-public class InheritanceSearch implements Iterator<Class>, Iterable<Class>
-{
-    private Class searchClass;
-
-    private final Set<Class> addedInterfaces = CollectionFactory.newSet();
-
-    private final LinkedList<Class> interfaceQueue = CollectionFactory.newLinkedList();
-
-    private enum State
-    {
-        CLASS, INTERFACE, DONE
-    }
-
-    private State state;
-
-    public InheritanceSearch(Class searchClass)
-    {
-        this.searchClass = searchClass;
-
-        queueInterfaces(searchClass);
-
-        state = searchClass == Object.class ? State.INTERFACE : State.CLASS;
-    }
-
-    private void queueInterfaces(Class searchClass)
-    {
-        for (Class intf : searchClass.getInterfaces())
-        {
-            if (addedInterfaces.contains(intf)) continue;
-
-            interfaceQueue.addLast(intf);
-            addedInterfaces.add(intf);
-        }
-    }
-
-    @Override
-    public Iterator<Class> iterator()
-    {
-        return this;
-    }
-
-    @Override
-    public boolean hasNext()
-    {
-        return state != State.DONE;
-    }
-
-    @Override
-    public Class next()
-    {
-        switch (state)
-        {
-            case CLASS:
-
-                Class result = searchClass;
-
-                searchClass = parentOf(searchClass);
-
-                if (searchClass == null) state = State.INTERFACE;
-                else queueInterfaces(searchClass);
-
-                return result;
-
-            case INTERFACE:
-
-                if (interfaceQueue.isEmpty())
-                {
-                    state = State.DONE;
-                    return Object.class;
-                }
-
-                Class intf = interfaceQueue.removeFirst();
-
-                queueInterfaces(intf);
-
-                return intf;
-
-            default:
-                throw new IllegalStateException();
-        }
-
-    }
-
-    /**
-     * Returns the parent of the given class. Tweaks inheritance for object arrays. Returns null instead of
-     * Object.class.
-     */
-    private Class parentOf(Class clazz)
-    {
-        if (clazz != void.class && clazz.isPrimitive()) return PlasticUtils.toWrapperType(clazz);
-
-        if (clazz.isArray() && clazz != Object[].class)
-        {
-            Class componentType = clazz.getComponentType();
-
-            while (componentType.isArray()) componentType = componentType.getComponentType();
-
-            if (!componentType.isPrimitive()) return Object[].class;
-        }
-
-        Class parent = clazz.getSuperclass();
-
-        return parent != Object.class ? parent : null;
-    }
-
-    /**
-     * @throws UnsupportedOperationException
-     *         always
-     */
-    @Override
-    public void remove()
-    {
-        throw new UnsupportedOperationException();
-    }
-
-}


[09/15] tapestry-5 git commit: Second pass creating the BeanModel and Commons packages.

Posted by th...@apache.org.
Second 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/c9e97d64
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/c9e97d64
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/c9e97d64

Branch: refs/heads/beanmodel-split
Commit: c9e97d64a51b25c875d5daa94d2f607e4ed299f3
Parents: 1f36bb2
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Sat Dec 6 16:42:10 2014 -0200
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Sat Dec 6 16:42:10 2014 -0200

----------------------------------------------------------------------
 beanmodel/.gitignore                            |   4 +
 beanmodel/build.gradle                          |  51 ++++-
 .../tapestry5/internal/BeanModelUtils.java      | 145 +++++++++++++
 .../internal/beaneditor/BeanModelImpl.java      |   4 +-
 .../internal/beaneditor/PropertyModelImpl.java  |  14 +-
 .../services/PropertyConduitDelegate.java       |   1 -
 .../services/PropertyConduitSourceImpl.java     |  10 +-
 .../org/apache/tapestry5/ioc/ObjectLocator.java |   3 +-
 .../ioc/internal/util/InternalStringUtils.java  | 203 +++++++++++++++++++
 .../ioc/internal/util/TapestryException.java    |  23 ++-
 .../tapestry5/ioc/util/AvailableValues.java     |   4 +-
 tapestry-core/build.gradle                      |  37 ----
 .../internal/TapestryInternalUtils.java         |  46 +----
 .../ioc/internal/util/InternalUtils.java        | 142 +++----------
 14 files changed, 472 insertions(+), 215 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/beanmodel/.gitignore
----------------------------------------------------------------------
diff --git a/beanmodel/.gitignore b/beanmodel/.gitignore
new file mode 100644
index 0000000..f739972
--- /dev/null
+++ b/beanmodel/.gitignore
@@ -0,0 +1,4 @@
+docs
+/.externalToolBuilders
+src/main/generated
+src/test/generated

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/beanmodel/build.gradle
----------------------------------------------------------------------
diff --git a/beanmodel/build.gradle b/beanmodel/build.gradle
index ccdeb37..c09ebdd 100644
--- a/beanmodel/build.gradle
+++ b/beanmodel/build.gradle
@@ -6,7 +6,18 @@ description = "Fast class property discovery, reading and writing library based
 //apply plugin: JavaPlugin
 
 buildDir = 'target/gradle-build'
-       
+
+project.ext {
+	antlrSource = "src/main/antlr"
+	mainGeneratedDir = "src/main/generated"
+	testGeneratedDir = "src/test/generated"
+	antlrOutput = "$mainGeneratedDir/antlr"
+}
+
+configurations {
+	antlr3
+}
+      
 project.ext.libraryVersions = [
 	jcache: '1.0.0',
 ]
@@ -15,12 +26,50 @@ dependencies {
 	compile project(":plastic")
 	compile project(":tapestry5-annotations")
 	compile project(":commons")
+	
+	// Antlr3 tool path used with the antlr3 task
+	antlr3 "org.antlr:antlr:3.5.2"
+
 	// Transitive will bring in the unwanted string template library as well
 	compile "org.antlr:antlr-runtime:3.5.2", {
 		exclude group: "org.antlr", module: "stringtemplate"
 	}
 }
 
+// This may spin out as a plugin once we've got the details down pat
+
+task generateGrammarSource(type: JavaExec) {
+	description "Generates Java sources from Antlr3 grammars."
+	inputs.source fileTree(dir: antlrSource, include: "**/*.g")
+	outputs.dir file(antlrOutput)
+
+	classpath configurations.antlr3
+
+	main "org.antlr.Tool"
+	args "-o", "${antlrOutput}/org/apache/tapestry5/internal/antlr"
+	args inputs.sourceFiles
+
+	doFirst {
+		logger.info "Executing Antlr3 grammar generation:\n${commandLine.join(' ')}"
+	}
+}
+
+sourceSets {
+	main {
+		output.dir(antlrOutput, builtBy: generateGrammarSource)
+		java {
+			srcDir antlrOutput
+		}
+	}
+}
+
+clean.delete mainGeneratedDir, testGeneratedDir
+
+compileJava {
+	dependsOn generateGrammarSource
+	options.fork(memoryMaximumSize: '512m')
+}
+
 jar {	
 	manifest {	
 	}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java
new file mode 100644
index 0000000..08cb88a
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java
@@ -0,0 +1,145 @@
+// 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 BeanModelUtils {
+	
+	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/c9e97d64/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 26eb309..b72a3d6 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.InternalUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
 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 InternalUtils.isNonBlank(propertyName);
+        assert InternalStringUtils.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/c9e97d64/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 703ce44..b21e5bb 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
@@ -14,17 +14,17 @@
 
 package org.apache.tapestry5.internal.beaneditor;
 
+import java.lang.annotation.Annotation;
+
 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.TapestryInternalUtils;
+import org.apache.tapestry5.internal.BeanModelUtils;
 import org.apache.tapestry5.ioc.Messages;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
 import org.apache.tapestry5.plastic.PlasticUtils;
 
-import java.lang.annotation.Annotation;
-
 @SuppressWarnings("all")
 public class PropertyModelImpl implements PropertyModel
 {
@@ -48,9 +48,9 @@ public class PropertyModelImpl implements PropertyModel
         this.name = name;
         this.conduit = conduit;
 
-        id = TapestryInternalUtils.extractIdFromPropertyExpression(name);
+        id = BeanModelUtils.extractIdFromPropertyExpression(name);
 
-        label = TapestryInternalUtils.defaultLabel(id, messages, name);
+        label = BeanModelUtils.defaultLabel(id, messages, name);
 
         // TAP5-2305
         if (conduit != null)
@@ -87,7 +87,7 @@ public class PropertyModelImpl implements PropertyModel
 
     public PropertyModel label(String label)
     {
-        assert InternalUtils.isNonBlank(label);
+        assert InternalStringUtils.isNonBlank(label);
         this.label = label;
 
         return this;

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
index 1242031..3849103 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
@@ -19,7 +19,6 @@ import java.lang.annotation.Annotation;
 import org.apache.tapestry5.internal.InternalPropertyConduit;
 import org.apache.tapestry5.internal.util.IntegerRange;
 import org.apache.tapestry5.ioc.AnnotationProvider;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
 import org.apache.tapestry5.ioc.services.TypeCoercer;
 
 /**

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/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 701420f..83f67fa 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,6 +19,7 @@ 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.BeanModelUtils;
 import org.apache.tapestry5.internal.InternalPropertyConduit;
 import org.apache.tapestry5.internal.antlr.PropertyExpressionLexer;
 import org.apache.tapestry5.internal.antlr.PropertyExpressionParser;
@@ -29,7 +30,7 @@ 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.InternalUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
 import org.apache.tapestry5.ioc.services.*;
 import org.apache.tapestry5.ioc.util.AvailableValues;
 import org.apache.tapestry5.ioc.util.ExceptionUtils;
@@ -1106,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()],
-                    InternalUtils.joinSorted(tokenNames));
+                    InternalStringUtils.joinSorted(tokenNames));
 
             return new RuntimeException(message);
         }
@@ -1259,7 +1260,7 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
 
             Type returnType = GenericsUtils.extractActualType(activeType, method);
 
-            return new Term(returnType, toUniqueId(method), InternalUtils.toAnnotationProvider(method), new InstructionBuilderCallback()
+            return new Term(returnType, toUniqueId(method), BeanModelUtils.toAnnotationProvider(method), new InstructionBuilderCallback()
             {
                 public void doBuild(InstructionBuilder builder)
                 {
@@ -1363,7 +1364,7 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
     public PropertyConduit create(Class rootClass, String expression)
     {
         assert rootClass != null;
-        assert InternalUtils.isNonBlank(expression);
+        assert InternalStringUtils.isNonBlank(expression);
 
         MultiKey key = new MultiKey(rootClass, expression);
 
@@ -1560,4 +1561,5 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
 
         return builder.append(")").toString();
     }
+    
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java b/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
index 81d1f77..e60c0d9 100644
--- a/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2010, 2011 The Apache Software Foundation
+// Copyright 2006, 2007, 2010, 2011, 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.
@@ -15,7 +15,6 @@
 package org.apache.tapestry5.ioc;
 
 import org.apache.tapestry5.ioc.annotations.Inject;
-import org.apache.tapestry5.ioc.services.MasterObjectProvider;
 
 import java.lang.annotation.Annotation;
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java
new file mode 100644
index 0000000..e345593
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java
@@ -0,0 +1,203 @@
+// Copyright 2006-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.util;
+
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * String-related utilities used within various internal implementations of the Apache Tapestry subprojects.
+ * Broken off Tapestry-IoC's InternalUtils.
+ */
+@SuppressWarnings("all")
+public class InternalStringUtils
+{
+	
+    /**
+     * Pattern used to eliminate leading and trailing underscores and dollar signs.
+     */
+    private static final Pattern NAME_PATTERN = Pattern.compile("^[_|$]*([\\p{javaJavaIdentifierPart}]+?)[_|$]*$",
+            Pattern.CASE_INSENSITIVE);
+
+    /**
+     * Converts a method to a user presentable string consisting of the containing class name, the method name, and the
+     * short form of the parameter list (the class name of each parameter type, shorn of the package name portion).
+     *
+     * @param method
+     * @return short string representation
+     */
+    public static String asString(Method method)
+    {
+        StringBuilder buffer = new StringBuilder();
+
+        buffer.append(method.getDeclaringClass().getName());
+        buffer.append(".");
+        buffer.append(method.getName());
+        buffer.append("(");
+
+        for (int i = 0; i < method.getParameterTypes().length; i++)
+        {
+            if (i > 0)
+                buffer.append(", ");
+
+            String name = method.getParameterTypes()[i].getSimpleName();
+
+            buffer.append(name);
+        }
+
+        return buffer.append(")").toString();
+    }
+
+    /**
+     * Strips leading "_" and "$" and trailing "_" from the name.
+     */
+    public static String stripMemberName(String memberName)
+    {
+        assert isNonBlank(memberName);
+        Matcher matcher = NAME_PATTERN.matcher(memberName);
+
+        if (!matcher.matches())
+            throw new IllegalArgumentException(String.format("Input '%s' is not a valid Java identifier.", memberName));
+
+        return matcher.group(1);
+    }
+
+    /**
+     * Joins together some number of elements to form a comma separated list.
+     */
+    public static String join(List elements)
+    {
+        return join(elements, ", ");
+    }
+
+    /**
+     * Joins together some number of elements. If a value in the list is the empty string, it is replaced with the
+     * string "(blank)".
+     *
+     * @param elements
+     *         objects to be joined together
+     * @param separator
+     *         used between elements when joining
+     */
+    public static String join(List elements, String separator)
+    {
+        switch (elements.size())
+        {
+            case 0:
+                return "";
+
+            case 1:
+                return elements.get(0).toString();
+
+            default:
+
+                StringBuilder buffer = new StringBuilder();
+                boolean first = true;
+
+                for (Object o : elements)
+                {
+                    if (!first)
+                        buffer.append(separator);
+
+                    String string = String.valueOf(o);
+
+                    if (string.equals(""))
+                        string = "(blank)";
+
+                    buffer.append(string);
+
+                    first = false;
+                }
+
+                return buffer.toString();
+        }
+    }
+
+    /**
+     * Creates a sorted copy of the provided elements, then turns that into a comma separated list.
+     *
+     * @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
+     *         empty
+     */
+    public static String joinSorted(Collection elements)
+    {
+        if (elements == null || elements.isEmpty())
+            return "(none)";
+
+        List<String> list = CollectionFactory.newList();
+
+        for (Object o : elements)
+            list.add(String.valueOf(o));
+
+        Collections.sort(list);
+
+        return join(list);
+    }
+
+    /**
+     * Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
+     */
+
+    public static boolean isBlank(String input)
+    {
+        return input == null || input.length() == 0 || input.trim().length() == 0;
+    }
+
+    public static boolean isNonBlank(String input)
+    {
+        return !isBlank(input);
+    }
+
+    /**
+     * Capitalizes a string, converting the first character to uppercase.
+     */
+    public static String capitalize(String input)
+    {
+        if (input.length() == 0)
+            return input;
+
+        return input.substring(0, 1).toUpperCase() + input.substring(1);
+    }
+
+    /**
+     * Return true if the input string contains the marker for symbols that must be expanded.
+     */
+    public static boolean containsSymbols(String input)
+    {
+        return input.contains("${");
+    }
+
+    /**
+     * Searches the string for the final period ('.') character and returns everything after that. The input string is
+     * generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
+     * expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
+     * character.
+     */
+    public static String lastTerm(String input)
+    {
+        assert isNonBlank(input);
+        int dotx = input.lastIndexOf('.');
+
+        if (dotx < 0)
+            return input;
+
+        return input.substring(dotx + 1);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
index ef217cb..d8d8018 100644
--- a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
@@ -34,7 +34,7 @@ public class TapestryException extends RuntimeException implements Locatable
      */
     public TapestryException(String message, Object location, Throwable cause)
     {
-        this(message, InternalUtils.locationOf(location), cause);
+        this(message, locationOf(location), cause);
     }
 
     /**
@@ -71,5 +71,26 @@ public class TapestryException extends RuntimeException implements Locatable
 
         return String.format("%s [at %s]", super.toString(), location);
     }
+    
+    /**
+     * Sniffs the object to see if it is a {@link Location} or {@link Locatable}. Returns null if null or not
+     * convertable to a location.
+     * Copied from InternalUtils to avoid having it moved to BeanModel or Commons subprojects.
+     */
+
+    private static Location locationOf(Object location)
+    {
+        if (location == null)
+            return null;
+
+        if (location instanceof Location)
+            return (Location) location;
+
+        if (location instanceof Locatable)
+            return ((Locatable) location).getLocation();
+
+        return null;
+    }
+
 
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
index c4c5c6d..8c9cb3f 100644
--- a/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
@@ -20,7 +20,7 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
 
 /**
  * Used (as part of a {@link UnknownValueException} to identify what available values
@@ -81,7 +81,7 @@ public class AvailableValues
     @Override
     public String toString()
     {
-        return String.format("AvailableValues[%s: %s]", valueType, InternalUtils.join(values));
+        return String.format("AvailableValues[%s: %s]", valueType, InternalStringUtils.join(values));
     }
 
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/tapestry-core/build.gradle
----------------------------------------------------------------------
diff --git a/tapestry-core/build.gradle b/tapestry-core/build.gradle
index 584200a..d35c166 100644
--- a/tapestry-core/build.gradle
+++ b/tapestry-core/build.gradle
@@ -8,11 +8,6 @@ project.ext {
     antlrSource = "src/main/antlr"
     mainGeneratedDir = "src/main/generated"
     testGeneratedDir = "src/test/generated"
-    antlrOutput = "$mainGeneratedDir/antlr"
-}
-
-configurations {
-    antlr3
 }
 
 dependencies {
@@ -27,30 +22,9 @@ dependencies {
 
     compile "commons-codec:commons-codec:1.5"
 
-    // Antlr3 tool path used with the antlr3 task
-    antlr3 "org.antlr:antlr:3.5.2"
-
     testRuntime "org.hsqldb:hsqldb:1.8.0.10"
 }
 
-// This may spin out as a plugin once we've got the details down pat
-
-task generateGrammarSource(type: JavaExec) {
-    description "Generates Java sources from Antlr3 grammars."
-    inputs.source fileTree(dir: antlrSource, include: "**/*.g")
-    outputs.dir file(antlrOutput)
-
-    classpath configurations.antlr3
-
-    main "org.antlr.Tool"
-    args "-o", "${antlrOutput}/org/apache/tapestry5/internal/antlr"
-    args inputs.sourceFiles
-
-    doFirst {
-        logger.info "Executing Antlr3 grammar generation:\n${commandLine.join(' ')}"
-    }
-}
-
 task preprocessCoffeeScript(type: PreprocessCoffeeScript) {
 }
 
@@ -73,23 +47,12 @@ sourceSets {
     main {
         output.dir(compileCoffeeScript.outputDir, builtBy: compileCoffeeScript)
         output.dir(compileProcessedCoffeescript.outputDir, builtBy: compileProcessedCoffeescript)
-        output.dir(antlrOutput, builtBy: generateGrammarSource)
-        java {
-            srcDir antlrOutput
-        }
     }
     test {
         output.dir(compileTestCoffeeScript.outputDir, builtBy: compileTestCoffeeScript)
     }
 }
 
-clean.delete mainGeneratedDir, testGeneratedDir
-
-compileJava {
-    dependsOn generateGrammarSource
-    options.fork(memoryMaximumSize: '512m')
-}
-
 // Not sure why this is necessary:
 compileTestGroovy.dependsOn compileTestJava
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
index 3435d64..aba7225 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
@@ -59,40 +59,7 @@ public class TapestryInternalUtils
      */
     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();
+        return BeanModelUtils.toUserPresentable(id);
     }
 
     public static Map<String, String> mapFromKeysAndValues(String... keysAndValues)
@@ -261,7 +228,7 @@ public class TapestryInternalUtils
      */
     public static String extractIdFromPropertyExpression(String expression)
     {
-        return replace(expression, NON_WORD_PATTERN, "");
+        return BeanModelUtils.extractIdFromPropertyExpression(expression);
     }
 
     /**
@@ -270,12 +237,7 @@ public class TapestryInternalUtils
      */
     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(lastTerm(propertyExpression)));
+        return BeanModelUtils.defaultLabel(id, messages, propertyExpression);
     }
 
     /**
@@ -342,7 +304,7 @@ public class TapestryInternalUtils
 
     private static String replace(String input, Pattern pattern, String replacement)
     {
-        return pattern.matcher(input).replaceAll(replacement);
+        return BeanModelUtils.replace(input, pattern, replacement);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
index e9e7806..a40f984 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
@@ -17,16 +17,16 @@ package org.apache.tapestry5.ioc.internal.util;
 import org.apache.tapestry5.func.F;
 import org.apache.tapestry5.func.Mapper;
 import org.apache.tapestry5.func.Predicate;
+import org.apache.tapestry5.internal.BeanModelUtils;
 import org.apache.tapestry5.internal.plastic.PlasticInternalUtils;
 import org.apache.tapestry5.ioc.*;
 import org.apache.tapestry5.ioc.annotations.*;
 import org.apache.tapestry5.ioc.def.*;
-import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
 import org.apache.tapestry5.ioc.internal.ServiceDefImpl;
 import org.apache.tapestry5.ioc.services.Coercion;
-import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
 import org.apache.tapestry5.ioc.util.ExceptionUtils;
 import org.apache.tapestry5.plastic.PlasticUtils;
+import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
 import org.slf4j.Logger;
 
 import javax.annotation.PostConstruct;
@@ -56,18 +56,6 @@ public class InternalUtils
     public static final boolean SERVICE_CLASS_RELOADING_ENABLED = Boolean.parseBoolean(System.getProperty(
             IOCConstants.SERVICE_CLASS_RELOADING_ENABLED, "true"));
 
-
-    /**
-     * Pattern used to eliminate leading and trailing underscores and dollar signs.
-     */
-    private static final Pattern NAME_PATTERN = Pattern.compile("^[_|$]*([\\p{javaJavaIdentifierPart}]+?)[_|$]*$",
-            Pattern.CASE_INSENSITIVE);
-
-    /**
-     * @since 5.3
-     */
-    public static AnnotationProvider NULL_ANNOTATION_PROVIDER = new NullAnnotationProvider();
-
     /**
      * Converts a method to a user presentable string using a {@link PlasticProxyFactory} to obtain a {@link Location}
      * (where possible). {@link #asString(Method)} is used under the covers, to present a detailed, but not excessive,
@@ -92,27 +80,11 @@ public class InternalUtils
      *
      * @param method
      * @return short string representation
+     * @deprecated use {@link InternalStringUtils#asString(Method)} instead.
      */
     public static String asString(Method method)
     {
-        StringBuilder buffer = new StringBuilder();
-
-        buffer.append(method.getDeclaringClass().getName());
-        buffer.append(".");
-        buffer.append(method.getName());
-        buffer.append("(");
-
-        for (int i = 0; i < method.getParameterTypes().length; i++)
-        {
-            if (i > 0)
-                buffer.append(", ");
-
-            String name = method.getParameterTypes()[i].getSimpleName();
-
-            buffer.append(name);
-        }
-
-        return buffer.append(")").toString();
+        return InternalStringUtils.asString(method);
     }
 
     /**
@@ -131,16 +103,11 @@ public class InternalUtils
 
     /**
      * Strips leading "_" and "$" and trailing "_" from the name.
+     * @deprecated use {@link InternalStringUtils#stripMemberName(String)} instead.
      */
     public static String stripMemberName(String memberName)
     {
-        assert InternalUtils.isNonBlank(memberName);
-        Matcher matcher = NAME_PATTERN.matcher(memberName);
-
-        if (!matcher.matches())
-            throw new IllegalArgumentException(String.format("Input '%s' is not a valid Java identifier.", memberName));
-
-        return matcher.group(1);
+        return InternalStringUtils.stripMemberName(memberName);
     }
 
     /**
@@ -425,10 +392,11 @@ public class InternalUtils
 
     /**
      * Joins together some number of elements to form a comma separated list.
+     * @deprecated use {@link InternalStringUtils#join(List)} instead.
      */
     public static String join(List elements)
     {
-        return join(elements, ", ");
+        return InternalStringUtils.join(elements);
     }
 
     /**
@@ -439,39 +407,11 @@ public class InternalUtils
      *         objects to be joined together
      * @param separator
      *         used between elements when joining
+     * @deprecated use {@link InternalStringUtils#asString(Method, String)} instead.
      */
     public static String join(List elements, String separator)
     {
-        switch (elements.size())
-        {
-            case 0:
-                return "";
-
-            case 1:
-                return elements.get(0).toString();
-
-            default:
-
-                StringBuilder buffer = new StringBuilder();
-                boolean first = true;
-
-                for (Object o : elements)
-                {
-                    if (!first)
-                        buffer.append(separator);
-
-                    String string = String.valueOf(o);
-
-                    if (string.equals(""))
-                        string = "(blank)";
-
-                    buffer.append(string);
-
-                    first = false;
-                }
-
-                return buffer.toString();
-        }
+        return InternalStringUtils.join(elements, separator);
     }
 
     /**
@@ -479,29 +419,21 @@ public class InternalUtils
      *
      * @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
      *         empty
+     * @deprecated use {@link InternalStringUtils#joinSorted(Collection)} instead.
      */
     public static String joinSorted(Collection elements)
     {
-        if (elements == null || elements.isEmpty())
-            return "(none)";
-
-        List<String> list = CollectionFactory.newList();
-
-        for (Object o : elements)
-            list.add(String.valueOf(o));
-
-        Collections.sort(list);
-
-        return join(list);
+        return InternalStringUtils.joinSorted(elements);
     }
 
     /**
      * Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
+     * @deprecated use {@link InternalStringUtils#isBlank(String)} instead.
      */
 
     public static boolean isBlank(String input)
     {
-        return input == null || input.length() == 0 || input.trim().length() == 0;
+        return InternalStringUtils.isBlank(input);
     }
 
     /**
@@ -518,20 +450,21 @@ public class InternalUtils
         return false;
     }
 
+    /**
+     * @deprecated use {@link InternalStringUtils#isNonBlank(String)} instead.
+     */
     public static boolean isNonBlank(String input)
     {
-        return !isBlank(input);
+        return InternalStringUtils.isNonBlank(input);
     }
 
     /**
      * Capitalizes a string, converting the first character to uppercase.
+     * @deprecated use {@link InternalStringUtils#capitalize(String)} instead.
      */
     public static String capitalize(String input)
     {
-        if (input.length() == 0)
-            return input;
-
-        return input.substring(0, 1).toUpperCase() + input.substring(1);
+        return InternalStringUtils.capitalize(input);
     }
 
     /**
@@ -639,10 +572,11 @@ public class InternalUtils
 
     /**
      * Return true if the input string contains the marker for symbols that must be expanded.
+     * @deprecated use {@link InternalStringUtils#containsSymbols(String)} instead.
      */
     public static boolean containsSymbols(String input)
     {
-        return input.contains("${");
+        return InternalStringUtils.containsSymbols(input);
     }
 
     /**
@@ -650,16 +584,11 @@ public class InternalUtils
      * generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
      * expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
      * character.
+     * @deprecated use {@link InternalStringUtils#lastTerm(String)} instead.
      */
     public static String lastTerm(String input)
     {
-        assert InternalUtils.isNonBlank(input);
-        int dotx = input.lastIndexOf('.');
-
-        if (dotx < 0)
-            return input;
-
-        return input.substring(dotx + 1);
+        return InternalStringUtils.lastTerm(input);
     }
 
     /**
@@ -848,18 +777,9 @@ public class InternalUtils
      */
     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));
-            }
-        };
+        return BeanModelUtils.toAnnotationProvider(element);
     }
 
-    ;
-
     /**
      * @since 5.3
      */
@@ -1484,17 +1404,7 @@ public class InternalUtils
 
     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);
-            }
-        };
+        return BeanModelUtils.toAnnotationProvider(element);
     }
 
     public static <T> ObjectCreator<T> createConstructorConstructionPlan(final OperationTracker tracker, final ObjectLocator locator,


[04/15] tapestry-5 git commit: First pass creating the BeanModel and Commons packages. Lots of stuff moved around, but no actual code changes so far

Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/services/InvalidationListener.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/services/InvalidationListener.java b/commons/src/main/java/org/apache/tapestry5/services/InvalidationListener.java
new file mode 100644
index 0000000..b9b4aa3
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/services/InvalidationListener.java
@@ -0,0 +1,33 @@
+// Copyright 2006, 2007, 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.services;
+
+/**
+ * Interface for objects that may cache information that can be invalidated. Invalidation occurs when external files,
+ * from which in-memory data is cached, is determined to have changed. Granularity is very limited; when any external
+ * file is found to have changed, the event is fired (with the expectation that the cleared cache will be repopulated as
+ * necessary).
+ *
+ * @see org.apache.tapestry5.services.InvalidationEventHub
+ * @since 5.1.0.0
+ * @deprecated In 5.4; use {@link InvalidationEventHub#addInvalidationCallback(Runnable)} instead
+ */
+public interface InvalidationListener
+{
+    /**
+     * Invoked to indicate that some object is invalid. The receiver should clear its cache.
+     */
+    void objectWasInvalidated();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/settings.gradle
----------------------------------------------------------------------
diff --git a/settings.gradle b/settings.gradle
index 6397777..593c3a4 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -4,5 +4,5 @@ include "tapestry-beanvalidator", "tapestry-jpa", "tapestry-kaptcha"
 include "tapestry-javadoc", "quickstart", "tapestry-clojure", "tapestry-mongodb"
 include "tapestry-test-data", 'tapestry-internal-test', "tapestry-ioc-junit"
 include "tapestry-webresources", "tapestry-runner", "tapestry-test-constants"
-include "tapestry-ioc-jcache"
+include "tapestry-ioc-jcache", "beanmodel", "commons"
 // include "tapestry-cdi"

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/build.gradle
----------------------------------------------------------------------
diff --git a/tapestry-core/build.gradle b/tapestry-core/build.gradle
index c16cd48..584200a 100644
--- a/tapestry-core/build.gradle
+++ b/tapestry-core/build.gradle
@@ -18,6 +18,7 @@ configurations {
 dependencies {
     compile project(':tapestry-ioc')
     compile project(':tapestry-json')
+    compile project(':beanmodel')
 
     provided project(":tapestry-test")
     provided project(":tapestry-test-constants")
@@ -26,11 +27,6 @@ dependencies {
 
     compile "commons-codec:commons-codec:1.5"
 
-    // Transitive will bring in the unwanted string template library as well
-    compile "org.antlr:antlr-runtime:3.5.2", {
-        exclude group: "org.antlr", module: "stringtemplate"
-    }
-
     // 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/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit.java b/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit.java
deleted file mode 100644
index 3dbb0c0..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit.java
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2007 The Apache Software Foundation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.apache.tapestry5;
-
-import org.apache.tapestry5.ioc.AnnotationProvider;
-
-/**
- * Used to read or update the value associated with a property. A PropertyConduit provides access to the annotations on
- * the underlying getter and/or setter methods.
- */
-public interface PropertyConduit extends AnnotationProvider
-{
-    /**
-     * Reads the property from the instance.
-     *
-     * @param instance object containing the property
-     * @return the current value of the property
-     */
-    Object get(Object instance);
-
-    /**
-     * Changes the current value of the property.
-     *
-     * @param instance object containing the property
-     * @param value    to change the property to
-     */
-    void set(Object instance, Object value);
-
-    /**
-     * Returns the type of the property read or updated by the conduit.
-     */
-    Class getPropertyType();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit2.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit2.java b/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit2.java
deleted file mode 100644
index 839d70f..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit2.java
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2007 The Apache Software Foundation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.apache.tapestry5;
-
-import java.lang.reflect.Method;
-import java.lang.reflect.Type;
-
-import org.apache.tapestry5.services.PropertyConduitSource;
-
-
-/**
- * Extension to {@link PropertyConduit} that adds a method to access the generic property type.
- * {@link PropertyConduitSource} instances should ideally return PropertyConduit2 objects, not PropertyConduit.
- * This is only primarily of interest to {@link Binding2}.
- * 
- * @since 5.4
- */
-public interface PropertyConduit2 extends PropertyConduit
-{
-    /**
-     * Returns the generic type of the property
-     * 
-     * @see Method#getGenericReturnType()
-     * @see java.lang.reflect.Field#getGenericType()
-     * 
-     */
-	Type getPropertyGenericType();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/BeanModel.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/BeanModel.java b/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/BeanModel.java
deleted file mode 100644
index 0a60fd7..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/BeanModel.java
+++ /dev/null
@@ -1,169 +0,0 @@
-// Copyright 2007, 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.beaneditor;
-
-import org.apache.tapestry5.PropertyConduit;
-
-import java.util.List;
-
-/**
- * Provides the information necessary to build a user interface to view, create or edit an instance of a particular
- * type.
- * <p/>
- * BeanModels are not thread-safe, they are also not serializable.
- * <p/>
- * Here, and in {@link org.apache.tapestry5.beaneditor.PropertyModel}, the term "propertyName" is used for simplicitly.
- * However, a full {@linkplain org.apache.tapestry5.services.PropertyConduitSource#create(Class, String) property
- * expression} may be utilized when {@linkplain #add(String) adding new properties to an existing BeanModel}.
- *
- * @see org.apache.tapestry5.services.BeanModelSource
- */
-public interface BeanModel<T>
-{
-    /**
-     * Returns the type of bean for which this model was initially created.
-     */
-    Class<T> getBeanType();
-
-
-    /**
-     * Creates a new bean instance.  This is based on {@link org.apache.tapestry5.ioc.ObjectLocator#autobuild(Class)},
-     * so a public constructor will be used, and dependencies injected.
-     *
-     * @return new instance of the bean
-     */
-    T newInstance();
-
-    /**
-     * Returns a list of the editable properties of the bean, in <em>presentation</em> order.
-     */
-    List<String> getPropertyNames();
-
-    /**
-     * Returns the named model.
-     *
-     * @param propertyName name of property to retrieve model for (case is ignored)
-     * @return the model for the property
-     * @throws RuntimeException if the bean editor model does not have a property model for the provided name
-     */
-    PropertyModel get(String propertyName);
-
-    /**
-     * Returns the identified model.  Property ids are a stripped version of the property name. Case is ignored.
-     *
-     * @param propertyId matched caselessly against {@link org.apache.tapestry5.beaneditor.PropertyModel#getId()}
-     * @throws RuntimeException if the bean editor model does not have a property model with the indicated id
-     */
-    PropertyModel getById(String propertyId);
-
-    /**
-     * Adds a new property to the model, returning its mutable model for further refinement. The property is added to
-     * the <em>end</em> of the list of properties. The property must be real (but may have been excluded if there was no
-     * {@linkplain org.apache.tapestry5.beaneditor.DataType datatype} associated with the property). To add a synthetic
-     * property, use {@link #add(String, org.apache.tapestry5.PropertyConduit)}
-     *
-     * @param propertyName name of property to add
-     * @return the new property model (for further configuration)
-     * @throws RuntimeException if the property already exists
-     */
-    PropertyModel add(String propertyName);
-
-
-    /**
-     * Adds a new synthetic property to the model, returning its mutable model for further refinement. The property is added to
-     * the <em>end</em> of the list of properties.
-     *
-     * @param propertyName name of property to add
-     * @param expression   expression for the property
-     * @return the new property model (for further configuration)
-     * @throws RuntimeException if the property already exists
-     * @since 5.3
-     */
-    PropertyModel addExpression(String propertyName, String expression);
-
-    /**
-     * Adds an empty property (one with no property conduit).
-     *
-     * @param propertyName name of property to add
-     * @return the new property model (for further configuration)
-     * @throws RuntimeException if the property already exists
-     * @since 5.3
-     */
-    PropertyModel addEmpty(String propertyName);
-
-    /**
-     * Adds a new property to the model (as with {@link #add(String)}), ordered before or after an existing property.
-     *
-     * @param position             controls whether the new property is ordered before or after the existing property
-     * @param existingPropertyName the name of an existing property (this must exist)
-     * @param propertyName         the new property to add
-     * @return the new property model (for further configuration)
-     * @throws RuntimeException if the existing property does not exist, or if the new property already does exist
-     */
-    PropertyModel add(RelativePosition position, String existingPropertyName, String propertyName);
-
-    /**
-     * Adds a new property to the model, ordered before or after an existing property.
-     *
-     * @param position             controls whether the new property is ordered before or after the existing property
-     * @param existingPropertyName the name of an existing property (this must exist)
-     * @param propertyName         the new property to add
-     * @param conduit              conduit used to read or update the property; this may be null for a synthetic or
-     *                             placeholder property
-     * @return the new property model (for further configuration)
-     * @throws RuntimeException if the existing property does not exist, or if the new property already does exist
-     */
-    PropertyModel add(RelativePosition position, String existingPropertyName, String propertyName,
-                      PropertyConduit conduit);
-
-    /**
-     * Adds a new, synthetic property to the model, returning its mutable model for further refinement.
-     *
-     * @param propertyName name of property to add
-     * @param conduit      the conduit used to read or update the property; this may be null for a synthetic or
-     *                     placeholder property.  Instead of passing null, please invoke {@link #addEmpty(String)}.
-     * @return the model for the property
-     * @throws RuntimeException if the property already exists
-     * @see #addExpression(String, String)
-     */
-    PropertyModel add(String propertyName, PropertyConduit conduit);
-
-    /**
-     * Removes the named properties from the model, if present. It is not considered an error to remove a property that
-     * does not exist.
-     *
-     * @param propertyNames the names of properties to be removed (case insensitive)
-     * @return the model for further modifications
-     */
-    BeanModel<T> exclude(String... propertyNames);
-
-    /**
-     * Re-orders the properties of the model into the specified order. Existing properties that are not indicated are
-     * retained, but ordered to the end of the list.
-     *
-     * @param propertyNames property names in order they should be displayed (case insensitive)
-     * @return the model for further modifications
-     */
-    BeanModel<T> reorder(String... propertyNames);
-
-    /**
-     * Re-orders the properties of the model into the specified order. Existing properties that are not indicated are
-     * <<removed>>.
-     *
-     * @param propertyNames the names of properties to be retained
-     * @return the model for further modifications
-     */
-    BeanModel<T> include(String... propertyNames);
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/PropertyModel.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/PropertyModel.java b/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/PropertyModel.java
deleted file mode 100644
index 6095fb9..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/PropertyModel.java
+++ /dev/null
@@ -1,97 +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.beaneditor;
-
-import org.apache.tapestry5.PropertyConduit;
-import org.apache.tapestry5.ioc.AnnotationProvider;
-
-/**
- * Part of a {@link org.apache.tapestry5.beaneditor.BeanModel} that defines the attributes of a single property of a
- * bean.
- * <p/>
- * <p/>
- * A PropertyModel is also an {@link AnnotationProvider}, as long as the {@link org.apache.tapestry5.PropertyConduit} is
- * non-null.  When there is no property conduit, then {@link org.apache.tapestry5.ioc.AnnotationProvider#getAnnotation(Class)}
- * will return null.
- */
-public interface PropertyModel extends AnnotationProvider
-{
-    /**
-     * Returns the name of the property (which may, in fact, be a property expression).
-     */
-    String getPropertyName();
-
-    /**
-     * Returns the id used to access other resources (this is based on the property name, but with any excess
-     * punctuation stripped out).
-     */
-    String getId();
-
-    /**
-     * Returns a user-presentable label for the property.
-     */
-    String getLabel();
-
-    /**
-     * Returns the type of the property.
-     */
-    Class getPropertyType();
-
-    /**
-     * Returns a logical name for the type of UI needed to view or edit the property. This is initially determined from
-     * the property type.
-     */
-    String getDataType();
-
-    /**
-     * Changes the data type for the property.
-     *
-     * @param dataType
-     * @return the property model, for further changes
-     */
-    PropertyModel dataType(String dataType);
-
-    /**
-     * Returns an object used to read or update the property. For virtual properties (properties that do not actually
-     * exist on the bean), the conduit may be null.
-     */
-    PropertyConduit getConduit();
-
-    /**
-     * Changes the label for the property to the provided value.
-     *
-     * @param label new label for property
-     * @return the property model, for further changes
-     */
-    PropertyModel label(String label);
-
-    /**
-     * Returns the containing model, often used for "fluent" construction of the model.
-     */
-    BeanModel model();
-
-    /**
-     * Returns true if the property can be used for sorting. By default, this is true only if the property type
-     * implements Comparable.
-     */
-    boolean isSortable();
-
-    /**
-     * Updates sortable and returns the model for further changes.
-     *
-     * @return the property model, for further changes
-     */
-    PropertyModel sortable(boolean sortable);
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalPropertyConduit.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalPropertyConduit.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalPropertyConduit.java
deleted file mode 100644
index 315b372..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalPropertyConduit.java
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 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.internal;
-
-import org.apache.tapestry5.PropertyConduit2;
-
-
-/**
- * Extension to {@link org.apache.tapestry5.PropertyConduit2} that adds a method to determine the name of the property.
- * 
- * @since 5.2.0
- *
- */
-public interface InternalPropertyConduit extends PropertyConduit2
-{
-    /**
-     * Returns the name of the property read or updated by the conduit or null. 
-     * If the expression points to a property on a bean (e.g. user.name) this method returns the last property in the chain. 
-     * Otherwise this method returns {@code null}.
-     * 
-     * @return property name or {@code null}
-     * 
-     */
-    String getPropertyName();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
deleted file mode 100644
index 26eb309..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
+++ /dev/null
@@ -1,289 +0,0 @@
-// Copyright 2007, 2008, 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.internal.beaneditor;
-
-import org.apache.tapestry5.PropertyConduit;
-import org.apache.tapestry5.beaneditor.BeanModel;
-import org.apache.tapestry5.beaneditor.PropertyModel;
-import org.apache.tapestry5.beaneditor.RelativePosition;
-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.InternalUtils;
-import org.apache.tapestry5.ioc.services.TypeCoercer;
-import org.apache.tapestry5.ioc.util.AvailableValues;
-import org.apache.tapestry5.ioc.util.UnknownValueException;
-import org.apache.tapestry5.plastic.PlasticUtils;
-import org.apache.tapestry5.services.PropertyConduitSource;
-
-import java.util.List;
-import java.util.Map;
-
-public class BeanModelImpl<T> implements BeanModel<T>
-{
-    private final Class<T> beanType;
-
-    private final PropertyConduitSource propertyConduitSource;
-
-    private final TypeCoercer typeCoercer;
-
-    private final Messages messages;
-
-    private final ObjectLocator locator;
-
-    private final Map<String, PropertyModel> properties = CollectionFactory.newCaseInsensitiveMap();
-
-    // The list of property names, in desired order (generally not alphabetical order).
-
-    private final List<String> propertyNames = CollectionFactory.newList();
-
-    private static PropertyConduit NULL_PROPERTY_CONDUIT = null;
-
-    public BeanModelImpl(Class<T> beanType, PropertyConduitSource propertyConduitSource, TypeCoercer typeCoercer,
-                         Messages messages, ObjectLocator locator)
-
-    {
-        this.beanType = beanType;
-        this.propertyConduitSource = propertyConduitSource;
-        this.typeCoercer = typeCoercer;
-        this.messages = messages;
-        this.locator = locator;
-    }
-
-    public Class<T> getBeanType()
-    {
-        return beanType;
-    }
-
-    public T newInstance()
-    {
-        return locator.autobuild("Instantiating new instance of " + beanType.getName(), beanType);
-    }
-
-    public PropertyModel add(String propertyName)
-    {
-        return addExpression(propertyName, propertyName);
-    }
-
-    public PropertyModel addEmpty(String propertyName)
-    {
-        return add(propertyName, NULL_PROPERTY_CONDUIT);
-    }
-
-    public PropertyModel addExpression(String propertyName, String expression)
-    {
-        PropertyConduit conduit = createConduit(expression);
-
-        return add(propertyName, conduit);
-
-    }
-
-    private void validateNewPropertyName(String propertyName)
-    {
-        assert InternalUtils.isNonBlank(propertyName);
-        if (properties.containsKey(propertyName))
-            throw new RuntimeException(String.format(
-                    "Bean editor model for %s already contains a property model for property '%s'.",
-                    beanType.getName(), propertyName));
-    }
-
-    public PropertyModel add(RelativePosition position, String existingPropertyName, String propertyName,
-                             PropertyConduit conduit)
-    {
-        assert position != null;
-        validateNewPropertyName(propertyName);
-
-        // Locate the existing one.
-
-        PropertyModel existing = get(existingPropertyName);
-
-        // Use the case normalized property name.
-
-        int pos = propertyNames.indexOf(existing.getPropertyName());
-
-        PropertyModel newModel = new PropertyModelImpl(this, propertyName, conduit, messages);
-
-        properties.put(propertyName, newModel);
-
-        int offset = position == RelativePosition.AFTER ? 1 : 0;
-
-        propertyNames.add(pos + offset, propertyName);
-
-        return newModel;
-    }
-
-    public PropertyModel add(RelativePosition position, String existingPropertyName, String propertyName)
-    {
-        PropertyConduit conduit = createConduit(propertyName);
-
-        return add(position, existingPropertyName, propertyName, conduit);
-    }
-
-    public PropertyModel add(String propertyName, PropertyConduit conduit)
-    {
-        validateNewPropertyName(propertyName);
-
-        PropertyModel propertyModel = new PropertyModelImpl(this, propertyName, conduit, messages);
-
-        properties.put(propertyName, propertyModel);
-
-        // Remember the order in which the properties were added.
-
-        propertyNames.add(propertyName);
-
-        return propertyModel;
-    }
-
-    private CoercingPropertyConduitWrapper createConduit(String propertyName)
-    {
-        return new CoercingPropertyConduitWrapper(propertyConduitSource.create(beanType, propertyName), typeCoercer);
-    }
-
-    public PropertyModel get(String propertyName)
-    {
-        PropertyModel propertyModel = properties.get(propertyName);
-
-        if (propertyModel == null)
-            throw new UnknownValueException(String.format(
-                    "Bean editor model for %s does not contain a property named '%s'.", beanType.getName(),
-                    propertyName), new AvailableValues("Defined properties", propertyNames));
-
-        return propertyModel;
-    }
-
-    public PropertyModel getById(String propertyId)
-    {
-        for (PropertyModel model : properties.values())
-        {
-            if (model.getId().equalsIgnoreCase(propertyId))
-                return model;
-        }
-
-        // Not found, so we throw an exception. A bit of work to set
-        // up the exception however.
-
-        List<String> ids = CollectionFactory.newList();
-
-        for (PropertyModel model : properties.values())
-        {
-            ids.add(model.getId());
-        }
-
-        throw new UnknownValueException(String.format(
-                "Bean editor model for %s does not contain a property with id '%s'.", beanType.getName(), propertyId),
-                new AvailableValues("Defined property ids", ids));
-    }
-
-    public List<String> getPropertyNames()
-    {
-        return CollectionFactory.newList(propertyNames);
-    }
-
-    public BeanModel<T> exclude(String... propertyNames)
-    {
-        for (String propertyName : propertyNames)
-        {
-            PropertyModel model = properties.get(propertyName);
-
-            if (model == null)
-                continue;
-
-            // De-referencing from the model is needed because the name provided may not be a
-            // case-exact match, so we get the normalized or canonical name from the model because
-            // that's the one in propertyNames.
-
-            this.propertyNames.remove(model.getPropertyName());
-
-            properties.remove(propertyName);
-        }
-
-        return this;
-    }
-
-    public BeanModel<T> reorder(String... propertyNames)
-    {
-        List<String> remainingPropertyNames = CollectionFactory.newList(this.propertyNames);
-        List<String> reorderedPropertyNames = CollectionFactory.newList();
-
-        for (String name : propertyNames)
-        {
-            PropertyModel model = get(name);
-
-            // Get the canonical form (which may differ from name in terms of case)
-            String canonical = model.getPropertyName();
-
-            reorderedPropertyNames.add(canonical);
-
-            remainingPropertyNames.remove(canonical);
-        }
-
-        this.propertyNames.clear();
-        this.propertyNames.addAll(reorderedPropertyNames);
-
-        // Any unspecified names are ordered to the end. Don't want them? Remove them instead.
-        this.propertyNames.addAll(remainingPropertyNames);
-
-        return this;
-    }
-
-    public BeanModel<T> include(String... propertyNames)
-    {
-        List<String> reorderedPropertyNames = CollectionFactory.newList();
-        Map<String, PropertyModel> reduced = CollectionFactory.newCaseInsensitiveMap();
-
-        for (String name : propertyNames)
-        {
-
-            PropertyModel model = get(name);
-
-            String canonical = model.getPropertyName();
-
-            reorderedPropertyNames.add(canonical);
-            reduced.put(canonical, model);
-
-        }
-
-        this.propertyNames.clear();
-        this.propertyNames.addAll(reorderedPropertyNames);
-
-        properties.clear();
-        properties.putAll(reduced);
-
-        return this;
-    }
-
-    @Override
-    public String toString()
-    {
-        StringBuilder builder = new StringBuilder("BeanModel[");
-        builder.append(PlasticUtils.toTypeName(beanType));
-
-        builder.append(" properties:");
-        String sep = "";
-
-        for (String name : propertyNames)
-        {
-            builder.append(sep);
-            builder.append(name);
-
-            sep = ", ";
-        }
-
-        builder.append("]");
-
-        return builder.toString();
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
deleted file mode 100644
index 703ce44..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright 2007, 2008, 2010, 2011, 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.internal.beaneditor;
-
-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.TapestryInternalUtils;
-import org.apache.tapestry5.ioc.Messages;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.plastic.PlasticUtils;
-
-import java.lang.annotation.Annotation;
-
-@SuppressWarnings("all")
-public class PropertyModelImpl implements PropertyModel
-{
-    private final BeanModel model;
-
-    private final String name;
-
-    private final PropertyConduit conduit;
-
-    private final String id;
-
-    private String label;
-
-    private String dataType;
-
-    private boolean sortable;
-
-    public PropertyModelImpl(BeanModel model, String name, PropertyConduit conduit, Messages messages)
-    {
-        this.model = model;
-        this.name = name;
-        this.conduit = conduit;
-
-        id = TapestryInternalUtils.extractIdFromPropertyExpression(name);
-
-        label = TapestryInternalUtils.defaultLabel(id, messages, name);
-
-        // TAP5-2305
-        if (conduit != null)
-        {
-            Sortable sortableAnnotation = conduit.getAnnotation(Sortable.class);
-            if (sortableAnnotation != null)
-            {
-                sortable = sortableAnnotation.value();
-            }
-            else
-            {
-                // Primitive types need to be converted to wrapper types before checking to see
-                // if they are sortable.
-                Class wrapperType = PlasticUtils.toWrapperType(getPropertyType());
-                sortable = Comparable.class.isAssignableFrom(wrapperType);
-            }
-        }
-    }
-
-    public String getId()
-    {
-        return id;
-    }
-
-    public Class getPropertyType()
-    {
-        return conduit == null ? Object.class : conduit.getPropertyType();
-    }
-
-    public PropertyConduit getConduit()
-    {
-        return conduit;
-    }
-
-    public PropertyModel label(String label)
-    {
-        assert InternalUtils.isNonBlank(label);
-        this.label = label;
-
-        return this;
-    }
-
-    public String getLabel()
-    {
-        return label;
-    }
-
-    public String getPropertyName()
-    {
-        return name;
-    }
-
-    public BeanModel model()
-    {
-        return model;
-    }
-
-    public PropertyModel dataType(String dataType)
-    {
-        this.dataType = dataType;
-
-        return this;
-    }
-
-    public String getDataType()
-    {
-        return dataType;
-    }
-
-    public boolean isSortable()
-    {
-        return sortable;
-    }
-
-    public PropertyModel sortable(boolean sortable)
-    {
-        this.sortable = sortable;
-
-        return this;
-    }
-
-    public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
-    {
-        return conduit == null ? null : conduit.getAnnotation(annotationClass);
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
deleted file mode 100644
index 4dbfb2d..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2007 The Apache Software Foundation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.apache.tapestry5.internal.services;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-
-import org.apache.tapestry5.PropertyConduit;
-import org.apache.tapestry5.PropertyConduit2;
-import org.apache.tapestry5.ioc.services.TypeCoercer;
-
-public class CoercingPropertyConduitWrapper implements PropertyConduit2
-{
-    private final PropertyConduit conduit;
-
-    private final TypeCoercer coercer;
-
-    public CoercingPropertyConduitWrapper(final PropertyConduit conduit, final TypeCoercer coercer)
-    {
-        this.conduit = conduit;
-        this.coercer = coercer;
-    }
-
-    public Object get(Object instance)
-    {
-        return conduit.get(instance);
-    }
-
-    public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
-    {
-        return conduit.getAnnotation(annotationClass);
-    }
-
-    public Class getPropertyType()
-    {
-        return conduit.getPropertyType();
-    }
-    
-    public Type getPropertyGenericType()
-    {
-    	if (conduit instanceof PropertyConduit2) {
-    		return ((PropertyConduit2) conduit).getPropertyGenericType();
-    	}
-    	return conduit.getPropertyType();
-    }
-
-    @SuppressWarnings("unchecked")
-    public void set(Object instance, Object value)
-    {
-        Object coerced = coercer.coerce(value, getPropertyType());
-
-        conduit.set(instance, coerced);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
deleted file mode 100644
index 1242031..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2007, 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.internal.services;
-
-import java.lang.annotation.Annotation;
-
-import org.apache.tapestry5.internal.InternalPropertyConduit;
-import org.apache.tapestry5.internal.util.IntegerRange;
-import org.apache.tapestry5.ioc.AnnotationProvider;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.ioc.services.TypeCoercer;
-
-/**
- * Companion class for {@link org.apache.tapestry5.PropertyConduit} instances created by the
- * {@link org.apache.tapestry5.services.PropertyConduitSource}.
- */
-@SuppressWarnings("all")
-public class PropertyConduitDelegate
-{
-    private final TypeCoercer typeCoercer;
-
-    public PropertyConduitDelegate(TypeCoercer typeCoercer)
-    {
-        this.typeCoercer = typeCoercer;
-    }
-
-    public final IntegerRange range(int from, int to)
-    {
-        return new IntegerRange(from, to);
-    }
-
-    public final <T> T coerce(Object value, Class<T> type)
-    {
-        return typeCoercer.coerce(value, type);
-    }
-
-    public final boolean invert(Object value)
-    {
-        return coerce(value, Boolean.class).equals(Boolean.FALSE);
-    }
-}


[03/15] tapestry-5 git commit: First pass creating the BeanModel and Commons packages. Lots of stuff moved around, but no actual code changes so far

Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
deleted file mode 100644
index 701420f..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
+++ /dev/null
@@ -1,1563 +0,0 @@
-// Copyright 2007-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.internal.services;
-
-import org.antlr.runtime.ANTLRInputStream;
-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.InternalPropertyConduit;
-import org.apache.tapestry5.internal.antlr.PropertyExpressionLexer;
-import org.apache.tapestry5.internal.antlr.PropertyExpressionParser;
-import org.apache.tapestry5.internal.util.IntegerRange;
-import org.apache.tapestry5.internal.util.MultiKey;
-import org.apache.tapestry5.ioc.AnnotationProvider;
-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.InternalUtils;
-import org.apache.tapestry5.ioc.services.*;
-import org.apache.tapestry5.ioc.util.AvailableValues;
-import org.apache.tapestry5.ioc.util.ExceptionUtils;
-import org.apache.tapestry5.ioc.util.UnknownValueException;
-import org.apache.tapestry5.plastic.*;
-import org.apache.tapestry5.services.ComponentClasses;
-import org.apache.tapestry5.services.ComponentLayer;
-import org.apache.tapestry5.services.InvalidationEventHub;
-import org.apache.tapestry5.services.PropertyConduitSource;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.*;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.*;
-
-public class PropertyConduitSourceImpl implements PropertyConduitSource
-{
-    static class ConduitMethods
-    {
-        private static final MethodDescription GET = getMethodDescription(PropertyConduit.class, "get", Object.class);
-
-        private static final MethodDescription SET = getMethodDescription(PropertyConduit.class, "set", Object.class,
-                Object.class);
-
-        private static final MethodDescription GET_PROPERTY_TYPE = getMethodDescription(PropertyConduit.class,
-                "getPropertyType");
-
-        private static final MethodDescription GET_PROPERTY_GENERIC_TYPE = getMethodDescription(PropertyConduit2.class,
-                "getPropertyGenericType");
-        
-        private static final MethodDescription GET_PROPERTY_NAME = getMethodDescription(InternalPropertyConduit.class,
-                "getPropertyName");
-        
-        private static final MethodDescription GET_ANNOTATION = getMethodDescription(AnnotationProvider.class,
-                "getAnnotation", Class.class);
-
-    }
-
-    static class DelegateMethods
-    {
-        static final Method INVERT = getMethod(PropertyConduitDelegate.class, "invert", Object.class);
-
-        static final Method RANGE = getMethod(PropertyConduitDelegate.class, "range", int.class, int.class);
-
-        static final Method COERCE = getMethod(PropertyConduitDelegate.class, "coerce", Object.class, Class.class);
-    }
-
-    static class ArrayListMethods
-    {
-        static final Method ADD = getMethod(ArrayList.class, "add", Object.class);
-    }
-
-    static class HashMapMethods
-    {
-        static final Method PUT = getMethod(HashMap.class, "put", Object.class, Object.class);
-    }
-
-    private static InstructionBuilderCallback RETURN_NULL = new InstructionBuilderCallback()
-    {
-        public void doBuild(InstructionBuilder builder)
-        {
-            builder.loadNull().returnResult();
-        }
-    };
-
-    private static final String[] SINGLE_OBJECT_ARGUMENT = new String[]
-            {Object.class.getName()};
-
-    @SuppressWarnings("unchecked")
-    private static Method getMethod(Class containingClass, String name, Class... parameterTypes)
-    {
-        try
-        {
-            return containingClass.getMethod(name, parameterTypes);
-        } catch (NoSuchMethodException ex)
-        {
-            throw new IllegalArgumentException(ex);
-        }
-    }
-
-    private static MethodDescription getMethodDescription(Class containingClass, String name, Class... parameterTypes)
-    {
-        return new MethodDescription(getMethod(containingClass, name, parameterTypes));
-    }
-
-    private final AnnotationProvider nullAnnotationProvider = new NullAnnotationProvider();
-
-    /**
-     * How are null values in intermdiate terms to be handled?
-     */
-    private enum NullHandling
-    {
-        /**
-         * Add code to check for null and throw exception if null.
-         */
-        FORBID,
-
-        /**
-         * Add code to check for null and short-circuit (i.e., the "?."
-         * safe-dereference operator)
-         */
-        ALLOW
-    }
-
-    /**
-     * One term in an expression. Expressions start with some root type and each term advances
-     * to a new type.
-     */
-    private class Term
-    {
-        /**
-         * The generic type of the term.
-         */
-        final Type type;
-
-        final Class genericType;
-
-        /**
-         * Describes the term, for use in error messages.
-         */
-        final String description;
-
-        final AnnotationProvider annotationProvider;
-
-        /**
-         * Callback that will implement the term.
-         */
-        final InstructionBuilderCallback callback;
-
-        Term(Type type, Class genericType, String description, AnnotationProvider annotationProvider,
-             InstructionBuilderCallback callback)
-        {
-            this.type = type;
-            this.genericType = genericType;
-            this.description = description;
-            this.annotationProvider = annotationProvider;
-            this.callback = callback;
-        }
-
-        Term(Type type, String description, AnnotationProvider annotationProvider, InstructionBuilderCallback callback)
-        {
-            this(type, GenericsUtils.asClass(type), description, annotationProvider, callback);
-        }
-
-        Term(Type type, String description, InstructionBuilderCallback callback)
-        {
-            this(type, description, null, callback);
-        }
-
-        /**
-         * Returns a clone of this Term with a new callback.
-         */
-        Term withCallback(InstructionBuilderCallback newCallback)
-        {
-            return new Term(type, genericType, description, annotationProvider, newCallback);
-        }
-    }
-
-    private final PropertyAccess access;
-
-    private final PlasticProxyFactory proxyFactory;
-
-    private final TypeCoercer typeCoercer;
-
-    private final StringInterner interner;
-
-    /**
-     * Keyed on combination of root class and expression.
-     */
-    private final Map<MultiKey, PropertyConduit> cache = CollectionFactory.newConcurrentMap();
-
-    private final Invariant invariantAnnotation = new Invariant()
-    {
-        public Class<? extends Annotation> annotationType()
-        {
-            return Invariant.class;
-        }
-    };
-
-    private final AnnotationProvider invariantAnnotationProvider = new AnnotationProvider()
-    {
-        public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
-        {
-            if (annotationClass == Invariant.class)
-                return annotationClass.cast(invariantAnnotation);
-
-            return null;
-        }
-    };
-
-    private final PropertyConduit literalTrue;
-
-    private final PropertyConduit literalFalse;
-
-    private final PropertyConduit literalNull;
-
-    private final PropertyConduitDelegate sharedDelegate;
-
-    /**
-     * Encapsulates the process of building a PropertyConduit instance from an
-     * expression, as an {@link PlasticClassTransformer}.
-     */
-    class PropertyConduitBuilder implements PlasticClassTransformer
-    {
-        private final Class rootType;
-
-        private final String expression;
-
-        private final Tree tree;
-
-        private Class conduitPropertyType;
-
-        private Type conduitPropertyGenericType;
-
-        private String conduitPropertyName;
-
-        private AnnotationProvider annotationProvider = nullAnnotationProvider;
-
-        private PlasticField delegateField;
-
-        private PlasticClass plasticClass;
-
-        private PlasticMethod getRootMethod, navMethod;
-
-        PropertyConduitBuilder(Class rootType, String expression, Tree tree)
-        {
-            this.rootType = rootType;
-            this.expression = expression;
-            this.tree = tree;
-        }
-
-        public void transform(PlasticClass plasticClass)
-        {
-            this.plasticClass = plasticClass;
-
-            // Create the various methods; also determine the conduit's property type, property name and identify
-            // the annotation provider.
-
-            implementNavMethodAndAccessors();
-
-            implementOtherMethods();
-
-            plasticClass.addToString(String.format("PropertyConduit[%s %s]", rootType.getName(), expression));
-        }
-
-        private void implementOtherMethods()
-        {
-            PlasticField annotationProviderField = plasticClass.introduceField(AnnotationProvider.class,
-                    "annotationProvider").inject(annotationProvider);
-
-            plasticClass.introduceMethod(ConduitMethods.GET_ANNOTATION).delegateTo(annotationProviderField);
-
-            plasticClass.introduceMethod(ConduitMethods.GET_PROPERTY_NAME, new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    builder.loadConstant(conduitPropertyName).returnResult();
-                }
-            });
-
-            final PlasticField propertyTypeField = plasticClass.introduceField(Class.class, "propertyType").inject(
-                    conduitPropertyType);
-
-            plasticClass.introduceMethod(ConduitMethods.GET_PROPERTY_TYPE, new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    builder.loadThis().getField(propertyTypeField).returnResult();
-                }
-            });
-
-            final PlasticField propertyGenericTypeField = plasticClass.introduceField(Type.class, "propertyGenericType").inject(
-                    conduitPropertyGenericType);
-
-            plasticClass.introduceMethod(ConduitMethods.GET_PROPERTY_GENERIC_TYPE, new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    builder.loadThis().getField(propertyGenericTypeField).returnResult();
-                }
-            });
-        }
-
-        /**
-         * Creates a method that does a conversion from Object to the expected root type, with
-         * a null check.
-         */
-        private void implementGetRoot()
-        {
-            getRootMethod = plasticClass.introducePrivateMethod(PlasticUtils.toTypeName(rootType), "getRoot",
-                    SINGLE_OBJECT_ARGUMENT, null);
-
-            getRootMethod.changeImplementation(new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    builder.loadArgument(0).dupe().when(Condition.NULL, new InstructionBuilderCallback()
-                    {
-                        public void doBuild(InstructionBuilder builder)
-                        {
-                            builder.throwException(NullPointerException.class,
-                                    String.format("Root object of property expression '%s' is null.", expression));
-                        }
-                    });
-
-                    builder.checkcast(rootType).returnResult();
-                }
-            });
-        }
-
-        private boolean isLeaf(Tree node)
-        {
-            int type = node.getType();
-
-            return type != DEREF && type != SAFEDEREF;
-        }
-
-        private void implementNavMethodAndAccessors()
-        {
-            implementGetRoot();
-
-            // First, create the navigate method.
-
-            final List<InstructionBuilderCallback> callbacks = CollectionFactory.newList();
-
-            Type activeType = rootType;
-
-            Tree node = tree;
-
-            while (!isLeaf(node))
-            {
-                Term term = analyzeDerefNode(activeType, node);
-
-                callbacks.add(term.callback);
-
-                activeType = term.type;
-
-                // Second term is the continuation, possibly another chained
-                // DEREF, etc.
-                node = node.getChild(1);
-            }
-
-            Class activeClass = GenericsUtils.asClass(activeType);
-
-            if (callbacks.isEmpty())
-            {
-                navMethod = getRootMethod;
-            } else
-            {
-                navMethod = plasticClass.introducePrivateMethod(PlasticUtils.toTypeName(activeClass), "navigate",
-                        SINGLE_OBJECT_ARGUMENT, null);
-
-                navMethod.changeImplementation(new InstructionBuilderCallback()
-                {
-                    public void doBuild(InstructionBuilder builder)
-                    {
-                        builder.loadThis().loadArgument(0).invokeVirtual(getRootMethod);
-
-                        for (InstructionBuilderCallback callback : callbacks)
-                        {
-                            callback.doBuild(builder);
-                        }
-
-                        builder.returnResult();
-                    }
-                });
-            }
-
-            implementAccessors(activeType, node);
-        }
-
-        private void implementAccessors(Type activeType, Tree node)
-        {
-            switch (node.getType())
-            {
-                case IDENTIFIER:
-
-                    implementPropertyAccessors(activeType, node);
-
-                    return;
-
-                case INVOKE:
-
-                    // So, at this point, we have the navigation method written
-                    // and it covers all but the terminal
-                    // de-reference. node is an IDENTIFIER or INVOKE. We're
-                    // ready to use the navigation
-                    // method to implement get() and set().
-
-                    implementMethodAccessors(activeType, node);
-
-                    return;
-
-                case RANGEOP:
-
-                    // As currently implemented, RANGEOP can only appear as the
-                    // top level, which
-                    // means we didn't need the navigate method after all.
-
-                    implementRangeOpGetter(node);
-                    implementNoOpSetter();
-
-                    conduitPropertyType = IntegerRange.class;
-                    conduitPropertyGenericType = IntegerRange.class;
-
-                    return;
-
-                case LIST:
-
-                    implementListGetter(node);
-                    implementNoOpSetter();
-
-                    conduitPropertyType = List.class;
-                    conduitPropertyGenericType = List.class;
-                    
-                    return;
-
-                case MAP:
-                    implementMapGetter(node);
-                    implementNoOpSetter();
-
-                    conduitPropertyType = Map.class;
-                    conduitPropertyGenericType = Map.class;
-
-                    return;
-
-
-                case NOT:
-                    implementNotOpGetter(node);
-                    implementNoOpSetter();
-
-                    conduitPropertyType = boolean.class;
-                    conduitPropertyGenericType = boolean.class;
-
-                    return;
-
-                default:
-                    throw unexpectedNodeType(node, IDENTIFIER, INVOKE, RANGEOP, LIST, NOT);
-            }
-        }
-
-        public void implementMethodAccessors(final Type activeType, final Tree invokeNode)
-        {
-            final Term term = buildInvokeTerm(activeType, invokeNode);
-
-            implementNoOpSetter();
-
-            conduitPropertyName = term.description;
-            conduitPropertyType = term.genericType;
-            conduitPropertyGenericType = term.genericType;
-            annotationProvider = term.annotationProvider;
-
-            plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    invokeNavigateMethod(builder);
-
-                    term.callback.doBuild(builder);
-
-                    boxIfPrimitive(builder, conduitPropertyType);
-
-                    builder.returnResult();
-                }
-            });
-
-            implementNoOpSetter();
-        }
-
-        public void implementPropertyAccessors(Type activeType, Tree identifierNode)
-        {
-            String propertyName = identifierNode.getText();
-
-            PropertyAdapter adapter = findPropertyAdapter(activeType, propertyName);
-
-            conduitPropertyName = propertyName;
-            conduitPropertyType = adapter.getType();
-            conduitPropertyGenericType = getGenericType(adapter);
-            annotationProvider = adapter;
-
-            implementGetter(adapter);
-            implementSetter(adapter);
-        }
-
-        private Type getGenericType(PropertyAdapter adapter)
-        {
-        	Type genericType = null;
-        	if (adapter.getField() != null)
-        	{
-        		genericType = adapter.getField().getGenericType();
-        	}
-        	else if (adapter.getReadMethod() != null)
-        	{
-        		genericType = adapter.getReadMethod().getGenericReturnType(); 
-        	}
-        	else if (adapter.getWriteMethod() != null)
-        	{
-        		genericType = adapter.getWriteMethod().getGenericParameterTypes()[0];
-        	}
-        	else
-        	{
-        		throw new RuntimeException("Could not find accessor for property " + adapter.getName());
-        	}
-        	
-        	return genericType == null ? adapter.getType() : genericType;
-		}
-
-		private void implementSetter(PropertyAdapter adapter)
-        {
-            if (adapter.getWriteMethod() != null)
-            {
-                implementSetter(adapter.getWriteMethod());
-                return;
-            }
-
-            if (adapter.getField() != null && adapter.isUpdate())
-            {
-                implementSetter(adapter.getField());
-                return;
-            }
-
-            implementNoOpMethod(ConduitMethods.SET, "Expression '%s' for class %s is read-only.", expression,
-                    rootType.getName());
-        }
-
-        private boolean isStatic(Member member)
-        {
-            return Modifier.isStatic(member.getModifiers());
-        }
-
-        private void implementSetter(final Field field)
-        {
-            if (isStatic(field))
-            {
-                plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback()
-                {
-                    public void doBuild(InstructionBuilder builder)
-                    {
-                        builder.loadArgument(1).castOrUnbox(PlasticUtils.toTypeName(field.getType()));
-
-                        builder.putStaticField(field.getDeclaringClass().getName(), field.getName(), field.getType());
-
-                        builder.returnResult();
-                    }
-                });
-
-                return;
-            }
-
-            plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    invokeNavigateMethod(builder);
-
-                    builder.loadArgument(1).castOrUnbox(PlasticUtils.toTypeName(field.getType()));
-
-                    builder.putField(field.getDeclaringClass().getName(), field.getName(), field.getType());
-
-                    builder.returnResult();
-                }
-            });
-        }
-
-        private void implementSetter(final Method writeMethod)
-        {
-            plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    invokeNavigateMethod(builder);
-
-                    Class propertyType = writeMethod.getParameterTypes()[0];
-                    String propertyTypeName = PlasticUtils.toTypeName(propertyType);
-
-                    builder.loadArgument(1).castOrUnbox(propertyTypeName);
-
-                    builder.invoke(writeMethod);
-
-                    builder.returnResult();
-                }
-            });
-        }
-
-        private void implementGetter(PropertyAdapter adapter)
-        {
-            if (adapter.getReadMethod() != null)
-            {
-                implementGetter(adapter.getReadMethod());
-                return;
-            }
-
-            if (adapter.getField() != null)
-            {
-                implementGetter(adapter.getField());
-                return;
-            }
-
-            implementNoOpMethod(ConduitMethods.GET, "Expression '%s' for class %s is write-only.", expression,
-                    rootType.getName());
-        }
-
-        private void implementGetter(final Field field)
-        {
-            if (isStatic(field))
-            {
-                plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
-                {
-                    public void doBuild(InstructionBuilder builder)
-                    {
-                        builder.getStaticField(field.getDeclaringClass().getName(), field.getName(), field.getType());
-
-                        // Cast not necessary here since the return type of get() is Object
-
-                        boxIfPrimitive(builder, field.getType());
-
-                        builder.returnResult();
-                    }
-                });
-
-                return;
-            }
-
-            plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    invokeNavigateMethod(builder);
-
-                    builder.getField(field.getDeclaringClass().getName(), field.getName(), field.getType());
-
-                    // Cast not necessary here since the return type of get() is Object
-
-                    boxIfPrimitive(builder, field.getType());
-
-                    builder.returnResult();
-                }
-            });
-        }
-
-        private void implementGetter(final Method readMethod)
-        {
-            plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    invokeNavigateMethod(builder);
-
-                    invokeMethod(builder, readMethod, null, 0);
-
-                    boxIfPrimitive(builder, conduitPropertyType);
-
-                    builder.returnResult();
-                }
-            });
-        }
-
-        private void implementRangeOpGetter(final Tree rangeNode)
-        {
-            plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    // Put the delegate on top of the stack
-
-                    builder.loadThis().getField(getDelegateField());
-
-                    invokeMethod(builder, DelegateMethods.RANGE, rangeNode, 0);
-
-                    builder.returnResult();
-                }
-            });
-        }
-
-        /**
-         * @param node
-         *         subexpression to invert
-         */
-        private void implementNotOpGetter(final Tree node)
-        {
-            // Implement get() as navigate, then do a method invocation based on node
-            // then, then pass (wrapped) result to delegate.invert()
-
-            plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    Type expressionType = implementNotExpression(builder, node);
-
-                    // Yes, we know this will always be the case, for now.
-
-                    boxIfPrimitive(builder, expressionType);
-
-                    builder.returnResult();
-                }
-            });
-        }
-
-        /**
-         * The first part of any implementation of get() or set(): invoke the navigation method
-         * and if the result is null, return immediately.
-         */
-        private void invokeNavigateMethod(InstructionBuilder builder)
-        {
-            builder.loadThis().loadArgument(0).invokeVirtual(navMethod);
-
-            builder.dupe().when(Condition.NULL, RETURN_NULL);
-        }
-
-        /**
-         * Uses the builder to add instructions for a subexpression.
-         *
-         * @param builder
-         *         used to add instructions
-         * @param activeType
-         *         type of value on top of the stack when this code will execute, or null if no value on stack
-         * @param node
-         *         defines the expression
-         * @return the expression type
-         */
-        private Type implementSubexpression(InstructionBuilder builder, Type activeType, Tree node)
-        {
-            Term term;
-
-            while (true)
-            {
-                switch (node.getType())
-                {
-                    case IDENTIFIER:
-                    case INVOKE:
-
-                        if (activeType == null)
-                        {
-                            invokeGetRootMethod(builder);
-
-                            activeType = rootType;
-                        }
-
-                        term = buildTerm(activeType, node);
-
-                        term.callback.doBuild(builder);
-
-                        return term.type;
-
-                    case INTEGER:
-
-                        builder.loadConstant(new Long(node.getText()));
-
-                        return long.class;
-
-                    case DECIMAL:
-
-                        builder.loadConstant(new Double(node.getText()));
-
-                        return double.class;
-
-                    case STRING:
-
-                        builder.loadConstant(node.getText());
-
-                        return String.class;
-
-                    case DEREF:
-                    case SAFEDEREF:
-
-                        if (activeType == null)
-                        {
-                            invokeGetRootMethod(builder);
-
-                            activeType = rootType;
-                        }
-
-                        term = analyzeDerefNode(activeType, node);
-
-                        term.callback.doBuild(builder);
-
-                        activeType = GenericsUtils.asClass(term.type);
-
-                        node = node.getChild(1);
-
-                        break;
-
-                    case TRUE:
-                    case FALSE:
-
-                        builder.loadConstant(node.getType() == TRUE ? 1 : 0);
-
-                        return boolean.class;
-
-                    case LIST:
-
-                        return implementListConstructor(builder, node);
-
-                    case MAP:
-                        return implementMapConstructor(builder, node);
-
-                    case NOT:
-
-                        return implementNotExpression(builder, node);
-
-                    case THIS:
-
-                        invokeGetRootMethod(builder);
-
-                        return rootType;
-
-                    case NULL:
-
-                        builder.loadNull();
-
-                        return Void.class;
-
-                    default:
-                        throw unexpectedNodeType(node, TRUE, FALSE, INTEGER, DECIMAL, STRING, DEREF, SAFEDEREF,
-                                IDENTIFIER, INVOKE, LIST, NOT, THIS, NULL);
-                }
-            }
-        }
-
-        public void invokeGetRootMethod(InstructionBuilder builder)
-        {
-            builder.loadThis().loadArgument(0).invokeVirtual(getRootMethod);
-        }
-
-        private void implementListGetter(final Tree listNode)
-        {
-            plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    implementListConstructor(builder, listNode);
-
-                    builder.returnResult();
-                }
-            });
-        }
-
-        private Type implementListConstructor(InstructionBuilder builder, Tree listNode)
-        {
-            // First, create an empty instance of ArrayList
-
-            int count = listNode.getChildCount();
-
-            builder.newInstance(ArrayList.class);
-            builder.dupe().loadConstant(count).invokeConstructor(ArrayList.class, int.class);
-
-            for (int i = 0; i < count; i++)
-            {
-                builder.dupe(); // the ArrayList
-
-                Type expressionType = implementSubexpression(builder, null, listNode.getChild(i));
-
-                boxIfPrimitive(builder, GenericsUtils.asClass(expressionType));
-
-                // Add the value to the array, then pop off the returned boolean
-                builder.invoke(ArrayListMethods.ADD).pop();
-            }
-
-            return ArrayList.class;
-        }
-
-        private void implementMapGetter(final Tree mapNode)
-        {
-            plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    implementMapConstructor(builder, mapNode);
-
-                    builder.returnResult();
-                }
-            });
-        }
-
-        private Type implementMapConstructor(InstructionBuilder builder, Tree mapNode)
-        {
-            int count = mapNode.getChildCount();
-            builder.newInstance(HashMap.class);
-            builder.dupe().loadConstant(count).invokeConstructor(HashMap.class, int.class);
-
-            for (int i = 0; i < count; i += 2)
-            {
-                builder.dupe();
-
-                //build the key:
-                Type keyType = implementSubexpression(builder, null, mapNode.getChild(i));
-                boxIfPrimitive(builder, GenericsUtils.asClass(keyType));
-
-                //and the value:
-                Type valueType = implementSubexpression(builder, null, mapNode.getChild(i + 1));
-                boxIfPrimitive(builder, GenericsUtils.asClass(valueType));
-
-                //put the value into the array, then pop off the returned object.
-                builder.invoke(HashMapMethods.PUT).pop();
-
-            }
-
-            return HashMap.class;
-        }
-
-
-        private void implementNoOpSetter()
-        {
-            implementNoOpMethod(ConduitMethods.SET, "Expression '%s' for class %s is read-only.", expression,
-                    rootType.getName());
-        }
-
-        public void implementNoOpMethod(MethodDescription method, String format, Object... arguments)
-        {
-            final String message = String.format(format, arguments);
-
-            plasticClass.introduceMethod(method).changeImplementation(new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    builder.throwException(RuntimeException.class, message);
-                }
-            });
-        }
-
-        /**
-         * Invokes a method that may take parameters. The children of the invokeNode are subexpressions
-         * to be evaluated, and potentially coerced, so that they may be passed to the method.
-         *
-         * @param builder
-         *         constructs code
-         * @param method
-         *         method to invoke
-         * @param node
-         *         INVOKE or RANGEOP node
-         * @param childOffset
-         *         offset within the node to the first child expression (1 in an INVOKE node because the
-         *         first child is the method name, 0 in a RANGEOP node)
-         */
-        private void invokeMethod(InstructionBuilder builder, Method method, Tree node, int childOffset)
-        {
-            // We start with the target object for the method on top of the stack.
-            // Next, we have to push each method parameter, which may include boxing/deboxing
-            // and coercion. Once the code is in good shape, there's a lot of room to optimize
-            // the bytecode (a bit too much boxing/deboxing occurs, as well as some unnecessary
-            // trips through TypeCoercer). We might also want to have a local variable to store
-            // the root object (result of getRoot()).
-
-            Class[] parameterTypes = method.getParameterTypes();
-
-            for (int i = 0; i < parameterTypes.length; i++)
-            {
-                Type expressionType = implementSubexpression(builder, null, node.getChild(i + childOffset));
-
-                // The value left on the stack is not primitive, and expressionType represents
-                // its real type.
-
-                Class parameterType = parameterTypes[i];
-
-                if (!parameterType.isAssignableFrom(GenericsUtils.asClass(expressionType)))
-                {
-                    boxIfPrimitive(builder, expressionType);
-
-                    builder.loadThis().getField(getDelegateField());
-                    builder.swap().loadTypeConstant(PlasticUtils.toWrapperType(parameterType));
-                    builder.invoke(DelegateMethods.COERCE);
-
-                    if (parameterType.isPrimitive())
-                    {
-                        builder.castOrUnbox(parameterType.getName());
-                    } else
-                    {
-                        builder.checkcast(parameterType);
-                    }
-                }
-
-                // And that should leave an object of the correct type on the stack,
-                // ready for the method invocation.
-            }
-
-            // Now the target object and all parameters are in place.
-
-            builder.invoke(method.getDeclaringClass(), method.getReturnType(), method.getName(),
-                    method.getParameterTypes());
-        }
-
-        /**
-         * Analyzes a DEREF or SAFEDEREF node, proving back a term that identifies its type and provides a callback to
-         * peform the dereference.
-         *
-         * @return a term indicating the type of the expression to this point, and a {@link InstructionBuilderCallback}
-         *         to advance the evaluation of the expression form the previous value to the current
-         */
-        private Term analyzeDerefNode(Type activeType, Tree node)
-        {
-            // The first child is the term.
-
-            Tree term = node.getChild(0);
-
-            boolean allowNull = node.getType() == SAFEDEREF;
-
-            return buildTerm(activeType, term, allowNull ? NullHandling.ALLOW : NullHandling.FORBID);
-        }
-
-        private Term buildTerm(Type activeType, Tree term, final NullHandling nullHandling)
-        {
-            assertNodeType(term, IDENTIFIER, INVOKE);
-
-            final Term simpleTerm = buildTerm(activeType, term);
-
-            if (simpleTerm.genericType.isPrimitive())
-                return simpleTerm;
-
-            return simpleTerm.withCallback(new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    simpleTerm.callback.doBuild(builder);
-
-                    builder.dupe().when(Condition.NULL, new InstructionBuilderCallback()
-                    {
-                        public void doBuild(InstructionBuilder builder)
-                        {
-                            switch (nullHandling)
-                            {
-                                // It is necessary to load a null onto the stack (even if there's already one
-                                // there) because of the verifier. It sees the return when the stack contains an
-                                // intermediate value (along the navigation chain) and thinks the method is
-                                // returning a value of the wrong type.
-
-                                case ALLOW:
-                                    builder.loadNull().returnResult();
-
-                                case FORBID:
-
-                                    builder.loadConstant(simpleTerm.description);
-                                    builder.loadConstant(expression);
-                                    builder.loadArgument(0);
-
-                                    builder.invokeStatic(PropertyConduitSourceImpl.class, NullPointerException.class,
-                                            "nullTerm", String.class, String.class, Object.class);
-                                    builder.throwException();
-
-                                    break;
-
-                            }
-                        }
-                    });
-                }
-            });
-        }
-
-        private void assertNodeType(Tree node, int... expected)
-        {
-            int type = node.getType();
-
-            for (int e : expected)
-            {
-                if (type == e)
-                    return;
-            }
-
-            throw unexpectedNodeType(node, expected);
-        }
-
-        private RuntimeException unexpectedNodeType(Tree node, int... expected)
-        {
-            List<String> tokenNames = CollectionFactory.newList();
-
-            for (int i = 0; i < expected.length; i++)
-                tokenNames.add(PropertyExpressionParser.tokenNames[expected[i]]);
-
-            String message = String.format("Node %s was type %s, but was expected to be (one of) %s.",
-                    node.toStringTree(), PropertyExpressionParser.tokenNames[node.getType()],
-                    InternalUtils.joinSorted(tokenNames));
-
-            return new RuntimeException(message);
-        }
-
-        private Term buildTerm(Type activeType, Tree termNode)
-        {
-            switch (termNode.getType())
-            {
-                case INVOKE:
-
-                    return buildInvokeTerm(activeType, termNode);
-
-                case IDENTIFIER:
-
-                    return buildPropertyAccessTerm(activeType, termNode);
-
-                default:
-                    throw unexpectedNodeType(termNode, INVOKE, IDENTIFIER);
-            }
-        }
-
-        private Term buildPropertyAccessTerm(Type activeType, Tree termNode)
-        {
-            String propertyName = termNode.getText();
-
-            PropertyAdapter adapter = findPropertyAdapter(activeType, propertyName);
-
-            // Prefer the accessor over the field
-
-            if (adapter.getReadMethod() != null)
-            {
-                return buildGetterMethodAccessTerm(activeType, propertyName,
-                        adapter.getReadMethod());
-            }
-
-            if (adapter.getField() != null)
-            {
-                return buildPublicFieldAccessTerm(activeType, propertyName,
-                        adapter.getField());
-            }
-
-            throw new RuntimeException(String.format(
-                    "Property '%s' of class %s is not readable (it has no read accessor method).", adapter.getName(),
-                    adapter.getBeanType().getName()));
-        }
-
-        public PropertyAdapter findPropertyAdapter(Type activeType, String propertyName)
-        {
-            Class activeClass = GenericsUtils.asClass(activeType);
-
-            ClassPropertyAdapter classAdapter = access.getAdapter(activeClass);
-            PropertyAdapter adapter = classAdapter.getPropertyAdapter(propertyName);
-
-            if (adapter == null)
-            {
-                final List<String> names = classAdapter.getPropertyNames();
-                final String className = activeClass.getName();
-                throw new UnknownValueException(String.format(
-                        "Class %s does not contain a property (or public field) named '%s'.", className, propertyName),
-                        new AvailableValues("Properties (and public fields)", names));
-            }
-            return adapter;
-        }
-
-        private Term buildGetterMethodAccessTerm(final Type activeType, String propertyName, final Method readMethod)
-        {
-            Type returnType = GenericsUtils.extractActualType(activeType, readMethod);
-
-            return new Term(returnType, propertyName, new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    invokeMethod(builder, readMethod, null, 0);
-
-                    Type genericType = GenericsUtils.extractActualType(activeType, readMethod);
-
-                    castToGenericType(builder, readMethod.getReturnType(), genericType);
-                }
-            });
-        }
-
-        private Term buildPublicFieldAccessTerm(Type activeType, String propertyName, final Field field)
-        {
-            final Type fieldType = GenericsUtils.extractActualType(activeType, field);
-
-            return new Term(fieldType, propertyName, new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    Class rawFieldType = field.getType();
-
-                    String rawTypeName = PlasticUtils.toTypeName(rawFieldType);
-                    String containingClassName = field.getDeclaringClass().getName();
-                    String fieldName = field.getName();
-
-                    if (isStatic(field))
-                    {
-                        // We've gone to the trouble of loading the root object, or navigated to some other object,
-                        // but we don't need or want the instance, since it's a static field we're accessing.
-                        // Ideally, we would optimize this, and only generate and invoke the getRoot() and nav() methods as needed, but
-                        // access to public fields is relatively rare, and the cost is just the unused bytecode.
-
-                        builder.pop();
-
-                        builder.getStaticField(containingClassName, fieldName, rawTypeName);
-
-                    } else
-                    {
-                        builder.getField(containingClassName, fieldName, rawTypeName);
-                    }
-
-                    castToGenericType(builder, rawFieldType, fieldType);
-                }
-
-            });
-        }
-
-        /**
-         * Casts the results of a field read or method invocation based on generic information.
-         *
-         * @param builder
-         *         used to add instructions
-         * @param rawType
-         *         the simple type (often Object) of the field (or method return type)
-         * @param genericType
-         *         the generic Type, from which parameterizations can be determined
-         */
-        private void castToGenericType(InstructionBuilder builder, Class rawType, final Type genericType)
-        {
-            if (!genericType.equals(rawType))
-            {
-                Class castType = GenericsUtils.asClass(genericType);
-                builder.checkcast(castType);
-            }
-        }
-
-        private Term buildInvokeTerm(final Type activeType, final Tree invokeNode)
-        {
-            String methodName = invokeNode.getChild(0).getText();
-
-            int parameterCount = invokeNode.getChildCount() - 1;
-
-            Class activeClass = GenericsUtils.asClass(activeType);
-
-            final Method method = findMethod(activeClass, methodName, parameterCount);
-
-            if (method.getReturnType().equals(void.class))
-                throw new RuntimeException(String.format("Method %s.%s() returns void.", activeClass.getName(),
-                        methodName));
-
-            Type returnType = GenericsUtils.extractActualType(activeType, method);
-
-            return new Term(returnType, toUniqueId(method), InternalUtils.toAnnotationProvider(method), new InstructionBuilderCallback()
-            {
-                public void doBuild(InstructionBuilder builder)
-                {
-                    invokeMethod(builder, method, invokeNode, 1);
-
-                    Type genericType = GenericsUtils.extractActualType(activeType, method);
-
-                    castToGenericType(builder, method.getReturnType(), genericType);
-                }
-            }
-            );
-        }
-
-        private Method findMethod(Class activeType, String methodName, int parameterCount)
-        {
-            Class searchType = activeType;
-
-            while (true)
-            {
-
-                for (Method method : searchType.getMethods())
-                {
-                    if (method.getParameterTypes().length == parameterCount
-                            && method.getName().equalsIgnoreCase(methodName))
-                        return method;
-                }
-
-                // TAP5-330
-                if (searchType != Object.class)
-                {
-                    searchType = Object.class;
-                } else
-                {
-                    throw new RuntimeException(String.format("Class %s does not contain a public method named '%s()'.",
-                            activeType.getName(), methodName));
-                }
-            }
-        }
-
-        public void boxIfPrimitive(InstructionBuilder builder, Type termType)
-        {
-            boxIfPrimitive(builder, GenericsUtils.asClass(termType));
-        }
-
-        public void boxIfPrimitive(InstructionBuilder builder, Class termType)
-        {
-            if (termType.isPrimitive())
-                builder.boxPrimitive(termType.getName());
-        }
-
-        public Class implementNotExpression(InstructionBuilder builder, final Tree notNode)
-        {
-            Type expressionType = implementSubexpression(builder, null, notNode.getChild(0));
-
-            boxIfPrimitive(builder, expressionType);
-
-            // Now invoke the delegate invert() method
-
-            builder.loadThis().getField(getDelegateField());
-
-            builder.swap().invoke(DelegateMethods.INVERT);
-
-            return boolean.class;
-        }
-
-        /**
-         * Defer creation of the delegate field unless actually needed.
-         */
-        private PlasticField getDelegateField()
-        {
-            if (delegateField == null)
-                delegateField = plasticClass.introduceField(PropertyConduitDelegate.class, "delegate").inject(
-                        sharedDelegate);
-
-            return delegateField;
-        }
-    }
-
-    public PropertyConduitSourceImpl(PropertyAccess access, @ComponentLayer
-    PlasticProxyFactory proxyFactory, TypeCoercer typeCoercer, StringInterner interner)
-    {
-        this.access = access;
-        this.proxyFactory = proxyFactory;
-        this.typeCoercer = typeCoercer;
-        this.interner = interner;
-
-        literalTrue = createLiteralConduit(Boolean.class, true);
-        literalFalse = createLiteralConduit(Boolean.class, false);
-        literalNull = createLiteralConduit(Void.class, null);
-
-        sharedDelegate = new PropertyConduitDelegate(typeCoercer);
-    }
-
-    @PostInjection
-    public void listenForInvalidations(@ComponentClasses InvalidationEventHub hub)
-    {
-        hub.clearOnInvalidation(cache);
-    }
-
-
-    public PropertyConduit create(Class rootClass, String expression)
-    {
-        assert rootClass != null;
-        assert InternalUtils.isNonBlank(expression);
-
-        MultiKey key = new MultiKey(rootClass, expression);
-
-        PropertyConduit result = cache.get(key);
-
-        if (result == null)
-        {
-            result = build(rootClass, expression);
-            cache.put(key, result);
-        }
-
-        return result;
-    }
-
-    /**
-     * Builds a subclass of {@link PropertyConduitDelegate} that implements the
-     * get() and set() methods and overrides the
-     * constructor. In a worst-case race condition, we may build two (or more)
-     * conduits for the same
-     * rootClass/expression, and it will get sorted out when the conduit is
-     * stored into the cache.
-     *
-     * @param rootClass
-     *         class of root object for expression evaluation
-     * @param expression
-     *         expression to be evaluated
-     * @return the conduit
-     */
-    private PropertyConduit build(final Class rootClass, String expression)
-    {
-        Tree tree = parse(expression);
-
-        try
-        {
-            switch (tree.getType())
-            {
-                case TRUE:
-
-                    return literalTrue;
-
-                case FALSE:
-
-                    return literalFalse;
-
-                case NULL:
-
-                    return literalNull;
-
-                case INTEGER:
-
-                    // Leading '+' may screw this up.
-                    // TODO: Singleton instance for "0", maybe "1"?
-
-                    return createLiteralConduit(Long.class, new Long(tree.getText()));
-
-                case DECIMAL:
-
-                    // Leading '+' may screw this up.
-                    // TODO: Singleton instance for "0.0"?
-
-                    return createLiteralConduit(Double.class, new Double(tree.getText()));
-
-                case STRING:
-
-                    return createLiteralConduit(String.class, tree.getText());
-
-                case RANGEOP:
-
-                    Tree fromNode = tree.getChild(0);
-                    Tree toNode = tree.getChild(1);
-
-                    // If the range is defined as integers (not properties, etc.)
-                    // then it is possible to calculate the value here, once, and not
-                    // build a new class.
-
-                    if (fromNode.getType() != INTEGER || toNode.getType() != INTEGER)
-                        break;
-
-                    int from = Integer.parseInt(fromNode.getText());
-                    int to = Integer.parseInt(toNode.getText());
-
-                    IntegerRange ir = new IntegerRange(from, to);
-
-                    return createLiteralConduit(IntegerRange.class, ir);
-
-                case THIS:
-
-                    return createLiteralThisPropertyConduit(rootClass);
-
-                default:
-                    break;
-            }
-
-            return proxyFactory.createProxy(InternalPropertyConduit.class,
-                    new PropertyConduitBuilder(rootClass, expression, tree)).newInstance();
-        } catch (Exception ex)
-        {
-            throw new PropertyExpressionException(String.format("Exception generating conduit for expression '%s': %s",
-                    expression, ExceptionUtils.toMessage(ex)), expression, ex);
-        }
-    }
-
-    private PropertyConduit createLiteralThisPropertyConduit(final Class rootClass)
-    {
-        return new PropertyConduit()
-        {
-            public Object get(Object instance)
-            {
-                return instance;
-            }
-
-            public void set(Object instance, Object value)
-            {
-                throw new RuntimeException("Literal values are not updateable.");
-            }
-
-            public Class getPropertyType()
-            {
-                return rootClass;
-            }
-            
-            public Type getPropertyGenericType()
-            {
-            	return rootClass;
-            }
-
-            public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
-            {
-                return invariantAnnotationProvider.getAnnotation(annotationClass);
-            }
-        };
-    }
-
-    private <T> PropertyConduit createLiteralConduit(Class<T> type, T value)
-    {
-        return new LiteralPropertyConduit(typeCoercer, type, invariantAnnotationProvider, interner.format(
-                "LiteralPropertyConduit[%s]", value), value);
-    }
-
-    private Tree parse(String expression)
-    {
-        InputStream is = new ByteArrayInputStream(expression.getBytes());
-
-        ANTLRInputStream ais;
-
-        try
-        {
-            ais = new ANTLRInputStream(is);
-        } catch (IOException ex)
-        {
-            throw new RuntimeException(ex);
-        }
-
-        PropertyExpressionLexer lexer = new PropertyExpressionLexer(ais);
-
-        CommonTokenStream tokens = new CommonTokenStream(lexer);
-
-        PropertyExpressionParser parser = new PropertyExpressionParser(tokens);
-
-        try
-        {
-            return (Tree) parser.start().getTree();
-        } catch (Exception ex)
-        {
-            throw new RuntimeException(String.format("Error parsing property expression '%s': %s.", expression,
-                    ex.getMessage()), ex);
-        }
-    }
-
-    /**
-     * May be invoked from fabricated PropertyConduit instances.
-     */
-    @SuppressWarnings("unused")
-    public static NullPointerException nullTerm(String term, String expression, Object root)
-    {
-        String message = String.format("Property '%s' (within property expression '%s', of %s) is null.", term,
-                expression, root);
-
-        return new NullPointerException(message);
-    }
-
-    private static String toUniqueId(Method method)
-    {
-        StringBuilder builder = new StringBuilder(method.getName()).append("(");
-        String sep = "";
-
-        for (Class parameterType : method.getParameterTypes())
-        {
-            builder.append(sep);
-            builder.append(PlasticUtils.toTypeName(parameterType));
-
-            sep = ",";
-        }
-
-        return builder.append(")").toString();
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java
deleted file mode 100644
index 7b2b7ab..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright 2006 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.util;
-
-import java.util.Iterator;
-
-/**
- * Represents a sequence of integer values, either ascending or descending. The sequence is always inclusive (of the
- * finish value).
- */
-public final class IntegerRange implements Iterable<Integer>
-{
-    private final int start;
-
-    private final int finish;
-
-    private class RangeIterator implements Iterator<Integer>
-    {
-        private final int increment;
-
-        private int value = start;
-
-        private boolean hasNext = true;
-
-        RangeIterator()
-        {
-            increment = start < finish ? +1 : -1;
-        }
-
-        public boolean hasNext()
-        {
-            return hasNext;
-        }
-
-        public Integer next()
-        {
-            if (!hasNext) throw new IllegalStateException();
-
-            int result = value;
-
-            hasNext = value != finish;
-
-            value += increment;
-
-            return result;
-        }
-
-        public void remove()
-        {
-            throw new UnsupportedOperationException();
-        }
-
-    }
-
-    public IntegerRange(final int start, final int finish)
-    {
-        this.start = start;
-        this.finish = finish;
-    }
-
-    public int getFinish()
-    {
-        return finish;
-    }
-
-    public int getStart()
-    {
-        return start;
-    }
-
-    @Override
-    public String toString()
-    {
-        return String.format("%d..%d", start, finish);
-    }
-
-    /**
-     * The main puprose of a range object is to produce an Iterator. Since IntegerRange is iterable, it is useful with
-     * the Tapestry Loop component, but also with the Java for loop!
-     */
-    public Iterator<Integer> iterator()
-    {
-        return new RangeIterator();
-    }
-
-    @Override
-    public int hashCode()
-    {
-        final int PRIME = 31;
-
-        int result = PRIME + finish;
-
-        result = PRIME * result + start;
-
-        return result;
-    }
-
-    /**
-     * Returns true if the other object is an IntegerRange with the same start and finish values.
-     */
-    @Override
-    public boolean equals(Object obj)
-    {
-        if (this == obj) return true;
-        if (obj == null) return false;
-        if (getClass() != obj.getClass()) return false;
-        final IntegerRange other = (IntegerRange) obj;
-        if (finish != other.finish) return false;
-
-        return start == other.start;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java
deleted file mode 100644
index 503bb1f..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2006 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.util;
-
-import java.util.Arrays;
-
-/**
- * Combines multiple values to form a single composite key. MultiKey can often be used as an alternative to nested
- * maps.
- */
-public final class MultiKey
-{
-    private static final int PRIME = 31;
-
-    private final Object[] values;
-
-    private final int hashCode;
-
-    /**
-     * Creates a new instance from the provided values. It is assumed that the values provided are good map keys
-     * themselves -- immutable, with proper implementations of equals() and hashCode().
-     *
-     * @param values
-     */
-    public MultiKey(Object... values)
-    {
-        this.values = values;
-
-        hashCode = PRIME * Arrays.hashCode(this.values);
-    }
-
-    @Override
-    public int hashCode()
-    {
-        return hashCode;
-    }
-
-    @Override
-    public boolean equals(Object obj)
-    {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        final MultiKey other = (MultiKey) obj;
-
-        return Arrays.equals(values, other.values);
-    }
-
-    @Override
-    public String toString()
-    {
-        StringBuilder builder = new StringBuilder("MultiKey[");
-
-        boolean first = true;
-
-        for (Object o : values)
-        {
-            if (!first)
-                builder.append(", ");
-
-            builder.append(o);
-
-            first = false;
-        }
-
-        builder.append("]");
-
-        return builder.toString();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/services/BeanModelSource.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/BeanModelSource.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/BeanModelSource.java
deleted file mode 100644
index 16b4fca..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/BeanModelSource.java
+++ /dev/null
@@ -1,70 +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.services;
-
-import org.apache.tapestry5.beaneditor.BeanModel;
-import org.apache.tapestry5.ioc.Messages;
-
-/**
- * Used by a component to create a default {@link org.apache.tapestry5.beaneditor.BeanModel} for a particular bean
- * class. Also provides support to the model by generating validation information for individual fields.
- * <p/>
- * BeanModels are the basis for the {@link org.apache.tapestry5.corelib.components.BeanEditor} and {@link
- * org.apache.tapestry5.corelib.components.Grid} comopnents.
- *
- * @see org.apache.tapestry5.services.PropertyConduitSource
- */
-public interface BeanModelSource
-{
-    /**
-     * Creates a new model used for editing the indicated bean class. The model will represent all read/write properties
-     * of the bean. The order of properties is determined from the order of the getter methods in the code, and can be
-     * overridden with the {@link org.apache.tapestry5.beaneditor.ReorderProperties} annotation. The labels for the
-     * properties are derived from the property names, but if the component's message catalog has keys of the form
-     * <code>propertyName-label</code>, then those will be used instead.
-     * <p/>
-     * Models are <em>mutable</em>, so they are not cached, a fresh instance is created each time.
-     *
-     * @param beanClass                class of object to be edited
-     * @param filterReadOnlyProperties if true, then properties that are read-only will be skipped (leaving only
-     *                                 read-write properties, appropriate for {@link org.apache.tapestry5.corelib.components.BeanEditForm},
-     *                                 etc.). If false, then both read-only and read-write properties will be included
-     *                                 (appropriate for {@link org.apache.tapestry5.corelib.components.Grid} or {@link
-     *                                 org.apache.tapestry5.corelib.components.BeanDisplay}).
-     * @param messages                 Used to find explicit overrides of
-     * @return a model
-     * @deprecated use {@link #createDisplayModel(Class, org.apache.tapestry5.ioc.Messages)} or {@link
-     *             #createEditModel(Class, org.apache.tapestry5.ioc.Messages)}
-     */
-    <T> BeanModel<T> create(Class<T> beanClass, boolean filterReadOnlyProperties, Messages messages);
-
-    /**
-     * Creates a model for display purposes; this may include properties which are read-only.
-     *
-     * @param beanClass class of object to be edited
-     * @param messages
-     * @return a model containing properties that can be presented to the user
-     */
-    <T> BeanModel<T> createDisplayModel(Class<T> beanClass, Messages messages);
-
-    /**
-     * Creates a model for edit and update purposes, only properties that are fully read-write are included.
-     *
-     * @param beanClass class of object to be edited
-     * @param messages
-     * @return a model containing properties that can be presented to the user
-     */
-    <T> BeanModel<T> createEditModel(Class<T> beanClass, Messages messages);
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClasses.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClasses.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClasses.java
deleted file mode 100644
index c901d3a..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClasses.java
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 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.services;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Marker annotation used to inject the correct {@link org.apache.tapestry5.services.InvalidationEventHub} service
- * responsible for invalidations when underlying component class files are changed.
- * 
- * @since 5.1.0.0
- */
-@Target(
-{ ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD })
-@Retention(RetentionPolicy.RUNTIME)
-@Documented
-public @interface ComponentClasses
-{
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentLayer.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentLayer.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentLayer.java
deleted file mode 100644
index e342c3f..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentLayer.java
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2007 The Apache Software Foundation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.apache.tapestry5.services;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.PARAMETER;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-/**
- * Marker annotation used to identify a service from the component layer that conflicts, in terms of service interface,
- * with a service from elsewhere. In particular, this is used to disambiguate {@link org.apache.tapestry5.ioc.services.PlasticProxyFactory} which has one implementation (marked with {@link
- * org.apache.tapestry5.ioc.services.Builtin} and another with this annotation.
- */
-@Target(
-        {PARAMETER, FIELD})
-@Retention(RUNTIME)
-@Documented
-public @interface ComponentLayer
-{
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java
deleted file mode 100644
index 77b028e..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2006, 2007, 2008, 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.services;
-
-import java.util.Map;
-
-/**
- * An object which manages a list of {@link org.apache.tapestry5.services.InvalidationListener}s. There are multiple
- * event hub services implementing this interface, each with a specific marker annotation; each can register listeners
- * and fire events; these are based on the type of resource that has been invalidated. Tapestry has built-in support
- * for:
- * <dl>
- * <dt>message catalog resources
- * <dd>{@link org.apache.tapestry5.services.ComponentMessages} marker annotation
- * <dt>component templates
- * <dd>{@link org.apache.tapestry5.services.ComponentTemplates} marker annotation
- * <dt>component classes
- * <dd>{@link org.apache.tapestry5.services.ComponentClasses} marker annotation
- * </dl>
- * <p/>
- * Starting in Tapestry 5.3, these services are disabled in production (it does nothing).
- *
- * @since 5.1.0.0
- */
-public interface InvalidationEventHub
-{
-    /**
-     * Adds a listener, who needs to know when an underlying resource of a given category has changed (so that the
-     * receiver may discard any cached data that may have been invalidated). Does nothing in production mode.
-     *
-     * @deprecated in 5.4, use {@link #addInvalidationCallback(Runnable)} instead}
-     */
-    void addInvalidationListener(InvalidationListener listener);
-
-    /**
-     * Adds a callback that is invoked when an underlying tracked resource has changed. Does nothing in production mode.
-     *
-     * @since  5.4
-     */
-    void addInvalidationCallback(Runnable callback);
-
-    /**
-     * Adds a callback that clears the map.
-     *
-     * @since 5.4
-     */
-    void clearOnInvalidation(Map<?,?> map);
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationListener.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationListener.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationListener.java
deleted file mode 100644
index b9b4aa3..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationListener.java
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2006, 2007, 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.services;
-
-/**
- * Interface for objects that may cache information that can be invalidated. Invalidation occurs when external files,
- * from which in-memory data is cached, is determined to have changed. Granularity is very limited; when any external
- * file is found to have changed, the event is fired (with the expectation that the cleared cache will be repopulated as
- * necessary).
- *
- * @see org.apache.tapestry5.services.InvalidationEventHub
- * @since 5.1.0.0
- * @deprecated In 5.4; use {@link InvalidationEventHub#addInvalidationCallback(Runnable)} instead
- */
-public interface InvalidationListener
-{
-    /**
-     * Invoked to indicate that some object is invalid. The receiver should clear its cache.
-     */
-    void objectWasInvalidated();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java
deleted file mode 100644
index 312cd60..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2007, 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.services;
-
-import org.apache.tapestry5.PropertyConduit;
-
-/**
- * A source for {@link org.apache.tapestry5.PropertyConduit}s, which can be thought of as a compiled property path
- * expression. PropertyConduits are the basis of the "prop:" binding factory, thus this service defines the expression
- * format used by the {@link org.apache.tapestry5.internal.bindings.PropBindingFactory}.
- */
-public interface PropertyConduitSource
-{
-    /**
-     * Returns a property conduit instance for the given expression. PropertyConduitSource caches the conduits it
-     * returns, so despite the name, this method does not always create a <em>new</em> conduit. The cache is cleared if
-     * a change to component classes is observed.
-     * <p/>
-     * Callers of this method should observe notifications from the {@link org.apache.tapestry5.services.InvalidationEventHub}
-     * for {@link org.apache.tapestry5.services.ComponentClasses} and discard any aquired conduits; failure to do so
-     * will create memory leaks whenever component classes change (the conduits will keep references to the old classes
-     * and classloaders).
-     *
-     * @param rootType   the type of the root object to which the expression is applied
-     * @param expression expression to be evaluated on instances of the root class
-     * @return RuntimeException if the expression is invalid (poorly formed, references non-existent properties, etc.)
-     */
-    PropertyConduit create(Class rootType, String expression);
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/build.gradle
----------------------------------------------------------------------
diff --git a/tapestry-ioc/build.gradle b/tapestry-ioc/build.gradle
index e890f7e..5a5321f 100644
--- a/tapestry-ioc/build.gradle
+++ b/tapestry-ioc/build.gradle
@@ -4,6 +4,7 @@ dependencies {
     compile project(':tapestry-func')
     compile project(':tapestry5-annotations')
     compile project(":plastic")
+    compile project(":beanmodel")
 
     provided project(':tapestry-test')
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java
deleted file mode 100644
index 1f0e744..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2007, 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;
-
-import java.lang.annotation.Annotation;
-
-/**
- * A source of annotations. This interface is used to mask where the annotations come from (for example, from a Method,
- * a Class, or some other source).
- */
-public interface AnnotationProvider
-{
-    /**
-     * Searches for the specified annotation, returning the matching annotation instance.
-     *
-     * @param <T>
-     * @param annotationClass used to select the annotation to return
-     * @return the annotation, or null if not found
-     */
-    <T extends Annotation> T getAnnotation(Class<T> annotationClass);
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Locatable.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Locatable.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Locatable.java
deleted file mode 100644
index 37b6551..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Locatable.java
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2006, 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;
-
-/**
- * Interface implemented by objects which carry a location tag. Defines a readable property, location.
- */
-@SuppressWarnings({"JavaDoc"})
-public interface Locatable
-{
-    /**
-     * Returns the location associated with this object for error reporting purposes.
-     */
-    Location getLocation();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Location.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Location.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Location.java
deleted file mode 100644
index e6688c2..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Location.java
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2006 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;
-
-/**
- * A kind of tag applied to other objects to identify where they came from, in terms of a file (the resource), a line
- * number, and a column number. This is part of "line precise exception reporting", whereby errors at runtime can be
- * tracked backwards to the files from which they were parsed or otherwise constructed.
- */
-public interface Location
-{
-    /**
-     * The resource from which the object tagged with a location was derived.
-     */
-    Resource getResource();
-
-    /**
-     * The line number within the resource, if known, or -1 otherwise.
-     */
-    int getLine();
-
-    /**
-     * The column number within the line if known, or -1 otherwise.
-     */
-    int getColumn();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java
deleted file mode 100644
index e90eb65..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2006 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;
-
-/**
- * Obtained from a {@link org.apache.tapestry5.ioc.Messages}, used to format messages for a specific localized message
- * key.
- */
-public interface MessageFormatter
-{
-    /**
-     * Formats the message. The arguments are passed to {@link java.util.Formatter} as is with one exception: Object of
-     * type {@link Throwable} are converted to their {@link Throwable#getMessage()} (or, if that is null, to the name of
-     * the class).
-     *
-     * @param args
-     * @return formatted string
-     */
-    String format(Object... args);
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Messages.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Messages.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Messages.java
deleted file mode 100644
index ba7452c..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Messages.java
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2006, 2007, 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;
-
-import java.util.Set;
-
-/**
- * Provides access to a messages catalog, a set of properties files that provide localized messages for a particular
- * locale. The message catalog consists of keys and values and follows the semantics of a Java {@link
- * java.util.ResourceBundle} with some changes.
- */
-public interface Messages
-{
-    /**
-     * Returns true if the bundle contains the named key.
-     */
-    boolean contains(String key);
-
-    /**
-     * Returns the localized message for the given key. If catalog does not contain such a key, then a modified version
-     * of the key is returned (converted to upper case and enclosed in brackets).
-     *
-     * @param key
-     * @return localized message for key, or placeholder
-     */
-    String get(String key);
-
-    /**
-     * Returns a formatter for the message, which can be used to substitute arguments (as per {@link
-     * java.util.Formatter}).
-     *
-     * @param key
-     * @return formattable object
-     */
-    MessageFormatter getFormatter(String key);
-
-    /**
-     * Convenience for accessing a formatter and formatting a localized message with arguments.
-     */
-    String format(String key, Object... args);
-
-    /**
-     * Returns a set of all the keys for which this instance may provide a value.
-     *
-     * @return set of keys
-     * @since 5.4
-     */
-    Set<String> getKeys();
-}


[06/15] tapestry-5 git commit: First pass creating the BeanModel and Commons packages. Lots of stuff moved around, but no actual code changes so far

Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/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
new file mode 100644
index 0000000..701420f
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
@@ -0,0 +1,1563 @@
+// Copyright 2007-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.internal.services;
+
+import org.antlr.runtime.ANTLRInputStream;
+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.InternalPropertyConduit;
+import org.apache.tapestry5.internal.antlr.PropertyExpressionLexer;
+import org.apache.tapestry5.internal.antlr.PropertyExpressionParser;
+import org.apache.tapestry5.internal.util.IntegerRange;
+import org.apache.tapestry5.internal.util.MultiKey;
+import org.apache.tapestry5.ioc.AnnotationProvider;
+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.InternalUtils;
+import org.apache.tapestry5.ioc.services.*;
+import org.apache.tapestry5.ioc.util.AvailableValues;
+import org.apache.tapestry5.ioc.util.ExceptionUtils;
+import org.apache.tapestry5.ioc.util.UnknownValueException;
+import org.apache.tapestry5.plastic.*;
+import org.apache.tapestry5.services.ComponentClasses;
+import org.apache.tapestry5.services.ComponentLayer;
+import org.apache.tapestry5.services.InvalidationEventHub;
+import org.apache.tapestry5.services.PropertyConduitSource;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.*;
+
+public class PropertyConduitSourceImpl implements PropertyConduitSource
+{
+    static class ConduitMethods
+    {
+        private static final MethodDescription GET = getMethodDescription(PropertyConduit.class, "get", Object.class);
+
+        private static final MethodDescription SET = getMethodDescription(PropertyConduit.class, "set", Object.class,
+                Object.class);
+
+        private static final MethodDescription GET_PROPERTY_TYPE = getMethodDescription(PropertyConduit.class,
+                "getPropertyType");
+
+        private static final MethodDescription GET_PROPERTY_GENERIC_TYPE = getMethodDescription(PropertyConduit2.class,
+                "getPropertyGenericType");
+        
+        private static final MethodDescription GET_PROPERTY_NAME = getMethodDescription(InternalPropertyConduit.class,
+                "getPropertyName");
+        
+        private static final MethodDescription GET_ANNOTATION = getMethodDescription(AnnotationProvider.class,
+                "getAnnotation", Class.class);
+
+    }
+
+    static class DelegateMethods
+    {
+        static final Method INVERT = getMethod(PropertyConduitDelegate.class, "invert", Object.class);
+
+        static final Method RANGE = getMethod(PropertyConduitDelegate.class, "range", int.class, int.class);
+
+        static final Method COERCE = getMethod(PropertyConduitDelegate.class, "coerce", Object.class, Class.class);
+    }
+
+    static class ArrayListMethods
+    {
+        static final Method ADD = getMethod(ArrayList.class, "add", Object.class);
+    }
+
+    static class HashMapMethods
+    {
+        static final Method PUT = getMethod(HashMap.class, "put", Object.class, Object.class);
+    }
+
+    private static InstructionBuilderCallback RETURN_NULL = new InstructionBuilderCallback()
+    {
+        public void doBuild(InstructionBuilder builder)
+        {
+            builder.loadNull().returnResult();
+        }
+    };
+
+    private static final String[] SINGLE_OBJECT_ARGUMENT = new String[]
+            {Object.class.getName()};
+
+    @SuppressWarnings("unchecked")
+    private static Method getMethod(Class containingClass, String name, Class... parameterTypes)
+    {
+        try
+        {
+            return containingClass.getMethod(name, parameterTypes);
+        } catch (NoSuchMethodException ex)
+        {
+            throw new IllegalArgumentException(ex);
+        }
+    }
+
+    private static MethodDescription getMethodDescription(Class containingClass, String name, Class... parameterTypes)
+    {
+        return new MethodDescription(getMethod(containingClass, name, parameterTypes));
+    }
+
+    private final AnnotationProvider nullAnnotationProvider = new NullAnnotationProvider();
+
+    /**
+     * How are null values in intermdiate terms to be handled?
+     */
+    private enum NullHandling
+    {
+        /**
+         * Add code to check for null and throw exception if null.
+         */
+        FORBID,
+
+        /**
+         * Add code to check for null and short-circuit (i.e., the "?."
+         * safe-dereference operator)
+         */
+        ALLOW
+    }
+
+    /**
+     * One term in an expression. Expressions start with some root type and each term advances
+     * to a new type.
+     */
+    private class Term
+    {
+        /**
+         * The generic type of the term.
+         */
+        final Type type;
+
+        final Class genericType;
+
+        /**
+         * Describes the term, for use in error messages.
+         */
+        final String description;
+
+        final AnnotationProvider annotationProvider;
+
+        /**
+         * Callback that will implement the term.
+         */
+        final InstructionBuilderCallback callback;
+
+        Term(Type type, Class genericType, String description, AnnotationProvider annotationProvider,
+             InstructionBuilderCallback callback)
+        {
+            this.type = type;
+            this.genericType = genericType;
+            this.description = description;
+            this.annotationProvider = annotationProvider;
+            this.callback = callback;
+        }
+
+        Term(Type type, String description, AnnotationProvider annotationProvider, InstructionBuilderCallback callback)
+        {
+            this(type, GenericsUtils.asClass(type), description, annotationProvider, callback);
+        }
+
+        Term(Type type, String description, InstructionBuilderCallback callback)
+        {
+            this(type, description, null, callback);
+        }
+
+        /**
+         * Returns a clone of this Term with a new callback.
+         */
+        Term withCallback(InstructionBuilderCallback newCallback)
+        {
+            return new Term(type, genericType, description, annotationProvider, newCallback);
+        }
+    }
+
+    private final PropertyAccess access;
+
+    private final PlasticProxyFactory proxyFactory;
+
+    private final TypeCoercer typeCoercer;
+
+    private final StringInterner interner;
+
+    /**
+     * Keyed on combination of root class and expression.
+     */
+    private final Map<MultiKey, PropertyConduit> cache = CollectionFactory.newConcurrentMap();
+
+    private final Invariant invariantAnnotation = new Invariant()
+    {
+        public Class<? extends Annotation> annotationType()
+        {
+            return Invariant.class;
+        }
+    };
+
+    private final AnnotationProvider invariantAnnotationProvider = new AnnotationProvider()
+    {
+        public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+        {
+            if (annotationClass == Invariant.class)
+                return annotationClass.cast(invariantAnnotation);
+
+            return null;
+        }
+    };
+
+    private final PropertyConduit literalTrue;
+
+    private final PropertyConduit literalFalse;
+
+    private final PropertyConduit literalNull;
+
+    private final PropertyConduitDelegate sharedDelegate;
+
+    /**
+     * Encapsulates the process of building a PropertyConduit instance from an
+     * expression, as an {@link PlasticClassTransformer}.
+     */
+    class PropertyConduitBuilder implements PlasticClassTransformer
+    {
+        private final Class rootType;
+
+        private final String expression;
+
+        private final Tree tree;
+
+        private Class conduitPropertyType;
+
+        private Type conduitPropertyGenericType;
+
+        private String conduitPropertyName;
+
+        private AnnotationProvider annotationProvider = nullAnnotationProvider;
+
+        private PlasticField delegateField;
+
+        private PlasticClass plasticClass;
+
+        private PlasticMethod getRootMethod, navMethod;
+
+        PropertyConduitBuilder(Class rootType, String expression, Tree tree)
+        {
+            this.rootType = rootType;
+            this.expression = expression;
+            this.tree = tree;
+        }
+
+        public void transform(PlasticClass plasticClass)
+        {
+            this.plasticClass = plasticClass;
+
+            // Create the various methods; also determine the conduit's property type, property name and identify
+            // the annotation provider.
+
+            implementNavMethodAndAccessors();
+
+            implementOtherMethods();
+
+            plasticClass.addToString(String.format("PropertyConduit[%s %s]", rootType.getName(), expression));
+        }
+
+        private void implementOtherMethods()
+        {
+            PlasticField annotationProviderField = plasticClass.introduceField(AnnotationProvider.class,
+                    "annotationProvider").inject(annotationProvider);
+
+            plasticClass.introduceMethod(ConduitMethods.GET_ANNOTATION).delegateTo(annotationProviderField);
+
+            plasticClass.introduceMethod(ConduitMethods.GET_PROPERTY_NAME, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    builder.loadConstant(conduitPropertyName).returnResult();
+                }
+            });
+
+            final PlasticField propertyTypeField = plasticClass.introduceField(Class.class, "propertyType").inject(
+                    conduitPropertyType);
+
+            plasticClass.introduceMethod(ConduitMethods.GET_PROPERTY_TYPE, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    builder.loadThis().getField(propertyTypeField).returnResult();
+                }
+            });
+
+            final PlasticField propertyGenericTypeField = plasticClass.introduceField(Type.class, "propertyGenericType").inject(
+                    conduitPropertyGenericType);
+
+            plasticClass.introduceMethod(ConduitMethods.GET_PROPERTY_GENERIC_TYPE, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    builder.loadThis().getField(propertyGenericTypeField).returnResult();
+                }
+            });
+        }
+
+        /**
+         * Creates a method that does a conversion from Object to the expected root type, with
+         * a null check.
+         */
+        private void implementGetRoot()
+        {
+            getRootMethod = plasticClass.introducePrivateMethod(PlasticUtils.toTypeName(rootType), "getRoot",
+                    SINGLE_OBJECT_ARGUMENT, null);
+
+            getRootMethod.changeImplementation(new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    builder.loadArgument(0).dupe().when(Condition.NULL, new InstructionBuilderCallback()
+                    {
+                        public void doBuild(InstructionBuilder builder)
+                        {
+                            builder.throwException(NullPointerException.class,
+                                    String.format("Root object of property expression '%s' is null.", expression));
+                        }
+                    });
+
+                    builder.checkcast(rootType).returnResult();
+                }
+            });
+        }
+
+        private boolean isLeaf(Tree node)
+        {
+            int type = node.getType();
+
+            return type != DEREF && type != SAFEDEREF;
+        }
+
+        private void implementNavMethodAndAccessors()
+        {
+            implementGetRoot();
+
+            // First, create the navigate method.
+
+            final List<InstructionBuilderCallback> callbacks = CollectionFactory.newList();
+
+            Type activeType = rootType;
+
+            Tree node = tree;
+
+            while (!isLeaf(node))
+            {
+                Term term = analyzeDerefNode(activeType, node);
+
+                callbacks.add(term.callback);
+
+                activeType = term.type;
+
+                // Second term is the continuation, possibly another chained
+                // DEREF, etc.
+                node = node.getChild(1);
+            }
+
+            Class activeClass = GenericsUtils.asClass(activeType);
+
+            if (callbacks.isEmpty())
+            {
+                navMethod = getRootMethod;
+            } else
+            {
+                navMethod = plasticClass.introducePrivateMethod(PlasticUtils.toTypeName(activeClass), "navigate",
+                        SINGLE_OBJECT_ARGUMENT, null);
+
+                navMethod.changeImplementation(new InstructionBuilderCallback()
+                {
+                    public void doBuild(InstructionBuilder builder)
+                    {
+                        builder.loadThis().loadArgument(0).invokeVirtual(getRootMethod);
+
+                        for (InstructionBuilderCallback callback : callbacks)
+                        {
+                            callback.doBuild(builder);
+                        }
+
+                        builder.returnResult();
+                    }
+                });
+            }
+
+            implementAccessors(activeType, node);
+        }
+
+        private void implementAccessors(Type activeType, Tree node)
+        {
+            switch (node.getType())
+            {
+                case IDENTIFIER:
+
+                    implementPropertyAccessors(activeType, node);
+
+                    return;
+
+                case INVOKE:
+
+                    // So, at this point, we have the navigation method written
+                    // and it covers all but the terminal
+                    // de-reference. node is an IDENTIFIER or INVOKE. We're
+                    // ready to use the navigation
+                    // method to implement get() and set().
+
+                    implementMethodAccessors(activeType, node);
+
+                    return;
+
+                case RANGEOP:
+
+                    // As currently implemented, RANGEOP can only appear as the
+                    // top level, which
+                    // means we didn't need the navigate method after all.
+
+                    implementRangeOpGetter(node);
+                    implementNoOpSetter();
+
+                    conduitPropertyType = IntegerRange.class;
+                    conduitPropertyGenericType = IntegerRange.class;
+
+                    return;
+
+                case LIST:
+
+                    implementListGetter(node);
+                    implementNoOpSetter();
+
+                    conduitPropertyType = List.class;
+                    conduitPropertyGenericType = List.class;
+                    
+                    return;
+
+                case MAP:
+                    implementMapGetter(node);
+                    implementNoOpSetter();
+
+                    conduitPropertyType = Map.class;
+                    conduitPropertyGenericType = Map.class;
+
+                    return;
+
+
+                case NOT:
+                    implementNotOpGetter(node);
+                    implementNoOpSetter();
+
+                    conduitPropertyType = boolean.class;
+                    conduitPropertyGenericType = boolean.class;
+
+                    return;
+
+                default:
+                    throw unexpectedNodeType(node, IDENTIFIER, INVOKE, RANGEOP, LIST, NOT);
+            }
+        }
+
+        public void implementMethodAccessors(final Type activeType, final Tree invokeNode)
+        {
+            final Term term = buildInvokeTerm(activeType, invokeNode);
+
+            implementNoOpSetter();
+
+            conduitPropertyName = term.description;
+            conduitPropertyType = term.genericType;
+            conduitPropertyGenericType = term.genericType;
+            annotationProvider = term.annotationProvider;
+
+            plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    invokeNavigateMethod(builder);
+
+                    term.callback.doBuild(builder);
+
+                    boxIfPrimitive(builder, conduitPropertyType);
+
+                    builder.returnResult();
+                }
+            });
+
+            implementNoOpSetter();
+        }
+
+        public void implementPropertyAccessors(Type activeType, Tree identifierNode)
+        {
+            String propertyName = identifierNode.getText();
+
+            PropertyAdapter adapter = findPropertyAdapter(activeType, propertyName);
+
+            conduitPropertyName = propertyName;
+            conduitPropertyType = adapter.getType();
+            conduitPropertyGenericType = getGenericType(adapter);
+            annotationProvider = adapter;
+
+            implementGetter(adapter);
+            implementSetter(adapter);
+        }
+
+        private Type getGenericType(PropertyAdapter adapter)
+        {
+        	Type genericType = null;
+        	if (adapter.getField() != null)
+        	{
+        		genericType = adapter.getField().getGenericType();
+        	}
+        	else if (adapter.getReadMethod() != null)
+        	{
+        		genericType = adapter.getReadMethod().getGenericReturnType(); 
+        	}
+        	else if (adapter.getWriteMethod() != null)
+        	{
+        		genericType = adapter.getWriteMethod().getGenericParameterTypes()[0];
+        	}
+        	else
+        	{
+        		throw new RuntimeException("Could not find accessor for property " + adapter.getName());
+        	}
+        	
+        	return genericType == null ? adapter.getType() : genericType;
+		}
+
+		private void implementSetter(PropertyAdapter adapter)
+        {
+            if (adapter.getWriteMethod() != null)
+            {
+                implementSetter(adapter.getWriteMethod());
+                return;
+            }
+
+            if (adapter.getField() != null && adapter.isUpdate())
+            {
+                implementSetter(adapter.getField());
+                return;
+            }
+
+            implementNoOpMethod(ConduitMethods.SET, "Expression '%s' for class %s is read-only.", expression,
+                    rootType.getName());
+        }
+
+        private boolean isStatic(Member member)
+        {
+            return Modifier.isStatic(member.getModifiers());
+        }
+
+        private void implementSetter(final Field field)
+        {
+            if (isStatic(field))
+            {
+                plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback()
+                {
+                    public void doBuild(InstructionBuilder builder)
+                    {
+                        builder.loadArgument(1).castOrUnbox(PlasticUtils.toTypeName(field.getType()));
+
+                        builder.putStaticField(field.getDeclaringClass().getName(), field.getName(), field.getType());
+
+                        builder.returnResult();
+                    }
+                });
+
+                return;
+            }
+
+            plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    invokeNavigateMethod(builder);
+
+                    builder.loadArgument(1).castOrUnbox(PlasticUtils.toTypeName(field.getType()));
+
+                    builder.putField(field.getDeclaringClass().getName(), field.getName(), field.getType());
+
+                    builder.returnResult();
+                }
+            });
+        }
+
+        private void implementSetter(final Method writeMethod)
+        {
+            plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    invokeNavigateMethod(builder);
+
+                    Class propertyType = writeMethod.getParameterTypes()[0];
+                    String propertyTypeName = PlasticUtils.toTypeName(propertyType);
+
+                    builder.loadArgument(1).castOrUnbox(propertyTypeName);
+
+                    builder.invoke(writeMethod);
+
+                    builder.returnResult();
+                }
+            });
+        }
+
+        private void implementGetter(PropertyAdapter adapter)
+        {
+            if (adapter.getReadMethod() != null)
+            {
+                implementGetter(adapter.getReadMethod());
+                return;
+            }
+
+            if (adapter.getField() != null)
+            {
+                implementGetter(adapter.getField());
+                return;
+            }
+
+            implementNoOpMethod(ConduitMethods.GET, "Expression '%s' for class %s is write-only.", expression,
+                    rootType.getName());
+        }
+
+        private void implementGetter(final Field field)
+        {
+            if (isStatic(field))
+            {
+                plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+                {
+                    public void doBuild(InstructionBuilder builder)
+                    {
+                        builder.getStaticField(field.getDeclaringClass().getName(), field.getName(), field.getType());
+
+                        // Cast not necessary here since the return type of get() is Object
+
+                        boxIfPrimitive(builder, field.getType());
+
+                        builder.returnResult();
+                    }
+                });
+
+                return;
+            }
+
+            plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    invokeNavigateMethod(builder);
+
+                    builder.getField(field.getDeclaringClass().getName(), field.getName(), field.getType());
+
+                    // Cast not necessary here since the return type of get() is Object
+
+                    boxIfPrimitive(builder, field.getType());
+
+                    builder.returnResult();
+                }
+            });
+        }
+
+        private void implementGetter(final Method readMethod)
+        {
+            plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    invokeNavigateMethod(builder);
+
+                    invokeMethod(builder, readMethod, null, 0);
+
+                    boxIfPrimitive(builder, conduitPropertyType);
+
+                    builder.returnResult();
+                }
+            });
+        }
+
+        private void implementRangeOpGetter(final Tree rangeNode)
+        {
+            plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    // Put the delegate on top of the stack
+
+                    builder.loadThis().getField(getDelegateField());
+
+                    invokeMethod(builder, DelegateMethods.RANGE, rangeNode, 0);
+
+                    builder.returnResult();
+                }
+            });
+        }
+
+        /**
+         * @param node
+         *         subexpression to invert
+         */
+        private void implementNotOpGetter(final Tree node)
+        {
+            // Implement get() as navigate, then do a method invocation based on node
+            // then, then pass (wrapped) result to delegate.invert()
+
+            plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    Type expressionType = implementNotExpression(builder, node);
+
+                    // Yes, we know this will always be the case, for now.
+
+                    boxIfPrimitive(builder, expressionType);
+
+                    builder.returnResult();
+                }
+            });
+        }
+
+        /**
+         * The first part of any implementation of get() or set(): invoke the navigation method
+         * and if the result is null, return immediately.
+         */
+        private void invokeNavigateMethod(InstructionBuilder builder)
+        {
+            builder.loadThis().loadArgument(0).invokeVirtual(navMethod);
+
+            builder.dupe().when(Condition.NULL, RETURN_NULL);
+        }
+
+        /**
+         * Uses the builder to add instructions for a subexpression.
+         *
+         * @param builder
+         *         used to add instructions
+         * @param activeType
+         *         type of value on top of the stack when this code will execute, or null if no value on stack
+         * @param node
+         *         defines the expression
+         * @return the expression type
+         */
+        private Type implementSubexpression(InstructionBuilder builder, Type activeType, Tree node)
+        {
+            Term term;
+
+            while (true)
+            {
+                switch (node.getType())
+                {
+                    case IDENTIFIER:
+                    case INVOKE:
+
+                        if (activeType == null)
+                        {
+                            invokeGetRootMethod(builder);
+
+                            activeType = rootType;
+                        }
+
+                        term = buildTerm(activeType, node);
+
+                        term.callback.doBuild(builder);
+
+                        return term.type;
+
+                    case INTEGER:
+
+                        builder.loadConstant(new Long(node.getText()));
+
+                        return long.class;
+
+                    case DECIMAL:
+
+                        builder.loadConstant(new Double(node.getText()));
+
+                        return double.class;
+
+                    case STRING:
+
+                        builder.loadConstant(node.getText());
+
+                        return String.class;
+
+                    case DEREF:
+                    case SAFEDEREF:
+
+                        if (activeType == null)
+                        {
+                            invokeGetRootMethod(builder);
+
+                            activeType = rootType;
+                        }
+
+                        term = analyzeDerefNode(activeType, node);
+
+                        term.callback.doBuild(builder);
+
+                        activeType = GenericsUtils.asClass(term.type);
+
+                        node = node.getChild(1);
+
+                        break;
+
+                    case TRUE:
+                    case FALSE:
+
+                        builder.loadConstant(node.getType() == TRUE ? 1 : 0);
+
+                        return boolean.class;
+
+                    case LIST:
+
+                        return implementListConstructor(builder, node);
+
+                    case MAP:
+                        return implementMapConstructor(builder, node);
+
+                    case NOT:
+
+                        return implementNotExpression(builder, node);
+
+                    case THIS:
+
+                        invokeGetRootMethod(builder);
+
+                        return rootType;
+
+                    case NULL:
+
+                        builder.loadNull();
+
+                        return Void.class;
+
+                    default:
+                        throw unexpectedNodeType(node, TRUE, FALSE, INTEGER, DECIMAL, STRING, DEREF, SAFEDEREF,
+                                IDENTIFIER, INVOKE, LIST, NOT, THIS, NULL);
+                }
+            }
+        }
+
+        public void invokeGetRootMethod(InstructionBuilder builder)
+        {
+            builder.loadThis().loadArgument(0).invokeVirtual(getRootMethod);
+        }
+
+        private void implementListGetter(final Tree listNode)
+        {
+            plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    implementListConstructor(builder, listNode);
+
+                    builder.returnResult();
+                }
+            });
+        }
+
+        private Type implementListConstructor(InstructionBuilder builder, Tree listNode)
+        {
+            // First, create an empty instance of ArrayList
+
+            int count = listNode.getChildCount();
+
+            builder.newInstance(ArrayList.class);
+            builder.dupe().loadConstant(count).invokeConstructor(ArrayList.class, int.class);
+
+            for (int i = 0; i < count; i++)
+            {
+                builder.dupe(); // the ArrayList
+
+                Type expressionType = implementSubexpression(builder, null, listNode.getChild(i));
+
+                boxIfPrimitive(builder, GenericsUtils.asClass(expressionType));
+
+                // Add the value to the array, then pop off the returned boolean
+                builder.invoke(ArrayListMethods.ADD).pop();
+            }
+
+            return ArrayList.class;
+        }
+
+        private void implementMapGetter(final Tree mapNode)
+        {
+            plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    implementMapConstructor(builder, mapNode);
+
+                    builder.returnResult();
+                }
+            });
+        }
+
+        private Type implementMapConstructor(InstructionBuilder builder, Tree mapNode)
+        {
+            int count = mapNode.getChildCount();
+            builder.newInstance(HashMap.class);
+            builder.dupe().loadConstant(count).invokeConstructor(HashMap.class, int.class);
+
+            for (int i = 0; i < count; i += 2)
+            {
+                builder.dupe();
+
+                //build the key:
+                Type keyType = implementSubexpression(builder, null, mapNode.getChild(i));
+                boxIfPrimitive(builder, GenericsUtils.asClass(keyType));
+
+                //and the value:
+                Type valueType = implementSubexpression(builder, null, mapNode.getChild(i + 1));
+                boxIfPrimitive(builder, GenericsUtils.asClass(valueType));
+
+                //put the value into the array, then pop off the returned object.
+                builder.invoke(HashMapMethods.PUT).pop();
+
+            }
+
+            return HashMap.class;
+        }
+
+
+        private void implementNoOpSetter()
+        {
+            implementNoOpMethod(ConduitMethods.SET, "Expression '%s' for class %s is read-only.", expression,
+                    rootType.getName());
+        }
+
+        public void implementNoOpMethod(MethodDescription method, String format, Object... arguments)
+        {
+            final String message = String.format(format, arguments);
+
+            plasticClass.introduceMethod(method).changeImplementation(new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    builder.throwException(RuntimeException.class, message);
+                }
+            });
+        }
+
+        /**
+         * Invokes a method that may take parameters. The children of the invokeNode are subexpressions
+         * to be evaluated, and potentially coerced, so that they may be passed to the method.
+         *
+         * @param builder
+         *         constructs code
+         * @param method
+         *         method to invoke
+         * @param node
+         *         INVOKE or RANGEOP node
+         * @param childOffset
+         *         offset within the node to the first child expression (1 in an INVOKE node because the
+         *         first child is the method name, 0 in a RANGEOP node)
+         */
+        private void invokeMethod(InstructionBuilder builder, Method method, Tree node, int childOffset)
+        {
+            // We start with the target object for the method on top of the stack.
+            // Next, we have to push each method parameter, which may include boxing/deboxing
+            // and coercion. Once the code is in good shape, there's a lot of room to optimize
+            // the bytecode (a bit too much boxing/deboxing occurs, as well as some unnecessary
+            // trips through TypeCoercer). We might also want to have a local variable to store
+            // the root object (result of getRoot()).
+
+            Class[] parameterTypes = method.getParameterTypes();
+
+            for (int i = 0; i < parameterTypes.length; i++)
+            {
+                Type expressionType = implementSubexpression(builder, null, node.getChild(i + childOffset));
+
+                // The value left on the stack is not primitive, and expressionType represents
+                // its real type.
+
+                Class parameterType = parameterTypes[i];
+
+                if (!parameterType.isAssignableFrom(GenericsUtils.asClass(expressionType)))
+                {
+                    boxIfPrimitive(builder, expressionType);
+
+                    builder.loadThis().getField(getDelegateField());
+                    builder.swap().loadTypeConstant(PlasticUtils.toWrapperType(parameterType));
+                    builder.invoke(DelegateMethods.COERCE);
+
+                    if (parameterType.isPrimitive())
+                    {
+                        builder.castOrUnbox(parameterType.getName());
+                    } else
+                    {
+                        builder.checkcast(parameterType);
+                    }
+                }
+
+                // And that should leave an object of the correct type on the stack,
+                // ready for the method invocation.
+            }
+
+            // Now the target object and all parameters are in place.
+
+            builder.invoke(method.getDeclaringClass(), method.getReturnType(), method.getName(),
+                    method.getParameterTypes());
+        }
+
+        /**
+         * Analyzes a DEREF or SAFEDEREF node, proving back a term that identifies its type and provides a callback to
+         * peform the dereference.
+         *
+         * @return a term indicating the type of the expression to this point, and a {@link InstructionBuilderCallback}
+         *         to advance the evaluation of the expression form the previous value to the current
+         */
+        private Term analyzeDerefNode(Type activeType, Tree node)
+        {
+            // The first child is the term.
+
+            Tree term = node.getChild(0);
+
+            boolean allowNull = node.getType() == SAFEDEREF;
+
+            return buildTerm(activeType, term, allowNull ? NullHandling.ALLOW : NullHandling.FORBID);
+        }
+
+        private Term buildTerm(Type activeType, Tree term, final NullHandling nullHandling)
+        {
+            assertNodeType(term, IDENTIFIER, INVOKE);
+
+            final Term simpleTerm = buildTerm(activeType, term);
+
+            if (simpleTerm.genericType.isPrimitive())
+                return simpleTerm;
+
+            return simpleTerm.withCallback(new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    simpleTerm.callback.doBuild(builder);
+
+                    builder.dupe().when(Condition.NULL, new InstructionBuilderCallback()
+                    {
+                        public void doBuild(InstructionBuilder builder)
+                        {
+                            switch (nullHandling)
+                            {
+                                // It is necessary to load a null onto the stack (even if there's already one
+                                // there) because of the verifier. It sees the return when the stack contains an
+                                // intermediate value (along the navigation chain) and thinks the method is
+                                // returning a value of the wrong type.
+
+                                case ALLOW:
+                                    builder.loadNull().returnResult();
+
+                                case FORBID:
+
+                                    builder.loadConstant(simpleTerm.description);
+                                    builder.loadConstant(expression);
+                                    builder.loadArgument(0);
+
+                                    builder.invokeStatic(PropertyConduitSourceImpl.class, NullPointerException.class,
+                                            "nullTerm", String.class, String.class, Object.class);
+                                    builder.throwException();
+
+                                    break;
+
+                            }
+                        }
+                    });
+                }
+            });
+        }
+
+        private void assertNodeType(Tree node, int... expected)
+        {
+            int type = node.getType();
+
+            for (int e : expected)
+            {
+                if (type == e)
+                    return;
+            }
+
+            throw unexpectedNodeType(node, expected);
+        }
+
+        private RuntimeException unexpectedNodeType(Tree node, int... expected)
+        {
+            List<String> tokenNames = CollectionFactory.newList();
+
+            for (int i = 0; i < expected.length; i++)
+                tokenNames.add(PropertyExpressionParser.tokenNames[expected[i]]);
+
+            String message = String.format("Node %s was type %s, but was expected to be (one of) %s.",
+                    node.toStringTree(), PropertyExpressionParser.tokenNames[node.getType()],
+                    InternalUtils.joinSorted(tokenNames));
+
+            return new RuntimeException(message);
+        }
+
+        private Term buildTerm(Type activeType, Tree termNode)
+        {
+            switch (termNode.getType())
+            {
+                case INVOKE:
+
+                    return buildInvokeTerm(activeType, termNode);
+
+                case IDENTIFIER:
+
+                    return buildPropertyAccessTerm(activeType, termNode);
+
+                default:
+                    throw unexpectedNodeType(termNode, INVOKE, IDENTIFIER);
+            }
+        }
+
+        private Term buildPropertyAccessTerm(Type activeType, Tree termNode)
+        {
+            String propertyName = termNode.getText();
+
+            PropertyAdapter adapter = findPropertyAdapter(activeType, propertyName);
+
+            // Prefer the accessor over the field
+
+            if (adapter.getReadMethod() != null)
+            {
+                return buildGetterMethodAccessTerm(activeType, propertyName,
+                        adapter.getReadMethod());
+            }
+
+            if (adapter.getField() != null)
+            {
+                return buildPublicFieldAccessTerm(activeType, propertyName,
+                        adapter.getField());
+            }
+
+            throw new RuntimeException(String.format(
+                    "Property '%s' of class %s is not readable (it has no read accessor method).", adapter.getName(),
+                    adapter.getBeanType().getName()));
+        }
+
+        public PropertyAdapter findPropertyAdapter(Type activeType, String propertyName)
+        {
+            Class activeClass = GenericsUtils.asClass(activeType);
+
+            ClassPropertyAdapter classAdapter = access.getAdapter(activeClass);
+            PropertyAdapter adapter = classAdapter.getPropertyAdapter(propertyName);
+
+            if (adapter == null)
+            {
+                final List<String> names = classAdapter.getPropertyNames();
+                final String className = activeClass.getName();
+                throw new UnknownValueException(String.format(
+                        "Class %s does not contain a property (or public field) named '%s'.", className, propertyName),
+                        new AvailableValues("Properties (and public fields)", names));
+            }
+            return adapter;
+        }
+
+        private Term buildGetterMethodAccessTerm(final Type activeType, String propertyName, final Method readMethod)
+        {
+            Type returnType = GenericsUtils.extractActualType(activeType, readMethod);
+
+            return new Term(returnType, propertyName, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    invokeMethod(builder, readMethod, null, 0);
+
+                    Type genericType = GenericsUtils.extractActualType(activeType, readMethod);
+
+                    castToGenericType(builder, readMethod.getReturnType(), genericType);
+                }
+            });
+        }
+
+        private Term buildPublicFieldAccessTerm(Type activeType, String propertyName, final Field field)
+        {
+            final Type fieldType = GenericsUtils.extractActualType(activeType, field);
+
+            return new Term(fieldType, propertyName, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    Class rawFieldType = field.getType();
+
+                    String rawTypeName = PlasticUtils.toTypeName(rawFieldType);
+                    String containingClassName = field.getDeclaringClass().getName();
+                    String fieldName = field.getName();
+
+                    if (isStatic(field))
+                    {
+                        // We've gone to the trouble of loading the root object, or navigated to some other object,
+                        // but we don't need or want the instance, since it's a static field we're accessing.
+                        // Ideally, we would optimize this, and only generate and invoke the getRoot() and nav() methods as needed, but
+                        // access to public fields is relatively rare, and the cost is just the unused bytecode.
+
+                        builder.pop();
+
+                        builder.getStaticField(containingClassName, fieldName, rawTypeName);
+
+                    } else
+                    {
+                        builder.getField(containingClassName, fieldName, rawTypeName);
+                    }
+
+                    castToGenericType(builder, rawFieldType, fieldType);
+                }
+
+            });
+        }
+
+        /**
+         * Casts the results of a field read or method invocation based on generic information.
+         *
+         * @param builder
+         *         used to add instructions
+         * @param rawType
+         *         the simple type (often Object) of the field (or method return type)
+         * @param genericType
+         *         the generic Type, from which parameterizations can be determined
+         */
+        private void castToGenericType(InstructionBuilder builder, Class rawType, final Type genericType)
+        {
+            if (!genericType.equals(rawType))
+            {
+                Class castType = GenericsUtils.asClass(genericType);
+                builder.checkcast(castType);
+            }
+        }
+
+        private Term buildInvokeTerm(final Type activeType, final Tree invokeNode)
+        {
+            String methodName = invokeNode.getChild(0).getText();
+
+            int parameterCount = invokeNode.getChildCount() - 1;
+
+            Class activeClass = GenericsUtils.asClass(activeType);
+
+            final Method method = findMethod(activeClass, methodName, parameterCount);
+
+            if (method.getReturnType().equals(void.class))
+                throw new RuntimeException(String.format("Method %s.%s() returns void.", activeClass.getName(),
+                        methodName));
+
+            Type returnType = GenericsUtils.extractActualType(activeType, method);
+
+            return new Term(returnType, toUniqueId(method), InternalUtils.toAnnotationProvider(method), new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    invokeMethod(builder, method, invokeNode, 1);
+
+                    Type genericType = GenericsUtils.extractActualType(activeType, method);
+
+                    castToGenericType(builder, method.getReturnType(), genericType);
+                }
+            }
+            );
+        }
+
+        private Method findMethod(Class activeType, String methodName, int parameterCount)
+        {
+            Class searchType = activeType;
+
+            while (true)
+            {
+
+                for (Method method : searchType.getMethods())
+                {
+                    if (method.getParameterTypes().length == parameterCount
+                            && method.getName().equalsIgnoreCase(methodName))
+                        return method;
+                }
+
+                // TAP5-330
+                if (searchType != Object.class)
+                {
+                    searchType = Object.class;
+                } else
+                {
+                    throw new RuntimeException(String.format("Class %s does not contain a public method named '%s()'.",
+                            activeType.getName(), methodName));
+                }
+            }
+        }
+
+        public void boxIfPrimitive(InstructionBuilder builder, Type termType)
+        {
+            boxIfPrimitive(builder, GenericsUtils.asClass(termType));
+        }
+
+        public void boxIfPrimitive(InstructionBuilder builder, Class termType)
+        {
+            if (termType.isPrimitive())
+                builder.boxPrimitive(termType.getName());
+        }
+
+        public Class implementNotExpression(InstructionBuilder builder, final Tree notNode)
+        {
+            Type expressionType = implementSubexpression(builder, null, notNode.getChild(0));
+
+            boxIfPrimitive(builder, expressionType);
+
+            // Now invoke the delegate invert() method
+
+            builder.loadThis().getField(getDelegateField());
+
+            builder.swap().invoke(DelegateMethods.INVERT);
+
+            return boolean.class;
+        }
+
+        /**
+         * Defer creation of the delegate field unless actually needed.
+         */
+        private PlasticField getDelegateField()
+        {
+            if (delegateField == null)
+                delegateField = plasticClass.introduceField(PropertyConduitDelegate.class, "delegate").inject(
+                        sharedDelegate);
+
+            return delegateField;
+        }
+    }
+
+    public PropertyConduitSourceImpl(PropertyAccess access, @ComponentLayer
+    PlasticProxyFactory proxyFactory, TypeCoercer typeCoercer, StringInterner interner)
+    {
+        this.access = access;
+        this.proxyFactory = proxyFactory;
+        this.typeCoercer = typeCoercer;
+        this.interner = interner;
+
+        literalTrue = createLiteralConduit(Boolean.class, true);
+        literalFalse = createLiteralConduit(Boolean.class, false);
+        literalNull = createLiteralConduit(Void.class, null);
+
+        sharedDelegate = new PropertyConduitDelegate(typeCoercer);
+    }
+
+    @PostInjection
+    public void listenForInvalidations(@ComponentClasses InvalidationEventHub hub)
+    {
+        hub.clearOnInvalidation(cache);
+    }
+
+
+    public PropertyConduit create(Class rootClass, String expression)
+    {
+        assert rootClass != null;
+        assert InternalUtils.isNonBlank(expression);
+
+        MultiKey key = new MultiKey(rootClass, expression);
+
+        PropertyConduit result = cache.get(key);
+
+        if (result == null)
+        {
+            result = build(rootClass, expression);
+            cache.put(key, result);
+        }
+
+        return result;
+    }
+
+    /**
+     * Builds a subclass of {@link PropertyConduitDelegate} that implements the
+     * get() and set() methods and overrides the
+     * constructor. In a worst-case race condition, we may build two (or more)
+     * conduits for the same
+     * rootClass/expression, and it will get sorted out when the conduit is
+     * stored into the cache.
+     *
+     * @param rootClass
+     *         class of root object for expression evaluation
+     * @param expression
+     *         expression to be evaluated
+     * @return the conduit
+     */
+    private PropertyConduit build(final Class rootClass, String expression)
+    {
+        Tree tree = parse(expression);
+
+        try
+        {
+            switch (tree.getType())
+            {
+                case TRUE:
+
+                    return literalTrue;
+
+                case FALSE:
+
+                    return literalFalse;
+
+                case NULL:
+
+                    return literalNull;
+
+                case INTEGER:
+
+                    // Leading '+' may screw this up.
+                    // TODO: Singleton instance for "0", maybe "1"?
+
+                    return createLiteralConduit(Long.class, new Long(tree.getText()));
+
+                case DECIMAL:
+
+                    // Leading '+' may screw this up.
+                    // TODO: Singleton instance for "0.0"?
+
+                    return createLiteralConduit(Double.class, new Double(tree.getText()));
+
+                case STRING:
+
+                    return createLiteralConduit(String.class, tree.getText());
+
+                case RANGEOP:
+
+                    Tree fromNode = tree.getChild(0);
+                    Tree toNode = tree.getChild(1);
+
+                    // If the range is defined as integers (not properties, etc.)
+                    // then it is possible to calculate the value here, once, and not
+                    // build a new class.
+
+                    if (fromNode.getType() != INTEGER || toNode.getType() != INTEGER)
+                        break;
+
+                    int from = Integer.parseInt(fromNode.getText());
+                    int to = Integer.parseInt(toNode.getText());
+
+                    IntegerRange ir = new IntegerRange(from, to);
+
+                    return createLiteralConduit(IntegerRange.class, ir);
+
+                case THIS:
+
+                    return createLiteralThisPropertyConduit(rootClass);
+
+                default:
+                    break;
+            }
+
+            return proxyFactory.createProxy(InternalPropertyConduit.class,
+                    new PropertyConduitBuilder(rootClass, expression, tree)).newInstance();
+        } catch (Exception ex)
+        {
+            throw new PropertyExpressionException(String.format("Exception generating conduit for expression '%s': %s",
+                    expression, ExceptionUtils.toMessage(ex)), expression, ex);
+        }
+    }
+
+    private PropertyConduit createLiteralThisPropertyConduit(final Class rootClass)
+    {
+        return new PropertyConduit()
+        {
+            public Object get(Object instance)
+            {
+                return instance;
+            }
+
+            public void set(Object instance, Object value)
+            {
+                throw new RuntimeException("Literal values are not updateable.");
+            }
+
+            public Class getPropertyType()
+            {
+                return rootClass;
+            }
+            
+            public Type getPropertyGenericType()
+            {
+            	return rootClass;
+            }
+
+            public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+            {
+                return invariantAnnotationProvider.getAnnotation(annotationClass);
+            }
+        };
+    }
+
+    private <T> PropertyConduit createLiteralConduit(Class<T> type, T value)
+    {
+        return new LiteralPropertyConduit(typeCoercer, type, invariantAnnotationProvider, interner.format(
+                "LiteralPropertyConduit[%s]", value), value);
+    }
+
+    private Tree parse(String expression)
+    {
+        InputStream is = new ByteArrayInputStream(expression.getBytes());
+
+        ANTLRInputStream ais;
+
+        try
+        {
+            ais = new ANTLRInputStream(is);
+        } catch (IOException ex)
+        {
+            throw new RuntimeException(ex);
+        }
+
+        PropertyExpressionLexer lexer = new PropertyExpressionLexer(ais);
+
+        CommonTokenStream tokens = new CommonTokenStream(lexer);
+
+        PropertyExpressionParser parser = new PropertyExpressionParser(tokens);
+
+        try
+        {
+            return (Tree) parser.start().getTree();
+        } catch (Exception ex)
+        {
+            throw new RuntimeException(String.format("Error parsing property expression '%s': %s.", expression,
+                    ex.getMessage()), ex);
+        }
+    }
+
+    /**
+     * May be invoked from fabricated PropertyConduit instances.
+     */
+    @SuppressWarnings("unused")
+    public static NullPointerException nullTerm(String term, String expression, Object root)
+    {
+        String message = String.format("Property '%s' (within property expression '%s', of %s) is null.", term,
+                expression, root);
+
+        return new NullPointerException(message);
+    }
+
+    private static String toUniqueId(Method method)
+    {
+        StringBuilder builder = new StringBuilder(method.getName()).append("(");
+        String sep = "";
+
+        for (Class parameterType : method.getParameterTypes())
+        {
+            builder.append(sep);
+            builder.append(PlasticUtils.toTypeName(parameterType));
+
+            sep = ",";
+        }
+
+        return builder.append(")").toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/beanmodel/src/main/java/org/apache/tapestry5/services/BeanModelSource.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/services/BeanModelSource.java b/beanmodel/src/main/java/org/apache/tapestry5/services/BeanModelSource.java
new file mode 100644
index 0000000..16b4fca
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/services/BeanModelSource.java
@@ -0,0 +1,70 @@
+// 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.services;
+
+import org.apache.tapestry5.beaneditor.BeanModel;
+import org.apache.tapestry5.ioc.Messages;
+
+/**
+ * Used by a component to create a default {@link org.apache.tapestry5.beaneditor.BeanModel} for a particular bean
+ * class. Also provides support to the model by generating validation information for individual fields.
+ * <p/>
+ * BeanModels are the basis for the {@link org.apache.tapestry5.corelib.components.BeanEditor} and {@link
+ * org.apache.tapestry5.corelib.components.Grid} comopnents.
+ *
+ * @see org.apache.tapestry5.services.PropertyConduitSource
+ */
+public interface BeanModelSource
+{
+    /**
+     * Creates a new model used for editing the indicated bean class. The model will represent all read/write properties
+     * of the bean. The order of properties is determined from the order of the getter methods in the code, and can be
+     * overridden with the {@link org.apache.tapestry5.beaneditor.ReorderProperties} annotation. The labels for the
+     * properties are derived from the property names, but if the component's message catalog has keys of the form
+     * <code>propertyName-label</code>, then those will be used instead.
+     * <p/>
+     * Models are <em>mutable</em>, so they are not cached, a fresh instance is created each time.
+     *
+     * @param beanClass                class of object to be edited
+     * @param filterReadOnlyProperties if true, then properties that are read-only will be skipped (leaving only
+     *                                 read-write properties, appropriate for {@link org.apache.tapestry5.corelib.components.BeanEditForm},
+     *                                 etc.). If false, then both read-only and read-write properties will be included
+     *                                 (appropriate for {@link org.apache.tapestry5.corelib.components.Grid} or {@link
+     *                                 org.apache.tapestry5.corelib.components.BeanDisplay}).
+     * @param messages                 Used to find explicit overrides of
+     * @return a model
+     * @deprecated use {@link #createDisplayModel(Class, org.apache.tapestry5.ioc.Messages)} or {@link
+     *             #createEditModel(Class, org.apache.tapestry5.ioc.Messages)}
+     */
+    <T> BeanModel<T> create(Class<T> beanClass, boolean filterReadOnlyProperties, Messages messages);
+
+    /**
+     * Creates a model for display purposes; this may include properties which are read-only.
+     *
+     * @param beanClass class of object to be edited
+     * @param messages
+     * @return a model containing properties that can be presented to the user
+     */
+    <T> BeanModel<T> createDisplayModel(Class<T> beanClass, Messages messages);
+
+    /**
+     * Creates a model for edit and update purposes, only properties that are fully read-write are included.
+     *
+     * @param beanClass class of object to be edited
+     * @param messages
+     * @return a model containing properties that can be presented to the user
+     */
+    <T> BeanModel<T> createEditModel(Class<T> beanClass, Messages messages);
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/beanmodel/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java b/beanmodel/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java
new file mode 100644
index 0000000..312cd60
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java
@@ -0,0 +1,41 @@
+// Copyright 2007, 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.services;
+
+import org.apache.tapestry5.PropertyConduit;
+
+/**
+ * A source for {@link org.apache.tapestry5.PropertyConduit}s, which can be thought of as a compiled property path
+ * expression. PropertyConduits are the basis of the "prop:" binding factory, thus this service defines the expression
+ * format used by the {@link org.apache.tapestry5.internal.bindings.PropBindingFactory}.
+ */
+public interface PropertyConduitSource
+{
+    /**
+     * Returns a property conduit instance for the given expression. PropertyConduitSource caches the conduits it
+     * returns, so despite the name, this method does not always create a <em>new</em> conduit. The cache is cleared if
+     * a change to component classes is observed.
+     * <p/>
+     * Callers of this method should observe notifications from the {@link org.apache.tapestry5.services.InvalidationEventHub}
+     * for {@link org.apache.tapestry5.services.ComponentClasses} and discard any aquired conduits; failure to do so
+     * will create memory leaks whenever component classes change (the conduits will keep references to the old classes
+     * and classloaders).
+     *
+     * @param rootType   the type of the root object to which the expression is applied
+     * @param expression expression to be evaluated on instances of the root class
+     * @return RuntimeException if the expression is invalid (poorly formed, references non-existent properties, etc.)
+     */
+    PropertyConduit create(Class rootType, String expression);
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/build.gradle
----------------------------------------------------------------------
diff --git a/commons/build.gradle b/commons/build.gradle
new file mode 100644
index 0000000..76850ef
--- /dev/null
+++ b/commons/build.gradle
@@ -0,0 +1,18 @@
+import org.gradle.plugins.ide.idea.model.*
+import t5build.*
+
+description = "Project including common classes for tapestry-core, tapestry-ioc and beanmodel."
+
+//apply plugin: JavaPlugin
+
+buildDir = 'target/gradle-build'
+       
+dependencies {
+	compile project(":plastic")
+	compile project(":tapestry5-annotations")
+}
+
+jar {	
+	manifest {	
+	}
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java b/commons/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java
new file mode 100644
index 0000000..7b2b7ab
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java
@@ -0,0 +1,125 @@
+// Copyright 2006 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.util;
+
+import java.util.Iterator;
+
+/**
+ * Represents a sequence of integer values, either ascending or descending. The sequence is always inclusive (of the
+ * finish value).
+ */
+public final class IntegerRange implements Iterable<Integer>
+{
+    private final int start;
+
+    private final int finish;
+
+    private class RangeIterator implements Iterator<Integer>
+    {
+        private final int increment;
+
+        private int value = start;
+
+        private boolean hasNext = true;
+
+        RangeIterator()
+        {
+            increment = start < finish ? +1 : -1;
+        }
+
+        public boolean hasNext()
+        {
+            return hasNext;
+        }
+
+        public Integer next()
+        {
+            if (!hasNext) throw new IllegalStateException();
+
+            int result = value;
+
+            hasNext = value != finish;
+
+            value += increment;
+
+            return result;
+        }
+
+        public void remove()
+        {
+            throw new UnsupportedOperationException();
+        }
+
+    }
+
+    public IntegerRange(final int start, final int finish)
+    {
+        this.start = start;
+        this.finish = finish;
+    }
+
+    public int getFinish()
+    {
+        return finish;
+    }
+
+    public int getStart()
+    {
+        return start;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%d..%d", start, finish);
+    }
+
+    /**
+     * The main puprose of a range object is to produce an Iterator. Since IntegerRange is iterable, it is useful with
+     * the Tapestry Loop component, but also with the Java for loop!
+     */
+    public Iterator<Integer> iterator()
+    {
+        return new RangeIterator();
+    }
+
+    @Override
+    public int hashCode()
+    {
+        final int PRIME = 31;
+
+        int result = PRIME + finish;
+
+        result = PRIME * result + start;
+
+        return result;
+    }
+
+    /**
+     * Returns true if the other object is an IntegerRange with the same start and finish values.
+     */
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj) return true;
+        if (obj == null) return false;
+        if (getClass() != obj.getClass()) return false;
+        final IntegerRange other = (IntegerRange) obj;
+        if (finish != other.finish) return false;
+
+        return start == other.start;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java b/commons/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java
new file mode 100644
index 0000000..503bb1f
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java
@@ -0,0 +1,86 @@
+// Copyright 2006 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.util;
+
+import java.util.Arrays;
+
+/**
+ * Combines multiple values to form a single composite key. MultiKey can often be used as an alternative to nested
+ * maps.
+ */
+public final class MultiKey
+{
+    private static final int PRIME = 31;
+
+    private final Object[] values;
+
+    private final int hashCode;
+
+    /**
+     * Creates a new instance from the provided values. It is assumed that the values provided are good map keys
+     * themselves -- immutable, with proper implementations of equals() and hashCode().
+     *
+     * @param values
+     */
+    public MultiKey(Object... values)
+    {
+        this.values = values;
+
+        hashCode = PRIME * Arrays.hashCode(this.values);
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return hashCode;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        final MultiKey other = (MultiKey) obj;
+
+        return Arrays.equals(values, other.values);
+    }
+
+    @Override
+    public String toString()
+    {
+        StringBuilder builder = new StringBuilder("MultiKey[");
+
+        boolean first = true;
+
+        for (Object o : values)
+        {
+            if (!first)
+                builder.append(", ");
+
+            builder.append(o);
+
+            first = false;
+        }
+
+        builder.append("]");
+
+        return builder.toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java b/commons/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java
new file mode 100644
index 0000000..1f0e744
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java
@@ -0,0 +1,33 @@
+// Copyright 2007, 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;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * A source of annotations. This interface is used to mask where the annotations come from (for example, from a Method,
+ * a Class, or some other source).
+ */
+public interface AnnotationProvider
+{
+    /**
+     * Searches for the specified annotation, returning the matching annotation instance.
+     *
+     * @param <T>
+     * @param annotationClass used to select the annotation to return
+     * @return the annotation, or null if not found
+     */
+    <T extends Annotation> T getAnnotation(Class<T> annotationClass);
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/Locatable.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/Locatable.java b/commons/src/main/java/org/apache/tapestry5/ioc/Locatable.java
new file mode 100644
index 0000000..37b6551
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/Locatable.java
@@ -0,0 +1,27 @@
+// Copyright 2006, 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;
+
+/**
+ * Interface implemented by objects which carry a location tag. Defines a readable property, location.
+ */
+@SuppressWarnings({"JavaDoc"})
+public interface Locatable
+{
+    /**
+     * Returns the location associated with this object for error reporting purposes.
+     */
+    Location getLocation();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/Location.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/Location.java b/commons/src/main/java/org/apache/tapestry5/ioc/Location.java
new file mode 100644
index 0000000..e6688c2
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/Location.java
@@ -0,0 +1,38 @@
+// Copyright 2006 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;
+
+/**
+ * A kind of tag applied to other objects to identify where they came from, in terms of a file (the resource), a line
+ * number, and a column number. This is part of "line precise exception reporting", whereby errors at runtime can be
+ * tracked backwards to the files from which they were parsed or otherwise constructed.
+ */
+public interface Location
+{
+    /**
+     * The resource from which the object tagged with a location was derived.
+     */
+    Resource getResource();
+
+    /**
+     * The line number within the resource, if known, or -1 otherwise.
+     */
+    int getLine();
+
+    /**
+     * The column number within the line if known, or -1 otherwise.
+     */
+    int getColumn();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java b/commons/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java
new file mode 100644
index 0000000..e90eb65
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java
@@ -0,0 +1,32 @@
+// Copyright 2006 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;
+
+/**
+ * Obtained from a {@link org.apache.tapestry5.ioc.Messages}, used to format messages for a specific localized message
+ * key.
+ */
+public interface MessageFormatter
+{
+    /**
+     * Formats the message. The arguments are passed to {@link java.util.Formatter} as is with one exception: Object of
+     * type {@link Throwable} are converted to their {@link Throwable#getMessage()} (or, if that is null, to the name of
+     * the class).
+     *
+     * @param args
+     * @return formatted string
+     */
+    String format(Object... args);
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/Messages.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/Messages.java b/commons/src/main/java/org/apache/tapestry5/ioc/Messages.java
new file mode 100644
index 0000000..ba7452c
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/Messages.java
@@ -0,0 +1,61 @@
+// Copyright 2006, 2007, 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;
+
+import java.util.Set;
+
+/**
+ * Provides access to a messages catalog, a set of properties files that provide localized messages for a particular
+ * locale. The message catalog consists of keys and values and follows the semantics of a Java {@link
+ * java.util.ResourceBundle} with some changes.
+ */
+public interface Messages
+{
+    /**
+     * Returns true if the bundle contains the named key.
+     */
+    boolean contains(String key);
+
+    /**
+     * Returns the localized message for the given key. If catalog does not contain such a key, then a modified version
+     * of the key is returned (converted to upper case and enclosed in brackets).
+     *
+     * @param key
+     * @return localized message for key, or placeholder
+     */
+    String get(String key);
+
+    /**
+     * Returns a formatter for the message, which can be used to substitute arguments (as per {@link
+     * java.util.Formatter}).
+     *
+     * @param key
+     * @return formattable object
+     */
+    MessageFormatter getFormatter(String key);
+
+    /**
+     * Convenience for accessing a formatter and formatting a localized message with arguments.
+     */
+    String format(String key, Object... args);
+
+    /**
+     * Returns a set of all the keys for which this instance may provide a value.
+     *
+     * @return set of keys
+     * @since 5.4
+     */
+    Set<String> getKeys();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java b/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
new file mode 100644
index 0000000..81d1f77
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
@@ -0,0 +1,143 @@
+// Copyright 2006, 2007, 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;
+
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.ioc.services.MasterObjectProvider;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * Defines an object which can provide access to services defined within a {@link org.apache.tapestry5.ioc.Registry}, or
+ * to objects or object instances available by other means. Services are accessed via service id, or
+ * (when appropriate)
+ * by just service interface. The Registry itself implements this interface, as does
+ * {@link org.apache.tapestry5.ioc.ServiceResources}.
+ */
+public interface ObjectLocator
+{
+    /**
+     * Obtains a service via its unique service id. Returns the service's proxy. The service proxy
+     * implements the same
+     * interface as the actual service, and is used to instantiate the actual service only as needed
+     * (this is
+     * transparent to the application).
+     *
+     * @param <T>
+     * @param serviceId        unique Service id used to locate the service object (may contain <em>symbols</em>,
+     *                         which
+     *                         will be expanded), case is ignored
+     * @param serviceInterface the interface implemented by the service (or an interface extended by the service
+     *                         interface)
+     * @return the service instance
+     * @throws RuntimeException if the service is not defined, or if an error occurs instantiating it
+     */
+    <T> T getService(String serviceId, Class<T> serviceInterface);
+
+    /**
+     * Locates a service given a service interface and (optionally) some marker annotation types. A single service must implement the service
+     * interface (which                                                   * can be hard to guarantee) and by marked by all the marker types. The search takes into account inheritance of the service interface
+     * (not the service <em>implementation</em>), which may result in a failure due to extra
+     * matches.
+     *
+     * @param serviceInterface the interface the service implements
+     * @return the service's proxy
+     * @throws RuntimeException if the service does not exist (this is considered programmer error), or multiple
+     *                          services directly implement, or extend from, the service interface
+     * @see org.apache.tapestry5.ioc.annotations.Marker
+     */
+    <T> T getService(Class<T> serviceInterface);
+
+    /**
+     * Locates a service given a service interface and (optionally) some marker annotation types. A single service must implement the service
+     * interface (which                                                   * can be hard to guarantee) and by marked by all the marker types. The search takes into account inheritance of the service interface
+     * (not the service <em>implementation</em>), which may result in a failure due to extra
+     * matches.        The ability to specify marker annotation types was added in 5.3
+     *
+     * @param serviceInterface the interface the service implements
+     * @param markerTypes      Markers used to select a specific service that implements the interface
+     * @return the service's proxy
+     * @throws RuntimeException if the service does not exist (this is considered programmer error), or multiple
+     *                          services directly implement, or extend from, the service interface
+     * @see org.apache.tapestry5.ioc.annotations.Marker
+     * @since 5.3
+     */
+    <T> T getService(Class<T> serviceInterface, Class<? extends Annotation>... markerTypes);
+
+    /**
+     * Obtains an object indirectly, using the {@link org.apache.tapestry5.ioc.services.MasterObjectProvider} service.
+     *
+     * @param objectType         the type of object to be returned
+     * @param annotationProvider provides access to annotations on the field or parameter for which a value is to
+     *                           be
+     *                           obtained, which may be utilized in selecting an appropriate object, use
+     *                           <strong>null</strong> when annotations are not available (in which case, selection
+     *                           will
+     *                           be based only on the object type)
+     * @param <T>
+     * @return the requested object
+     * @see ObjectProvider
+     */
+    <T> T getObject(Class<T> objectType, AnnotationProvider annotationProvider);
+
+    /**
+     * Autobuilds a class by finding the public constructor with the most parameters. Services and other resources or
+     * dependencies will be injected into the parameters of the constructor and into private fields marked with the
+     * {@link Inject} annotation. There are two cases: constructing a service implementation, and constructing
+     * an arbitrary object. In the former case, many <em>service resources</em> are also available for injection, not
+     * just dependencies or objects provided via
+     * {@link MasterObjectProvider#provide(Class, AnnotationProvider, ObjectLocator, boolean)}.
+     *
+     * @param <T>
+     * @param clazz the type of object to instantiate
+     * @return the instantiated instance
+     * @throws RuntimeException if the autobuild fails
+     * @see MasterObjectProvider
+     */
+    <T> T autobuild(Class<T> clazz);
+
+    /**
+     * Preferred version of {@link #autobuild(Class)} that tracks the operation using
+     * {@link OperationTracker#invoke(String, Invokable)}.
+     *
+     * @param <T>
+     * @param description description used with {@link OperationTracker}
+     * @param clazz       the type of object to instantiate
+     * @return the instantiated instance
+     * @throws RuntimeException if the autobuild fails
+     * @see MasterObjectProvider
+     * @since 5.2.0
+     */
+    <T> T autobuild(String description, Class<T> clazz);
+
+    /**
+     * Creates a proxy. The proxy will defer invocation of {@link #autobuild(Class)} until
+     * just-in-time (that is, first method invocation). In a limited number of cases, it is necessary to use such a
+     * proxy to prevent service construction cycles, particularly when contributing (directly or indirectly) to the
+     * {@link org.apache.tapestry5.ioc.services.MasterObjectProvider} (which is itself at the heart
+     * of autobuilding).
+     * <p/>
+     * If the class file for the class is a file on the file system (not a file packaged in a JAR), then the proxy will
+     * <em>autoreload</em>: changing the class file will result in the new class being reloaded and re-instantiated
+     * (with dependencies).
+     *
+     * @param <T>
+     * @param interfaceClass      the interface implemented by the proxy
+     * @param implementationClass a concrete class that implements the interface
+     * @return a proxy
+     * @see #autobuild(Class)
+     */
+    <T> T proxy(Class<T> interfaceClass, Class<? extends T> implementationClass);
+}


[10/15] tapestry-5 git commit: Third pass creating the BeanModel and Commons packages.

Posted by th...@apache.org.
Third 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/dd958465
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/dd958465
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/dd958465

Branch: refs/heads/beanmodel-split
Commit: dd9584659823c87f014a1cf57c7be592eedfa4c6
Parents: c9e97d6
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Sat Dec 6 17:33:54 2014 -0200
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Sat Dec 6 17:33:54 2014 -0200

----------------------------------------------------------------------
 .../tapestry5/internal/BeanModelUtils.java      | 145 ------------
 .../internal/InternalBeanModelUtils.java        | 145 ++++++++++++
 .../internal/beaneditor/BeanModelUtils.java     | 120 ++++++++++
 .../internal/beaneditor/PropertyModelImpl.java  |   6 +-
 .../internal/services/BeanModelSourceImpl.java  | 222 +++++++++++++++++++
 .../services/PropertyConduitSourceImpl.java     |   4 +-
 .../tapestry5/services/DataTypeAnalyzer.java    |  48 ++++
 .../internal/TapestryInternalUtils.java         |   8 +-
 .../internal/beaneditor/BeanModelUtils.java     | 119 ----------
 .../internal/services/BeanModelSourceImpl.java  | 222 -------------------
 .../tapestry5/services/DataTypeAnalyzer.java    |  48 ----
 .../annotations/UsesMappedConfiguration.java    |  41 ----
 .../annotations/UsesOrderedConfiguration.java   |  33 ---
 .../ioc/internal/util/InternalUtils.java        |   6 +-
 .../annotations/UsesMappedConfiguration.java    |  41 ++++
 .../annotations/UsesOrderedConfiguration.java   |  33 +++
 16 files changed, 621 insertions(+), 620 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java
deleted file mode 100644
index 08cb88a..0000000
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.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 BeanModelUtils {
-	
-	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/dd958465/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
new file mode 100644
index 0000000..88f4c7f
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalBeanModelUtils.java
@@ -0,0 +1,145 @@
+// 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/dd958465/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
new file mode 100644
index 0000000..154ee79
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
@@ -0,0 +1,120 @@
+// Copyright 2007, 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.internal.beaneditor;
+
+import org.apache.tapestry5.beaneditor.BeanModel;
+import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
+
+/**
+ * Utilities used in a few places to modify an existing {@link BeanModel}.
+ */
+public final class BeanModelUtils
+{
+
+    final private static String[] EMPTY_STRING_ARRAY = new String[0];
+
+    /**
+     * Performs standard set of modifications to a {@link org.apache.tapestry5.beaneditor.BeanModel}
+     * . First new
+     * properties may be added, then properties removed, then properties reordered.
+     *
+     * @param model                to modifiy
+     * @param addPropertyNames     comma seperated list of property names to add, or null
+     * @param includePropertyNames comma seperated list of property names to include
+     * @param excludePropertyNames comma seperated list of property names to exclude, or null
+     * @param reorderPropertyNames comma seperated list of property names to reorder, or null
+     */
+    public static void modify(BeanModel model, String addPropertyNames,
+                              String includePropertyNames, String excludePropertyNames, String reorderPropertyNames)
+    {
+        if (addPropertyNames != null)
+            add(model, addPropertyNames);
+
+        if (includePropertyNames != null)
+            include(model, join(includePropertyNames, addPropertyNames));
+
+        if (excludePropertyNames != null)
+            exclude(model, excludePropertyNames);
+
+        if (reorderPropertyNames != null)
+            reorder(model, reorderPropertyNames);
+    }
+
+    private static final String join(String firstList, String optionalSecondList)
+    {
+        if (InternalStringUtils.isBlank(optionalSecondList))
+            return firstList;
+
+        return firstList + "," + optionalSecondList;
+    }
+
+    /**
+     * Adds empty properties to the bean model. New properties are added with a <em>null</em>
+     * {@link org.apache.tapestry5.PropertyConduit}. `
+     *
+     * @param model         to be modified
+     * @param propertyNames comma-separated list of property names
+     * @see BeanModel#addEmpty(String)
+     */
+    public static void add(BeanModel model, String propertyNames)
+    {
+        for (String name : split(propertyNames))
+        {
+            model.addEmpty(name);
+        }
+    }
+
+    /**
+     * Removes properties from the bean model.
+     *
+     * @param model
+     * @param propertyNames comma-separated list of property names
+     * @see BeanModel#exclude(String...)
+     */
+    public static void exclude(BeanModel model, String propertyNames)
+    {
+        model.exclude(split(propertyNames));
+    }
+
+    /**
+     * Selects a subset of the properties to keep, and reorders them.
+     */
+    public static void include(BeanModel model, String propertyNames)
+    {
+        model.include(split(propertyNames));
+    }
+
+    /**
+     * Reorders properties within the bean model.
+     *
+     * @param model
+     * @param propertyNames comma-separated list of property names
+     * @see BeanModel#reorder(String...)
+     */
+    public static void reorder(BeanModel model, String propertyNames)
+    {
+        model.reorder(split(propertyNames));
+    }
+    
+    static String[] split(String propertyNames)
+    {
+        String trimmed = propertyNames.trim();
+
+        if (trimmed.length() == 0)
+            return EMPTY_STRING_ARRAY;
+
+        return trimmed.split("\\s*,\\s*");
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/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 b21e5bb..4632818 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,7 +20,7 @@ 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.BeanModelUtils;
+import org.apache.tapestry5.internal.InternalBeanModelUtils;
 import org.apache.tapestry5.ioc.Messages;
 import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
 import org.apache.tapestry5.plastic.PlasticUtils;
@@ -48,9 +48,9 @@ public class PropertyModelImpl implements PropertyModel
         this.name = name;
         this.conduit = conduit;
 
-        id = BeanModelUtils.extractIdFromPropertyExpression(name);
+        id = InternalBeanModelUtils.extractIdFromPropertyExpression(name);
 
-        label = BeanModelUtils.defaultLabel(id, messages, name);
+        label = InternalBeanModelUtils.defaultLabel(id, messages, name);
 
         // TAP5-2305
         if (conduit != null)

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/beanmodel/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java
new file mode 100644
index 0000000..bb20de0
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java
@@ -0,0 +1,222 @@
+// Copyright 2007, 2008, 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.internal.services;
+
+import org.apache.tapestry5.beaneditor.BeanModel;
+import org.apache.tapestry5.beaneditor.NonVisual;
+import org.apache.tapestry5.beaneditor.ReorderProperties;
+import org.apache.tapestry5.internal.beaneditor.BeanModelImpl;
+import org.apache.tapestry5.internal.beaneditor.BeanModelUtils;
+import org.apache.tapestry5.ioc.Location;
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.ObjectLocator;
+import org.apache.tapestry5.ioc.annotations.Primary;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.services.*;
+import org.apache.tapestry5.services.BeanModelSource;
+import org.apache.tapestry5.services.ComponentLayer;
+import org.apache.tapestry5.services.DataTypeAnalyzer;
+import org.apache.tapestry5.services.PropertyConduitSource;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Collections;
+import java.util.List;
+
+public class BeanModelSourceImpl implements BeanModelSource
+{
+    private final TypeCoercer typeCoercer;
+
+    private final PropertyAccess propertyAccess;
+
+    private final PropertyConduitSource propertyConduitSource;
+
+    private final PlasticProxyFactory proxyFactory;
+
+    private final DataTypeAnalyzer dataTypeAnalyzer;
+
+    private final ObjectLocator locator;
+
+    private static class PropertyOrder implements Comparable<PropertyOrder>
+    {
+        final String propertyName;
+
+        final int classDepth;
+
+        final int sortKey;
+
+        public PropertyOrder(final String propertyName, int classDepth, int sortKey)
+        {
+            this.propertyName = propertyName;
+            this.classDepth = classDepth;
+            this.sortKey = sortKey;
+        }
+
+        public int compareTo(PropertyOrder o)
+        {
+            int result = classDepth - o.classDepth;
+
+            if (result == 0)
+                result = sortKey - o.sortKey;
+
+            if (result == 0)
+                result = propertyName.compareTo(o.propertyName);
+
+            return result;
+        }
+    }
+
+    /**
+     * @param classAdapter  defines the bean that contains the properties
+     * @param propertyNames the initial set of property names, which will be rebuilt in the correct order
+     */
+    private void orderProperties(ClassPropertyAdapter classAdapter, List<String> propertyNames)
+    {
+        List<PropertyOrder> properties = CollectionFactory.newList();
+
+        for (String name : propertyNames)
+        {
+            PropertyAdapter pa = classAdapter.getPropertyAdapter(name);
+
+            Method readMethod = pa.getReadMethod();
+
+            Location location = readMethod == null ? null : proxyFactory.getMethodLocation(readMethod);
+
+            int line = location == null ? -1 : location.getLine();
+
+            properties.add(new PropertyOrder(name, computeDepth(pa), line));
+        }
+
+        Collections.sort(properties);
+
+        propertyNames.clear();
+
+        for (PropertyOrder po : properties)
+        {
+            propertyNames.add(po.propertyName);
+        }
+    }
+
+    private static int computeDepth(PropertyAdapter pa)
+    {
+        int depth = 0;
+        Class c = pa.getDeclaringClass();
+
+        // When the method originates in an interface, the parent may be null, not Object.
+
+        while (c != null && c != Object.class)
+        {
+            depth++;
+            c = c.getSuperclass();
+        }
+
+        return depth;
+    }
+
+    public BeanModelSourceImpl(TypeCoercer typeCoercer, PropertyAccess propertyAccess,
+                               PropertyConduitSource propertyConduitSource,
+                               @ComponentLayer
+                               PlasticProxyFactory proxyFactory,
+                               @Primary
+                               DataTypeAnalyzer dataTypeAnalyzer, ObjectLocator locator)
+    {
+        this.typeCoercer = typeCoercer;
+        this.propertyAccess = propertyAccess;
+        this.propertyConduitSource = propertyConduitSource;
+        this.proxyFactory = proxyFactory;
+        this.dataTypeAnalyzer = dataTypeAnalyzer;
+        this.locator = locator;
+    }
+
+    public <T> BeanModel<T> createDisplayModel(Class<T> beanClass, Messages messages)
+    {
+        return create(beanClass, false, messages);
+    }
+
+    public <T> BeanModel<T> createEditModel(Class<T> beanClass, Messages messages)
+    {
+        return create(beanClass, true, messages);
+    }
+
+    public <T> BeanModel<T> create(Class<T> beanClass, boolean filterReadOnlyProperties, Messages messages)
+    {
+        assert beanClass != null;
+        assert messages != null;
+        ClassPropertyAdapter adapter = propertyAccess.getAdapter(beanClass);
+
+        BeanModel<T> model = new BeanModelImpl<T>(beanClass, propertyConduitSource, typeCoercer, messages, locator);
+
+        for (final String propertyName : adapter.getPropertyNames())
+        {
+            PropertyAdapter pa = adapter.getPropertyAdapter(propertyName);
+
+            if (!pa.isRead())
+            {
+                continue;
+            }
+
+            if (isStaticFieldProperty(pa))
+            {
+                continue;
+            }
+
+            if (pa.getAnnotation(NonVisual.class) != null)
+            {
+                continue;
+            }
+
+            if (filterReadOnlyProperties && !pa.isUpdate())
+            {
+                continue;
+            }
+
+            final String dataType = dataTypeAnalyzer.identifyDataType(pa);
+
+            // If an unregistered type, then ignore the property.
+
+            if (dataType == null)
+            {
+                continue;
+            }
+
+            model.add(propertyName).dataType(dataType);
+        }
+
+        // First, order the properties based on the location of the getter method
+        // within the class.
+
+        List<String> propertyNames = model.getPropertyNames();
+
+        orderProperties(adapter, propertyNames);
+
+        model.reorder(propertyNames.toArray(new String[propertyNames.size()]));
+
+        // Next, check for an annotation with specific ordering information.
+
+        ReorderProperties reorderAnnotation = beanClass.getAnnotation(ReorderProperties.class);
+
+        if (reorderAnnotation != null)
+        {
+            BeanModelUtils.reorder(model, reorderAnnotation.value());
+        }
+
+        return model;
+    }
+
+    private boolean isStaticFieldProperty(PropertyAdapter adapter)
+    {
+        return adapter.isField() && Modifier.isStatic(adapter.getField().getModifiers());
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/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 83f67fa..4ce072e 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,7 @@ 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.BeanModelUtils;
+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;
@@ -1260,7 +1260,7 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
 
             Type returnType = GenericsUtils.extractActualType(activeType, method);
 
-            return new Term(returnType, toUniqueId(method), BeanModelUtils.toAnnotationProvider(method), new InstructionBuilderCallback()
+            return new Term(returnType, toUniqueId(method), InternalBeanModelUtils.toAnnotationProvider(method), new InstructionBuilderCallback()
             {
                 public void doBuild(InstructionBuilder builder)
                 {

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/commons/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java b/commons/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java
new file mode 100644
index 0000000..ba7e995
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java
@@ -0,0 +1,48 @@
+// Copyright 2007, 2008, 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.services;
+
+import org.apache.tapestry5.ioc.annotations.UsesMappedConfiguration;
+import org.apache.tapestry5.ioc.annotations.UsesOrderedConfiguration;
+import org.apache.tapestry5.ioc.services.PropertyAdapter;
+
+/**
+ * Used by {@link BeanModelSource} to identify the type of data associated with a particular property (represented as a
+ * {@link PropertyAdapter}). The data type is a string used to determine what kind of interface to use for displaying
+ * the value of the property, or what kind of interface to use for editing the value of the property. Common property
+ * types are "text", "enum", "checkbox", but the list is extensible.
+ * <p/>
+ * Different strategies for identifying the data type are encapsulated in the DataTypeAnalyzer service, forming a
+ * chain of command.
+ * <p/>
+ * The DefaultDataTypeAnalyzer service maps property types to data type names.
+ * <p/>
+ * The DataTypeAnalyzer service is an extensible {@linkplain org.apache.tapestry5.ioc.services.ChainBuilder chain of
+ * command}), that (by default) includes {@link org.apache.tapestry5.internal.services.AnnotationDataTypeAnalyzer} and
+ * the {@link org.apache.tapestry5.internal.services.DefaultDataTypeAnalyzer} service (ordered last).   It uses an ordered configuration.
+ *
+ * @see org.apache.tapestry5.corelib.components.Grid
+ * @see org.apache.tapestry5.corelib.components.BeanEditForm
+ * @see BeanBlockSource
+ */
+@UsesOrderedConfiguration(DataTypeAnalyzer.class)
+@UsesMappedConfiguration(key = Class.class, value = String.class)
+public interface DataTypeAnalyzer
+{
+    /**
+     * Identifies the data type, if known, or returns null if not known.
+     */
+    String identifyDataType(PropertyAdapter adapter);
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
index aba7225..e69377f 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
@@ -59,7 +59,7 @@ public class TapestryInternalUtils
      */
     public static String toUserPresentable(String id)
     {
-        return BeanModelUtils.toUserPresentable(id);
+        return InternalBeanModelUtils.toUserPresentable(id);
     }
 
     public static Map<String, String> mapFromKeysAndValues(String... keysAndValues)
@@ -228,7 +228,7 @@ public class TapestryInternalUtils
      */
     public static String extractIdFromPropertyExpression(String expression)
     {
-        return BeanModelUtils.extractIdFromPropertyExpression(expression);
+        return InternalBeanModelUtils.extractIdFromPropertyExpression(expression);
     }
 
     /**
@@ -237,7 +237,7 @@ public class TapestryInternalUtils
      */
     public static String defaultLabel(String id, Messages messages, String propertyExpression)
     {
-        return BeanModelUtils.defaultLabel(id, messages, propertyExpression);
+        return InternalBeanModelUtils.defaultLabel(id, messages, propertyExpression);
     }
 
     /**
@@ -304,7 +304,7 @@ public class TapestryInternalUtils
 
     private static String replace(String input, Pattern pattern, String replacement)
     {
-        return BeanModelUtils.replace(input, pattern, replacement);
+        return InternalBeanModelUtils.replace(input, pattern, replacement);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
deleted file mode 100644
index 6a79b6e..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2007, 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.internal.beaneditor;
-
-import org.apache.tapestry5.beaneditor.BeanModel;
-import org.apache.tapestry5.internal.InternalConstants;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-
-/**
- * Utilities used in a few places to modify an existing {@link BeanModel}.
- */
-public final class BeanModelUtils
-{
-
-    /**
-     * Performs standard set of modifications to a {@link org.apache.tapestry5.beaneditor.BeanModel}
-     * . First new
-     * properties may be added, then properties removed, then properties reordered.
-     *
-     * @param model                to modifiy
-     * @param addPropertyNames     comma seperated list of property names to add, or null
-     * @param includePropertyNames comma seperated list of property names to include
-     * @param excludePropertyNames comma seperated list of property names to exclude, or null
-     * @param reorderPropertyNames comma seperated list of property names to reorder, or null
-     */
-    public static void modify(BeanModel model, String addPropertyNames,
-                              String includePropertyNames, String excludePropertyNames, String reorderPropertyNames)
-    {
-        if (addPropertyNames != null)
-            add(model, addPropertyNames);
-
-        if (includePropertyNames != null)
-            include(model, join(includePropertyNames, addPropertyNames));
-
-        if (excludePropertyNames != null)
-            exclude(model, excludePropertyNames);
-
-        if (reorderPropertyNames != null)
-            reorder(model, reorderPropertyNames);
-    }
-
-    private static final String join(String firstList, String optionalSecondList)
-    {
-        if (InternalUtils.isBlank(optionalSecondList))
-            return firstList;
-
-        return firstList + "," + optionalSecondList;
-    }
-
-    /**
-     * Adds empty properties to the bean model. New properties are added with a <em>null</em>
-     * {@link org.apache.tapestry5.PropertyConduit}. `
-     *
-     * @param model         to be modified
-     * @param propertyNames comma-separated list of property names
-     * @see BeanModel#addEmpty(String)
-     */
-    public static void add(BeanModel model, String propertyNames)
-    {
-        for (String name : split(propertyNames))
-        {
-            model.addEmpty(name);
-        }
-    }
-
-    /**
-     * Removes properties from the bean model.
-     *
-     * @param model
-     * @param propertyNames comma-separated list of property names
-     * @see BeanModel#exclude(String...)
-     */
-    public static void exclude(BeanModel model, String propertyNames)
-    {
-        model.exclude(split(propertyNames));
-    }
-
-    /**
-     * Selects a subset of the properties to keep, and reorders them.
-     */
-    public static void include(BeanModel model, String propertyNames)
-    {
-        model.include(split(propertyNames));
-    }
-
-    /**
-     * Reorders properties within the bean model.
-     *
-     * @param model
-     * @param propertyNames comma-separated list of property names
-     * @see BeanModel#reorder(String...)
-     */
-    public static void reorder(BeanModel model, String propertyNames)
-    {
-        model.reorder(split(propertyNames));
-    }
-
-    static String[] split(String propertyNames)
-    {
-        String trimmed = propertyNames.trim();
-
-        if (trimmed.length() == 0)
-            return InternalConstants.EMPTY_STRING_ARRAY;
-
-        return trimmed.split("\\s*,\\s*");
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java
deleted file mode 100644
index bb20de0..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java
+++ /dev/null
@@ -1,222 +0,0 @@
-// Copyright 2007, 2008, 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.internal.services;
-
-import org.apache.tapestry5.beaneditor.BeanModel;
-import org.apache.tapestry5.beaneditor.NonVisual;
-import org.apache.tapestry5.beaneditor.ReorderProperties;
-import org.apache.tapestry5.internal.beaneditor.BeanModelImpl;
-import org.apache.tapestry5.internal.beaneditor.BeanModelUtils;
-import org.apache.tapestry5.ioc.Location;
-import org.apache.tapestry5.ioc.Messages;
-import org.apache.tapestry5.ioc.ObjectLocator;
-import org.apache.tapestry5.ioc.annotations.Primary;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.services.*;
-import org.apache.tapestry5.services.BeanModelSource;
-import org.apache.tapestry5.services.ComponentLayer;
-import org.apache.tapestry5.services.DataTypeAnalyzer;
-import org.apache.tapestry5.services.PropertyConduitSource;
-
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Collections;
-import java.util.List;
-
-public class BeanModelSourceImpl implements BeanModelSource
-{
-    private final TypeCoercer typeCoercer;
-
-    private final PropertyAccess propertyAccess;
-
-    private final PropertyConduitSource propertyConduitSource;
-
-    private final PlasticProxyFactory proxyFactory;
-
-    private final DataTypeAnalyzer dataTypeAnalyzer;
-
-    private final ObjectLocator locator;
-
-    private static class PropertyOrder implements Comparable<PropertyOrder>
-    {
-        final String propertyName;
-
-        final int classDepth;
-
-        final int sortKey;
-
-        public PropertyOrder(final String propertyName, int classDepth, int sortKey)
-        {
-            this.propertyName = propertyName;
-            this.classDepth = classDepth;
-            this.sortKey = sortKey;
-        }
-
-        public int compareTo(PropertyOrder o)
-        {
-            int result = classDepth - o.classDepth;
-
-            if (result == 0)
-                result = sortKey - o.sortKey;
-
-            if (result == 0)
-                result = propertyName.compareTo(o.propertyName);
-
-            return result;
-        }
-    }
-
-    /**
-     * @param classAdapter  defines the bean that contains the properties
-     * @param propertyNames the initial set of property names, which will be rebuilt in the correct order
-     */
-    private void orderProperties(ClassPropertyAdapter classAdapter, List<String> propertyNames)
-    {
-        List<PropertyOrder> properties = CollectionFactory.newList();
-
-        for (String name : propertyNames)
-        {
-            PropertyAdapter pa = classAdapter.getPropertyAdapter(name);
-
-            Method readMethod = pa.getReadMethod();
-
-            Location location = readMethod == null ? null : proxyFactory.getMethodLocation(readMethod);
-
-            int line = location == null ? -1 : location.getLine();
-
-            properties.add(new PropertyOrder(name, computeDepth(pa), line));
-        }
-
-        Collections.sort(properties);
-
-        propertyNames.clear();
-
-        for (PropertyOrder po : properties)
-        {
-            propertyNames.add(po.propertyName);
-        }
-    }
-
-    private static int computeDepth(PropertyAdapter pa)
-    {
-        int depth = 0;
-        Class c = pa.getDeclaringClass();
-
-        // When the method originates in an interface, the parent may be null, not Object.
-
-        while (c != null && c != Object.class)
-        {
-            depth++;
-            c = c.getSuperclass();
-        }
-
-        return depth;
-    }
-
-    public BeanModelSourceImpl(TypeCoercer typeCoercer, PropertyAccess propertyAccess,
-                               PropertyConduitSource propertyConduitSource,
-                               @ComponentLayer
-                               PlasticProxyFactory proxyFactory,
-                               @Primary
-                               DataTypeAnalyzer dataTypeAnalyzer, ObjectLocator locator)
-    {
-        this.typeCoercer = typeCoercer;
-        this.propertyAccess = propertyAccess;
-        this.propertyConduitSource = propertyConduitSource;
-        this.proxyFactory = proxyFactory;
-        this.dataTypeAnalyzer = dataTypeAnalyzer;
-        this.locator = locator;
-    }
-
-    public <T> BeanModel<T> createDisplayModel(Class<T> beanClass, Messages messages)
-    {
-        return create(beanClass, false, messages);
-    }
-
-    public <T> BeanModel<T> createEditModel(Class<T> beanClass, Messages messages)
-    {
-        return create(beanClass, true, messages);
-    }
-
-    public <T> BeanModel<T> create(Class<T> beanClass, boolean filterReadOnlyProperties, Messages messages)
-    {
-        assert beanClass != null;
-        assert messages != null;
-        ClassPropertyAdapter adapter = propertyAccess.getAdapter(beanClass);
-
-        BeanModel<T> model = new BeanModelImpl<T>(beanClass, propertyConduitSource, typeCoercer, messages, locator);
-
-        for (final String propertyName : adapter.getPropertyNames())
-        {
-            PropertyAdapter pa = adapter.getPropertyAdapter(propertyName);
-
-            if (!pa.isRead())
-            {
-                continue;
-            }
-
-            if (isStaticFieldProperty(pa))
-            {
-                continue;
-            }
-
-            if (pa.getAnnotation(NonVisual.class) != null)
-            {
-                continue;
-            }
-
-            if (filterReadOnlyProperties && !pa.isUpdate())
-            {
-                continue;
-            }
-
-            final String dataType = dataTypeAnalyzer.identifyDataType(pa);
-
-            // If an unregistered type, then ignore the property.
-
-            if (dataType == null)
-            {
-                continue;
-            }
-
-            model.add(propertyName).dataType(dataType);
-        }
-
-        // First, order the properties based on the location of the getter method
-        // within the class.
-
-        List<String> propertyNames = model.getPropertyNames();
-
-        orderProperties(adapter, propertyNames);
-
-        model.reorder(propertyNames.toArray(new String[propertyNames.size()]));
-
-        // Next, check for an annotation with specific ordering information.
-
-        ReorderProperties reorderAnnotation = beanClass.getAnnotation(ReorderProperties.class);
-
-        if (reorderAnnotation != null)
-        {
-            BeanModelUtils.reorder(model, reorderAnnotation.value());
-        }
-
-        return model;
-    }
-
-    private boolean isStaticFieldProperty(PropertyAdapter adapter)
-    {
-        return adapter.isField() && Modifier.isStatic(adapter.getField().getModifiers());
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry-core/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java
deleted file mode 100644
index ba7e995..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2007, 2008, 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.services;
-
-import org.apache.tapestry5.ioc.annotations.UsesMappedConfiguration;
-import org.apache.tapestry5.ioc.annotations.UsesOrderedConfiguration;
-import org.apache.tapestry5.ioc.services.PropertyAdapter;
-
-/**
- * Used by {@link BeanModelSource} to identify the type of data associated with a particular property (represented as a
- * {@link PropertyAdapter}). The data type is a string used to determine what kind of interface to use for displaying
- * the value of the property, or what kind of interface to use for editing the value of the property. Common property
- * types are "text", "enum", "checkbox", but the list is extensible.
- * <p/>
- * Different strategies for identifying the data type are encapsulated in the DataTypeAnalyzer service, forming a
- * chain of command.
- * <p/>
- * The DefaultDataTypeAnalyzer service maps property types to data type names.
- * <p/>
- * The DataTypeAnalyzer service is an extensible {@linkplain org.apache.tapestry5.ioc.services.ChainBuilder chain of
- * command}), that (by default) includes {@link org.apache.tapestry5.internal.services.AnnotationDataTypeAnalyzer} and
- * the {@link org.apache.tapestry5.internal.services.DefaultDataTypeAnalyzer} service (ordered last).   It uses an ordered configuration.
- *
- * @see org.apache.tapestry5.corelib.components.Grid
- * @see org.apache.tapestry5.corelib.components.BeanEditForm
- * @see BeanBlockSource
- */
-@UsesOrderedConfiguration(DataTypeAnalyzer.class)
-@UsesMappedConfiguration(key = Class.class, value = String.class)
-public interface DataTypeAnalyzer
-{
-    /**
-     * Identifies the data type, if known, or returns null if not known.
-     */
-    String identifyDataType(PropertyAdapter adapter);
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java
deleted file mode 100644
index a336365..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java
+++ /dev/null
@@ -1,41 +0,0 @@
-//  Copyright 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.annotations;
-
-import java.lang.annotation.*;
-
-/**
- * A documentation-only interface placed on service interfaces for services which have a {@linkplain
- * org.apache.tapestry5.ioc.MappedConfiguration mapped configuration}, to identify the type of key (often, a String),
- * and type ofcontribution.
- * <p/>
- * Remember that when the key type is String, the map will be case-insensitive.
- */
-@Target(ElementType.TYPE)
-@Retention(RetentionPolicy.CLASS)
-@Documented
-@UseWith(AnnotationUseContext.SERVICE)
-public @interface UsesMappedConfiguration
-{
-    /**
-     * The type of key used to identify contribution values.
-     */
-    Class key() default String.class;
-
-    /**
-     * The type of object which may be contributed into the service's configuration.
-     */
-    Class value();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java
deleted file mode 100644
index 7c608f6..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java
+++ /dev/null
@@ -1,33 +0,0 @@
-//  Copyright 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.annotations;
-
-import java.lang.annotation.*;
-
-/**
- * A documentation-only interface placed on service interfaces for services which have an {@linkplain
- * org.apache.tapestry5.ioc.OrderedConfiguration ordered configuration}, to identify the type of contribution.
- */
-@Target(ElementType.TYPE)
-@Retention(RetentionPolicy.CLASS)
-@Documented
-@UseWith(AnnotationUseContext.SERVICE)
-public @interface UsesOrderedConfiguration
-{
-    /**
-     * The type of object which may be contributed into the service's configuration.
-     */
-    Class value();
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
index a40f984..8f1f7b6 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
@@ -17,7 +17,7 @@ package org.apache.tapestry5.ioc.internal.util;
 import org.apache.tapestry5.func.F;
 import org.apache.tapestry5.func.Mapper;
 import org.apache.tapestry5.func.Predicate;
-import org.apache.tapestry5.internal.BeanModelUtils;
+import org.apache.tapestry5.internal.InternalBeanModelUtils;
 import org.apache.tapestry5.internal.plastic.PlasticInternalUtils;
 import org.apache.tapestry5.ioc.*;
 import org.apache.tapestry5.ioc.annotations.*;
@@ -777,7 +777,7 @@ public class InternalUtils
      */
     public static AnnotationProvider toAnnotationProvider(final Class element)
     {
-        return BeanModelUtils.toAnnotationProvider(element);
+        return InternalBeanModelUtils.toAnnotationProvider(element);
     }
 
     /**
@@ -1404,7 +1404,7 @@ public class InternalUtils
 
     public static AnnotationProvider toAnnotationProvider(final Method element)
     {
-        return BeanModelUtils.toAnnotationProvider(element);
+        return InternalBeanModelUtils.toAnnotationProvider(element);
     }
 
     public static <T> ObjectCreator<T> createConstructorConstructionPlan(final OperationTracker tracker, final ObjectLocator locator,

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java b/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java
new file mode 100644
index 0000000..a336365
--- /dev/null
+++ b/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java
@@ -0,0 +1,41 @@
+//  Copyright 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.annotations;
+
+import java.lang.annotation.*;
+
+/**
+ * A documentation-only interface placed on service interfaces for services which have a {@linkplain
+ * org.apache.tapestry5.ioc.MappedConfiguration mapped configuration}, to identify the type of key (often, a String),
+ * and type ofcontribution.
+ * <p/>
+ * Remember that when the key type is String, the map will be case-insensitive.
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.CLASS)
+@Documented
+@UseWith(AnnotationUseContext.SERVICE)
+public @interface UsesMappedConfiguration
+{
+    /**
+     * The type of key used to identify contribution values.
+     */
+    Class key() default String.class;
+
+    /**
+     * The type of object which may be contributed into the service's configuration.
+     */
+    Class value();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java b/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java
new file mode 100644
index 0000000..7c608f6
--- /dev/null
+++ b/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java
@@ -0,0 +1,33 @@
+//  Copyright 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.annotations;
+
+import java.lang.annotation.*;
+
+/**
+ * A documentation-only interface placed on service interfaces for services which have an {@linkplain
+ * org.apache.tapestry5.ioc.OrderedConfiguration ordered configuration}, to identify the type of contribution.
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.CLASS)
+@Documented
+@UseWith(AnnotationUseContext.SERVICE)
+public @interface UsesOrderedConfiguration
+{
+    /**
+     * The type of object which may be contributed into the service's configuration.
+     */
+    Class value();
+}


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

Posted by th...@apache.org.
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/eb7ec86e
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/eb7ec86e
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/eb7ec86e

Branch: refs/heads/beanmodel-split
Commit: eb7ec86e3368e4a4e20d88c8f009d88fd1d37740
Parents: dd95846
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 19:45:14 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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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/eb7ec86e/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);
+    }
+}


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

Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java
new file mode 100644
index 0000000..49b0b15
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java
@@ -0,0 +1,59 @@
+// 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.util.List;
+
+/**
+ * Chain of command for {@link org.apache.tapestry5.ioc.AnnotationProvider}.
+ */
+public class AnnotationProviderChain implements AnnotationProvider
+{
+    private final AnnotationProvider[] providers;
+
+    public AnnotationProviderChain(AnnotationProvider[] providers)
+    {
+        this.providers = providers;
+    }
+
+    /**
+     * Creates an AnnotationProvider from the list of providers.  Returns either an {@link AnnotationProviderChain} or
+     * the sole element in the list.
+     */
+    public static AnnotationProvider create(List<AnnotationProvider> providers)
+    {
+        int size = providers.size();
+
+        if (size == 1) return providers.get(0);
+
+        return new AnnotationProviderChain(providers.toArray(new AnnotationProvider[providers.size()]));
+    }
+
+    @Override
+    public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+    {
+        for (AnnotationProvider p : providers)
+        {
+            T result = p.getAnnotation(annotationClass);
+
+            if (result != null) return result;
+        }
+
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java
new file mode 100644
index 0000000..4a5dece
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java
@@ -0,0 +1,54 @@
+// Copyright 2006, 2007 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.ioc.internal.services;
+
+import org.apache.tapestry5.ioc.services.Coercion;
+
+/**
+ * Combines two coercions to create a coercion through an intermediate type.
+ *
+ * @param <S> The source (input) type
+ * @param <I> The intermediate type
+ * @param <T> The target (output) type
+ */
+public class CompoundCoercion<S, I, T> implements Coercion<S, T>
+{
+    private final Coercion<S, I> op1;
+
+    private final Coercion<I, T> op2;
+
+    public CompoundCoercion(Coercion<S, I> op1, Coercion<I, T> op2)
+    {
+        this.op1 = op1;
+        this.op2 = op2;
+    }
+
+    @Override
+    public T coerce(S input)
+    {
+        // Run the input through the first operation (S --> I), then run the result of that through
+        // the second operation (I --> T).
+
+        I intermediate = op1.coerce(input);
+
+        return op2.coerce(intermediate);
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%s, %s", op1, op2);
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
new file mode 100644
index 0000000..e92ef2d
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
@@ -0,0 +1,68 @@
+// Copyright 2006, 2007, 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.ioc.Messages;
+import org.apache.tapestry5.ioc.internal.util.MessagesImpl;
+import org.apache.tapestry5.ioc.services.Coercion;
+import org.apache.tapestry5.plastic.PlasticUtils;
+
+public class ServiceMessages
+{
+    private final static Messages MESSAGES = MessagesImpl.forClass(ServiceMessages.class);
+
+    private ServiceMessages()
+    {
+    }
+
+    public static String noSuchProperty(Class clazz, String propertyName)
+    {
+        return MESSAGES.format("no-such-property", clazz.getName(), propertyName);
+    }
+
+
+    public static String readFailure(String propertyName, Object instance, Throwable cause)
+    {
+        return MESSAGES.format("read-failure", propertyName, instance, cause);
+    }
+
+    public static String propertyTypeMismatch(String propertyName, Class sourceClass, Class propertyType,
+                                              Class expectedType)
+    {
+        return MESSAGES.format("property-type-mismatch", propertyName, sourceClass.getName(), propertyType.getName(),
+                expectedType.getName());
+    }
+
+    public static String shutdownListenerError(Object listener, Throwable cause)
+    {
+        return MESSAGES.format("shutdown-listener-error", listener, cause);
+    }
+
+    public static String failedCoercion(Object input, Class targetType, Coercion coercion, Throwable cause)
+    {
+        return MESSAGES.format("failed-coercion", String.valueOf(input), PlasticUtils.toTypeName(targetType),
+                coercion, cause);
+    }
+
+    public static String registryShutdown(String serviceId)
+    {
+        return MESSAGES.format("registry-shutdown", serviceId);
+    }
+
+    public static String serviceBuildFailure(String serviceId, Throwable cause)
+    {
+        return MESSAGES.format("service-build-failure", serviceId, cause);
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java
new file mode 100644
index 0000000..0769b7e
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java
@@ -0,0 +1,65 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.ioc.internal.services;
+
+import org.apache.tapestry5.ioc.Location;
+import org.apache.tapestry5.ioc.Resource;
+
+/**
+ * Implementation of {@link Location} used when the underlying resource isn't really known.
+ */
+public final class StringLocation implements Location
+{
+    private final String description;
+
+    private final int line;
+
+    public StringLocation(String description, int line)
+    {
+        this.description = description;
+        this.line = line;
+    }
+
+    @Override
+    public String toString()
+    {
+        return description;
+    }
+
+    /**
+     * Returns 0.
+     */
+    @Override
+    public int getColumn()
+    {
+        return 0;
+    }
+
+    @Override
+    public int getLine()
+    {
+        return line;
+    }
+
+    /**
+     * Returns null; we don't know where the file really is (it's probably a class on the class path).
+     */
+    @Override
+    public Resource getResource()
+    {
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
new file mode 100644
index 0000000..6481384
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
@@ -0,0 +1,508 @@
+// Copyright 2006, 2007, 2008, 2010, 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.func.F;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InheritanceSearch;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
+import org.apache.tapestry5.ioc.internal.util.LockSupport;
+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.AvailableValues;
+import org.apache.tapestry5.ioc.util.UnknownValueException;
+import org.apache.tapestry5.plastic.PlasticUtils;
+import org.apache.tapestry5.util.StringToEnumCoercion;
+
+import java.util.*;
+
+@SuppressWarnings("all")
+public class TypeCoercerImpl extends LockSupport implements TypeCoercer
+{
+    // Constructed from the service's configuration.
+
+    private final Map<Class, List<CoercionTuple>> sourceTypeToTuple = CollectionFactory.newMap();
+
+    /**
+     * A coercion to a specific target type. Manages a cache of coercions to specific types.
+     */
+    private class TargetCoercion
+    {
+        private final Class type;
+
+        private final Map<Class, Coercion> cache = CollectionFactory.newConcurrentMap();
+
+        TargetCoercion(Class type)
+        {
+            this.type = type;
+        }
+
+        void clearCache()
+        {
+            cache.clear();
+        }
+
+        Object coerce(Object input)
+        {
+            Class sourceType = input != null ? input.getClass() : Void.class;
+
+            if (type.isAssignableFrom(sourceType))
+            {
+                return input;
+            }
+
+            Coercion c = getCoercion(sourceType);
+
+            try
+            {
+                return type.cast(c.coerce(input));
+            } catch (Exception ex)
+            {
+                throw new RuntimeException(ServiceMessages.failedCoercion(input, type, c, ex), ex);
+            }
+        }
+
+        String explain(Class sourceType)
+        {
+            return getCoercion(sourceType).toString();
+        }
+
+        private Coercion getCoercion(Class sourceType)
+        {
+            Coercion c = cache.get(sourceType);
+
+            if (c == null)
+            {
+                c = findOrCreateCoercion(sourceType, type);
+                cache.put(sourceType, c);
+            }
+
+            return c;
+        }
+    }
+
+    /**
+     * Map from a target type to a TargetCoercion for that type.
+     */
+    private final Map<Class, TargetCoercion> typeToTargetCoercion = new WeakHashMap<Class, TargetCoercion>();
+
+    private static final Coercion NO_COERCION = new Coercion<Object, Object>()
+    {
+        @Override
+        public Object coerce(Object input)
+        {
+            return input;
+        }
+    };
+
+    private static final Coercion COERCION_NULL_TO_OBJECT = new Coercion<Void, Object>()
+    {
+        @Override
+        public Object coerce(Void input)
+        {
+            return null;
+        }
+
+        @Override
+        public String toString()
+        {
+            return "null --> null";
+        }
+    };
+
+    public TypeCoercerImpl(Collection<CoercionTuple> tuples)
+    {
+        for (CoercionTuple tuple : tuples)
+        {
+            Class key = tuple.getSourceType();
+
+            InternalCommonsUtils.addToMapList(sourceTypeToTuple, key, tuple);
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public Object coerce(Object input, Class targetType)
+    {
+        assert targetType != null;
+
+        Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
+
+        if (effectiveTargetType.isInstance(input))
+        {
+            return input;
+        }
+
+
+        return getTargetCoercion(effectiveTargetType).coerce(input);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <S, T> Coercion<S, T> getCoercion(Class<S> sourceType, Class<T> targetType)
+    {
+        assert sourceType != null;
+        assert targetType != null;
+
+        Class effectiveSourceType = PlasticUtils.toWrapperType(sourceType);
+        Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
+
+        if (effectiveTargetType.isAssignableFrom(effectiveSourceType))
+        {
+            return NO_COERCION;
+        }
+
+        return getTargetCoercion(effectiveTargetType).getCoercion(effectiveSourceType);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <S, T> String explain(Class<S> sourceType, Class<T> targetType)
+    {
+        assert sourceType != null;
+        assert targetType != null;
+
+        Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
+        Class effectiveSourceType = PlasticUtils.toWrapperType(sourceType);
+
+        // Is a coercion even necessary? Not if the target type is assignable from the
+        // input value.
+
+        if (effectiveTargetType.isAssignableFrom(effectiveSourceType))
+        {
+            return "";
+        }
+
+        return getTargetCoercion(effectiveTargetType).explain(effectiveSourceType);
+    }
+
+    private TargetCoercion getTargetCoercion(Class targetType)
+    {
+        try
+        {
+            acquireReadLock();
+
+            TargetCoercion tc = typeToTargetCoercion.get(targetType);
+
+            return tc != null ? tc : createAndStoreNewTargetCoercion(targetType);
+        } finally
+        {
+            releaseReadLock();
+        }
+    }
+
+    private TargetCoercion createAndStoreNewTargetCoercion(Class targetType)
+    {
+        try
+        {
+            upgradeReadLockToWriteLock();
+
+            // Inner check since some other thread may have beat us to it.
+
+            TargetCoercion tc = typeToTargetCoercion.get(targetType);
+
+            if (tc == null)
+            {
+                tc = new TargetCoercion(targetType);
+                typeToTargetCoercion.put(targetType, tc);
+            }
+
+            return tc;
+        } finally
+        {
+            downgradeWriteLockToReadLock();
+        }
+    }
+
+    @Override
+    public void clearCache()
+    {
+        try
+        {
+            acquireReadLock();
+
+            // There's no need to clear the typeToTargetCoercion map, as it is a WeakHashMap and
+            // will release the keys for classes that are no longer in existence. On the other hand,
+            // there's likely all sorts of references to unloaded classes inside each TargetCoercion's
+            // individual cache, so clear all those.
+
+            for (TargetCoercion tc : typeToTargetCoercion.values())
+            {
+                // Can tc ever be null?
+
+                tc.clearCache();
+            }
+        } finally
+        {
+            releaseReadLock();
+        }
+    }
+
+    /**
+     * Here's the real meat; we do a search of the space to find coercions, or a system of
+     * coercions, that accomplish
+     * the desired coercion.
+     * <p/>
+     * There's <strong>TREMENDOUS</strong> room to improve this algorithm. For example, inheritance lists could be
+     * cached. Further, there's probably more ways to early prune the search. However, even with dozens or perhaps
+     * hundreds of tuples, I suspect the search will still grind to a conclusion quickly.
+     * <p/>
+     * The order of operations should help ensure that the most efficient tuple chain is located. If you think about how
+     * tuples are added to the queue, there are two factors: size (the number of steps in the coercion) and
+     * "class distance" (that is, number of steps up the inheritance hiearchy). All the appropriate 1 step coercions
+     * will be considered first, in class distance order. Along the way, we'll queue up all the 2 step coercions, again
+     * in class distance order. By the time we reach some of those, we'll have begun queueing up the 3 step coercions, and
+     * so forth, until we run out of input tuples we can use to fabricate multi-step compound coercions, or reach a
+     * final response.
+     * <p/>
+     * This does create a good number of short lived temporary objects (the compound tuples), but that's what the GC is
+     * really good at.
+     *
+     * @param sourceType
+     * @param targetType
+     * @return coercer from sourceType to targetType
+     */
+    @SuppressWarnings("unchecked")
+    private Coercion findOrCreateCoercion(Class sourceType, Class targetType)
+    {
+        if (sourceType == Void.class)
+        {
+            return searchForNullCoercion(targetType);
+        }
+
+        // These are instance variables because this method may be called concurrently.
+        // On a true race, we may go to the work of seeking out and/or fabricating
+        // a tuple twice, but it's more likely that different threads are looking
+        // for different source/target coercions.
+
+        Set<CoercionTuple> consideredTuples = CollectionFactory.newSet();
+        LinkedList<CoercionTuple> queue = CollectionFactory.newLinkedList();
+
+        seedQueue(sourceType, targetType, consideredTuples, queue);
+
+        while (!queue.isEmpty())
+        {
+            CoercionTuple tuple = queue.removeFirst();
+
+            // If the tuple results in a value type that is assignable to the desired target type,
+            // we're done! Later, we may add a concept of "cost" (i.e. number of steps) or
+            // "quality" (how close is the tuple target type to the desired target type). Cost
+            // is currently implicit, as compound tuples are stored deeper in the queue,
+            // so simpler coercions will be located earlier.
+
+            Class tupleTargetType = tuple.getTargetType();
+
+            if (targetType.isAssignableFrom(tupleTargetType))
+            {
+                return tuple.getCoercion();
+            }
+
+            // So .. this tuple doesn't get us directly to the target type.
+            // However, it *may* get us part of the way. Each of these
+            // represents a coercion from the source type to an intermediate type.
+            // Now we're going to look for conversions from the intermediate type
+            // to some other type.
+
+            queueIntermediates(sourceType, targetType, tuple, consideredTuples, queue);
+        }
+
+        // Not found anywhere. Identify the source and target type and a (sorted) list of
+        // all the known coercions.
+
+        throw new UnknownValueException(String.format("Could not find a coercion from type %s to type %s.",
+                sourceType.getName(), targetType.getName()), buildCoercionCatalog());
+    }
+
+    /**
+     * Coercion from null is special; we match based on the target type and its not a spanning
+     * search. In many cases, we
+     * return a pass-thru that leaves the value as null.
+     *
+     * @param targetType
+     *         desired type
+     * @return the coercion
+     */
+    private Coercion searchForNullCoercion(Class targetType)
+    {
+        List<CoercionTuple> tuples = getTuples(Void.class, targetType);
+
+        for (CoercionTuple tuple : tuples)
+        {
+            Class tupleTargetType = tuple.getTargetType();
+
+            if (targetType.equals(tupleTargetType))
+                return tuple.getCoercion();
+        }
+
+        // Typical case: no match, this coercion passes the null through
+        // as null.
+
+        return COERCION_NULL_TO_OBJECT;
+    }
+
+    /**
+     * Builds a string listing all the coercions configured for the type coercer, sorted
+     * alphabetically.
+     */
+    @SuppressWarnings("unchecked")
+    private AvailableValues buildCoercionCatalog()
+    {
+        List<CoercionTuple> masterList = CollectionFactory.newList();
+
+        for (List<CoercionTuple> list : sourceTypeToTuple.values())
+        {
+            masterList.addAll(list);
+        }
+
+        return new AvailableValues("Configured coercions", masterList);
+    }
+
+    /**
+     * Seeds the pool with the initial set of coercions for the given type.
+     */
+    private void seedQueue(Class sourceType, Class targetType, Set<CoercionTuple> consideredTuples,
+                           LinkedList<CoercionTuple> queue)
+    {
+        // Work from the source type up looking for tuples
+
+        for (Class c : new InheritanceSearch(sourceType))
+        {
+            List<CoercionTuple> tuples = getTuples(c, targetType);
+
+            if (tuples == null)
+            {
+                continue;
+            }
+
+            for (CoercionTuple tuple : tuples)
+            {
+                queue.addLast(tuple);
+                consideredTuples.add(tuple);
+            }
+
+            // Don't pull in Object -> type coercions when doing
+            // a search from null.
+
+            if (sourceType == Void.class)
+            {
+                return;
+            }
+        }
+    }
+
+    /**
+     * Creates and adds to the pool a new set of coercions based on an intermediate tuple. Adds
+     * compound coercion tuples
+     * to the end of the queue.
+     *
+     * @param sourceType
+     *         the source type of the coercion
+     * @param targetType
+     *         TODO
+     * @param intermediateTuple
+     *         a tuple that converts from the source type to some intermediate type (that is not
+     *         assignable to the target type)
+     * @param consideredTuples
+     *         set of tuples that have already been added to the pool (directly, or as a compound
+     *         coercion)
+     * @param queue
+     *         the work queue of tuples
+     */
+    @SuppressWarnings("unchecked")
+    private void queueIntermediates(Class sourceType, Class targetType, CoercionTuple intermediateTuple,
+                                    Set<CoercionTuple> consideredTuples, LinkedList<CoercionTuple> queue)
+    {
+        Class intermediateType = intermediateTuple.getTargetType();
+
+        for (Class c : new InheritanceSearch(intermediateType))
+        {
+            for (CoercionTuple tuple : getTuples(c, targetType))
+            {
+                if (consideredTuples.contains(tuple))
+                {
+                    continue;
+                }
+
+                Class newIntermediateType = tuple.getTargetType();
+
+                // If this tuple is for coercing from an intermediate type back towards our
+                // initial source type, then ignore it. This should only be an optimization,
+                // as branches that loop back towards the source type will
+                // eventually be considered and discarded.
+
+                if (sourceType.isAssignableFrom(newIntermediateType))
+                {
+                    continue;
+                }
+
+                // The intermediateTuple coercer gets from S --> I1 (an intermediate type).
+                // The current tuple's coercer gets us from I2 --> X. where I2 is assignable
+                // from I1 (i.e., I2 is a superclass/superinterface of I1) and X is a new
+                // intermediate type, hopefully closer to our eventual target type.
+
+                Coercion compoundCoercer = new CompoundCoercion(intermediateTuple.getCoercion(), tuple.getCoercion());
+
+                CoercionTuple compoundTuple = new CoercionTuple(sourceType, newIntermediateType, compoundCoercer, false);
+
+                // So, every tuple that is added to the queue can take as input the sourceType.
+                // The target type may be another intermediate type, or may be something
+                // assignable to the target type, which will bring the search to a successful
+                // conclusion.
+
+                queue.addLast(compoundTuple);
+                consideredTuples.add(tuple);
+            }
+        }
+    }
+
+    /**
+     * Returns a non-null list of the tuples from the source type.
+     *
+     * @param sourceType
+     *         used to locate tuples
+     * @param targetType
+     *         used to add synthetic tuples
+     * @return non-null list of tuples
+     */
+    private List<CoercionTuple> getTuples(Class sourceType, Class targetType)
+    {
+        List<CoercionTuple> tuples = sourceTypeToTuple.get(sourceType);
+
+        if (tuples == null)
+        {
+            tuples = Collections.emptyList();
+        }
+
+        // So, when we see String and an Enum type, we add an additional synthetic tuple to the end
+        // of the real list. This is the easiest way to accomplish this is a thread-safe and class-reloading
+        // safe way (i.e., what if the Enum is defined by a class loader that gets discarded?  Don't want to cause
+        // memory leaks by retaining an instance). In any case, there are edge cases where we may create
+        // the tuple unnecessarily (such as when an explicit string-to-enum coercion is part of the TypeCoercer
+        // configuration), but on the whole, this is cheap and works.
+
+        if (sourceType == String.class && Enum.class.isAssignableFrom(targetType))
+        {
+            tuples = extend(tuples, new CoercionTuple(sourceType, targetType, new StringToEnumCoercion(targetType)));
+        }
+
+        return tuples;
+    }
+
+    private static <T> List<T> extend(List<T> list, T extraValue)
+    {
+        return F.flow(list).append(extraValue).toList();
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
new file mode 100644
index 0000000..f1830a7
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
@@ -0,0 +1,159 @@
+// Copyright 2006 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.util;
+
+import org.apache.tapestry5.plastic.PlasticUtils;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Set;
+
+/**
+ * Used to search from a particular class up the inheritance hierarchy of extended classes and implemented interfaces.
+ * <p/>
+ * The search starts with the initial class (provided in the constructor). It progresses up the inheritance chain, but
+ * skips java.lang.Object.
+ * <p/>
+ * Once classes are exhausted, the inheritance hierarchy is searched. This is a breadth-first search, rooted in the
+ * interfaces implemented by the initial class at its super classes.
+ * <p/>
+ * Once all interfaces are exhausted, java.lang.Object is returned (it is always returned last).
+ * <p/>
+ * Two minor tweak to normal inheritance rules: <ul> <li> Normally, the parent class of an <em>object</em> array is
+ * java.lang.Object, which is odd because FooService[] is assignable to Object[]. Thus, we tweak the search so that the
+ * effective super class of FooService[] is Object[]. <li> The "super class" of a primtive type is its <em>wrapper type</em>,
+ * with the exception of void, whose "super class" is left at its normal value (Object.class) </ul>
+ * <p/>
+ * This class implements the {@link Iterable} interface, so it can be used directly in a for loop: <code> for (Class
+ * search : new InheritanceSearch(startClass)) { ... } </code>
+ * <p/>
+ * This class is not thread-safe.
+ */
+public class InheritanceSearch implements Iterator<Class>, Iterable<Class>
+{
+    private Class searchClass;
+
+    private final Set<Class> addedInterfaces = CollectionFactory.newSet();
+
+    private final LinkedList<Class> interfaceQueue = CollectionFactory.newLinkedList();
+
+    private enum State
+    {
+        CLASS, INTERFACE, DONE
+    }
+
+    private State state;
+
+    public InheritanceSearch(Class searchClass)
+    {
+        this.searchClass = searchClass;
+
+        queueInterfaces(searchClass);
+
+        state = searchClass == Object.class ? State.INTERFACE : State.CLASS;
+    }
+
+    private void queueInterfaces(Class searchClass)
+    {
+        for (Class intf : searchClass.getInterfaces())
+        {
+            if (addedInterfaces.contains(intf)) continue;
+
+            interfaceQueue.addLast(intf);
+            addedInterfaces.add(intf);
+        }
+    }
+
+    @Override
+    public Iterator<Class> iterator()
+    {
+        return this;
+    }
+
+    @Override
+    public boolean hasNext()
+    {
+        return state != State.DONE;
+    }
+
+    @Override
+    public Class next()
+    {
+        switch (state)
+        {
+            case CLASS:
+
+                Class result = searchClass;
+
+                searchClass = parentOf(searchClass);
+
+                if (searchClass == null) state = State.INTERFACE;
+                else queueInterfaces(searchClass);
+
+                return result;
+
+            case INTERFACE:
+
+                if (interfaceQueue.isEmpty())
+                {
+                    state = State.DONE;
+                    return Object.class;
+                }
+
+                Class intf = interfaceQueue.removeFirst();
+
+                queueInterfaces(intf);
+
+                return intf;
+
+            default:
+                throw new IllegalStateException();
+        }
+
+    }
+
+    /**
+     * Returns the parent of the given class. Tweaks inheritance for object arrays. Returns null instead of
+     * Object.class.
+     */
+    private Class parentOf(Class clazz)
+    {
+        if (clazz != void.class && clazz.isPrimitive()) return PlasticUtils.toWrapperType(clazz);
+
+        if (clazz.isArray() && clazz != Object[].class)
+        {
+            Class componentType = clazz.getComponentType();
+
+            while (componentType.isArray()) componentType = componentType.getComponentType();
+
+            if (!componentType.isPrimitive()) return Object[].class;
+        }
+
+        Class parent = clazz.getSuperclass();
+
+        return parent != Object.class ? parent : null;
+    }
+
+    /**
+     * @throws UnsupportedOperationException
+     *         always
+     */
+    @Override
+    public void remove()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
new file mode 100644
index 0000000..3c391e0
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
@@ -0,0 +1,388 @@
+// Copyright 2006-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.util;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+import org.apache.tapestry5.ioc.Locatable;
+import org.apache.tapestry5.ioc.Location;
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
+
+/**
+ * Utility methods class for the Commons package.
+ */
+public class InternalCommonsUtils {
+
+	/**
+	 * @since 5.3
+	 */
+	public final static AnnotationProvider NULL_ANNOTATION_PROVIDER = new NullAnnotationProvider();
+	private static final Pattern NON_WORD_PATTERN = Pattern.compile("[^\\w]");
+
+    /**
+     * Adds a value to a specially organized map where the values are lists of objects. This somewhat simulates a map
+     * that allows multiple values for the same key.
+     *
+     * @param map
+     *         to store value into
+     * @param key
+     *         for which a value is added
+     * @param value
+     *         to add
+     * @param <K>
+     *         the type of key
+     * @param <V>
+     *         the type of the list
+     */
+    public static <K, V> void addToMapList(Map<K, List<V>> map, K key, V value)
+    {
+        List<V> list = map.get(key);
+
+        if (list == null)
+        {
+            list = CollectionFactory.newList();
+            map.put(key, list);
+        }
+
+        list.add(value);
+    }
+
+	/**
+	 * Sniffs the object to see if it is a {@link Location} or {@link Locatable}. Returns null if null or not
+	 * convertable to a location.
+	 */
+	
+	public static Location locationOf(Object location)
+	{
+	    if (location == null)
+	        return null;
+	
+	    if (location instanceof Location)
+	        return (Location) location;
+	
+	    if (location instanceof Locatable)
+	        return ((Locatable) location).getLocation();
+	
+	    return null;
+	}
+
+	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);
+	        }
+	    };
+	}
+
+	/**
+	 * 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(InternalCommonsUtils.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));
+	        }
+	    };
+	}
+
+	/**
+	 * Pattern used to eliminate leading and trailing underscores and dollar signs.
+	 */
+	static final Pattern NAME_PATTERN = Pattern.compile("^[_|$]*([\\p{javaJavaIdentifierPart}]+?)[_|$]*$",
+	        Pattern.CASE_INSENSITIVE);
+
+	/**
+	 * Converts a method to a user presentable string consisting of the containing class name, the method name, and the
+	 * short form of the parameter list (the class name of each parameter type, shorn of the package name portion).
+	 *
+	 * @param method
+	 * @return short string representation
+	 */
+	public static String asString(Method method)
+	{
+	    StringBuilder buffer = new StringBuilder();
+	
+	    buffer.append(method.getDeclaringClass().getName());
+	    buffer.append(".");
+	    buffer.append(method.getName());
+	    buffer.append("(");
+	
+	    for (int i = 0; i < method.getParameterTypes().length; i++)
+	    {
+	        if (i > 0)
+	            buffer.append(", ");
+	
+	        String name = method.getParameterTypes()[i].getSimpleName();
+	
+	        buffer.append(name);
+	    }
+	
+	    return buffer.append(")").toString();
+	}
+
+	/**
+	 * Strips leading "_" and "$" and trailing "_" from the name.
+	 */
+	public static String stripMemberName(String memberName)
+	{
+	    assert InternalCommonsUtils.isNonBlank(memberName);
+	    Matcher matcher = NAME_PATTERN.matcher(memberName);
+	
+	    if (!matcher.matches())
+	        throw new IllegalArgumentException(String.format("Input '%s' is not a valid Java identifier.", memberName));
+	
+	    return matcher.group(1);
+	}
+
+	/**
+	 * Joins together some number of elements to form a comma separated list.
+	 */
+	public static String join(List elements)
+	{
+	    return InternalCommonsUtils.join(elements, ", ");
+	}
+
+	/**
+	 * Joins together some number of elements. If a value in the list is the empty string, it is replaced with the
+	 * string "(blank)".
+	 *
+	 * @param elements
+	 *         objects to be joined together
+	 * @param separator
+	 *         used between elements when joining
+	 */
+	public static String join(List elements, String separator)
+	{
+	    switch (elements.size())
+	    {
+	        case 0:
+	            return "";
+	
+	        case 1:
+	            return elements.get(0).toString();
+	
+	        default:
+	
+	            StringBuilder buffer = new StringBuilder();
+	            boolean first = true;
+	
+	            for (Object o : elements)
+	            {
+	                if (!first)
+	                    buffer.append(separator);
+	
+	                String string = String.valueOf(o);
+	
+	                if (string.equals(""))
+	                    string = "(blank)";
+	
+	                buffer.append(string);
+	
+	                first = false;
+	            }
+	
+	            return buffer.toString();
+	    }
+	}
+
+	/**
+	 * Creates a sorted copy of the provided elements, then turns that into a comma separated list.
+	 *
+	 * @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
+	 *         empty
+	 */
+	public static String joinSorted(Collection elements)
+	{
+	    if (elements == null || elements.isEmpty())
+	        return "(none)";
+	
+	    List<String> list = CollectionFactory.newList();
+	
+	    for (Object o : elements)
+	        list.add(String.valueOf(o));
+	
+	    Collections.sort(list);
+	
+	    return join(list);
+	}
+
+	/**
+	 * Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
+	 */
+	
+	public static boolean isBlank(String input)
+	{
+	    return input == null || input.length() == 0 || input.trim().length() == 0;
+	}
+
+	/**
+	 * Capitalizes a string, converting the first character to uppercase.
+	 */
+	public static String capitalize(String input)
+	{
+	    if (input.length() == 0)
+	        return input;
+	
+	    return input.substring(0, 1).toUpperCase() + input.substring(1);
+	}
+
+	public static boolean isNonBlank(String input)
+	{
+	    return !isBlank(input);
+	}
+
+	/**
+	 * Return true if the input string contains the marker for symbols that must be expanded.
+	 */
+	public static boolean containsSymbols(String input)
+	{
+	    return input.contains("${");
+	}
+
+	/**
+	 * Searches the string for the final period ('.') character and returns everything after that. The input string is
+	 * generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
+	 * expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
+	 * character.
+	 */
+	public static String lastTerm(String input)
+	{
+	    assert isNonBlank(input);
+	    int dotx = input.lastIndexOf('.');
+	
+	    if (dotx < 0)
+	        return input;
+	
+	    return input.substring(dotx + 1);
+	}
+
+	/**
+	 * Extracts the string keys from a map and returns them in sorted order. The keys are converted to strings.
+	 *
+	 * @param map
+	 *         the map to extract keys from (may be null)
+	 * @return the sorted keys, or the empty set if map is null
+	 */
+	
+	public static List<String> sortedKeys(Map map)
+	{
+	    if (map == null)
+	        return Collections.emptyList();
+	
+	    List<String> keys = CollectionFactory.newList();
+	
+	    for (Object o : map.keySet())
+	        keys.add(String.valueOf(o));
+	
+	    Collections.sort(keys);
+	
+	    return keys;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java
deleted file mode 100644
index e345593..0000000
--- a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright 2006-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.util;
-
-import java.lang.reflect.Method;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * String-related utilities used within various internal implementations of the Apache Tapestry subprojects.
- * Broken off Tapestry-IoC's InternalUtils.
- */
-@SuppressWarnings("all")
-public class InternalStringUtils
-{
-	
-    /**
-     * Pattern used to eliminate leading and trailing underscores and dollar signs.
-     */
-    private static final Pattern NAME_PATTERN = Pattern.compile("^[_|$]*([\\p{javaJavaIdentifierPart}]+?)[_|$]*$",
-            Pattern.CASE_INSENSITIVE);
-
-    /**
-     * Converts a method to a user presentable string consisting of the containing class name, the method name, and the
-     * short form of the parameter list (the class name of each parameter type, shorn of the package name portion).
-     *
-     * @param method
-     * @return short string representation
-     */
-    public static String asString(Method method)
-    {
-        StringBuilder buffer = new StringBuilder();
-
-        buffer.append(method.getDeclaringClass().getName());
-        buffer.append(".");
-        buffer.append(method.getName());
-        buffer.append("(");
-
-        for (int i = 0; i < method.getParameterTypes().length; i++)
-        {
-            if (i > 0)
-                buffer.append(", ");
-
-            String name = method.getParameterTypes()[i].getSimpleName();
-
-            buffer.append(name);
-        }
-
-        return buffer.append(")").toString();
-    }
-
-    /**
-     * Strips leading "_" and "$" and trailing "_" from the name.
-     */
-    public static String stripMemberName(String memberName)
-    {
-        assert isNonBlank(memberName);
-        Matcher matcher = NAME_PATTERN.matcher(memberName);
-
-        if (!matcher.matches())
-            throw new IllegalArgumentException(String.format("Input '%s' is not a valid Java identifier.", memberName));
-
-        return matcher.group(1);
-    }
-
-    /**
-     * Joins together some number of elements to form a comma separated list.
-     */
-    public static String join(List elements)
-    {
-        return join(elements, ", ");
-    }
-
-    /**
-     * Joins together some number of elements. If a value in the list is the empty string, it is replaced with the
-     * string "(blank)".
-     *
-     * @param elements
-     *         objects to be joined together
-     * @param separator
-     *         used between elements when joining
-     */
-    public static String join(List elements, String separator)
-    {
-        switch (elements.size())
-        {
-            case 0:
-                return "";
-
-            case 1:
-                return elements.get(0).toString();
-
-            default:
-
-                StringBuilder buffer = new StringBuilder();
-                boolean first = true;
-
-                for (Object o : elements)
-                {
-                    if (!first)
-                        buffer.append(separator);
-
-                    String string = String.valueOf(o);
-
-                    if (string.equals(""))
-                        string = "(blank)";
-
-                    buffer.append(string);
-
-                    first = false;
-                }
-
-                return buffer.toString();
-        }
-    }
-
-    /**
-     * Creates a sorted copy of the provided elements, then turns that into a comma separated list.
-     *
-     * @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
-     *         empty
-     */
-    public static String joinSorted(Collection elements)
-    {
-        if (elements == null || elements.isEmpty())
-            return "(none)";
-
-        List<String> list = CollectionFactory.newList();
-
-        for (Object o : elements)
-            list.add(String.valueOf(o));
-
-        Collections.sort(list);
-
-        return join(list);
-    }
-
-    /**
-     * Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
-     */
-
-    public static boolean isBlank(String input)
-    {
-        return input == null || input.length() == 0 || input.trim().length() == 0;
-    }
-
-    public static boolean isNonBlank(String input)
-    {
-        return !isBlank(input);
-    }
-
-    /**
-     * Capitalizes a string, converting the first character to uppercase.
-     */
-    public static String capitalize(String input)
-    {
-        if (input.length() == 0)
-            return input;
-
-        return input.substring(0, 1).toUpperCase() + input.substring(1);
-    }
-
-    /**
-     * Return true if the input string contains the marker for symbols that must be expanded.
-     */
-    public static boolean containsSymbols(String input)
-    {
-        return input.contains("${");
-    }
-
-    /**
-     * Searches the string for the final period ('.') character and returns everything after that. The input string is
-     * generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
-     * expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
-     * character.
-     */
-    public static String lastTerm(String input)
-    {
-        assert isNonBlank(input);
-        int dotx = input.lastIndexOf('.');
-
-        if (dotx < 0)
-            return input;
-
-        return input.substring(dotx + 1);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
new file mode 100644
index 0000000..41de363
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
@@ -0,0 +1,89 @@
+// Copyright 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.util;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * Base class for classes that need to manage a ReadWriteLock.
+ */
+public abstract class LockSupport
+{
+    private final Lock readLock, writeLock;
+
+    protected LockSupport()
+    {
+        ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
+
+        readLock = lock.readLock();
+        writeLock = lock.writeLock();
+    }
+
+    /**
+     * Locks the shared read lock. Any number of threads may lock the read lock at the same time.
+     */
+    protected final void acquireReadLock()
+    {
+        readLock.lock();
+    }
+
+    /**
+     * Takes the exclusive write lock. Once started, no other thread lock the read or write lock. When this method returns,
+     * this thread will have locked the write lock and no other thread will have either the read or write lock.
+     * Note that this thread must first drop the read lock (if it has it) before attempting to take the write lock, or this method will block forever.
+     */
+    protected final void takeWriteLock()
+    {
+        writeLock.lock();
+    }
+
+    /**
+     * Releases the shared read lock.
+     */
+    protected final void releaseReadLock()
+    {
+        readLock.unlock();
+    }
+
+    /**
+     * Releases the  exclusive read lock.
+     */
+    protected final void releaseWriteLock()
+    {
+        writeLock.unlock();
+    }
+
+    /**
+     * Releases the read lock, then takes the write lock. There's a short window where the thread will have neither lock:
+     * during that window, some other thread may have a chance to take the write lock. In code, you'll often see a second check
+     * inside the code that has the write lock to see if the update to perform is still necessary.
+     */
+    protected final void upgradeReadLockToWriteLock()
+    {
+        releaseReadLock();
+        // This is that instant where another thread may grab the write lock. Very rare, but possible.
+        takeWriteLock();
+    }
+
+    /**
+     * Takes the read lock then releases the write lock.
+     */
+    protected final void downgradeWriteLockToReadLock()
+    {
+        acquireReadLock();
+        releaseWriteLock();
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java
new file mode 100644
index 0000000..f4d8949
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java
@@ -0,0 +1,65 @@
+// 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.util;
+
+import org.apache.tapestry5.ioc.MessageFormatter;
+import org.apache.tapestry5.ioc.util.ExceptionUtils;
+
+import java.util.Locale;
+
+
+public class MessageFormatterImpl implements MessageFormatter
+{
+    private final String format;
+
+    private final Locale locale;
+
+    public MessageFormatterImpl(String format, Locale locale)
+    {
+        this.format = format;
+        this.locale = locale;
+    }
+
+    @Override
+    public String format(Object... args)
+    {
+        for (int i = 0; i < args.length; i++)
+        {
+            Object arg = args[i];
+
+            if (Throwable.class.isInstance(arg))
+            {
+                args[i] = ExceptionUtils.toMessage((Throwable) arg);
+            }
+        }
+
+        // Might be tempting to create a Formatter object and just keep reusing it ... but
+        // Formatters are not threadsafe.
+
+        return String.format(locale, format, args);
+    }
+
+    /**
+     * Returns the underlying format string for this formatter.
+     *
+     * @since 5.4
+     */
+    @Override
+    public String toString()
+    {
+        return format;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
new file mode 100644
index 0000000..c06ef90
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
@@ -0,0 +1,74 @@
+// Copyright 2006, 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.util;
+
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.util.AbstractMessages;
+
+import java.util.*;
+
+/**
+ * Implementation of {@link org.apache.tapestry5.ioc.Messages} based around a {@link java.util.ResourceBundle}.
+ */
+public class MessagesImpl extends AbstractMessages
+{
+    private final Map<String, String> properties = CollectionFactory.newCaseInsensitiveMap();
+
+    /**
+     * Finds the messages for a given Messages utility class. Strings the trailing "Messages" and replaces it with
+     * "Strings" to form the base path. Loads the bundle using the default locale, and the class' class loader.
+     *
+     * @param forClass
+     * @return Messages for the class
+     */
+    public static Messages forClass(Class forClass)
+    {
+        String className = forClass.getName();
+        String stringsClassName = className.replaceAll("Messages$", "Strings");
+
+        Locale locale = Locale.getDefault();
+
+        ResourceBundle bundle = ResourceBundle.getBundle(stringsClassName, locale, forClass.getClassLoader());
+
+        return new MessagesImpl(locale, bundle);
+    }
+
+    public MessagesImpl(Locale locale, ResourceBundle bundle)
+    {
+        super(locale);
+
+        // Our best (threadsafe) chance to determine all the available keys.
+        Enumeration<String> e = bundle.getKeys();
+        while (e.hasMoreElements())
+        {
+            String key = e.nextElement();
+            String value = bundle.getString(key);
+
+            properties.put(key, value);
+        }
+    }
+
+    @Override
+    protected String valueForKey(String key)
+    {
+        return properties.get(key);
+    }
+
+    @Override
+    public Set<String> getKeys()
+    {
+        return properties.keySet();
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
index d8d8018..6e23c5b 100644
--- a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
@@ -34,7 +34,7 @@ public class TapestryException extends RuntimeException implements Locatable
      */
     public TapestryException(String message, Object location, Throwable cause)
     {
-        this(message, locationOf(location), cause);
+        this(message, InternalCommonsUtils.locationOf(location), cause);
     }
 
     /**
@@ -71,26 +71,5 @@ public class TapestryException extends RuntimeException implements Locatable
 
         return String.format("%s [at %s]", super.toString(), location);
     }
-    
-    /**
-     * Sniffs the object to see if it is a {@link Location} or {@link Locatable}. Returns null if null or not
-     * convertable to a location.
-     * Copied from InternalUtils to avoid having it moved to BeanModel or Commons subprojects.
-     */
-
-    private static Location locationOf(Object location)
-    {
-        if (location == null)
-            return null;
-
-        if (location instanceof Location)
-            return (Location) location;
-
-        if (location instanceof Locatable)
-            return ((Locatable) location).getLocation();
-
-        return null;
-    }
-
 
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java
new file mode 100644
index 0000000..590c337
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java
@@ -0,0 +1,94 @@
+// Copyright 2006, 2009, 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.util;
+
+import org.apache.tapestry5.ioc.MessageFormatter;
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.MessageFormatterImpl;
+
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Abstract implementation of {@link Messages} that doesn't know where values come from (that information is supplied in
+ * a subclass, via the {@link #valueForKey(String)} method).
+ */
+public abstract class AbstractMessages implements Messages
+{
+    /**
+     * String key to MF instance.
+     */
+    private final Map<String, MessageFormatter> cache = CollectionFactory.newConcurrentMap();
+
+    private final Locale locale;
+
+    protected AbstractMessages(Locale locale)
+    {
+        this.locale = locale;
+    }
+
+    /**
+     * Invoked to provide the value for a particular key. This may be invoked multiple times even for the same key. The
+     * implementation should <em>ignore the case of the key</em>.
+     *
+     * @param key the key to obtain a value for (case insensitive)
+     * @return the value for the key, or null if this instance can not provide the value
+     */
+    protected abstract String valueForKey(String key);
+
+
+    @Override
+    public boolean contains(String key)
+    {
+        return valueForKey(key) != null;
+    }
+
+    @Override
+    public String get(String key)
+    {
+        if (contains(key)) return valueForKey(key);
+
+        return String.format("[[missing key: %s]]", key);
+    }
+
+    @Override
+    public MessageFormatter getFormatter(String key)
+    {
+        MessageFormatter result = cache.get(key);
+
+        if (result == null)
+        {
+            result = buildMessageFormatter(key);
+            cache.put(key, result);
+        }
+
+        return result;
+    }
+
+    private MessageFormatter buildMessageFormatter(String key)
+    {
+        String format = get(key);
+
+        return new MessageFormatterImpl(format, locale);
+    }
+
+    @Override
+    public String format(String key, Object... args)
+    {
+        return getFormatter(key).format(args);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
index 8c9cb3f..b2f1386 100644
--- a/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
@@ -20,7 +20,7 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
 
 /**
  * Used (as part of a {@link UnknownValueException} to identify what available values
@@ -81,7 +81,7 @@ public class AvailableValues
     @Override
     public String toString()
     {
-        return String.format("AvailableValues[%s: %s]", valueType, InternalStringUtils.join(values));
+        return String.format("AvailableValues[%s: %s]", valueType, InternalCommonsUtils.join(values));
     }
 
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java
new file mode 100644
index 0000000..01ef99e
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java
@@ -0,0 +1,195 @@
+// Copyright 2007, 2008, 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.util;
+
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
+
+/**
+ * Used to represent a period of time, specifically as a configuration value. This is often used to specify timeouts.
+ * <p/>
+ * TimePeriods are parsed from strings.
+ * <p/>
+ * The string specifys a number of terms. The values of all the terms are summed together to form the total time period.
+ * Each term consists of a number followed by a unit. Units (from largest to smallest) are: <dl> <dt>y <dd>year <dt>d
+ * <dd>day <dt>h <dd>hour <dt>m <dd>minute <dt>s <dd>second <dt>ms <dd>millisecond </dl> <p>  Example: "2 h 30 m". By
+ * convention, terms are specified largest to smallest.  A term without a unit is assumed to be milliseconds.  Units are
+ * case insensitive ("h" or "H" are treated the same).
+ */
+public class TimeInterval
+{
+    private static final Map<String, Long> UNITS = CollectionFactory.newCaseInsensitiveMap();
+
+    private static final long MILLISECOND = 1000l;
+
+    static
+    {
+        UNITS.put("ms", 1l);
+        UNITS.put("s", MILLISECOND);
+        UNITS.put("m", 60 * MILLISECOND);
+        UNITS.put("h", 60 * UNITS.get("m"));
+        UNITS.put("d", 24 * UNITS.get("h"));
+        UNITS.put("y", 365 * UNITS.get("d"));
+    }
+
+    /**
+     * The unit keys, sorted in descending order.
+     */
+    private static final String[] UNIT_KEYS =
+    { "y", "d", "h", "m", "s", "ms" };
+
+    private static final Pattern PATTERN = Pattern.compile("\\s*(\\d+)\\s*([a-z]*)", Pattern.CASE_INSENSITIVE);
+
+    private final long milliseconds;
+
+    /**
+     * Creates a TimeInterval for a string.
+     * 
+     * @param input
+     *            the string specifying the amount of time in the period
+     */
+    public TimeInterval(String input)
+    {
+        this(parseMilliseconds(input));
+    }
+
+    public TimeInterval(long milliseconds)
+    {
+        this.milliseconds = milliseconds;
+    }
+
+    public long milliseconds()
+    {
+        return milliseconds;
+    }
+
+    public long seconds()
+    {
+        return milliseconds / MILLISECOND;
+    }
+
+    /**
+     * Converts the milliseconds back into a string (compatible with {@link #TimeInterval(String)}).
+     * 
+     * @since 5.2.0
+     */
+    public String toDescription()
+    {
+        StringBuilder builder = new StringBuilder();
+
+        String sep = "";
+
+        long remainder = milliseconds;
+
+        for (String key : UNIT_KEYS)
+        {
+            if (remainder == 0)
+                break;
+
+            long value = UNITS.get(key);
+
+            long units = remainder / value;
+
+            if (units > 0)
+            {
+                builder.append(sep);
+                builder.append(units);
+                builder.append(key);
+
+                sep = " ";
+
+                remainder = remainder % value;
+            }
+        }
+
+        return builder.toString();
+    }
+
+    static long parseMilliseconds(String input)
+    {
+        long milliseconds = 0l;
+
+        Matcher matcher = PATTERN.matcher(input);
+
+        matcher.useAnchoringBounds(true);
+
+        // TODO: Notice non matching characters and reject input, including at end
+
+        int lastMatchEnd = -1;
+
+        while (matcher.find())
+        {
+            int start = matcher.start();
+
+            if (lastMatchEnd + 1 < start)
+            {
+                String invalid = input.substring(lastMatchEnd + 1, start);
+                throw new RuntimeException(String.format("Unexpected string '%s' (in time interval '%s').", invalid, input));
+            }
+
+            lastMatchEnd = matcher.end();
+
+            long count = Long.parseLong(matcher.group(1));
+            String units = matcher.group(2);
+
+            if (units.length() == 0)
+            {
+                milliseconds += count;
+                continue;
+            }
+
+            Long unitValue = UNITS.get(units);
+
+            if (unitValue == null)
+                throw new RuntimeException(String.format("Unknown time interval unit '%s' (in '%s').  Defined units: %s.", units, input, InternalCommonsUtils.joinSorted(UNITS.keySet())));
+
+            milliseconds += count * unitValue;
+        }
+
+        if (lastMatchEnd + 1 < input.length())
+        {
+            String invalid = input.substring(lastMatchEnd + 1);
+            throw new RuntimeException(String.format("Unexpected string '%s' (in time interval '%s').", invalid, input));
+        }
+
+        return milliseconds;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("TimeInterval[%d ms]", milliseconds);
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (obj == null)
+            return false;
+
+        if (obj instanceof TimeInterval)
+        {
+            TimeInterval tp = (TimeInterval) obj;
+
+            return milliseconds == tp.milliseconds;
+        }
+
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java b/commons/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java
new file mode 100644
index 0000000..bdde866
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java
@@ -0,0 +1,91 @@
+// Copyright 2007, 2008, 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.util;
+
+import java.util.Map;
+
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
+import org.apache.tapestry5.ioc.services.Coercion;
+import org.apache.tapestry5.ioc.util.AvailableValues;
+import org.apache.tapestry5.ioc.util.UnknownValueException;
+
+/**
+ * A {@link org.apache.tapestry5.ioc.services.Coercion} for converting strings into an instance of a particular
+ * enumerated type. The {@link Enum#name() name} is used as the key to identify the enum instance, in a case-insensitive
+ * fashion.
+ * <p>
+ * Moved from tapestry-core to tapestry-ioc is release 5.3, but kept in same package for compatibility.
+ * 
+ * @param <T>
+ *            the type of enumeration
+ */
+public final class StringToEnumCoercion<T extends Enum> implements Coercion<String, T>
+{
+    private final Class<T> enumClass;
+
+    private final Map<String, T> stringToEnum = CollectionFactory.newCaseInsensitiveMap();
+
+    public StringToEnumCoercion(Class<T> enumClass)
+    {
+        this(enumClass, enumClass.getEnumConstants());
+    }
+
+    public StringToEnumCoercion(Class<T> enumClass, T... values)
+    {
+        this.enumClass = enumClass;
+
+        for (T value : values)
+            stringToEnum.put(value.name(), value);
+    }
+
+    @Override
+    public T coerce(String input)
+    {
+        if (InternalCommonsUtils.isBlank(input))
+            return null;
+
+        T result = stringToEnum.get(input);
+
+        if (result == null)
+        {
+            String message = String.format("Input '%s' does not identify a value from enumerated type %s.", input,
+                    enumClass.getName());
+
+            throw new UnknownValueException(message, new AvailableValues(enumClass.getName() + " enum constants",
+                    stringToEnum));
+        }
+
+        return result;
+    }
+
+    /**
+     * Allows an alias value (alternate) string to reference a value.
+     * 
+     * @since 5.2.2
+     */
+    public StringToEnumCoercion<T> addAlias(String alias, T value)
+    {
+        stringToEnum.put(alias, value);
+
+        return this;
+    }
+
+    public static <T extends Enum> StringToEnumCoercion<T> create(Class<T> enumClass)
+    {
+        return new StringToEnumCoercion<T>(enumClass);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
index e69377f..e032975 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
@@ -59,7 +59,7 @@ public class TapestryInternalUtils
      */
     public static String toUserPresentable(String id)
     {
-        return InternalBeanModelUtils.toUserPresentable(id);
+        return InternalUtils.toUserPresentable(id);
     }
 
     public static Map<String, String> mapFromKeysAndValues(String... keysAndValues)
@@ -228,7 +228,7 @@ public class TapestryInternalUtils
      */
     public static String extractIdFromPropertyExpression(String expression)
     {
-        return InternalBeanModelUtils.extractIdFromPropertyExpression(expression);
+        return InternalUtils.extractIdFromPropertyExpression(expression);
     }
 
     /**
@@ -237,7 +237,7 @@ public class TapestryInternalUtils
      */
     public static String defaultLabel(String id, Messages messages, String propertyExpression)
     {
-        return InternalBeanModelUtils.defaultLabel(id, messages, propertyExpression);
+        return InternalUtils.defaultLabel(id, messages, propertyExpression);
     }
 
     /**
@@ -304,7 +304,7 @@ public class TapestryInternalUtils
 
     private static String replace(String input, Pattern pattern, String replacement)
     {
-        return InternalBeanModelUtils.replace(input, pattern, replacement);
+        return InternalUtils.replace(input, pattern, replacement);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java
deleted file mode 100644
index 43519dc..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java
+++ /dev/null
@@ -1,53 +0,0 @@
-// 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/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Configuration.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Configuration.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Configuration.java
deleted file mode 100644
index 03814f5..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Configuration.java
+++ /dev/null
@@ -1,53 +0,0 @@
-// 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/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java
deleted file mode 100644
index 47c6026..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java
+++ /dev/null
@@ -1,81 +0,0 @@
-// 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);
-}


[06/15] tapestry-5 git commit: First pass creating the BeanModel and Commons packages. Lots of stuff moved around, but no actual code changes so far

Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/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
new file mode 100644
index 0000000..701420f
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
@@ -0,0 +1,1563 @@
+// Copyright 2007-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.internal.services;
+
+import org.antlr.runtime.ANTLRInputStream;
+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.InternalPropertyConduit;
+import org.apache.tapestry5.internal.antlr.PropertyExpressionLexer;
+import org.apache.tapestry5.internal.antlr.PropertyExpressionParser;
+import org.apache.tapestry5.internal.util.IntegerRange;
+import org.apache.tapestry5.internal.util.MultiKey;
+import org.apache.tapestry5.ioc.AnnotationProvider;
+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.InternalUtils;
+import org.apache.tapestry5.ioc.services.*;
+import org.apache.tapestry5.ioc.util.AvailableValues;
+import org.apache.tapestry5.ioc.util.ExceptionUtils;
+import org.apache.tapestry5.ioc.util.UnknownValueException;
+import org.apache.tapestry5.plastic.*;
+import org.apache.tapestry5.services.ComponentClasses;
+import org.apache.tapestry5.services.ComponentLayer;
+import org.apache.tapestry5.services.InvalidationEventHub;
+import org.apache.tapestry5.services.PropertyConduitSource;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.*;
+
+public class PropertyConduitSourceImpl implements PropertyConduitSource
+{
+    static class ConduitMethods
+    {
+        private static final MethodDescription GET = getMethodDescription(PropertyConduit.class, "get", Object.class);
+
+        private static final MethodDescription SET = getMethodDescription(PropertyConduit.class, "set", Object.class,
+                Object.class);
+
+        private static final MethodDescription GET_PROPERTY_TYPE = getMethodDescription(PropertyConduit.class,
+                "getPropertyType");
+
+        private static final MethodDescription GET_PROPERTY_GENERIC_TYPE = getMethodDescription(PropertyConduit2.class,
+                "getPropertyGenericType");
+        
+        private static final MethodDescription GET_PROPERTY_NAME = getMethodDescription(InternalPropertyConduit.class,
+                "getPropertyName");
+        
+        private static final MethodDescription GET_ANNOTATION = getMethodDescription(AnnotationProvider.class,
+                "getAnnotation", Class.class);
+
+    }
+
+    static class DelegateMethods
+    {
+        static final Method INVERT = getMethod(PropertyConduitDelegate.class, "invert", Object.class);
+
+        static final Method RANGE = getMethod(PropertyConduitDelegate.class, "range", int.class, int.class);
+
+        static final Method COERCE = getMethod(PropertyConduitDelegate.class, "coerce", Object.class, Class.class);
+    }
+
+    static class ArrayListMethods
+    {
+        static final Method ADD = getMethod(ArrayList.class, "add", Object.class);
+    }
+
+    static class HashMapMethods
+    {
+        static final Method PUT = getMethod(HashMap.class, "put", Object.class, Object.class);
+    }
+
+    private static InstructionBuilderCallback RETURN_NULL = new InstructionBuilderCallback()
+    {
+        public void doBuild(InstructionBuilder builder)
+        {
+            builder.loadNull().returnResult();
+        }
+    };
+
+    private static final String[] SINGLE_OBJECT_ARGUMENT = new String[]
+            {Object.class.getName()};
+
+    @SuppressWarnings("unchecked")
+    private static Method getMethod(Class containingClass, String name, Class... parameterTypes)
+    {
+        try
+        {
+            return containingClass.getMethod(name, parameterTypes);
+        } catch (NoSuchMethodException ex)
+        {
+            throw new IllegalArgumentException(ex);
+        }
+    }
+
+    private static MethodDescription getMethodDescription(Class containingClass, String name, Class... parameterTypes)
+    {
+        return new MethodDescription(getMethod(containingClass, name, parameterTypes));
+    }
+
+    private final AnnotationProvider nullAnnotationProvider = new NullAnnotationProvider();
+
+    /**
+     * How are null values in intermdiate terms to be handled?
+     */
+    private enum NullHandling
+    {
+        /**
+         * Add code to check for null and throw exception if null.
+         */
+        FORBID,
+
+        /**
+         * Add code to check for null and short-circuit (i.e., the "?."
+         * safe-dereference operator)
+         */
+        ALLOW
+    }
+
+    /**
+     * One term in an expression. Expressions start with some root type and each term advances
+     * to a new type.
+     */
+    private class Term
+    {
+        /**
+         * The generic type of the term.
+         */
+        final Type type;
+
+        final Class genericType;
+
+        /**
+         * Describes the term, for use in error messages.
+         */
+        final String description;
+
+        final AnnotationProvider annotationProvider;
+
+        /**
+         * Callback that will implement the term.
+         */
+        final InstructionBuilderCallback callback;
+
+        Term(Type type, Class genericType, String description, AnnotationProvider annotationProvider,
+             InstructionBuilderCallback callback)
+        {
+            this.type = type;
+            this.genericType = genericType;
+            this.description = description;
+            this.annotationProvider = annotationProvider;
+            this.callback = callback;
+        }
+
+        Term(Type type, String description, AnnotationProvider annotationProvider, InstructionBuilderCallback callback)
+        {
+            this(type, GenericsUtils.asClass(type), description, annotationProvider, callback);
+        }
+
+        Term(Type type, String description, InstructionBuilderCallback callback)
+        {
+            this(type, description, null, callback);
+        }
+
+        /**
+         * Returns a clone of this Term with a new callback.
+         */
+        Term withCallback(InstructionBuilderCallback newCallback)
+        {
+            return new Term(type, genericType, description, annotationProvider, newCallback);
+        }
+    }
+
+    private final PropertyAccess access;
+
+    private final PlasticProxyFactory proxyFactory;
+
+    private final TypeCoercer typeCoercer;
+
+    private final StringInterner interner;
+
+    /**
+     * Keyed on combination of root class and expression.
+     */
+    private final Map<MultiKey, PropertyConduit> cache = CollectionFactory.newConcurrentMap();
+
+    private final Invariant invariantAnnotation = new Invariant()
+    {
+        public Class<? extends Annotation> annotationType()
+        {
+            return Invariant.class;
+        }
+    };
+
+    private final AnnotationProvider invariantAnnotationProvider = new AnnotationProvider()
+    {
+        public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+        {
+            if (annotationClass == Invariant.class)
+                return annotationClass.cast(invariantAnnotation);
+
+            return null;
+        }
+    };
+
+    private final PropertyConduit literalTrue;
+
+    private final PropertyConduit literalFalse;
+
+    private final PropertyConduit literalNull;
+
+    private final PropertyConduitDelegate sharedDelegate;
+
+    /**
+     * Encapsulates the process of building a PropertyConduit instance from an
+     * expression, as an {@link PlasticClassTransformer}.
+     */
+    class PropertyConduitBuilder implements PlasticClassTransformer
+    {
+        private final Class rootType;
+
+        private final String expression;
+
+        private final Tree tree;
+
+        private Class conduitPropertyType;
+
+        private Type conduitPropertyGenericType;
+
+        private String conduitPropertyName;
+
+        private AnnotationProvider annotationProvider = nullAnnotationProvider;
+
+        private PlasticField delegateField;
+
+        private PlasticClass plasticClass;
+
+        private PlasticMethod getRootMethod, navMethod;
+
+        PropertyConduitBuilder(Class rootType, String expression, Tree tree)
+        {
+            this.rootType = rootType;
+            this.expression = expression;
+            this.tree = tree;
+        }
+
+        public void transform(PlasticClass plasticClass)
+        {
+            this.plasticClass = plasticClass;
+
+            // Create the various methods; also determine the conduit's property type, property name and identify
+            // the annotation provider.
+
+            implementNavMethodAndAccessors();
+
+            implementOtherMethods();
+
+            plasticClass.addToString(String.format("PropertyConduit[%s %s]", rootType.getName(), expression));
+        }
+
+        private void implementOtherMethods()
+        {
+            PlasticField annotationProviderField = plasticClass.introduceField(AnnotationProvider.class,
+                    "annotationProvider").inject(annotationProvider);
+
+            plasticClass.introduceMethod(ConduitMethods.GET_ANNOTATION).delegateTo(annotationProviderField);
+
+            plasticClass.introduceMethod(ConduitMethods.GET_PROPERTY_NAME, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    builder.loadConstant(conduitPropertyName).returnResult();
+                }
+            });
+
+            final PlasticField propertyTypeField = plasticClass.introduceField(Class.class, "propertyType").inject(
+                    conduitPropertyType);
+
+            plasticClass.introduceMethod(ConduitMethods.GET_PROPERTY_TYPE, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    builder.loadThis().getField(propertyTypeField).returnResult();
+                }
+            });
+
+            final PlasticField propertyGenericTypeField = plasticClass.introduceField(Type.class, "propertyGenericType").inject(
+                    conduitPropertyGenericType);
+
+            plasticClass.introduceMethod(ConduitMethods.GET_PROPERTY_GENERIC_TYPE, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    builder.loadThis().getField(propertyGenericTypeField).returnResult();
+                }
+            });
+        }
+
+        /**
+         * Creates a method that does a conversion from Object to the expected root type, with
+         * a null check.
+         */
+        private void implementGetRoot()
+        {
+            getRootMethod = plasticClass.introducePrivateMethod(PlasticUtils.toTypeName(rootType), "getRoot",
+                    SINGLE_OBJECT_ARGUMENT, null);
+
+            getRootMethod.changeImplementation(new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    builder.loadArgument(0).dupe().when(Condition.NULL, new InstructionBuilderCallback()
+                    {
+                        public void doBuild(InstructionBuilder builder)
+                        {
+                            builder.throwException(NullPointerException.class,
+                                    String.format("Root object of property expression '%s' is null.", expression));
+                        }
+                    });
+
+                    builder.checkcast(rootType).returnResult();
+                }
+            });
+        }
+
+        private boolean isLeaf(Tree node)
+        {
+            int type = node.getType();
+
+            return type != DEREF && type != SAFEDEREF;
+        }
+
+        private void implementNavMethodAndAccessors()
+        {
+            implementGetRoot();
+
+            // First, create the navigate method.
+
+            final List<InstructionBuilderCallback> callbacks = CollectionFactory.newList();
+
+            Type activeType = rootType;
+
+            Tree node = tree;
+
+            while (!isLeaf(node))
+            {
+                Term term = analyzeDerefNode(activeType, node);
+
+                callbacks.add(term.callback);
+
+                activeType = term.type;
+
+                // Second term is the continuation, possibly another chained
+                // DEREF, etc.
+                node = node.getChild(1);
+            }
+
+            Class activeClass = GenericsUtils.asClass(activeType);
+
+            if (callbacks.isEmpty())
+            {
+                navMethod = getRootMethod;
+            } else
+            {
+                navMethod = plasticClass.introducePrivateMethod(PlasticUtils.toTypeName(activeClass), "navigate",
+                        SINGLE_OBJECT_ARGUMENT, null);
+
+                navMethod.changeImplementation(new InstructionBuilderCallback()
+                {
+                    public void doBuild(InstructionBuilder builder)
+                    {
+                        builder.loadThis().loadArgument(0).invokeVirtual(getRootMethod);
+
+                        for (InstructionBuilderCallback callback : callbacks)
+                        {
+                            callback.doBuild(builder);
+                        }
+
+                        builder.returnResult();
+                    }
+                });
+            }
+
+            implementAccessors(activeType, node);
+        }
+
+        private void implementAccessors(Type activeType, Tree node)
+        {
+            switch (node.getType())
+            {
+                case IDENTIFIER:
+
+                    implementPropertyAccessors(activeType, node);
+
+                    return;
+
+                case INVOKE:
+
+                    // So, at this point, we have the navigation method written
+                    // and it covers all but the terminal
+                    // de-reference. node is an IDENTIFIER or INVOKE. We're
+                    // ready to use the navigation
+                    // method to implement get() and set().
+
+                    implementMethodAccessors(activeType, node);
+
+                    return;
+
+                case RANGEOP:
+
+                    // As currently implemented, RANGEOP can only appear as the
+                    // top level, which
+                    // means we didn't need the navigate method after all.
+
+                    implementRangeOpGetter(node);
+                    implementNoOpSetter();
+
+                    conduitPropertyType = IntegerRange.class;
+                    conduitPropertyGenericType = IntegerRange.class;
+
+                    return;
+
+                case LIST:
+
+                    implementListGetter(node);
+                    implementNoOpSetter();
+
+                    conduitPropertyType = List.class;
+                    conduitPropertyGenericType = List.class;
+                    
+                    return;
+
+                case MAP:
+                    implementMapGetter(node);
+                    implementNoOpSetter();
+
+                    conduitPropertyType = Map.class;
+                    conduitPropertyGenericType = Map.class;
+
+                    return;
+
+
+                case NOT:
+                    implementNotOpGetter(node);
+                    implementNoOpSetter();
+
+                    conduitPropertyType = boolean.class;
+                    conduitPropertyGenericType = boolean.class;
+
+                    return;
+
+                default:
+                    throw unexpectedNodeType(node, IDENTIFIER, INVOKE, RANGEOP, LIST, NOT);
+            }
+        }
+
+        public void implementMethodAccessors(final Type activeType, final Tree invokeNode)
+        {
+            final Term term = buildInvokeTerm(activeType, invokeNode);
+
+            implementNoOpSetter();
+
+            conduitPropertyName = term.description;
+            conduitPropertyType = term.genericType;
+            conduitPropertyGenericType = term.genericType;
+            annotationProvider = term.annotationProvider;
+
+            plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    invokeNavigateMethod(builder);
+
+                    term.callback.doBuild(builder);
+
+                    boxIfPrimitive(builder, conduitPropertyType);
+
+                    builder.returnResult();
+                }
+            });
+
+            implementNoOpSetter();
+        }
+
+        public void implementPropertyAccessors(Type activeType, Tree identifierNode)
+        {
+            String propertyName = identifierNode.getText();
+
+            PropertyAdapter adapter = findPropertyAdapter(activeType, propertyName);
+
+            conduitPropertyName = propertyName;
+            conduitPropertyType = adapter.getType();
+            conduitPropertyGenericType = getGenericType(adapter);
+            annotationProvider = adapter;
+
+            implementGetter(adapter);
+            implementSetter(adapter);
+        }
+
+        private Type getGenericType(PropertyAdapter adapter)
+        {
+        	Type genericType = null;
+        	if (adapter.getField() != null)
+        	{
+        		genericType = adapter.getField().getGenericType();
+        	}
+        	else if (adapter.getReadMethod() != null)
+        	{
+        		genericType = adapter.getReadMethod().getGenericReturnType(); 
+        	}
+        	else if (adapter.getWriteMethod() != null)
+        	{
+        		genericType = adapter.getWriteMethod().getGenericParameterTypes()[0];
+        	}
+        	else
+        	{
+        		throw new RuntimeException("Could not find accessor for property " + adapter.getName());
+        	}
+        	
+        	return genericType == null ? adapter.getType() : genericType;
+		}
+
+		private void implementSetter(PropertyAdapter adapter)
+        {
+            if (adapter.getWriteMethod() != null)
+            {
+                implementSetter(adapter.getWriteMethod());
+                return;
+            }
+
+            if (adapter.getField() != null && adapter.isUpdate())
+            {
+                implementSetter(adapter.getField());
+                return;
+            }
+
+            implementNoOpMethod(ConduitMethods.SET, "Expression '%s' for class %s is read-only.", expression,
+                    rootType.getName());
+        }
+
+        private boolean isStatic(Member member)
+        {
+            return Modifier.isStatic(member.getModifiers());
+        }
+
+        private void implementSetter(final Field field)
+        {
+            if (isStatic(field))
+            {
+                plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback()
+                {
+                    public void doBuild(InstructionBuilder builder)
+                    {
+                        builder.loadArgument(1).castOrUnbox(PlasticUtils.toTypeName(field.getType()));
+
+                        builder.putStaticField(field.getDeclaringClass().getName(), field.getName(), field.getType());
+
+                        builder.returnResult();
+                    }
+                });
+
+                return;
+            }
+
+            plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    invokeNavigateMethod(builder);
+
+                    builder.loadArgument(1).castOrUnbox(PlasticUtils.toTypeName(field.getType()));
+
+                    builder.putField(field.getDeclaringClass().getName(), field.getName(), field.getType());
+
+                    builder.returnResult();
+                }
+            });
+        }
+
+        private void implementSetter(final Method writeMethod)
+        {
+            plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    invokeNavigateMethod(builder);
+
+                    Class propertyType = writeMethod.getParameterTypes()[0];
+                    String propertyTypeName = PlasticUtils.toTypeName(propertyType);
+
+                    builder.loadArgument(1).castOrUnbox(propertyTypeName);
+
+                    builder.invoke(writeMethod);
+
+                    builder.returnResult();
+                }
+            });
+        }
+
+        private void implementGetter(PropertyAdapter adapter)
+        {
+            if (adapter.getReadMethod() != null)
+            {
+                implementGetter(adapter.getReadMethod());
+                return;
+            }
+
+            if (adapter.getField() != null)
+            {
+                implementGetter(adapter.getField());
+                return;
+            }
+
+            implementNoOpMethod(ConduitMethods.GET, "Expression '%s' for class %s is write-only.", expression,
+                    rootType.getName());
+        }
+
+        private void implementGetter(final Field field)
+        {
+            if (isStatic(field))
+            {
+                plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+                {
+                    public void doBuild(InstructionBuilder builder)
+                    {
+                        builder.getStaticField(field.getDeclaringClass().getName(), field.getName(), field.getType());
+
+                        // Cast not necessary here since the return type of get() is Object
+
+                        boxIfPrimitive(builder, field.getType());
+
+                        builder.returnResult();
+                    }
+                });
+
+                return;
+            }
+
+            plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    invokeNavigateMethod(builder);
+
+                    builder.getField(field.getDeclaringClass().getName(), field.getName(), field.getType());
+
+                    // Cast not necessary here since the return type of get() is Object
+
+                    boxIfPrimitive(builder, field.getType());
+
+                    builder.returnResult();
+                }
+            });
+        }
+
+        private void implementGetter(final Method readMethod)
+        {
+            plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    invokeNavigateMethod(builder);
+
+                    invokeMethod(builder, readMethod, null, 0);
+
+                    boxIfPrimitive(builder, conduitPropertyType);
+
+                    builder.returnResult();
+                }
+            });
+        }
+
+        private void implementRangeOpGetter(final Tree rangeNode)
+        {
+            plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    // Put the delegate on top of the stack
+
+                    builder.loadThis().getField(getDelegateField());
+
+                    invokeMethod(builder, DelegateMethods.RANGE, rangeNode, 0);
+
+                    builder.returnResult();
+                }
+            });
+        }
+
+        /**
+         * @param node
+         *         subexpression to invert
+         */
+        private void implementNotOpGetter(final Tree node)
+        {
+            // Implement get() as navigate, then do a method invocation based on node
+            // then, then pass (wrapped) result to delegate.invert()
+
+            plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    Type expressionType = implementNotExpression(builder, node);
+
+                    // Yes, we know this will always be the case, for now.
+
+                    boxIfPrimitive(builder, expressionType);
+
+                    builder.returnResult();
+                }
+            });
+        }
+
+        /**
+         * The first part of any implementation of get() or set(): invoke the navigation method
+         * and if the result is null, return immediately.
+         */
+        private void invokeNavigateMethod(InstructionBuilder builder)
+        {
+            builder.loadThis().loadArgument(0).invokeVirtual(navMethod);
+
+            builder.dupe().when(Condition.NULL, RETURN_NULL);
+        }
+
+        /**
+         * Uses the builder to add instructions for a subexpression.
+         *
+         * @param builder
+         *         used to add instructions
+         * @param activeType
+         *         type of value on top of the stack when this code will execute, or null if no value on stack
+         * @param node
+         *         defines the expression
+         * @return the expression type
+         */
+        private Type implementSubexpression(InstructionBuilder builder, Type activeType, Tree node)
+        {
+            Term term;
+
+            while (true)
+            {
+                switch (node.getType())
+                {
+                    case IDENTIFIER:
+                    case INVOKE:
+
+                        if (activeType == null)
+                        {
+                            invokeGetRootMethod(builder);
+
+                            activeType = rootType;
+                        }
+
+                        term = buildTerm(activeType, node);
+
+                        term.callback.doBuild(builder);
+
+                        return term.type;
+
+                    case INTEGER:
+
+                        builder.loadConstant(new Long(node.getText()));
+
+                        return long.class;
+
+                    case DECIMAL:
+
+                        builder.loadConstant(new Double(node.getText()));
+
+                        return double.class;
+
+                    case STRING:
+
+                        builder.loadConstant(node.getText());
+
+                        return String.class;
+
+                    case DEREF:
+                    case SAFEDEREF:
+
+                        if (activeType == null)
+                        {
+                            invokeGetRootMethod(builder);
+
+                            activeType = rootType;
+                        }
+
+                        term = analyzeDerefNode(activeType, node);
+
+                        term.callback.doBuild(builder);
+
+                        activeType = GenericsUtils.asClass(term.type);
+
+                        node = node.getChild(1);
+
+                        break;
+
+                    case TRUE:
+                    case FALSE:
+
+                        builder.loadConstant(node.getType() == TRUE ? 1 : 0);
+
+                        return boolean.class;
+
+                    case LIST:
+
+                        return implementListConstructor(builder, node);
+
+                    case MAP:
+                        return implementMapConstructor(builder, node);
+
+                    case NOT:
+
+                        return implementNotExpression(builder, node);
+
+                    case THIS:
+
+                        invokeGetRootMethod(builder);
+
+                        return rootType;
+
+                    case NULL:
+
+                        builder.loadNull();
+
+                        return Void.class;
+
+                    default:
+                        throw unexpectedNodeType(node, TRUE, FALSE, INTEGER, DECIMAL, STRING, DEREF, SAFEDEREF,
+                                IDENTIFIER, INVOKE, LIST, NOT, THIS, NULL);
+                }
+            }
+        }
+
+        public void invokeGetRootMethod(InstructionBuilder builder)
+        {
+            builder.loadThis().loadArgument(0).invokeVirtual(getRootMethod);
+        }
+
+        private void implementListGetter(final Tree listNode)
+        {
+            plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    implementListConstructor(builder, listNode);
+
+                    builder.returnResult();
+                }
+            });
+        }
+
+        private Type implementListConstructor(InstructionBuilder builder, Tree listNode)
+        {
+            // First, create an empty instance of ArrayList
+
+            int count = listNode.getChildCount();
+
+            builder.newInstance(ArrayList.class);
+            builder.dupe().loadConstant(count).invokeConstructor(ArrayList.class, int.class);
+
+            for (int i = 0; i < count; i++)
+            {
+                builder.dupe(); // the ArrayList
+
+                Type expressionType = implementSubexpression(builder, null, listNode.getChild(i));
+
+                boxIfPrimitive(builder, GenericsUtils.asClass(expressionType));
+
+                // Add the value to the array, then pop off the returned boolean
+                builder.invoke(ArrayListMethods.ADD).pop();
+            }
+
+            return ArrayList.class;
+        }
+
+        private void implementMapGetter(final Tree mapNode)
+        {
+            plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    implementMapConstructor(builder, mapNode);
+
+                    builder.returnResult();
+                }
+            });
+        }
+
+        private Type implementMapConstructor(InstructionBuilder builder, Tree mapNode)
+        {
+            int count = mapNode.getChildCount();
+            builder.newInstance(HashMap.class);
+            builder.dupe().loadConstant(count).invokeConstructor(HashMap.class, int.class);
+
+            for (int i = 0; i < count; i += 2)
+            {
+                builder.dupe();
+
+                //build the key:
+                Type keyType = implementSubexpression(builder, null, mapNode.getChild(i));
+                boxIfPrimitive(builder, GenericsUtils.asClass(keyType));
+
+                //and the value:
+                Type valueType = implementSubexpression(builder, null, mapNode.getChild(i + 1));
+                boxIfPrimitive(builder, GenericsUtils.asClass(valueType));
+
+                //put the value into the array, then pop off the returned object.
+                builder.invoke(HashMapMethods.PUT).pop();
+
+            }
+
+            return HashMap.class;
+        }
+
+
+        private void implementNoOpSetter()
+        {
+            implementNoOpMethod(ConduitMethods.SET, "Expression '%s' for class %s is read-only.", expression,
+                    rootType.getName());
+        }
+
+        public void implementNoOpMethod(MethodDescription method, String format, Object... arguments)
+        {
+            final String message = String.format(format, arguments);
+
+            plasticClass.introduceMethod(method).changeImplementation(new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    builder.throwException(RuntimeException.class, message);
+                }
+            });
+        }
+
+        /**
+         * Invokes a method that may take parameters. The children of the invokeNode are subexpressions
+         * to be evaluated, and potentially coerced, so that they may be passed to the method.
+         *
+         * @param builder
+         *         constructs code
+         * @param method
+         *         method to invoke
+         * @param node
+         *         INVOKE or RANGEOP node
+         * @param childOffset
+         *         offset within the node to the first child expression (1 in an INVOKE node because the
+         *         first child is the method name, 0 in a RANGEOP node)
+         */
+        private void invokeMethod(InstructionBuilder builder, Method method, Tree node, int childOffset)
+        {
+            // We start with the target object for the method on top of the stack.
+            // Next, we have to push each method parameter, which may include boxing/deboxing
+            // and coercion. Once the code is in good shape, there's a lot of room to optimize
+            // the bytecode (a bit too much boxing/deboxing occurs, as well as some unnecessary
+            // trips through TypeCoercer). We might also want to have a local variable to store
+            // the root object (result of getRoot()).
+
+            Class[] parameterTypes = method.getParameterTypes();
+
+            for (int i = 0; i < parameterTypes.length; i++)
+            {
+                Type expressionType = implementSubexpression(builder, null, node.getChild(i + childOffset));
+
+                // The value left on the stack is not primitive, and expressionType represents
+                // its real type.
+
+                Class parameterType = parameterTypes[i];
+
+                if (!parameterType.isAssignableFrom(GenericsUtils.asClass(expressionType)))
+                {
+                    boxIfPrimitive(builder, expressionType);
+
+                    builder.loadThis().getField(getDelegateField());
+                    builder.swap().loadTypeConstant(PlasticUtils.toWrapperType(parameterType));
+                    builder.invoke(DelegateMethods.COERCE);
+
+                    if (parameterType.isPrimitive())
+                    {
+                        builder.castOrUnbox(parameterType.getName());
+                    } else
+                    {
+                        builder.checkcast(parameterType);
+                    }
+                }
+
+                // And that should leave an object of the correct type on the stack,
+                // ready for the method invocation.
+            }
+
+            // Now the target object and all parameters are in place.
+
+            builder.invoke(method.getDeclaringClass(), method.getReturnType(), method.getName(),
+                    method.getParameterTypes());
+        }
+
+        /**
+         * Analyzes a DEREF or SAFEDEREF node, proving back a term that identifies its type and provides a callback to
+         * peform the dereference.
+         *
+         * @return a term indicating the type of the expression to this point, and a {@link InstructionBuilderCallback}
+         *         to advance the evaluation of the expression form the previous value to the current
+         */
+        private Term analyzeDerefNode(Type activeType, Tree node)
+        {
+            // The first child is the term.
+
+            Tree term = node.getChild(0);
+
+            boolean allowNull = node.getType() == SAFEDEREF;
+
+            return buildTerm(activeType, term, allowNull ? NullHandling.ALLOW : NullHandling.FORBID);
+        }
+
+        private Term buildTerm(Type activeType, Tree term, final NullHandling nullHandling)
+        {
+            assertNodeType(term, IDENTIFIER, INVOKE);
+
+            final Term simpleTerm = buildTerm(activeType, term);
+
+            if (simpleTerm.genericType.isPrimitive())
+                return simpleTerm;
+
+            return simpleTerm.withCallback(new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    simpleTerm.callback.doBuild(builder);
+
+                    builder.dupe().when(Condition.NULL, new InstructionBuilderCallback()
+                    {
+                        public void doBuild(InstructionBuilder builder)
+                        {
+                            switch (nullHandling)
+                            {
+                                // It is necessary to load a null onto the stack (even if there's already one
+                                // there) because of the verifier. It sees the return when the stack contains an
+                                // intermediate value (along the navigation chain) and thinks the method is
+                                // returning a value of the wrong type.
+
+                                case ALLOW:
+                                    builder.loadNull().returnResult();
+
+                                case FORBID:
+
+                                    builder.loadConstant(simpleTerm.description);
+                                    builder.loadConstant(expression);
+                                    builder.loadArgument(0);
+
+                                    builder.invokeStatic(PropertyConduitSourceImpl.class, NullPointerException.class,
+                                            "nullTerm", String.class, String.class, Object.class);
+                                    builder.throwException();
+
+                                    break;
+
+                            }
+                        }
+                    });
+                }
+            });
+        }
+
+        private void assertNodeType(Tree node, int... expected)
+        {
+            int type = node.getType();
+
+            for (int e : expected)
+            {
+                if (type == e)
+                    return;
+            }
+
+            throw unexpectedNodeType(node, expected);
+        }
+
+        private RuntimeException unexpectedNodeType(Tree node, int... expected)
+        {
+            List<String> tokenNames = CollectionFactory.newList();
+
+            for (int i = 0; i < expected.length; i++)
+                tokenNames.add(PropertyExpressionParser.tokenNames[expected[i]]);
+
+            String message = String.format("Node %s was type %s, but was expected to be (one of) %s.",
+                    node.toStringTree(), PropertyExpressionParser.tokenNames[node.getType()],
+                    InternalUtils.joinSorted(tokenNames));
+
+            return new RuntimeException(message);
+        }
+
+        private Term buildTerm(Type activeType, Tree termNode)
+        {
+            switch (termNode.getType())
+            {
+                case INVOKE:
+
+                    return buildInvokeTerm(activeType, termNode);
+
+                case IDENTIFIER:
+
+                    return buildPropertyAccessTerm(activeType, termNode);
+
+                default:
+                    throw unexpectedNodeType(termNode, INVOKE, IDENTIFIER);
+            }
+        }
+
+        private Term buildPropertyAccessTerm(Type activeType, Tree termNode)
+        {
+            String propertyName = termNode.getText();
+
+            PropertyAdapter adapter = findPropertyAdapter(activeType, propertyName);
+
+            // Prefer the accessor over the field
+
+            if (adapter.getReadMethod() != null)
+            {
+                return buildGetterMethodAccessTerm(activeType, propertyName,
+                        adapter.getReadMethod());
+            }
+
+            if (adapter.getField() != null)
+            {
+                return buildPublicFieldAccessTerm(activeType, propertyName,
+                        adapter.getField());
+            }
+
+            throw new RuntimeException(String.format(
+                    "Property '%s' of class %s is not readable (it has no read accessor method).", adapter.getName(),
+                    adapter.getBeanType().getName()));
+        }
+
+        public PropertyAdapter findPropertyAdapter(Type activeType, String propertyName)
+        {
+            Class activeClass = GenericsUtils.asClass(activeType);
+
+            ClassPropertyAdapter classAdapter = access.getAdapter(activeClass);
+            PropertyAdapter adapter = classAdapter.getPropertyAdapter(propertyName);
+
+            if (adapter == null)
+            {
+                final List<String> names = classAdapter.getPropertyNames();
+                final String className = activeClass.getName();
+                throw new UnknownValueException(String.format(
+                        "Class %s does not contain a property (or public field) named '%s'.", className, propertyName),
+                        new AvailableValues("Properties (and public fields)", names));
+            }
+            return adapter;
+        }
+
+        private Term buildGetterMethodAccessTerm(final Type activeType, String propertyName, final Method readMethod)
+        {
+            Type returnType = GenericsUtils.extractActualType(activeType, readMethod);
+
+            return new Term(returnType, propertyName, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    invokeMethod(builder, readMethod, null, 0);
+
+                    Type genericType = GenericsUtils.extractActualType(activeType, readMethod);
+
+                    castToGenericType(builder, readMethod.getReturnType(), genericType);
+                }
+            });
+        }
+
+        private Term buildPublicFieldAccessTerm(Type activeType, String propertyName, final Field field)
+        {
+            final Type fieldType = GenericsUtils.extractActualType(activeType, field);
+
+            return new Term(fieldType, propertyName, new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    Class rawFieldType = field.getType();
+
+                    String rawTypeName = PlasticUtils.toTypeName(rawFieldType);
+                    String containingClassName = field.getDeclaringClass().getName();
+                    String fieldName = field.getName();
+
+                    if (isStatic(field))
+                    {
+                        // We've gone to the trouble of loading the root object, or navigated to some other object,
+                        // but we don't need or want the instance, since it's a static field we're accessing.
+                        // Ideally, we would optimize this, and only generate and invoke the getRoot() and nav() methods as needed, but
+                        // access to public fields is relatively rare, and the cost is just the unused bytecode.
+
+                        builder.pop();
+
+                        builder.getStaticField(containingClassName, fieldName, rawTypeName);
+
+                    } else
+                    {
+                        builder.getField(containingClassName, fieldName, rawTypeName);
+                    }
+
+                    castToGenericType(builder, rawFieldType, fieldType);
+                }
+
+            });
+        }
+
+        /**
+         * Casts the results of a field read or method invocation based on generic information.
+         *
+         * @param builder
+         *         used to add instructions
+         * @param rawType
+         *         the simple type (often Object) of the field (or method return type)
+         * @param genericType
+         *         the generic Type, from which parameterizations can be determined
+         */
+        private void castToGenericType(InstructionBuilder builder, Class rawType, final Type genericType)
+        {
+            if (!genericType.equals(rawType))
+            {
+                Class castType = GenericsUtils.asClass(genericType);
+                builder.checkcast(castType);
+            }
+        }
+
+        private Term buildInvokeTerm(final Type activeType, final Tree invokeNode)
+        {
+            String methodName = invokeNode.getChild(0).getText();
+
+            int parameterCount = invokeNode.getChildCount() - 1;
+
+            Class activeClass = GenericsUtils.asClass(activeType);
+
+            final Method method = findMethod(activeClass, methodName, parameterCount);
+
+            if (method.getReturnType().equals(void.class))
+                throw new RuntimeException(String.format("Method %s.%s() returns void.", activeClass.getName(),
+                        methodName));
+
+            Type returnType = GenericsUtils.extractActualType(activeType, method);
+
+            return new Term(returnType, toUniqueId(method), InternalUtils.toAnnotationProvider(method), new InstructionBuilderCallback()
+            {
+                public void doBuild(InstructionBuilder builder)
+                {
+                    invokeMethod(builder, method, invokeNode, 1);
+
+                    Type genericType = GenericsUtils.extractActualType(activeType, method);
+
+                    castToGenericType(builder, method.getReturnType(), genericType);
+                }
+            }
+            );
+        }
+
+        private Method findMethod(Class activeType, String methodName, int parameterCount)
+        {
+            Class searchType = activeType;
+
+            while (true)
+            {
+
+                for (Method method : searchType.getMethods())
+                {
+                    if (method.getParameterTypes().length == parameterCount
+                            && method.getName().equalsIgnoreCase(methodName))
+                        return method;
+                }
+
+                // TAP5-330
+                if (searchType != Object.class)
+                {
+                    searchType = Object.class;
+                } else
+                {
+                    throw new RuntimeException(String.format("Class %s does not contain a public method named '%s()'.",
+                            activeType.getName(), methodName));
+                }
+            }
+        }
+
+        public void boxIfPrimitive(InstructionBuilder builder, Type termType)
+        {
+            boxIfPrimitive(builder, GenericsUtils.asClass(termType));
+        }
+
+        public void boxIfPrimitive(InstructionBuilder builder, Class termType)
+        {
+            if (termType.isPrimitive())
+                builder.boxPrimitive(termType.getName());
+        }
+
+        public Class implementNotExpression(InstructionBuilder builder, final Tree notNode)
+        {
+            Type expressionType = implementSubexpression(builder, null, notNode.getChild(0));
+
+            boxIfPrimitive(builder, expressionType);
+
+            // Now invoke the delegate invert() method
+
+            builder.loadThis().getField(getDelegateField());
+
+            builder.swap().invoke(DelegateMethods.INVERT);
+
+            return boolean.class;
+        }
+
+        /**
+         * Defer creation of the delegate field unless actually needed.
+         */
+        private PlasticField getDelegateField()
+        {
+            if (delegateField == null)
+                delegateField = plasticClass.introduceField(PropertyConduitDelegate.class, "delegate").inject(
+                        sharedDelegate);
+
+            return delegateField;
+        }
+    }
+
+    public PropertyConduitSourceImpl(PropertyAccess access, @ComponentLayer
+    PlasticProxyFactory proxyFactory, TypeCoercer typeCoercer, StringInterner interner)
+    {
+        this.access = access;
+        this.proxyFactory = proxyFactory;
+        this.typeCoercer = typeCoercer;
+        this.interner = interner;
+
+        literalTrue = createLiteralConduit(Boolean.class, true);
+        literalFalse = createLiteralConduit(Boolean.class, false);
+        literalNull = createLiteralConduit(Void.class, null);
+
+        sharedDelegate = new PropertyConduitDelegate(typeCoercer);
+    }
+
+    @PostInjection
+    public void listenForInvalidations(@ComponentClasses InvalidationEventHub hub)
+    {
+        hub.clearOnInvalidation(cache);
+    }
+
+
+    public PropertyConduit create(Class rootClass, String expression)
+    {
+        assert rootClass != null;
+        assert InternalUtils.isNonBlank(expression);
+
+        MultiKey key = new MultiKey(rootClass, expression);
+
+        PropertyConduit result = cache.get(key);
+
+        if (result == null)
+        {
+            result = build(rootClass, expression);
+            cache.put(key, result);
+        }
+
+        return result;
+    }
+
+    /**
+     * Builds a subclass of {@link PropertyConduitDelegate} that implements the
+     * get() and set() methods and overrides the
+     * constructor. In a worst-case race condition, we may build two (or more)
+     * conduits for the same
+     * rootClass/expression, and it will get sorted out when the conduit is
+     * stored into the cache.
+     *
+     * @param rootClass
+     *         class of root object for expression evaluation
+     * @param expression
+     *         expression to be evaluated
+     * @return the conduit
+     */
+    private PropertyConduit build(final Class rootClass, String expression)
+    {
+        Tree tree = parse(expression);
+
+        try
+        {
+            switch (tree.getType())
+            {
+                case TRUE:
+
+                    return literalTrue;
+
+                case FALSE:
+
+                    return literalFalse;
+
+                case NULL:
+
+                    return literalNull;
+
+                case INTEGER:
+
+                    // Leading '+' may screw this up.
+                    // TODO: Singleton instance for "0", maybe "1"?
+
+                    return createLiteralConduit(Long.class, new Long(tree.getText()));
+
+                case DECIMAL:
+
+                    // Leading '+' may screw this up.
+                    // TODO: Singleton instance for "0.0"?
+
+                    return createLiteralConduit(Double.class, new Double(tree.getText()));
+
+                case STRING:
+
+                    return createLiteralConduit(String.class, tree.getText());
+
+                case RANGEOP:
+
+                    Tree fromNode = tree.getChild(0);
+                    Tree toNode = tree.getChild(1);
+
+                    // If the range is defined as integers (not properties, etc.)
+                    // then it is possible to calculate the value here, once, and not
+                    // build a new class.
+
+                    if (fromNode.getType() != INTEGER || toNode.getType() != INTEGER)
+                        break;
+
+                    int from = Integer.parseInt(fromNode.getText());
+                    int to = Integer.parseInt(toNode.getText());
+
+                    IntegerRange ir = new IntegerRange(from, to);
+
+                    return createLiteralConduit(IntegerRange.class, ir);
+
+                case THIS:
+
+                    return createLiteralThisPropertyConduit(rootClass);
+
+                default:
+                    break;
+            }
+
+            return proxyFactory.createProxy(InternalPropertyConduit.class,
+                    new PropertyConduitBuilder(rootClass, expression, tree)).newInstance();
+        } catch (Exception ex)
+        {
+            throw new PropertyExpressionException(String.format("Exception generating conduit for expression '%s': %s",
+                    expression, ExceptionUtils.toMessage(ex)), expression, ex);
+        }
+    }
+
+    private PropertyConduit createLiteralThisPropertyConduit(final Class rootClass)
+    {
+        return new PropertyConduit()
+        {
+            public Object get(Object instance)
+            {
+                return instance;
+            }
+
+            public void set(Object instance, Object value)
+            {
+                throw new RuntimeException("Literal values are not updateable.");
+            }
+
+            public Class getPropertyType()
+            {
+                return rootClass;
+            }
+            
+            public Type getPropertyGenericType()
+            {
+            	return rootClass;
+            }
+
+            public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+            {
+                return invariantAnnotationProvider.getAnnotation(annotationClass);
+            }
+        };
+    }
+
+    private <T> PropertyConduit createLiteralConduit(Class<T> type, T value)
+    {
+        return new LiteralPropertyConduit(typeCoercer, type, invariantAnnotationProvider, interner.format(
+                "LiteralPropertyConduit[%s]", value), value);
+    }
+
+    private Tree parse(String expression)
+    {
+        InputStream is = new ByteArrayInputStream(expression.getBytes());
+
+        ANTLRInputStream ais;
+
+        try
+        {
+            ais = new ANTLRInputStream(is);
+        } catch (IOException ex)
+        {
+            throw new RuntimeException(ex);
+        }
+
+        PropertyExpressionLexer lexer = new PropertyExpressionLexer(ais);
+
+        CommonTokenStream tokens = new CommonTokenStream(lexer);
+
+        PropertyExpressionParser parser = new PropertyExpressionParser(tokens);
+
+        try
+        {
+            return (Tree) parser.start().getTree();
+        } catch (Exception ex)
+        {
+            throw new RuntimeException(String.format("Error parsing property expression '%s': %s.", expression,
+                    ex.getMessage()), ex);
+        }
+    }
+
+    /**
+     * May be invoked from fabricated PropertyConduit instances.
+     */
+    @SuppressWarnings("unused")
+    public static NullPointerException nullTerm(String term, String expression, Object root)
+    {
+        String message = String.format("Property '%s' (within property expression '%s', of %s) is null.", term,
+                expression, root);
+
+        return new NullPointerException(message);
+    }
+
+    private static String toUniqueId(Method method)
+    {
+        StringBuilder builder = new StringBuilder(method.getName()).append("(");
+        String sep = "";
+
+        for (Class parameterType : method.getParameterTypes())
+        {
+            builder.append(sep);
+            builder.append(PlasticUtils.toTypeName(parameterType));
+
+            sep = ",";
+        }
+
+        return builder.append(")").toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/beanmodel/src/main/java/org/apache/tapestry5/services/BeanModelSource.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/services/BeanModelSource.java b/beanmodel/src/main/java/org/apache/tapestry5/services/BeanModelSource.java
new file mode 100644
index 0000000..16b4fca
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/services/BeanModelSource.java
@@ -0,0 +1,70 @@
+// 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.services;
+
+import org.apache.tapestry5.beaneditor.BeanModel;
+import org.apache.tapestry5.ioc.Messages;
+
+/**
+ * Used by a component to create a default {@link org.apache.tapestry5.beaneditor.BeanModel} for a particular bean
+ * class. Also provides support to the model by generating validation information for individual fields.
+ * <p/>
+ * BeanModels are the basis for the {@link org.apache.tapestry5.corelib.components.BeanEditor} and {@link
+ * org.apache.tapestry5.corelib.components.Grid} comopnents.
+ *
+ * @see org.apache.tapestry5.services.PropertyConduitSource
+ */
+public interface BeanModelSource
+{
+    /**
+     * Creates a new model used for editing the indicated bean class. The model will represent all read/write properties
+     * of the bean. The order of properties is determined from the order of the getter methods in the code, and can be
+     * overridden with the {@link org.apache.tapestry5.beaneditor.ReorderProperties} annotation. The labels for the
+     * properties are derived from the property names, but if the component's message catalog has keys of the form
+     * <code>propertyName-label</code>, then those will be used instead.
+     * <p/>
+     * Models are <em>mutable</em>, so they are not cached, a fresh instance is created each time.
+     *
+     * @param beanClass                class of object to be edited
+     * @param filterReadOnlyProperties if true, then properties that are read-only will be skipped (leaving only
+     *                                 read-write properties, appropriate for {@link org.apache.tapestry5.corelib.components.BeanEditForm},
+     *                                 etc.). If false, then both read-only and read-write properties will be included
+     *                                 (appropriate for {@link org.apache.tapestry5.corelib.components.Grid} or {@link
+     *                                 org.apache.tapestry5.corelib.components.BeanDisplay}).
+     * @param messages                 Used to find explicit overrides of
+     * @return a model
+     * @deprecated use {@link #createDisplayModel(Class, org.apache.tapestry5.ioc.Messages)} or {@link
+     *             #createEditModel(Class, org.apache.tapestry5.ioc.Messages)}
+     */
+    <T> BeanModel<T> create(Class<T> beanClass, boolean filterReadOnlyProperties, Messages messages);
+
+    /**
+     * Creates a model for display purposes; this may include properties which are read-only.
+     *
+     * @param beanClass class of object to be edited
+     * @param messages
+     * @return a model containing properties that can be presented to the user
+     */
+    <T> BeanModel<T> createDisplayModel(Class<T> beanClass, Messages messages);
+
+    /**
+     * Creates a model for edit and update purposes, only properties that are fully read-write are included.
+     *
+     * @param beanClass class of object to be edited
+     * @param messages
+     * @return a model containing properties that can be presented to the user
+     */
+    <T> BeanModel<T> createEditModel(Class<T> beanClass, Messages messages);
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/beanmodel/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java b/beanmodel/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java
new file mode 100644
index 0000000..312cd60
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java
@@ -0,0 +1,41 @@
+// Copyright 2007, 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.services;
+
+import org.apache.tapestry5.PropertyConduit;
+
+/**
+ * A source for {@link org.apache.tapestry5.PropertyConduit}s, which can be thought of as a compiled property path
+ * expression. PropertyConduits are the basis of the "prop:" binding factory, thus this service defines the expression
+ * format used by the {@link org.apache.tapestry5.internal.bindings.PropBindingFactory}.
+ */
+public interface PropertyConduitSource
+{
+    /**
+     * Returns a property conduit instance for the given expression. PropertyConduitSource caches the conduits it
+     * returns, so despite the name, this method does not always create a <em>new</em> conduit. The cache is cleared if
+     * a change to component classes is observed.
+     * <p/>
+     * Callers of this method should observe notifications from the {@link org.apache.tapestry5.services.InvalidationEventHub}
+     * for {@link org.apache.tapestry5.services.ComponentClasses} and discard any aquired conduits; failure to do so
+     * will create memory leaks whenever component classes change (the conduits will keep references to the old classes
+     * and classloaders).
+     *
+     * @param rootType   the type of the root object to which the expression is applied
+     * @param expression expression to be evaluated on instances of the root class
+     * @return RuntimeException if the expression is invalid (poorly formed, references non-existent properties, etc.)
+     */
+    PropertyConduit create(Class rootType, String expression);
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/build.gradle
----------------------------------------------------------------------
diff --git a/commons/build.gradle b/commons/build.gradle
new file mode 100644
index 0000000..76850ef
--- /dev/null
+++ b/commons/build.gradle
@@ -0,0 +1,18 @@
+import org.gradle.plugins.ide.idea.model.*
+import t5build.*
+
+description = "Project including common classes for tapestry-core, tapestry-ioc and beanmodel."
+
+//apply plugin: JavaPlugin
+
+buildDir = 'target/gradle-build'
+       
+dependencies {
+	compile project(":plastic")
+	compile project(":tapestry5-annotations")
+}
+
+jar {	
+	manifest {	
+	}
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java b/commons/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java
new file mode 100644
index 0000000..7b2b7ab
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java
@@ -0,0 +1,125 @@
+// Copyright 2006 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.util;
+
+import java.util.Iterator;
+
+/**
+ * Represents a sequence of integer values, either ascending or descending. The sequence is always inclusive (of the
+ * finish value).
+ */
+public final class IntegerRange implements Iterable<Integer>
+{
+    private final int start;
+
+    private final int finish;
+
+    private class RangeIterator implements Iterator<Integer>
+    {
+        private final int increment;
+
+        private int value = start;
+
+        private boolean hasNext = true;
+
+        RangeIterator()
+        {
+            increment = start < finish ? +1 : -1;
+        }
+
+        public boolean hasNext()
+        {
+            return hasNext;
+        }
+
+        public Integer next()
+        {
+            if (!hasNext) throw new IllegalStateException();
+
+            int result = value;
+
+            hasNext = value != finish;
+
+            value += increment;
+
+            return result;
+        }
+
+        public void remove()
+        {
+            throw new UnsupportedOperationException();
+        }
+
+    }
+
+    public IntegerRange(final int start, final int finish)
+    {
+        this.start = start;
+        this.finish = finish;
+    }
+
+    public int getFinish()
+    {
+        return finish;
+    }
+
+    public int getStart()
+    {
+        return start;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%d..%d", start, finish);
+    }
+
+    /**
+     * The main puprose of a range object is to produce an Iterator. Since IntegerRange is iterable, it is useful with
+     * the Tapestry Loop component, but also with the Java for loop!
+     */
+    public Iterator<Integer> iterator()
+    {
+        return new RangeIterator();
+    }
+
+    @Override
+    public int hashCode()
+    {
+        final int PRIME = 31;
+
+        int result = PRIME + finish;
+
+        result = PRIME * result + start;
+
+        return result;
+    }
+
+    /**
+     * Returns true if the other object is an IntegerRange with the same start and finish values.
+     */
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj) return true;
+        if (obj == null) return false;
+        if (getClass() != obj.getClass()) return false;
+        final IntegerRange other = (IntegerRange) obj;
+        if (finish != other.finish) return false;
+
+        return start == other.start;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java b/commons/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java
new file mode 100644
index 0000000..503bb1f
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java
@@ -0,0 +1,86 @@
+// Copyright 2006 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.util;
+
+import java.util.Arrays;
+
+/**
+ * Combines multiple values to form a single composite key. MultiKey can often be used as an alternative to nested
+ * maps.
+ */
+public final class MultiKey
+{
+    private static final int PRIME = 31;
+
+    private final Object[] values;
+
+    private final int hashCode;
+
+    /**
+     * Creates a new instance from the provided values. It is assumed that the values provided are good map keys
+     * themselves -- immutable, with proper implementations of equals() and hashCode().
+     *
+     * @param values
+     */
+    public MultiKey(Object... values)
+    {
+        this.values = values;
+
+        hashCode = PRIME * Arrays.hashCode(this.values);
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return hashCode;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        final MultiKey other = (MultiKey) obj;
+
+        return Arrays.equals(values, other.values);
+    }
+
+    @Override
+    public String toString()
+    {
+        StringBuilder builder = new StringBuilder("MultiKey[");
+
+        boolean first = true;
+
+        for (Object o : values)
+        {
+            if (!first)
+                builder.append(", ");
+
+            builder.append(o);
+
+            first = false;
+        }
+
+        builder.append("]");
+
+        return builder.toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java b/commons/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java
new file mode 100644
index 0000000..1f0e744
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java
@@ -0,0 +1,33 @@
+// Copyright 2007, 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;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * A source of annotations. This interface is used to mask where the annotations come from (for example, from a Method,
+ * a Class, or some other source).
+ */
+public interface AnnotationProvider
+{
+    /**
+     * Searches for the specified annotation, returning the matching annotation instance.
+     *
+     * @param <T>
+     * @param annotationClass used to select the annotation to return
+     * @return the annotation, or null if not found
+     */
+    <T extends Annotation> T getAnnotation(Class<T> annotationClass);
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/Locatable.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/Locatable.java b/commons/src/main/java/org/apache/tapestry5/ioc/Locatable.java
new file mode 100644
index 0000000..37b6551
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/Locatable.java
@@ -0,0 +1,27 @@
+// Copyright 2006, 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;
+
+/**
+ * Interface implemented by objects which carry a location tag. Defines a readable property, location.
+ */
+@SuppressWarnings({"JavaDoc"})
+public interface Locatable
+{
+    /**
+     * Returns the location associated with this object for error reporting purposes.
+     */
+    Location getLocation();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/Location.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/Location.java b/commons/src/main/java/org/apache/tapestry5/ioc/Location.java
new file mode 100644
index 0000000..e6688c2
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/Location.java
@@ -0,0 +1,38 @@
+// Copyright 2006 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;
+
+/**
+ * A kind of tag applied to other objects to identify where they came from, in terms of a file (the resource), a line
+ * number, and a column number. This is part of "line precise exception reporting", whereby errors at runtime can be
+ * tracked backwards to the files from which they were parsed or otherwise constructed.
+ */
+public interface Location
+{
+    /**
+     * The resource from which the object tagged with a location was derived.
+     */
+    Resource getResource();
+
+    /**
+     * The line number within the resource, if known, or -1 otherwise.
+     */
+    int getLine();
+
+    /**
+     * The column number within the line if known, or -1 otherwise.
+     */
+    int getColumn();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java b/commons/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java
new file mode 100644
index 0000000..e90eb65
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java
@@ -0,0 +1,32 @@
+// Copyright 2006 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;
+
+/**
+ * Obtained from a {@link org.apache.tapestry5.ioc.Messages}, used to format messages for a specific localized message
+ * key.
+ */
+public interface MessageFormatter
+{
+    /**
+     * Formats the message. The arguments are passed to {@link java.util.Formatter} as is with one exception: Object of
+     * type {@link Throwable} are converted to their {@link Throwable#getMessage()} (or, if that is null, to the name of
+     * the class).
+     *
+     * @param args
+     * @return formatted string
+     */
+    String format(Object... args);
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/Messages.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/Messages.java b/commons/src/main/java/org/apache/tapestry5/ioc/Messages.java
new file mode 100644
index 0000000..ba7452c
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/Messages.java
@@ -0,0 +1,61 @@
+// Copyright 2006, 2007, 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;
+
+import java.util.Set;
+
+/**
+ * Provides access to a messages catalog, a set of properties files that provide localized messages for a particular
+ * locale. The message catalog consists of keys and values and follows the semantics of a Java {@link
+ * java.util.ResourceBundle} with some changes.
+ */
+public interface Messages
+{
+    /**
+     * Returns true if the bundle contains the named key.
+     */
+    boolean contains(String key);
+
+    /**
+     * Returns the localized message for the given key. If catalog does not contain such a key, then a modified version
+     * of the key is returned (converted to upper case and enclosed in brackets).
+     *
+     * @param key
+     * @return localized message for key, or placeholder
+     */
+    String get(String key);
+
+    /**
+     * Returns a formatter for the message, which can be used to substitute arguments (as per {@link
+     * java.util.Formatter}).
+     *
+     * @param key
+     * @return formattable object
+     */
+    MessageFormatter getFormatter(String key);
+
+    /**
+     * Convenience for accessing a formatter and formatting a localized message with arguments.
+     */
+    String format(String key, Object... args);
+
+    /**
+     * Returns a set of all the keys for which this instance may provide a value.
+     *
+     * @return set of keys
+     * @since 5.4
+     */
+    Set<String> getKeys();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java b/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
new file mode 100644
index 0000000..81d1f77
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
@@ -0,0 +1,143 @@
+// Copyright 2006, 2007, 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;
+
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.ioc.services.MasterObjectProvider;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * Defines an object which can provide access to services defined within a {@link org.apache.tapestry5.ioc.Registry}, or
+ * to objects or object instances available by other means. Services are accessed via service id, or
+ * (when appropriate)
+ * by just service interface. The Registry itself implements this interface, as does
+ * {@link org.apache.tapestry5.ioc.ServiceResources}.
+ */
+public interface ObjectLocator
+{
+    /**
+     * Obtains a service via its unique service id. Returns the service's proxy. The service proxy
+     * implements the same
+     * interface as the actual service, and is used to instantiate the actual service only as needed
+     * (this is
+     * transparent to the application).
+     *
+     * @param <T>
+     * @param serviceId        unique Service id used to locate the service object (may contain <em>symbols</em>,
+     *                         which
+     *                         will be expanded), case is ignored
+     * @param serviceInterface the interface implemented by the service (or an interface extended by the service
+     *                         interface)
+     * @return the service instance
+     * @throws RuntimeException if the service is not defined, or if an error occurs instantiating it
+     */
+    <T> T getService(String serviceId, Class<T> serviceInterface);
+
+    /**
+     * Locates a service given a service interface and (optionally) some marker annotation types. A single service must implement the service
+     * interface (which                                                   * can be hard to guarantee) and by marked by all the marker types. The search takes into account inheritance of the service interface
+     * (not the service <em>implementation</em>), which may result in a failure due to extra
+     * matches.
+     *
+     * @param serviceInterface the interface the service implements
+     * @return the service's proxy
+     * @throws RuntimeException if the service does not exist (this is considered programmer error), or multiple
+     *                          services directly implement, or extend from, the service interface
+     * @see org.apache.tapestry5.ioc.annotations.Marker
+     */
+    <T> T getService(Class<T> serviceInterface);
+
+    /**
+     * Locates a service given a service interface and (optionally) some marker annotation types. A single service must implement the service
+     * interface (which                                                   * can be hard to guarantee) and by marked by all the marker types. The search takes into account inheritance of the service interface
+     * (not the service <em>implementation</em>), which may result in a failure due to extra
+     * matches.        The ability to specify marker annotation types was added in 5.3
+     *
+     * @param serviceInterface the interface the service implements
+     * @param markerTypes      Markers used to select a specific service that implements the interface
+     * @return the service's proxy
+     * @throws RuntimeException if the service does not exist (this is considered programmer error), or multiple
+     *                          services directly implement, or extend from, the service interface
+     * @see org.apache.tapestry5.ioc.annotations.Marker
+     * @since 5.3
+     */
+    <T> T getService(Class<T> serviceInterface, Class<? extends Annotation>... markerTypes);
+
+    /**
+     * Obtains an object indirectly, using the {@link org.apache.tapestry5.ioc.services.MasterObjectProvider} service.
+     *
+     * @param objectType         the type of object to be returned
+     * @param annotationProvider provides access to annotations on the field or parameter for which a value is to
+     *                           be
+     *                           obtained, which may be utilized in selecting an appropriate object, use
+     *                           <strong>null</strong> when annotations are not available (in which case, selection
+     *                           will
+     *                           be based only on the object type)
+     * @param <T>
+     * @return the requested object
+     * @see ObjectProvider
+     */
+    <T> T getObject(Class<T> objectType, AnnotationProvider annotationProvider);
+
+    /**
+     * Autobuilds a class by finding the public constructor with the most parameters. Services and other resources or
+     * dependencies will be injected into the parameters of the constructor and into private fields marked with the
+     * {@link Inject} annotation. There are two cases: constructing a service implementation, and constructing
+     * an arbitrary object. In the former case, many <em>service resources</em> are also available for injection, not
+     * just dependencies or objects provided via
+     * {@link MasterObjectProvider#provide(Class, AnnotationProvider, ObjectLocator, boolean)}.
+     *
+     * @param <T>
+     * @param clazz the type of object to instantiate
+     * @return the instantiated instance
+     * @throws RuntimeException if the autobuild fails
+     * @see MasterObjectProvider
+     */
+    <T> T autobuild(Class<T> clazz);
+
+    /**
+     * Preferred version of {@link #autobuild(Class)} that tracks the operation using
+     * {@link OperationTracker#invoke(String, Invokable)}.
+     *
+     * @param <T>
+     * @param description description used with {@link OperationTracker}
+     * @param clazz       the type of object to instantiate
+     * @return the instantiated instance
+     * @throws RuntimeException if the autobuild fails
+     * @see MasterObjectProvider
+     * @since 5.2.0
+     */
+    <T> T autobuild(String description, Class<T> clazz);
+
+    /**
+     * Creates a proxy. The proxy will defer invocation of {@link #autobuild(Class)} until
+     * just-in-time (that is, first method invocation). In a limited number of cases, it is necessary to use such a
+     * proxy to prevent service construction cycles, particularly when contributing (directly or indirectly) to the
+     * {@link org.apache.tapestry5.ioc.services.MasterObjectProvider} (which is itself at the heart
+     * of autobuilding).
+     * <p/>
+     * If the class file for the class is a file on the file system (not a file packaged in a JAR), then the proxy will
+     * <em>autoreload</em>: changing the class file will result in the new class being reloaded and re-instantiated
+     * (with dependencies).
+     *
+     * @param <T>
+     * @param interfaceClass      the interface implemented by the proxy
+     * @param implementationClass a concrete class that implements the interface
+     * @return a proxy
+     * @see #autobuild(Class)
+     */
+    <T> T proxy(Class<T> interfaceClass, Class<? extends T> implementationClass);
+}


[05/15] tapestry-5 git commit: First pass creating the BeanModel and Commons packages. Lots of stuff moved around, but no actual code changes so far

Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/Resource.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/Resource.java b/commons/src/main/java/org/apache/tapestry5/ioc/Resource.java
new file mode 100644
index 0000000..b81c1c5
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/Resource.java
@@ -0,0 +1,108 @@
+// 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;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Locale;
+
+/**
+ * Represents a resource on the server that may be used for server side processing, or may be exposed to the client
+ * side. Generally, this represents an abstraction on top of files on the class path and files stored in the web
+ * application context.
+ * <p/>
+ * Resources are often used as map keys; they should be immutable and should implement hashCode() and equals().
+ */
+public interface Resource
+{
+
+    /**
+     * Returns true if the resource exists; if a stream to the content of the file may be opened. A resource exists
+     * if {@link #toURL()} returns a non-null value. Starting in release 5.3.4, the result of this is cached.
+     * <p/>
+     * Starting in 5.4, some "virtual resources", may return true even though {@link #toURL()} returns null.
+     *
+     * @return true if the resource exists, false if it does not
+     */
+    boolean exists();
+
+
+    /**
+     * Returns true if the resource is virtual, meaning this is no underlying file. Many operations are unsupported
+     * on virtual resources, including {@link #toURL()}, {@link #forLocale(java.util.Locale)},
+     * {@link #withExtension(String)}, {@link #getFile()}, {@link #getFolder()}, {@link #getPath()}}; these
+     * operations will throw an {@link java.lang.UnsupportedOperationException}.
+     *
+     * @since 5.4
+     */
+    boolean isVirtual();
+
+    /**
+     * Opens a stream to the content of the resource, or returns null if the resource does not exist. The native
+     * input stream supplied by the resource is wrapped in a {@link java.io.BufferedInputStream}.
+     *
+     * @return an open, buffered stream to the content, if available
+     */
+    InputStream openStream() throws IOException;
+
+    /**
+     * Returns the URL for the resource, or null if it does not exist. This value is lazily computed; starting in 5.3.4, subclasses may cache
+     * the result.  Starting in 5.4, some "virtual resources" may return null.
+     */
+    URL toURL();
+
+    /**
+     * Returns a localized version of the resource. May return null if no such resource exists. Starting in release
+     * 5.3.4, the result of this method is cached internally.
+     */
+    Resource forLocale(Locale locale);
+
+    /**
+     * Returns a Resource based on a relative path, relative to the folder containing the resource. Understands the "."
+     * (current folder) and ".." (parent folder) conventions, and treats multiple sequential slashes as a single slash.
+     * <p/>
+     * Virtual resources (resources fabricated at runtime) return themselves.
+     */
+    Resource forFile(String relativePath);
+
+    /**
+     * Returns a new Resource with the extension changed (or, if the resource does not have an extension, the extension
+     * is added). The new Resource may not exist (that is, {@link #toURL()} may return null.
+     *
+     * @param extension
+     *         to apply to the resource, such as "html" or "properties"
+     * @return the new resource
+     */
+    Resource withExtension(String extension);
+
+    /**
+     * Returns the portion of the path up to the last forward slash; this is the directory or folder portion of the
+     * Resource.
+     */
+    String getFolder();
+
+    /**
+     * Returns the file portion of the Resource path, everything that follows the final forward slash.
+     * <p/>
+     * Starting in 5.4, certain kinds of "virtual resources" may return null here.
+     */
+    String getFile();
+
+    /**
+     * Return the path (the combination of folder and file).
+     * <p/>
+     * Starting in 5.4, certain "virtual resources", may return an arbitrary value here.
+     */
+    String getPath();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java
new file mode 100644
index 0000000..716b7c6
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java
@@ -0,0 +1,35 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.ioc.internal;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * A null implementation of {@link AnnotationProvider}, used when there is not appropriate source of annotations.
+ */
+public class NullAnnotationProvider implements AnnotationProvider
+{
+    /**
+     * Always returns null.
+     */
+    @Override
+    public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+    {
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java
new file mode 100644
index 0000000..6711b1a
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java
@@ -0,0 +1,139 @@
+// Copyright 2006, 2007, 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.util;
+
+import org.apache.tapestry5.ioc.util.CaseInsensitiveMap;
+import org.apache.tapestry5.ioc.util.Stack;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Static factory methods to ease the creation of new collection types (when using generics). Most of these method
+ * leverage the compiler's ability to match generic types by return value. Typical usage (with a static import):
+ * <p/>
+ * <pre>
+ * Map&lt;Foo, Bar&gt; map = newMap();
+ * </pre>
+ * <p/>
+ * <p/>
+ * This is a replacement for:
+ * <p/>
+ * <pre>
+ * Map&lt;Foo, Bar&gt; map = new HashMap&lt;Foo, Bar&gt;();
+ * </pre>
+ */
+public final class CollectionFactory
+{
+    /**
+     * Constructs and returns a generic {@link HashMap} instance.
+     */
+    public static <K, V> Map<K, V> newMap()
+    {
+        return new HashMap<K, V>();
+    }
+
+    /**
+     * Constructs and returns a generic {@link java.util.HashSet} instance.
+     */
+    public static <T> Set<T> newSet()
+    {
+        return new HashSet<T>();
+    }
+
+    /**
+     * Contructs a new {@link HashSet} and initializes it using the provided collection.
+     */
+    public static <T, V extends T> Set<T> newSet(Collection<V> values)
+    {
+        return new HashSet<T>(values);
+    }
+
+    public static <T, V extends T> Set<T> newSet(V... values)
+    {
+        // Was a call to newSet(), but Sun JDK can't handle that. Fucking generics.
+        return new HashSet<T>(Arrays.asList(values));
+    }
+
+    /**
+     * Constructs a new {@link java.util.HashMap} instance by copying an existing Map instance.
+     */
+    public static <K, V> Map<K, V> newMap(Map<? extends K, ? extends V> map)
+    {
+        return new HashMap<K, V>(map);
+    }
+
+    /**
+     * Constructs a new concurrent map, which is safe to access via multiple threads.
+     */
+    public static <K, V> ConcurrentMap<K, V> newConcurrentMap()
+    {
+        return new ConcurrentHashMap<K, V>();
+    }
+
+    /**
+     * Contructs and returns a new generic {@link java.util.ArrayList} instance.
+     */
+    public static <T> List<T> newList()
+    {
+        return new ArrayList<T>();
+    }
+
+    /**
+     * Creates a new, fully modifiable list from an initial set of elements.
+     */
+    public static <T, V extends T> List<T> newList(V... elements)
+    {
+        // Was call to newList(), but Sun JDK can't handle that.
+        return new ArrayList<T>(Arrays.asList(elements));
+    }
+
+    /**
+     * Useful for queues.
+     */
+    public static <T> LinkedList<T> newLinkedList()
+    {
+        return new LinkedList<T>();
+    }
+
+    /**
+     * Constructs and returns a new {@link java.util.ArrayList} as a copy of the provided collection.
+     */
+    public static <T, V extends T> List<T> newList(Collection<V> list)
+    {
+        return new ArrayList<T>(list);
+    }
+
+    /**
+     * Constructs and returns a new {@link java.util.concurrent.CopyOnWriteArrayList}.
+     */
+    public static <T> List<T> newThreadSafeList()
+    {
+        return new CopyOnWriteArrayList<T>();
+    }
+
+    public static <T> Stack<T> newStack()
+    {
+        return new Stack<T>();
+    }
+
+    public static <V> Map<String, V> newCaseInsensitiveMap()
+    {
+        return new CaseInsensitiveMap<V>();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
new file mode 100644
index 0000000..1a6dd80
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
@@ -0,0 +1,615 @@
+// Copyright 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.util;
+
+import java.lang.reflect.*;
+import java.util.LinkedList;
+
+/**
+ * Static methods related to the use of JDK 1.5 generics.
+ */
+@SuppressWarnings("unchecked")
+public class GenericsUtils
+{
+    /**
+     * Analyzes the method in the context of containingClass and returns the Class that is represented by
+     * the method's generic return type. Any parameter information in the generic return type is lost. If you want
+     * to preserve the type parameters of the return type consider using
+     * {@link #extractActualType(java.lang.reflect.Type, java.lang.reflect.Method)}.
+     *
+     * @param containingClass class which either contains or inherited the method
+     * @param method          method from which to extract the return type
+     * @return the class represented by the methods generic return type, resolved based on the context .
+     * @see #extractActualType(java.lang.reflect.Type, java.lang.reflect.Method)
+     * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
+     * @see #asClass(java.lang.reflect.Type)
+     */
+    public static Class<?> extractGenericReturnType(Class<?> containingClass, Method method)
+    {
+        return asClass(resolve(method.getGenericReturnType(), containingClass));
+    }
+
+
+    /**
+     * Analyzes the field in the context of containingClass and returns the Class that is represented by
+     * the field's generic type. Any parameter information in the generic type is lost, if you want
+     * to preserve the type parameters of the return type consider using
+     * {@link #getTypeVariableIndex(java.lang.reflect.TypeVariable)}.
+     *
+     * @param containingClass class which either contains or inherited the field
+     * @param field           field from which to extract the type
+     * @return the class represented by the field's generic type, resolved based on the containingClass.
+     * @see #extractActualType(java.lang.reflect.Type, java.lang.reflect.Field)
+     * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
+     * @see #asClass(java.lang.reflect.Type)
+     */
+    public static Class extractGenericFieldType(Class containingClass, Field field)
+    {
+        return asClass(resolve(field.getGenericType(), containingClass));
+    }
+
+    /**
+     * Analyzes the method in the context of containingClass and returns the Class that is represented by
+     * the method's generic return type. Any parameter information in the generic return type is lost.
+     *
+     * @param containingType Type which is/represents the class that either contains or inherited the method
+     * @param method         method from which to extract the generic return type
+     * @return the generic type represented by the methods generic return type, resolved based on the containingType.
+     * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
+     */
+    public static Type extractActualType(Type containingType, Method method)
+    {
+        return resolve(method.getGenericReturnType(), containingType);
+    }
+
+    /**
+     * Analyzes the method in the context of containingClass and returns the Class that is represented by
+     * the method's generic return type. Any parameter information in the generic return type is lost.
+     *
+     * @param containingType Type which is/represents the class that either contains or inherited the field
+     * @param field          field from which to extract the generic return type
+     * @return the generic type represented by the methods generic return type, resolved based on the containingType.
+     * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
+     */
+    public static Type extractActualType(Type containingType, Field field)
+    {
+        return resolve(field.getGenericType(), containingType);
+    }
+
+    /**
+     * Resolves the type parameter based on the context of the containingType.
+     * <p/>
+     * {@link java.lang.reflect.TypeVariable} will be unwrapped to the type argument resolved form the class
+     * hierarchy. This may be something other than a simple Class if the type argument is a ParameterizedType for
+     * instance (e.g. List&lt;E>; List&lt;Map&lt;Long, String>>, E would be returned as a ParameterizedType with the raw
+     * type Map and type arguments Long and String.
+     * <p/>
+     *
+     * @param type
+     *          the generic type (ParameterizedType, GenericArrayType, WildcardType, TypeVariable) to be resolved
+     * @param containingType
+     *          the type which his
+     * @return
+     *          the type resolved to the best of our ability.
+     * @since 5.2.?
+     */
+    public static Type resolve(final Type type, final Type containingType)
+    {
+        // The type isn't generic. (String, Long, etc)
+        if (type instanceof Class)
+            return type;
+
+        // List<T>, List<String>, List<T extends Number>
+        if (type instanceof ParameterizedType)
+            return resolve((ParameterizedType) type, containingType);
+
+        // T[], List<String>[], List<T>[]
+        if (type instanceof GenericArrayType)
+            return resolve((GenericArrayType) type, containingType);
+
+        // List<? extends T>, List<? extends Object & Comparable & Serializable>
+        if (type instanceof WildcardType)
+            return resolve((WildcardType) type, containingType);
+
+        // T
+        if (type instanceof TypeVariable)
+            return resolve((TypeVariable) type, containingType);
+
+        // I'm leaning towards an exception here.
+        return type;
+    }
+
+
+    /**
+     * Determines if the suspected super type is assignable from the suspected sub type.
+     *
+     * @param suspectedSuperType
+     *          e.g. GenericDAO&lt;Pet, String>
+     * @param suspectedSubType
+     *          e.g. PetDAO extends GenericDAO&lt;Pet,String>
+     * @return
+     *          true if (sourceType)targetClass is a valid cast
+     */
+    public static boolean isAssignableFrom(Type suspectedSuperType, Type suspectedSubType)
+    {
+        final Class suspectedSuperClass = asClass(suspectedSuperType);
+        final Class suspectedSubClass = asClass(suspectedSubType);
+
+        // The raw types need to be compatible.
+        if (!suspectedSuperClass.isAssignableFrom(suspectedSubClass))
+        {
+            return false;
+        }
+
+        // From this point we know that the raw types are assignable.
+        // We need to figure out what the generic parameters in the targetClass are
+        // as they pertain to the sourceType.
+
+        if (suspectedSuperType instanceof WildcardType)
+        {
+            // ? extends Number
+            // needs to match all the bounds (there will only be upper bounds or lower bounds
+            for (Type t : ((WildcardType) suspectedSuperType).getUpperBounds())
+            {
+                if (!isAssignableFrom(t, suspectedSubType)) return false;
+            }
+            for (Type t : ((WildcardType) suspectedSuperType).getLowerBounds())
+            {
+                if (!isAssignableFrom(suspectedSubType, t)) return false;
+            }
+            return true;
+        }
+
+        Type curType = suspectedSubType;
+        Class curClass;
+
+        while (curType != null && !curType.equals(Object.class))
+        {
+            curClass = asClass(curType);
+
+            if (curClass.equals(suspectedSuperClass))
+            {
+                final Type resolved = resolve(curType, suspectedSubType);
+
+                if (suspectedSuperType instanceof Class)
+                {
+                    if ( resolved instanceof Class )
+                        return suspectedSuperType.equals(resolved);
+
+                    // They may represent the same class, but the suspectedSuperType is not parameterized. The parameter
+                    // types default to Object so they must be a match.
+                    // e.g. Pair p = new StringLongPair();
+                    //      Pair p = new Pair<? extends Number, String>
+
+                    return true;
+                }
+
+                if (suspectedSuperType instanceof ParameterizedType)
+                {
+                    if (resolved instanceof ParameterizedType)
+                    {
+                        final Type[] type1Arguments = ((ParameterizedType) suspectedSuperType).getActualTypeArguments();
+                        final Type[] type2Arguments = ((ParameterizedType) resolved).getActualTypeArguments();
+                        if (type1Arguments.length != type2Arguments.length) return false;
+
+                        for (int i = 0; i < type1Arguments.length; ++i)
+                        {
+                            if (!isAssignableFrom(type1Arguments[i], type2Arguments[i])) return false;
+                        }
+                        return true;
+                    }
+                }
+                else if (suspectedSuperType instanceof GenericArrayType)
+                {
+                    if (resolved instanceof GenericArrayType)
+                    {
+                        return isAssignableFrom(
+                                ((GenericArrayType) suspectedSuperType).getGenericComponentType(),
+                                ((GenericArrayType) resolved).getGenericComponentType()
+                        );
+                    }
+                }
+
+                return false;
+            }
+
+            final Type[] types = curClass.getGenericInterfaces();
+            for (Type t : types)
+            {
+                final Type resolved = resolve(t, suspectedSubType);
+                if (isAssignableFrom(suspectedSuperType, resolved))
+                    return true;
+            }
+
+            curType = curClass.getGenericSuperclass();
+        }
+        return false;
+    }
+
+    /**
+     * Get the class represented by the reflected type.
+     * This method is lossy; You cannot recover the type information from the class that is returned.
+     * <p/>
+     * {@code TypeVariable} the first bound is returned. If your type variable extends multiple interfaces that information
+     * is lost.
+     * <p/>
+     * {@code WildcardType} the first lower bound is returned. If the wildcard is defined with upper bounds
+     * then {@code Object} is returned.
+     *
+     * @param actualType
+     *           a Class, ParameterizedType, GenericArrayType
+     * @return the un-parameterized class associated with the type.
+     */
+    public static Class asClass(Type actualType)
+    {
+        if (actualType instanceof Class) return (Class) actualType;
+
+        if (actualType instanceof ParameterizedType)
+        {
+            final Type rawType = ((ParameterizedType) actualType).getRawType();
+            // The sun implementation returns getRawType as Class<?>, but there is room in the interface for it to be
+            // some other Type. We'll assume it's a Class.
+            // TODO: consider logging or throwing our own exception for that day when "something else" causes some confusion
+            return (Class) rawType;
+        }
+
+        if (actualType instanceof GenericArrayType)
+        {
+            final Type type = ((GenericArrayType) actualType).getGenericComponentType();
+            return Array.newInstance(asClass(type), 0).getClass();
+        }
+
+        if (actualType instanceof TypeVariable)
+        {
+            // Support for List<T extends Number>
+            // There is always at least one bound. If no bound is specified in the source then it will be Object.class
+            return asClass(((TypeVariable) actualType).getBounds()[0]);
+        }
+
+        if (actualType instanceof WildcardType)
+        {
+            final WildcardType wildcardType = (WildcardType) actualType;
+            final Type[] bounds = wildcardType.getLowerBounds();
+            if (bounds != null && bounds.length > 0)
+            {
+                return asClass(bounds[0]);
+            }
+            // If there is no lower bounds then the only thing that makes sense is Object.
+            return Object.class;
+        }
+
+        throw new RuntimeException(String.format("Unable to convert %s to Class.", actualType));
+    }
+
+    /**
+     * Convert the type into a string. The string representation approximates the code that would be used to define the
+     * type.
+     *
+     * @param type - the type.
+     * @return a string representation of the type, similar to how it was declared.
+     */
+    public static String toString(Type type)
+    {
+        if ( type instanceof ParameterizedType ) return toString((ParameterizedType)type);
+        if ( type instanceof WildcardType ) return toString((WildcardType)type);
+        if ( type instanceof GenericArrayType) return toString((GenericArrayType)type);
+        if ( type instanceof Class )
+        {
+            final Class theClass = (Class) type;
+            return (theClass.isArray() ? theClass.getName() + "[]" : theClass.getName());
+        }
+        return type.toString();
+    }
+
+    /**
+     * Method to resolve a TypeVariable to its most
+     * <a href="http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#112582">reifiable</a> form.
+     * <p/>
+     * <p/>
+     * How to resolve a TypeVariable:<br/>
+     * All of the TypeVariables defined by a generic class will be given a Type by any class that extends it. The Type
+     * given may or may not be reifiable; it may be another TypeVariable for instance.
+     * <p/>
+     * Consider <br/>
+     * <i>class Pair&gt;A,B> { A getA(){...}; ...}</i><br/>
+     * <i>class StringLongPair extends Pair&gt;String, Long> { }</i><br/>
+     * <p/>
+     * To resolve the actual return type of Pair.getA() you must first resolve the TypeVariable "A".
+     * We can do that by first finding the index of "A" in the Pair.class.getTypeParameters() array of TypeVariables.
+     * <p/>
+     * To get to the Type provided by StringLongPair you access the generics information by calling
+     * StringLongPair.class.getGenericSuperclass; this will be a ParameterizedType. ParameterizedType gives you access
+     * to the actual type arguments provided to Pair by StringLongPair. The array is in the same order as the array in
+     * Pair.class.getTypeParameters so you can use the index we discovered earlier to extract the Type; String.class.
+     * <p/>
+     * When extracting Types we only have to consider the superclass hierarchy and not the interfaces implemented by
+     * the class. When a class implements a generic interface it must provide types for the interface and any generic
+     * methods implemented from the interface will be re-defined by the class with its generic type variables.
+     *
+     * @param typeVariable   - the type variable to resolve.
+     * @param containingType - the shallowest class in the class hierarchy (furthest from Object) where typeVariable is defined.
+     * @return a Type that has had all possible TypeVariables resolved that have been defined between the type variable
+     *         declaration and the containingType.
+     */
+    private static Type resolve(TypeVariable typeVariable, Type containingType)
+    {
+        // The generic declaration is either a Class, Method or Constructor
+        final GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
+
+        if (!(genericDeclaration instanceof Class))
+        {
+            // It's a method or constructor. The best we can do here is try to resolve the bounds
+            // e.g. <T extends E> T getT(T param){} where E is defined by the class.
+            final Type bounds0 = typeVariable.getBounds()[0];
+            return resolve(bounds0, containingType);
+        }
+
+        final Class typeVariableOwner = (Class) genericDeclaration;
+
+        // find the typeOwner in the containingType's hierarchy
+        final LinkedList<Type> stack = new LinkedList<Type>();
+
+        // If you pass a List<Long> as the containingType then the TypeVariable is going to be resolved by the
+        // containingType and not the super class.
+        if (containingType instanceof ParameterizedType)
+        {
+            stack.add(containingType);
+        }
+
+        Class theClass = asClass(containingType);
+        Type genericSuperclass = theClass.getGenericSuperclass();
+        while (genericSuperclass != null && // true for interfaces with no superclass
+                !theClass.equals(Object.class) &&
+                !theClass.equals(typeVariableOwner))
+        {
+            stack.addFirst(genericSuperclass);
+            theClass = asClass(genericSuperclass);
+            genericSuperclass = theClass.getGenericSuperclass();
+        }
+
+        int i = getTypeVariableIndex(typeVariable);
+        Type resolved = typeVariable;
+        for (Type t : stack)
+        {
+            if (t instanceof ParameterizedType)
+            {
+                resolved = ((ParameterizedType) t).getActualTypeArguments()[i];
+                if (resolved instanceof Class) return resolved;
+                if (resolved instanceof TypeVariable)
+                {
+                    // Need to look at the next class in the hierarchy
+                    i = getTypeVariableIndex((TypeVariable) resolved);
+                    continue;
+                }
+                return resolve(resolved, containingType);
+            }
+        }
+
+        // the only way we get here is if resolved is still a TypeVariable, otherwise an
+        // exception is thrown or a value is returned.
+        return ((TypeVariable) resolved).getBounds()[0];
+    }
+
+    /**
+     * @param type           - something like List&lt;T>[] or List&lt;? extends T>[] or T[]
+     * @param containingType - the shallowest type in the hierarchy where type is defined.
+     * @return either the passed type if no changes required or a copy with a best effort resolve of the component type.
+     */
+    private static GenericArrayType resolve(GenericArrayType type, Type containingType)
+    {
+        final Type componentType = type.getGenericComponentType();
+
+        if (!(componentType instanceof Class))
+        {
+            final Type resolved = resolve(componentType, containingType);
+            return create(resolved);
+        }
+
+        return type;
+    }
+
+    /**
+     * @param type           - something like List&lt;T>, List&lt;T extends Number>
+     * @param containingType - the shallowest type in the hierarchy where type is defined.
+     * @return the passed type if nothing to resolve or a copy of the type with the type arguments resolved.
+     */
+    private static ParameterizedType resolve(ParameterizedType type, Type containingType)
+    {
+        // Use a copy because we're going to modify it.
+        final Type[] types = type.getActualTypeArguments().clone();
+
+        boolean modified = resolve(types, containingType);
+        return modified ? create(type.getRawType(), type.getOwnerType(), types) : type;
+    }
+
+    /**
+     * @param type           - something like List&lt;? super T>, List<&lt;? extends T>, List&lt;? extends T & Comparable&lt? super T>>
+     * @param containingType - the shallowest type in the hierarchy where type is defined.
+     * @return the passed type if nothing to resolve or a copy of the type with the upper and lower bounds resolved.
+     */
+    private static WildcardType resolve(WildcardType type, Type containingType)
+    {
+        // Use a copy because we're going to modify them.
+        final Type[] upper = type.getUpperBounds().clone();
+        final Type[] lower = type.getLowerBounds().clone();
+
+        boolean modified = resolve(upper, containingType);
+        modified = modified || resolve(lower, containingType);
+
+        return modified ? create(upper, lower) : type;
+    }
+
+    /**
+     * @param types          - Array of types to resolve. The unresolved type is replaced in the array with the resolved type.
+     * @param containingType - the shallowest type in the hierarchy where type is defined.
+     * @return true if any of the types were resolved.
+     */
+    private static boolean resolve(Type[] types, Type containingType)
+    {
+        boolean modified = false;
+        for (int i = 0; i < types.length; ++i)
+        {
+            Type t = types[i];
+            if (!(t instanceof Class))
+            {
+                modified = true;
+                final Type resolved = resolve(t, containingType);
+                if (!resolved.equals(t))
+                {
+                    types[i] = resolved;
+                    modified = true;
+                }
+            }
+        }
+        return modified;
+    }
+
+    /**
+     * @param rawType       - the un-parameterized type.
+     * @param ownerType     - the outer class or null if the class is not defined within another class.
+     * @param typeArguments - type arguments.
+     * @return a copy of the type with the typeArguments replaced.
+     */
+    static ParameterizedType create(final Type rawType, final Type ownerType, final Type[] typeArguments)
+    {
+        return new ParameterizedType()
+        {
+            @Override
+            public Type[] getActualTypeArguments()
+            {
+                return typeArguments;
+            }
+
+            @Override
+            public Type getRawType()
+            {
+                return rawType;
+            }
+
+            @Override
+            public Type getOwnerType()
+            {
+                return ownerType;
+            }
+
+            @Override
+            public String toString()
+            {
+                return GenericsUtils.toString(this);
+            }
+        };
+    }
+
+    static GenericArrayType create(final Type componentType)
+    {
+        return new GenericArrayType()
+        {
+            @Override
+            public Type getGenericComponentType()
+            {
+                return componentType;
+            }
+
+            @Override
+            public String toString()
+            {
+                return GenericsUtils.toString(this);
+            }
+        };
+    }
+
+    /**
+     * @param upperBounds - e.g. ? extends Number
+     * @param lowerBounds - e.g. ? super Long
+     * @return An new copy of the type with the upper and lower bounds replaced.
+     */
+    static WildcardType create(final Type[] upperBounds, final Type[] lowerBounds)
+    {
+
+        return new WildcardType()
+        {
+            @Override
+            public Type[] getUpperBounds()
+            {
+                return upperBounds;
+            }
+
+            @Override
+            public Type[] getLowerBounds()
+            {
+                return lowerBounds;
+            }
+
+            @Override
+            public String toString()
+            {
+                return GenericsUtils.toString(this);
+            }
+        };
+    }
+
+    static String toString(ParameterizedType pt)
+    {
+        String s = toString(pt.getActualTypeArguments());
+        return String.format("%s<%s>", toString(pt.getRawType()), s);
+    }
+
+    static String toString(GenericArrayType gat)
+    {
+        return String.format("%s[]", toString(gat.getGenericComponentType()));
+    }
+
+    static String toString(WildcardType wt)
+    {
+        final boolean isSuper = wt.getLowerBounds().length > 0;
+        return String.format("? %s %s",
+                isSuper ? "super" : "extends",
+                isSuper ? toString(wt.getLowerBounds()) : toString(wt.getLowerBounds()));
+    }
+
+    static String toString(Type[] types)
+    {
+        StringBuilder sb = new StringBuilder();
+        for ( Type t : types )
+        {
+            sb.append(toString(t)).append(", ");
+        }
+        return sb.substring(0, sb.length() - 2);// drop last ,
+    }
+
+    /**
+     * Find the index of the TypeVariable in the classes parameters. The offset can be used on a subclass to find
+     * the actual type.
+     *
+     * @param typeVariable - the type variable in question.
+     * @return the index of the type variable in its declaring class/method/constructor's type parameters.
+     */
+    private static int getTypeVariableIndex(final TypeVariable typeVariable)
+    {
+        // the label from the class (the T in List<T>, the K or V in Map<K,V>, etc)
+        final String typeVarName = typeVariable.getName();
+        final TypeVariable[] typeParameters = typeVariable.getGenericDeclaration().getTypeParameters();
+        for (int typeArgumentIndex = 0; typeArgumentIndex < typeParameters.length; typeArgumentIndex++)
+        {
+            // The .equals for TypeVariable may not be compatible, a name check should be sufficient.
+            if (typeParameters[typeArgumentIndex].getName().equals(typeVarName))
+                return typeArgumentIndex;
+        }
+
+        // The only way this could happen is if the TypeVariable is hand built incorrectly, or it's corrupted.
+        throw new RuntimeException(
+                String.format("%s does not have a TypeVariable matching %s", typeVariable.getGenericDeclaration(), typeVariable));
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
new file mode 100644
index 0000000..ef217cb
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
@@ -0,0 +1,75 @@
+// Copyright 2006 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.util;
+
+import org.apache.tapestry5.ioc.Locatable;
+import org.apache.tapestry5.ioc.Location;
+
+/**
+ * Exception class used as a replacement for {@link java.lang.RuntimeException} when the exception is related to a
+ * particular location.
+ */
+public class TapestryException extends RuntimeException implements Locatable
+{
+    private static final long serialVersionUID = 6396903640977182682L;
+
+    private transient final Location location;
+
+    /**
+     * @param message  a message (may be null)
+     * @param location implements {@link Location} or {@link Locatable}
+     * @param cause    if not null, the root cause of the exception
+     */
+    public TapestryException(String message, Object location, Throwable cause)
+    {
+        this(message, InternalUtils.locationOf(location), cause);
+    }
+
+    /**
+     * @param message a message (may be null)
+     * @param cause   if not null, the root cause of the exception, also used to set the location
+     */
+    public TapestryException(String message, Throwable cause)
+    {
+        this(message, cause, cause);
+    }
+
+    /**
+     * @param message  a message (may be null)
+     * @param location location to associated with the exception, or null if not known
+     * @param cause    if not null, the root cause of the exception
+     */
+    public TapestryException(String message, Location location, Throwable cause)
+    {
+        super(message, cause);
+
+        this.location = location;
+    }
+
+    @Override
+    public Location getLocation()
+    {
+        return location;
+    }
+
+    @Override
+    public String toString()
+    {
+        if (location == null) return super.toString();
+
+        return String.format("%s [at %s]", super.toString(), location);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java b/commons/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java
new file mode 100644
index 0000000..6159ed3
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java
@@ -0,0 +1,79 @@
+// Copyright 2006, 2007, 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.services;
+
+import java.lang.annotation.Annotation;
+import java.util.List;
+
+/**
+ * Organizes all {@link org.apache.tapestry5.ioc.services.PropertyAdapter}s for a particular class.
+ * <p/>
+ * Only provides access to <em>simple</em> properties. Indexed properties are ignored.
+ * <p/>
+ * When accessing properties by name, the case of the name is ignored.
+ */
+public interface ClassPropertyAdapter
+{
+    /**
+     * Returns the names of all properties, sorted into alphabetic order. This includes true properties
+     * (as defined in the JavaBeans specification), but also public fields. Starting in Tapestry 5.3, even public static fields are included.
+     */
+    List<String> getPropertyNames();
+
+    /**
+     * Returns the type of bean this adapter provides properties for.
+     */
+    Class getBeanType();
+
+    /**
+     * Returns the property adapter with the given name, or null if no such adapter exists.
+     *
+     * @param name of the property (case is ignored)
+     */
+    PropertyAdapter getPropertyAdapter(String name);
+
+    /**
+     * Reads the value of a property.
+     *
+     * @param instance     the object to read a value from
+     * @param propertyName the name of the property to read (case is ignored)
+     * @throws UnsupportedOperationException if the property is write only
+     * @throws IllegalArgumentException      if property does not exist
+     */
+    Object get(Object instance, String propertyName);
+
+    /**
+     * Updates the value of a property.
+     *
+     * @param instance     the object to update
+     * @param propertyName the name of the property to update (case is ignored)
+     * @throws UnsupportedOperationException if the property is read only
+     * @throws IllegalArgumentException      if property does not exist
+     */
+    void set(Object instance, String propertyName, Object value);
+
+    /**
+     * Returns the annotation of a given property for the specified type if such an annotation is present, else null.
+     *
+     * @param instance     the object to read a value from
+     * @param propertyName the name of the property to read (case is ignored)
+     * @param annotationClass the type of annotation to return
+     *
+     * @throws IllegalArgumentException      if property does not exist
+     *
+     * @since 5.4
+     */
+    Annotation getAnnotation(Object instance, String propertyName, Class<? extends Annotation> annotationClass);
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java b/commons/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java
new file mode 100644
index 0000000..b7a4cc8
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java
@@ -0,0 +1,31 @@
+// Copyright 2006 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.services;
+
+/**
+ * Responsible for converting from one type to another. This is used primarily around component parameters.
+ *
+ * @param <S> the source type (input)
+ * @param <T> the target type (output)
+ */
+public interface Coercion<S, T>
+{
+    /**
+     * Converts an input value.
+     *
+     * @param input the input value
+     */
+    T coerce(S input);
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java b/commons/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java
new file mode 100644
index 0000000..746de1e
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java
@@ -0,0 +1,145 @@
+// 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.services;
+
+import org.apache.tapestry5.plastic.PlasticUtils;
+
+/**
+ * An immutable object that represents a mapping from one type to another. This is also the contribution type when
+ * building the {@link org.apache.tapestry5.ioc.services.TypeCoercer} service. Wraps a
+ * {@link org.apache.tapestry5.ioc.services.Coercion} object that performs the work with additional properties that
+ * describe
+ * the input and output types of the coercion, needed when searching for an appropriate coercion (or sequence of
+ * coercions).
+ *
+ * @param <S>
+ *         source (input) type
+ * @param <T>
+ *         target (output) type
+ */
+public final class CoercionTuple<S, T>
+{
+    private final Class<S> sourceType;
+
+    private final Class<T> targetType;
+
+    private final Coercion<S, T> coercion;
+
+    /**
+     * Wraps an arbitrary coercion with an implementation of toString() that identifies the source and target types.
+     */
+    private class CoercionWrapper<WS, WT> implements Coercion<WS, WT>
+    {
+        private final Coercion<WS, WT> coercion;
+
+        public CoercionWrapper(Coercion<WS, WT> coercion)
+        {
+            this.coercion = coercion;
+        }
+
+        @Override
+        public WT coerce(WS input)
+        {
+            return coercion.coerce(input);
+        }
+
+        @Override
+        public String toString()
+        {
+            return String.format("%s --> %s", convert(sourceType), convert(targetType));
+        }
+    }
+
+    private String convert(Class type)
+    {
+        if (Void.class.equals(type))
+            return "null";
+
+        String name = PlasticUtils.toTypeName(type);
+
+        int dotx = name.lastIndexOf('.');
+
+        // Strip off a package name of "java.lang"
+
+        if (dotx > 0 && name.substring(0, dotx).equals("java.lang"))
+            return name.substring(dotx + 1);
+
+        return name;
+    }
+
+    /**
+     * Standard constructor, which defaults wrap to true.
+     */
+    public CoercionTuple(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion)
+    {
+        this(sourceType, targetType, coercion, true);
+    }
+
+    /**
+     * Convenience constructor to help with generics.
+     *
+     * @since 5.2.0
+     */
+    public static <S, T> CoercionTuple<S, T> create(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion)
+    {
+        return new CoercionTuple<S, T>(sourceType, targetType, coercion);
+    }
+
+    /**
+     * Internal-use constructor.
+     *
+     * @param sourceType
+     *         the source (or input) type of the coercion, may be Void.class to indicate a coercion from null
+     * @param targetType
+     *         the target (or output) type of the coercion
+     * @param coercion
+     *         the object that performs the coercion
+     * @param wrap
+     *         if true, the coercion is wrapped to provide a useful toString()
+     */
+    @SuppressWarnings("unchecked")
+    public CoercionTuple(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion, boolean wrap)
+    {
+        assert sourceType != null;
+        assert targetType != null;
+        assert coercion != null;
+
+        this.sourceType = PlasticUtils.toWrapperType(sourceType);
+        this.targetType = PlasticUtils.toWrapperType(targetType);
+        this.coercion = wrap ? new CoercionWrapper<S, T>(coercion) : coercion;
+    }
+
+    @Override
+    public String toString()
+    {
+        return coercion.toString();
+    }
+
+    public Coercion<S, T> getCoercion()
+    {
+        return coercion;
+    }
+
+    public Class<S> getSourceType()
+    {
+        return sourceType;
+    }
+
+    public Class<T> getTargetType()
+    {
+        return targetType;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java b/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java
new file mode 100644
index 0000000..ae542c5
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java
@@ -0,0 +1,77 @@
+// Copyright 2006, 2010, 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.services;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * A wrapper around the JavaBean Introspector that allows more manageable access to JavaBean properties of objects.
+ * <p/>
+ * Only provides access to <em>simple</em> properties. Indexed properties are ignored.
+ * <p>
+ * Starting in Tapestry 5.2, public fields can now be accessed as if they were properly JavaBean properties. Where there
+ * is a name conflict, the true property will be favored over the field access.
+ */
+public interface PropertyAccess
+{
+    /**
+     * Reads the value of a property.
+     *
+     * @throws UnsupportedOperationException
+     *             if the property is write only
+     * @throws IllegalArgumentException
+     *             if property does not exist
+     */
+    Object get(Object instance, String propertyName);
+
+    /**
+     * Updates the value of a property.
+     *
+     * @throws UnsupportedOperationException
+     *             if the property is read only
+     * @throws IllegalArgumentException
+     *             if property does not exist
+     */
+    void set(Object instance, String propertyName, Object value);
+
+    /**
+     * Returns the annotation of a given property for the specified type if such an annotation is present, else null.
+     * A convenience over invoking {@link #getAdapter(Object)}.{@link ClassPropertyAdapter#getPropertyAdapter(String)}.{@link PropertyAdapter#getAnnotation(Class)}
+     *
+     * @param instance     the object to read a value from
+     * @param propertyName the name of the property to read (case is ignored)
+     * @param annotationClass the type of annotation to return
+     * @throws IllegalArgumentException
+     *             if property does not exist
+     *
+     * @since 5.4
+     */
+    Annotation getAnnotation(Object instance, String propertyName, Class<? extends Annotation> annotationClass);
+
+    /**
+     * Returns the adapter for a particular object instance. A convienience over invoking {@link #getAdapter(Class)}.
+     */
+    ClassPropertyAdapter getAdapter(Object instance);
+
+    /**
+     * Returns the adapter used to access properties within the indicated class.
+     */
+    ClassPropertyAdapter getAdapter(Class forClass);
+
+    /**
+     * Discards all stored property access information, discarding all created class adapters.
+     */
+    void clearCache();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java b/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java
new file mode 100644
index 0000000..947535e
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java
@@ -0,0 +1,121 @@
+// Copyright 2006, 2008, 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.services;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * Provides access to a single property within a class. Acts as an {@link org.apache.tapestry5.ioc.AnnotationProvider};
+ * when searching for annotations, the read method (if present) is checked first, followed by the write method, followed
+ * by the underlying field (when the property name matches the field name).
+ * <p/>
+ * Starting in release 5.2, this property may actually be a public field. In 5.3, it may be a public static field.
+ *
+ * @see org.apache.tapestry5.ioc.services.ClassPropertyAdapter
+ */
+@SuppressWarnings("unchecked")
+public interface PropertyAdapter extends AnnotationProvider
+{
+    /**
+     * Returns the name of the property (or public field).
+     */
+    String getName();
+
+    /**
+     * Returns true if the property is readable (i.e., has a getter method or is a public field).
+     */
+    boolean isRead();
+
+    /**
+     * Returns the method used to read the property, or null if the property is not readable (or is a public field).
+     */
+    public Method getReadMethod();
+
+    /**
+     * Returns true if the property is writeable (i.e., has a setter method or is a non-final field).
+     */
+    boolean isUpdate();
+
+    /**
+     * Returns the method used to update the property, or null if the property is not writeable (or a public field).
+     */
+    public Method getWriteMethod();
+
+    /**
+     * Reads the property value.
+     *
+     * @param instance to read from
+     * @throws UnsupportedOperationException if the property is write only
+     */
+    Object get(Object instance);
+
+    /**
+     * Updates the property value. The provided value must not be null if the property type is primitive, and must
+     * otherwise be of the proper type.
+     *
+     * @param instance to update
+     * @param value    new value for the property
+     * @throws UnsupportedOperationException if the property is read only
+     */
+    void set(Object instance, Object value);
+
+    /**
+     * Returns the type of the property.
+     */
+    Class getType();
+
+    /**
+     * Returns true if the return type of the read method is not the same as the property type. This can occur when the
+     * property has been defined using generics, in which case, the method's type may be Object when the property type
+     * is something more specific. This method is primarily used when generating runtime code related to the property.
+     */
+    boolean isCastRequired();
+
+    /**
+     * Returns the {@link org.apache.tapestry5.ioc.services.ClassPropertyAdapter} that provides access to other
+     * properties defined by the same class.
+     */
+    ClassPropertyAdapter getClassAdapter();
+
+    /**
+     * Returns the type of bean to which this property belongs. This is the same as
+     * {@link org.apache.tapestry5.ioc.services.ClassPropertyAdapter#getBeanType()}.
+     */
+    Class getBeanType();
+
+    /**
+     * Returns true if the property is actually a public field (possibly, a public static field).
+     *
+     * @since 5.2
+     */
+    boolean isField();
+
+    /**
+     * Returns the field if the property is a public field or null if the property is accessed via the read method.
+     *
+     * @since 5.2
+     */
+    Field getField();
+
+    /**
+     * The class in which the property (or public field) is defined.
+     *
+     * @since 5.2
+     */
+    Class getDeclaringClass();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java b/commons/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java
new file mode 100644
index 0000000..ec8eaad
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java
@@ -0,0 +1,88 @@
+// Copyright 2006, 2007, 2008, 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.services;
+
+import org.apache.tapestry5.ioc.annotations.UsesConfiguration;
+
+/**
+ * Makes use of {@link org.apache.tapestry5.ioc.services.Coercion}s to convert between an input value (of some specific
+ * type) and a desired output type. Smart about coercing, even if it requires multiple coercion steps (i.e., via an
+ * intermediate type, such as String).
+ */
+@UsesConfiguration(CoercionTuple.class)
+public interface TypeCoercer
+{
+    /**
+     * Performs a coercion from an input type to a desired output type. When the target type is a primitive, the actual
+     * conversion will be to the equivalent wrapper type. In some cases, the TypeCoercer will need to search for an
+     * appropriate coercion, and may even combine existing coercions to form new ones; in those cases, the results of
+     * the search are cached.
+     * <p/>
+     * The TypeCoercer also caches the results of a coercion search.
+     * 
+     * @param <S>
+     *            source type (input)
+     * @param <T>
+     *            target type (output)
+     * @param input
+     * @param targetType
+     *            defines the target type
+     * @return the coerced value
+     * @throws RuntimeException
+     *             if the input can not be coerced
+     */
+    <S, T> T coerce(S input, Class<T> targetType);
+
+    /**
+     * Given a source and target type, computes the coercion that will be used.
+     * <p>
+     * Note: holding the returned coercion past the time when {@linkplain #clearCache() the cache is cleared} can cause
+     * a memory leak, especially in the context of live reloading (wherein holding a reference to a single class make
+     * keep an entire ClassLoader from being reclaimed).
+     * 
+     * @since 5.2.0
+     * @param <S>
+     *            source type (input)
+     * @param <T>
+     *            target type (output)
+     * @param sourceType
+     *            type to coerce from
+     * @param targetType
+     *            defines the target type
+     * @return the coercion that will ultimately be used
+     */
+    <S, T> Coercion<S, T> getCoercion(Class<S> sourceType, Class<T> targetType);
+
+    /**
+     * Used primarily inside test suites, this method performs the same steps as {@link #coerce(Object, Class)}, but
+     * returns a string describing the series of coercions, such as "Object --&gt; String --&gt; Long --&gt; Integer".
+     * 
+     * @param <S>
+     *            source type (input)
+     * @param <T>
+     *            target type (output)
+     * @param sourceType
+     *            the source coercion type (use void.class for coercions from null)
+     * @param targetType
+     *            defines the target type
+     * @return a string identifying the series of coercions, or the empty string if no coercion is necessary
+     */
+    <S, T> String explain(Class<S> sourceType, Class<T> targetType);
+
+    /**
+     * Clears cached information stored by the TypeCoercer.
+     */
+    void clearCache();
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
new file mode 100644
index 0000000..c4c5c6d
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
@@ -0,0 +1,87 @@
+// Copyright 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.util;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+
+/**
+ * Used (as part of a {@link UnknownValueException} to identify what available values
+ * are present.
+ * 
+ * @since 5.2.0
+ */
+public class AvailableValues
+{
+    private final String valueType;
+
+    private final List<String> values;
+
+    /**
+     * @param valueType
+     *            a word or phrase that describes what the values are such as "component types" or "service ids"
+     *@param values
+     *            a set of objects defining the values; the values will be converted to strings and sorted into
+     *            ascending order
+     */
+    public AvailableValues(String valueType, Collection<?> values)
+    {
+        this.valueType = valueType;
+        this.values = sortValues(values);
+    }
+
+    public AvailableValues(String valueType, Map<?, ?> map)
+    {
+        this(valueType, map.keySet());
+    }
+
+    private static List<String> sortValues(Collection<?> values)
+    {
+        List<String> result = CollectionFactory.newList();
+
+        for (Object v : values)
+        {
+            result.add(String.valueOf(v));
+        }
+
+        Collections.sort(result);
+
+        return Collections.unmodifiableList(result);
+    }
+
+    /** The type of value, i.e., "component types" or "service ids". */
+    public String getValueType()
+    {
+        return valueType;
+    }
+
+    /** The values, as strings, in sorted order. */
+    public List<String> getValues()
+    {
+        return values;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("AvailableValues[%s: %s]", valueType, InternalUtils.join(values));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java
new file mode 100644
index 0000000..f5aff7e
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java
@@ -0,0 +1,499 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.ioc.util;
+
+import java.io.Serializable;
+import java.util.*;
+
+/**
+ * An mapped collection where the keys are always strings and access to values is case-insensitive. The case of keys in
+ * the map is <em>maintained</em>, but on any access to a key (directly or indirectly), all key comparisons are
+ * performed in a case-insensitive manner. The map implementation is intended to support a reasonably finite number
+ * (dozens or hundreds, not thousands or millions of key/value pairs. Unlike HashMap, it is based on a sorted list of
+ * entries rather than hash bucket. It is also geared towards a largely static map, one that is created and then used
+ * without modification.
+ *
+ * @param <V> the type of value stored
+ */
+public class CaseInsensitiveMap<V> extends AbstractMap<String, V> implements Serializable
+{
+    private static final long serialVersionUID = 3362718337611953298L;
+
+    private static final int NULL_HASH = Integer.MIN_VALUE;
+
+    private static final int DEFAULT_SIZE = 20;
+
+    private static class CIMEntry<V> implements Map.Entry<String, V>, Serializable
+    {
+        private static final long serialVersionUID = 6713986085221148350L;
+
+        private String key;
+
+        private final int hashCode;
+
+        V value;
+
+        public CIMEntry(final String key, final int hashCode, V value)
+        {
+            this.key = key;
+            this.hashCode = hashCode;
+            this.value = value;
+        }
+
+        @Override
+        public String getKey()
+        {
+            return key;
+        }
+
+        @Override
+        public V getValue()
+        {
+            return value;
+        }
+
+        @Override
+        public V setValue(V value)
+        {
+            V result = this.value;
+
+            this.value = value;
+
+            return result;
+        }
+
+        /**
+         * Returns true if both keys are null, or if the provided key is the same as, or case-insensitively equal to,
+         * the entrie's key.
+         *
+         * @param key to compare against
+         * @return true if equal
+         */
+        @SuppressWarnings({ "StringEquality" })
+        boolean matches(String key)
+        {
+            return key == this.key || (key != null && key.equalsIgnoreCase(this.key));
+        }
+
+        boolean valueMatches(Object value)
+        {
+            return value == this.value || (value != null && value.equals(this.value));
+        }
+    }
+
+    private class EntrySetIterator implements Iterator
+    {
+        int expectedModCount = modCount;
+
+        int index;
+
+        int current = -1;
+
+        @Override
+        public boolean hasNext()
+        {
+            return index < size;
+        }
+
+        @Override
+        public Object next()
+        {
+            check();
+
+            if (index >= size) throw new NoSuchElementException();
+
+            current = index++;
+
+            return entries[current];
+        }
+
+        @Override
+        public void remove()
+        {
+            check();
+
+            if (current < 0) throw new NoSuchElementException();
+
+            new Position(current, true).remove();
+
+            expectedModCount = modCount;
+        }
+
+        private void check()
+        {
+            if (expectedModCount != modCount) throw new ConcurrentModificationException();
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private class EntrySet extends AbstractSet
+    {
+        @Override
+        public Iterator iterator()
+        {
+            return new EntrySetIterator();
+        }
+
+        @Override
+        public int size()
+        {
+            return size;
+        }
+
+        @Override
+        public void clear()
+        {
+            CaseInsensitiveMap.this.clear();
+        }
+
+        @Override
+        public boolean contains(Object o)
+        {
+            if (!(o instanceof Map.Entry)) return false;
+
+            Map.Entry e = (Map.Entry) o;
+
+            Position position = select(e.getKey());
+
+            return position.isFound() && position.entry().valueMatches(e.getValue());
+        }
+
+        @Override
+        public boolean remove(Object o)
+        {
+            if (!(o instanceof Map.Entry)) return false;
+
+            Map.Entry e = (Map.Entry) o;
+
+            Position position = select(e.getKey());
+
+            if (position.isFound() && position.entry().valueMatches(e.getValue()))
+            {
+                position.remove();
+                return true;
+            }
+
+            return false;
+        }
+
+    }
+
+    private class Position
+    {
+        private final int cursor;
+
+        private final boolean found;
+
+        Position(int cursor, boolean found)
+        {
+            this.cursor = cursor;
+            this.found = found;
+        }
+
+        boolean isFound()
+        {
+            return found;
+        }
+
+        CIMEntry<V> entry()
+        {
+            return entries[cursor];
+        }
+
+        V get()
+        {
+            return found ? entries[cursor].value : null;
+        }
+
+        V remove()
+        {
+            if (!found) return null;
+
+            V result = entries[cursor].value;
+
+            // Remove the entry by shifting everything else down.
+
+            System.arraycopy(entries, cursor + 1, entries, cursor, size - cursor - 1);
+
+            // We shifted down, leaving one (now duplicate) entry behind.
+
+            entries[--size] = null;
+
+            // A structural change for sure
+
+            modCount++;
+
+            return result;
+        }
+
+        @SuppressWarnings("unchecked")
+        V put(String key, int hashCode, V newValue)
+        {
+            if (found)
+            {
+                CIMEntry<V> e = entries[cursor];
+
+                V result = e.value;
+
+                // Not a structural change, so no change to modCount
+
+                // Update the key (to maintain case). By definition, the hash code
+                // will not change.
+
+                e.key = key;
+                e.value = newValue;
+
+                return result;
+            }
+
+            // Not found, we're going to add it.
+
+            int newSize = size + 1;
+
+            if (newSize == entries.length)
+            {
+                // Time to expand!
+
+                int newCapacity = (size * 3) / 2 + 1;
+
+                CIMEntry<V>[] newEntries = new CIMEntry[newCapacity];
+
+                System.arraycopy(entries, 0, newEntries, 0, cursor);
+
+                System.arraycopy(entries, cursor, newEntries, cursor + 1, size - cursor);
+
+                entries = newEntries;
+            }
+            else
+            {
+                // Open up a space for the new entry
+
+                System.arraycopy(entries, cursor, entries, cursor + 1, size - cursor);
+            }
+
+            CIMEntry<V> newEntry = new CIMEntry<V>(key, hashCode, newValue);
+            entries[cursor] = newEntry;
+
+            size++;
+
+            // This is definately a structural change
+
+            modCount++;
+
+            return null;
+        }
+
+    }
+
+    // The list of entries. This is kept sorted by hash code. In some cases, there may be different
+    // keys with the same hash code in adjacent indexes.
+    private CIMEntry<V>[] entries;
+
+    private int size = 0;
+
+    // Used by iterators to check for concurrent modifications
+
+    private transient int modCount = 0;
+
+    private transient Set<Map.Entry<String, V>> entrySet;
+
+    public CaseInsensitiveMap()
+    {
+        this(DEFAULT_SIZE);
+    }
+
+    @SuppressWarnings("unchecked")
+    public CaseInsensitiveMap(int size)
+    {
+        entries = new CIMEntry[Math.max(size, 3)];
+    }
+
+    public CaseInsensitiveMap(Map<String, ? extends V> map)
+    {
+        this(map.size());
+
+        for (Map.Entry<String, ? extends V> entry : map.entrySet())
+        {
+            put(entry.getKey(), entry.getValue());
+        }
+    }
+
+    @Override
+    public void clear()
+    {
+        for (int i = 0; i < size; i++)
+            entries[i] = null;
+
+        size = 0;
+        modCount++;
+    }
+
+    @Override
+    public boolean isEmpty()
+    {
+        return size == 0;
+    }
+
+    @Override
+    public int size()
+    {
+        return size;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public V put(String key, V value)
+    {
+        int hashCode = caseInsenitiveHashCode(key);
+
+        return select(key, hashCode).put(key, hashCode, value);
+    }
+
+    @Override
+    public boolean containsKey(Object key)
+    {
+        return select(key).isFound();
+    }
+
+    @Override
+    public V get(Object key)
+    {
+        return select(key).get();
+    }
+
+    @Override
+    public V remove(Object key)
+    {
+        return select(key).remove();
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public Set<Map.Entry<String, V>> entrySet()
+    {
+        if (entrySet == null) entrySet = new EntrySet();
+
+        return entrySet;
+    }
+
+    private Position select(Object key)
+    {
+        if (key == null || key instanceof String)
+        {
+            String keyString = (String) key;
+            return select(keyString, caseInsenitiveHashCode(keyString));
+        }
+
+        return new Position(0, false);
+    }
+
+    /**
+     * Searches the elements for the index of the indicated key and (case insensitive) hash code. Sets the _cursor and
+     * _found attributes.
+     */
+    private Position select(String key, int hashCode)
+    {
+        if (size == 0) return new Position(0, false);
+
+        int low = 0;
+        int high = size - 1;
+
+        int cursor;
+
+        while (low <= high)
+        {
+            cursor = (low + high) >> 1;
+
+            CIMEntry e = entries[cursor];
+
+            if (e.hashCode < hashCode)
+            {
+                low = cursor + 1;
+                continue;
+            }
+
+            if (e.hashCode > hashCode)
+            {
+                high = cursor - 1;
+                continue;
+            }
+
+            return tunePosition(key, hashCode, cursor);
+        }
+
+        return new Position(low, false);
+    }
+
+    /**
+     * select() has located a matching hashCode, but there's an outlying possibility that multiple keys share the same
+     * hashCode. Backup the cursor until we get to locate the initial hashCode match, then march forward until the key
+     * is located, or the hashCode stops matching.
+     *
+     * @param key
+     * @param hashCode
+     */
+    private Position tunePosition(String key, int hashCode, int cursor)
+    {
+        boolean found = false;
+
+        while (cursor > 0)
+        {
+            if (entries[cursor - 1].hashCode != hashCode) break;
+
+            cursor--;
+        }
+
+        while (true)
+        {
+            if (entries[cursor].matches(key))
+            {
+                found = true;
+                break;
+            }
+
+            // Advance to the next entry.
+
+            cursor++;
+
+            // If out of entries,
+            if (cursor >= size || entries[cursor].hashCode != hashCode) break;
+        }
+
+        return new Position(cursor, found);
+    }
+
+    static int caseInsenitiveHashCode(String input)
+    {
+        if (input == null) return NULL_HASH;
+
+        int length = input.length();
+        int hash = 0;
+
+        // This should end up more or less equal to input.toLowerCase().hashCode(), unless String
+        // changes its implementation. Let's hope this is reasonably fast.
+
+        for (int i = 0; i < length; i++)
+        {
+            int ch = input.charAt(i);
+
+            int caselessCh = Character.toLowerCase(ch);
+
+            hash = 31 * hash + caselessCh;
+        }
+
+        return hash;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/util/ExceptionUtils.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/ExceptionUtils.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/ExceptionUtils.java
new file mode 100644
index 0000000..2feaeca
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/ExceptionUtils.java
@@ -0,0 +1,115 @@
+// Copyright 2008-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.util;
+
+import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
+import org.apache.tapestry5.ioc.services.PropertyAccess;
+
+/**
+ * Contains static methods useful for manipulating exceptions.
+ */
+public class ExceptionUtils
+{
+    /**
+     * Locates a particular type of exception, working its way via the cause property of each exception in the exception
+     * stack.
+     *
+     * @param t    the outermost exception
+     * @param type the type of exception to search for
+     * @return the first exception of the given type, if found, or null
+     */
+    public static <T extends Throwable> T findCause(Throwable t, Class<T> type)
+    {
+        Throwable current = t;
+
+        while (current != null)
+        {
+            if (type.isInstance(current))
+            {
+                return type.cast(current);
+            }
+
+            // Not a match, work down.
+
+            current = current.getCause();
+        }
+
+        return null;
+    }
+
+    /**
+     * Locates a particular type of exception, working its way down via any property that returns some type of Exception.
+     * This is more expensive, but more accurate, than {@link #findCause(Throwable, Class)} as it works with older exceptions
+     * that do not properly implement the (relatively new) {@linkplain Throwable#getCause() cause property}.
+     *
+     * @param t      the outermost exception
+     * @param type   the type of exception to search for
+     * @param access used to access properties
+     * @return the first exception of the given type, if found, or null
+     */
+    public static <T extends Throwable> T findCause(Throwable t, Class<T> type, PropertyAccess access)
+    {
+        Throwable current = t;
+
+        while (current != null)
+        {
+            if (type.isInstance(current))
+            {
+                return type.cast(current);
+            }
+
+            Throwable next = null;
+
+            ClassPropertyAdapter adapter = access.getAdapter(current);
+
+            for (String name : adapter.getPropertyNames())
+            {
+
+                Object value = adapter.getPropertyAdapter(name).get(current);
+
+                if (value != null && value != current && value instanceof Throwable)
+                {
+                    next = (Throwable) value;
+                    break;
+                }
+            }
+
+            current = next;
+        }
+
+
+        return null;
+    }
+
+    /**
+     * Extracts the message from an exception. If the exception's message is null, returns the exceptions class name.
+     *
+     * @param exception
+     *         to extract message from
+     * @return message or class name
+     * @since 5.4
+     */
+    public static String toMessage(Throwable exception)
+    {
+        assert exception != null;
+
+        String message = exception.getMessage();
+
+        if (message != null)
+            return message;
+
+        return exception.getClass().getName();
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/util/UnknownValueException.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/UnknownValueException.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/UnknownValueException.java
new file mode 100644
index 0000000..470b611
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/UnknownValueException.java
@@ -0,0 +1,47 @@
+// Copyright 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.util;
+
+import org.apache.tapestry5.ioc.internal.util.TapestryException;
+
+/**
+ * Special exception used when a value (typically from a map) is referenced that does not exist. Uses a
+ * {@link AvailableValues} object
+ * to track what the known values are.
+ * 
+ * @since 5.2.0
+ */
+public class UnknownValueException extends TapestryException
+{
+    private final AvailableValues availableValues;
+
+    public UnknownValueException(String message, AvailableValues availableValues)
+    {
+        this(message, null, null, availableValues);
+    }
+
+    public UnknownValueException(String message, Object location, Throwable cause, AvailableValues availableValues)
+    {
+        super(message, location, cause);
+
+        this.availableValues = availableValues;
+    }
+
+    public AvailableValues getAvailableValues()
+    {
+        return availableValues;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java b/commons/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java
new file mode 100644
index 0000000..77b028e
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java
@@ -0,0 +1,60 @@
+// Copyright 2006, 2007, 2008, 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.services;
+
+import java.util.Map;
+
+/**
+ * An object which manages a list of {@link org.apache.tapestry5.services.InvalidationListener}s. There are multiple
+ * event hub services implementing this interface, each with a specific marker annotation; each can register listeners
+ * and fire events; these are based on the type of resource that has been invalidated. Tapestry has built-in support
+ * for:
+ * <dl>
+ * <dt>message catalog resources
+ * <dd>{@link org.apache.tapestry5.services.ComponentMessages} marker annotation
+ * <dt>component templates
+ * <dd>{@link org.apache.tapestry5.services.ComponentTemplates} marker annotation
+ * <dt>component classes
+ * <dd>{@link org.apache.tapestry5.services.ComponentClasses} marker annotation
+ * </dl>
+ * <p/>
+ * Starting in Tapestry 5.3, these services are disabled in production (it does nothing).
+ *
+ * @since 5.1.0.0
+ */
+public interface InvalidationEventHub
+{
+    /**
+     * Adds a listener, who needs to know when an underlying resource of a given category has changed (so that the
+     * receiver may discard any cached data that may have been invalidated). Does nothing in production mode.
+     *
+     * @deprecated in 5.4, use {@link #addInvalidationCallback(Runnable)} instead}
+     */
+    void addInvalidationListener(InvalidationListener listener);
+
+    /**
+     * Adds a callback that is invoked when an underlying tracked resource has changed. Does nothing in production mode.
+     *
+     * @since  5.4
+     */
+    void addInvalidationCallback(Runnable callback);
+
+    /**
+     * Adds a callback that clears the map.
+     *
+     * @since 5.4
+     */
+    void clearOnInvalidation(Map<?,?> map);
+}


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

Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java
deleted file mode 100644
index 9151381..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java
+++ /dev/null
@@ -1,84 +0,0 @@
-// 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/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java
deleted file mode 100644
index 2acfd0d..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java
+++ /dev/null
@@ -1,46 +0,0 @@
-// 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);
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java
deleted file mode 100644
index 49b0b15..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java
+++ /dev/null
@@ -1,59 +0,0 @@
-// 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.util.List;
-
-/**
- * Chain of command for {@link org.apache.tapestry5.ioc.AnnotationProvider}.
- */
-public class AnnotationProviderChain implements AnnotationProvider
-{
-    private final AnnotationProvider[] providers;
-
-    public AnnotationProviderChain(AnnotationProvider[] providers)
-    {
-        this.providers = providers;
-    }
-
-    /**
-     * Creates an AnnotationProvider from the list of providers.  Returns either an {@link AnnotationProviderChain} or
-     * the sole element in the list.
-     */
-    public static AnnotationProvider create(List<AnnotationProvider> providers)
-    {
-        int size = providers.size();
-
-        if (size == 1) return providers.get(0);
-
-        return new AnnotationProviderChain(providers.toArray(new AnnotationProvider[providers.size()]));
-    }
-
-    @Override
-    public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
-    {
-        for (AnnotationProvider p : providers)
-        {
-            T result = p.getAnnotation(annotationClass);
-
-            if (result != null) return result;
-        }
-
-        return null;
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
deleted file mode 100644
index af4bd7d..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
+++ /dev/null
@@ -1,250 +0,0 @@
-// 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.ArrayList;
-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.InternalUtils;
-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 = InternalUtils.joinSorted(adapters.keySet());
-
-        return String.format("<ClassPropertyAdaptor %s: %s>", beanType.getName(), names);
-    }
-
-    @Override
-    public List<String> getPropertyNames()
-    {
-        return InternalUtils.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/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java
deleted file mode 100644
index 4a5dece..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2006, 2007 The Apache Software Foundation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.apache.tapestry5.ioc.internal.services;
-
-import org.apache.tapestry5.ioc.services.Coercion;
-
-/**
- * Combines two coercions to create a coercion through an intermediate type.
- *
- * @param <S> The source (input) type
- * @param <I> The intermediate type
- * @param <T> The target (output) type
- */
-public class CompoundCoercion<S, I, T> implements Coercion<S, T>
-{
-    private final Coercion<S, I> op1;
-
-    private final Coercion<I, T> op2;
-
-    public CompoundCoercion(Coercion<S, I> op1, Coercion<I, T> op2)
-    {
-        this.op1 = op1;
-        this.op2 = op2;
-    }
-
-    @Override
-    public T coerce(S input)
-    {
-        // Run the input through the first operation (S --> I), then run the result of that through
-        // the second operation (I --> T).
-
-        I intermediate = op1.coerce(input);
-
-        return op2.coerce(intermediate);
-    }
-
-    @Override
-    public String toString()
-    {
-        return String.format("%s, %s", op1, op2);
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java
deleted file mode 100644
index 8ebdede..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java
+++ /dev/null
@@ -1,47 +0,0 @@
-// 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/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
deleted file mode 100644
index 112e29d..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
+++ /dev/null
@@ -1,286 +0,0 @@
-// 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.annotations.IncompatibleChange;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-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 InternalUtils.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 InternalUtils.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/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java
deleted file mode 100644
index 8dd1e02..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java
+++ /dev/null
@@ -1,217 +0,0 @@
-// 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/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
deleted file mode 100644
index 97685ef..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
+++ /dev/null
@@ -1,273 +0,0 @@
-// 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/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
deleted file mode 100644
index e92ef2d..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2006, 2007, 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.ioc.Messages;
-import org.apache.tapestry5.ioc.internal.util.MessagesImpl;
-import org.apache.tapestry5.ioc.services.Coercion;
-import org.apache.tapestry5.plastic.PlasticUtils;
-
-public class ServiceMessages
-{
-    private final static Messages MESSAGES = MessagesImpl.forClass(ServiceMessages.class);
-
-    private ServiceMessages()
-    {
-    }
-
-    public static String noSuchProperty(Class clazz, String propertyName)
-    {
-        return MESSAGES.format("no-such-property", clazz.getName(), propertyName);
-    }
-
-
-    public static String readFailure(String propertyName, Object instance, Throwable cause)
-    {
-        return MESSAGES.format("read-failure", propertyName, instance, cause);
-    }
-
-    public static String propertyTypeMismatch(String propertyName, Class sourceClass, Class propertyType,
-                                              Class expectedType)
-    {
-        return MESSAGES.format("property-type-mismatch", propertyName, sourceClass.getName(), propertyType.getName(),
-                expectedType.getName());
-    }
-
-    public static String shutdownListenerError(Object listener, Throwable cause)
-    {
-        return MESSAGES.format("shutdown-listener-error", listener, cause);
-    }
-
-    public static String failedCoercion(Object input, Class targetType, Coercion coercion, Throwable cause)
-    {
-        return MESSAGES.format("failed-coercion", String.valueOf(input), PlasticUtils.toTypeName(targetType),
-                coercion, cause);
-    }
-
-    public static String registryShutdown(String serviceId)
-    {
-        return MESSAGES.format("registry-shutdown", serviceId);
-    }
-
-    public static String serviceBuildFailure(String serviceId, Throwable cause)
-    {
-        return MESSAGES.format("service-build-failure", serviceId, cause);
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java
deleted file mode 100644
index 0769b7e..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2007 The Apache Software Foundation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.apache.tapestry5.ioc.internal.services;
-
-import org.apache.tapestry5.ioc.Location;
-import org.apache.tapestry5.ioc.Resource;
-
-/**
- * Implementation of {@link Location} used when the underlying resource isn't really known.
- */
-public final class StringLocation implements Location
-{
-    private final String description;
-
-    private final int line;
-
-    public StringLocation(String description, int line)
-    {
-        this.description = description;
-        this.line = line;
-    }
-
-    @Override
-    public String toString()
-    {
-        return description;
-    }
-
-    /**
-     * Returns 0.
-     */
-    @Override
-    public int getColumn()
-    {
-        return 0;
-    }
-
-    @Override
-    public int getLine()
-    {
-        return line;
-    }
-
-    /**
-     * Returns null; we don't know where the file really is (it's probably a class on the class path).
-     */
-    @Override
-    public Resource getResource()
-    {
-        return null;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
deleted file mode 100644
index 46f1c0a..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
+++ /dev/null
@@ -1,508 +0,0 @@
-// Copyright 2006, 2007, 2008, 2010, 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.func.F;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InheritanceSearch;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.ioc.internal.util.LockSupport;
-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.AvailableValues;
-import org.apache.tapestry5.ioc.util.UnknownValueException;
-import org.apache.tapestry5.plastic.PlasticUtils;
-import org.apache.tapestry5.util.StringToEnumCoercion;
-
-import java.util.*;
-
-@SuppressWarnings("all")
-public class TypeCoercerImpl extends LockSupport implements TypeCoercer
-{
-    // Constructed from the service's configuration.
-
-    private final Map<Class, List<CoercionTuple>> sourceTypeToTuple = CollectionFactory.newMap();
-
-    /**
-     * A coercion to a specific target type. Manages a cache of coercions to specific types.
-     */
-    private class TargetCoercion
-    {
-        private final Class type;
-
-        private final Map<Class, Coercion> cache = CollectionFactory.newConcurrentMap();
-
-        TargetCoercion(Class type)
-        {
-            this.type = type;
-        }
-
-        void clearCache()
-        {
-            cache.clear();
-        }
-
-        Object coerce(Object input)
-        {
-            Class sourceType = input != null ? input.getClass() : Void.class;
-
-            if (type.isAssignableFrom(sourceType))
-            {
-                return input;
-            }
-
-            Coercion c = getCoercion(sourceType);
-
-            try
-            {
-                return type.cast(c.coerce(input));
-            } catch (Exception ex)
-            {
-                throw new RuntimeException(ServiceMessages.failedCoercion(input, type, c, ex), ex);
-            }
-        }
-
-        String explain(Class sourceType)
-        {
-            return getCoercion(sourceType).toString();
-        }
-
-        private Coercion getCoercion(Class sourceType)
-        {
-            Coercion c = cache.get(sourceType);
-
-            if (c == null)
-            {
-                c = findOrCreateCoercion(sourceType, type);
-                cache.put(sourceType, c);
-            }
-
-            return c;
-        }
-    }
-
-    /**
-     * Map from a target type to a TargetCoercion for that type.
-     */
-    private final Map<Class, TargetCoercion> typeToTargetCoercion = new WeakHashMap<Class, TargetCoercion>();
-
-    private static final Coercion NO_COERCION = new Coercion<Object, Object>()
-    {
-        @Override
-        public Object coerce(Object input)
-        {
-            return input;
-        }
-    };
-
-    private static final Coercion COERCION_NULL_TO_OBJECT = new Coercion<Void, Object>()
-    {
-        @Override
-        public Object coerce(Void input)
-        {
-            return null;
-        }
-
-        @Override
-        public String toString()
-        {
-            return "null --> null";
-        }
-    };
-
-    public TypeCoercerImpl(Collection<CoercionTuple> tuples)
-    {
-        for (CoercionTuple tuple : tuples)
-        {
-            Class key = tuple.getSourceType();
-
-            InternalUtils.addToMapList(sourceTypeToTuple, key, tuple);
-        }
-    }
-
-    @Override
-    @SuppressWarnings("unchecked")
-    public Object coerce(Object input, Class targetType)
-    {
-        assert targetType != null;
-
-        Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
-
-        if (effectiveTargetType.isInstance(input))
-        {
-            return input;
-        }
-
-
-        return getTargetCoercion(effectiveTargetType).coerce(input);
-    }
-
-    @Override
-    @SuppressWarnings("unchecked")
-    public <S, T> Coercion<S, T> getCoercion(Class<S> sourceType, Class<T> targetType)
-    {
-        assert sourceType != null;
-        assert targetType != null;
-
-        Class effectiveSourceType = PlasticUtils.toWrapperType(sourceType);
-        Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
-
-        if (effectiveTargetType.isAssignableFrom(effectiveSourceType))
-        {
-            return NO_COERCION;
-        }
-
-        return getTargetCoercion(effectiveTargetType).getCoercion(effectiveSourceType);
-    }
-
-    @Override
-    @SuppressWarnings("unchecked")
-    public <S, T> String explain(Class<S> sourceType, Class<T> targetType)
-    {
-        assert sourceType != null;
-        assert targetType != null;
-
-        Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
-        Class effectiveSourceType = PlasticUtils.toWrapperType(sourceType);
-
-        // Is a coercion even necessary? Not if the target type is assignable from the
-        // input value.
-
-        if (effectiveTargetType.isAssignableFrom(effectiveSourceType))
-        {
-            return "";
-        }
-
-        return getTargetCoercion(effectiveTargetType).explain(effectiveSourceType);
-    }
-
-    private TargetCoercion getTargetCoercion(Class targetType)
-    {
-        try
-        {
-            acquireReadLock();
-
-            TargetCoercion tc = typeToTargetCoercion.get(targetType);
-
-            return tc != null ? tc : createAndStoreNewTargetCoercion(targetType);
-        } finally
-        {
-            releaseReadLock();
-        }
-    }
-
-    private TargetCoercion createAndStoreNewTargetCoercion(Class targetType)
-    {
-        try
-        {
-            upgradeReadLockToWriteLock();
-
-            // Inner check since some other thread may have beat us to it.
-
-            TargetCoercion tc = typeToTargetCoercion.get(targetType);
-
-            if (tc == null)
-            {
-                tc = new TargetCoercion(targetType);
-                typeToTargetCoercion.put(targetType, tc);
-            }
-
-            return tc;
-        } finally
-        {
-            downgradeWriteLockToReadLock();
-        }
-    }
-
-    @Override
-    public void clearCache()
-    {
-        try
-        {
-            acquireReadLock();
-
-            // There's no need to clear the typeToTargetCoercion map, as it is a WeakHashMap and
-            // will release the keys for classes that are no longer in existence. On the other hand,
-            // there's likely all sorts of references to unloaded classes inside each TargetCoercion's
-            // individual cache, so clear all those.
-
-            for (TargetCoercion tc : typeToTargetCoercion.values())
-            {
-                // Can tc ever be null?
-
-                tc.clearCache();
-            }
-        } finally
-        {
-            releaseReadLock();
-        }
-    }
-
-    /**
-     * Here's the real meat; we do a search of the space to find coercions, or a system of
-     * coercions, that accomplish
-     * the desired coercion.
-     * <p/>
-     * There's <strong>TREMENDOUS</strong> room to improve this algorithm. For example, inheritance lists could be
-     * cached. Further, there's probably more ways to early prune the search. However, even with dozens or perhaps
-     * hundreds of tuples, I suspect the search will still grind to a conclusion quickly.
-     * <p/>
-     * The order of operations should help ensure that the most efficient tuple chain is located. If you think about how
-     * tuples are added to the queue, there are two factors: size (the number of steps in the coercion) and
-     * "class distance" (that is, number of steps up the inheritance hiearchy). All the appropriate 1 step coercions
-     * will be considered first, in class distance order. Along the way, we'll queue up all the 2 step coercions, again
-     * in class distance order. By the time we reach some of those, we'll have begun queueing up the 3 step coercions, and
-     * so forth, until we run out of input tuples we can use to fabricate multi-step compound coercions, or reach a
-     * final response.
-     * <p/>
-     * This does create a good number of short lived temporary objects (the compound tuples), but that's what the GC is
-     * really good at.
-     *
-     * @param sourceType
-     * @param targetType
-     * @return coercer from sourceType to targetType
-     */
-    @SuppressWarnings("unchecked")
-    private Coercion findOrCreateCoercion(Class sourceType, Class targetType)
-    {
-        if (sourceType == Void.class)
-        {
-            return searchForNullCoercion(targetType);
-        }
-
-        // These are instance variables because this method may be called concurrently.
-        // On a true race, we may go to the work of seeking out and/or fabricating
-        // a tuple twice, but it's more likely that different threads are looking
-        // for different source/target coercions.
-
-        Set<CoercionTuple> consideredTuples = CollectionFactory.newSet();
-        LinkedList<CoercionTuple> queue = CollectionFactory.newLinkedList();
-
-        seedQueue(sourceType, targetType, consideredTuples, queue);
-
-        while (!queue.isEmpty())
-        {
-            CoercionTuple tuple = queue.removeFirst();
-
-            // If the tuple results in a value type that is assignable to the desired target type,
-            // we're done! Later, we may add a concept of "cost" (i.e. number of steps) or
-            // "quality" (how close is the tuple target type to the desired target type). Cost
-            // is currently implicit, as compound tuples are stored deeper in the queue,
-            // so simpler coercions will be located earlier.
-
-            Class tupleTargetType = tuple.getTargetType();
-
-            if (targetType.isAssignableFrom(tupleTargetType))
-            {
-                return tuple.getCoercion();
-            }
-
-            // So .. this tuple doesn't get us directly to the target type.
-            // However, it *may* get us part of the way. Each of these
-            // represents a coercion from the source type to an intermediate type.
-            // Now we're going to look for conversions from the intermediate type
-            // to some other type.
-
-            queueIntermediates(sourceType, targetType, tuple, consideredTuples, queue);
-        }
-
-        // Not found anywhere. Identify the source and target type and a (sorted) list of
-        // all the known coercions.
-
-        throw new UnknownValueException(String.format("Could not find a coercion from type %s to type %s.",
-                sourceType.getName(), targetType.getName()), buildCoercionCatalog());
-    }
-
-    /**
-     * Coercion from null is special; we match based on the target type and its not a spanning
-     * search. In many cases, we
-     * return a pass-thru that leaves the value as null.
-     *
-     * @param targetType
-     *         desired type
-     * @return the coercion
-     */
-    private Coercion searchForNullCoercion(Class targetType)
-    {
-        List<CoercionTuple> tuples = getTuples(Void.class, targetType);
-
-        for (CoercionTuple tuple : tuples)
-        {
-            Class tupleTargetType = tuple.getTargetType();
-
-            if (targetType.equals(tupleTargetType))
-                return tuple.getCoercion();
-        }
-
-        // Typical case: no match, this coercion passes the null through
-        // as null.
-
-        return COERCION_NULL_TO_OBJECT;
-    }
-
-    /**
-     * Builds a string listing all the coercions configured for the type coercer, sorted
-     * alphabetically.
-     */
-    @SuppressWarnings("unchecked")
-    private AvailableValues buildCoercionCatalog()
-    {
-        List<CoercionTuple> masterList = CollectionFactory.newList();
-
-        for (List<CoercionTuple> list : sourceTypeToTuple.values())
-        {
-            masterList.addAll(list);
-        }
-
-        return new AvailableValues("Configured coercions", masterList);
-    }
-
-    /**
-     * Seeds the pool with the initial set of coercions for the given type.
-     */
-    private void seedQueue(Class sourceType, Class targetType, Set<CoercionTuple> consideredTuples,
-                           LinkedList<CoercionTuple> queue)
-    {
-        // Work from the source type up looking for tuples
-
-        for (Class c : new InheritanceSearch(sourceType))
-        {
-            List<CoercionTuple> tuples = getTuples(c, targetType);
-
-            if (tuples == null)
-            {
-                continue;
-            }
-
-            for (CoercionTuple tuple : tuples)
-            {
-                queue.addLast(tuple);
-                consideredTuples.add(tuple);
-            }
-
-            // Don't pull in Object -> type coercions when doing
-            // a search from null.
-
-            if (sourceType == Void.class)
-            {
-                return;
-            }
-        }
-    }
-
-    /**
-     * Creates and adds to the pool a new set of coercions based on an intermediate tuple. Adds
-     * compound coercion tuples
-     * to the end of the queue.
-     *
-     * @param sourceType
-     *         the source type of the coercion
-     * @param targetType
-     *         TODO
-     * @param intermediateTuple
-     *         a tuple that converts from the source type to some intermediate type (that is not
-     *         assignable to the target type)
-     * @param consideredTuples
-     *         set of tuples that have already been added to the pool (directly, or as a compound
-     *         coercion)
-     * @param queue
-     *         the work queue of tuples
-     */
-    @SuppressWarnings("unchecked")
-    private void queueIntermediates(Class sourceType, Class targetType, CoercionTuple intermediateTuple,
-                                    Set<CoercionTuple> consideredTuples, LinkedList<CoercionTuple> queue)
-    {
-        Class intermediateType = intermediateTuple.getTargetType();
-
-        for (Class c : new InheritanceSearch(intermediateType))
-        {
-            for (CoercionTuple tuple : getTuples(c, targetType))
-            {
-                if (consideredTuples.contains(tuple))
-                {
-                    continue;
-                }
-
-                Class newIntermediateType = tuple.getTargetType();
-
-                // If this tuple is for coercing from an intermediate type back towards our
-                // initial source type, then ignore it. This should only be an optimization,
-                // as branches that loop back towards the source type will
-                // eventually be considered and discarded.
-
-                if (sourceType.isAssignableFrom(newIntermediateType))
-                {
-                    continue;
-                }
-
-                // The intermediateTuple coercer gets from S --> I1 (an intermediate type).
-                // The current tuple's coercer gets us from I2 --> X. where I2 is assignable
-                // from I1 (i.e., I2 is a superclass/superinterface of I1) and X is a new
-                // intermediate type, hopefully closer to our eventual target type.
-
-                Coercion compoundCoercer = new CompoundCoercion(intermediateTuple.getCoercion(), tuple.getCoercion());
-
-                CoercionTuple compoundTuple = new CoercionTuple(sourceType, newIntermediateType, compoundCoercer, false);
-
-                // So, every tuple that is added to the queue can take as input the sourceType.
-                // The target type may be another intermediate type, or may be something
-                // assignable to the target type, which will bring the search to a successful
-                // conclusion.
-
-                queue.addLast(compoundTuple);
-                consideredTuples.add(tuple);
-            }
-        }
-    }
-
-    /**
-     * Returns a non-null list of the tuples from the source type.
-     *
-     * @param sourceType
-     *         used to locate tuples
-     * @param targetType
-     *         used to add synthetic tuples
-     * @return non-null list of tuples
-     */
-    private List<CoercionTuple> getTuples(Class sourceType, Class targetType)
-    {
-        List<CoercionTuple> tuples = sourceTypeToTuple.get(sourceType);
-
-        if (tuples == null)
-        {
-            tuples = Collections.emptyList();
-        }
-
-        // So, when we see String and an Enum type, we add an additional synthetic tuple to the end
-        // of the real list. This is the easiest way to accomplish this is a thread-safe and class-reloading
-        // safe way (i.e., what if the Enum is defined by a class loader that gets discarded?  Don't want to cause
-        // memory leaks by retaining an instance). In any case, there are edge cases where we may create
-        // the tuple unnecessarily (such as when an explicit string-to-enum coercion is part of the TypeCoercer
-        // configuration), but on the whole, this is cheap and works.
-
-        if (sourceType == String.class && Enum.class.isAssignableFrom(targetType))
-        {
-            tuples = extend(tuples, new CoercionTuple(sourceType, targetType, new StringToEnumCoercion(targetType)));
-        }
-
-        return tuples;
-    }
-
-    private static <T> List<T> extend(List<T> list, T extraValue)
-    {
-        return F.flow(list).append(extraValue).toList();
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
deleted file mode 100644
index f1830a7..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright 2006 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.util;
-
-import org.apache.tapestry5.plastic.PlasticUtils;
-
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.Set;
-
-/**
- * Used to search from a particular class up the inheritance hierarchy of extended classes and implemented interfaces.
- * <p/>
- * The search starts with the initial class (provided in the constructor). It progresses up the inheritance chain, but
- * skips java.lang.Object.
- * <p/>
- * Once classes are exhausted, the inheritance hierarchy is searched. This is a breadth-first search, rooted in the
- * interfaces implemented by the initial class at its super classes.
- * <p/>
- * Once all interfaces are exhausted, java.lang.Object is returned (it is always returned last).
- * <p/>
- * Two minor tweak to normal inheritance rules: <ul> <li> Normally, the parent class of an <em>object</em> array is
- * java.lang.Object, which is odd because FooService[] is assignable to Object[]. Thus, we tweak the search so that the
- * effective super class of FooService[] is Object[]. <li> The "super class" of a primtive type is its <em>wrapper type</em>,
- * with the exception of void, whose "super class" is left at its normal value (Object.class) </ul>
- * <p/>
- * This class implements the {@link Iterable} interface, so it can be used directly in a for loop: <code> for (Class
- * search : new InheritanceSearch(startClass)) { ... } </code>
- * <p/>
- * This class is not thread-safe.
- */
-public class InheritanceSearch implements Iterator<Class>, Iterable<Class>
-{
-    private Class searchClass;
-
-    private final Set<Class> addedInterfaces = CollectionFactory.newSet();
-
-    private final LinkedList<Class> interfaceQueue = CollectionFactory.newLinkedList();
-
-    private enum State
-    {
-        CLASS, INTERFACE, DONE
-    }
-
-    private State state;
-
-    public InheritanceSearch(Class searchClass)
-    {
-        this.searchClass = searchClass;
-
-        queueInterfaces(searchClass);
-
-        state = searchClass == Object.class ? State.INTERFACE : State.CLASS;
-    }
-
-    private void queueInterfaces(Class searchClass)
-    {
-        for (Class intf : searchClass.getInterfaces())
-        {
-            if (addedInterfaces.contains(intf)) continue;
-
-            interfaceQueue.addLast(intf);
-            addedInterfaces.add(intf);
-        }
-    }
-
-    @Override
-    public Iterator<Class> iterator()
-    {
-        return this;
-    }
-
-    @Override
-    public boolean hasNext()
-    {
-        return state != State.DONE;
-    }
-
-    @Override
-    public Class next()
-    {
-        switch (state)
-        {
-            case CLASS:
-
-                Class result = searchClass;
-
-                searchClass = parentOf(searchClass);
-
-                if (searchClass == null) state = State.INTERFACE;
-                else queueInterfaces(searchClass);
-
-                return result;
-
-            case INTERFACE:
-
-                if (interfaceQueue.isEmpty())
-                {
-                    state = State.DONE;
-                    return Object.class;
-                }
-
-                Class intf = interfaceQueue.removeFirst();
-
-                queueInterfaces(intf);
-
-                return intf;
-
-            default:
-                throw new IllegalStateException();
-        }
-
-    }
-
-    /**
-     * Returns the parent of the given class. Tweaks inheritance for object arrays. Returns null instead of
-     * Object.class.
-     */
-    private Class parentOf(Class clazz)
-    {
-        if (clazz != void.class && clazz.isPrimitive()) return PlasticUtils.toWrapperType(clazz);
-
-        if (clazz.isArray() && clazz != Object[].class)
-        {
-            Class componentType = clazz.getComponentType();
-
-            while (componentType.isArray()) componentType = componentType.getComponentType();
-
-            if (!componentType.isPrimitive()) return Object[].class;
-        }
-
-        Class parent = clazz.getSuperclass();
-
-        return parent != Object.class ? parent : null;
-    }
-
-    /**
-     * @throws UnsupportedOperationException
-     *         always
-     */
-    @Override
-    public void remove()
-    {
-        throw new UnsupportedOperationException();
-    }
-
-}