5

I have two Spring Boot projects, and want to use one of them as MAVEN dependency in other.

  • Project Scraper depends on Database project
  • Project Database contains database layer (Entities and DAO are build and tested here)

In Database project I have to override the Hibernate version, and did like described in https://spring.io/blog/2016/04/13/overriding-dependency-versions-with-spring-boot option 2.

<properties>
...
    <hibernate.version>5.2.10.Final</hibernate.version>
</properties>

This works fine and I see proper version in MAVEN depdndencies for Database project: /home/pm/.m2/repository/org/hibernate/hibernate-core/5.2.10.Final/hibernate-core-5.2.10.Final.jar

Than I come to Scraper project. It not contain any Hibernate in Maven dependencies, as I not import them explicitly. Now I add my Database prject dependency

    <dependency>
        <groupId>web.scraper.database</groupId>
        <artifactId>DataBase</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>

And this imports hibernate as well, but with wrong version (version mentioned in Spring parent pom, instead of my Database project Hibernate version) /home/pm/.m2/repository/org/hibernate/hibernate-core/5.0.12.Final/hibernate-core-5.0.12.Final.jar

I want to get hibernate version mentioned in Database project dependecy. Ho to do this?

I would like to not override Hibernate version in Scraper project.

Scraper/pom.xml

<?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>web.scraper.engine</groupId>
    <artifactId>Scraper</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>Scraper</name>
    <description>Web scraper application</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>web.scraper.database</groupId>
            <artifactId>DataBase</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>6.0.6</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

Database/pom.xml

<?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>web.scraper.database</groupId>
    <artifactId>DataBase</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>DataBase</name>
    <description>Data base model and DAO</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.4.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <!-- Need to set Hibernate version explicitly,
        because java 8 date and time not mapped properly
        with default version -->
        <hibernate.version>5.2.10.Final</hibernate.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <!-- 
            <scope>runtime</scope>
             -->
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- This makes H2 web console available -->
        <!-- 
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <optional>true</optional>
            </dependency>
        -->             

<!-- 
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>1.1.0.Final</version>
        </dependency>
 -->

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.4.1.Final</version>
        </dependency>


    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>
P_M
  • 2,723
  • 4
  • 29
  • 62

2 Answers2

2

To coordinate dependencies between projects, you should introduce a parent pom that both projects inherit from. The parent project itself can inherit from the Spring Boot parent pom. All dependency version overrides via properties should occur in your new parent pom, something like this:

<?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>web.scraper</groupId>
    <artifactId>Parent</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>

    <name>Parent</name>
    <description>Parent pom to coordinate dependencies</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.4.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <!-- Need to set Hibernate version explicitly,
        because java 8 date and time not mapped properly
        with default version -->
        <hibernate.version>5.2.10.Final</hibernate.version>
    </properties>

    <!-- Optionally, you can make this parent define a multi-module project, 
         so that the artifacts can be built together, but you don't have to. -->
    <modules>
        <module>Scraper</module>
        <module>Database</module>
    </modules>
</project>

And then, in your Scraper and Database poms, declare the parent like so:

<parent>
    <groupId>web.scraper</groupId>
    <artifactId>Parent</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <relativePath/> <!-- lookup parent, or make a multi-module project -->
</parent>

Additionally, any new dependencies that you need to add that are not managed by spring, can be added to the <dependencyManagement> section of the parent pom, so that your other poms never have to declare versions.

With this in place, mvn dependency:tree | grep hibernate-core shows the correct versions in both projects:

[INFO] |  +- org.hibernate:hibernate-core:jar:5.2.10.Final:compile
derickson82
  • 456
  • 2
  • 11
  • Looks reasonable. I will check and come back with results – P_M Aug 04 '17 at 14:53
  • Thanks! This works without any issues for me. As about modules - I thought about it, but think in my case I do not need it for now – P_M Aug 07 '17 at 07:01
1

You can force the proper version. In your scraper project, from within your database dependency tag, exclude the Hibernate dependency.

<exclusions>
  <exclusion>  
    <groupId>sample.ProjectB</groupId>
    <artifactId>Project-B</artifactId>
  </exclusion>
</exclusions> 

Maven Optional Dependencies and Dependency Exclusions

Obviously, replace the sample.ProjectB stuff with the Hibernate info. Then, you just include a separate dependency for the version of Hibernate that you want.

I think there is a simpler way to do this all within the database dependency in your scraper project but I can't find it ATM and I don't have much time.

