Ermintar
Ermintar

Reputation: 1393

BootJar + MavenJar. Artifact wasn't produced by this build

I have a sample project with the following hierearhy:

Sample (root)
   -- model (simple jar)
   -- api   (springboot jar)

I want to publish both generated jars: plain jar & bootJar to my localRepository.

gradlew clean build -xTest publishToMavenLocal    

However, the following error occures:

* What went wrong:
Execution failed for task ':api:publishMavenJavaPublicationToMavenLocal'.
> Failed to publish publication 'mavenJava' to repository 'mavenLocal'
   > Artifact api.jar wasn't produced by this build.

The root build.gradle is a follows:

plugins {
    id 'java'
    id "org.springframework.boot" version "2.2.5.RELEASE" apply false
    id 'io.spring.dependency-management' version '1.0.9.RELEASE'
}
group 'sample'
version '1.0-SNAPSHOT'

apply plugin: 'java'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
}
ext {
    artifactVersion = version
    springBootVersion = "2.2.5.RELEASE"
}

allprojects {
    apply plugin: 'java'
    apply plugin: 'idea'
    apply plugin: 'maven'
    tasks.withType(JavaCompile) {
        options.encoding = 'UTF-8'
    }
    repositories {
        mavenCentral()
        jcenter()
    }
}

subprojects {
    apply plugin: "io.spring.dependency-management"
    apply plugin: "maven-publish"

    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8

    dependencyManagement {
        imports {
            mavenBom "org.springframework.boot:spring-boot-dependencies:${springBootVersion}"
        }
    }
    dependencies {
        implementation "org.springframework.boot:spring-boot-dependencies:${springBootVersion}"
    }

    publishing {
        publications {
            mavenJava(MavenPublication) {
                groupId project.group
                artifactId project.name
                version project.version

                from components.java
            }
        }
    }
}

api build.gradle

apply plugin: 'org.springframework.boot'

dependencies {
    compile project(":model")
    implementation "org.springframework.boot:spring-boot-starter-web"
}

bootJar {
}

Adding bootJava task to api build.gradle allowes to publish the bootJar directly from api module, but the root publish task remains broken.

publishing {
    publications {
        bootJava(MavenPublication) {
            artifact bootJar
        }
    }
}

I've tried almost every solution from docs & google, but none seem to work. Can anyone explain, what is misconfigured?

Gradle version: 6.3

Upvotes: 19

Views: 19643

Answers (6)

codependent
codependent

Reputation: 24482

For Spring Boot 2.5.0+, this configurations works for publishing the embedded jar, its sources and javadoc:

plugins {
    id 'maven-publish'
    id 'java-library'
}

jar {
    enabled = false
}

java {
    withSourcesJar()
    withJavadocJar()
}

publishing {
    publications {
        publication(MavenPublication) {
            artifact bootJar
            from components.java
        }
    }
}

Upvotes: 4

Prasanth Rajendran
Prasanth Rajendran

Reputation: 5542

Excerpt from

Starting from Gradle 6.2, the main jar task is disabled by the Spring Boot application, and the component expects it to be present. Because the bootJar task uses the same file as the main jar task by default, previous releases of Gradle would either:

  • publish a stale bootJar artifact
  • or fail if the bootJar task hasn’t been called previously

To simple workaround would be configuring the outgoing configurations. For multi-module Gradle project, place the below configuration in the service module(spring boot module).


dependencies {
          .....
}

configurations {
    [apiElements, runtimeElements].each {
        it.outgoing.artifacts.removeIf {
            it.buildDependencies.getDependencies(null).contains(jar)
        }
        it.outgoing.artifact(bootJar)
    }
}

Note: There is no need for changing anything with artifactory task if it was configured correctly. This working solution has been tested with Gradle 6.4.1.

Don't try the alternate suggestion that they provided, because classifier attribute is deprecated in recent versions, also altering the bootJar task with custom configuration would result in improper uber jar construction, and if you extract the generated jar distributive, you could find the missing BOOT-INF directory and necessary META-INF/MANIFEST.MF values.

jar {
   enabled = true
}

bootJar {
   classifier = 'application'
}

Update:

From Spring Boot 2.5.0, jar task generates an additional jar archive which ends with -plain.jar. It may break someone's build if they have used some patterns like *.jar to copy the build archive, hence, to restrict the additional jar creation, the following jar task configuration code snippet should be used.

jar {
    enabled = false
}

Upvotes: 13

Sujay Bhowmick
Sujay Bhowmick

Reputation: 31

If you are using gradle kotlin dsl add the equivalent in your build.gradle. It worked for me

 configurations {
    val elements = listOf(apiElements, runtimeElements)
    elements.forEach { element ->
        element.get().outgoing.artifacts.removeIf { it -> it.buildDependencies.getDependencies(null).contains(tasks.jar.get())}
        element.get().outgoing.artifact(tasks.bootJar.get())
    }
}

Upvotes: 3

Janitha Madushan
Janitha Madushan

Reputation: 1543

According to the 'Gradle' documentation under,

https://docs.gradle.org/current/userguide/upgrading_version_6.html#publishing_spring_boot_applications

Just add the following to the build.gradle file

jar {
   enabled = true
}

bootJar {
   classifier = 'application'
}

Upvotes: 7

Jarvis
Jarvis

Reputation: 345

I could get this worked by just adding artifact bootJar in the publishing task as shown below and with out adding any configurations as suggested in the gradle documentation. I believe this could be working same as their first workaround in the documentation. Tested with gradle 6.5.1

publishing {
    publications {
        mavenJava(MavenPublication) {
            artifact bootJar
            artifact sourceJar {
                classifier "sources"
            }
        }
    }
}

project.tasks.publish.dependsOn bootJar

Upvotes: 12

hasnae
hasnae

Reputation: 2183

As stated by gradle documentation here:

Starting from Gradle 6.2, Gradle performs a sanity check before uploading, to make sure you don’t upload stale files (files produced by another build). This introduces a problem with Spring Boot applications which are uploaded using the components.java component

More explanation is available in the link above. They propose the following workaround that I personally tried and worked for me :

configure the outgoing configurations

configurations {
       [apiElements, runtimeElements].each {
           it.outgoing.artifacts.removeIf { it.buildDependencies.getDependencies(null).contains(jar) }
           it.outgoing.artifact(bootJar)
       }
    }

here after the configuration from my build.gradle:

....
apply plugin: 'maven-publish'
...

configurations {
    [apiElements, runtimeElements].each {
        it.outgoing.artifacts.removeIf { it.buildDependencies.getDependencies(null).contains(jar) }
        it.outgoing.artifact(bootJar)
    }
    ....
}


publishing {
    publications {
        myPublication(MavenPublication) {
            groupId groupId
            artifactId artifactId
            version version
            from components.java
            versionMapping {
                usage('java-api') {
                    fromResolutionOf('runtimeClasspath')
                }
                usage('java-runtime') {
                    fromResolutionResult()
                }
            }
        }
    }
    repositories {
        maven {
            url azureRepoUrl
            name azureRepoName
            credentials {
                username azureRepoUserName
                password azureRepoAccessToken
            }
        }
    }
}

Upvotes: 16

Related Questions