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 2008/03/01 03:45:41 UTC

svn commit: r632540 - in /tapestry/tapestry5/trunk/tapestry-core/src: main/java/org/apache/tapestry/beaneditor/ main/java/org/apache/tapestry/corelib/components/ main/java/org/apache/tapestry/internal/beaneditor/ main/java/org/apache/tapestry/internal/...

Author: hlship
Date: Fri Feb 29 18:45:25 2008
New Revision: 632540

URL: http://svn.apache.org/viewvc?rev=632540&view=rev
Log:
TAPESTRY-2202: When the BeanEditForm or BeanEditor components must create the bean to be editted, it should be autobuilt (supporting injection) rather than just instantiated via the default constructor

Removed:
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/corelib/components/BeanEditFormTest.java
Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/beaneditor/BeanModel.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/BeanEditForm.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/BeanEditor.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/PropertyEditor.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/beaneditor/BeanModelImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/BeanModelSourceImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/BeanModelSource.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/corelib/components/BeanEditForm.tml
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/corelib/components/BeanEditorTest.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/BeanModelSourceImplTest.java

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/beaneditor/BeanModel.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/beaneditor/BeanModel.java?rev=632540&r1=632539&r2=632540&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/beaneditor/BeanModel.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/beaneditor/BeanModel.java Fri Feb 29 18:45:25 2008
@@ -23,19 +23,28 @@
  * type.
  * <p/>
  * BeanModels are not thread-safe, they are also not serializable.
- * <p>
+ * <p/>
  * Here, and in {@link org.apache.tapestry.beaneditor.PropertyModel}, the term "propertyName" is used for simplicitly.
