Say you have a Application Project that’s run as a container. It has a dependency on a module from another in-house Library Project .

Deployment jobs on your CI/CD tool are:

  • 🔨 Library Project : Compiles and mvn deploys the modules to a private maven registry.
  • 🔨 Application Project : Builds the image (pulling in Library Project ’s jars during the image build stage’s mvn install).

What if you want to make local changes to Library Project and test them on your local via Application Project without having to deploy Library Project first?

If you’re running Application Project outside of a container it’s a given: as long as you compiled Library Project locally then subsequent compiles of Application Project will use the updated jars from your local .m2 when pulling in module(s) of Library Project as dependencies.

But what if Application Project must be (or is most convenient to) run as a container? Some options:

  1. Make a volume mapped to your local .m2 folder that can be used during Application Project ’s build.

    • ❌ Impossible: Docker has no concept of volumes at buildtime and there’s currently no way to have BuildKit’s cache be mapped to an actual folder on the host.
  2. Perpetually run a maven registry server on localhost - with it’s .m2 mapped to your local .m2.

    • 👍 Having a shared .m2 between your local & localhost maven registry server means you wouldn’t have to deploy to the local repository - only have to install to your local .m2 and it would be picked up by the local maven server.
    • 👎 Have to perpetually run a local maven registry server on your local during development.
    • 👎 Have to add logic in the Application Project ’s docker file so that it accepts the URL:port of the local maven registry server as a (build-arg)[https://docs.docker.com/build/guide/build-args/] for local builds and passes that on via maven (command-line argument)[https://www.baeldung.com/maven-arguments#define-placeholders-for-properties] to the pom to use as a repository:

    Build

    > ... docker build --build-arg LOCAL_MAVEN_REGISTRY="https://localhost:8080" ...
    

    Dockerfile

    ARG LOCAL_MAVEN_REGISTRY # empty by default
    
    ...
    
    RUN --mount-type=cache,target=/root/.m2 mvn install -DLOCAL_MAVEN_REGISTRY=$LOCAL_MAVEN_REGISTRY
    
    ...
    
    

    pom.xml

    <project>
    
    ...
    
    <repositories>
        <repository>
            <id>local-maven-registry</id>
            <url>${LOCAL_MAVEN_REGISTRY}</url>
        </repository>
    </repositories>
    
    ...
    
    </project>
    
  3. Give Library Project a dockerfile that builds the source and stores the built jars in the built image. Then have Application Project grab those jars and put them in their own BuildKit cache’s .m2 before building the source.

    • 👍 Don’t need to perpetually run a local maven registry server on your local during development.
    • 👎 Have to add a Dockerfile in Library Project and logic in it that copies over the built folder from it’s BuildKit cache’s .m2 folder into the image:
    
    ...
    
    # build the project
    RUN --mount-type=cache,target=/root/.m2 mvn install
    
    # remove source files and copy over built .m2 sub-folder for the project into the image
    RUN rm -Rf *
    RUN --mount-type=cache,target=/root/.m2 cp -r /root/.m2/repository/org/example/library-example/* .
    
    ...
    
    
    • 👎 Have to add logic in the Dockerfile of Application Project to copy over the .m2 folder from the dependency image and move to the .m2 of the BuildKit cache:
    # By default it's
    ARG OPTIONAL_EXAMPLE_LIBRARY_IMAGE_NAME="hello-world"
    
    ...
    
    ## -------------------------------------- Optional  ----------------------------------------
    # copy over the example-library jar if the build arg OPTIONAL_EXAMPLE_LIBRARY_IMAGE_NAME is set
    FROM ${OPTIONAL_EXAMPLE_LIBRARY_IMAGE_NAME}:latest
    RUN --mount-type=cache,target=/root/.m2 if [[ "$OPTIONAL_EXAMPLE_LIBRARY_IMAGE_NAME" != "hello-world" ]] ; then \
        rm -Rf /root/.m2/repository/org/example/library-example/*; fi && \
        mkdir -p /root/.m2/repository/org/example/library-example && \
        cp -r /usr/src/* /root/.m2/repository/org/example/library-example/.; \
    fi
    
    ...