Modules

In Apache Causeway we use Spring @Configurations to define a module, consisting of a set of domain services and domain objects (entities, view models and mixins). Spring’s @Import is used to express a dependency between each "configuration" module.

See Spring documentation on annotation-based container configuration, classpath scanning and java-based configuration for much more on this topic.

By convention, we have one Spring "logical" module in each Maven "physical" module, meaning that Maven itself can be used to enforce acyclic dependencies. (See previous chapter for more discussion on the alternatives).

Thus, there will be a single top-level package corresponding to the module, and this will be aligned with the <groupId> and <artifactId> of the Maven module in which it resides.

The framework’s own modules follow this convention. For example, the Excel extension module has several submodules, one of which is its applib. This:

  • has a Maven

    • groupId = org.apache.causeway.extensions

    • artifactId = causeway-extensions-excel-applib

  • in the applib, has a top-level package of org.apache.causeway.extensions.excel.applib

  • defines a Spring configuration module called CausewayModuleExtExcelApplib, that is simply:

    @Configuration
    @ComponentScan                                  (1)
    public class CausewayModuleExtExcelApplib {
    }
    1 the @ComponentScan indicates that the classpath should be scanned for domain services, entities and fixture scripts.

When there is a dependency, this is expressed in two ways: first, as a "physical" <dependency in Maven; and second, as a "logical" dependency using @Import in the @Configuration module.

We can see this for example in the testing module of the Excel library (artifactId of causeway-extensions-excel-testing), where:

Testing submodule depends upon Applib submodule
Figure 1. Testing submodule depends upon Applib submodule

Therefore:

  • in the testing module’s pom.xml, we see:

    <dependency>
        <groupId>org.apache.causeway.extensions</groupId>
        <artifactId>causeway-extensions-excel-applib</artifactId>
    </dependency>
  • and in the testing module’s CausewayModuleExtExcelTesting we see:

    @Configuration
    @Import({                                           (1)
        CausewayModuleExtExcelApplib.class
    })
    @ComponentScan
    public class CausewayModuleExtExcelTesting {
    }
    1 The @Import annotation declares the dependency.
unlike Maven, there is no distinction in Spring between production (src/main/java) and test (src/test/java) classpath dependencies. But if the physical classpath dependency is missing, then an incorrectly defined @Import will simply not compile.

In our own code, if an application’s customers module needs to use the aforementioned Excel subdomain model (perhaps to generate a downloadable report), then this would be expressed using:

package com.mycompany.modules.customer;
...

@Configuration                                  (1)
@Import({
    CausewayModuleExtExcelApplib.class       (2)
})
@ComponentScan                                  (3)
public class CustomerModule {}
1 this is a module
2 dependency on the Excel module (more precisely, its "applib")
3 scan for domain services and objects etc under this package (eg a Customer entity or a CustomerRepository domain service).

Since @Configuration and @ComponentScan often appear together, Apache Causeway provides a convenience @Module annotation, which is meta-annotated with both. The above example could therefore be rewritten as:

package com.mycompany.modules.customer;
...
import org.apache.causeway.applib.annotation.Module;

@Module
@Import({
    CausewayModuleExtExcelApplib.class
})
public class CustomerModule {}