Multi module application

Hi,

First of all, congratulations on the 1.0 release it is awesome!

I am starting a new project and wanted to structure it a bit different. My idea is to have one single (gradle) project with several modules in it, one for the application and others for components. That is: I want to put in the same project the Jmix application and Jmix components.

My rationale is that having everything in one place at the beggining lets me move fast, but having some pieces in components very early on will force for better decoupling and make my life easier as the project grows.

The 1st thing I noticed is that Jmix documentation does not include many details about components as CUBA did (cuba docs). Not much of a problem, I cloned several of the current addons to see how they are built.

I have succeeded. I was impressed that it is not completely unexpected because the Studio addon is detecting the components and application and showing all of them!!

But I had to do it all by hand. If you tell IDEA to add a new Module to the project and select Jmix it results in an empty folder with nothing in it. So I had to create the projects and then copy over stuff to the main project amending the gradle files.

I will now drop some snippets for further reference and for anyone looking into this, any feedback is more than welcome!!

I will get to the point at the bottom!

Main project

./gradle.properties
version = 1.0.0-SNAPSHOT
jmixVersion = 1.0.0
bomVersion = 1.0.0-SNAPSHOT
./settings.gradle

This is mostly based on the datatools addon, the gradle files of the subprojects are named as the subproject instead of build.gradle, hence the bottom code block.

rootProject.name = 'mni'

include 'main'  // This is the Application module. Should be named "app" maybe.
include 'a3link-bom:a3link'  // This is the component module
include 'a3link-bom:a3link-starter' // This is the Springboot starter for the component

rootProject.children.each { p1 ->
    p1.buildFileName = "${p1.name}.gradle"
    p1.children.each {p2 ->
        p2.buildFileName = "${p2.name}.gradle"
    }
}
./build.gradle

This is also based on the datatools addon mixing parts from an empty Jmix project.

buildscript {
    repositories {
        mavenLocal()
        maven {
            url 'https://nexus.jmix.io/repository/public'
        }
        gradlePluginPortal()
    }
    dependencies {
        classpath("io.jmix.build:jmix-build:${rootProject.findProperty('jmixVersion')}")
        classpath("io.jmix.gradle:jmix-gradle-plugin:${rootProject.findProperty('jmixVersion')}")
    }
}

subprojects {
    group = 'com.company.mni'
    version = rootProject.findProperty('bomVersion')

    repositories {
        mavenLocal()
        mavenCentral()
        maven {
            url 'https://global.repo.jmix.io/repository/public'
        }
    }

    /* datatools applies jmix plugin here, but we do not as we might want different
       plugins applied for certain modules. So we do this on each module. */
    //apply plugin: 'io.jmix.build'
}

“main” module

This is the application module, it is based on an empty Jmix application project.
The src folder is copied over, and the only gradle file is main.gradle (no settings, properties, wrapper, etc).

./main/main.gradle
plugins {
    id 'io.jmix'
    id 'java'
}

apply plugin: 'org.springframework.boot'

jmix {
    bomVersion = rootProject.findProperty('jmixVersion')
    projectId = 'main'
}

dependencies {
    // here go all the jmix dependencies + spring-boot-starter-web + database driver
    // just copy that from the empty project

    // Add the components from the project
    implementation project(':a3link-bom:a3link-starter')
}

test {
    useJUnitPlatform()
}

a3link module

Here start the doubts… I created a -bom module and put both component’s modules in here (the component + starter modules) so I can keep them toghether. I could have them directly on the rootProject. I have no idea of what the implication are except that I need an extra build file (for the -bom project) and the project names are longer (:project-bom:project). Also, the a3link-bom.gradle file has some stuff that might be needed (based on a clean component build.gradle file)

./a3link-bom/a3link-bom.gradle

Mostly based on the build.gradle of and empty component project,

subprojects {
    apply plugin: 'java-library'
    apply plugin: 'io.jmix'

    jmix {
        bomVersion = rootProject.findProperty('jmixVersion')
        projectId = 'a3link'
    }

    java {
        withSourcesJar()
    }

    artifacts {
        archives sourcesJar
    }
}
./a3link-bom/a3link/a3link.gradle

Inside its module (a3link-bom/a3link)

plugins {
    id 'java'
}

archivesBaseName = 'a3link'

dependencies {
    // Jmix dependencies, copied from the empty project
}

test {
    useJUnitPlatform()
}
./a3link-bom/a3link/a3link-starter.gradle

Inside its module (a3link-bom/a3link-starter)

archivesBaseName = 'a3link-starter'

jmix {
    entitiesEnhancing {
        enabled = false
    }
}

dependencies {
    api project(':a3link-bom:a3link')

    implementation 'io.jmix.core:jmix-core'
    implementation 'io.jmix.data:jmix-data'

    implementation 'org.springframework.boot:spring-boot-autoconfigure'
}

To the point

So, now to the point:

  1. Is such a setup supported or discouraged? (having one big gradle project with application+components)
  2. If it is supported, may Jmix include such a project template in the future? (multi module application)
  3. Will Jmix documentation expand on components on future releases like CUBA did?
  4. If I had more than one application subproject, how would I tell Jmix Studio which one to run then using the “Jmix Application” configuration?
  5. If the “creating a Jmix module inside a project results in an empty folder” can be reproduced, please file and issue!

Best,
Marc

2 Likes