History | Log In     View a printable version of the current page.  
Issue Details (XML | Word | Printable)

Key: STS-614
Type: New Feature New Feature
Status: Resolved Resolved
Resolution: Fixed
Priority: Major Major
Assignee: Ben Gunter
Reporter: Patrick Lightbody
Votes: 2
Watchers: 2
Operations

If you were logged in you would be able to see more operations.
Stripes

Ability to specify "ObjectFactory" for beans created during binding

Created: 10/Oct/08 03:54 PM   Updated: 02/Mar/09 07:16 PM
Component/s: None
Affects Version/s: None
Fix Version/s: Release 1.6

File Attachments: 1. Text File obj_fact.patch (2 kb)
2. Text File object_factory_v2.patch (6 kb)



 Description  « Hide
See patch.

 All   Comments   Change History      Sort Order: Ascending order - Click to sort in descending order
Ben Gunter - 14/Oct/08 05:39 PM
This is my version. I added documentation, support for autodiscovery, and a postProcess(..) method.

Frederic Daoud - 14/Oct/08 07:47 PM
Very nice....would this ObjectFactory also be used to create instances of other Stripes objects?

- ActionBeans
- ActionBeanContext
- Interceptors
- ExceptionHandler
- Formatters
- TypeConverters
- TagErrorRenderer

Just about everywhere newInstance() is called....?

Ben Gunter - 15/Oct/08 06:58 AM
That has been discussed. Personally, I like the idea. I only added calls to it from the couple of spots I know we all agree on. If no one is opposed to using the ObjectFactory everywhere else, I'll make the necessary changes.

Ben Gunter - 15/Oct/08 08:44 AM
We've all been discussing this on IRC, and here is what we have decided, as I understand it. If I mess something up, please correct it.

- ObjectFactory should be an interface that extends ConfigurableComponent and declares a single method: newInstance(Class<?>)

- We will provide a DefaultObjectFactory that just calls Class.newInstance()

- The Configuration interface will declare a new getObjectFactory() method

- All calls to Class.newInstance() will be replaced with a call to ObjectFactory.newInstance(Class)

Levi Hoogenberg - 15/Oct/08 09:30 AM
And this is still targeted at 1.5.1? Adding methods to interfaces means a major backward compatibility break ;) (Just kidding, I don't expect many people to implement Configuration themselves. Besides, there has been an ActionResolver change in 1.3.2, IIRC.)

Kidding aside, why are the configurable components that already have a factory listed (in Freddy's comment)? I understand the beauty of having a single place to post-process newly created beans, but it would create yet another layer of abstraction, something I thought Stripes has always been trying to avoid.

Levi Hoogenberg - 15/Oct/08 09:35 AM
Another thought: maybe ReflectUtil#getInterfaceImplementation could be refactored into DefaultObjectFactory as well, then.

Tim Fennell - 15/Oct/08 09:43 AM
Levi: Yes! I've had the same thought several times and keep forgetting to write it down. That definitely belongs in the same place since that behaviour should ideally be extensible/overridable

Chris Herron - 15/Oct/08 03:55 PM
Could you change the visibility of SpringHelper#findSpringBean(...) from protected to public please? (I have a SpringObjectFactory implementation to share, and this would eliminate some otherwise redundant code in its implementation).

John Newman - 15/Oct/08 04:26 PM
This should eliminate spring helper / interceptor entirely. All action beans, interceptors, etc, etc, could be wired in the xml application context and use normal setter injection!

major +1 from me

Chris Herron - 15/Oct/08 04:44 PM
Sorry if we're hijacking the comments for Spring-specific discussion, but to respond to John: I don't think that @SpringBean and its infrastructure should be eliminated. Reasons:
* Not breaking existing code that relies upon it
* Having public getters/setters on ActionBeans for Spring dependencies is a bit of a security risk when exposed to Stripes binding. @SpringBean allows Spring dependencies to be injected into private fields.

About declaring all that stuff in XML: For a typical project, I think it would get really tedious to have to explicitly declare lots of Stripes components in XML. Not very Stripey! I have a SpringObjectFactory that dynamically registers ActionBeans as Spring Beans with prototype scope. My thinking is that dependencies would be satisfied either by Spring's @Autowired, or by Stripes' @SpringBean if security is a concern. As far as I've heard, lot of the interest in a Spring or Guice ObjectFactory implementation is less for the dependency-injection support and more for the cross-cutting concerns like security and transactions. Doing it dynamically avoids having to coordinate Spring bean-naming and still supports the injection of other XML-defined beans as well as Autowired stuff.

Gérald Quintana - 16/Oct/08 01:43 AM
Chris: Since Spring 2.5 you don't need to register each bean in the Context XML file, you can use @Component and component scan for that.

Chris Herron - 06/Nov/08 05:27 PM
Per conversation on IRC, add MultipartWrapper to Freddy's list of Stripes components that ObjectFactory would handle:

- ActionBeans
- ActionBeanContext
- Interceptors
- ExceptionHandler
- Formatters
- TypeConverters
- TagErrorRenderer
- MultipartWrapper

John Newman - 10/Nov/08 02:08 PM
Wait, is this change meant to give the developer access to instantiation of action bean properties? Or is it for stripes components?

If it's both (I think we need both), do you think they should be separated into ObjectFactory and StripesComponentFactory?

I know we would probably have very different logic in both cases, stripes components would have spring beans injected, model objects may have some default values etc. It would be more dev friendly if the stripes level instantiation was in a totally different area than business entity instantiation.

StripesComponentFactory would instantiate ObjectFactory ... =)

Thoughts?


Chris Herron - 08/Dec/08 09:35 AM
I've added my SpringObjectFactory work to the Stripes Stuff project (http://www.stripes-stuff.org/).
See the the Stripes Users Mailing List for details. For feedback, please contact me directly, or use the ML.

Ben Gunter - 26/Feb/09 02:40 PM
I think we're settled on the API at this point. There might still be some minor changes, but it's basically done. Please give it a try and let us know how it goes. Closing as resolved, but feel free to continue commenting.

John Newman - 27/Feb/09 11:13 AM
Ben, can you clarify this for us real quick:

Do we now have access to the instantiation of A) fields in the action bean and/or B) action beans and stripes components themselves?

Ben Gunter - 27/Feb/09 04:15 PM
After initialization, everything instantiated by Stripes (type converters, formatters, action beans, action bean contexts, everything during binding) is initalized through the ObjectFactory. You have access to it all.

John Newman - 27/Feb/09 04:31 PM
thank you, that is exactly what i wanted to hear. So much quirky glue code to tie stripes and spring together will be getting deleted.

great job

Ben Gunter - 28/Feb/09 01:19 PM
Since we didn't document this in these comments earlier, I'll do so now. The preferred way to post-process new objects in Stripes is to implement an ObjectPostProcessor<T> and drop it into your extensions package. You also still can extend DefaultObjectFactory and override postProcess(Object), but that is a little less flexible. DefaultObjectFactory uses the same strategy used by DefaultFormatterFactory to find a post-processor based on interfaces and inheritance, which enables you to write, for example, an ObjectPostProcessor<ActionBean>, drop it in place and not have to worry about whether the object you're handed is an ActionBean or not.

There are some more advanced cases where you'd need to extend DefaultObjectFactory, though. One Striper did so to add constructor injection, which has to be done instead of the no-arg constructor call by DefaultObjectFactory.

Ben Gunter - 02/Mar/09 07:16 PM
We've decided that 1.5.1 will be bug fixes only so I'm removing this from 1.5.1. The commits that have been made for this issue to the 1.5.x branch will be rolled back. Look for this new feature in 1.6.