Maven EAR compiling - java

I have this dependency (and many others like this) :
<dependency>
<groupId>jShrink</groupId>
<artifactId>jShrink</artifactId>
<version>3.0.2</version>
<scope>system</scope>
<systemPath>${project.basedir}/../kladr-ear/lib/jShrink-3.0.2.jar</systemPath>
</dependency>
So how to add this JAR to EAR/LIB folder with MAVEN while package?

Looking at the available Maven scopes, I would expect you to mark this as
<scope>compile</scope>
and upload the jar file to your repository (local or remote). Maven should give you the appropriate command line to perform that upload.
EDIT: As noted below, this scope is the default, and as such you could omit it.

Dependencies going into the EAR should generally be based on he dependencies needed for EJB modules. If you have an EJB module with library X on compile scope then that will trigger Maven to want to package the library in the ear that the EJB is part of. No need to manage any scopes at all in the ear pom.
If you don't have any EJBs and only WARs, I would not package libraries in the EAR but simply deploy them as part of the WAR (so they end up in WEB-INF/lib). Keep the web dependencies nice and contained per module, even if that means you get duplicates.
Also compile is the default scope, so you don't ever need to manually declare it unless you're doing it to override another scope set for the dependency.

Related

Understanding Maven dependencies and assembly

I am not very much experienced with Maven and it's compilation and packaging logic gets me confused.
I have some dependencies declares as :
<dependency>
<groupId>com.dependency_group</groupId>
<artifactId>dependency_1</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.dependency_group</groupId>
<artifactId>dependency_2</artifactId>
<version>1.0.0</version>
<scope>provided</scope>
</dependency>
So as far as I understand, dependency_1 will be added to the classpath of my program as something that comes along with my jar, and dependency_2 on the other hand, will be added to the classpath as something that the system runtime will provide upon deployment.
Then I run the package goal of Maven and none of my dependencies are packed with my code (I am using the shade plugin, but even without it nothing changes).
I expected that when some dependency is set as compile scope, it will be exported with my compiled code, since AFAICS, there's no point in setting the classpath saying a dependency will come along with my code, and Maven just don't package that dependency with it. It looks to me as if Maven is not obeying it's contract.
So:
1 - What's the logic behind this?
2 - Do I have to always use the Assembly plugin?
3 - Are there cases where people will define a dependency as compile and will not want it packaged within a jar?
Let me shed some light on the main point here. There are fundamentally two kinds of java artifacts:
Applications, i.e. ears, wars, executable jars
Libraries, i.e. jars that are meant to be used as dependencies for other artifacts.
For Applications your reasoning makes perfectly sense. Wars and Ears automatically package all their compile dependencies and you need no assembly plugin for that. For libraries, you do not pack the dependencies into the library. Maven handles transitive dependency resolution and would be confused if you put a fat jar on the classpath.
The thing is that packaging jar can be both a libary or an application. If you want a standalone application, you need to tell Maven to package everything, e.g. by using the assembly plugin or shade plugin.
You use compile scope when you want some dependencies to come along with your code. For example you want Jackson to be a part of your application if you are using it for json serialization.
You use provided scope, if you want dependency to be on the classpath during the compilation but wont be included within your application. It must be provided by running environment. For example you want Lombok as it is compile only library, or you want to have Servlet Api dependency as provided when you are writing servlet application because such app will be ran on servlet container thus there is no need to pack it within your application (it will be available in container runtime)
Do I have to always use the Assembly plugin
Nobody forces you to do so.

Same dependency as "ejb" and "jar" - what happens?

Dependencies in Maven have a type element which defaults to jar, but can be set to ejb, war, ear, etc. The type ejb is a special case because it does not lead to a different file ending: The ejb has still the ending .jar.
I have an ear project where the same dependency is referenced once with type ejb and once with type jar (in the transitive dependency tree). Both entries ask for the very same file, with different Maven "coordinates".
From the perspective of the dependencyConvergence rule of the enforcer plugin, both dependencies seem to be different - the version of the <type>jar dependency is seemingly not managed by dependencyManagement. Nevertheless, only one of the dependencies makes it into the ear - namely the <type>ejb one.
When does Maven "drop" the second dependency and what can I do to influence this?
Please note: I know that you shouldn't have ejbs as jars on your dependency list, but if I kill the responsible developers, I might go to prison.
I created two sample projects in Eclipse: one EAR, one EJB.
If the order in the EAR's POM is:
<dependency>
...
<type>jar</type>
<dependency>
...
<type>ejb</type>
the ejb.jar is put to .ear's /lib only.
If the order in the EAR's POM is:
<dependency>
...
<type>ejb</type>
<dependency>
...
<type>jar</type>
the ejb.jar is put to .ear's root and /lib.
Apparently one of the rare cases where order of declaration in the POM matters.
BTW, just to make it clear: Your "the same dependency is referenced [...] with different Maven 'coordinates'" is contradicting. Maven coordinates are groupId, artifactId and version (GAV), not packaging and/or classifier, because the latter two don't specify the "Where?" but the "What?". It's probably that why you quoted "coordinates".

OSGi (Karaf) Resolution vs Maven dependencies

