On Fri, 27 Sep 2013 18:09:13 -0300, Barry Books <[email protected]> wrote:
It useful for library modules because you can build a set of pages,
components and classes that work on Interfaces instead of concrete
classes.
The application can just implement the interfaces and contribute them. In
my case about I have an Invoice interface that's is defined in a shop
module. The shop module just operates on the Interface. Then I have a web
app that implements that Interface in my case as a DynamoDB object.
Others could implement it as a JPA or Hibernate object.
A library module can define interfaces and @Inject them without the module
itself defining the service implementations. Of course, to test or use it,
you'll need to create and define implementations for that services, maybe
mocks in some module class outside the library component that defines that
inteface, but that's not a requirement for building a module library. All
you need to do is to *not* define the service and let other module class
(maybe AppModule) do that. If no one actually provides a service
implementation, Tapestry will raise an exception explaining that.
There are several reasons it needs to be in the core.
1. It would be great if BeanEditForm used it so BeanEditForm could work
with interfaces.
Actually, implementing BeanModel yourself or decorating one created
through BeanModelSource and passing it to BeanEditForm and BeanEditor,
probably by decorating or advising the BeanModelSource service, you can
implement the BeanModel.newInstance() method (or decorate the BeanModel
created by BeanModelSource and override the newInstance() method) and have
it instantiate any object you want automatically (as long at it implements
the interface, of course).
2. If you are going to build a Modules based on Interfaces it needs to be
in the core otherwise everyone will end up with a different
implementation and they don't interoperate.
I'm sorry, I'm not following you here, maybe because of my explanation
below.
3. It's easier to use in pages/components than locator.
Agreed. If it's just about instantiating objects based on interfaces, I've
just discovered ObjectProvider and MasterObjectProvider (which is
basically a façade around the list of ObjectProviders), which I believe
may fit the scenario you're thinking:
/**
* Object providers represent an alternate way to locate an object
provided somewhere in the {@link
* org.apache.tapestry5.ioc.Registry}. Instead of using a just the service
id to gain access to a service within the
* Registry, object providers in different flavors are capable of vending,
or even creating, objects of disparate types
* from disparate sources.
* <p/>
* Object providers are consulted in a strict order, and the first
non-null result is taken.
* <p/>
* In many cases, an object provider searches for additional annotations
on the element (usually a parameter, or perhaps
* a field) for which a value is required.
*/
public interface ObjectProvider {
<T> T provide(Class<T> objectType, AnnotationProvider annotationProvider,
ObjectLocator locator);
}
4. Tapestry is really good about using Interfaces to define functionality
but it's difficult to do this in modules that define components. This
solves most of the problems.
I'm sorry, I'm not following you here, maybe because of my explanation
above.
By the way, for many scenarios, I've found that defining a chain of
responsibility service (which Tapestry calls chain of command for some
reason) the best way for dealing with stuff with distributed configuration
instead of just defining a service. For example, your scenario deals with
instantiating objects defining a given interface the library which defines
this interface doesn't know the implementations. So I could define an
InterfaceInstantiator service:
@UsesOrderedConfiguration(InterfaceInstantiator.class);
public interface InterfaceInstantiator<T> {
/**
* Instantiates an object of the given type. If this
implementation doesn't support that type,
* this method should return null.
*/
<T> instantiate(Class<T> type);
}
And define it as a service that receives instances of itself as its
distributed configuration (!!!):
public static InterfaceInstantiator buildInterfaceInstantiator(
OrderedConfiguration<InterfaceInstantiator> configuration,
ChainBuilder chainBuilder) {
return chainBuilder.build(IterfaceInstantiator.class, configuration);
}
By the way, many of the most important Tapestry services are defined in
this Inception-esque this way (MasterDispatcher,
ComponentClassTransformerWorker, DataTypeAnalyzer, InjctionProvider).
Summary: what I wrote here will probably be turned into a blog post about
chain of responsibility in Tapestry-IoC later, but I think ObjectProvider
and MasterObjectProvider are widely unknown interfaces that already do
what you want.
--
Thiago H. de Paula Figueiredo
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]