Skip to content

Installers

Installer is a core integration concept: every extension point has it's own installer. Installers used for both auto scan and manual modes (the only difference is in manual mode classes specified manually). Installers itself are resolved using classpath scanning, so it's very easy to add custom installers (and possibly override default one by disabling it and registering alternative).

All default installers are registered by CoreInstallersBundle

How it works

When installer recognize class, it binds it into guice binder.bind(foundClass) (or bind by installer if it support binding). But extensions annotated with @LazyBinding are not bound to guice context. This may be useful to delay bean creation: by default, guice production stage will instantiate all registered beans.

On run phase (after injector created) all found or manually provided extensions are installed by type or instantiated (injector.getInstance(foundClass)) and passed to installer to register extension within dropwizard (installation type is defined by installer).

Installers are ordered.

Each extension is installed by only one installer!

If extension could be recognized by more then one installers, it will be installed only by first matching installer (according to installers order).

Writing custom installer

Installer should implement FeatureInstaller interface. It will be automatically registered if auto scan is enabled. To register manually use .installers() bundle option.

Installer matches method implements feature detection logic. You can use FeatureUtils for type checks, because it's denies abstract classes. Method is called for classes found during scan to detect installable features and for classes directly specified with .extensions() bundle option to detect installer.

Three types of installation supported. Installer should implement one or more of these interfaces:

  • BindingInstaller allows custom guice bindings. If installer doesn't implement this interface sinmple bind(type) will be called to register in guice.
  • TypeInstaller used for registration based on type (no instance created during installation).
  • InstanceInstaller used for instance registration. Instance created using injector.getInstance(type).
  • JerseyInstaller used for registration of bindings in HK context.

Note that extensions may use @LazyBinding annotation. In general case such extensions will not be registered in guice. In case of BindingInstaller, special hint will be passed and installer should decide how to handle it (may throw exception as not supported).

BindingInstaller called in time of injector creation, whereas TypeInstaller and InstanceInstaller are called just after injector creation. JerseyInstaller is called on jersey start.

Installers are not guice beans! So injections can't be used inside them. This is because installers also used during initialization phase and instantiated before injector creation.

Example installer:

public class CustomInstaller implements FeatureInstaller<CustomFeature> {
    @Override
    public boolean matches(final Class<?> type) {
        return FeatureUtils.is(type, CustomFeature.class);
    }    
}

Finds all CustomFeature derived classes and register them in guice (implicit registration - all classes matched by installer are registered in injector). Note that no installer interfaces were used, because guice registration is enough.

Now suppose CustomFeature is a base class for our jersey extensions. Then installer will be:

public class CustomInstaller implements FeatureInstaller<CustomFeature>, JerseyInstaller<CustomFeature> {
    @Override
    public boolean matches(final Class<?> type) {
        return FeatureUtils.is(type, CustomFeature.class);
    }

    @Override
    public void install(final AbstractBinder binder, final Class<CustomFeature> type) {
        JerseyBinding.bindComponent(binder, type);
    }

    @Override
    public void report() {
    }
}

Ordering

In order to support ordering, installer must implement Ordered interface. If installer doesn't implement it extensions will not be sorted, even if extensions has @Order annotations.

As example, see ManagedInstaller

Reporting

Installers report() method will be called after it finish installation of all found extensions. Report provides user visibility of installed extensions.

To simplify reporting use predefined Reporter class. See example usage in ManagedInstaller

INFO  [2016-08-21 23:49:49,534] ru.vyarus.dropwizard.guice.module.installer.feature.ManagedInstaller: managed =

    (ru.vyarus.dropwizard.guice.support.feature.DummyManaged)

For complex cases, reporter may be extended to better handle installed extensions. As examples see plugin installer reporter and provider installer reporter

INFO  [2016-08-21 23:49:49,535] ru.vyarus.dropwizard.guice.module.installer.feature.plugin.PluginInstaller: plugins =

    Set<PluginInterface>
        (ru.vyarus.dropwizard.guice.support.feature.DummyPlugin1)
        (ru.vyarus.dropwizard.guice.support.feature.DummyPlugin2)

    Map<DummyPluginKey, PluginInterface>
        ONE        (ru.vyarus.dropwizard.guice.support.feature.DummyNamedPlugin1)
        TWO        (ru.vyarus.dropwizard.guice.support.feature.DummyNamedPlugin2)