How to create two JARs from one project (...and why you shouldn't)
By Tim OBrien
8 minute read time
This is a repost of an answer on Stack Overflow. Someone asked a question about creating two build targets from a single project. Here is an excerpt from the question:
...the ant build has 2 build targets - one that builds the entire app, and one that builds a jar from some of those files (only a few). In ant, it's easy to have multiple build targets to handle this, but I'm trying to determine the best way to handle this in maven.
I could split the subset of files into a second project and it will have its own pom. Then the first project could depend on this one. However, since the subset of files is so small (less than 10), it seems like it might be overkill to have an entirely new project for that.
I answered by detailing two solutions. Using two separate profiles to build two classified JAR artifacts, and configuring two extra executions of the JAR plugin. I want to be very clear about this answer. We strongly recommend that you not configure a Maven project to create two separate JARs from a single project. It violates one of the most important core concepts of Maven: modularity. Once you go down this path, you will likely be tempted to start creating more and more "uber" projects that create multiple JARs. If you start designing complex POM profiles to generate these JARs you are going to have to do a lot of heavy-lifting managing dependencies (classified dependencies), and fixing hard-to-diagnose bugs in different projects.
In doing this, you break a core convention of Maven, and when you do this, you are on your own. Tools that have been designed to work with Maven won't help you. The various forums and mailing lists set up to provide you with help will be of no use. I wrote this answer to counter the argument that Maven isn't "flexible" and that it "forces" you to work within its limitations. This isn't true. You can do just about anything you want to do in Maven. You can customize the lifecycle to do just about anything you need it to do. Maven, like Ant, is infinitely flexible. Assuming that you've read the books and are familiar with plugin configuration syntax, you could configure Maven to do anything. The real question isn't "can I do this with Maven?" it is "should I do this with Maven?" If you are violating a core convention, the answer is usually no.
The following is my answer from Stack Overflow:
Click here for the original Answer on Stack.
You could do this with profiles...
If you really wanted to use two separate profiles and customize the JAR plugin to include and exclude patterns of class and package names, you could easily do this by putting something like this in your POM:
<code><profiles> <profile> <id>everything</id>; <build> <plugins> <plugin> <artifactId>maven-jar-plugin</artifactId> <configuration> <classifier>everything</classifier> <includes> <include>**/*</include> </includes> </configuration> </plugin> </plugins> </build> </profile> <profile> <id>only-library</id> <build> <plugins> <plugin> <artifactId>maven-jar-plugin</artifactId> <configuration> <classifier>only-library</classifier> <excludes> <exclude&>**/Main*</exclude> </excludes> </configuration> </plugin> </plugins> </build> </profile> </profiles> </code>
Aside: If that seems like a lot of configuration, polyglot Maven's support for Groovy POMs is just about ready. It will cut the line count down considerably.
You would put this at the end of your pom.xml (withing the project element), and it adds two profiles. The first profile "everything" is really just there to demonstrate the configuration. This "everything" profile is unnecessary because it simply duplicates the behavior of the default JAR plugin jar goal execution. The second profile "only-library" excludes any class in any package that starts with the text "Main." To invoke these profiles:
<code>mvn package -Peverything mvn package -Ponly-library </code>
I tested this against the sample application that ships with Chapter 6 of Maven by Example, and running either of these commands will produce a JAR file in ${basedir}/target that has a classifier. Since the JAR plugin's jar goal is bound to the package phase in the default maven lifecycle, these two profiles are going to modify the configuration for this plugin.
Or, you could do this with two JAR plugin executions...
If you need to create two JARs without using profiles. You can bind the JAR plugin's jar goal to the package lifecycle phase multiple times and use different configuration for each configured execution. If you configure two separate executions, each execution has an execution-specific configuration block so you can supply a unique identifier and include/exclude pattern for each execution.
Here is the build element you would use to add both custom JARs to the lifecycle phase "package." Doing this on a project with packaging "jar" would result in the jar goal being run three times. Once as the default lifecycle binding, and then twice for two custom, classified JARs.
<code> <build> <plugins> <plugin> <artifactId>maven-jar-plugin</artifactId> <executions> <execution> <id>only-library</id> <goals><goal>jar</goal></goals> <phase>package</phase> <configuration> <classifier>only-library</classifier> <excludes> <exclude>**/Main</exclude> </excludes> </configuration> </execution> <execution> <id>everything</id> <goals><goal>jar</goal></goals> <phase>package</phase> <configuration> <classifier>everything</classifier> <includes> <include>**/*</include> </includes> </configuration> </execution> </executions> </plugin> </plugins> </build> </code>
If you are not talking about including a different set of classes in each artifact, you'll want to use Maven Assemblies. If you want to know the details of assemblies, there is a chapter listed at the end of this answer from Maven: The Complete Reference. Frankly, i don't think that this particular chapter is a good introductory reference; in fact, I've had numerous reports that this chapter is nearly unreadable (and we're working to fix that). If you are looking to use assemblies, I'd recommend the Maven Assembly Plugin's documentation. In the left-hand nav menu you'll see a list of sample assembly descriptors.
Disclaimer: (Please) don't do this. If you are creating two different JARs with two different set of classes I strongly recommend that you split the project up into two interdependent modules.
While you can do this with profiles, it is going to be easier for you to split the project into two (actually three). Longer term there are going to be challenges that you are going to face as your application scales. You will be responsible for figuring out this manual list of classes and packages to be included in each of your classified JARs.
There is minimal overhead to having a simple parent project that references two separate modules. If you look at the free Maven by Example book, we show how to make the transition between a single-module and a multi-module project. Chapters 3-5 focus on single module projects, and Chapter 6 shows you how you would combine these single module components into a larger multi-module project.
For more information:
- The Maven JAR Plugin: http://maven.apache.org/plugins/maven-jar-plugin/jar-mojo.html
- Multi-module Maven Projects: Chapter 6 of Maven by Example and Section 3.6.2 of Maven: The Complete Reference.
- The Maven Lifecycle (jar is bound to package if your packagin is "jar"): Section 3.5.2 of Maven by Example "Core Concepts" and Chapter 4 of Maven: The Complete Reference.
- Maven Assemblies: First, the Maven Assembly Plugin site, then Chapter 8 of Maven: The Complete Reference for some heavy (almost too heavy) details.
Written by Tim OBrien
Tim is a Software Architect with experience in all aspects of software development from project inception to developing scaleable production architectures for large-scale systems during critical, high-risk events such as Black Friday. He has helped many organizations ranging from small startups to Fortune 100 companies take a more strategic approach to adopting and evaluating technology and managing the risks associated with change.
Explore All Posts by Tim OBrien