Also of note/help:

EDIT: based on our comments, try excluding Hibernate from the first Spring dependency so that Spring is not able to pass it on to the scraper project.

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-jpa</artifactId>
  <exclusions>
    <exclusion>  
      <groupId>HIBERNATE-STUFF</groupId>
      <artifactId>HIBERNATE-STUFF</artifactId>
  </exclusion>
</exclusions> 
</dependency>

This would be the Spring dependency in the database file. Have a separate dependency for the version of Hibernate you want.

As a side note, give these a spin. They can help spot what's coming from where:

mvn dependency:tree -Dverbose 
mvn dependency:tree -Dverbose | grep 'omitted for conflict'
Old Schooled
  • 1,222
  • 11
  • 22
  • 1
    I will check this, and probably use for now, though this forces developer on Scraper project have to know the dependencies version overriden on Database project. Right? So the Scraper project developer should check the Database\pom.xml on every new version... The idea though was to be able work on Database and Scraper independently. Any more thoughts are welcome. – P_M Aug 04 '17 at 08:20
  • If I'm following this correctly, the wrongHibernate is coming from the Spring dependency in the database pom? If that's the case, how about putting the exclusion NOT in the scrapper pom under the database dependency but instead in the database pom under the spring dependency? You already import it separately there so should be able to exclude it from Spring before it gets to scrapper. We try to get rid of it at the source? I've talked myself in loops. Not sure if that works. – Old Schooled Aug 04 '17 at 08:25
  • 1
    I already overriden Hibernate version in Database project. See the line in Database\pom.xml 5.2.10.Final, and this works even without exclusions, but when I import Database as dependency in Scraper project, it takes older Spring predefined version. – P_M Aug 04 '17 at 08:47
  • You misunderstood. I understand that you've overridden hibernate in the database **project**, however, I'm asking you to exclude it from the **spring dependency**, inside of the database project. So, keep what you already have but within the Spring dependency, exclude hibernate specifically. You get me? Spring is bringing this into your second project so exclude hibernate from **Spring** in your first. Check my answer above again, I've thrown an edit at the bottom to try and show what I mean. – Old Schooled Aug 04 '17 at 08:53
  • 1
    Well... it looks I start to understand what you mean. In Database\pom.xml I will exclude Hibernate from spring-boot-starter-data-jpa dependency, and instead of overriding its version just add Hibernate core as usual dependency to Database project. Right? – P_M Aug 04 '17 at 09:00
  • Yes your update on post is great. I will check this a bit later. Have to break. – P_M Aug 04 '17 at 09:02
  • Bingo. That's exactly what I mean. – Old Schooled Aug 04 '17 at 09:05
  • 1
    I tried but not works. Here what in maven tree [INFO] | +- org.hibernate:hibernate-core:jar:5.0.12.Final:compile (version managed from 5.2.10.Final). I excluded hibernate dependencies in my Database pom for Spring artifacts, and import them with explicitly written versions. Looks like the version value in Spring parent pom in Scraper project overrides settings from Database project transitive dependency. So the Scraper project still gets older hibernate version from spring config. – P_M Aug 04 '17 at 11:23
  • :( Tough. Then the only way I see it at the moment is to specify the version you want or exclude the version you don't want in the scrapper dependencies (although I know that sucks and doesn't give you the separation you're looking for.) However, it's not so horrible if you go with the simplest way, just to include the Hibernate version in your properties tag in scrapper just like you did for database. 5.2.10.Final – Old Schooled Aug 04 '17 at 11:49
  • 1
    Yes right, I do not see anything better for now. MAVEN allows only one pom and I have it, because of Spring boot needs it. Versions are inherited from parent pom. So I can create my own parent pom (copy most content of spring boot pom files). But this will be not Spring boot - just Spring and will need some efforts to create and support. I will just override hibernate version in Scraper pom. – P_M Aug 04 '17 at 11:56
  • Also, although you want to keep this away from this part of development, the fact that you have to use this version (and not the most current) is something you'll always have to explain/account for anyway. Might as well make the code in the scrapper project so if the version does cause other problems at least you won't have people tripping over an imaginary problem, it will be something that's documented in their current project. Basically, putting the force inside of scrappers pom lets all scrapper programmers see that they are using a specific version and not the lastest. – Old Schooled Aug 04 '17 at 11:57
  • Thanks for looking into this! – P_M Aug 04 '17 at 12:06