Skip to content
Immortius edited this page Nov 28, 2019 · 2 revisions

Module Environment

A module environment is a loaded set of modules that are available for use.

Creation

A ModuleEnvironment requires the following during creation

  • The set of modules that will compose the environment
  • A PermissionProviderFactory - typically ModuleSecurityManager - that produces a PermissionProvider specifying the allowed permissions and classes for each module.
  • Optionally a ClassLoaderProvider to use to generate the ModuleClassLoader from the module. This is used to support Android (use gestalt-android's AndroidModuleClassLoader) or to introduce byte code injection.
  • Optionally the root classloader to base the module classloaders on. If not provided the classloader providing ModuleEnvironment is used.

ModuleEnvironment will create a classloader for every module providing code, chained so that dependencies are earlier in the chain that dependent modules.

Usage

ModuleEnvironment provides methods for discovering classes of interest from the modules loaded within it

getSubtypesOf

getSubtypesOf(BaseClass.class);
getSubtypesOf(BaseClass.class, new FromModule(environment, moduleId)); 

This method returns all subtypes of a class from the environment. Optionally a Predicate can be provided to filter the results.

getTypesAnnotatedWith

getTypesAnnotatedWith(Annotation.class);
getTypesAnnotatedWith(Annotation.class, new FromModule(environment, moduleId));

This method returns all types marked with an annotation. The annotation must have runtime retention.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
}

This will also include types with a parent marked with the annotation.

getModuleProviding

ModuleEnvironment also provides a method to determine which Module provided a given type, if any

getModuleProviding(SomeClass.class);

Considerations

You should avoid mixing objects from two different ModuleEnvironments - because they have different classloader hierarchies, their types are different and not compatible. For instance, if a module introduces an interface, an object implementing that interface in one ModuleEnvironment cannot be passed to a method on an object from a different ModuleEnvironment - the second ModuleEnvironment has a distinct version of that interface.

Cleanup

When you have finished a module environment you should close it - this will close all the classloaders it has created. They will not be disposed until all classes and instances of those classes have been disposed however - so you will need to ensure this occurs.

environment.close();

If you only need an environment for a short period, it can be created as a resource in a try-with-resources.

try (ModuleEnvironment environment = new ModuleEnvironment(modules, securityManager, injectors)) {
   // Do stuff
}

You do not need to worry about cleanup if the application is shutting down.