I've noticed that fabric8.io for Kubernetes client has two dependencies ending with project and BOM.
The only difference I've noticed is that it first has a distributed version. Also according to apache guides, bom usually used as a parent for projects.
Are there any other uses/differences? Which dependency should I use with Spring Boot?
A BOM project can be either used as a parent for your Maven module or imported as a BOM dependency which allows you to import dependencies from that BOM. A really good article on this matter can be found here.
Why is a BOM important? Since you've added a Spring tag to your question, let's say you want to use a certain Spring version and component_1 works fine with component_2 as long as they have the same version. As a library developer, you would have a versioned BOM which contains component_1 and component_2 and in your project, you would need to import the BOM with the version you need and the components you need without the version, as it will be inherited from your imported BOM/parent. This is exactly what Spring does.
In case the link above won't work in the future, here is the basic workflow with BOMs.
// BOM project
<project ...>
<modelVersion>4.0.0</modelVersion>
<groupId>baeldung</groupId>
<artifactId>Baeldung-BOM</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>BaelDung-BOM</name>
<description>parent pom</description>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>test</groupId>
<artifactId>a</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>test</groupId>
<artifactId>b</artifactId>
<version>1.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>test</groupId>
<artifactId>c</artifactId>
<version>1.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
// importing the BOM in your project
<project ...>
<modelVersion>4.0.0</modelVersion>
<groupId>baeldung</groupId>
<artifactId>Test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Test</name>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>baeldung</groupId>
<artifactId>Baeldung-BOM</artifactId>
<version>0.0.1-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<dependency>
<groupId>test</groupId>
<artifactId>b</artifactId>
<!-- version and scope omitted, inherited from the BOM, 1.0 and compile (you can override them here, but that defeats the purpose) -->
</dependency>
</dependencies>
</project>
Note that importing a BOM does NOT add all of its dependencies specified in the dependencyManagement section, unless you add them in the dependencies section of your project. It's like a product catalog, it shows you what the BOM is offering you.
Here is the Spring Boot 2.3.0 dependencies pom.xml, with dependencyManagement section to see how a real world BOM looks like (or just parent, if you want).
If you ever wanted to use Spring 6, Hibernate 5 and JUnit 5 & Assertion lib friends, assuming that all of them provide a BOM, you could include those 3 BOMs and every time you need to upgrade Spring version for your project, all you'd need is an update to the imported Spring BOM's version.
Related
I have a long list of modules getting properties from a parent module in maven. I want one of the modules to use a different version of spring from the parent. The other modules are using an older version of spring which will not work with module-c.
Is there a way to make the child module use its own version of spring?
// Parent
<groupId>xxx.xx.com</groupId>
<artifactId>test-environment</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<name>test-environment</name>
<properties>
<spring.version>4.0.6.RELEASE</spring.version>
</properties>
<modules>
<module>module-a</module>
<module>module-b</module>
<module>module-c</module>
</modules>
</project>
//Child
<project>
<parent>
<groupId>xxx.xx.com</groupId>
<artifactId>test-environment</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>module-c</artifactId>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.0.RELEASE</version>
</dependency>
</dependencies>
</project>
//Error
java.lang.NoSuchMethodError: org.springframework.core.ResolvableType.forInstance(Ljava/lang/Object;)Lorg/springframework/core/ResolvableType;
at org.springframework.context.event.SimpleApplicationEventMulticaster.resolveDefaultEventType(SimpleApplicationEventMulticaster.java:144)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:121)
at org.springframework.boot.context.event.EventPublishingRunListener.publishEvent(EventPublishingRunListener.java:111)
at org.springframework.boot.context.event.EventPublishingRunListener.started(EventPublishingRunListener.java:60)
at org.springframework.boot.SpringApplicationRunListeners.started(SpringApplicationRunListeners.java:48)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
at org.springframework.boot.context.web.SpringBootServletInitializer.run(SpringBootServletInitializer.java:149)
Your approach with declaring newer dependency directly in the child pom.xml is correct. As per Introduction to the Dependency Mechanism:
Dependency mediation - this determines what version of an artifact will be chosen when multiple versions are encountered as dependencies. Maven picks the "nearest definition". That is, it uses the version of the closest dependency to your project in the tree of dependencies. You can always guarantee a version by declaring it explicitly in your project's POM.
You most likely need to add spring-core on which the spring-context depends to have the right version of org.springframework.core.ResolvableType class and avoid NoSuchMethodError:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.0.RELEASE</version>
</dependency>
Running with multiple version of Spring in the classpath is asking for runtime problems. It's best to keep all the Spring JARs in the same version in your runtime deployment.
currently I'm working on a project in my company that imports XML data to our database. While doing this I rely on some basic configuration projects which have been already created and used in other Projects, i.e. an EntityManagerBuilder or other utility classes that are used in order to create a connection to our oracle database. And it seems to me that those dependencies are creating some problems for me.
My project runs perfectly fine if I start it within eclipse. And when I create the project with mvn clean install -DskipTests it builds all fine.
But when I want to run it from the command line the application starts and after a few lines of code just stops, without throwing any errors or exceptions.
The reason why I think that it has something to do with some dependencies is that by logging I managed to find the point where the application stops. Since it stopped at a point I could investigate, I just did that. I downloaded the sources an only added some logging and suddenly my application had no problems at all with that class, instead it just stopped with the next static call to an other class.
I have no idea at all where to search for the error. Since this is an application that has to run by it self as a monthly task, executing it from eclipse is not an option.
Hopefully someone can give me a hint how to solve this.
Here is my POM:
<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>
<parent>
<groupId>com.company.infrastructure.foo</groupId>
<artifactId>foo</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>foo-import</artifactId>
<packaging>jar</packaging>
<name>FooImport</name>
<properties>
<company.consoleapp.main.class>com.company.infrastructure.foo.import.FooImporter</company.consoleapp.main.class>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.company.maven</groupId>
<artifactId>company-standalone-dm</artifactId>
<version>${company.parent.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
<!-- Utilities -->
<dependency>
<groupId>args4j</groupId>
<artifactId>args4j</artifactId>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.2.11</version>
</dependency>
<!-- Using foo-dataaccess -->
<dependency>
<groupId>com.company.infrastructure.marken</groupId>
<artifactId>foo-dataaccess</artifactId>
<version>1.0.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<finalName>foo-import</finalName>
<plugins>
<!-- Consoleapp-Mixin -->
<plugin>
<groupId>com.github.odavid.maven.plugins</groupId>
<artifactId>mixin-maven-plugin</artifactId>
<configuration>
<mixins>
<mixin>
<groupId>com.company.maven</groupId>
<artifactId>company-consoleapp-mixin</artifactId>
<version>${company.parent.version}</version>
</mixin>
</mixins>
</configuration>
</plugin>
</plugins>
</build>
I think this might be something to do with your dependency management in maven, since you haven't specified the versions and maven figures out those versions automatically.
However when you run the application, you need those jars to be in your classpath otherwise you might end up getting a ClassNotFoundException because the jars are not available. So unless you figure out what your dependencies are like you mentioned and add them to your classpath you would end up seeing the error.
It might be worth enabling a further level of logging in your application to give you some indication of where the error is. You could also try and see if at the point of failure is referenced to an external library, which is the one that is not available in your classpath.
Could you also please share how your running your application through CLI.
I am having trouble importing spring framework into eclipse. I have downloaded spring but am unable to import it. Can anyone help or direct me to a web page that can do so?
You can either follow this tutorial:
http://www.tutorialspoint.com/spring/spring_hello_world_example.htm
or use the spring eclipse plugin (you can find it in eclipse under Help/eclipse marketplace and search for it)
or you can use a tool to manage your dependencies like maven.
It wouldn't be a bad idea to get familiar with a dependency manager like Maven. For use in Eclipse there is a nice plugin M2Eclipse. The pom.xml file is what you use to specify your dependencies, and then when you build with Maven it resolves everything for you and downloads automatically anything it needs. This is the example pom.xml file from the Maven installation instructions:
<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.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Maven Quick Start Archetype</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
The dependency for the core Spring Framework is
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.1.6.RELEASE</version>
</dependency>
And generally you can find the pom.xml dependency specifications at the Maven Repository. Might seem a little overdone for simply getting Spring into Eclipse, but once you have it set up it is then a snap to add more dependencies down the road, all you do is add the appropriate item to the pom.xml file.
The setup is the following:
I am using Maven and I would like to use as a parent POM some artifact that has a number of dependencies in the dependencyManagement section. But I would also like to have a dependencyManagement section in my POM as well, because my artifact will be the parent pom of some other submodules.
Example:
<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>
<parent>
<groupId>com.mycompany</groupId>
<artifactId>parent-pom</artifactId>
<version>1.0</version>
</parent>
<groupId>com.mycompany</groupId>
<artifactId>my-artifact</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>sub-module-01</module>
<module>sub-module-02</module>
</modules>
<packaging>pom</packaging>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.2.3.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
Let's say that both these parent poms define a version for some dependency (let's say the version for jackson), but each has a different version.
When I define that dependency in one of my submodules, which version will be resolved?
I am not sure how to search for this situation on google.
Typically, Maven resolves using the closest version declaration.
My best guess would be that the one from the import in the dependency management section would be preferred, since it is closer to the location where the dependency is used:
dependency -> imported dependency in parent pom = 2 hops
dependency -> parent pom -> dependencyManagement in parent pom = 3 hops
But really, just try it ;)
Let us according to the different case:
Firstly, The simplest case is NO pom dependency import tag in any pom's dependencyManagement section, everything is clear and the dependency declaration will make a really affect with the closest dependency and properties such as exclude will inherit from parent pom and the exclusion with be merged .
Secondly, if the there is a direct declaration in any of each pom's DM section, this declaration will be used for this jar . if not, the closest import dependency declaration if exists will be used to the jar/pom's version. Here the closest mean is the distance to the pom and super pom or ,super super pom. But Not The transitivity distance!
I think it will be the version from import. Because the import
DependencyManagement Just do a replace of dependencies. so Parent dependency will be overwritten by the import dependency. I do not verify this. Just a guess.
I Just do an experiment to check this situation.
Firstly. I define a dependency of netty-handler.
In my maven repository netty-handler version contain:
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-handler</artifactId>
<version>4.1.8.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-handler</artifactId>
<version>4.1.9.Final</version>
</dependency>
I create one test_parent pom project with this content in pom.xml
<groupId>dm-test</groupId>
<artifactId>parent-test-pom</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<dependencyManagement>
<dependencies>
<!-- define a dependency in super parent pom with version 4.1.8.Final -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-handler</artifactId>
<version>4.1.8.Final</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
and then create a pom project for import:
<groupId>dm-test</groupId>
<artifactId>import-pom</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<dependencyManagement>
<dependencies>
<!-- define a dependency in super parent pom with version 4.1.9.Final -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-handler</artifactId>
<version>4.1.9.Final</version>
</dependency>
</dependencies>
</dependencyManagement>
Finally, I create a war project with the parent_pom and import_pom, like this:
<groupId>dm-test</groupId>
<artifactId>test-project</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<parent>
<groupId>dm-test</groupId>
<artifactId>parent-test-pom</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>dm-test</groupId>
<artifactId>import-pom</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-handler</artifactId>
</dependency>
</dependencies>
finally, We can see the dependency jar version is 4.1.8.Final
So, My guess is wrong. sorry about that.
Env: Maven 2.2.1
I have two java projects under svn (projectA, projectB). My maven structure is as follows..
For projectA
pom.xml (contains ProjectA parent pom definitions)
module moduleA
module moduleB
For projectB
pom.xml (contains ProjectB parent pom definitions)
module moduleC
module moduleD
projectA/pom.xml and projectB/pom.xml contain common definitions like junit, selenium, compiler, eclipse plug-ins which are common to both projects. (e.g. given below)
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.4</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency
How should I create / organize a organization specific project pom which includes such common definitions, so that individual projects don't have to re-create / maintain one. Can someone provide some snippets or projects which have already done this before?
EDIT1:
company/pom.xml
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany</groupId>
<artifactId>company</artifactId>
<packaging>pom</packaging>
<name>parent</name>
<version>1.0.0</version>
<build>
<defaultGoal>install</defaultGoal>
</build>
<dependencies>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.4</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
</dependencies>
projectA/pom.xml
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.mycompany</groupId>
<artifactId>company</artifactId>
<version>1.0.0</version>
</parent>
<groupId>com.mycompany</groupId>
<artifactId>projectA</artifactId>
<packaging>pom</packaging>
<name>projectA</name>
<version>1.0.0</version>
<modules>
<module>moduleA</module>
<build>
<defaultGoal>install</defaultGoal>
</build>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
projectA/moduleA/pom.xml
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.mycompany</groupId>
<artifactId>projectA</artifactId>
<version>1.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>com.mycompany</groupId>
<artifactId>moduleA</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>moduleA</name>
<build>
<finalName>moduleA</finalName>
<defaultGoal>install</defaultGoal>
</build>
<dependencies>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</dependency>
</dependencies>
Throws the following error:
Project ID: com.mycompany:moduleA
POM Location: c:\temp\maven\projectA\moduleA\pom.xml
Validation Messages:
[0] 'dependencies.dependency.version' is missing for commons-lang:comm
ons-lang:jar
[1] 'dependencies.dependency.version' is missing for javax.servlet:ser
vlet-api:jar
I would seriously reconsider adding dependencies into a "super" POM, this unnecessarily couples the projects (but may hint that if the projects aren't disparate then they should be merged anyway).
I think the last comment by #lexicore is poignant too, to expand on the OOP analogy it also feels like "mixing levels of abstraction".
Alex Gitelman provides the correct answer, you need to use dependencyManagement as shown here Dependency Scope
Maven3 is supposed to be supporting POM fragments see How to use Maven 3 mixins? which I've long been waiting for.
We have an organisation Über POM but this just contains:
<organization>
<name>...</name>
<url>...</url>
</organization>
<developers>
<developer>
<id>...<id>
<name>...</name>
<email>...</email>
<roles>
<role>...</role>
</roles>
</developer>
<distributionManagement>
...
</distributionManagement>
<repositories>
<!-- your proxy repo here -->
</repositories>
These are things that change very rarely (if we change our repository/distribution-management then all projects must change, if a developer leaves or joins we can update the project POMs at any time convenient).
Dependencies belong specifically to the module under consideration, just because two independent project happen to share dependencies now doesn't mean they always will. I completely understand the annoyance of having to copy 'n' paste reams of XML for each project (compiler plugin, reporting plugins, junit etc), but differing levels of activity in each project will surely mean they diverge at some point.
WRT cascade builds in Continuous Integration, if project A demands a change in the super dependencies POM, then all you other projects will be forced to rebuild - maybe fine if you've only 2 projects but even then did you checkout and build both before committing the change?
If it's only dependencies that you need to reuse, create another project with packaging pom and specify dependencies there. Let's call it OrgDependencies Then include it as dependency in your projectA and projectB. It will transitively pull all dependencies from OrgDependencies project.
In your example, in projectA, instead of
<parent>
<groupId>com.mycompany</groupId>
<artifactId>company</artifactId>
<version>1.0.0</version>
</parent>
Try putting
<dependencies>
<dependency>
<groupId>com.mycompany</groupId>
<artifactId>company</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
And remove dependencies to commons-lang etc from modules.
Update.
While my previous solution with transitive dependencies should work, actually what you need
is <dependencyManagement> section in your company wide pom.xml
That's where you define versions.
Note: Anything in dependencyManagement section is not really a dependency but just a descriptor that allows to specify version and exclude transitive dependencies (if necessary) in case normal dependencies section specifies that dependency. So you can put as many items in dependencyManagement as you want, it will not make all descendants dependent on them.
I tested it and it works:
<?xml version="1.0" encoding="UTF-8"?>
<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.mycompany</groupId>
<artifactId>company</artifactId>
<packaging>pom</packaging>
<name>parent</name>
<version>1.0.0</version>
<build>
<defaultGoal>install</defaultGoal>
</build>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.4</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
In OS projects I am normally using 3+ levels of POMs:
"Company-wide POM" contains dev-wide definitions like distribution management, individual plugin versions etc. Very stable, normally has one-number version. Example: Sonatype OSS Parent.
"Project POM" contains project-wide definitions: Java compiler version, dependency management etc. Parent is company-wide POM. Example :JAXB2 Basics Project. Version is updated with each release.
"Module POMs" on different levels. List individual dependencies (versions of dependencies are inherited from the project POM), add "special" build steps. Example: JAXB Basics.
I saw a similar pattern an other OS projects (like Apache's) as well.
A few more comments:
You may also have the "department POM" or "product POM" depending on the company size and product organization.
Think of POM inheritance pretty much as of OOP inheritance. What would you put into which abstract class so that class hierarchy is stable but dynamic? For instance, it would not make sense to define versions of dependencies in the company-wide POM since versions change too often. On the contrary, defining distribution management in earch of the projects would hurt the DRY principle.