What's the best way to setup Maven for a project that has a SmartClient architecture? Consider the following packages:
myproject.core
myproject.server
myproject.client
Of course there are several sub-packages in each. Client and Server both use core. I see two main options:
Make an uber-POM in myproject to cover all three and have some sort of build parameter to identify what to build.
Make a POM in each package above (one for core, another for server and another for client).
Here are the outputs we need to build (at a minimum):
Standalone.jar: A test application that will launch the server and a client.
Server.war: A WAR file that can be deployed to Tomcat.
Client.jar: The SmartClient without any server code.
Is option #1 even possible? If so, is it good practice? From my initial research, option #2 sounds like best practice. However, jumping from POM to POM when all the code is intimately related sounds like extra work and extra clutter we may not need. Should I just stick with option #2?
Maven has a general rule that there should be only a single artifact per project. In other words, option #1 wouldn't allow you to produce a server.war, a client.jar, etc without fighting against maven. This would be a big mess and you wouldn't be able to take advantage of maven plugins. No, really, you don't want this. So just go for option #2, with a structure like (omitting the src directory):
.
|-- core
| `-- pom.xml
|-- server
| `-- pom.xml
|-- client
| `-- pom.xml
`-- pom.xml
Regarding your concern about jumping from POM to POM, well, just import all modules into your IDE and you won't really notice it. This just works pretty well for lots of people.
UPDATE (to cover questions from the OP in comments):
Fighting against Maven doesn't sound fun.
No, and you will loose :)
What is in the pom.xml at the root level?
This is a parent POM used for Project Aggregation. Quoting the Introduction to the POM document:
Project Aggregation is similar to
Project Inheritance. But instead of
specifying the parent POM from the
module, it specifies the modules from
the parent POM. By doing so, the
parent project now knows its modules,
and if a Maven command is invoked
against the parent project, that Maven
command will then be executed to the
parent's modules as well. To do
Project Aggregation, you must do the
following:
Change the parent POMs packaging to the value "pom" .
Specify in the parent POM the directories of its modules (children
POMs)
Project aggregation and project inheritance are often used together. Refer to the mentioned document for more details.
By "single artifact per project" do you mean that there should be a separate POM for Standalone.jar, Server.war, and Client.jar (three total POMs)?
Yes, this is what I mean, one project generates one artifact (there are some exceptions but this is true 99% of the time). This is a maven best practice that you should (must?) follow.
What if I also want a Server.jar, a simple server based with Grizzly included? Wouldn't server need two POM's?
I think that the maven way to handle this would be to use assemblies and there is no unique answer to your question (this might be one of the exception to the rule mentioned above). But this won't prevent you from starting.
Also, how would one kick off a build that would result in all three artifacts getting produced?
Launch your maven command from an aggregating project as we saw (aka "multi-modules build").
Related
This question already has answers here:
How to activate a Maven profile per pom.xml?
(3 answers)
Closed 7 years ago.
I'm not familiar with Maven and am trying to figure out how it works on our existing project.
project and folder structure is basically
A
A\1
A\2
A\3
Inside each folder is a pom file. Each pom contains 1 or more defined profiles.
What I do not understand is with this command
A>mvn install
How do all of the pom get executed and which profiles are being executed?
I don't see any tags marked with activebydefault
Frustrated when I need to spend time learning at step 1 and build some projects but am forced to be at step 50 without anybody on the team that knows the first thing about Maven. Of course solutions are always due yesterday.
Profiles can be specified in your POM, in your parent POM, in your settings. Hence, looking just at your POM file may not be enough.
Running mvn help:active-profiles would give you a list of all active profiles and from which source (pom or settings).
Running mvn help:all-profiles would give you a list of all available profiles, the active ones and from which source (pom or settings).
Running mvn help:effective-pom -Doutput=full-pom.xml would provide you the full POM file (in the full-pom.xml generated file), as a merging of current pom, parent pom and settings. That would be the full source of true.
The structure you describe is for a multi-module maven project, which means A is the aggregator project (having packaging pom, its only delivery is a pom file, its only function is to provide the modules it will build).
However, beware that in Maven aggregation and inheritance are two different concepts, which are often used together: aggregation means I will build as part of my build all of my defined modules; inheritance means I will inherit configuration from my parent pom. As such, A\1 may inherit profiles from project A if in the pom of A\1 you will find A defined as parent (which is often the case, to have an aggregator which is also parent of all the defined modules).
Why to have an aggregator? To have a centralized build and location of correlated sub-projects while still keep a good separation of concerns across sub-modules. Moreover, as Maven best practices, a project should only generate one artefact, hence it might be the case to have a web application having logic in one module, war generation in another module, ear generation in yet another module, for instance.
Why to have inheritance? To have a centralized place where to set shared/common configuration, like profiles but also dependencies and dependencies management.
Lastly, it is a common misunderstanding and hence be also aware that:
If a profile is active by default in Maven, it will be part of the default build. However, if you activate a profile via command line (via the -P option) you will then activate the requested profile but also and automatically deactivate the one which was active by default
the mechanism above doesn't apply to profiles defined in the settings.xml of your maven installation (which are applied by default, if activated, to all the Maven builds on the concerned machine).
Update A further note on this answer leveraged by some comments: a Maven build is specified as part of the build section (a flow of plugins executions), which doesn't necessarily need profiles. Profiles are generally defined to add a further behavior to the build, but it is good practice to have a build building successfully regardless of any activable profile, that is, I don't have to know about the defined profiles to run your build, it's a core concept of maven, harmonization and convention over configuration: given a Maven project, I can always assume that simply mvn clean install would do the required magic.
For a list of common questions about starting with Maven, the official Getting Started Guide already provides a good help.
Also check the Profiles Pitfalls of the official Introduction to Profiles for further guidance on profiles.
No profile is active unless you have one marked as activeByDefault.
Well here is an interesting experience i had since last couple of weeks structuring my maven multi module project.
When i decided to use maven for my build life cycle management i had couple of reason that i wished to choose maven.
a. Mostly development teams are divided so that each team can work on separate Module within the project like Team-A to work on User Management System, Team-B to work on Authorization System, Team-C to work on Document Management System...and so on. Each team has java developers, testers, UI experts etc.
So the maven Project structure should be such that each team can independently work on their respective modules. They must be able to code, compile, build, test, deploy their module without having to compile, test modules belonging to other teams.
And thus i came to conclusion that each development module of the maven multi-module project must represent a Functional Module
After some discussions on forums i found people suggesting me to follow layered approach were child modules must be layers like controller-layer,service-layer,dao-layer etc. I did not pay heed to this advice because this not solving my purpose of teams working on individual module. This way for large project the build and deployment time for each team during development increases which does impact the project time-lines. sometimes the build and deploy time is upto 30 minutes say if there are 10 to 11 modules in the project.
But i did pay heed to a suggestion that keeping DAO layer separate for each module is not a good idea as DAO is highly granular and reused by other modules. and so the dependency of one module on other would would any how become greater.
I found a solution to this problem by creating a common module and moving DAOs and DOMAIN to the common module which will be inherited as a dependency by each module. And this seems to be a more viable option. Now the Project Structure looks like this.
Now when i build the project and run the webapp on server, It complains 404, Resource Not Found. I found that this is because the WEB-INF/classes folder is missing, src/main/java is missing in web-app module. I searched and found couple of links that suggested it is Deployment Assembly issue in Eclipse. So i need to manually create these folders and add in the deployment assembly because maven does not do it.
But the bigger questions are
do i need to move the Controller classes like com.mycompany.usermgmtsys.controller.UserMgmtController etc.. to src/main/java Or maven should find the controllers from the module jars included as dependency in WEB-INF/lib.
I dont want to do this i.e. putting java file in web-app. i want all the controllers should be available to the web-app as dependency for example WEB-INF/lib/usermgmtsystem.jar. But then wouldnt the Tomcat be looking for controllers in classes folder.
I dont know what should i do ? Any suggestions would be appreciated.
Its the way the eclipse render maven based project. It generally creates two structure. One based on master pom (parent project) and others based on individual module pom. however doing changes in any structure will reflect in the other one. As a practice I do changes in individual module folder structures and is more easy to read too.
Personally I try to avoid multi-module projects as, if you're using the Maven Release Plugin, you are locked into releasing all your modules together.
While this may sound like a convenience the problem arises when you need to do bug fix release to one of the modules - you end up releasing all the modules, not just the module with the bug fix, incrementing their version even though they haven't changed.
You also take a hit if you're running CI with multi-module projects - you're build typically runs over all modules from you root pom but if you're working in a particular module, you end up taking the hit of building those that haven't changed, in effect losing some of the benefits that the modularization was meant to provide.
So, go with independent modules but, and this is the important bit, create a common 'dependency' pom used by each.
A 'dependency' pom is a pom that standardizes all the dependencies across your projects and is different in that those dependencies are specified in the dependencyManagement section rather than the dependencies section (it also sets up standard plugin config, etc). This allows your project poms to specify the dependency pom as their parent and then declare the dependencies they need minus the versions, which are picked up from the 'dependency' pom and thus standardized across your projects.
If you are still concerned about being able to built everything, this can be achieved with a simple batch-file.
This is a good question. There are many aspects that must be considered for a useful project layout. I'd like to try to answer one which you didn't mention. Is your app extensible by users? If it is, then consider creating a separate module for your public API layer (service interfaces, DTOs used by those services, and Exceptions thrown by the services).
In our app, we have several maven modules per functional area. The idea is that a group worked on a feature within just one functional area and this isolation kept them messing with sources being modified by another group. Each functional area is broken down further in maven sub-modules we call "api", "domain", and "service" - we don't lump services/controllers, domain, and exceptions into a single module. The api module contains those classes we want to expose to customers for their customizations. Our service layer is the implementation of those interfaces. Further, we do not allow one module's service to call another module's service as this would bypass our service orchestration layer where customer can attach extensions to our services. Using separate maven modules per functional area helps enforce this.
We have other modules (internal-api, web, adapter) but they don't really add to this topic.
I figured out the issue. Controllers are presentation-layer components. The dispatcher expects the presentation layer components in the WEB-INF/classes folder in the target rather than looking for it in the lib. I am not sure if this is valid only for maven based structuring in eclipse. So finally these are the changes i have made
a. Created a src/main/java source folder in web-app. It is not generated by default in web-app module.
b. Add packages and respective controllers in the src/main/java folder.
So the final structure that i have (i am not pasting exact eclipse snapshot, this is generalized view)
my java se project/system consists of multiple components like below where there can be many shared libs and many applications/ running processes. Example the 3 components below make up 'System 1'.
System 1:
1. Common lib - for our shared code
2. App 1 - a app/process with it's own code referencing the common lib.
3. App 2 - a app/process with it's own code referencing the common lib.
My questions how do i setup Maven/Intelij to support this structure ... and is it a good structure to follow?
At present I have the groupId as 'com.MyCompany.System1' and the Mavan modules for the components with artifactIds as 'com-MyCompany-System1-common' etc.
Is this the correct way to go or how should i arrange Maven to support this structure?
Thanks in advance.
It sounds like a typical Maven multi-module setup should serve your needs. As for IntelliJ, just set it up in Maven and then import the maven pom into IntelliJ. It'll just work. You can just open the pom file as a project, and IntelliJ will set everything up for you correctly.
Advice:
Even if it feels like more work up front, the more you can break up your project into cleanly-defined modules, the happier you'll be in the end.
I wouldn't repeat the groupId in the artifactId. The artifactId should definitely be distinct, but not that distinct.
Consider using Gradle instead if it's an option. It's the next logical step in build tools after Maven, and it'll vastly reduce your effort as the number of modules increases. Gradle/IntelliJ interaction is almost as good as Maven/IntelliJ. It's slightly more work, but the tradeoff is worth it.
Source: I have a mix of >100 Maven and Gradle modules spread across >30 source code repos which I've been building and working in with IntelliJ for 3 years.
In a nutshell, what I am trying to do is build a bunch of libraries and applications, all Maven projects, all at once. From what I understand a way to accomplish this just in one command line run of mvn package would be to create a multimodule project that will list each module that I would like to build, throw them in the Maven reactor, and build.
Following examples in the Maven book it seems that normally a multimodule pom sits in a directory above the individual modules. However it is also normally the case that a parent pom sits in a directory above the modules, which raises the question, is it normally the case that a multimodule build should also be a parent? I think not; however I wonder why I am running into this funny design quirk.
So, I'm wondering the right way to set this up. I see the following conventions / requirements:
The multimodule pom must have knowledge of where the other modules live on disc. Since it is actually doing the build from source it can't simply rely on already installed versions (since it's installing them!)
The parent doesn't actually have to be a physical directory up although that would be preferable. I see this as the convention best to break.
Really the individual libraries/application shouldn't even need to know they are being built as part of a multimodule build.
How is this usually set up in a multimodule build? Is there a simpler way to manage building multiple Maven projects all at once?
I put all the individual modules within the root module. Some software has trouble with multiple layers of hierarchy.
To make a child module refer to it's parent on the same level:
<parent>
<groupId>com.domain</groupId>
<artifactId>xyz</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../xyz/pom.xml</relativePath>
</parent>
I suggest you do not put anything in the multimodule (e.g. properties) that individual modules need to inherit. If you do, you won't be able to build the other modules independently.
I would go so far as to say that this is the fuzzy part of the "conventions". The documentation, and common sense, both suggest that project aggregation ( aka multi-module builds ) and inheritance are two different mechanisms provided to handle different use cases.
At the same time, it seems that there is a de facto convention ( yeah, I know ) of combining both the project aggregation and inheritance parent roles into a single pom. In fact, both the element of the parent declaration and the module element of the project aggegration mechanism seem to steer the use toward this combination.
Personally, I find it very usefull to separate the parent pom out on a regular basis. And I also find it useful ot locate parent pom in a totally separation location in my source control, and thus my folder structure. However, it rarely seems useful to locate builds that are a part of the same multi-module build structure in source control / folder structure. Perhaps this is even a good measure of whether something should be included in the same aggregate build; if it seems to deserve collocation in the source folder structure, then perhaps its a strong candidate for aggregation.
The only thin I am sure of is that these things are worth sorting out a head of time. And it's probably better to error on the side of not creating monolithic build structures . . . it's very hard to deal with a huge lump of aggregated, parent child build modules that isn't really necessary. On the other hand, aggregating individual builds to run together is a functionality provide at higher levels, such as the CI build server. So, I guess I might suggest erroring on the side of more independence.
What are the main possible reasons of breaking down a Maven project to sub-modules?
Are you looking something more than the benefits of Modularization? The sub-modules should ideally be representing a single concept/feature so that they are functionally cohesive.
Pom file inheritence
You can use the and sections of the root poms to keep consistent version numbers and configurations across all child projects. So if I have an aggregator project that lists 300 projects, all that use apache commons-io and I want to upgrade them all the the latest version of commons-io, I can just change the version in the dependencyManagement section of the root pom. None of the child projects need specify a version.
build profiles
In the above example, if I have 300 sub projects, an individual developer is probably not regularly working on all (or even many) of the 300 sub-projects. You can create a build profile that specifies only the modules you work on regularly, and if you have a continuous integration server that deploys artifacts to an artifact repository, you'll get all the changes the developers on your team make too, without having to build all 300 modules.
General organization/clarity
While waiting for an answer to my comment.
A reason to split a Java EE based maven project into sub modules is so you can build the JAR/RAR/WAR/EAR/whatever independently of eachother.
For regular Java apps, you might split out the functionality into separate JARs, again each of these could be a sub-module under the overall project and again you can build them independently, run separate goals/phases/reports etc.