You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2007/04/17 01:31:54 UTC

svn commit: r529445 [3/3] - in /tapestry/tapestry5: tapestry-core/trunk/.settings/ tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ tapestry-hibernate/trunk/src/mai...

Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/main/resources/org/apache/tapestry/ioc/internal/IOCStrings.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/main/resources/org/apache/tapestry/ioc/internal/IOCStrings.properties?view=diff&rev=529445&r1=529444&r2=529445
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/main/resources/org/apache/tapestry/ioc/internal/IOCStrings.properties (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/main/resources/org/apache/tapestry/ioc/internal/IOCStrings.properties Mon Apr 16 16:31:50 2007
@@ -22,7 +22,8 @@
 builder-locked=The Registry Builder has created the Registry, further operations are not allowed.
 service-wrong-interface=Service '%s' implements interface %s, which is not compatible with the requested type %s.
 instantiate-builder-error=Unable to instantiate class %s as a module builder: %s
-builder-method-error=Error invoking service builder method %s (for service '%s'): %s
+builder-method-error=Error invoking service builder method %s (for service '%s'): %s
+constructor-error=Error invoking constructor %s (for service '%s'): %s
 decorator-method-error=Error invoking service decorator method %s (for service '%s'): %s
 builder-method-returned-null=Builder method %s (for service '%s') returned null.
 no-service-matches-type=No service implements the interface %s.
@@ -35,7 +36,8 @@
 decorator-returned-wrong-type=Decorator method %s (invoked for service '%s') returned %s, \
   which is not assignable to the %s service interface.
 creating-service=Creating service '%s'.
-invoking-method=Invoking method %s.
+invoking-method=Invoking method %s.
+invoking-constructor=Invoking constructor %s.
 recursive-service-build=Construction of service '%s' has failed due to recursion: \
   the service depends on itself in some way. \
   Please check %s for references to another service that is itself dependent on service '%1$s'.
@@ -73,4 +75,9 @@
 service-construction-failed=Construction of service %s failed: %s
 no-such-service=Service id '%s' is not defined by any module.  Defined services: %s.
 service-id-conflict=Service id '%s' has already been defined by %s and may not be redefined by %s. \
- You should rename one of the service builder methods.
\ No newline at end of file
+ You should rename one of the service builder methods.
+ no-constructor=Class %s (implementation of service '%s') does not contain any public constructors.
+ bind-method-must-be-static=Method %s appears to be a service binder method, but is an instance method, not a static method.
+ error-in-bind-method=Error invoking service binder method %s: %s
+ 
+ 
\ No newline at end of file

Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/module.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/module.apt?view=diff&rev=529445&r1=529444&r2=529445
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/module.apt (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/module.apt Mon Apr 16 16:31:50 2007
@@ -58,6 +58,28 @@
   how to inject dependencies. See {{{service.html#Injecting Dependencies}the service documentation}} 
   for more details.
   
+Autobuilding Services
+
+  An alternate, and usually preferred, way to define a service is via a module's bind() method.  The previous
+  example can be rewritten as:
+  
++---+
+package org.example.myapp.services;
+
+import org.apache.tapestry.ioc.ServiceBinder;
+
+public class MyAppModule
+{
+  public static void bind(ServiceBinder binder)
+  {
+     binder.bind(Indexer.class, IndexerImpl.class);
+  }
+}
++----+  
+
+  The {{{service.html}service}} documentation goes into much greater detail about autobuilding of services. In most cases,
+  autobuilding is the <preferred> approach.
+  
 {Cacheing Services}
 
   You will often find yourself in the position of injecting the same services

Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/provider.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/provider.apt?view=diff&rev=529445&r1=529444&r2=529445
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/provider.apt (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/provider.apt Mon Apr 16 16:31:50 2007
@@ -24,7 +24,7 @@
 
   The {{{apidocs/org/apache/tapestry/ioc/annotations/Value.html}@Value annotation}}
   allows a literal value to be injected.  When combined with 
-  {{{symbols.html}symbols}}, the represent a way for parts of the overall service
+  {{{symbols.html}symbols}}, they represent a way for parts of the overall service
   network to be spot-configured.  For example:
   
 +----+
@@ -38,8 +38,14 @@
   The value is supplied as a symbol, with a factory default that may be overwritten
   with an application default. 
   
-  
-  
+Alias Object Provider
+
+  The {{{http://tapestry.apache.org/tapestry5/tapestry-core/}tapestry-core}} module
+  defines the 
+  {{{http://tapestry.apache.org/tapestry5/tapestry-core/guide/alias.html}Alias object provider}},
+   which is used as a way to override services or
+  disambiguate services (when multiple services implement the same interface).  
+    
 Defining New Providers
 
   New providers can be specified by contributing to the

Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/service.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/service.apt?view=diff&rev=529445&r1=529444&r2=529445
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/service.apt (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/service.apt Mon Apr 16 16:31:50 2007
@@ -18,8 +18,6 @@
 +-----------------------------------------------------------------------------------+
 package org.example.myapp.services;
 
-import org.apache.tapestry.ioc.annotations.Id;
-
 public class MyAppModule
 {
   public static Indexer build()
@@ -43,6 +41,66 @@
   doing more interest work (such as registering the newly created service for events published by some other service),
   the Java code is simply the most direct, flexible, extensible and readable approach.
   
+Autobuilding
+
+  Tapestry IoC can also <autobuild> your service. Autobuilding is an alternate way to register services
+  with the container.
+  
+  Every module may have an optional, static bind() method which is passed a
+  {{{apidocs/org/apache/tapestry/ioc/ServiceBinder.html}ServiceBinder}}.  Services may be registered with
+  the container by "binding" a service interface to a service implementation:
+  
++------+
+package org.example.myapp.services;
+
+import org.apache.tapestry.ioc.ServiceBinder;
+
+public class MyAppModule
+{
+  public static void bind(ServiceBinder binder)
+  {
+    binder.bind(Indexer.class, IndexerImpl.class);
+  }
+}
++----+
+
+  You can make repeated calls to bind(), to register more services.
+
+
+  You might ask, "which is better, a builder method for each service, or a bind() method for the module?"  For simple services,
+  those that are just an instantiated instance with simple dependencies, binding is better than building.
+  
+  There are many cases, however, where constructing a service is more than just instantiating a class. Often the new service
+  will (for example) be registered as a listener with some other service. In other cases, the implementation of the
+  service is generated at runtime. These are where the service builder methods are most useful.
+
+  In terms of the evolution of the framework, service builder methods came first, and autobuilding was a later
+  addition, inspired by the terseness of the {{{http://code.google.com/p/google-guice/}Guice}} IoC container.
+    
+Service Ids
+
+  Every service will have a unique service id. 
+  
+  When using a service builder method, the service id is the <simple name> of the service interface.
+  
+  This can be overridden by adding the service id to the method name, after "build", for example:
+  
++---+
+  public static Indexer buildFileSystemIndexer(@InjectService("FileSystem") FileSystem fileSystem)
+  {
+     . . .
+  }
++----+
+
+  Here, the service id is "FileSystemIndexer" not "Indexer".
+  
+  For autobuilt services, the service id can be specified when the service is bount:
+  
++---+
+  binder.bind(Indexer.class, IndexerImpl.class).withId("FileSystemIndexer");
++---+
+  
+  
 {Injecting Dependencies} with @InjectService
 
   It's pretty unlikely  that your service will be able to operate in a total vacuum. It will
@@ -78,6 +136,62 @@
   (or service decorator) methods, you can 
   {{{module.html#Caching Services}cache dependency injections}} in your module, by defining
   a constructor.  This reduces duplication in your module.
+  
+Injecting Dependencies for Autobuilt Services
+
+  With autobuilt services, there's no service builder method in which to specify injections.
+  
+  Instead, the injections occur on <constructor> for the implementation class:
+  
++---+
+package org.example.myapp.services;
+
+import org.apache.tapestry.ioc.annotations.InjectService;
+
+public class IndexerImpl implements Indexer
+{
+  private final FileSystem _fileSystem;
+  
+  public IndexerImpl(@InjectService("FileSystem") FileSystem fileSystem)
+  {
+    _fileSystem = fileSystem;
+  }
+}
++---+  
+
+  If the class has multiple constructors, the constructor with the most parameters will be invoked.
+  
+  Note how we are using final fields for our dependencies; this is generally a Good Idea.
+  These services will often execute inside a multi-threaded environment, such as a web application,
+  and the use of final fields inside a constructor ensures that the fields will be properly published
+  (meaning, "visible to other threads") in accordance with the Java Memory Model.
+  
+  Once thing that is not a good idea is to pass in another service, such as JobScheduler in the previous
+  example, and pass <<<this>>> from a constructor:
+  
++---+
+package org.example.myapp.services;
+
+import org.apache.tapestry.ioc.annotations.InjectService;
+
+public class IndexerImpl implements Indexer
+{
+  private final FileSystem _fileSystem;
+  
+  public IndexerImpl(@InjectService("FileSystem") FileSystem fileSystem,
+  
+  @InjectService("JobScheduler") JobScheduler scheduler)
+  {
+    _fileSystem = fileSystem;
+    
+    scheduler.scheduleDailyJob(this); // Bad Idea
+  }
+}
++---+
+ 
+  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.
     
 Defining Service Scope
 
@@ -140,6 +254,21 @@
   a request, and should not have overly complex relationships with the other services
   in the registry.
   
+Defining the scope of Autobuilt Services
+
+  There are two options for defining the scope for an autobuilt service.
+  
+   The service implementation class may include the @Scope annotation. This is generally the preferred way
+   to specify scope.
+  
+  In addition, it is possible to specify the scope when binding the service:
+  
++----+
+  bind(MyServiceInterface.class, MyServiceImpl.class).scope("perthread");
++----+
+
+    
+  
 Eager Loading Services
 
   Services are normally created only as needed (per the scope discussion above).
@@ -160,6 +289,20 @@
   With the perthread lifecycle, 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. 
+  
+Eager Loading Autobuilt Services
+
+  As with service scope, there are two options for indicating that an autobuilt service should be
+  eagerly loaded.
+  
+  The service implementation class may include the @EagerLoad annotation.
+  
+  You may also specify eager loading explicitly when binding the service:
+
++----+
+  bind(MyServiceInterface.class, MyServiceImpl.class).eagerLoad();
++----+
+  
      
 Injecting Resources
 
@@ -209,7 +352,12 @@
   to use the @InjectService annotation.
   
   The Log's name (used when configuring logging settings for the service) consists of
-  the module class name and the service id seperated by a period, i.e. "org.example.myapp.MyModule.Indexer".
+  the module class name and the service id seperated by a period, i.e. "org.example.myapp.MyModule.Indexer".  
+  
+  This works the exact same way with autobuilt services, except that the parameters of the service
+  implementation constructor are considered, rather than the parameters of the service
+  builder method.
+  
   
 Automatic Dependency Resolution
 
@@ -245,6 +393,18 @@
   Assuming that JobScheduler and FileSystem are unique service interfaces, the above will work.
   It is not necessary that Indexer, JobScheduler and FileSystem be in the same
   module.
+  
+  Again, this works identically whether it is a service builder method, or an autobuilt service's constructor.
+
+Injecting Objects
+
+  Another option is to inject <objects>, not <services>.  
+  
+  This is accomplished using the
+  {{{apidocs/org/apache/tapestry/ioc/annotations/Inject.html}Inject}} annotation.   The object
+  that gets injected is defined by an
+  {{{provider.html}object provider}}, and is based on the type of the parameter, and potentially
+  other annotations on the parameter.
   
 Builtin Services
 

Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/strategy.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/strategy.apt?view=diff&rev=529445&r1=529444&r2=529445
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/strategy.apt (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/strategy.apt Mon Apr 16 16:31:50 2007
@@ -13,7 +13,7 @@
   The inheritance search works its way up the class hierarchy looking for a matching registration. If nothing is found, then all the interfaces directly or indirectly
   implemented by the selector class are checked. java.lang.Object is always the final match.
   
-  A runtime exception is thrown if no match can be found. «
+  A runtime exception is thrown if no match can be found.
   
   As a special case, the value null is search for as if it was an instance of the class void.
     
@@ -39,7 +39,7 @@
 
   You will usually have a service configuration for defining the adapter registry.
   
-  You conver the configuration into a StrategyRegistry, and use that to build the final service:
+  You convert the configuration into a StrategyRegistry, and use that to build the final service:
   
 +---+
   public static MyStrategyService build(Map<Class, MyStrategyService> configuration,

Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/symbols.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/symbols.apt?view=diff&rev=529445&r1=529444&r2=529445
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/symbols.apt (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/site/apt/symbols.apt Mon Apr 16 16:31:50 2007
@@ -103,4 +103,4 @@
 +----+  
   
   When the <<<report.url>>> is referenced, an exception will be thrown with the message: <<
-  Symbol 'report.path' is defined in terms of itself (report.path --> report.util --> report.path).>>
+  Symbol 'report.path' is defined in terms of itself (report.path --> report.url --> report.path).>>

Added: tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/AutobuildModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/AutobuildModule.java?view=auto&rev=529445
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/AutobuildModule.java (added)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/AutobuildModule.java Mon Apr 16 16:31:50 2007
@@ -0,0 +1,23 @@
+// 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.tapestry.ioc;
+
+public class AutobuildModule
+{
+    public static void bind(ServiceBinder binder)
+    {
+        binder.bind(StringHolder.class, StringHolderImpl.class);
+    }
+}

Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/IntegrationTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/IntegrationTest.java?view=diff&rev=529445&r1=529444&r2=529445
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/IntegrationTest.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/IntegrationTest.java Mon Apr 16 16:31:50 2007
@@ -20,10 +20,13 @@
 import java.util.List;
 import java.util.Map;
 
+import org.apache.tapestry.ioc.internal.ExceptionInConstructorModule;
 import org.apache.tapestry.ioc.internal.IOCInternalTestCase;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
+import com.sun.tools.javac.util.Log;
+
 /**
  * A few tests that are easiest (or even just possible) by building a Registry and trying out a few
  * things.
@@ -337,5 +340,53 @@
         Runnable fred = r.getService("Fred", Runnable.class);
 
         assertSame(r.getService("FRED", Runnable.class), fred);
+    }
+
+    @Test
+    public void simple_autobuild()
+    {
+        Registry r = buildRegistry(AutobuildModule.class);
+
+        StringHolder sh = r.getService(StringHolder.class);
+
+        sh.setValue("Foo");
+
+        assertEquals(sh.getValue(), "Foo");
+    }
+
+    @Test
+    public void exception_in_autobuild_service_constructor()
+    {
+        Registry r = buildRegistry(ExceptionInConstructorModule.class);
+
+        Runnable runnable = r.getService(Runnable.class);
+
+        try
+        {
+            runnable.run();
+            unreachable();
+        }
+        catch (RuntimeException ex)
+        {
+            assertMessageContains(
+                    ex,
+                    "Error invoking constructor",
+                    "ExceptionInConstructorServiceImpl() (at ExceptionInConstructorServiceImpl.java",
+                    "for service 'Runnable'",
+                    "Yes, we have no tomatoes.");
+        }
+    }
+
+    @Test
+    public void non_proxied_service()
+    {
+        Registry r = buildRegistry(NonProxiedServiceModule.class);
+
+        // Note: obtained via the (or an) interface implemented by
+        // the service implementation.
+
+        StringHolder holder = r.getService(StringHolder.class);
+
+        assertTrue(holder instanceof StringHolderImpl);
     }
 }

Added: tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/NonProxiedServiceModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/NonProxiedServiceModule.java?view=auto&rev=529445
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/NonProxiedServiceModule.java (added)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/NonProxiedServiceModule.java Mon Apr 16 16:31:50 2007
@@ -0,0 +1,23 @@
+// 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.tapestry.ioc;
+
+public class NonProxiedServiceModule
+{
+    public static void bind(ServiceBinder binder)
+    {
+        binder.bind(StringHolderImpl.class);
+    }
+}

Added: tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/ComplexAutobuildModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/ComplexAutobuildModule.java?view=auto&rev=529445
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/ComplexAutobuildModule.java (added)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/ComplexAutobuildModule.java Mon Apr 16 16:31:50 2007
@@ -0,0 +1,27 @@
+// 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.tapestry.ioc.internal;
+
+import org.apache.tapestry.ioc.ServiceBinder;
+import org.apache.tapestry.ioc.StringHolder;
+import org.apache.tapestry.ioc.StringHolderImpl;
+
+public class ComplexAutobuildModule
+{
+    public static void bind(ServiceBinder binder)
+    {
+        binder.bind(StringHolder.class, StringHolderImpl.class).eagerLoad().scope("magic").withId("SH");
+    }
+}

Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/DefaultModuleDefImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/DefaultModuleDefImplTest.java?view=diff&rev=529445&r1=529444&r2=529445
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/DefaultModuleDefImplTest.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/DefaultModuleDefImplTest.java Mon Apr 16 16:31:50 2007
@@ -15,12 +15,18 @@
 package org.apache.tapestry.ioc.internal;
 
 import static org.apache.tapestry.ioc.internal.IOCMessages.buildMethodConflict;
+import static org.easymock.EasyMock.and;
+import static org.easymock.EasyMock.contains;
 
 import java.lang.reflect.Method;
 import java.util.Set;
 
 import org.apache.commons.logging.Log;
+import org.apache.tapestry.ioc.AutobuildModule;
 import org.apache.tapestry.ioc.IOCConstants;
+import org.apache.tapestry.ioc.ObjectCreator;
+import org.apache.tapestry.ioc.ServiceBuilderResources;
+import org.apache.tapestry.ioc.StringHolder;
 import org.apache.tapestry.ioc.def.ContributionDef;
 import org.apache.tapestry.ioc.def.DecoratorDef;
 import org.apache.tapestry.ioc.def.ModuleDef;
@@ -78,7 +84,7 @@
         assertEquals(sd.getServiceInterface(), FieService.class);
 
         assertTrue(sd.toString().contains(className + ".buildFred()"));
-        assertEquals(sd.getServiceScope(), IOCConstants.DEFAULT_LIFECYCLE);
+        assertEquals(sd.getServiceScope(), IOCConstants.DEFAULT_SCOPE);
         assertEquals(sd.isEagerLoad(), false);
 
         sd = md.getServiceDef("Wilma");
@@ -121,12 +127,14 @@
     public void service_id_conflict() throws Exception
     {
         Method conflictMethod = ServiceIdConflictMethodModule.class.getMethod("buildFred");
+        String conflictMethodString = InternalUtils.asString(conflictMethod, _classFactory);
+
         String expectedMethod = InternalUtils.asString(ServiceIdConflictMethodModule.class
                 .getMethod("buildFred", Object.class), _classFactory);
 
         Log log = newLog();
 
-        log.warn(buildMethodConflict(conflictMethod, expectedMethod), null);
+        log.warn(buildMethodConflict(conflictMethodString, expectedMethod), null);
 
         replay();
 
@@ -311,6 +319,168 @@
         ModuleDef md = new DefaultModuleDefImpl(moduleClass, log, null);
 
         assertTrue(md.getContributionDefs().isEmpty());
+
+        verify();
+    }
+
+    @Test
+    public void simple_binder_method()
+    {
+        Log log = newLog();
+
+        replay();
+
+        ModuleDef md = new DefaultModuleDefImpl(AutobuildModule.class, log, _classFactory);
+
+        ServiceDef sd = md.getServiceDef("StringHolder");
+
+        assertEquals(sd.getServiceInterface(), StringHolder.class);
+        assertEquals(sd.getServiceId(), "StringHolder");
+        assertEquals(sd.getServiceScope(), IOCConstants.DEFAULT_SCOPE);
+        assertFalse(sd.isEagerLoad());
+
+        verify();
+    }
+
+    @Test
+    public void bind_service_with_all_options()
+    {
+        Log log = newLog();
+
+        replay();
+
+        ModuleDef md = new DefaultModuleDefImpl(ComplexAutobuildModule.class, log, _classFactory);
+
+        ServiceDef sd = md.getServiceDef("SH");
+
+        assertEquals(sd.getServiceInterface(), StringHolder.class);
+        assertEquals(sd.getServiceId(), "SH");
+        assertEquals(sd.getServiceScope(), "magic");
+        assertTrue(sd.isEagerLoad());
+
+        verify();
+    }
+
+    @Test
+    public void attempt_to_bind_a_service_with_no_public_constructor()
+    {
+        Log log = newLog();
+
+        replay();
+
+        try
+        {
+            new DefaultModuleDefImpl(UninstantiableAutobuildServiceModule.class, log, _classFactory);
+            unreachable();
+        }
+        catch (RuntimeException ex)
+        {
+            assertEquals(
+                    ex.getMessage(),
+                    "Class org.apache.tapestry.ioc.internal.RunnableServiceImpl (implementation of service \'Runnable\') does not contain any public constructors.");
+        }
+
+        verify();
+    }
+
+    @Test
+    public void instance_method_bind_is_ignored()
+    {
+        Log log = newLog();
+
+        log.error(and(
+                contains(NonStaticBindMethodModule.class.getName()),
+                contains("but is an instance method")));
+
+        replay();
+
+        ModuleDef md = new DefaultModuleDefImpl(NonStaticBindMethodModule.class, log, _classFactory);
+
+        // Prove that the bind method was not invoke
+
+        assertTrue(md.getServiceIds().isEmpty());
+
+        verify();
+    }
+
+    @Test
+    public void multiple_constructors_on_autobuild_service_implementation()
+    {
+        Log log = newLog();
+        ServiceBuilderResources resources = newServiceBuilderResources();
+
+        train_isDebugEnabled(log, true);
+
+        // The point is, we're choosing the constructor with the largest number of parameters.
+
+        log
+                .debug(contains("Invoking constructor org.apache.tapestry.ioc.internal.MultipleConstructorsAutobuildService(StringHolder)"));
+
+        train_getServiceId(resources, "StringHolder");
+        train_getServiceLog(resources, log);
+        train_getServiceInterface(resources, StringHolder.class);
+        train_getService(
+                resources,
+                "ToUpperCaseStringHolder",
+                StringHolder.class,
+                new ToUpperCaseStringHolder());
+
+        replay();
+
+        ModuleDef def = new DefaultModuleDefImpl(MutlipleAutobuildServiceConstructorsModule.class,
+                log, _classFactory);
+
+        ServiceDef sd = def.getServiceDef("StringHolder");
+
+        assertNotNull(sd);
+
+        ObjectCreator oc = sd.createServiceCreator(resources);
+
+        StringHolder holder = (StringHolder) oc.createObject();
+
+        holder.setValue("foo");
+        assertEquals(holder.getValue(), "FOO");
+
+        verify();
+    }
+
+    @Test
+    public void exception_from_inside_bind_method()
+    {
+        Log log = newLog();
+
+        replay();
+
+        try
+        {
+            new DefaultModuleDefImpl(ExceptionInBindMethod.class, log, _classFactory);
+            unreachable();
+        }
+        catch (RuntimeException ex)
+        {
+            assertTrue(ex
+                    .getMessage()
+                    .matches(
+                            "Error invoking service binder method org.apache.tapestry.ioc.internal.ExceptionInBindMethod.bind\\(ServiceBinder\\) "
+                                    + "\\(at ExceptionInBindMethod.java:\\d+\\): Really, how often is this going to happen\\?"));
+        }
+
+        verify();
+    }
+
+    @Test
+    public void autoload_service_is_eager_load_via_annotation()
+    {
+        Log log = newLog();
+
+        replay();
+
+        ModuleDef md = new DefaultModuleDefImpl(EagerLoadViaAnnotationModule.class, log,
+                _classFactory);
+
+        ServiceDef sd = md.getServiceDef("Runnable");
+
+        assertTrue(sd.isEagerLoad());
 
         verify();
     }

Added: tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/EagerLoadViaAnnotationModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/EagerLoadViaAnnotationModule.java?view=auto&rev=529445
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/EagerLoadViaAnnotationModule.java (added)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/EagerLoadViaAnnotationModule.java Mon Apr 16 16:31:50 2007
@@ -0,0 +1,26 @@
+// 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.tapestry.ioc.internal;
+
+import org.apache.tapestry.ioc.ServiceBinder;
+
+public class EagerLoadViaAnnotationModule
+{
+    public static void bind(ServiceBinder binder)
+    {
+        binder.bind(Runnable.class, EagerLoadViaAnnotationServiceImpl.class);
+    }
+
+}

Added: tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/EagerLoadViaAnnotationServiceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/EagerLoadViaAnnotationServiceImpl.java?view=auto&rev=529445
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/EagerLoadViaAnnotationServiceImpl.java (added)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/EagerLoadViaAnnotationServiceImpl.java Mon Apr 16 16:31:50 2007
@@ -0,0 +1,27 @@
+// 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.tapestry.ioc.internal;
+
+import org.apache.tapestry.ioc.annotations.EagerLoad;
+
+@EagerLoad
+public class EagerLoadViaAnnotationServiceImpl implements Runnable
+{
+
+    public void run()
+    {
+    }
+
+}

Added: tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/ExceptionInBindMethod.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/ExceptionInBindMethod.java?view=auto&rev=529445
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/ExceptionInBindMethod.java (added)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/ExceptionInBindMethod.java Mon Apr 16 16:31:50 2007
@@ -0,0 +1,25 @@
+// 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.tapestry.ioc.internal;
+
+import org.apache.tapestry.ioc.ServiceBinder;
+
+public class ExceptionInBindMethod
+{
+    public static void bind(ServiceBinder binder)
+    {
+        throw new RuntimeException("Really, how often is this going to happen?");
+    }
+}

Added: tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/ExceptionInConstructorModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/ExceptionInConstructorModule.java?view=auto&rev=529445
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/ExceptionInConstructorModule.java (added)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/ExceptionInConstructorModule.java Mon Apr 16 16:31:50 2007
@@ -0,0 +1,25 @@
+// 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.tapestry.ioc.internal;
+
+import org.apache.tapestry.ioc.ServiceBinder;
+
+public class ExceptionInConstructorModule
+{
+    public static void bind(ServiceBinder binder)
+    {
+        binder.bind(Runnable.class, ExceptionInConstructorServiceImpl.class);
+    }
+}

Added: tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/ExceptionInConstructorServiceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/ExceptionInConstructorServiceImpl.java?view=auto&rev=529445
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/ExceptionInConstructorServiceImpl.java (added)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/ExceptionInConstructorServiceImpl.java Mon Apr 16 16:31:50 2007
@@ -0,0 +1,29 @@
+// 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.tapestry.ioc.internal;
+
+public class ExceptionInConstructorServiceImpl implements Runnable
+{
+
+    public ExceptionInConstructorServiceImpl()
+    {
+        throw new RuntimeException("Yes, we have no tomatoes.");
+    }
+
+    public void run()
+    {
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/ModuleImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/ModuleImplTest.java?view=diff&rev=529445&r1=529444&r2=529445
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/ModuleImplTest.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/ModuleImplTest.java Mon Apr 16 16:31:50 2007
@@ -41,7 +41,8 @@
         Log log = newLog();
         ClassFactory factory = new ClassFactoryImpl();
 
-        ModuleDef moduleDef = new DefaultModuleDefImpl(ModuleImplTestModule.class, log, null);
+        ModuleDef moduleDef = new DefaultModuleDefImpl(ModuleImplTestModule.class, log,
+                getClassFactory());
 
         Module module = new ModuleImpl(registry, moduleDef, log);
 

Added: tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/MultipleConstructorsAutobuildService.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/MultipleConstructorsAutobuildService.java?view=auto&rev=529445
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/MultipleConstructorsAutobuildService.java (added)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/MultipleConstructorsAutobuildService.java Mon Apr 16 16:31:50 2007
@@ -0,0 +1,44 @@
+// 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.tapestry.ioc.internal;
+
+import org.apache.tapestry.ioc.StringHolder;
+import org.apache.tapestry.ioc.annotations.InjectService;
+
+public class MultipleConstructorsAutobuildService implements StringHolder
+{
+    private final StringHolder _delegate;
+
+    public MultipleConstructorsAutobuildService()
+    {
+        this(null);
+    }
+
+    public MultipleConstructorsAutobuildService(@InjectService("ToUpperCaseStringHolder") StringHolder delegate)
+    {
+        _delegate = delegate;
+    }
+
+    public String getValue()
+    {
+        return _delegate.getValue();
+    }
+
+    public void setValue(String value)
+    {
+        _delegate.setValue(value);
+    }
+
+}

Added: tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/MutlipleAutobuildServiceConstructorsModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/MutlipleAutobuildServiceConstructorsModule.java?view=auto&rev=529445
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/MutlipleAutobuildServiceConstructorsModule.java (added)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/MutlipleAutobuildServiceConstructorsModule.java Mon Apr 16 16:31:50 2007
@@ -0,0 +1,28 @@
+// 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.tapestry.ioc.internal;
+
+import org.apache.tapestry.ioc.ServiceBinder;
+import org.apache.tapestry.ioc.StringHolder;
+
+public class MutlipleAutobuildServiceConstructorsModule
+{
+    public static void bind(ServiceBinder binder)
+    {
+        binder.bind(StringHolder.class, ToUpperCaseStringHolder.class).withId(
+                "ToUpperCaseStringHolder");
+        binder.bind(StringHolder.class, MultipleConstructorsAutobuildService.class);
+    }
+}

Added: tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/NonStaticBindMethodModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/NonStaticBindMethodModule.java?view=auto&rev=529445
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/NonStaticBindMethodModule.java (added)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/NonStaticBindMethodModule.java Mon Apr 16 16:31:50 2007
@@ -0,0 +1,26 @@
+// 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.tapestry.ioc.internal;
+
+import org.apache.tapestry.ioc.ServiceBinder;
+import org.apache.tapestry.ioc.StringHolder;
+import org.apache.tapestry.ioc.StringHolderImpl;
+
+public class NonStaticBindMethodModule
+{
+    public void bind(ServiceBinder binder) {
+        binder.bind(StringHolder.class, StringHolderImpl.class);
+    }
+}

Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/RecursiveServiceCreationCheckWrapperTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/RecursiveServiceCreationCheckWrapperTest.java?view=diff&rev=529445&r1=529444&r2=529445
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/RecursiveServiceCreationCheckWrapperTest.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/RecursiveServiceCreationCheckWrapperTest.java Mon Apr 16 16:31:50 2007
@@ -14,8 +14,6 @@
 
 package org.apache.tapestry.ioc.internal;
 
-import java.lang.reflect.Method;
-
 import org.apache.commons.logging.Log;
 import org.apache.tapestry.ioc.ObjectCreator;
 import org.apache.tapestry.ioc.def.ServiceDef;
@@ -24,19 +22,22 @@
 public class RecursiveServiceCreationCheckWrapperTest extends IOCInternalTestCase
 {
 
+    private static final String SOURCE_DESCRIPTION = "{SOURCE DESCRIPTION}";
+
     @Test
     public void ensure_only_called_once() throws Exception
     {
         Log log = newLog();
-        Method method = getClass().getMethod("buildMyService");
-
+        ObjectCreatorSource source = newObjectCreatorSource();
         ObjectCreator delegate = newObjectCreator();
         Object service = new Object();
 
-        ServiceDef def = new ServiceDefImpl("Bar", "singleton", method, false, getClassFactory());
+        ServiceDef def = new ServiceDefImpl(Runnable.class, "Bar", "singleton", false, source);
 
         train_createObject(delegate, service);
 
+        train_getDescription(source, SOURCE_DESCRIPTION);
+
         replay();
 
         ObjectCreator wrapper = new RecursiveServiceCreationCheckWrapper(def, delegate, log);
@@ -53,7 +54,7 @@
             assertMessageContains(
                     ex,
                     "Construction of service 'Bar' has failed due to recursion: the service depends on itself in some way.",
-                    getClass().getName() + ".buildMyService() ",
+                    SOURCE_DESCRIPTION,
                     "for references to another service that is itself dependent on service 'Bar'.");
         }
 
@@ -65,12 +66,11 @@
     {
         RuntimeException failure = new RuntimeException("Just cranky.");
         Log log = newLog();
-        Method method = getClass().getMethod("buildMyService");
-
+        ObjectCreatorSource source = newObjectCreatorSource();
         ObjectCreator delegate = newObjectCreator();
         Object service = new Object();
 
-        ServiceDef def = new ServiceDefImpl("Bar", "singleton", method, false, null);
+        ServiceDef def = new ServiceDefImpl(Runnable.class, "Bar", "singleton", false, source);
 
         expect(delegate.createObject()).andThrow(failure);
 
@@ -103,11 +103,4 @@
         verify();
 
     }
-
-    /** Fake service builder method. */
-    public Runnable buildMyService()
-    {
-        return null;
-    }
-
 }

Added: tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/RunnableServiceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/RunnableServiceImpl.java?view=auto&rev=529445
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/RunnableServiceImpl.java (added)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/RunnableServiceImpl.java Mon Apr 16 16:31:50 2007
@@ -0,0 +1,30 @@
+// 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.tapestry.ioc.internal;
+
+/**
+ * This service implementation is not instantiable, which triggers an exception.
+ */
+public class RunnableServiceImpl implements Runnable
+{
+    private RunnableServiceImpl()
+    {
+    }
+
+    public void run()
+    {
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/ServiceBuilderMethodInvokerTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/ServiceBuilderMethodInvokerTest.java?view=diff&rev=529445&r1=529444&r2=529445
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/ServiceBuilderMethodInvokerTest.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/ServiceBuilderMethodInvokerTest.java Mon Apr 16 16:31:50 2007
@@ -30,13 +30,15 @@
 
 public class ServiceBuilderMethodInvokerTest extends IOCInternalTestCase
 {
-    private static final String SERVICE_ID = "ioc.Fie";
+    private static final String SERVICE_ID = "Fie";
+
+    private static final String CREATOR_DESCRIPTION = "{CREATOR DESCRIPTION}";
 
     @Test
     public void noargs_method()
     {
         ServiceBuilderMethodFixture fixture = new ServiceBuilderMethodFixture();
-        ServiceBuilderResources resources = newServiceCreatorResources();
+        ServiceBuilderResources resources = newServiceBuilderResources();
         Log log = newLog();
 
         fixture._fie = newFieService();
@@ -49,8 +51,8 @@
 
         replay();
 
-        ObjectCreator sc = new ServiceBuilderMethodInvoker(findMethod(fixture, "build_noargs"),
-                resources, getClassFactory());
+        ObjectCreator sc = new ServiceBuilderMethodInvoker(resources, CREATOR_DESCRIPTION,
+                findMethod(fixture, "build_noargs"));
 
         Object actual = sc.createObject();
 
@@ -73,7 +75,7 @@
     {
         ServiceBuilderMethodFixture fixture = new ServiceBuilderMethodFixture();
         Method method = findMethod(fixture, "build_args");
-        ServiceBuilderResources resources = newServiceCreatorResources();
+        ServiceBuilderResources resources = newServiceBuilderResources();
 
         Log log = newLog();
 
@@ -90,11 +92,11 @@
 
         train_isDebugEnabled(log, true);
 
-        log.debug(IOCMessages.invokingMethod(InternalUtils.asString(method, getClassFactory())));
+        log.debug(IOCMessages.invokingMethod(CREATOR_DESCRIPTION));
 
         replay();
 
-        ObjectCreator sc = new ServiceBuilderMethodInvoker(method, resources, getClassFactory());
+        ObjectCreator sc = new ServiceBuilderMethodInvoker(resources, CREATOR_DESCRIPTION, method);
 
         Object actual = sc.createObject();
 
@@ -107,7 +109,7 @@
     public void injected_service_method()
     {
         ServiceBuilderMethodFixture fixture = new ServiceBuilderMethodFixture();
-        ServiceBuilderResources resources = newServiceCreatorResources();
+        ServiceBuilderResources resources = newServiceBuilderResources();
         Log log = newLog();
 
         fixture._fie = newFieService();
@@ -123,8 +125,8 @@
 
         replay();
 
-        ObjectCreator sc = new ServiceBuilderMethodInvoker(findMethod(fixture, "build_injected"),
-                resources, getClassFactory());
+        ObjectCreator sc = new ServiceBuilderMethodInvoker(resources, CREATOR_DESCRIPTION,
+                findMethod(fixture, "build_injected"));
 
         Object actual = sc.createObject();
 
@@ -138,7 +140,7 @@
     public void injected_ordered_collection()
     {
         ServiceBuilderMethodFixture fixture = new ServiceBuilderMethodFixture();
-        ServiceBuilderResources resources = newServiceCreatorResources();
+        ServiceBuilderResources resources = newServiceBuilderResources();
         Log log = newLog();
 
         fixture._fie = newFieService();
@@ -155,9 +157,8 @@
 
         replay();
 
-        ObjectCreator sc = new ServiceBuilderMethodInvoker(findMethod(
-                fixture,
-                "buildWithOrderedConfiguration"), resources, getClassFactory());
+        ObjectCreator sc = new ServiceBuilderMethodInvoker(resources, CREATOR_DESCRIPTION,
+                findMethod(fixture, "buildWithOrderedConfiguration"));
 
         Object actual = sc.createObject();
 
@@ -172,7 +173,7 @@
     public void injected_unordered_collection()
     {
         ServiceBuilderMethodFixture fixture = new ServiceBuilderMethodFixture();
-        ServiceBuilderResources resources = newServiceCreatorResources();
+        ServiceBuilderResources resources = newServiceBuilderResources();
         Log log = newLog();
 
         fixture._fie = newFieService();
@@ -189,9 +190,8 @@
 
         replay();
 
-        ObjectCreator sc = new ServiceBuilderMethodInvoker(findMethod(
-                fixture,
-                "buildWithUnorderedConfiguration"), resources, getClassFactory());
+        ObjectCreator sc = new ServiceBuilderMethodInvoker(resources, CREATOR_DESCRIPTION,
+                findMethod(fixture, "buildWithUnorderedConfiguration"));
 
         Object actual = sc.createObject();
 
@@ -209,13 +209,11 @@
     public void builder_method_returns_null()
     {
         ServiceBuilderMethodFixture fixture = new ServiceBuilderMethodFixture();
-        ServiceBuilderResources resources = newServiceCreatorResources();
+        ServiceBuilderResources resources = newServiceBuilderResources();
         Log log = newLog();
 
         Method method = findMethod(fixture, "build_noargs");
 
-        String methodId = InternalUtils.asString(method, getClassFactory());
-
         trainForConstructor(resources, log);
 
         train_getModuleBuilder(resources, fixture);
@@ -224,7 +222,7 @@
 
         replay();
 
-        ObjectCreator sc = new ServiceBuilderMethodInvoker(method, resources, getClassFactory());
+        ObjectCreator sc = new ServiceBuilderMethodInvoker(resources, CREATOR_DESCRIPTION, method);
 
         try
         {
@@ -233,8 +231,8 @@
         }
         catch (RuntimeException ex)
         {
-            Assert.assertEquals(ex.getMessage(), "Builder method " + methodId
-                    + " (for service 'ioc.Fie') returned null.");
+            Assert.assertEquals(ex.getMessage(), "Builder method " + CREATOR_DESCRIPTION
+                    + " (for service 'Fie') returned null.");
         }
 
         verify();
@@ -244,11 +242,10 @@
     public void builder_method_failed()
     {
         ServiceBuilderMethodFixture fixture = new ServiceBuilderMethodFixture();
-        ServiceBuilderResources resources = newServiceCreatorResources();
+        ServiceBuilderResources resources = newServiceBuilderResources();
         Log log = newLog();
 
         Method method = findMethod(fixture, "build_fail");
-        String methodId = InternalUtils.asString(method, getClassFactory());
 
         trainForConstructor(resources, log);
 
@@ -258,7 +255,7 @@
 
         replay();
 
-        ObjectCreator sc = new ServiceBuilderMethodInvoker(method, resources, getClassFactory());
+        ObjectCreator sc = new ServiceBuilderMethodInvoker(resources, CREATOR_DESCRIPTION, method);
 
         try
         {
@@ -267,8 +264,8 @@
         }
         catch (RuntimeException ex)
         {
-            assertEquals(ex.getMessage(), "Error invoking service builder method " + methodId
-                    + " (for service 'ioc.Fie'): Method failed.");
+            assertEquals(ex.getMessage(), "Error invoking service builder method "
+                    + CREATOR_DESCRIPTION + " (for service 'Fie'): Method failed.");
 
             Throwable cause = ex.getCause();
 
@@ -284,7 +281,7 @@
         ServiceBuilderMethodFixture fixture = new ServiceBuilderMethodFixture();
         Method method = findMethod(fixture, "build_auto");
 
-        ServiceBuilderResources resources = newServiceCreatorResources();
+        ServiceBuilderResources resources = newServiceBuilderResources();
         Log log = newLog();
 
         fixture._fie = newFieService();
@@ -300,7 +297,7 @@
 
         replay();
 
-        ObjectCreator sc = new ServiceBuilderMethodInvoker(method, resources, getClassFactory());
+        ObjectCreator sc = new ServiceBuilderMethodInvoker(resources, CREATOR_DESCRIPTION, method);
 
         Object actual = sc.createObject();
 

Added: tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/ToUpperCaseStringHolder.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/ToUpperCaseStringHolder.java?view=auto&rev=529445
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/ToUpperCaseStringHolder.java (added)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/ToUpperCaseStringHolder.java Mon Apr 16 16:31:50 2007
@@ -0,0 +1,33 @@
+// 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.tapestry.ioc.internal;
+
+import org.apache.tapestry.ioc.StringHolder;
+
+public class ToUpperCaseStringHolder implements StringHolder
+{
+    private String _value;
+
+    public String getValue()
+    {
+        return _value;
+    }
+
+    public void setValue(String value)
+    {
+        _value = value.toUpperCase();
+    }
+
+}

Added: tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/UninstantiableAutobuildServiceModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/UninstantiableAutobuildServiceModule.java?view=auto&rev=529445
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/UninstantiableAutobuildServiceModule.java (added)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/UninstantiableAutobuildServiceModule.java Mon Apr 16 16:31:50 2007
@@ -0,0 +1,25 @@
+// 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.tapestry.ioc.internal;
+
+import org.apache.tapestry.ioc.ServiceBinder;
+
+public class UninstantiableAutobuildServiceModule
+{
+    public static void bind(ServiceBinder binder)
+    {
+        binder.bind(Runnable.class, RunnableServiceImpl.class);
+    }
+}

Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/services/ClassFactoryImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/services/ClassFactoryImplTest.java?view=diff&rev=529445&r1=529444&r2=529445
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/services/ClassFactoryImplTest.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/services/ClassFactoryImplTest.java Mon Apr 16 16:31:50 2007
@@ -14,6 +14,7 @@
 
 package org.apache.tapestry.ioc.internal.services;
 
+import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 
@@ -96,7 +97,7 @@
 
         assertEquals(
                 factory.getMethodLocation(m).toString(),
-                "org.apache.tapestry.ioc.internal.services.LineNumberBean.fred() (at LineNumberBean.java:21)");
+                "org.apache.tapestry.ioc.internal.services.LineNumberBean.fred() (at LineNumberBean.java:25)");
 
         m = target.getMethod("betty", String.class, int.class);
 
@@ -104,17 +105,32 @@
 
         assertEquals(
                 factory.getMethodLocation(m).toString(),
-                "org.apache.tapestry.ioc.internal.services.LineNumberBean.betty(String, int) (at LineNumberBean.java:25)");
+                "org.apache.tapestry.ioc.internal.services.LineNumberBean.betty(String, int) (at LineNumberBean.java:29)");
 
         m = target.getDeclaredMethod("wilma", int[].class, Double[][][].class);
 
         assertEquals(
                 factory.getMethodLocation(m).toString(),
-                "org.apache.tapestry.ioc.internal.services.LineNumberBean.wilma(int[], Double[][][]) (at LineNumberBean.java:30)");
+                "org.apache.tapestry.ioc.internal.services.LineNumberBean.wilma(int[], Double[][][]) (at LineNumberBean.java:34)");
     }
 
     private void addRunMethod(ClassFab cf)
     {
         cf.addMethod(Modifier.PUBLIC, new MethodSignature(void.class, "run", null, null), " { } ");
+    }
+
+    @Test
+    public void get_constructor_location() throws Exception
+    {
+        Constructor cc = LineNumberBean.class.getConstructors()[0];
+
+        ClassFactory factory = new ClassFactoryImpl();
+
+        // Eclipse and Sun JDK don't agree on the line number, so we'll accept either.
+
+        assertTrue(factory
+                .getConstructorLocation(cc)
+                .matches(
+                        "org.apache.tapestry.ioc.internal.services.LineNumberBean\\(String, int\\) \\(at LineNumberBean.java:(19|20)\\)"));
     }
 }

Modified: tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/services/LineNumberBean.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/services/LineNumberBean.java?view=diff&rev=529445&r1=529444&r2=529445
==============================================================================
--- tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/services/LineNumberBean.java (original)
+++ tapestry/tapestry5/tapestry-ioc/trunk/src/test/java/org/apache/tapestry/ioc/internal/services/LineNumberBean.java Mon Apr 16 16:31:50 2007
@@ -16,6 +16,10 @@
 
 public class LineNumberBean
 {
+    public LineNumberBean(String foo, int bar)
+    {
+    }
+
     public void fred()
     {
     }

Modified: tapestry/tapestry5/tapestry-spring/trunk/pom.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-spring/trunk/pom.xml?view=diff&rev=529445&r1=529444&r2=529445
==============================================================================
--- tapestry/tapestry5/tapestry-spring/trunk/pom.xml (original)
+++ tapestry/tapestry5/tapestry-spring/trunk/pom.xml Mon Apr 16 16:31:50 2007
@@ -5,7 +5,7 @@
   <modelVersion>4.0.0</modelVersion>
   <groupId>org.apache.tapestry</groupId>
   <artifactId>tapestry-spring</artifactId>
-  <name>Tapestry-Spring Integration Library</name>
+  <name>Tapestry/Spring Integration Library</name>
   <packaging>jar</packaging>
   <version>5.0.4-SNAPSHOT</version>
   <description>Provides integration of Tapestry with the Spring IoC container.</description>

Modified: tapestry/tapestry5/tapestry-spring/trunk/src/main/java/org/apache/tapestry/spring/SpringModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-spring/trunk/src/main/java/org/apache/tapestry/spring/SpringModule.java?view=diff&rev=529445&r1=529444&r2=529445
==============================================================================
--- tapestry/tapestry5/tapestry-spring/trunk/src/main/java/org/apache/tapestry/spring/SpringModule.java (original)
+++ tapestry/tapestry5/tapestry-spring/trunk/src/main/java/org/apache/tapestry/spring/SpringModule.java Mon Apr 16 16:31:50 2007
@@ -14,27 +14,19 @@
 
 package org.apache.tapestry.spring;
 
-import org.apache.commons.logging.Log;
-import org.apache.tapestry.ioc.MappedConfiguration;
 import org.apache.tapestry.ioc.ObjectProvider;
 import org.apache.tapestry.ioc.OrderedConfiguration;
-import org.apache.tapestry.ioc.annotations.EagerLoad;
-import org.apache.tapestry.ioc.annotations.Inject;
+import org.apache.tapestry.ioc.ServiceBinder;
 import org.apache.tapestry.ioc.annotations.InjectService;
 import org.apache.tapestry.services.Context;
 import org.springframework.web.context.WebApplicationContext;
 
 public class SpringModule
 {
-    /**
-     * Provider that interprets expressions as the names of beans within the Spring
-     * {@link WebApplicationContext}.
-     */
-    public static ObjectProvider buildSpringObjectProvider(Log log,
-            @InjectService("WebApplicationContext")
-            WebApplicationContext context)
+    public static void bind(ServiceBinder binder)
     {
-        return new SpringObjectProvider(log, context);
+        binder.bind(ObjectProvider.class, SpringObjectProvider.class)
+                .withId("SpringObjectProvider");
     }
 
     /**

Modified: tapestry/tapestry5/tapestry-spring/trunk/src/main/java/org/apache/tapestry/spring/SpringObjectProvider.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-spring/trunk/src/main/java/org/apache/tapestry/spring/SpringObjectProvider.java?view=diff&rev=529445&r1=529444&r2=529445
==============================================================================
--- tapestry/tapestry5/tapestry-spring/trunk/src/main/java/org/apache/tapestry/spring/SpringObjectProvider.java (original)
+++ tapestry/tapestry5/tapestry-spring/trunk/src/main/java/org/apache/tapestry/spring/SpringObjectProvider.java Mon Apr 16 16:31:50 2007
@@ -22,6 +22,7 @@
 import org.apache.tapestry.ioc.AnnotationProvider;
 import org.apache.tapestry.ioc.ObjectProvider;
 import org.apache.tapestry.ioc.ServiceLocator;
+import org.apache.tapestry.ioc.annotations.InjectService;
 import org.springframework.web.context.WebApplicationContext;
 
 /**
@@ -30,7 +31,7 @@
  * This is just a first pass; later we'll have the provider check to see if beans are singletons,
  * and provide a proxy to the singleton rather than the raw object itself.
  */
-class SpringObjectProvider implements ObjectProvider
+public class SpringObjectProvider implements ObjectProvider
 {
     private final Log _log;
 
@@ -40,7 +41,8 @@
 
     private final Map<String, String> _beanNames = newCaseInsensitiveMap();
 
-    public SpringObjectProvider(Log log, WebApplicationContext context)
+    public SpringObjectProvider(Log log, @InjectService("WebApplicationContext")
+    WebApplicationContext context)
     {
         _log = log;