- * However, a full {@linkplain org.apache.tapestry.services.PropertyConduitSource#create(Class, String) property expression}
- * may be utilized when {@linkplain #add(String) adding new properties to an existing BeanModel}. 
+ * However, a full {@linkplain org.apache.tapestry.services.PropertyConduitSource#create(Class, String) property
+ * expression} may be utilized when {@linkplain #add(String) adding new properties to an existing BeanModel}.
  *
  * @see org.apache.tapestry.services.BeanModelSource
  */
-public interface BeanModel
+public interface BeanModel<T>
 {
     /**
      * Returns the type of bean for which this model was initially created.
      */
-    Class getBeanType();
+    Class<T> getBeanType();
+
+
+    /**
+     * Creates a new bean instance.  This is based on {@link org.apache.tapestry.ioc.ObjectLocator#autobuild(Class)}, so
+     * a public constructor will be used, and dependencies injected.
+     *
+     * @return new instance of the bean
+     */
+    T newInstance();
 
     /**
      * Returns a list of the editable properties of the bean, in <em>presentation</em> order.

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/BeanEditForm.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/BeanEditForm.java?rev=632540&r1=632539&r2=632540&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/BeanEditForm.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/BeanEditForm.java Fri Feb 29 18:45:25 2008
@@ -16,12 +16,11 @@
 
 import org.apache.tapestry.*;
 import org.apache.tapestry.annotations.Component;
+import org.apache.tapestry.annotations.InjectComponent;
 import org.apache.tapestry.annotations.Parameter;
 import org.apache.tapestry.annotations.SupportsInformalParameters;
 import org.apache.tapestry.beaneditor.BeanModel;
-import org.apache.tapestry.corelib.internal.InternalMessages;
 import org.apache.tapestry.ioc.annotations.Inject;
-import org.apache.tapestry.ioc.internal.util.TapestryException;
 import org.apache.tapestry.services.BeanModelSource;
 import org.apache.tapestry.services.ComponentDefaultProvider;
 
@@ -51,11 +50,10 @@
     private String _submitLabel;
 
     /**
-     * The object to be edited. This will be read when the component renders and updated when the form
-     * for the component is submitted. Typically, the container will listen for a "prepare" event, in order to ensure
-     * that a non-null value is ready to be read or updated. Often, the BeanEditForm can create the object as needed
-     * (assuming a public, no arguments constructor).  The object property defaults to a property with the same name as
-     * the component id.
+     * The object to be edited. This will be read when the component renders and updated when the form for the component
+     * is submitted. Typically, the container will listen for a "prepare" event, in order to ensure that a non-null
+     * value is ready to be read or updated. Often, the BeanEditForm can create the object as needed (assuming a public,
+     * no arguments constructor).  The object property defaults to a property with the same name as the component id.
      */
     @SuppressWarnings("unused")
     @Parameter(required = true)
@@ -88,6 +86,9 @@
     @Component(parameters = "clientValidation=inherit:clientValidation")
     private Form _form;
 
+    @InjectComponent
+    private BeanEditor _editor;
+
     /**
      * The model that identifies the parameters to be edited, their order, and every other aspect. If not specified, a
      * default bean model will be created from the type of the object bound to the object parameter.
@@ -102,6 +103,9 @@
     @Inject
     private ComponentResources _resources;
 
+    @Inject
+    private BeanModelSource _beanModelSource;
+
     /**
      * Defaults the object parameter to a property of the container matching the BeanEditForm's id.
      */
@@ -110,38 +114,38 @@
         return _defaultProvider.defaultBinding("object", _resources);
     }
 
-    void onPrepareFromForm()
+    public void setObject(Object object)
     {
-        // Fire a new prepare event to be consumed by the container. This is the container's
-        // chance to ensure that there's an object to edit.
+        _object = object;
+    }
 
-        _resources.triggerEvent(Form.PREPARE, null, null);
+    public Object getObject()
+    {
+        return _object;
+    }
 
-        if (_object == null) _object = createDefaultObject();
+    public BeanModel getModel()
+    {
+        return _model;
+    }
 
-        assert _object != null;
+    public void setModel(BeanModel model)
+    {
+        _model = model;
     }
 
-    private Object createDefaultObject()
+    void onPrepareFromForm()
     {
-        Class type = _resources.getBoundType("object");
+        _resources.triggerEvent(Form.PREPARE, null, null);
 
-        try
-        {
-            return type.newInstance();
-        }
-        catch (Exception ex)
+        if (_model == null)
         {
-            throw new TapestryException(
-                    InternalMessages.failureInstantiatingObject(type, _resources.getCompleteId(), ex),
-                    _resources.getLocation(), ex);
+            Class beanType = _resources.getBoundType("object");
+
+            _model = _beanModelSource.create(beanType, false, _resources.getContainerResources());
         }
     }
 
-    public Object getObject()
-    {
-        return _object;
-    }
 
     /**
      * Returns the client id of the embedded form.
@@ -180,10 +184,4 @@
     {
         _form.recordError(errorMessage);
     }
-
-    void inject(ComponentResources resources)
-    {
-        _resources = resources;
-    }
-
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/BeanEditor.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/BeanEditor.java?rev=632540&r1=632539&r2=632540&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/BeanEditor.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/BeanEditor.java Fri Feb 29 18:45:25 2008
@@ -30,9 +30,8 @@
 import org.apache.tapestry.services.FormSupport;
 
 /**
- * A component that generates a user interface for editing the properties of a bean. This is the
- * central component of the {@link BeanEditForm}, and utilizes a {@link PropertyEditor} for much of
- * its functionality.
+ * A component that generates a user interface for editing the properties of a bean. This is the central component of
+ * the {@link BeanEditForm}, and utilizes a {@link PropertyEditor} for much of its functionality.
  */
 @SupportsInformalParameters
 public class BeanEditor
@@ -48,42 +47,40 @@
     }
 
     /**
-     * The object to be edited by the BeanEditor. This will be read when the component renders and
-     * updated when the form for the component is submitted. Typically, the container will listen
-     * for a "prepare" event, in order to ensure that a non-null value is ready to be read or
-     * updated.
+     * The object to be edited by the BeanEditor. This will be read when the component renders and updated when the form
+     * for the component is submitted. Typically, the container will listen for a "prepare" event, in order to ensure
+     * that a non-null value is ready to be read or updated.
      */
     @Parameter
     private Object _object;
 
     /**
-     * A comma-separated list of property names to be removed from the {@link BeanModel}. The names
-     * are case-insensitive.
+     * A comma-separated list of property names to be removed from the {@link BeanModel}. The names are
+     * case-insensitive.
      */
     @Parameter(defaultPrefix = "literal")
     private String _remove;
 
     /**
-     * A comma-separated list of property names indicating the order in which the properties should
-     * be presented. The names are case insensitive. Any properties not indicated in the list will
-     * be appended to the end of the display order.
+     * A comma-separated list of property names indicating the order in which the properties should be presented. The
+     * names are case insensitive. Any properties not indicated in the list will be appended to the end of the display
+     * order.
      */
     @Parameter(defaultPrefix = "literal")
     private String _reorder;
 
     /**
-     * The model that identifies the parameters to be edited, their order, and every other aspect.
-     * If not specified, a default bean model will be created from the type of the object bound to
-     * the object parameter.
+     * The model that identifies the parameters to be edited, their order, and every other aspect. If not specified, a
+     * default bean model will be created from the type of the object bound to the object parameter.
      */
     @Parameter
     private BeanModel _model;
 
     /**
-     * Where to search for local overrides of property editing blocks as block parameters. Further,
-     * the container of the overrides is used as the source for overridden validation messages. This
-     * is normally the BeanEditor component itself, but when the component is used within a BeanEditForm, it
-     * will be the BeanEditForm's resources that will be searched.
+     * Where to search for local overrides of property editing blocks as block parameters. Further, the container of the
+     * overrides is used as the source for overridden validation messages. This is normally the BeanEditor component
+     * itself, but when the component is used within a BeanEditForm, it will be the BeanEditForm's resources that will
+     * be searched.
      */
     @Parameter(value = "componentResources")
     private ComponentResources _overrides;
@@ -147,40 +144,34 @@
 
     void doPrepare()
     {
+        if (_model == null)
+        {
+            Class type = _resources.getBoundType("object");
+            _model = _modelSource.create(type, true, _overrides.getContainerResources());
+        }
+
         // The only problem here is that if the bound property is backed by a persistent field, it
         // is assigned (and stored to the session, and propagated around the cluster) first,
         // before values are assigned.
 
-        if (_object == null) _object = createDefaultObject();
-
-        assert _object != null;
-
-        if (_model == null)
+        if (_object == null)
         {
-            Class<?> beanType = _object.getClass();
-
-            _model = _modelSource.create(beanType, true, _overrides.getContainerResources());
+            try
+            {
+                _object = _model.newInstance();
+            }
+            catch (Exception ex)
+            {
+                String message = InternalMessages.failureInstantiatingObject(_model.getBeanType(),
+                                                                             _resources.getCompleteId(),
+                                                                             ex);
+                throw new TapestryException(message, _resources.getLocation(), ex);
+            }
         }
 
         if (_remove != null) BeanModelUtils.remove(_model, _remove);
 
         if (_reorder != null) BeanModelUtils.reorder(_model, _reorder);
-    }
-
-    private Object createDefaultObject()
-    {
-        Class type = _resources.getBoundType("object");
-
-        try
-        {
-            return type.newInstance();
-        }
-        catch (Exception ex)
-        {
-            throw new TapestryException(
-                    InternalMessages.failureInstantiatingObject(type, _resources.getCompleteId(), ex),
-                    _resources.getLocation(), ex);
-        }
     }
 
     // For testing

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/PropertyEditor.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/PropertyEditor.java?rev=632540&r1=632539&r2=632540&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/PropertyEditor.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/PropertyEditor.java Fri Feb 29 18:45:25 2008
@@ -76,7 +76,7 @@
      * containing component of the PropertyEditor, but when the component is used within a BeanEditor, it will be the
      * BeanEditForm's block parameters that will be searched.
      */
-    @Parameter(value = "componentResources.containerResources")
+    @Parameter(value = "componentResources")
     private ComponentResources _overrides;
 
     /**

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/beaneditor/BeanModelImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/beaneditor/BeanModelImpl.java?rev=632540&r1=632539&r2=632540&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/beaneditor/BeanModelImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/beaneditor/BeanModelImpl.java Fri Feb 29 18:45:25 2008
@@ -20,6 +20,7 @@
 import org.apache.tapestry.beaneditor.RelativePosition;
 import org.apache.tapestry.internal.services.CoercingPropertyConduitWrapper;
 import org.apache.tapestry.ioc.Messages;
+import org.apache.tapestry.ioc.ObjectLocator;
 import org.apache.tapestry.ioc.internal.util.CollectionFactory;
 import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newCaseInsensitiveMap;
 import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newList;
@@ -32,9 +33,9 @@
 import java.util.List;
 import java.util.Map;
 
-public class BeanModelImpl implements BeanModel
+public class BeanModelImpl<T> implements BeanModel<T>
 {
-    private final Class _beanType;
+    private final Class<T> _beanType;
 
     private final PropertyConduitSource _propertyConduitSource;
 
@@ -42,24 +43,36 @@
 
     private final Messages _messages;
 
+    private final ObjectLocator _locator;
+
     private final Map<String, PropertyModel> _properties = newCaseInsensitiveMap();
 
     // The list of property names, in desired order (generally not alphabetical order).
 
     private final List<String> _propertyNames = CollectionFactory.newList();
 
-    public BeanModelImpl(Class beanType, PropertyConduitSource propertyConduitSource,
-                         TypeCoercer typeCoercer, Messages messages)
+    public BeanModelImpl(
+            Class<T> beanType, PropertyConduitSource
+            propertyConduitSource,
+            TypeCoercer typeCoercer, Messages
+            messages, ObjectLocator locator)
+
     {
         _beanType = beanType;
         _propertyConduitSource = propertyConduitSource;
         _typeCoercer = typeCoercer;
         _messages = messages;
+        _locator = locator;
     }
 
-    public Class getBeanType()
+    public Class<T> getBeanType()
     {
         return _beanType;
+    }
+
+    public T newInstance()
+    {
+        return _locator.autobuild(_beanType);
     }
 
     public PropertyModel add(String propertyName)

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/BeanModelSourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/BeanModelSourceImpl.java?rev=632540&r1=632539&r2=632540&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/BeanModelSourceImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/BeanModelSourceImpl.java Fri Feb 29 18:45:25 2008
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2008 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
 import org.apache.tapestry.internal.beaneditor.BeanModelImpl;
 import org.apache.tapestry.ioc.LoggerSource;
 import org.apache.tapestry.ioc.Messages;
+import org.apache.tapestry.ioc.ObjectLocator;
 import org.apache.tapestry.ioc.annotations.Primary;
 import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newList;
 import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
@@ -48,9 +49,11 @@
 
     private final DataTypeAnalyzer _dataTypeAnalyzer;
 
+    private final ObjectLocator _locator;
+
     public BeanModelSourceImpl(LoggerSource loggerSource, TypeCoercer typeCoercer, PropertyAccess propertyAccess,
                                PropertyConduitSource propertyConduitSource, @ComponentLayer ClassFactory classFactory,
-                               @Primary DataTypeAnalyzer dataTypeAnalyzer)
+                               @Primary DataTypeAnalyzer dataTypeAnalyzer, ObjectLocator locator)
     {
         _loggerSource = loggerSource;
         _typeCoercer = typeCoercer;
@@ -58,9 +61,10 @@
         _propertyConduitSource = propertyConduitSource;
         _classFactory = classFactory;
         _dataTypeAnalyzer = dataTypeAnalyzer;
+        _locator = locator;
     }
 
-    public BeanModel create(Class beanClass, boolean filterReadOnlyProperties, ComponentResources resources)
+    public <T> BeanModel<T> create(Class<T> beanClass, boolean filterReadOnlyProperties, ComponentResources resources)
     {
         notNull(beanClass, "beanClass");
         notNull(resources, "resources");
@@ -69,7 +73,8 @@
 
         ClassPropertyAdapter adapter = _propertyAccess.getAdapter(beanClass);
 
-        final BeanModel model = new BeanModelImpl(beanClass, _propertyConduitSource, _typeCoercer, messages);
+        final BeanModel<T> model = new BeanModelImpl<T>(beanClass, _propertyConduitSource, _typeCoercer, messages,
+                                                        _locator);
 
         List<String> propertyNames = newList();
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/BeanModelSource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/BeanModelSource.java?rev=632540&r1=632539&r2=632540&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/BeanModelSource.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/BeanModelSource.java Fri Feb 29 18:45:25 2008
@@ -45,5 +45,5 @@
      *                                 labels)
      * @return a model
      */
-    BeanModel create(Class beanClass, boolean filterReadOnlyProperties, ComponentResources resources);
+    <T> BeanModel<T> create(Class<T> beanClass, boolean filterReadOnlyProperties, ComponentResources resources);
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/corelib/components/BeanEditForm.tml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/corelib/components/BeanEditForm.tml?rev=632540&r1=632539&r2=632540&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/corelib/components/BeanEditForm.tml (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/corelib/components/BeanEditForm.tml Fri Feb 29 18:45:25 2008
@@ -4,8 +4,8 @@
 
   <div class="t-beaneditor">
 
-    <t:beaneditor object="object" remove="inherit:remove"
-      reorder="inherit:reorder" model="inherit:model" overrides="this" />
+    <t:beaneditor t:id="editor" object="object" remove="inherit:remove"
+      reorder="inherit:reorder" model="model" overrides="this" />
 
     <div class="t-beaneditor-row">
       <input type="submit" class="t-beaneditor-submit" value="${submitLabel}" />

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/corelib/components/BeanEditorTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/corelib/components/BeanEditorTest.java?rev=632540&r1=632539&r2=632540&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/corelib/components/BeanEditorTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/corelib/components/BeanEditorTest.java Fri Feb 29 18:45:25 2008
@@ -33,6 +33,7 @@
         ComponentResources containerResources = mockComponentResources();
         BeanModelSource source = mockBeanModelSource();
         BeanModel model = mockBeanModel();
+        RegistrationData data = new RegistrationData();
 
         train_getBoundType(resources, "object", RegistrationData.class);
 
@@ -40,6 +41,8 @@
 
         train_create(source, RegistrationData.class, true, containerResources, model);
 
+        expect(model.newInstance()).andReturn(data);
+
         replay();
 
         BeanEditor component = new BeanEditor();
@@ -48,31 +51,42 @@
 
         component.doPrepare();
 
-        Object object = component.getObject();
-
-        assertNotNull(object);
-        assertSame(object.getClass(), RegistrationData.class);
+        assertSame(component.getObject(), data);
 
         verify();
     }
 
+
     @Test
     public void object_can_not_be_instantiated()
     {
         ComponentResources resources = mockComponentResources();
+        ComponentResources overrides = mockComponentResources();
+        ComponentResources containerResources = mockComponentResources();
+        BeanModelSource source = mockBeanModelSource();
+        BeanModel model = mockBeanModel();
         Location l = mockLocation();
+        Throwable exception = new RuntimeException("Fall down go boom.");
 
         train_getBoundType(resources, "object", Runnable.class);
 
+        train_getContainerResources(overrides, containerResources);
+
+        train_create(source, Runnable.class, true, containerResources, model);
+
+        expect(model.newInstance()).andThrow(exception);
+
         train_getCompleteId(resources, "Foo.bar");
 
         train_getLocation(resources, l);
 
+        expect(model.getBeanType()).andReturn(Runnable.class);
+
         replay();
 
         BeanEditor component = new BeanEditor();
 
-        component.inject(resources, null, null);
+        component.inject(resources, overrides, source);
 
         try
         {
@@ -84,6 +98,7 @@
             assertMessageContains(
                     ex,
                     "Exception instantiating instance of java.lang.Runnable (for component \'Foo.bar\'):");
+
             assertSame(ex.getLocation(), l);
         }
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/BeanModelSourceImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/BeanModelSourceImplTest.java?rev=632540&r1=632539&r2=632540&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/BeanModelSourceImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/BeanModelSourceImplTest.java Fri Feb 29 18:45:25 2008
@@ -24,7 +24,6 @@
 import org.apache.tapestry.ioc.Messages;
 import org.apache.tapestry.services.BeanModelSource;
 import org.easymock.EasyMock;
-import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
@@ -44,12 +43,6 @@
         _source = getObject(BeanModelSource.class, null);
     }
 
-    @AfterClass
-    public void cleanup()
-    {
-        _source = null;
-    }
-
     /**
      * Tests defaults for property names, labels and conduits.
      */
@@ -140,6 +133,32 @@
         assertEquals(property.getPropertyName(), "middleInitial");
         assertSame(property.getConduit(), conduit);
         assertSame(property.getPropertyType(), propertyType);
+
+        verify();
+    }
+
+    /** TAPESTRY-2202 */
+    @Test
+    public void new_instance()
+    {
+        ComponentResources resources = mockComponentResources();
+        Messages messages = mockMessages();
+
+        train_getMessages(resources, messages);
+        stub_contains(messages, false);
+
+        replay();
+
+        BeanModel<SimpleBean> model = _source.create(SimpleBean.class, true, resources);
+
+        SimpleBean s1 = model.newInstance();
+
+        assertNotNull(s1);
+
+        SimpleBean s2 = model.newInstance();
+
+        assertNotNull(s2);
+        assertNotSame(s1, s2);        
 
         verify();
     }