Reputation: 371
I have created extended alert manager: interface
public interface AlertManagerExt extends AlertManager {
void successCode(String messageCode, Object... args);
void infoCode(String messageCode, Object... args);
void warnCode(String messageCode, Object... args);
void errorCode(String messageCode, Object... args);
}
and implementation
public class AlertManagerExtImpl extends AlertManagerImpl implements AlertManagerExt {
private final Messages messages;
public AlertManagerExtImpl(ApplicationStateManager asm, Request request, AjaxResponseRenderer ajaxResponseRenderer,
PerthreadManager perThreadManager, Messages messages) {
super(asm, request, ajaxResponseRenderer, perThreadManager);
this.messages = messages;
}
@Override
public void successCode(String messageCode, Object... args) {
success(getMessage(messageCode, args));
}
@Override
public void infoCode(String messageCode, Object... args) {
info(getMessage(messageCode, args));
}
@Override
public void warnCode(String messageCode, Object... args) {
warn(getMessage(messageCode, args));
}
@Override
public void errorCode(String messageCode, Object... args) {
error(getMessage(messageCode, args));
}
protected String getMessage(String code, Object... args) {
if (args.length > 0) {
return messages.format(code, args);
}
return messages.get(code);
}
}
When I tried to bind it via binder:
binder.bind(AlertManagerExt.class, AlertManagerExtImpl.class);
I got exception:
java.lang.RuntimeException: Service interface org.apache.tapestry5.alerts.AlertManager is matched by 2 services: AlertManager, AlertManagerExtImpl. Automatic dependency resolution requires that exactly one service implement the interface.
at org.apache.tapestry5.ioc.internal.RegistryImpl.getServiceByTypeAlone(RegistryImpl.java:789)
at org.apache.tapestry5.ioc.internal.RegistryImpl.getServiceByTypeAndMarkers(RegistryImpl.java:797)
at org.apache.tapestry5.ioc.internal.RegistryImpl.getService(RegistryImpl.java:755)
I know I can copy-and-paste all methods from AlertManager and do not extend it. But may be there is better way?
Upvotes: 2
Views: 356
Reputation: 11
I know I'm a bit late to the party but I ran into a similar exception trying to override an internal Tapestry service implementation, (GoogleClosureMinimizerOptionsProvider in my case), and I managed to solve it using by contributing to ServiceOverride.class using the annotation. For example in my Tapestry ApplicationModule, I have this:
@Contribute(ServiceOverride.class)
public static void contributeServiceOverride(MappedConfiguration<Class<? extends GoogleClosureMinimizerOptionsProvider>,Object<? super GoogleClosureMinimizerOptionsProvider>> configuration) {
configuration.addInstance(GoogleClosureMinimizerOptionsProvider.class, CustomGCMCompilerOptions.class)
I believe this could work in your case as well:
@Contribute(ServiceOverride.class)
public static void contributeServiceOverride(MappedConfiguration<Class<? extends AlertManager,Object<? super AlertManager> configuration) {
configuration.addInstance(AlertManager.class, AlertManagerExtImpl.class)
Quick ref to the ServiceOverride
interface Tapestry5 APIDocs:
@UsesMappedConfiguration(key=java.lang.Class.class, value=java.lang.Object.class) public interface ServiceOverride
Used to override built in services. Simply contribute a mapping from a type >to an instance of that type. Anywhere that exact type is injected, without >specifying markers or other annotations, the contributed instance will be >injected, even if there is already a service that implements the interface.
In fact, this is not limited to overriding services; any object that can be >injected based solely on type can be contributed.
Upvotes: 0
Reputation: 891
This is because Tapestry IoC tries to find all services that implement an interface when you try to @Inject
it by interface type only. Your new AlertManagerExt
also implements the AlertManager
hence the ambiguity.
This is usually resolved by explicitly specifying service ID or marker annotation, but this won't work for your case as tapestry's core code already @Inject
ing AlertManager
by interface only.
Upvotes: 1
Reputation: 139
You can accomplish this in a few ways, depending on what you really need. I invite you to read the documentation and the IoC cookbook.
Understanding the Inversion of Control configuration is important because it's a very powerful module.
Upvotes: -1