Groovy Dependency management - maven

I am quite new to groovy and need to clarify on the Groovy Dependency management.
Here is the summary according to my "Homework":
Groovy Dependency management is as simple as adding an annotation to the script. E.g.
#Grab('org.springframework:spring-orm:3.2.5.RELEASE')
Grape will then quickly add the dependencies from maven repository to your classpath
So, is adding to my groovy script the dependency annotation is all that I need, and Groovy/Grape will take care of the rest, when I run my Groovy script, right? (or there are some prerequisites, like I can't put my groovy script randomly anywhere, but has to be at a specific place like within a Groovy project, etc)
Second question, how to translate Maven dependency to Groovy/Grape dependency annotation?
For e..g., this is the Maven dependency for Opencsv:
<dependencies>
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>5.2</version>
</dependency>
</dependencies>
Does that translate to #Grab('com.opencsv:opencsv:5.2')?
Third question,
suppose I need to import org.apache.commons.collections.primitives.ArrayIntList, how can I come up with a Groovy/Grape dependency annotation as
#Grab(group='commons-primitives', module='commons-primitives', version='1.0')
I.e., where can I found the connection between org.apache.commons.collections.primitives.ArrayIntList and commons-primitives?
And finally,
where would Groovy/Grape store the downloaded .jar files?

Related

Spring Boot autoconfigure and its dependencies

I checked the source code of module spring-boot-autoconfigure
It has configurations classes for plenty of technologies : data, redis, cassandra, JPA, LDAP etc...
How can this module can compile properly without including all theses technologies dependencies jar in its POM ?
If I take the example of HibernateJpaAutoConfiguration class :
It uses beans/classes from other Spring modules like spring-orm :
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
However spring-boot-autoconfigure has no dependency to spring-orm in its POM. So how is compilation possible ?
This is possible because they apply Maven's concept of optional dependencies:
Optional dependencies are used when it's not possible (for whatever reason) to split a project into sub-modules. The idea is that some of the dependencies are only used for certain features in the project and will not be needed if that feature isn't used. (...) However, since the project cannot be split up (again, for whatever reason), these dependencies are declared optional. If a user wants to use functionality related to an optional dependency, they have to redeclare that optional dependency in their own project.
In Maven, it would usually look like this:
<dependency>
<groupId>sample.ProjectA</groupId>
<artifactId>Project-A</artifactId>
<version>1.0</version>
<optional>true</optional>
</dependency>
In this example, the project is compiled with Project-A. However, Project-A is not shared as transitive dependency.
The developers of Spring Boot use Gradle instead of Maven. They wrote their own Gradle plugin to replicate this behavior. The result looks something like this:
dependencies {
...
optional("org.springframework:spring-orm")
(see spring-boot-autoconfigure/build.gradle)

Import maven property used in bill of materials (bom)

We have a project layout with sub-modules and dependencies in bom files:
projectA
bom
module1
module2
The actual version numbers are defined as properties in the bom file, so for each dependency we have something like
<properties>
<guice-version>4.1.0</guice-version>
</properties>
<dependencies>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>${guice-version}</version>
</dependency>
</dependencies>
The top-level pom in projectA import the bom in the dependecyManagement section with
<dependencyManagement>
<dependencies>
<dependency>
<groupId>group</groupId>
<artifactId>bom</artifactId>
<version>1.0.0</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
This all works fine and we have centralized dependency definitions.
However, at one point during the build process we need to use the version of one of the dependencies. I was hoping that importing the bom in the dependencyManagement section would also import the properties into the top-level pom, but that is not the case. It is also not possible to make the bom a children of the top-level pom with a section because this creates a cyclic dependency between pom files.
I thought about putting the properties into an external file and read it with the maven properties plugin where needed. That would be obviously in the bom and in the pom file where we need to get the version of the dependency. However, since the bom is not packaged as a jar, so the path would have to be hard-coded.
I could fix it by duplicating the properties to two places, but I don't want to do that. Is there a way to get the version of a dependency, e.g. using a property defined by the dependency?
The problem seems to be common enough and I am wondering if we did something wrong in the project structure. What is the standard way to centralize properties in this case?
You can try using the BOM as the parent of your parent module as a BOM is technically some kind of minimal version of a POM. This is what the official Maven project describes here:
http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html
I don't like this solution, because if you already extend from a parent, you get into a multi-inheritance problem here.
It appears that a BOM is not fulfilling your requirements. It only assembles a bunch of dependencies like an extract of a dependency management section of a parent project. However its internal structure should not matter to your project. If the BOM changes structurally, your project won't be influenced by that. Perhaps it's a more proper solution not to use a BOM here, but instead pick the dependencies and use your own version property here. Depends a little bit on how complex the BOM is.
So either use the BOM as a parent or dismiss the BOM at all, since you need more than your BOM gives you.
The actual purpose about BOM import is precisely to avoid having to declare the exact version of the dependencies declared in the BOM.
So, consider that you have a BOM witch declares a dependency like
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>${guice-version}</version>
</dependency>
(we asume your BOM also declares the property in it).
So then, in your projects, you can declare the guice dependency without having to determine the version attribute as it is inherited from the BOM.
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
</dependency>
The benefit is that if you change your BOM version, this kind of dependencies will be updated accorndingly without having to do any change in the pom.xml of your project!

Adding a dependency existing internally as a dependency

My project is a fairly large project consisting of many maven modules (but not microservices). I was trying to do Moving from spring to spring-bom on WAS but seems lot of clashes in versions. So for example one of my modules is using commons-collectionsversion 2.6.0 and my current project is using 3.2.2. I want the same jar to be used across. Since its more of a migration project I cannot do changes in container or repository changes at this time. I should only make sure that all the version are compatible with each other. My plan :
I want to include a dependency which is with in some other dependency
into the current pom as a dependency.
Also I want other jars in this pom (which exists as a dependency) to included the dependency
Is there anyway to do it?
I didn't completely understand your question, but the can help you to define a cross-module dependency version, as long as you place it in the parent-pom file.
<dependencyManagement>
<dependency>
<groupId>com.group</groupId>
<artifactId>project-1</artifactId>
<version>1.0.0</version>
</dependency>
</dependencyManagement>
and then define the dependency in the relevant module without providing it a version (it will be inherited from the parent-pom's <dependencyManagment> tag:
<dependencies>
<dependency>
<groupId>com.group</groupId>
<artifactId>project-1</artifactId>
</dependency>
</dependencies>

List only used jars

I have Maven projects which I can build with these dependencies:
<dependency>
<groupId>org.wildfly.arquillian</groupId>
<artifactId>wildfly-arquillian-container-embedded</artifactId>
<version>1.0.2.Final</version>
</dependency>
<dependency>
<groupId>org.wildfly</groupId>
<artifactId>wildfly-embedded</artifactId>
<version>9.0.2.Final</version>
</dependency>
There are a lot of jars into these dependencies and I would like to use on the necessary. How I can list which jars are only needed for the build?
The simple answer to you question is that there is no easy way to do what you are asking. In maven you declare for your package all the dependencies that the code inside your package will ever need in all scenarios. In this case if your using only a specific part of the wildfly-embedded package, and that part that you are using only depends on a subset of the package's declared dependencies then Maven has no way of knowing this.
One approach you could take is to simply look at the declared dependencies of those artifacts, exclude one of them, and then run your test suite. Assuming you have a comprehensive test suite if the tests past then you can reasonably assume that the dependency you excluded was not required by any of the parts of the library you utilized. You can do this for each of the declared dependencies.

Does Maven need to explicitly specify the dependency that Spring/Hibernate dependented?

I'm new to Maven, I try to use Maven with Spring, Hibernate in my project. After go though the Spring and Hibernate reference, I found that "there is no need to explicitly specify the dependent liberaries in POM.xml file for such Apache commons liberaries".
My questions is that : If my other parts of project refer to Apache commons liberary, such as commons-io, SHOULD I explicit specify this dependency in POM.xml file?
You should define those dependencies in Maven which your project is using. For example, even though some library depends on commons-io but if your code needs this then you should directly define commons-io in your pom.xml
You should not worry about the dependencies of the libraries you have defined in your pom.xml. Maven will do that for you.
Maven is used to avoid the issue of having to run down JAR files that are dependent on other JAR files. Of course you do not HAVE to use maven to do this, but you should. Maven will automatically download the dependent JAR files of the JAR file you require. THe hibernate-entity manager JAR file, for example, has over 100 dependencies and maven does the work for you.
Anyway,even if you do add the commons-io file to the build path/classpath of the maven project,and then update the project configuration, maven will kick it out.
You can provide a lib name on a site like mvnrepository.com to see what it depends on (e.g. take a look at a section called "This artifact depends on ..." in case of spring-webmvc library). Those dependencies (which your artifact depends on) are called transitive dependencies. You don't have to specify these in your pom.xml as maven will resolve them for you.
For the sake of readability you should only state those dependencies in your module that you rely on directly. You want JUnit to test your software, only declare JUnit; you need hibernate to use ORM, declare hibernate, and so on. Leave the rest to Maven.
And most of the time you should state what you intend to use in the very module you want to use it in. So if you want to use a dependency in more than one module, consider moving it into a dependencyManagement block in a parent pom and referencing it from there in the module you want it in.
parent pom.xml
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
child pom.xml
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
This guarantees you version-stability and still allows you to find out what a module uses by only looking in it's pom (and not all over the place).

Resources