blob: 8e3084388a596b8f85561541a3f46c4be56c756d [file] [log] [blame]
----
Overriding Services
----
Overriding Services
Tapestry is designed to be easy to customize, and the IoC container is key to that customizability.
Part of Tapestry's core functionality is resolving injected objects; that is, when Tapestry is building an object
or service and sees a constructor parameter or a field, what value does it plug in? Most of the time,
the injected object is a service defined elsewhere within the container (and, in fact, that actual instance
will be a proxy to the service, which may not have been fully realized yet).
However, there are cases where you might want to override how Tapestry operates in some specific way.
The strategy used to determine what object gets injected where is
{{{../injection.html}defined inside Tapestry IoC itself}}; thus we can take advantage of
several features of the IoC container in order to take control over specific injections.
Overriding Services
In most cases, services are injected by matching just type; there no @InjectService annotation,
just a method or constructor parameter whose type matches the service's interface.
In this case, it is very easy to supply your own alternate implementation of a service.
<<AppModule.java>> (partial)
----
public static void contributeServiceOverride(MappedConfiguration<Class,Object> configuration)
{
configuration.add(SomeServiceType.class, new SomeServiceType() { . . . });
}
----
In this example, the service to be overriden is provided as an inner class implementing the interface.
Sometimes you'll want to define the override as a service of its own: this is useful if you want
to inject a Logger specific to the service, or if the overriding implementation needs a configuration:
<<AppModule.java>> (partial)
----
public static void bind(ServiceBinder binder)
{
binder.bind(SomeServiceType.class, SomeServiceTypeOverrideImpl.class).withId("Override");
}
public static void contributeServiceOverride(MappedConfiguration<Class,Object> configuration, @Local SomeServiceType override)
{
configuration.add(SomeServiceType.class, override);
}
----
Here we're defining a service local to this module using the bind() method.
Every service in the IoC container must have a unique id, that's why we used the withId() method; if we we hadn't,
the default service id would have been "SomeServiceType" which is a likely conflict with the very service we're trying to
override.
We can inject our overriding implementation of SomeServiceType using the special
@{{{../../apidocs/org/apache/tapestry5/annotations/Local.html}Local}} annotation, which indicates that a service
within the same module only should be injected: otherwise there would be a problem because the override parameter
would need to be resolved using the MasterObjectProvider and, ultimately, the ServiceOverride service; this would cause
Tapestry to throw an exception indicating that ServiceOverride depends on itself. We defuse that situation by using
@Local, which prevents the MasterObjectProvider service from being used to resolve the override parameter.
Decorating Services
Another option is to {{{../deocrator.html}decorate}} the existing service. Perhaps you want to extend some of the behavior
of the service but keep the rest.
Alternately, this approach is useful to override a service that is matched using marker annotations.
<<AppModule.java>> (partial)
----
public SomeServiceType decorateSomeServiceType(SomeServiceType original)
{
return new SomeServiceType() { . . . };
}
----
This decorate method is invoked because its name matches the service id of the original service, "SomeServiceType"
(you have to adjust the name to match the service id).
It is passed the original service and its job it to return an <interceptor>, and object that implements the same
interface, wrapping around the original service.
Note that the object passed in as original may be the core service implementation, or it may be some other
interceptor from some other decorator for the same service (often, such a parameter is named "delegate" to highlight
this ambiguity).