Maven create many jars from one module - java

I have a maven (multi-module) project that contains something like an IAction. In this project I have implemented about 50 implementation of different actions. Each Action consists of a MyAction.java and a MyAction.properties file.
I use Java's SPI (java.util.spi) to load all the implementations at runtime. This all works great, but now I want to package each Action into a single jar, so that I end up with 50 jars.
What would be a good way to accomplish this? I don't really want to create a sub-module for each action, as that takes a lot of maintenance.

You can use the Maven assembly plugin in order to create additional artifacts for building a module. However, note that you need to add these artifacts to your deployment queue once you created them, in case that you do not only want to build these artifacts. This can be achieved by for example using the build-helper-maven-plugin.
However, as for the iteration over 50 elements, you might want to consider writing your own specialized plugin. There are additional plugins that allow the iteration over another plugin, but this will blow up your POM. If a build is therefore very specific, you might therefore consider writing an individual plugin which is specialized on this task. You can do this in pure Java instead of XML and it is not as hard as it sounds. There is documentation and there are default APIs to Maven. And you can check the source code of the named plugins on how to achieve your requirements.

Related

Lightweight way to use a Maven dependency?

What do you normally do when you want to make use of some utility which is part of some Java library? I mean, if you add it as a Maven dependency is the whole library get included in the assembled JAR?
I don't have storage problems of any sort and I don't mind the JAR to get bloated but I'm just curious if there's some strategy to reduce the JAR size in this case.
Thanks
It is even worse: You do not only add the "whole library" to your project, but also its dependencies, whether you need them or not.
Joachim Sauer is right in saying that you do not bundle dependencies into your artifact unless you want it to be runnable. But IMHO this just moves the problem to a different point. Eventually, you want to run the stuff. At some point, a runnable JAR, a WAR or an EAR is built and it will incorporate the whole dependency tree (minus the fact that you get only one version per artifact).
The Maven shade plugin can help you to minimise your jar (see Minimize an Uber Jar correctly, Using Shade-Plugin) by only adding the "necessary" classes. But this is of course tricky in general:
Classes referenced by non-Java elements are not found.
Classes used by reflection are not found.
If you have some dependency injection going on, you only use the interfaces in your code. So the implementations might get kicked out.
So your minimizedJar might in general just be too small.
As you see I don't know any general solution for this.
What are sensible approaches?
Don't build JARs that have five purposes, but build JARs that are small. To avoid a huge number of different build processes, use multi-module projects.
Don't add libraries as dependencies unless you really need them. Better duplicate a method to convert Strings instead of adding a whole String library just for this purpose.

Using Java annotations in Maven multi-module projects

A common use case for me is that I need to deploy multiple Java applications/customizations into customer environments. Often these different parts have to be developed as separate Maven projects where each project contains/produces multiple files of various types (jar, JSP, properties, XML etc). A lot of these extra files are generated via the use of Java annotations and the preprocessor functionality.
The problem I'm facing is that multiple projects may produce the same files which must then be merged together and it is becoming increasingly harder to do this as the number of submodules go up. The result being that I may mess up the merging and create either invalid or incomplete files which are then deployed causing problems in the target environment. Not to mention that this manual merging process makes it impossible to automate the builds.
I'm looking for a way to structure my projects or for plugins (or some other way) that may help, so that I can have an aggregator project that can collect all these files from all the projects and merge them into final versions that contains the contributions from each individual submodule. The goal is of course that building some sort of top project will result in a complete deployment package that can be directly installed without any further manual processing.
A good approach could have been if the aggregator project could run preprocessing on all annotations from all the submodules and simply create the finished files but as far as I understand how the preproccesor this is not really an option.
Do you know of any technique, plugin or something else that could help me accomplish this?

Who is using my maven artifact?

