I was understanding something in spring boot and to being with, used a very simple snippet, like adding this in pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
</parent>
As I understand <parent> in this context means that in my pom.xml, there we have a parent pom.xml (saw the pom.xml file for spring-boot-starter-parent) which will have list of dependencies.
The important thing is that it is only pom packaging, and NOT a real jar / binary (please correct if I am wrong)
I saw the following in mvn repository:
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-parent -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<type>pom</type>
</dependency>
My doubt is:
How can we include it as an dependency , it is just a pom packaging (and not a real jar / war), which acts as central place which holds common dependencies? Is it allowed? I tried adding in my project, but saw errors in STS IDE.
How does this get downloaded? Can we see the contents of this "parent"
First off, you've probably missed the meaning of parent pom in this case.
Spring boot of any specific version (2.2.1 in this case) comes with a bunch of possible integrations with many technologies / libraries. So it provides "default" versions of the libraries to work with because its very hard to check that it compatible with all possible versions of all libraries. You can of course provide your own version but then you should test a compatibility as an application maintainer.
So If you'll checkout the source code of spring-boot-starter-parent pom, you'll see that it provides some plugins and plugin management and more importantly inherits from another pom called spring-boot-dependencies
Note it doesn't add any dependencies to your project. It only defines a dependencyManagement section. This means that once you'll use the dependency in your project (that inherits) from this pom, you don't have to specify a version, only group id and artifact id.
Again, that's because spring boot offers by default very specific versions of thirdparties - the version that it was verified that it's compatible with...
Now as for the second part of the question - indeed it doesn't make sense to include dependency with packaging pom like you've posted, could you please provide a link where exactly you've seen this?
Sometimes when people adopt spring boot in their projects they already have have some parent, so they can't use the inheritance, in this case they can use a very special maven scope "import" and use the dependency on pom treating it as BOM (bill of materials) - frankly a pretty advanced stuff in maven. But spring boot uses this feature for these cases.
The dependency inclusion looks like this:
<dependencies>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
Note, the `import line. From maven's site: This is meant to allow dependency management information such as versions and excludes be retrieved from a remote POM file.
Here is a tutorial about this topic
#CuriousMind, including the spring-boot-starter-parent as a dependency is like trying to instantiate an interface or Abstract Class in Java. As you noticed, its packaging is pom, meaning it is just a maven artifact to help configure your maven project. Jar and War will contain some java binaries. I think the MVN repository code automatically generate all sample as dependencies..
Related
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!
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>
The json-simple jar is missing in packaged WAR because it is marked as optional in spring-boot-starter-parent, BUT I do include a dependency gelfj that declares json-simple as dependency..... example below (used with Maven 3.3.3):
<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.giveandtake</groupId>
<artifactId>main</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.2.RELEASE</version>
</parent>
<name>main</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.graylog2</groupId>
<artifactId>gelfj</artifactId>
<version>1.1.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j</artifactId>
<version>1.2.3.RELEASE</version>
</dependency>
</dependencies>
</project>
[1] when packaging war with maven 3.0.4 i get the json-simple inside war (without asking for the jar explicitly).
[2] when packaging with maven 3.3.x war i dont have this jar in my war(unless i explicitly ask for it) file.
which leaves me with these questions:
Question 1: if i have ProjectX-->(Inherit)Spring-boot-Parent and also declare a dependency Y that has dependency for json-simple, shouldnt the dependency for simple-json be transitive into war and recognize that as not optional anymore?
Question 2: why is the different results with different maven versions [maven bug? , searched for release notes but didnt find anything matching]
if i have ProjectX-->(Inherit)Spring-boot-Parent and also declare a dependency Y that has dependency for json-simple, shouldnt the dependency for simple-json be transitive into war and recognize that as not optional anymore?
The spring-boot-starter-parent pom declares the json-simple dependency as optional in its dependencyManagement section (and not in its dependencies section):
<dependencyManagement>
<dependencies>
...
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
<optional>true</optional>
</dependency>
...
dependencyManagement has a strong governance over declared dependencies and transitive dependencies, making in this case json-simple as optional for any transitive dependency (re-defining its mediation hence) of your declared dependencies, that's why it would not be added to the packaged war (even if the gelfj dependency has it as transitive dependency).
From official documentation:
A second, and very important use of the dependency management section is to control the versions of artifacts used in transitive dependencies
[...] dependency management takes precedence over dependency mediation for transitive dependencies.
why is the different results with different maven versions [maven bug? , searched for release notes but didnt find anything matching]
Maven 3.0.4 is has a default binding to Maven War Plugin version 2.1.1, while Maven 3.3.3 has a default binding to Maven War Plugin version 2.2, that's the main difference concerning the two Maven versions and the War plugin.
However, the spring-boot-starter-parent pom declares the WAR plugin as version 2.5 in its pluginManagement, hence impacting the version you will finally use as part of your build and removing the difference above between the two maven versions.
So this was a Maven Core bug rather than a WAR Plugin bug and this bug looks pretty much the fix (in the Maven version 3.1.0).
Upon my tests, I was able to reproduce the following scenarios:
Maven 3.0.4, no gelfj dependency declared, hence json-simple inherited as optional, WAR plugin did not package it: CORRECT BEHAVIOR
Maven 3.3.3, no gelfj dependency declared, again json-simple as optional, not packaged: CORRECT BEHAVIOR
Maven 3.0.4, gelfj dependency declared, json-simple should still be as optional, WAR Plugin did package it: INCORRECT BEHAVIOR
Maven 3.3.3, gelfj dependency declared, again json-simple still optional, WAR Plugin did not package it: CORRECT BEHAVIOR
I would hence suggest to rather upgrade your maven version (recommended, avoid 3.0.4) or explicitly declared the dependency as not optional (by declaring it as your dependency, for instance, or as not optional in your dependencyManagement section).
If you have a dependency management entry for json-simple with optional=true
in your parents, this might lead to the described situation.
Have a look at the effective pom in eclipse or with mvn help effective-pom
than search for any occurence of json-simple it might help.
For the version differences : You might use effective-pom for this, also
We have a couple of different applications which may or may not interact together. When they interact together, there have been issues because of mismatch in third party library versions (Let it be Spring or something else).
The pom files for these applications are separate, but to solve the above issue, we want them to use the same versions of third party libraries. The easiest way to do this is to specify the versions in common properties file, and then let respective pom.xml read the versions from the properties file.
Usually I am used to specify the versions as properties in the parent pom, and let the module pom read it from there. Is there a way I can make pom.xml read the properties file for reading the versions?
Some projects, e.g. spring-cloud and spring-boot, express their 'release train' (a set of dependencies and their versions that are known to work well together) in a 'BOM' (bill of materials). The BOM is nothing but a POM with only a dependencyManagement section, where all these dependencies are listed with the correct version. That BOM is then included in each project's POM that should follow these dependencies/versions in its dependencyManagement section, with scope 'import'.
E.g.
You create your separate project 'my-bom', containing only a pom like this:
<project>
<groupId>your.organication.program</groupId>
<artifactId>my-bom</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.whatever</groupId>
<artifactId>somedependency</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>com.whatever</groupId>
<artifactId>someotherdependency</artifactId>
<version>4.5.6</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
And then you include that in each project that should be aligned with these dependencies/versions:
groupId>your.organication.program.project</groupId>
<artifactId>some-project</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>your.organisation.program</groupId>
<artifactId>my-bom</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencyManagement>
Within the projects the dependencies that are effectively used must still be referenced in dependencies-section, but without the version - the versions are managed by the BOM.
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).