Search code examples
spring-bootgradlespring-clouddependency-managementspring-vault

How to allow spring boot applications to use custom jar having spring cloud dependency


I have many spring boot microservices and I have developed a new project that has Spring-Vault as a dependency. This new project (say vault-client-spring) is developed in order to have common configuration for setting up of Vault and use it in all of the microservices and I have published the jar in private maven hosted repository in my organization.

My problem is when I add this jar as dependency in any microservices, the application is not starting throwing the following error. The Spring-Cloud-Vault dependencies are not imported to my consuming projects. I've also added the necessary properties requrired starting with prefix spring.cloud.vault in bootstrap.yml file.

Here's my build.gradle file for vault-client-spring.

group = 'com.mygroup'
version = '0.0.1'

buildscript {
    ext {
        springBootVersion = '2.4.4'
        springDepsMgmtVersion = '1.0.11.RELEASE'
    }

    repositories {
        mavenCentral()
    }

    dependencies {
        classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"
        classpath "io.spring.gradle:dependency-management-plugin:${springDepsMgmtVersion}"
    }
}

apply plugin: 'java-library'
apply plugin: 'idea'
apply plugin: 'maven-publish'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

sourceCompatibility = '1.8'

repositories {
    mavenCentral()
}

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

bootJar {
    enabled = false
}

jar {
    archivesBaseName = 'vault-client-spring'
    enabled = true
}

ext {
    springCloudVersion = '2020.0.2'
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
    }
}

dependencies {
    implementation 'org.springframework.cloud:spring-cloud-starter-vault-config'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

test {
    useJUnitPlatform()
}

task sourcesJar(type: Jar, dependsOn: classes) {
    classifier('sources')
    from sourceSets.main.allSource
}

publishing {
    publications {
        mavenJava(MavenPublication) {
            artifact jar
            artifact sourcesJar
        }
    }
    repositories {
        maven {
            credentials {
                username 'PRIVATE-USER'
                password 'PRIVATE-PASSWORD'
            }
            url 'PRIVATE MAVEN URL'
        }
    }
}

Here's the build.gradle file for a microservice using this jar.

plugins {
    id 'org.springframework.boot' version '2.4.3'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
}

group = 'com.mygroup'
version = ''
sourceCompatibility = '1.8'

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
    maven { url 'PRIVATE MAVEN URL' }
}

bootJar {
    setArchivesBaseName("microservice-one")
    version("")
}

dependencies {
    implementation 'com.mygroup:vault-client-spring:0.0.1' // here's the dependency
    implementation 'org.springframework.boot:spring-boot-starter-web'

    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

compileJava {
    compileJava.inputs.files(processResources)
}

test {
    useJUnitPlatform()
}

The generated POM file.

<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.mygroup</groupId>
    <artifactId>vault-client-spring</artifactId>
    <version>0.0.1</version>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>2020.0.2</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.4.4</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

The error I'm facing is as follows..

Caused by: java.io.FileNotFoundException: class path resource [org/springframework/vault/config/AbstractVaultConfiguration.class] cannot be opened because it does not exist
    at org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.java:180) ~[spring-core-5.3.4.jar:5.3.4]
    at org.springframework.core.type.classreading.SimpleMetadataReader.getClassReader(SimpleMetadataReader.java:55) ~[spring-core-5.3.4.jar:5.3.4]
    at org.springframework.core.type.classreading.SimpleMetadataReader.<init>(SimpleMetadataReader.java:49) ~[spring-core-5.3.4.jar:5.3.4]
    at org.springframework.core.type.classreading.SimpleMetadataReaderFactory.getMetadataReader(SimpleMetadataReaderFactory.java:103) ~[spring-core-5.3.4.jar:5.3.4]
    at org.springframework.boot.type.classreading.ConcurrentReferenceCachingMetadataReaderFactory.createMetadataReader(ConcurrentReferenceCachingMetadataReaderFactory.java:86) ~[spring-boot-2.4.3.jar:2.4.3]
    at org.springframework.boot.type.classreading.ConcurrentReferenceCachingMetadataReaderFactory.getMetadataReader(ConcurrentReferenceCachingMetadataReaderFactory.java:73) ~[spring-boot-2.4.3.jar:2.4.3]
    at org.springframework.core.type.classreading.SimpleMetadataReaderFactory.getMetadataReader(SimpleMetadataReaderFactory.java:81) ~[spring-core-5.3.4.jar:5.3.4]
    at org.springframework.context.annotation.ConfigurationClassParser.asSourceClass(ConfigurationClassParser.java:696) ~[spring-context-5.3.4.jar:5.3.4]
    at org.springframework.context.annotation.ConfigurationClassParser$SourceClass.getSuperClass(ConfigurationClassParser.java:1010) ~[spring-context-5.3.4.jar:5.3.4]
    at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:341) ~[spring-context-5.3.4.jar:5.3.4]
    at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:250) ~[spring-context-5.3.4.jar:5.3.4]
    at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:199) ~[spring-context-5.3.4.jar:5.3.4]
    at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:304) ~[spring-context-5.3.4.jar:5.3.4]
    at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:250) ~[spring-context-5.3.4.jar:5.3.4]
    at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:207) ~[spring-context-5.3.4.jar:5.3.4]
    at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:175) ~[spring-context-5.3.4.jar:5.3.4]
    ... 14 common frames omitted

How to solve this error? I'm working for the first time in Spring Cloud native projects


Solution

  • I found it myself. Since I'm developing as "library", I have to allow Spring-Vault dependencies to get included in consuming applications. As per Gradle's java-library plugin, I used api dependency. The consuming applications can able to access and bootstrap them.