xl0e
xl0e

Reputation: 371

How to override tapestry AlertManager

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

Answers (3)

permabei
permabei

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

Dmitry Gusev
Dmitry Gusev

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 @Injecting AlertManager by interface only.

Upvotes: 1

Dushko Jovanovski
Dushko Jovanovski

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

Related Questions