I have a system consisting of multiple web applications (war) and libraries (jar). All of them are using maven and are under my control (source code, built artifacts in Nexus,...). Let say that application A is using library L1 directly and L2 indirectly (it is used from L1). I can easily check the dependency tree top-down from the application, using maven's dependency:tree or graph:project plugins. But how can I check, who's using my library? From my example, I want to know, whether A is the only application (or library) using L1 and that L2 is used from L1 and from some other application, let say B. Is there any plugin for maven or nexus or should I try to write some script for that? What are your suggestions?
If you wish to achieve this on a repository level, Apache Archiva has a "used by" feature listed under project information
.
This is similar to what mvnrepository.com lists under its "used by" section of an artifact description.
Unfortunately, Nexus does not seem to provide an equivalent feature.
Now I suppose it would be a hassle to maintain yet another repository just for that, but then it would probably easier than what some other answers suggestions, such as writing a plugin to Nexus. I believe Archiva can be configured to proxy other repositories.
Update
In fact, there's also a plugin for Nexus to achieve the "used by" feature.
As far as I know nothing along these lines exists as an open source tool. You could write a Nexus plugin that traverses a repo and checks for usages of your component in all other components by iterating through all the pom's and analyzing them. This would be a rather heavy task to run though since it would have to look at all components and parse all the poms.
In a similar fashion you could do it on a local repository with some other tool. However it probably makes more sense to parse the contents of a repo manager rather than a local repository.
I don't think there's a Maven way to do this. That being said, there are ways of doing this or similar things. Here's a handful examples:
Open up your projects in your favorite IDE. For instance Eclipse will help you with impact analysis on a class level, which most of the time might be good enough
Use a simple "grep" on your source directory. This sounds a bit brusk (as well as stating the obvious), perhaps, but we've used this a lot
Use dependency analysis tools such as Sonargraph or Lattix
I am not aware of any public libraries for this job, so I wrote a customized app which does it for me.
I work with a distribution which involves more than 70 artifacts bundled together. Many times after modifying an artifact, I want to ensure changes are backward compatible (i.e. no compilation errors are introduced in dependent artifacts). To achieve this, it was crucial to know all dependents of modified artifact.
Hence, I wrote an app which scans through all artifacts under a directory(/subdirectories), extracts their pom.xml and searches (in dependency section of pom) for occurrence of modified artifact.
(I did this in java although shell/windows script can do this even more compactly.)
I'll be happy to share code on github, if that could be of any help.
One way that might suit your needs are to create a master-pom with all your maven projects. Then you run the following command on the master-pom:
mvn dependency:tree -DoutputType=graphml -DoutputFile=dependency.graphml
Open the generated file in yEd.
Used the instructions found here:
http://www.summa-tech.com/blog/2011/04/12/a-visual-maven-dependency-tree-view/
More interesting is probably: what would you do with this information? Inform the developers of A not to use library L1 or L2 anymore, because it has a critical bug?
In my opinion you should be able to create a blacklist of dependencies/parents/plugins on your repository manager. Once a project tries to deploy/upload itself with a blacklisted artifact, it should fail. I'm saying uploading and not downloading, because that might break a lot of projects. As far as I know, this is not yet available for any repository-manager.
One of the ways to approach this problem is outside Java itself : write an OS-level monitoring script that tracks each case of fopen() on the jar file under question! Assuming this is in a corporate environemnt, you might have to wait for a few weeks (!) to allow all using processes to access the library at least once!
On Windows, you might use Sysinternals Process Monitor to do this:
http://technet.microsoft.com/en-us/sysinternals/bb896645
On Unix variants, you would use DTrace or strace.
IMHO and also from my experience, looking for a technical solution for such a problem is often an overkill. If the reason why you want to know who is using your artifact(library) is because you want to ensure backward compatibility when you change an artifact or something similar, I think it is best done by communicating your changes using traditional channels and also encourage other teams who might be using your library to talk about it (project blogs, wiki, email, a well known location where documentations are put, Jour fixe etc.).
In theory, you could write a script that crawls though each project in your repository and then parses the maven build.xml (assuming they all use maven) and see whether they have defined a dependency to your artifact. If all the projects in your organization follows the standard maven structure, it should be easy to write one such script (though if any of those projects have a dependency to your artifact via a transitive dependency, things can get a bit more tricky).

Java package / class library convention?

