Can't set variables before plugins{} - spring-boot

I have this build.gradle
plugins {
id 'org.springframework.boot' version '2.1.6.RELEASE'
id 'java'
id 'eclipse-wtp'
}
[...]
dependencies {
compileOnly group: 'org.springframework.boot', name: 'spring-boot-dependencies', version: '2.1.6.RELEASE', ext: 'pom'
[...]
I would specify a variable springBootVersion = "2.1.6.RELEASE". Unluckily, this is not possible, since I get this error:
only buildscript {} and other plugins {} script blocks are allowed
before plugins {} blocks
I also tried to remove the version from spring-boot-dependencies but I get this error:
Could not resolve: org.springframework.boot:spring-boot-dependencies
Is there not a way to declare a variable before the plugin{} block, or, alternatively, remove the version from spring-boot-dependencies?
I'm using Gradle 5.4.1

You cannot use variables in the plugins block. Check the "Strict Syntax" section here: https://docs.gradle.org/current/javadoc/org/gradle/plugin/use/PluginDependenciesSpec.html
also:
https://github.com/gradle/gradle/issues/3593
You shouldn't need to define the spring boot version anywhere else than in the plugins block by applying the spring boot plugin(org.springframework.boot) and then applying the (io.spring.dependency-management) after the block. The latter one then will take care of resolving the right versions based on the boot plugin version.
If don't know about it yet, I suggest to use the https://start.spring.io/ to generate your spring boot project, because it can generate you a ready-to-go gradle project.

Perhaps
plugins {
ext.springBootVersion = '2.1.6.RELEASE'
id 'org.springframework.boot' version springBootVersion
...
}
[...]
dependencies {
compileOnly "org.springframework.boot:spring-boot-dependencies:${plugins.springBootVersion}#pom"

Using buildscript you can do this:
buildscript {
ext {
springBootVersion = '2.6.6'
}
}
plugins {
id 'org.springframework.boot' version "${springBootVersion}"
}

Related

Can I specify in gradle that I only want to use a certain plugin for tests?

I have a project and for testing purposes only I want to standup a quick websocket server. Spring Boot seems like the simplest way to do that, but I don't want to include the plugin in my implementation, only for tests. I can't seem to find documentation on something like this, but in general I've found the answer to the question "can gradle do this" is usually yes.
So how would I go about specifying to only use the 'org.springframework.boot' plugin for test builds?
I've tried placing the plugins {} block inside a test {} block but that doesn't work.
I'm pretty sure you may just apply the org.springframework.boot plugin in the regular way and it won't effect your build artifacts.
However, it is possible to apply plugins dynamically, if you are afraid that they might have undesired side-effects on build artifacts. The old plugin mechanism actually worked this way by default and separated the resolution of plugins from their application to the Project instance:
// This part resolves the plugin
buildscript {
repositories {
maven {
url 'https://plugins.gradle.org/m2/'
}
}
dependencies {
classpath 'org.springframework.boot:spring-boot-gradle-plugin:2.3.2.RELEASE'
}
}
// This part applies the plugin
apply plugin: 'org.springframework.boot'
This way it was possible to apply a plugin based on a condition:
if (testMode) {
apply plugin: 'org.springframework.boot'
}
Using the new plugins block to apply plugins, this is not possible directly, as the plugins block is a special block that does not allow custom code:
// This is not allowed!
plugins {
if (testMode) {
id 'org.springframework.boot' version '2.3.2.RELEASE'
}
}
The solution is to tell the plugins block to resolve a plugin without applying it automatically. This can then be done dynamically using apply plugin::
plugins {
id 'org.springframework.boot' version '2.3.2.RELEASE' apply false
}
if (testMode) {
apply plugin: 'org.springframework.boot'
}
You don't have to use org.springframework.boot plugin: just use io.spring.dependency-management plugin. This way, you will be able to declare spring-* related dependencies in your testImplementation configuration, without any impact on the implementation configuration.
plugins {
id 'io.spring.dependency-management' version '1.0.8.RELEASE'
id 'java'
}
dependencies {
testImplementation 'org.springframework.boot:spring-boot-starter'
testImplementation 'org.springframework.boot:spring-boot-starter-websocket'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
dependencyManagement {
imports {
mavenBom "org.springframework.boot:spring-boot-dependencies:2.2.0.RELEASE"
}
}
Then in your test sources, you will be able to declare SpringBoot application and other websocket-related stuff (controllers)
EDIT what org.springframework.boot is actually doing, is to change the packaging of the main jar artifact by declaring the bootJar task, see Springboot plugin reference. In your case you don't need this, as far as I understand, if you just want to run some Spring application in test sourceset.

How to get dependency version form parent project in Gradle

I have a Gradle project and I want to create a submodule but I am getting an FAILURE when building the project.
The error message is
Execution failed for task ':child-project:compileJava'
> Could not resolve all files for configuration 'child-project:compileClasspath'.
> Could not find org.springframework.boot:spring-boot-starter:.
Required by:
project :parent-project
This is the parent project build.gradle file:
plugins {
id 'org.springframework.boot' version '2.3.0.RELEASE'
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
id 'java'
}
allprojects {
apply plugin: 'java'
group = 'com.test'
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
repositories {
//local nexus
}
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-web'
//other dependencies
}
This is the child project build.gradle:
plugins {
id 'java'
}
group = 'com.test'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = JavaVersion.VERSION_11
dependencies {
compile 'org.springframework.boot:spring-boot-starter'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
Please help, thanks in advance.
In order to be able to specify Spring Boot dependencies without versions, you need to apply the Spring Boot plugin to all modules. Right now you only have it in the parent project, but not the child.
Because applying the plugin will also, by default, disable the normal jar task can create a bootJar instead, you need to change this for libraries:
// Child build file
plugins {
// Note that there are no versions on the plugins in the child project as this is defined by the ones in the parent
id 'org.springframework.boot'
id 'io.spring.dependency-management'
}
bootJar {
enabled = false
}
jar {
enabled = true
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
}
Alternatively, you could also scrap the io.spring.dependency-management plugin (and the org.springframework.boot plugin in the child project), and instead import the Spring Boot BOM as a platform:
// Child build file (alternative)
dependencies {
// Use 'platform' for making the versions in the BOM a recommendation only, and 'enforcedPlatform' for making them a requirement.
// Note that you need the version of the BOM, so I recommend putting it in a property.
implementation enforcedPlatform("org.springframework.boot:spring-boot-dependencies:2.3.0.RELEASE")
// Here you can leave out the version
implementation 'org.springframework.boot:spring-boot-starter'
}
I usually go for the latter alternative as this allows me to use normal Gradle semantics. But it is mostly just preference.
(And just a small note to your build script: the compile configuration is deprecated. It is used in the line compile 'org.springframework.boot:spring-boot-starter'. You probably just copy/pasted it from somewhere, but you should replace it with implementation.)

gradle does not fetch dependencies after upgrade from 5.1.1 to 6.4.1

I have several services that uses gradle 5.1.1 with java 8.
As we want to upgrade to Java 13, we first need to upgrade to gradle 6after doing so, some dependencies are not fetched.
Those dependencies are listed with compile() under a dependency which is our jar library and still built with gradle 5.1.1
our libraries are stored in a S3 bucket and we use shadowjar to generate the end jar.
so, for example:
I have project A which I want to upgrdae.
Project A has project B as a dependency (compile)
Project B has google guava as a dependency (also with compile)
Now, project A, that under gradle 5.1.1 had fetched guava with no problems, alerting me that it is missing guava after upgrading to gradle 6.
I use local computer installed gradle (not wrapper).
Here are the important build.gradle parts:
buildscript {
repositories {
jcenter()
maven {
url "https://plugins.gradle.org/m2/"
}
}
ext.ver = [
'springboot': '2.2.0.RELEASE',
'slf4j' : '1.7.12'
]
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:${ver.springboot}"
classpath 'io.spring.gradle:dependency-management-plugin:1.0.7.BUILD-SNAPSHOT'
classpath 'com.github.jengelman.gradle.plugins:shadow:5.2.0'
classpath 'com.amazonaws:aws-java-sdk-core:1.11.5'
}
}
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'maven'
apply plugin: 'com.github.johnrengelman.shadow'
apply plugin: 'maven-publish'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
compileJava {
sourceCompatibility = JavaVersion.VERSION_1_8
}
configurations {
compile.exclude module: 'spring-boot-starter-logging'
testCompile.exclude module: 'spring-boot-starter-logging'
runtime.exclude module: 'spring-boot-starter-logging'
compile.exclude group: 'ch.qos.logback'
}
configurations.all {
resolutionStrategy.cacheDynamicVersionsFor 10, 'seconds'
resolutionStrategy.cacheChangingModulesFor 10, 'seconds'
}
dependencyManagement {
applyMavenExclusions = false
}
repositories {
mavenLocal()
maven {
url "s3://bucket"
credentials(AwsCredentials) {
accessKey = awsCredentials.AWSAccessKeyId
secretKey = awsCredentials.AWSSecretKey
}
metadataSources {
artifact()
}
}
mavenCentral()
}
dependencies {
compile("com.test:projectB:1.0.0")
...
}
import com.github.jengelman.gradle.plugins.shadow.transformers.PropertiesFileTransformer
shadowJar {
classifier = ''
baseName = 'project-A'
manifest {
attributes 'Main-Class': 'com.test.projectA.Starter'
}
mergeServiceFiles()
append 'META-INF/spring.handlers'
append 'META-INF/spring.schemas'
append 'META-INF/spring.tooling'
transform(PropertiesFileTransformer) {
paths = ['META-INF/spring.factories']
mergeStrategy = "append"
}
}
Could this be because project B was not built with new gradle?
unfortunately, I cannot create a real reproducer as those libraries are real code of the company I work at.
Thanks and Regards,
Ido
The metadataSources declaration of the s3 bucket Maven repository is most likely the root cause why transitive dependencies of projectB are not resolved. The documentation is quite a bit vague here, but I suspect artifact() looks for the actual jar file only and not for the POM file, hence transitive dependency resolution is not performed. You should be able to see this behavior when running the build with switches --info and --refresh-dependencies.
Thankfully, this is quite easy to fix. Add mavenPom() and Gradle will try to resolve the POM first and with that, dependency resolution should be back to normal.
And while you're at it, you might want to read the upgrading from Gradle 5 guide and get rid of the compile configuration in favor of implementation. You should be able to see a warning similar to this when running the build with --warning-mode all:
The compile configuration has been deprecated for dependency declaration. This will fail with an error in Gradle 7.0. Please use the implementation or api configuration instead. Consult the upgrading guide for further information: https://docs.gradle.org/6.4.1/userguide/upgrading_version_5.html#dependencies_should_no_longer_be_declared_using_the_compile_and_runtime_configurations

Spring Data Neo4j OGM Gradle Dependency Issues

I am trying to manage my spring dependencies using gradle and the spring dependency management plugin. Currently this brings down version 5.0.3.RELEASE of spring-data-neo4j which according to the pom here, should bring down version 3.0.3 of the neo4j-ogm, but instead it brings down version 2.1.5. This means that even though I've followed the docs to the letter about configuration that the ConfigurationBuilder symbol is not found. Any help would be greatly appreciated. I am currently using gradle 4.4.1
buildscript {
repositories {
mavenCentral()
maven { url 'https://repo.spring.io/plugins-snapshot' }
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.8.RELEASE")
classpath 'io.spring.gradle:dependency-management-plugin:1.0.5.BUILD-SNAPSHOT'
}
}
plugins {
id "io.spring.dependency-management" version "1.0.4.RELEASE"
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
apply plugin: "io.spring.dependency-management"
ext {
springVersion = '5.0.3.RELEASE'
springDataVersion = 'Kay-SR3'
}
dependencyManagement {
imports {
mavenBom "org.springframework:spring-framework-bom:${springVersion}"
mavenBom "org.springframework.data:spring-data-releasetrain:${springDataVersion}"
}
}
repositories {
mavenCentral()
maven {
url 'https://repo.spring.io/libs-release'
}
}
dependencies {
compile group: "org.springframework.boot", name: "spring-boot-starter-web"
compile group: "org.springframework.boot", name: "spring-boot-starter-security"
compile group: "org.springframework", name: "spring-aspects"
compile group: "org.springframework.data", name: "spring-data-neo4j"
compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310'
testCompile group: "org.springframework.boot", name: "spring-boot-starter-test"
testCompile group: "org.neo4j", name: "neo4j-ogm-embedded-driver", version: "3.1.0"
}
You are using the spring-boot-gradle-plugin with version 1.5.8.RELEASE. This will pull in the version 4 of SDN and its dependency OGM 2.1.x when you declare the dependency here compile group: "org.springframework.data", name: "spring-data-neo4j".
The only solution at this point is to use Spring Boot 2 RC1. If you would include SDN with its dependencies to Spring Data commons and Spring Framework 5 you will mess up your class path because Spring Boot 1 is based on Spring Framework 4.
Background: Tried it once to integrate SDN 5.x in Spring Boot 1 but it did not work out, you will lose all benefits of Spring Boot since you have to deactivate pretty everything.

How are some gradle dependencies working with no version supplied

As far as I know gradle requires a version number when setting dependencies, but partial wildcards are allowed. For example if I want Guava, I cannot do this as it fails:
compile('com.google.guava:guava')
It has to be (as an example):
compile('com.google.guava:guava:21.0')
However, I'm learning Spring, which has the following:
compile("org.springframework.boot:spring-boot-starter")
compile("org.springframework:spring-web")
compile("com.fasterxml.jackson.core:jackson-databind")
How are these dependencies working with no version supplied?
Is it because of the following, but I thought these lines were required only for my plugin 'org.springframework.boot':
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.4.3.RELEASE")
}
}
It is worth mentioning that the trick is called BOM (bill of materials) and the actual versions can be checked in the related POM file (in this example, it is for the version 2.7.0) inside spring-boot-dependencies package. This is mentioned in the Spring Boot official documentation here: Build Systems.
Another way that Spring provides this (for non Boot projects) is through Spring Platform BOM where it actually provides version for the following dependencies.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'io.spring.gradle:dependency-management-plugin:0.6.0.RELEASE'
}
}
apply plugin: 'io.spring.dependency-management'
dependencyManagement {
imports {
mavenBom 'io.spring.platform:platform-bom:Athens-SR2'
}
}
TL;DR - spring boot uses custom dependencies resolver.
A spring boot plugin that is applied with the following piece of code:
apply plugin: 'spring-boot'
handles the dependencies that are listed without version. This logic is implemented in this class which delegates it to here. DependencyManagementPluginFeatures are applied here.
The spring boot gradle plugin documentation states the following:
The version of the spring-boot gradle plugin that you declare
determines the version of the spring-boot-starter-parent bom that is
imported (this ensures that builds are always repeatable). You should
always set the version of the spring-boot gradle plugin to the actual
Spring Boot version that you wish to use.
Spring Boot Dependency Management Plugin is not necessary.
You may use build-in Gradle BOM support instead of Spring Boot Dependency Management Plugin
For example:
plugins {
id 'java'
id 'org.springframework.boot' version '2.1.0.RELEASE'
}
repositories {
jcenter()
}
dependencies {
implementation platform('org.springframework.boot:spring-boot-dependencies:2.1.0.RELEASE')
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-security'
}
and for multi-module project:
in root build.gradle :
plugins {
id 'java-library'
id 'org.springframework.boot' version '2.1.0.RELEASE'
}
allprojects {
apply plugin: 'java-library'
repositories {
jcenter()
}
}
dependencies {
implementation project(':core')
implementation 'org.springframework.boot:spring-boot-starter-web'
}
and in core/build.gradle
dependencies {
api platform('org.springframework.boot:spring-boot-dependencies:2.1.0.RELEASE')
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

Resources