Skip to main content

Resource sharing with Maven Dependency Plugin

 We have typically known maven as a build automation and dependency management tool. But can it also help us share resources across artefacts? Well, yes this is possible. But what is the use case for such sharing. Let's say I am maintaining a project with multiple micro services. Out of one service is input to another. Although this design scales well and is easy to extend it is hard to test end to end, especially when I want to ensure a small change in one service does not break my overall system. One approach is to write integration tests on sample data but data may evolve over time and sample data will need to be updated frequently.


A more evolved approach would be to create a seperate repository just to test the entire flow. Lets call it Test Drive App. Test Drive App repo can have production data updated frequently in its class path. This will give us 2 options. 

1. Test released artefacts with sample data within Test Drive App on local machine

2. Import resources from Test Drive App in to each individual service to test run it locally


Case 1 is simple. For case 2 we need to make the sample data available to the component service. We can copy all data in each component but that will increase redundancy and the repo size. This can be non trivial if the data being processed is in magnitudes of hundreds of GB. So we do not want to copy test data in each component. 

Maven Dependency Plugin

Using maven dependency plugin you can unpack only the resources you need in your component project
<build>
      <plugins>
        <plugin>
         <groupid>org.apache.maven.plugins</groupid>
         <artifactid>maven-dependency-plugin</artifactid>
         <version>3.6.0</version>
         <executions>
          <execution>
           <id>unpack-test-resources</id>
           <phase>generate-test-resources</phase><!--During test resource generation-->
              <goals>
                <goal>unpack</goal>
              </goals>
              <configuration>
                <artifactitems>
                  <artifactitem>
                    <groupid>com.example.project.component</groupid>
                    <artifactid>test-drive-application</artifactid>
                    <version>0.0.0.1</version>
                    <type>jar</type>
                    <overwrite>true</overwrite>
                    <outputdirectory>${project.build.directory}/test-resources</outputdirectory>
                    <includes>ComponentFolder/**</includes> <!--Only unpack this folder-->
                  </artifactitem>
                </artifactitems>
              </configuration>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </build>

✨ What this does:

  • During the generate-test-resources phase,

  • Maven will unpack only ComponentFolder/** folder

  • Into target/test-resources/

Without importing any .class files, no pollution.

Then, in your test code, you can load it from target/test-resources/:

Path resourceFolder = Paths.get("target", "test-resources", "ComponentFolder", "products");

Or mount it into Docker container in Test containers like:

container.withCopyFileToContainer(

    MountableFile.forHostPath(resourceFolder),

    "/container/path/products"

);

For the above code to work however you will need test containers dependency:
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>${testcontainers.version}</version>
<scope>test</scope>
</dependency>
Now you’re not depending on the JAR's classpath, just its unpacked files! 
This approach avoids class path pollution and prevents unwanted class files from dependency leaking in to your project. Super clean when writing integration tests that need large config/resource files. 

Comments

Popular posts from this blog

Intercommunication in the world of micro services

I always wondered what can be the different ways in which the microservices can commmunicate with each other. Like majority of us I almost instintively thought of REST or SOAP as two prominant ways of passing data over internet, but are there other better ways of making the different components of an enterprise systen talk to each other? If yes what is the purpose of their existance, lets address these and other related queries in this article. The manner in which micro services talk to each other can be classified in four major categories: Synchronous Communication Asynchronous Communication Database Level Communication Hybrid Lets explore them one by one -  Synchronous Communication In this style of inter service communication a sender service requests some resource from its counterpart and then waits for the response before proceeding ahead. This is also called blocking mode because the caller is blocked till it gets wahat it had requested. Lets explore some protocols which use ...

Spark Checkpointing,Union, Lineage And Partioning

I have been working on apache spark lately and wanted to consolidated my learnings at one place so that I can refer later and make it available to other developers as well. While working with spark you will often run into situations where the way you write code normally results in most inefficient results. You can visualise spark plan executions but it is very tedious to navigate and make sense of in terms of what exactly is cause of the problem. In such case having basic knowledge of how spark manages tasks can help arrive at solutions to improve compute efficiency. Below are a set of techniques I have used to improve compute efficiency of spark applications. SparkContext with a Checkpoint Directory In  Apache Spark , the  SparkContext  is the entry point to interact with the Spark framework. It manages the execution of jobs, resource allocation, and coordination across clusters. A  checkpoint directory  in Spark is used to store  checkpointed RDDs or stre...

Java 21: 1 Hour Crash Course

Let’s embark on a  journey to discover the most important parts of Java 21 . I’ll cover the essentials, highlight new features in Java 21, and provide code samples and explanations. At the end of this article you’ll get a solid foundation and pointers for deeper study. Let's get started! Java 21: 1 Hour Crash Course 1. Introduction Java  is a powerful, object-oriented programming language. Java 21, released in September 2023, brings performance improvements and new features. Prerequisites: Basic programming concepts (variables, loops, functions). Java installed (JDK 21). 2. Your First Program public class HelloWorld { public static void main ( String [ ] args ) { System . out . println ( "Hello, Java 21!" ) ; } } public class HelloWorld  — Defines a class. public static void main  — Entry point. System.out.println  — Prints to console. 3. Variables and Data Types int age = 25 ; double price = 19.99 ; boolean isJavaFun = true ...