I am a C# developer and I am messing around with Java. In C# I would normally have my front end project and then when I need to add another layer to the project (i.e service layer etc) I would add a class library in the solution and add a reference to it.
What is the convention in Java? Do you add another Java project to the workspace and then reference the project? Or do you add a package to the project which contains your front end?
UPDATE
Sorry, I am using eclipse...hence the reference to 'workspace'
There's no real convention. When you say "workspace" you're not referring to Java, but rather a development environment (sounds like Eclipse). There are a number of ways to do it; you could do it the way you're suggesting, you could include the dependency via Maven, you could combine them all together in one project, etc.
Which to choose depends on your needs, who else will be consuming either the individual libraries or the completed project, and so on.
How to divide your source code depends a lot on the structure of your project. It is important to pay attention to a good code organization. You should keep classes for a common task or for a distinct application layer in own packages. You should watch for inter-package dependencies.
Using different "projects" (be it Maven or Eclipse projects) helps ensuring that you (your developers) do not violate structural boundaries because the compiler checks the dependencies (one project references the other project, like in C#/VS). Maven generates a build artifact (e.g. a JAR file) for every project.
To summarize, I think it is a good idea to create new individual projects for each program module in order to be able to manage the dependencies between the projects explicitly.
You are assuming everyone works with eclipse, it seems (your references to "workspace").
You can do anything you want, but keep in mind others might not be able to include 'separate' projects for various components of the application.
You can easily address that issue by using some build tool (ant, maven) to build appropriate jars for the various app components, like data-model, persistence, API, etc.
If you front-end is an RIA, might make more sense to develop it as a separate project, although not necessary. If your app is some sort of Java driven UI, you can still do whatever you want, in both cases make sure the UI components have their own package hierarchy.
Yes, I guess I would create a separate package. So your UI code might be in com.mycompany.app.ui, your service code in com.mycompany.app.service, etc. However you want to organize your classes is up to you. Java itself doesn't care what packages the classes are in. The packages just help to make the code more manageable for the developers.
Unlike most things in Java, there's no real convention defined for how to split up project.
In my experience, it makes sense to include code that serves a particular business purpose in a single project, and to separate out code that you intend to share between multiple projects, or code that is not specific to a particular business purpose (e.g. database access, JMS libraries, etc.), into a separate project.
If the UI and the server layer are being developed in a single project, which means packaged and deployed in the same WAR file, I'd create a new package for the service and add classes and interfaces as needed.
If the service layer is deployed separately, I'd add dependencies as a JAR to the web project. All I should need are clients for the service.
If you're working in Eclipse follow these steps:
1) Right-click the project and choose "Build Path"-"Configure Build Path..."
2) Switch to Libraries tab and click Add External JARs (or just Add JARs if they're already in the workspace).
3) Now you can either manually add import of the corresponding class, or just hit Ctrl+Shift+O (Source-Organize Imports) and Eclipse will do the job for you.
I suggest you can use netbeans then you can create a java class library,when you deploy your project,netbeans will generate jar files for you,and place them at the right location.I'm also a ms developer,hope it helps

Multiple Java projects and refactoring

I have recently joined a project that is using multiple different projects. A lot of these projects are depending on each other, using JAR files of the other project included in a library, so anytime you change one project, you have to then know which other projest use it and update them too. I would like to make this much easier, and was thinking about merging all this java code into one project in seperate packages. Is it possible to do this and then deploy only some of the packages in a jar. I would like to not deploy only part of it but have been sassked if this is possible.
Is there a better way to handle this?
Approach 1: Using Hudson
If you use a continuous integration server like Hudson, then you can configure upstream/downstream projects (see Terminology).
A project can have one or several downstream projcets. The downstream projects are added to the build queue if the current project is built successfully. It is possible to setup that it should add the downstream project to the call queue even if the current project is unstable (default is off).
What this means is, if someone checks in some code into one project, at least you would get early warning if it broke other builds.
Approach 2: Using Maven
If the projects are not too complex, then perhaps you could create a main project, and make these sub-projects child modules of this project. However, mangling a project into a form that Maven likes can be quite tricky.
If you use Eclipse (or any decent IDE) you can just make one project depend on another, and supply that configuration aspect in your SVN, and assume checkouts in your build scripts.
Note that if one project depends on a certain version of another project, the Jar file is a far simpler way to manage this. A major refactoring could immediately means lots of work in all the other projects to fix things, whereas you could just drop the new jar in to each project as required and do the migration work then.
I guess it probably all depends on the specific project, but I think I would keep all the projects separate. This help keep the whole system loosely coupled. You can use a tool such as maven to help manage all the dependencies between the projects. Managing dependencies like this is one of maven's main strengths.
Using Ant as your build tool, you can package your project any way that you want. However, leaving parts of your code out of the distribution seems like it would be error prone; you might accidentally leave out necessary classes (presumably, all of your classes are necessary).
In relation to keeping your code in different projects, I have a loose guideline. Keep the code that changes together in the same project and package it in its own jar file. This works best when some of your code can be broken out into utility libraries that change less frequently than your main application.
For example, you might have an application where you've generated web service client classes from a web service WSDL (using something like the Axis library). The web service interface will likely change infrequently, so you don't want to have the regeneration step reoccurring all the time in your main application build. Create a separate project for this piece so that you only have to recreate the web service client classes when the WSDL changes. Create a separate jar and use it in your main application. This style also allows other projects to reuse these utility modules.
When following this style, you should place a version number in the jar manifest so that you can keep track of which applications are using which versions of your module. Depending on how far you want to take this, you could also keep a text file in the jar that details the changes that have occurred for each revision (much like an open source library).
It's all possible (we had the same situation some years ago). How hard or easy it'll be depends on your IDE (refactoring, merging, organizing new project) and you build tool (deploying). We used IDEA as IDE and Ant as build tool and it wasn't too hard. One sunday (nobody working+committing), 2 people on one computer.
I'm not sure what you mean by
"deploy only some of the packages in a jar"
I think you will need all of them at runtime, won't you? As I understood they depend on each other.

Categories