I have gone through the documentation, but still not able to achieve what I am trying to. The requirement is very simple. I have two maven projects. ProjectA and ProjectB. ProjectB requires to reuse some common configs and code from ProjectA. I don't want to just copy and paste them as this is will require to updates if anything changes. So, what are the options now? How can I achieve this?
I don't think there is a silver bullet for this but we use combination of these two aproaches:
Multi-module project (best if projects are connected and you want to change common parts a lot): https://maven.apache.org/guides/mini/guide-multiple-modules.html
Extract parts you want to reuse from projectA and make it a standalone artifact which you publish to maven repo (local/private/public - depending on your use case).
You might have two options.
Use your ProjectA has parent of your projectB
http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
<parent>
<groupId>com.example</groupId>
<artifactId>projectA</artifactId>
<version>1.0</version>
</parent>
<artifactId>projectB</artifactId>
Thus, your projectB will inherit from the first one, with all its dependencies build / dependency management.
Use your ProjectA has dependency of your projectB
http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
<artifactId>projectB</artifactId>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>projectA</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
In this case, projectB wil inherit from projectA all the sources and dependencies.
I created a multi module maven project but it was always compiling that the packages not found. Eventually, I figured out the issue here. Maven Multi-module dependency package not found
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<classifier>exec</classifier>
</configuration>
</execution>
</executions>
Related
I have a multi module maven project wie quarkus modules and some custom libraries which are local maven repositories (so they can be used by the other maven projects/modules). However, so that local maven repositories are recognizable und usable by your other local maven projects, you have to manually index them for some reason. I.e. add a config like this for quarkus index to the application.properties of the project including the local maven repo dependency:
quarkus.index-dependency.<index-name>.group-id = <group-id-of-local-maven-repo>
quarkus.index-dependency.<index-name>.artifact-id = <artifact-id-of-local-maven-repo>
The problem is, this causes issues for me becausse if you have 3 layers of project dependencies, say:
Project A (custom local maven repo library)
Project B (custom local maven repo library, includes Project A dependency)
application.properties (indexing Project A library dependency)
Project C (Local maven project for an end product, includes Project B
library dependency - and through it indirectly Project A).
application.properties (indexing Project B library dependency and config for datasources or other app related things)
Then when you generate an uber-jar (fat jar) of Project C for deployment, it for some reason uses application.properties of Project B in the packaged jar, instead of from the project which im building (Project C). Thus, the app is missing key configs and does not work. Maven seems to use an inverse priority here, which i dont know if thats a bug or not. When i asked about this, i was simply told that:
"My dependencies should not have application.properties".
I tried to find a way to prevent manual indexing via application.properties and found the maven jandex plugin - which is supposed to generate an index. The next problem is, this seems to only work in some projects but not in others in the dependency hierarchy, resulting in the same situation as before, and i don't understand why. This is the pom.xml config for the plugin i have included in all 3 projects (the entire pom.xml for all is too long, so let me know if you need more info):
<properties>
...
<jandex.skip>false</jandex.skip>
...
</properties>
...
<build>
...
<plugin>
<groupId>io.smallrye</groupId>
<artifactId>jandex-maven-plugin</artifactId>
<version>3.0.5</version>
<inherited>true</inherited>
<executions>
<execution>
<id>make-index</id>
<goals>
<goal>jandex</goal>
</goals>
</execution>
</executions>
<configuration>
<skip>${jandex.skip}</skip>
</configuration>
</plugin>
...
The odd thing is, this works to the extend that i no longer have to index Project B library dependency in Project C application.properties, but Project B library dependency still has to manually index Project A library dependency - thus rendering the entire exercise futile. Project C having an application.properties was never the issue, and is obviously needed. Project B still requires a properties file to point to Project A now, how do i solve this?
I have a parent module POM in the root folder containing all these projects, over which this maven jandex dependency is distributed to all modules, so it looks like this:
Maven parent module (contains all dependencies and versions used by all project sub modules)
Project A (custom local maven library repo), own pom.xml with inheritance from parent module
Project B (custom local maven library repo, includes Project A library), own pom.xml with inheritance from parent module
application.properties - Indexes Project A dependency manually, this is the problematic one which needs to go!
Project C (Local maven project for REST API etc., includes Project B library), own pom.xml with inheritance from parent module
pom.xml (parent module POM, containing maven jandex dependepency among others)
Edit: One of the projects, "entity", where all the database access objects are stored, does not run the jandex plugin during mvn clean install. This is the POM of the project:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.compamny.project</groupId>
<artifactId>entity</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-orm</artifactId>
<version>2.16.1.Final</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-validator</artifactId>
<version>2.16.1.Final</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive-jackson</artifactId>
<version>2.16.1.Final</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
<version>2.13.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.smallrye/jandex-maven-plugin -->
<dependency>
<groupId>io.smallrye</groupId>
<artifactId>jandex-maven-plugin</artifactId>
<version>3.0.0</version>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
<plugin>
<groupId>io.smallrye</groupId>
<artifactId>jandex-maven-plugin</artifactId>
<version>3.0.0</version>
<inherited>true</inherited>
<executions>
<execution>
<id>make-index</id>
<goals>
<goal>jandex</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
When i force the execution of the jandex goal with mvn io.smallrye:jandex-maven-plugin:3.0.0:jandex it creates an META-INF/jandex.jdx file, but it does not produce one when i run mvn clean install. This is not a solution since i need to build the project, run the jandex plugin and install it into my local repositories separately. Also, notice that im using the "io.smallrye" version of the jandex plugin since the "org.jboss" version seems to not work at all.
I figured it out. The jandex plugin was set in the <pluginManagement> section of the POM configuration, which made it not run on mvn clean install. I had to move it to the plugins section so it gets executed. Thanks #Ladicek for making me look closer and keep trying!
This question already has answers here:
What does the parent tag in Maven pom represent?
(4 answers)
Closed 4 years ago.
In my project I alway use <dependency><dependency> but I can see <parent></parent> in some project pom.xml like:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
</parent>
so I want to konw when to use it.
<parent> a superset of <dependencies>
<parent> and <dependencies> elements are two distinct things but it exists all the same an important relation between them.
Simply said the parent defines the parent pom of the current pom and dependencies defines the actual dependencies of the current pom.
The parent pom can define dependencies but also many other things inherited by the children Maven project (and particularly the dependencyManagement element and the build element that allow to configure many things) can so be considered in a some way as a superset of the dependencies element.
Here is the list of elements inherited from the parent pom :
groupId
version
description
url
inceptionYear
organization
licenses
developers
contributors
mailingLists
scm
issueManagement
ciManagement
properties
dependencyManagement
dependencies
repositories
pluginRepositories
build
plugin executions with matching ids
plugin configuration
etc.
reporting
profiles
As use dependencies and as use <parent>?
We can use only the first, only the second or both.
It depends really on the way which the Maven projects are designed.
Trying to enumerate all possible configurations would be long and not necessary very helpful.
So I think that you should really retain that parent is much more structuring as dependencies as it defines both more things for the children projects but it also allow not to repeat the actual configuration that you want to define in a set of projects.
So you should favor parent as you want to make inherit some child Maven projects an overall configuration and not only a list of dependencies.
Your example is perfect to illustrate the consequences on the client projects from using <parent> or dependencies as alternative.
1) With parent inheriting
Here the project inherits from the spring-boot-starter-parent pom :
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
</parent>
As a consequence, the project will inherit any things defined in dependencies and dependencyManagement but it will also inherit from the <build> element defined in the super pom.
For example you would have the Maven compiler plugin configured out of the box with Java 8 and UTF-8 (that you can of course redefined in your child project) :
<properties>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<resource.delimiter>#</resource.delimiter>
<maven.compiler.source>${java.version}</maven.compiler.source>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>${java.version}</maven.compiler.target>
</properties>
Additionally, some other plugins potential useful by a Spring Boot project will also be defined in the super pom and be inherited by your project such as :
<pluginManagement>
<plugins>
...
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>${start-class}</mainClass>
</configuration>
</plugin>
...
</plugins>
</pluginManagement>
Note that a parent pom may define dependencies, directly inherited by the child projects but not necessary.
For example the spring-boot-starter-parent doesn't define any dependency directly inherited by child projects but instead of define dependency in <dependencyManagement><dependencies>.
It means that children of this parent pom may use the dependencies but they have to explicitly state that in dependencies.
For example :
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
Note that the version is not valued as inherited.
2) Without parent inheriting
You will have to define all required dependencies by your Spring Boot application in or more straightly use the spring-boot-dependencies dependency in dependencyManagement with a import scope to have a way to declare them thanks to the dependency management feature :
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.2.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
But in any cases you will never inherit from the plugins configured out of the box by the parent as you don't have parent.
So you should declare them explicitly in the pom.xml of your project.
For example to define the compiler version, used encoding and configure the build to repackage the built component(to make it standalone executable), you will will have to specify more things :
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<springboot.version>1.5.2.RELEASE</springboot.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${springboot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${springboot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>myClass</mainClass>
</configuration>
</plugin>
<plugins>
</build>
A parent POM can be declared with packaging pom. It is not meant to be distributed because it is only referenced from other projects.
Where as a dependency pom is declared as a jar. So, that it can be included in the project and thus the project can consume it's features.
Maven parent pom can contain almost everything and those can be inherited into child pom files, e.g
Common data – Developers’ names, SCM address, distribution management etc.
Constants – Such as version numbers
Common dependencies – Common to all child. It has same effect as writing them several times in individual pom files.
Properties – For example plugins, declarations, executions and IDs.
Configurations
Resources
The use case <paraent> is where you store information for version(s) of artifacts and compiler settings/version which is used across modules.
See following for details Introduction to the POM
A dependency is libraries you need to get your code to compile. This can be your own code, or libraries such as Apache Commons.
A parent contains information, but nothing to actually build, that is shared between a number of your projects. Suppose that you have a couple of modules of related code, and you want to ensure that the same versions of libraries are used by all modules. Then you could define those libraries in the <dependencies> section of each module, but you would define the version in the <dependencyManagement> section of the parent module.
Parent POMs can have their own parents, so you can build a whole hierarchy.
I have many java projects, each with its maven build. They all install fine.
In addition, I have many JUnit tests. These tests may depend on other projects, i.e. a test from Project A may import a class from Project B.
My projects are not structered good (all of the classes are just in src directory and not src/main/java). So when I run mvn clean test I get No sources to compile. If I structure it good by moving all of the main classes to src/main/java and all the tests to src/test/java I keep getting cannot find symbol (with a reference to an import of a class in a different project).
I tried defining <testSourceDirectory>, used many different plugins and profiles and also tried lowering my java configuration level to 1.7, all to no avail.
I even tried defining a TestProject that has a simple POM with many modules (either with only <modules>, or defining <dependencies> or both), but even in this - either I get No sources to compile, cannot find symbol or even package x.y does not exist (or it compiles but trying to include it in other projects does nothing).
Can I run a test that involves classes from other other projects? How?
Maybe you can have and use Test dependencies. I'll explain how i achieve that, hope it's usefull for your project.
I've got a project with many subprojects (named projectA, projectB, etc.) each one with its own Tests. Also one of the projects named 'core' with jar packaging that contains common classes. They look like the following structure:
Main
|- core (jar)
|- projectA (war)
|- projectB (war)
All tests on the diferent projects used common code that finally were placed on 'core' project test clases.
This is how we manage the dependencies on maven 3.1.1.
Only for reference Main is also a project with its own pom.xml
Main (pom.xml):
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.myproject</groupId>
<artifactId>MyArtifact</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<properties>
</properties>
<repositories>
</repositories>
<modules>
<module>core</module>
<module>projectA</module>
<module>projectB</module>
</modules>
...
</project>
On core project pom.xml we put:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>core</artifactId>
<packaging>jar</packaging>
<parent>
<groupId>com.mycompany.myproject</groupId>
<artifactId>MyArtifact</artifactId>
<version>1.0</version>
</parent>
<build>
<pluginManagement>
<plugins>
<!-- Common test classes jar creation -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.5</version>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
...
And on the rest of the projects pom.xml we put the dependency with this jar:
<dependencies>
<!-- We put dependency with core.jar an test-core.jar -->
<dependency>
<groupId>com.mycompany.myproject</groupId>
<artifactId>core</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>com.mycompany.myproject</groupId>
<artifactId>core</artifactId>
<version>1.0</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
Eclipse warns about this maven dependency but it works fin when running Test from the command line with maven.
Hope this helps.
I'm turning a single Eclipse Maven-managed webapp project in a multi-module Maven project (this is a test project to experiment with Maven, so feel free to provide any kind of suggestion).
The single project webapp doean't have any error, succesfully compiles and behaves correctly when deployed, so I'm starting with a working application.
The application has a web part and a console part, meaning that there are some classes with a main() method that when run from within Eclipse (with Run as -> Java Application) work as expected. Both parts show data from a database, queried either directly through JDBC or through jOOQ.
So, this is how I split the project:
core (holds everything common to the other two parts);
runnable (contains the classes that have a main() method);
webapp (the web application part).
Inside Eclipse, I have now 4 separate projects:
shaker-multi holds the aggregator (and parent) POM, plus each module in a subdirectory;
shaker-multi-core;
shaker-multi-runnable;
shaker-multi-webapp.
Inside Eclipse, core and webapp compile, and the latter can be deployed to a Tomcat instance and I can see it in the browser.
The problem arises with runnable. That project relies on jOOQ classes, so the relevant source code must be generated. The jOOQ dependencies and configuration are in core/pom.xml (since they may be used there too).
When I do Project -> Run As -> Maven build... -> clean generate-sources, on shaker-multi-core I get:
Non-resolvable parent POM: Failure to find sunshine.web:shaker-multi:pom:0.0.1
which sounds reasonable, since I didn't install any of those artifacts, even in my local repository.
But when I call Maven build... -> 'clean install' on shaker-multi, it breaks because it can't find the web.xml file for shaker-multi-webapp (although it correctly resides in shaker-multi-webapp/src/main/webapp/WEB-INF/web.xml).
What should I do?
Is my project configuration / splitting totally wrong?
Should I add another module with the parent POM? This sounds wrong, since the POM Reference states:
Inheritance and aggregation create a nice dynamic to control builds through a single, high-level POM. You will often see projects that are both parents and aggregators.
I'm totally lost here.
My expectations:
run Maven package on shaker-multi-webapp and obtain a deployable war;
run Maven package on shaker-multi-runnable and obtain a command line runnable jar (I still need to configure its POM to generate a jar-with-dependencies, though, I know);
run Maven package on shaker-multi and obtain some kind of bundle that I can move around and that will contain the war or the jar of each module.
EDIT
I added
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<webXml>src/main/webapp/WEB-INF/web.xml</webXml>
</configuration>
</plugin>
to shaker-multi-webapp POM, as seen in this answer, but with no difference.
EDIT-2
I cleared my whole local repository (as suggested here), and when I reopened Eclipse, in the Maven console I saw
[...]
05/09/14 07:58:19 CEST: [INFO] Adding source folder /shaker-multi-webapp/src/main/java
05/09/14 07:58:19 CEST: [INFO] Adding source folder /shaker-multi-webapp/src/test/java
**05/09/14 07:58:19 CEST: [ERROR] Could not read web.xml**
[...]
Any hint? From where does it come from? I can't reproduce it though (without removing again my whole local repo).
This is shaker-multi POM:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>sunshine.web</groupId>
<artifactId>shaker-multi</artifactId>
<version>0.0.1</version>
<packaging>pom</packaging>
<modules>
<module>shaker-multi-core</module>
<module>shaker-multi-runnable</module>
<module>shaker-multi-webapp</module>
</modules>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
This is shaker-multi-core POM:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>sunshine.web</groupId>
<artifactId>shaker-multi</artifactId>
<version>0.0.1</version>
</parent>
<artifactId>shaker-multi-core</artifactId>
<packaging>jar</packaging>
<build>
<plugins>
<plugin><!-- jOOQ plugin--></plugin>
</plugins>
</build>
<dependencies>
<dependency><!-- jOOQ dependency --></dependency>
</dependencies>
</project>
This is shaker-multi-webapp POM:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>sunshine.web</groupId>
<artifactId>shaker-multi</artifactId>
<version>0.0.1</version>
</parent>
<artifactId>shaker-multi-webapp</artifactId>
<packaging>war</packaging>
<build>
<plugins>
<plugin><!-- Tomcat local -->
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>sunshine.web</groupId>
<artifactId>shaker-multi-core</artifactId>
<version>0.0.1</version>
</dependency>
<dependency>
<!-- JSP & Servlet dependencies -->
</dependency>
</dependencies>
</project>
I assume you folder structure is like this:
+-- shaker-multi
+--- pom.xml
+--- shaker-multi-core
+-- pom.xml
+--- shaker-multi-runnable
+-- pom.xml
+--- shaker-multi-webapp
+-- pom.xml
Furthermore you should check if your project works correctly on command and
NOT in Eclipse. So you should go to the root of your project
(shaker-multi folder) and
mvn clean package
This should produce no error etc.
One thing which comes into my mind is why do you use a release version instead of
a SNAPSHOT version for your project. So 0.0.1 instead of 0.0.1-SNAPSHOT?
A thing which you should improve is the definintion of maven-compiler plugin
in your parent:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
I would suggest to do it this way:
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
The encoding can be solved in a better way just define the following in your pom:
<project>
...
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
...
</project>
The above will define the default value for many plugin like maven-compiler-plugin,
maven-resources-plugin etc.
part from that your structure looks good ...one small improvement i would
suggest is if you define dependencies between your module:
<dependencies>
<dependency>
<groupId>sunshine.web</groupId>
<artifactId>shaker-multi-core</artifactId>
<version>0.0.1</version>
</dependency>
<dependency>
<!-- JSP & Servlet dependencies -->
</dependency>
</dependencies>
I would suggest to define inter module dependencies like this:
<dependencies>
<dependency>
<groupId>sunshine.web</groupId>
<artifactId>shaker-multi-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<!-- JSP & Servlet dependencies -->
</dependency>
</dependencies>
The whole problem here was really simple, and I feel a bit ashamed about it: but being the first time I did a multi–module project, I guess that could happen.
Of course, the details here hold when you work with all the project and modules sources by yourself: if you're in a team, working on only a part of the project and / or with a centralized private repository, then YMMV.
First of all, after I splitted the single–project into several modules, this was the situation in my Eclipse Project Explorer:
+-- shaker-multi
^--- pom.xml
^--- shaker-multi-core
^-- pom.xml
^-- (other content)
^--- shaker-multi-runnable
^-- pom.xml
^-- (other content)
^--- shaker-multi-webapp
^-- pom.xml
^-- (other content)
+-- shaker-multi-core
^-- pom.xml
+-- shaker-multi-runnable
^-- pom.xml
+-- shaker-multi-webapp
^-- pom.xml
Each +-- is a single, separated, Eclipse project. Each one of them has been singularly checked out from SVN (so they were, in fact, detached from one another).
I was, then, editing something in +-- shaker-multi-runnable and expecting that to work when I was running Maven on +-- shaker-multi, without svn–committing the former and svn–updating the latter.
That's why I kept getting the error in this question!
The proper way to handle such projects, if they come from an originally monolithic project is:
to split the code, resources, etc in subfolders;
to commit every change to the repository;
to erase every involved project in Eclipse.
Next, you go in the SVN Repositories tab of the IDE, expand the repository with the now splitted project and do Check out as Maven project of the parent–project (the one that has modules as subfolders).
If you, like me, are working with a recent version of Subclipse, you'll need the Maven Eclipse (m2e) SCM connector for subclipse 1.10 (svn 1.8) - update site (thanks go to buluschek development, see the last comments on that post), so that you can choose the repository path from the Check out as Maven Project dialog.
With it, you tell Eclipse to checkout the whole project from the parent folder, and the Eclipse automatically:
fetches all the Maven project modules;
creates a project corresponding to the parent–project, where modules are subfolders;
creates a separate project for every single module
links together each module project with the parent project, so that each edit in a module source code, resource, POM, etc is instantly reflected inside the folders of the parent-project.
That point (4) is the key here: although there are several projects, they have been linked together (I guess the same can be done when manually checking out each module folder, although I do not know how).
After having done this, all the Maven problems I had disappeared.
This is my parent pom.xml (part of it) in a multi-module project:
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
…
This configuration instructs mvn to execute checkstyle plugin in the root project and every sub-module. I don't want it to work this way. Instead, I want this plugin to be executed only for the root project, and be skipped for every sub-module. At the same time, I have many sub-modules, and I don't like the idea of explicitly skipping the plugin execution in every one of them.
Documentation for Checkstyle says "..ensure that you do not include the Maven Checkstyle Plugin in your sub modules..". But how can I ensure that if my sub-modules inherit my root pom.xml? I'm lost, please help.
But how can I ensure that if my sub-modules inherit my root pom.xml?
To strictly answer this question, you can specify an <inherited> element inside a <plugin> definition. From the POM Reference:
inherited: true or false, whether or not this plugin configuration should apply to POMs which inherit from this one.
Something like this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<!-- Lock down plugin version for build reproducibility -->
<version>2.5</version>
<inherited>true</inherited>
<configuration>
...
</configuration>
</plugin>
Some more advices/remarks (that may not apply):
You should always lock down plugin version for build reproducibility (you can enforce this rule with the Maven Enforcer Plugin).
People usually wants to use a a Custom Checkstyle Checker Configuration and/or a Suppressions Filter.
The Multimodule Configuration describes a typical setup allowing to share configuration files in large multimodules projects.
Perhaps you should separate your root pom into 2 separate entities: parent pom and aggregator pom. Your aggregator pom may even inherit from parent pom.
If you download latest project layout for hibernate, you will see this design pattern in action.
After this separation is done, you can define and execute checkstyle plugin just in aggregator/root pom. Because it is no longer a parent of your submodules it will not get inherited by them.
EDIT
Use <relativePath> when declaring <parent>
Just for demonstration, below is an example taken from the hibernate project structure.
The whole distribution can be found here-> http://sourceforge.net/projects/hibernate/files/hibernate3
Just so, that you have some context, here is a subset of their directory layout
project-root
|
+-pom.xml
|
+ parent
| |
| +-pom.xml
|
+ core
|
+-pom.xml
.. rest is scipped for brevity
project-root/pom.xml fragment
<parent>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-parent</artifactId>
<version>3.5.4-Final</version>
<relativePath>parent/pom.xml</relativePath>
</parent>
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
<packaging>pom</packaging>
<name>Hibernate Core Aggregator</name>
<description>Aggregator of the Hibernate Core modules.</description>
<modules>
<module>parent</module>
<module>core</module>
project-root/parent/pom.xml fragment
<groupId>org.hibernate</groupId>
<artifactId>hibernate-parent</artifactId>
<packaging>pom</packaging>
<version>3.5.4-Final</version>
project-root/core/pom.xml fragment
<parent>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-parent</artifactId>
<version>3.5.4-Final</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<packaging>jar</packaging>