Author: hlship
Date: Fri Sep 26 01:22:37 2008
New Revision: 699214

URL: http://svn.apache.org/viewvc?rev=699214&view=rev
Log:
TAP5-231: Unify injection; allow @Inject annotation on fields of service 
implementations

Added:
    
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/util/FieldInjectionViaInject.java
    
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/util/FieldInjectionViaInjectService.java
Modified:
    tapestry/tapestry5/trunk/src/site/apt/index.apt
    
tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/Inject.java
    
tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/InjectService.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/ActionLink.xdoc
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/BeanEditForm.xdoc
    
tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
    
tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry5/hibernate/annotations/CommitAfter.java
    
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ConstructorServiceCreator.java
    
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java
    
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java
    
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
    
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TapestryIOCModule.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/configuration.apt
    tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/decorator.apt
    tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/index.apt
    tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/module.apt
    tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/overview.apt
    tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/provider.apt
    tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/service.apt
    tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/shadow.apt
    
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/util/InternalUtilsTest.java

Modified: tapestry/tapestry5/trunk/src/site/apt/index.apt
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/src/site/apt/index.apt?rev=699214&r1=699213&r2=699214&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/src/site/apt/index.apt (original)
+++ tapestry/tapestry5/trunk/src/site/apt/index.apt Fri Sep 26 01:22:37 2008
@@ -32,26 +32,6 @@
 
  Tapestry is released under the Apache Software Licence 2.0.
 
-Roadmap
-
-  Tapestry is, of course, an open-source project, with all the work coming 
from unpaid volunteers.  That being said, our rough timeline is as follows:
-  
-  * 5.0 Release Candidate in September 2008  
-
-  * 5.0 Final Release shortly thereafter
-
-  * 5.1 development to follow, on a much shorter release schedule
-
-  * ... but we are all open source developers working on our own time and 
schedules are hard to pin down.  Please be patient.  Tapestry 5
-    is increasingly stable.  Further "stable" with Tapestry usually refers to 
names of interfaces and methods, not to code quality,
-    which is always very, very high.
-
-  * We are now finally edging towards a release candidate, with most work 
being documentation, minor bug fixes and modest
-    enhancements. Note that Tapestry team members have been using Tapestry 5 
to build production applications, and those
-    experiences are being applied back to the framework to improve its 
quality: we're finding rough edges and we're
-    smoothing them out.
-     
-  []
 
 Third Party Libraries, Tutorials and Resources
 
@@ -61,6 +41,8 @@
 *--+--+--+
 | <<Name>> | <<Author>> | <<Description>>
 *--+--+--+