In my example below there seems to be a discrepancy / duplication in the required steps in OSGi resolution and Maven dependency support.
I have a jar which is dependent on a external 3rd party jar, in this case time4j.
<dependency>
<groupId>net.time4j</groupId>
<artifactId>time4j-core</artifactId>
<version>4.16</version>
</dependency>
I can then run my simple jar locally by importing the packages and running etc.
When importing into OSGi I have to ensure that this jar is imported first, often using the PAX Wrap Url.
This is ok for 1 jar dependency but what about when there are multiple dependencies. I could use a features.xml file to collect these jars but why? I've already specified them in my pom.xml.
It seems there should be a way for OSGi / Karaf to read the pom.xml dependencies and import these into the container using the PAX Wrap url when needed.
Have I missed something here?
Sorry but your expectations are not in sync with reality.
First of all Maven dependencies are build-time dependencies. That's why you declare dependencies you know to be available in the runtime as provided
<scope>provided</scope>
Neither OSGi nor Karaf can do anything about your build time dependencies.
BUT with OSGi you can make sure your build dependencies are also available in your runtime and don't interfere with other libraries that might be available.
That's why you need to declare your imports and exports etc.
Karaf does help you with some of the dependencies for example with feature files.
If you have a feature definition maven project, all of your compile scope dependencies can be included in one feature file.
BUT, the OSGi resolver only looks at the currently available bundles and nothing more, no connection what so ever to maven, if you want to have some sort of automagic resolving of external dependencies you need to make sure that you have
a) an OBR resolver enabled (this depends on the karaf version you are using, with 4.x it's already included) and
b) an OBR repository at hand, Karaf Cave would be the project to look for in that case, cause it can reside like a proxy on top of a maven repository.

How is a maven artifactid connected to a file?

I experimented with webservices and jboss4 for the last couple of days, and I stumbled over the following problem:
I included this dependency in my pom.xml:
<dependency>
<groupId>org.jboss</groupId>
<artifactId>jboss-jaxws</artifactId>
<version>4.2.2</version>
</dependency>
As it turned out, this caused JBoss4 to fail with the error message
java.lang.IllegalStateException: Cannot find endpoint meta data
Until I added the tiny little line
<scope>provided</scope>
to the dependency. I now understand that this problem was caused by the fact, that JBoss4 brings this library himself, and that it is the double inclusion of the same library (probably 2 different versions) that caused this. But now, when I look into the JBoss lib folder I see the following files:
commons-codec.jar
commons-httpclient.jar
commons-logging.jar
concurrent.jar
endorsed
getopt.jar
jboss-common.jar
jboss-jmx.jar
jboss-system.jar
jboss-xml-binding.jar
log4j-boot.jar
How do I know which jars correspond to which maven artifact? How do I know for any of the million files in my .m2/repository folder which groupid, artifactid and version number they belong to?
All the jar files in provided/included by Jboss are not related to maven. They are there just for the sake for jboss it self to run. Other application who wants to run in the container need to provide they own sets of library. BUT, some time, some of the library provided by JBoss is enough for the application (since they will live on the same VM), so you dont need to provide your own. You use those provided library for your development purpose, and later, when you deploy, you dont include them in your deployment.
So, there are no telling which Jar, provided by JBOSS should relate to which artifactId or groupId or version in the maven repositories, unless for some hint on their names.
For example, if you see that Jboss brings "commons-codec.jar" with it. There are no telling that the jar comes from which artifactId or groupId or version in Maven. You may guess that "commons-codec" should be a name of some artifact. Sites like http://mvnrepository.com/ helps you to find what related maven artifact that may relate to the jar you are investigating.
The artefact name is always ${artifactId}-${version}.${type}
in your case : jboss-jaxws-4.2.2.jar.
You're just looking for it in the bad place, the lib folder you're talking about must be the one of the unified classloader, the library you're looking for must be loaded by the server classloader i.e. it must reside in JBOSS_HOME/modules
[edit]
Ferdinand Neman is right when he says that jboss is not related to maven. Dependencies declaration in pom just allows maven to build and package your project. The runtime behavior depends on your targeted environment, the only things to ensure is that your dependencies must be resolved during classloading whether because they are packaged with your project or provided by the runtime environment.
Anyway the jar jboss-jaxws-4.2.2.jar will necessary be present on your workstation (in the local maven repository) to allow class linkage during maven compilation, as the jar is marked as provided it will not be included in the resulting build artefact.
Maybe you find useful this maven command
mvn dependency:tree -Dverbose
It shows you jar dependencies, classified by group-artifact and it also represents dependencies between them as a tree.

add external jar to our dependency

There is a jar file lets say "abc.jar" which maven dependency does not exist(ie created a jar by using java command of own classes). I want to add this jar as maven dependency so that at build time it will automatically copy that jar in lib folder as like other maven dependency. how i will do. please help .
Add it as a dependency with a system scope. See the docs here.
However, rather than adding it as a system dependency it might be better to mavenize the jar itself, then you can build and install it into your dependency management system.
Also, see this question: Can I add jars to maven 2 build classpath without installing them?
You can use the systemPath attribute in the dependency tag in the POM file of your project.
In your pom.xml, use the following snippet corresponding to abc.jar:
<dependencies>
<!-- Other dependencies -->
<dependency>
<groupId>abc</groupId>
<artifactId>x</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>{path_to_abc.jar}</systemPath>
</dependency>
</dependencies>
The scope parameter corresponding to this artifact must be set to system, for the artifact to be picked up from the specified systemPath.
Hope this helps!
A normal maven dependency is always resolved by looking into a repository. So you must put your JAR file into a repository.
You could install your JAR into your local repository. Have a look at the install plugin. The install-file goal is your friend.
If other developers also need this JAR (because they are working with the same project), they either need to install it locally too, or - better - you deploy the JAR to a remote repository. Have a look at the deploy plugin. Here the deploy-file goal is your friend. For deploying artifacts, you need a repository manager like Nexus or Artifactory.
However, a dependency could also have the system scope (look at the other answers).

Categories