Skip to content

Guicey bundles

By analogy with dropwizard bundles, guicey has it's own GuiceyBundle. These bundles contains almost the same options as main GuiceBundle builder. The main purpose is to group installers, extensions and guice modules related to specific feature.

Guicey bundles are initialized during dropwizard run phase. All guice modules registered in bundles will also be checked for required dropwizard objects autowiring.

For example, custom integration with some scheduler framework will require installers to register tasks and guice module to configure framework. GuiceyBundle will allow reduce integration to just one bundle installation.

public class XLibIntegrationBundle implements GuiceyBundle {

    @Override
    public void initialize(final GuiceyBootstrap bootstrap) {
        bootstrap.installers(
                XLibFeature1Installer.class,
                XLibFeature2Installer.class,                
        )
        .modules(new XLibGuiceModule());
    }
}

bootstrap.addBundle(GuiceBundle.<TestConfiguration>builder()
        .bundles(new XLibIntegrationBundle())
        .enableAutoConfig("package.to.scan")
        .build()
);

Tip

GuiceyBootstrap object used not only for registration, but also provides access to Bootstrap, Configuration, ConfigurationTree, Environment and Options objects.

Bundles may be used to group application features: e.g. ResourcesBundle, TasksBundle (for example, when auto-scan not enabled to decompose configuration).

Bundles are transitive - bundle can install other bundles. Duplicate bundles are detected using bundle type, so infinite configuration loops or duplicate configurations are not possible.

Warning

Be careful if bundle is parameterizable (requires constructor arguments). If two such bundles will be registered, only first registration will be actually used and other instance ignored. Note that application configurations (using main GuiceBundle methods) performed before bundles processing and so bundle instance with correct parameters could be registered there.

Transitive bundles (or simply a lot of bundles) may cause confusion. Use diagnostic info to see how guicey was actually configured.

Predefined bundles

Guicey ships with few predefined bundles.

Core installers bundle

Default installers are grouped into CoreInstallersBundle. This bundle is always installed implicitly (so you always have default installers). It may be disabled using .noDefaultInstallers().

Web installers bundle

WebInstallersBundle provides installers for servlets, filters and listeners installation using servlet api annotations (@WebServlet, @WebFilter, @WebListener).

Warning

Bundle is not installed by default to avoid confusion. May be enabled using .useWebInstallers().

Tip

If web installers used, then you may not need guice ServletModule support. To remove GuiceFilter registrations and ServletModule support use .noGuiceFilter().

HK2 debug bundle

HK2DebugBundle is special debug bundle to check that beans properly instantiated by guice or HK2 (and no beans are instantiated by both).

Only beans installed by installers implementing JerseyInstaller (ResourceInstaller, JerseyProviderInstaller). All beans must be created by guice and only beans annotated with @HK2Managed must be instantiated by HK2.

Bundle may be used in tests. For example using guicey.bundles property (see bundles lookup below).

May be enabled by .strictScopeControl().

Note

Works in both guice-first or HK2-first modes.

Diagnostic bundle

Bundle renders collected guicey diagnostic information.

Output is highly configurable, use: DiagnosticBundle.builder() to configure reporting (if required).

Bundle may be registered with bundle lookup mechanism. For example:

PropertyBundleLookup.enableBundles(DiagnosticBundle.class);

May be enabled by .printDiagnosticInfo() shortcut method.

Special shortcut .printAvailableInstallers() register diagnostic bundle configured for showing only installers. Useful when you looking for available features.

Only one bundle instance accepted, both options can't be enabled at the same time.

Dropwizard bundles unification

Guicey bundles and dropwizard bundles may be unified providing single (standard) extension point for both dropwizard and guicey features:

public class MixedBundle implements ConfiguredBundle, GuiceyBundle {

    public void initialize(Bootstrap<?> bootstrap) {
        // do something in init phase
    }   

    public void initialize(GuiceyBootstrap bootstrap) {
        // apply guicey configurations
    } 

    public void run(T configuration, Environment environment) throws Exception {
        // not needed because everything could be done in guicey bundle's method
    } 
} 

Feature is disabled by default, to enable it use .configureFromDropwizardBundles() method.

bootstrap.addBundle(new MixedBundle());
bootstrap.addBundle(GuiceBundle.builder()
        .configureFromDropwizardBundles(true)
        .build()
);

When active, all registered dropwizard bundles are checked if they implement GuiceyBundle. Works with both Bundle and ConfiguredBundle dropwizard bundle types.

Warning

Don't assume if guicey bundle's initialize method will be called before/after dropwizard bundle's run method. Both are possible (it depends if bundle registered before or after GuiceBundle).

Bundle lookup

Bundle lookup mechanism used to lookup guicey bundles in various sources. It may be used to activate specific bundles in tests (e.g. HK2DebugBundle) or to install 3rd party extensions from classpath.

Bundle lookup is equivalent to registering bundle directly using builder bundles method.

By default, 2 lookup mechanisms active. All found bundles are logged into console. Duplicate bundles are removed (using bundle class to detect duplicate).

To disable default lookups use disableBundleLookup:

bootstrap.addBundle(GuiceBundle.<TestConfiguration>builder()
        .disableBundleLookup()
        .build()

System property lookup

System property guicey.bundles could contain comma separated list of guicey bundle classes. These bundles must have no-args constructor.

For example, activate HK2 debug bundle for tests:

java ... -Dguicey.bundles=ru.vyarus.dropwizard.guice.module.jersey.debug.HK2DebugBundle

Alternatively, system property may be set in code:

PropertyBundleLookup.enableBundles(HK2DebugBundle.class)

Service loader lookup

Using default java ServiceLoader mechanism, loads all GuiceyBundle services.

This is useful for automatically install 3rd party extensions (additional installers, extensions, guice modules).

3rd party jar must contain services file:

META-INF/services/ru.vyarus.dropwizard.guice.module.installer.bundle.GuiceyBundle

File contain one or more (per line) GuiceyBundle implementations. E.g.

com.foo.Bundle1
com.foo.Bundle2

Then Bundle1, Bundle2 would be loaded automatically on startup.

Customizing lookup mechanism

Custom bundle lookup must implement GuiceyBundleLookup interface:

public class CustomBundleLookup implements GuiceyBundleLookup {

    @Override
    public List<GuiceyBundle> lookup() {
        List<GuiceyBundle> bundles = Lists.newArrayList();
        ...
        return bundles;
    }
}

Custom lookup implementation may be registered through:

bootstrap.addBundle(GuiceBundle.<TestConfiguration>builder()
        .bundleLookup(new CustomBundleLookup())
        .build()

But it's better to register it through default implementation DefaultBundleLookup, which performs composition of multiple lookup implementations and logs resolved bundles to console.

bootstrap.addBundle(GuiceBundle.<TestConfiguration>builder()
        .bundleLookup(new DefaultBundleLookup().addLookup(new CustomBundleLookup()))
        .build()

To override list of default lookups:

bootstrap.addBundle(GuiceBundle.<TestConfiguration>builder()
        .bundleLookup(new DefaultBundleLookup(new ServiceLoaderBundleLookup(), new CustomBundleLookup()))
        .build()

Here two lookup mechanisms registered (property lookup is not registered and will not be implicitly added).

Options

Options could be used in guicey bundes:

public class MyBundle implements GuiceyBundle {
    @Override
    public void initialize(GuiceyBootstrap bootstrap) {
        if (bootstrap.option(GuiceyOptions.UseHkBridge)) {
            // show warning that bridge required
        } 
    }
}

Or it could be some custom options usage.

Apply modifications

Bundles could not only register new items, but also disable other.

bootstrap
    .disableInstallers(..)
    .disableExtensions(..)
    .disableModules()

Note

Bundles can't disable other bundles (because target bundle could be already processed at this point).

This could be used to register different versions instead of disabled items.

Also, bundle could directly override guice bindings with:

bootstrap
    .modulesOverride(new OverridingModule())

Configuration access

Unique feature config

When working with re-usable bundles, it could be handy to rely on unique configuration object:

public class XFeatureBundle implements GuiceyBundle {
    @Override
    public void initialize(GuiceyBootstrap bootstrap) {
        XFeatureConfig conf = bootstrap.configuration(XFeatureConfig.class);
        ...
    }
}

Note that this bundle doesn't known exact type of user configuration, it just assumes that XFeatureConfig is declared somewhere in configuration (on any level) just once. For example:

public class MyConfig extends Configuration {

    @JsonProperty
    private XFeatureConfig xfeature;

    ...
}

Important

Object uniqueness checked by exact type match, so if configuration also contains some extending class (XFeatureConfigExt) it will be different unique config.

Access by path

When you are not sure that configuration is unique, you can rely on exact path definition:

public class XFeatureBundle implements GuiceyBundle {
    private String path;

    public XFeatureBundle(String path) {
        this.path = path;
    } 

    @Override
    public void initialize(GuiceyBootstrap bootstrap) {
        XFeatureConfig conf = bootstrap.configuration(path);
        ...
    }
}

Path is declared by bundle user, who knows required configuration location:

GuiceBundle.builder()
    .bundles(new XFeatureBundle("sub.feature"))
    ...
    .build()

Where

public class MyConfig extends Configuration {

    @JsonProperty
    private SubConfig sub = { // pseudo code to combine class declarations
         @JsonProperty
         private XFeatureConfig feature;   
    }

    ...
}

Warning

Remember that you can't register 2 bundles with the same class

Multiple configs

In case, when multiple config objects could be declared in user configuration, you can access all of them:

public class XFeatureBundle implements GuiceyBundle {
    @Override
    public void initialize(GuiceyBootstrap bootstrap) {
        List<XFeatureConfig> confs = configurations(XFeatureConfig.class);
        ...
    }
}

For configuration

public class MyConfig extends Configuration {

    @JsonProperty
    private XFeatureConfig xfeature;
    @JsonProperty
    private XFeatureConfig xfeature2;

    ...
}

It wil return both objects: [xfeature, xfeature2]

Important

In contrast to unique configurations, this method returns all subclasses too. So if there are XFeatureConfigExt declared somewhere it will also be returned.

Custom configuration analysis

In all other cases (with more complex requirements) you can use ConfigurationTree object which represents introspected configuration paths.

public class XFeatureBundle implements GuiceyBundle {
    @Override
    public void initialize(GuiceyBootstrap bootstrap) {
         // get all properties of custom configuration (ignoring properties from base classes)
        List<ConfigPath> paths = bootstrap.configurationTree()
                .findAllRootPathsFrom(MyConfig.class);

        // search for not null values of marked (annotated) classes            
        List markedTypes = paths.stream()
            .filter(it -> it.getValue() != null 
                    && it.getType().getValueType().hasAnnotation(MyMarker.class))
            .map(it -> it.getValue())
            .collect(Collectors.toList());
        ...
    }
}

In this example, bundle search for properties declared directly in MyConfig configuration class with not null value and annotated (classes annotated, not properties!) with custom marker (@MyMarker).

See introspected configuration structure description