Creating and importing a custom Spring library whilst separating shared dependencies

Pre Java 9. You can exclude the spring dependencies using maven when you declare the dependency to your module, same goes on for Hibernate. But you can't tell to your module to use a different hibernate version in a WAR.

If you want to work around this you can develop your library as independent micro service expose interface in the form of REST or Websocket if you want full duplex communication or something else JMS whatever....

Post Java 9 you can use java modularity to define the exact dependencies for your jar module. Check Project Jigsaw https://www.baeldung.com/project-jigsaw-java-modularity.

In your case in order to have different versions of the same library (hibernate). You would need two separate class loaders. To achieve this you would need to use layering read here http://openjdk.java.net/projects/jigsaw/spec/sotms/#layers

And here is the source code of many examples including ones that use layers. Focus on them : https://github.com/accso/java9-jigsaw-examples/tree/master/jigsaw-examples


You can try to exclude all transitive dependencies that your library can bring to projects that will use it.

To do this you should replace spring-boot-starter-parent with spring-boot-dependencies in dependencyManagement section and use provided scope for all dependencies which the library needs to work with and which will be exactly used by the projects, that will work with the library.

For example, a pom.xml of your library can be looks like this:

<!-- ... -->
    <groupId>com.example</groupId>
    <artifactId>library</artifactId>
    <version>0.1.0</version>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>
        <spring-boot.version>2.1.5.RELEASE</spring-boot.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>
<!-- ... -->

Then you will be able to use your library in the different projects, that use for example the old Spring Boot:

<!-- ... -->
    <groupId>com.example</groupId>
    <artifactId>old-project</artifactId>
    <version>0.13.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.19.RELEASE</version>
        <relativePath/>
    </parent>
<!-- ... -->
    <dependencies>
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>library</artifactId>
            <version>0.1.0</version>
        </dependency>

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

So this project will use hibernate-validator:5.3.6.Final from its spring-boot-starter-web.

Important notes - the code of your library should be 'compatible' with this version of Spring Boot. In other words, you should test your library with different versions of Spring Boot in which you are interested.

See my project as an example.