+| {{{http://code.google.com/p/tapestry5-appfuse/}AppFuse for Tapestry 5}} |   
Serge Eby | Application template, with basic authentication and Hibernate and 
Spring integration pre-configured |
+*--+--+--+
 | {{{http://equanda.org/equanda-tapestry5/}equanda-tapestry5}} |   Joachim Van 
der Auwera |      Components useful for building enterprise applications. 
Includes Accordion, Tabs, Formtraversal. Amongst other things, these focus on 
easy input of data without the need for a mouse.
 *--+--+--+
 | {{{http://code.google.com/p/gc-tapestry-components/}Godcode Components}} |   
Chris Lewis |         A mixed collection of components providing simple but 
time-saving functionality, as well as more exotic ones; built on top of the 
prototype and script.aculo.us javascript libraries. |
@@ -86,6 +68,10 @@
 
 New And Of Note
 
+  * The Inject and InjectService annotations may now be used on fields of 
service implementations or other
+    objects constructed by the IoC container. In the past, injections only 
occured through method or
+    constructor parameters.
+
   * Tapestry now bundles Prototype version 1.6.0.2.
 
   * New methods have been added to

Modified: 
tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/Inject.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/Inject.java?rev=699214&r1=699213&r2=699214&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/Inject.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/Inject.java
 Fri Sep 26 01:22:37 2008
@@ -15,9 +15,7 @@
 package org.apache.tapestry5.ioc.annotations;
 
 import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.*;
 import java.lang.annotation.Retention;
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 import java.lang.annotation.Target;
@@ -35,6 +33,10 @@
  * This is most often used in conjunction with [EMAIL PROTECTED] 
org.apache.tapestry5.ioc.annotations.Value} annotation when
  * injecting a string, as normally, the String would be matched as the service 
id.
  * <p/>
+ * For service implementations, module classes, and other objects constructed 
via  [EMAIL PROTECTED]
+ * org.apache.tapestry5.ioc.ObjectLocator#autobuild(Class)}, this annotation 
indicates that an injection is desired on
+ * the field, as with fields of a Tapestry component.
+ * <p/>
  * In terms of the IoC container, the Inject annotation is only used on 
parameters to service builder methods (and
  * contributor and decorator methods) and on module class constructors. 
constructors. However, inside Tapestry
  * components (<em>and only inside components</em>), it may be applied to 
fields. On fields that require injection, the
@@ -46,7 +48,7 @@
  * @see org.apache.tapestry5.ioc.ObjectProvider
  */
 @Target(
-        { PARAMETER, FIELD, ElementType.CONSTRUCTOR })
+        {PARAMETER, FIELD, CONSTRUCTOR})
 @Retention(RUNTIME)
 @Documented
 public @interface Inject

Modified: 
tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/InjectService.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/InjectService.java?rev=699214&r1=699213&r2=699214&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/InjectService.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/InjectService.java
 Fri Sep 26 01:22:37 2008
@@ -15,21 +15,24 @@
 package org.apache.tapestry5.ioc.annotations;
 
 import java.lang.annotation.Documented;
+import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.PARAMETER;
 import java.lang.annotation.Retention;
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 import java.lang.annotation.Target;
 
[EMAIL PROTECTED](PARAMETER)
[EMAIL PROTECTED](RUNTIME)
[EMAIL PROTECTED]
+
 /**
- * Annotation used with parameters of service builder methods to identify the 
service to be injected
- * into the service builder method via the parameter. In many cases the
- * [EMAIL PROTECTED] org.apache.tapestry5.ioc.annotations.Inject} annotation 
is more flexible or appropriate.
- *
- *
+ * Annotation used with parameters of service builder methods to identify the 
service to be injected into the service
+ * builder method via the parameter. In many cases the [EMAIL PROTECTED] 
org.apache.tapestry5.ioc.annotations.Inject} annotation is
+ * more flexible or appropriate.
+ * <p/>
+ * This annotation may also be used with fields of service implementation 
classes, modules, or other objects constructed
+ * via [EMAIL PROTECTED] 
org.apache.tapestry5.ioc.ObjectLocator#autobuild(Class)}.
  */
[EMAIL PROTECTED]({PARAMETER, FIELD})
[EMAIL PROTECTED](RUNTIME)
[EMAIL PROTECTED]
 public @interface InjectService
 {
 

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/ActionLink.xdoc
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/ActionLink.xdoc?rev=699214&r1=699213&r2=699214&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/ActionLink.xdoc
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/ActionLink.xdoc
 Fri Sep 26 01:22:37 2008
@@ -13,9 +13,9 @@
                 <source><![CDATA[
 public class Account
 {
-    private long _id;
+    private long id;
 
-    private String _userName;
+    private String userName;
 
     // etc., etc., ...
 
@@ -54,23 +54,23 @@
 public class ViewAccount
 {
     @Persist
-    private Account _account;
+    private Account account;
 
     @InjectPage
-    private AccountsSummary _accountsSummaryPage;
+    private AccountsSummary accountsSummaryPage;
 
     @Inject
-    private AccountDAO _accountDAO;
+    private AccountDAO accountDAO;
 
-    public Account getAccount() { return _account; }
+    public Account getAccount() { return account; }
 
     Object onActionFromDelete(long accountId)
     {
-        _accountDAO.delete(accountId);
+        accountDAO.delete(accountId);
 
-        _accountsSummaryPage.setMessage(String.format("Account #%d has been 
deleted.", accountId));
+        accountsSummaryPage.setMessage(String.format("Account #%d has been 
deleted.", accountId));
 
-        return _accountsSummaryPage;
+        return accountsSummaryPage;
     }
 }
 ]]></source>
@@ -115,11 +115,11 @@
 
     Object onActionFromDelete(long companyId, long accountId)
     {
-        _accountDAO.delete(companyId, accountId);
+        accountDAO.delete(companyId, accountId);
 
-        _accountsSummaryPage.setMessage(String.format("Account #%d has been 
deleted.", accountId));
+        accountsSummaryPage.setMessage(String.format("Account #%d has been 
deleted.", accountId));
 
-        return _accountsSummaryPage;
+        return accountsSummaryPage;
     }]]></source>
 
             <p>

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/BeanEditForm.xdoc
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/BeanEditForm.xdoc?rev=699214&r1=699213&r2=699214&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/BeanEditForm.xdoc
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/BeanEditForm.xdoc
 Fri Sep 26 01:22:37 2008
@@ -42,30 +42,30 @@
                 <source><![CDATA[
 public class User
 {
-    private long _id;
+    private long id;
 
-    private String _firstName;
+    private String firstName;
 
-    private String _lastName;
+    private String lastName;
 
-    private int _age;
+    private int age;
 
-    public long getId() { return _id; }
+    public long getId() { return id; }
 
     @NonVisual
-    public void setId(long id) { _id = id; }
+    public void setId(long id) { this.id = id; }
 
-    public String getFirstName() { return _firstName; }
+    public String getFirstName() { return firstName; }
 
-    public void setFirstName(String firstName) { _firstName = firstName; }
+    public void setFirstName(String firstName) { this.firstName = firstName; }
 
-    public String getLastName() { return _lastName; }
+    public String getLastName() { return lastName; }
 
-    public void setLastName(String lastName) { _lastName = lastName; }
+    public void setLastName(String lastName) { this.lastName = lastName; }
 
-    public int getAge() { return _age; }
+    public int getAge() { return age; }
 
-    public void setAge(int age) { _age = age; }
+    public void setAge(int age) { this.age = age; }
 }]]></source>
 
                 <p>The @NonVisual annotation prevents the id from being 
displayed.</p>
@@ -144,24 +144,24 @@
 public class CreateUser
 {
     @Persist
-    private User _user;
+    private User user;
 
     @Inject
-    private UserDAO _userDAO;
+    private UserDAO userDAO;
 
     public User getUser()
     {
-      return _user;
+      return user;
     }
 
     public void setUser(User user)
     {
-      _user = user;
+      this.user = user;
     }
 
     Object onSuccess()
     {
-        _userDAO.add(_user);
+        userDAO.add(user);
 
         return UserAdmin.class;
     }
@@ -205,19 +205,19 @@
 
                 <source><![CDATA[
     @Validate("required")
-    public String getFirstName() { return _firstName; }
+    public String getFirstName() { return firstName; }
 
-    public void setFirstName(String firstName) { _firstName = firstName; }
+    public void setFirstName(String firstName) { this.firstName = firstName; }
 
     @Validate("required")
-    public String getLastName() { return _lastName; }
+    public String getLastName() { return lastName; }
 
-    public void setLastName(String lastName) { _lastName = lastName; }
+    public void setLastName(String lastName) { this.lastName = lastName; }
 
     @Validate("min=18,max=99")
-    public int getAge() { return _age; }
+    public int getAge() { return age; }
 
-    public void setAge(int age) { _age = age; }]]>    </source>
+    public void setAge(int age) { this.age = age; }]]>    </source>
 
                 <p>
                     The new @Validate annotations added to the first name and 
last name properties indicates that a
@@ -300,7 +300,7 @@
 
             <p>
                 You can accomplish the same thing by changing the order of the
-                getter methods in the bean class.  The default order for 
properties is not alphabetical,
+                getter methods in the bean class. The default order for 
properties is not alphabetical,
                 it is the order of the getter methods.
             </p>
 

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js?rev=699214&r1=699213&r2=699214&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
 Fri Sep 26 01:22:37 2008
@@ -597,23 +597,6 @@
 
         $T(element).zone = zoneDiv;
 
-        var successHandler = function(transport)
-        {
-            var reply = transport.responseJSON;
-
-            // Find the zone id for the element, and from there, the 
Tapestry.Zone object
-            // responsible for the zone.  This is evaluated late so that zone 
can be dynamically
-            // changed on the client.  Sorry about the confusion; there's the 
zone <div>, and
-            // there's the Tapestry.Zone object.    Perhaps should rename 
Tapestry.Zone
-            // to Tapestry.ZoneManager?
-
-            var zoneId = $T(element).zone;
-            var zoneObject = $T(zoneId).zone;
-
-            zoneObject.show(reply.content);
-
-            Tapestry.processScriptInReply(reply);
-        };
 
         if (element.tagName == "FORM")
         {
@@ -627,6 +610,14 @@
 
             element.observe(Tapestry.FORM_PROCESS_SUBMIT_EVENT, function()
             {
+                var successHandler = function(transport)
+                {
+                    var zoneId = $T(element).zone;
+                    var zoneObject = $T(zoneId).zone;
+
+                    zoneObject.processReply(transport.responseJSON);
+                };
+
                 element.sendAjaxRequest({ onSuccess : successHandler });
             });
 
@@ -637,7 +628,16 @@
 
         element.observe("click", function(event)
         {
-            Tapestry.ajaxRequest(element.href, successHandler);
+            // Find the zone id for the element, and from there, the 
Tapestry.Zone object
+            // responsible for the zone.  This is evaluated late so that zone 
can be dynamically
+            // changed on the client.  Sorry about the confusion; there's the 
zone <div>, and
+            // there's the Tapestry.Zone object.    Perhaps should rename 
Tapestry.Zone
+            // to Tapestry.ZoneManager?
+
+            var zoneId = $T(element).zone;
+            var zoneObject = $T(zoneId).zone;
+
+            zoneObject.updateFromURL(element.href);
 
             Event.stop(event);
         });
@@ -1211,6 +1211,33 @@
         var func = this.element.visible() ? this.updateFunc : this.showFunc;
 
         func.call(this, this.element);
+    },
+
+    /**
+     *  Invoked with a reply (i.e., transport.responseJSON), this updates the 
zone's div
+     * and processes any JavaScript in the reply.  The response should have a
+     * content key, and may have  script, scripts and stylesheets keys.
+     * @param reply response in JSON format appropriate to a Tapestry.Zone
+     */
+    processReply : function(reply)
+    {
+        this.show(reply.content);
+
+        Tapestry.processScriptInReply(reply);
+    },
+
+    /** Initiates an Ajax request to update this zone by sending a request
+     *  to the URL. Expects the correct JSON reply (wth keys content, etc.).
+     * @param URL component event request URL
+     */
+    updateFromURL : function (URL)
+    {
+        var successHandler = function(transport)
+        {
+            this.processReply(transport.responseJSON);
+        }.bind(this);
+
+        Tapestry.ajaxRequest(URL, successHandler);
     }
 });
 

Modified: 
tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry5/hibernate/annotations/CommitAfter.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry5/hibernate/annotations/CommitAfter.java?rev=699214&r1=699213&r2=699214&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry5/hibernate/annotations/CommitAfter.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-hibernate/src/main/java/org/apache/tapestry5/hibernate/annotations/CommitAfter.java
 Fri Sep 26 01:22:37 2008
@@ -23,7 +23,7 @@
 /**
  * Marks a method of a service (or a component method) as transactional: the 
active transaction should [EMAIL PROTECTED]
  * org.apache.tapestry5.hibernate.HibernateSessionManager#commit() commit} 
after invoking the method.  Runtime
- * exceptions will abort the transaction, checked exceptions will <also 
commit> the transaction.
+ * exceptions will abort the transaction, checked exceptions will <em>also 
commit</em> the transaction.
  *
  * @see org.apache.tapestry5.hibernate.HibernateTransactionDecorator
  */

Modified: 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ConstructorServiceCreator.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ConstructorServiceCreator.java?rev=699214&r1=699213&r2=699214&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ConstructorServiceCreator.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ConstructorServiceCreator.java
 Fri Sep 26 01:22:37 2008
@@ -49,7 +49,11 @@
 
             if (logger.isDebugEnabled()) 
logger.debug(IOCMessages.invokingConstructor(creatorDescription));
 
-            return constructor.newInstance(parameters);
+            Object result = constructor.newInstance(parameters);
+
+            InternalUtils.injectIntoFields(result, resources);
+
+            return result;
         }
         catch (InvocationTargetException ite)
         {

Modified: 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java?rev=699214&r1=699213&r2=699214&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java
 Fri Sep 26 01:22:37 2008
@@ -338,7 +338,11 @@
                                                                          
constructor.getParameterTypes(),
                                                                          
constructor.getParameterAnnotations());
 
-            return constructor.newInstance(parameterValues);
+            Object result = constructor.newInstance(parameterValues);
+
+            InternalUtils.injectIntoFields(result, locator);
+
+            return result;
         }
         catch (InvocationTargetException ex)
         {

Modified: 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java?rev=699214&r1=699213&r2=699214&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java
 Fri Sep 26 01:22:37 2008
@@ -174,7 +174,6 @@
 
                 for (Class marker : serviceDef.getMarkers())
                     InternalUtils.addToMapList(markerToServiceDef, marker, 
serviceDef);
-
             }
 
             moduleToServiceDefs.put(module, moduleServiceDefs);
@@ -454,7 +453,6 @@
 
             def.contribute(module, locator, validating);
         }
-
     }
 
     private <T> void addToUnorderedConfiguration(Configuration<T> 
configuration, Class<T> valueType,
@@ -781,7 +779,11 @@
 
             Object[] parameters = 
InternalUtils.calculateParametersForConstructor(constructor, this, empty);
 
-            return clazz.cast(constructor.newInstance(parameters));
+            Object result = constructor.newInstance(parameters);
+
+            InternalUtils.injectIntoFields(result, this);
+
+            return clazz.cast(result);
         }
         catch (InvocationTargetException ite)
         {

Modified: 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java?rev=699214&r1=699213&r2=699214&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
 Fri Sep 26 01:22:37 2008
@@ -30,6 +30,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.*;
@@ -166,14 +167,14 @@
     }
 
     @SuppressWarnings("unchecked")
-    private static Object calculateParameterValue(Class parameterType, final 
Annotation[] parameterAnnotations,
-                                                  ObjectLocator locator, 
Map<Class, Object> parameterDefaults)
+    private static Object calculateInjection(Class injectionType, final 
Annotation[] annotations,
+                                             ObjectLocator locator, Map<Class, 
Object> defaults)
     {
         AnnotationProvider provider = new AnnotationProvider()
         {
             public <T extends Annotation> T getAnnotation(Class<T> 
annotationClass)
             {
-                return findAnnotation(parameterAnnotations, annotationClass);
+                return findAnnotation(annotations, annotationClass);
             }
         };
 
@@ -186,7 +187,7 @@
         {
             String serviceId = is.value();
 
-            return locator.getService(serviceId, parameterType);
+            return locator.getService(serviceId, injectionType);
         }
 
         // In the absence of @InjectService, try some autowiring. First, does 
the
@@ -194,7 +195,7 @@
 
         if (provider.getAnnotation(Inject.class) == null)
         {
-            Object result = parameterDefaults.get(parameterType);
+            Object result = defaults.get(injectionType);
 
             if (result != null) return result;
         }
@@ -202,7 +203,7 @@
         // Otherwise, make use of the MasterObjectProvider service to resolve 
this type (plus
         // any other information gleaned from additional annotation) into the 
correct object.
 
-        return locator.getObject(parameterType, provider);
+        return locator.getObject(injectionType, provider);
     }
 
     public static Object[] calculateParametersForMethod(Method method, 
ObjectLocator locator,
@@ -223,7 +224,7 @@
         return calculateParameters(locator, parameterDefaults, parameterTypes, 
annotations);
     }
 
-    public static Object[] calculateParameters(ObjectLocator locator, 
Map<Class, Object> parameterDefaults,
+    public static Object[] calculateParameters(ObjectLocator locator, 
Map<Class, Object> defaults,
                                                Class[] parameterTypes, 
Annotation[][] parameterAnnotations)
     {
         int parameterCount = parameterTypes.length;
@@ -232,14 +233,86 @@
 
         for (int i = 0; i < parameterCount; i++)
         {
-            parameters[i] = calculateParameterValue(parameterTypes[i], 
parameterAnnotations[i], locator,
-                                                    parameterDefaults);
+            parameters[i] = calculateInjection(parameterTypes[i], 
parameterAnnotations[i], locator,
+                                               defaults);
         }
 
         return parameters;
     }
 
     /**
+     * Injects into the fields (of all visibilities)  when the [EMAIL 
PROTECTED] org.apache.tapestry5.ioc.annotations.Inject} or
+     * [EMAIL PROTECTED] org.apache.tapestry5.ioc.annotations.InjectService} 
annotations are present.
+     *
+     * @param object  to be initialized
+     * @param locator used to resolve external dependencies
+     */
+    public static void injectIntoFields(Object object, ObjectLocator locator)
+    {
+        Class clazz = object.getClass();
+
+        while (clazz != Object.class)
+        {
+
+            Field[] fields = clazz.getDeclaredFields();
+
+            for (final Field f : fields)
+            {
+                // Ignore all static fields.
+
+                if (Modifier.isStatic(f.getModifiers())) continue;
+
+                AnnotationProvider ap = new AnnotationProvider()
+                {
+                    public <T extends Annotation> T getAnnotation(Class<T> 
annotationClass)
+                    {
+                        return f.getAnnotation(annotationClass);
+                    }
+                };
+
+
+                InjectService is = ap.getAnnotation(InjectService.class);
+
+                if (is != null)
+                {
+                    inject(object, f, locator.getService(is.value(), 
f.getType()));
+                    continue;
+                }
+
+                if (ap.getAnnotation(Inject.class) != null)
+                {
+                    inject(object, f, locator.getObject(f.getType(), ap));
+                    continue;
+                }
+
+                // Ignore fields that do not have the necessary annotation.  
Should we ignore static
+                // fields?
+            }
+
+
+            clazz = clazz.getSuperclass();
+        }
+    }
+
+    private synchronized static void inject(Object target, Field field, Object 
value)
+    {
+        try
+        {
+            if (!field.isAccessible()) field.setAccessible(true);
+
+            field.set(target, value);
+
+            // Is there a need to setAccessible back to false?
+        }
+        catch (Exception ex)
+        {
+            throw new RuntimeException(String.format("Unable to set field '%s' 
of %s to %s: %s",
+                                                     field.getName(), target, 
value,
+                                                     toMessage(ex)));
+        }
+    }
+
+    /**
      * Joins together some number of elements to form a comma separated list.
      */
     public static String join(List elements)

Modified: 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TapestryIOCModule.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TapestryIOCModule.java?rev=699214&r1=699213&r2=699214&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TapestryIOCModule.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TapestryIOCModule.java
 Fri Sep 26 01:22:37 2008
@@ -17,7 +17,6 @@
 import org.apache.tapestry5.ioc.*;
 import static org.apache.tapestry5.ioc.IOCConstants.PERTHREAD_SCOPE;
 import org.apache.tapestry5.ioc.annotations.Marker;
-import org.apache.tapestry5.ioc.annotations.Value;
 import org.apache.tapestry5.ioc.internal.services.*;
 import org.apache.tapestry5.ioc.util.TimeInterval;
 
@@ -84,9 +83,8 @@
     }
 
     /**
-     * Contributes "DefaultProvider", ordered last, that delegates to [EMAIL 
PROTECTED] ObjectLocator#getService(Class)}.
-     * <p/>
-     * Contributes "Value", which injects values (not services) triggered by 
the [EMAIL PROTECTED] Value} annotation.
+     * <dl> <dt>Value</dt> <dd>Supports the [EMAIL PROTECTED] 
org.apache.tapestry5.ioc.annotations.Value} annotation</dd>
+     * <dt>Symbol</dt> <dd>Supports the [EMAIL PROTECTED] 
org.apache.tapestry5.ioc.annotations.Symbol} annotations</dd> </dl>
      */
     public static void 
contributeMasterObjectProvider(OrderedConfiguration<ObjectProvider> 
configuration,
 

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/configuration.apt
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/configuration.apt?rev=699214&r1=699213&r2=699214&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/configuration.apt 
(original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/configuration.apt Fri 
Sep 26 01:22:37 2008
@@ -50,7 +50,7 @@
   Like service builder and service decorator methods, we can inject services 
if we like:
   
 +------+
-  public static void 
contributFileServicerDispatcher(MappedConfiguration<String,FileServicer> 
configuration,
+  public static void 
contributeFileServicerDispatcher(MappedConfiguration<String,FileServicer> 
configuration,
   
     @InjectService("TextFileServicer") FileServicer textFileServicer,
     
@@ -65,7 +65,7 @@
   service configuration:
   
 +------+
-   public static void 
contributeFileServicerDispatcher(MappedConfiguration<String,FileServicer> 
configuration)
+  public static void 
contributeFileServicerDispatcher(MappedConfiguration<String,FileServicer> 
configuration)
   {
     configuration.add("doc", new WordFileServicer());
     configuration.add("ppt", new PowerPointFileServicer());
@@ -221,7 +221,7 @@
   be unique.  When conflicts occur, Tapestry will log warnings (identifying 
the source, in terms of invoked methods, of
   the conflict), and ignore the conflicting value.
   
-  The value may not be null.
+  Neither the key nor the value may be null.
   
   For mapped configurations where the key type is String, a 
   
{{{apidocs/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.html}CaseInsensitiveMap}}

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/decorator.apt
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/decorator.apt?rev=699214&r1=699213&r2=699214&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/decorator.apt (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/decorator.apt Fri Sep 26 
01:22:37 2008
@@ -149,8 +149,13 @@
   you may identify which services are to be decorated.
   
   The value specified in the Match annotation is one or more patterns. These 
patterns
-  are used to match services. In a pattern, a "*" at the start or end of a 
string
-  match zero or more characters.
+  are used to match services. Patterns take two forms: glob patterns and 
regular expressions.
+
+  In a glob pattern, a "*" at the start or end of a string
+  will match zero or more characters.              Regular expressions provide 
a lot more matching power, but require
+  a more involved syntax.
+
+  In either case, the matching is case insensitive.
   
   For example, to target all the services in your module:
   

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/index.apt
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/index.apt?rev=699214&r1=699213&r2=699214&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/index.apt (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/index.apt Fri Sep 26 
01:22:37 2008
@@ -100,7 +100,7 @@
   
   Another goal is "developer friendliness". This is a true cross-cutting 
concern, and one not likely to be packaged
   into an aspect any time soon. The Tapestry IoC framework is designed to be 
easy to use and easy to understand.
-  Further, when things go wrong, it actively attempts to help you by 
+  Further, when things go wrong, it actively attempts to help you via 
        comprehensive checks and carefully composed error messages. Further,
   all user-visible objects implement
   {{{http://howardlewisship.com/blog/2003/08/importance-of-tostring.html}a 
reasonable toString() method}},
@@ -119,7 +119,7 @@
   to test and maintain existing code.  Too often in the world of software 
development, the need to add functionality
   trumps all, and testing and maintenance is deferred ... until too late.
   
-  IoC containers is general, and Tapestry IoC very specifically, exist to 
address this issue, to provide the foundations
+  IoC containers in general, and Tapestry IoC very specifically, exist to 
address this issue, to provide the foundations
   for balancing the need to quickly add functionality against the need to test 
new functionality and maintain
   existing functionality.  IoC containers provide the means to break large, 
complex, monolithic blocks into light, small, testable
   pieces.   
@@ -201,7 +201,10 @@
   the service interface. The first time a method is invoked on the proxy, the 
full service (consisting of the core service implementation wrapped with any 
interceptors) is
   constructed. This occurs in a completely <<thread-safe>> manner. 
Just-in-time instantiation allows for more complex, more finely grained 
networks of services, and improves
   startup time.
-  
+
+  Instantiating a service, injecting dependencies, and decorating the service 
are all parts of service <<realization>>, the point
+  at which a service transitions from virtual (just a proxy) to real (fully 
instantiated and ready to operate). 
+
   Services define a <<scope>> that controls when the service is constructed, 
as well as its visibility.  The default scope is <<singleton>>, meaning a single
   global instance created as needed.  Other scopes allow service 
implementations to be bound to the current thread (i.e., the current
   request in a servlet application).
@@ -210,4 +213,7 @@
   dependencies can be <<injected>> into a service builder method and provided, 
from there, to a service implementation via
   its constructor, or via methods on the service implementation. These may 
also be referred to as <<collaborators>>, especially
   in the context of writing unit tests.
-  
\ No newline at end of file
+
+  The <<point of Injection>> is a field, method parameter, or constructor 
parameter that receives an injected value.
+  The type of service (or other dependency) is determined by the type of the 
field or parameter. Often,
+  annotations further identify what is to be injected, or in the case of field 
injection, that an injection is required.
\ No newline at end of file

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/module.apt
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/module.apt?rev=699214&r1=699213&r2=699214&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/module.apt (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/module.apt Fri Sep 26 
01:22:37 2008
@@ -299,3 +299,37 @@
 
   The annotation can be applied to method and constructor parameters, for use 
within the IoC container.  It can also be applied
   to fields, though this is specific to the Tapestry web framework.
+
+Field Injection
+
+  The {{{../apidocs/org/apache/tapestry5/annotations/Inject.html}Inject}}
+  and 
{{{../apidocs/org/apache/tapestry5/annotations/InjectService.html}InjectService}}
+  annotations may be used on instance fields of a module class, as an 
alternative
+  to passing dependencies of the module in via the constructor.
+
+  Caution: injection via fields uses reflection to make the fields accessible. 
In
+  addition, it may not be as thread-safe as using the constructor to assign to
+  final fields.
+
+  Using this style, the previous example of a module class may be
+  rewritten:
+
++-----------------------------------------------------------------------------------+
+public class MyModule
+{
+  @Inject
+  private JobScheduler scheduler;
+
+  @Inject
+  private FileSystem fileSystem;
+
+  public Indexer build()
+  {
+    IndexerImpl indexer = new IndexerImpl(fileSystem);
+      
+    scheduler.scheduleDailyJob(indexer);
+
+    return indexer;
+  }
+}
++-----------------------------------------------------------------------------------+

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/overview.apt
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/overview.apt?rev=699214&r1=699213&r2=699214&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/overview.apt (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/overview.apt Fri Sep 26 
01:22:37 2008
@@ -112,12 +112,13 @@
   Dependency Injection is a key part of <realization>: this is how a service 
is provided with the other services it needs to operate.  For example,
   a Data Access Object service may be injected with a ConnectionPool service.
   
-  In Tapestry, injection occurs exclusively through constructors.  Other 
frameworks support a mix of constructor injection, property injection (i.e., 
invoking setter methods)
-  and method injection (invoking arbitrary methods to pass in dependencies).  
Tapestry focuses exclusively on constructor injection, and emphasizes
+  In Tapestry, injection occurs through constructors, through parameters to 
service builder methods, or through direct injection
+  into fields.   Tapestry prefers constructor injection, as this emphasizes
   that dependencies should be stored in <<final>> variables.  This is the best 
approach towards ensuring thread safety.
   
   In any case, injection "just happens".  Tapestry finds the constructor of 
your class and analyzes the parameters to determine what to pass in.  In some 
cases,
-  it uses just the parameter type to find a match, in other cases, annotations 
on the parameters may also be used.
+  it uses just the parameter type to find a match, in other cases, annotations 
on the parameters may also be used.  It also scans through the fields
+  of your service implementation class to identify which should have injected 
values written into them.
   
 Why can't I just use <<<new>>>?
 
@@ -321,7 +322,7 @@
   A new TableMetricProducer instance is created and contributed in.  We could 
contribute as many producers as we like here.  Other modules could also
   define a contributeMetricScheduler() method and contribute their own 
MetricProducer instances.
 
-  Meanwhile, the QueueWriterImpl class no longer needs the _instance variable 
or getInstance() method, and the TableMetricProducer
+  Meanwhile, the QueueWriterImpl class no longer needs the <<<instance>>> 
variable or getInstance() method, and the TableMetricProducer
   only needs a single constructor.
 
 Advantages of IoC: Summary

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/provider.apt
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/provider.apt?rev=699214&r1=699213&r2=699214&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/provider.apt (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/provider.apt Fri Sep 26 
01:22:37 2008
@@ -16,10 +16,12 @@
   forming a {{{command.html}chain of command}}.  The commands in the chain may 
provide an object
   based on the parameter type, or based on additional annotations on the 
parameter.
   
-  There are two built-in object providers:
+  There are several built-in object providers:
   
   * Check for 
{{{../apidocs/org/apache/tapestry5/ioc/annotations/Value.html}Value}} annotation
-  
+
+  * Check for 
{{{../apidocs/org/apache/tapestry5/ioc/annotations/Symbol.html}Symbol}} 
annotation
+
   * Check for a <unique> service in the Registry whose service interface 
matches the parameter type
   
   []
@@ -43,8 +45,22 @@
 
   Here, the MyService service requires a configuration of a number of seconds.
   The value is supplied as a symbol, with a factory default that may be 
overwritten
-  with an application default. 
-  
+  with an application default.
+
+  Usually, the symbol reference is only part of the string, i.e. 
<<<@Value("$\{report.dir}/$\{report.name}.txt")>>>
+
[EMAIL PROTECTED] Annotation Provider
+
+   This is closely related to the @Value annotation approach, except that the 
annotation
+   directly specifies a symbol name.
+
++----+
+  public MyService build(@Symbol("max-seconds") long maxSeconds)
+  {
+    return new MyServiceImpl(maxSeconds);
+  }
++----+
+
 Service Provider
 
   This is always that last object provider checked.

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/service.apt
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/service.apt?rev=699214&r1=699213&r2=699214&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/service.apt (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/service.apt Fri Sep 26 
01:22:37 2008
@@ -155,13 +155,15 @@
   It's pretty unlikely  that your service will be able to operate in a total 
vacuum. It will
   have other dependencies.  
   
-  Dependencies are provided to a service in one of three ways:
+  Dependencies are provided to a service in one of several ways:
   
   * As parameters to the service builder method
   
   * As parameters to the service implementation class' constructor (for 
autobuilt services)
   
   * As parameters passed to the constructor of the service's module builder 
(cached inside instance variables)
+
+  * Directly into fields of the service implementation
   
   []
    
@@ -383,7 +385,37 @@
   Understanding why this is a bad idea involves a long detour into inner 
details of the Java Memory Model.
   The short form is that other threads may end up invoking methods on the 
IndexerImpl instance, and its fields
   (even though they are final, even though they appear to already have been 
set) may be uninitialized.
-    
+
+Field Injection
+
+  The {{{../apidocs/org/apache/tapestry5/annotations/Inject.html}Inject}}
+  and 
{{{../apidocs/org/apache/tapestry5/annotations/InjectService.html}InjectService}}
+  annotations may be used on instance fields of a service implementation 
class, as an alternative
+  to passing dependencies of the service implementation in via the constructor.
+
+  Note that only dependencies are settable this way; if you want resources, 
including
+  the service's {{{configuration.html}configuration}}, you must pass those 
through the constructor.
+  You <are> free to mix and match, injecting partially with field injection 
and partially
+  with constructor injection.
+
+  Caution: injection via fields uses reflection to make the fields accessible. 
In
+  addition, it may not be as thread-safe as using the constructor to assign to
+  final fields.
+
++---+
+package org.example.myapp.services;
+
+import org.apache.tapestry5.ioc.annotations.InjectService;
+
+public class IndexerImpl implements Indexer
+{
+  @InjectService("FileSystem")
+  private FileSystem fileSystem;
+
+  . . .
+}
++---+
+
 Defining Service Scope
 
   Each service has a <lifecycle> that controls when the service implementation 
is instantiated.
@@ -455,7 +487,7 @@
   In addition, it is possible to specify the scope when binding the service:
   
 +----+
-  bind(MyServiceInterface.class, MyServiceImpl.class).scope("perthread");
+  bind(MyServiceInterface.class, 
MyServiceImpl.class).scope(IOCConstants.PERTHREAD_SCOPE);
 +----+
 
     
@@ -477,7 +509,7 @@
   
   Many services may be annotated with @EagerLoad; the order in which services 
are created is not defined. 
   
-  With the perthread lifecycle, the service builder method will not be invoked 
(this won't happen until
+  With the perthread scope, the service builder method will not be invoked 
(this won't happen until
   a service method is invoked), but the decorators for
   the service will be created. 
   
@@ -514,7 +546,11 @@
   
   See also {{{configuration.html}service configuration}} for additional 
special cases
   of resources that can be injected.
-  
+
+  Note: resources may not be injected into fields, they are injectable only via
+  method or constructor parameters.
+
+
   Example:
   
 
+-----------------------------------------------------------------------------------+
@@ -642,7 +678,7 @@
   With Tapestry IoC, this is not even considered a special case:
   
 
+-----------------------------------------------------------------------------------+
-  public static Indexer build(JobScheduler scheduler, FileSystem fileSystem)
+  public static Indexer buildIndexer(JobScheduler scheduler, FileSystem 
fileSystem)
   {
     IndexerImpl indexer = new IndexerImpl(fileSystem);
   
@@ -651,7 +687,7 @@
     return indexer;
   }
     
-  public static Indexed build(Indexer indexer)
+  public static FileSystem buildFileSystem(Indexer indexer)
   {
     return new FileSystemImpl(indexer);
   }  

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/shadow.apt
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/shadow.apt?rev=699214&r1=699213&r2=699214&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/shadow.apt (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/site/apt/shadow.apt Fri Sep 26 
01:22:37 2008
@@ -16,23 +16,25 @@
 +----+
 public Request build()
 {
-  return _shadowBuilder.build(_requestGlobals, "request", Request.class);
+  return shadowBuilder.build(requestGlobals, "request", Request.class);
 }
 +----+
 
+  (shadowBuilder and requestGlobals are injected into the module builder 
instance)
+
   This can be thought of as similar to:
   
 +----+
 public Request build()
 {
-  return _requestGlobals.getRequest();
+  return requestGlobals.getRequest();
 }
 +----+
     
   However there is a <critical> difference between the two:  a shadow property 
is <re-evaluated on each method invocation>.
   In the former case, the Request service will always obtain the current value 
of the request property from the
   per-thread RequestGlobals service. The second example is more than likely 
broken, since it will expose whatever
-  value is in the request property of the RequestGlobals <at the time the 
Request service implementation is created>.
+  value is in the request property of the RequestGlobals <at the time the 
Request service implementation is realized>.
   
   Notice that in this example, the Request service is a normal singleton. This 
service can be freely injected
   into any service throughout the framework or application. Invoking methods 
on this service will always delegate
@@ -46,11 +48,11 @@
   A typical method is implemented as (approximately):
   
 +----+
-private RequestGlobals _source;
+private final RequestGlobals source;
 
 public String getParameter(String name)
 {
-  return _source.getRequest().getParameter(name);
+  return source.getRequest().getParameter(name);
 }
 +----+
 

Added: 
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/util/FieldInjectionViaInject.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/util/FieldInjectionViaInject.java?rev=699214&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/util/FieldInjectionViaInject.java
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/util/FieldInjectionViaInject.java
 Fri Sep 26 01:22:37 2008
@@ -0,0 +1,31 @@
+//  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.util;
+
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.ioc.services.Builtin;
+import org.apache.tapestry5.ioc.services.SymbolSource;
+
+public class FieldInjectionViaInject
+{
+    @Inject
+    @Builtin
+    private SymbolSource symbolSource;
+
+    public SymbolSource getSymbolSource()
+    {
+        return symbolSource;
+    }
+}

Added: 
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/util/FieldInjectionViaInjectService.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/util/FieldInjectionViaInjectService.java?rev=699214&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/util/FieldInjectionViaInjectService.java
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/util/FieldInjectionViaInjectService.java
 Fri Sep 26 01:22:37 2008
@@ -0,0 +1,29 @@
+//  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.util;
+
+import org.apache.tapestry5.ioc.annotations.InjectService;
+
+public class FieldInjectionViaInjectService
+{
+    @InjectService("FredService")
+    private Runnable fred;
+
+    public Runnable getFred() { return fred; }
+
+    @Override
+    public String toString()
+    { return "<FieldInjectionViaInjectService>"; }
+}

Modified: 
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/util/InternalUtilsTest.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/util/InternalUtilsTest.java?rev=699214&r1=699213&r2=699214&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/util/InternalUtilsTest.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/util/InternalUtilsTest.java
 Fri Sep 26 01:22:37 2008
@@ -14,12 +14,20 @@
 
 package org.apache.tapestry5.ioc.internal.util;
 
+import org.apache.tapestry5.ioc.AnnotationProvider;
 import org.apache.tapestry5.ioc.Locatable;
 import org.apache.tapestry5.ioc.Location;
+import org.apache.tapestry5.ioc.ObjectLocator;
 import org.apache.tapestry5.ioc.annotations.Inject;
 import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newMap;
 import static org.apache.tapestry5.ioc.internal.util.InternalUtils.toList;
+import org.apache.tapestry5.ioc.services.Builtin;
+import org.apache.tapestry5.ioc.services.SymbolSource;
 import org.apache.tapestry5.ioc.test.IOCTestCase;
+import org.easymock.EasyMock;
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.isA;
+import org.easymock.IAnswer;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
@@ -454,4 +462,86 @@
                                   "Constructor protected 
org.apache.tapestry5.ioc.internal.util.InternalUtilsTest$PublicInnerClass() is 
not public and may not be used for autobuilding an instance of the class.");
         }
     }
+
+    @Test
+    public void inject_service_annotation_on_field()
+    {
+        ObjectLocator ol = mockObjectLocator();
+        FieldInjectionViaInjectService target = new 
FieldInjectionViaInjectService();
+        Runnable fred = mockRunnable();
+
+        train_getService(ol, "FredService", Runnable.class, fred);
+
+        replay();
+
+        InternalUtils.injectIntoFields(target, ol);
+
+        assertSame(target.getFred(), fred);
+
+        verify();
+    }
+
+    @Test
+    public void inject_annotation_on_field()
+    {
+        ObjectLocator ol = mockObjectLocator();
+        FieldInjectionViaInject target = new FieldInjectionViaInject();
+        final SymbolSource ss = mockSymbolSource();
+
+        IAnswer answer = new IAnswer()
+        {
+            public Object answer() throws Throwable
+            {
+                Object[] args = EasyMock.getCurrentArguments();
+
+                AnnotationProvider ap = (AnnotationProvider) args[1];
+
+                // Verify that annotations on the field are accessible.
+
+                assertNotNull(ap.getAnnotation(Builtin.class));
+
+                return ss;
+            }
+        };
+
+        expect(ol.getObject(eq(SymbolSource.class), 
isA(AnnotationProvider.class))).andAnswer(answer);
+
+        replay();
+
+        InternalUtils.injectIntoFields(target, ol);
+
+        assertSame(target.getSymbolSource(), ss);
+
+        verify();
+    }
+
+    @Test
+    public void exception_injecting_into_field()
+    {
+        ObjectLocator ol = mockObjectLocator();
+        FieldInjectionViaInjectService target = new 
FieldInjectionViaInjectService();
+
+        // It's very hard to come up with a value that causes an error when 
assigned. We have to break
+        // a lot of rules.
+
+        ol.getService("FredService", Runnable.class);
+        EasyMock.expectLastCall().andReturn("NotTheRightType");
+
+        replay();
+
+        try
+        {
+            InternalUtils.injectIntoFields(target, ol);
+
+            unreachable();
+        }
+        catch (Exception ex)
+        {
+            assertMessageContains(ex,
+                                  "Unable to set field 'fred' of 
<FieldInjectionViaInjectService> to NotTheRightType");
+        }
+
+
+        verify();
+    }
 }


Reply via email to