How are some gradle dependencies working with no version supplied - gradle

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'
}

Related

Don't know how to include joinfaces into a multi module gradle build

An old application of mine is a Java 8 Enterprise mololith and i want to migrate it.
I want to migrate it into a spring boot project including primefaces,
myfaces and omnifaces by using joinfaces and split it into smaller parts (multi-modules-project)
for better maintainance.
So i split the project into the following modules to became an working prototype:
Short description of the modules:
Common / ComDb : Here are only generated JPA entities / classed directly from the database which classes can be used by all modules
Libraries / LibPrimeFaces : Here are only the latest primefaces elite JAR's which should be used in SpringBoot
Libraries / LibPrimeFacesTheme : Here are a buyed primefaces theme which will be bundeled and included by a generated JAR.
Services / * : Each spring boot service which should be used is located here, so it can be used in the main application or from an external service over REST
Application : Here is the spring boot application which should include all of the things above - even a runnable jar-file at last
The problem now for me is the usage of gradle which is completly new for me:
I dont't know how to integrate joinfaces in combination with my buyed primefaces-8.0.5.jar from elite subscription, omnifaces 3 and myfaces by using gradle.
The most manuals are for maven, but it seems that they are not working for gradle if i
convert the scripts.
Currently the whole project compiles and start without any errors but now i am at the point where i can't find a working example of using joinfaces and gradle in a multi module environment like mine.
Here are the main gradle-scripts:
The root-scripts:
gradle.properties (Holding the versions):
VersionSpringBoot=2.3.5.RELEASE
VersionSpringDependencyManagement=1.0.10.RELEASE
VersionPrimeFaces=8.0.5
settings.gradle (includes and names):
rootProject.name = 'EcoCalcDD4Web'
include 'Common:ComDb'
include 'Libraries:LibPrimeFaces'
include 'Services:ServiceConfigWebManagement'
include 'Application'
build.gradle (Main build file):
buildscript {
repositories {
mavenCentral()
maven {
url './Libraries/LibPrimeFaces'
}
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${VersionSpringBoot}")
}
}
allprojects {
group = 'com.skf.rocket'
version = '1.0.0'
repositories {
mavenCentral()
maven {
url './Libraries/LibPrimeFaces'
}
}
}
subprojects {
apply plugin: 'java-library'
apply plugin: 'io.spring.dependency-management'
repositories {
mavenCentral()
maven {
url './Libraries/LibPrimeFaces'
}
}
dependencyManagement {
imports {
mavenBom("org.springframework.boot:spring-boot-dependencies:${VersionSpringBoot}")
}
}
dependencies {
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
}
And here the application build.gradle - file where JoinFaces should be used with my primefaces, omnifaces and myfaces.
Here i don't know what to add to get all started with joinfaces:
apply plugin: 'org.springframework.boot'
bootJar {
mainClassName = "com.skf.rocket.EcoCalcDd4WebRocket"
}
// Maven dependencies
dependencies {
// Internal dependencies
api project(':Common:ComDb')
// Implementation project('Libraries:LibPrimeFacesTheme')
api project(':Services:ServiceConfigWebManagement')
// External dependencies
// JoinFaces + MyFaces + PrimeFaces - TODO ??
// Development tools with HotReDeploy
developmentOnly 'org.springframework.boot:spring-boot-devtools'
// Automatically configuration
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
// Lombok - Utility
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
// Global cache
implementation 'org.springframework.boot:spring-boot-starter-cache'
// Data access + MS SQL driver
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly 'com.microsoft.sqlserver:mssql-jdbc'
// Data validation
implementation 'org.springframework.boot:spring-boot-starter-validation'
// Web + RestService
implementation 'org.springframework.boot:spring-boot-starter-web'
// Session management
implementation 'org.springframework.session:spring-session-core'
// Boot Acturator - Application monitoring and alive checks
compile group: 'org.springframework.boot', name: 'spring-boot-starter-actuator'
// Unit test
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
test {
useJUnitPlatform()
}
At first, you should have a look at these resources:
https://docs.gradle.org/current/userguide/intro_multi_project_builds.html
https://docs.gradle.org/current/userguide/declaring_repositories.html#sub:flat_dir_resolver
https://docs.joinfaces.org/4.3.4/reference/#_gradle
https://docs.joinfaces.org/4.3.4/reference/#_example_using_myfaces_instead_of_mojarra
https://github.com/joinfaces/joinfaces-gradle-jar-example
To get started with JoinFaces, you need a dependency on org.joinfaces:jsf-spring-boot-starter.
Because you want to use MyFaces instead of Mojarra, you have to exclude it and pull MyFaces instead.
I'd start with these dependencies:
implementation ("org.joinfaces:jsf-spring-boot-starter") {
exclude module: "mojarra-spring-boot-starter"
}
implementation "org.joinfaces:myfaces-spring-boot-starter"
implementation "org.joinfaces:omnifaces1-spring-boot-starter"

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 'Implementation' Dependencies Are Runtime-Scoped When Project Has No Classes Of Its Own

I've got a Gradle multi-project build for a custom Spring Boot Starter. Following Spring Boot Starter convention, my classes are all in an 'autoconfiguration' project, and I have a separate 'starter' project that ONLY brings in the dependencies needed to use the autoconfiguration.
The multi-project build produces 2 non-runnable jars, 1 for the autoconfiguration sub-project, and one for the starter sub-project. My new project that is using this starter pulls in the starter jar, but when I go to use classes that are from transitive dependencies, my project can't find them anywhere on the classpath.
When I dug into the starter jar, I found that all the dependencies it defines are RUNTIME scoped, which would explain the problem. I can 'fix' the problem by setting all the dependencies in my starter as 'compile' instead of 'implementation', but it's my understanding that 'compile' is on its way out, and that 'implementation' dependencies should be compile-scoped anyway. Can someone tell me what additional config may be necessary to define the starter dependencies as 'implementation' without them being scoped as 'runtime' in the resulting jar?
My starter/autoconfigure multi-project root gradle file:
plugins {
id 'org.springframework.boot' version '2.1.4.RELEASE' apply false
id 'io.spring.dependency-management' version '1.0.7.RELEASE' apply false
}
wrapper {
gradleVersion = '5.2.1'
}
repositories {
mavenLocal()
// private repo info omitted
mavenCentral()
jcenter()
}
subprojects {
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'maven-publish'
apply plugin: 'java-library'
group = 'com.mystarter'
repositories {
mavenLocal()
// private repo info omitted
mavenCentral()
jcenter()
}
dependencies {
annotationProcessor "org.springframework.boot:spring-boot-autoconfigure-processor"
annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"
}
bootJar {
enabled = false
}
jar {
enabled = true
}
javadoc {
failOnError = false
options.addStringOption('Xdoclint:none', '-quiet')
}
task sourcesJar(type: Jar) {
from sourceSets.main.allJava
classifier = 'sources'
}
task javadocJar(type: Jar) {
from javadoc
classifier = 'javadoc'
}
publishing {
publications {
myProjStarterArtifacts(MavenPublication) {
from components.java
artifact sourcesJar
artifact javadocJar
}
}
repositories {
// private repo info omitted
}
}
tasks.build.finalizedBy tasks.publishToMavenLocal
}
My starter sub-project's build file:
dependencies {
compile project(':myproj-spring-boot-autoconfig')
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.security:spring-security-cas'
implementation 'org.springframework.security:spring-security-ldap'
}
If I change the above 'implementation' lines to be 'compile' lines, that's when the resulting pom file stops making these 4 dependencies 'runtime' scope and instead correctly scopes them as 'compile'. As a side note, the 'compile project' line works just fine, it's just the lines that are 'implementation' that don't seem to work the way I'd expect when the project has no classes of its own.
My new project's dependency for my starter:
dependencies {
implementation('com.myproj:myproj-spring-boot-starter:1.0.0')
// other dependencies
}
implementation dependencies defined in a Gradle project are only made transitive for the runtimeClasspath of the consumers of said project, that is by design.
If you have a project without code but only defining dependencies, consider using the java-platform plugin for it, which allows you to specify constraints and optionally dependencies.
Otherwise, if you want the project to expose its dependencies to consumers at compilation time, you should use the api configuration for declaring them instead of compile which is indeed on its way out.
For more details, see documentation.

How to use spring boot in gradle without the spring boot gradle plugin

Can anyone show me or point me to a spring boot gradle project that does not make use of the spring boot gradle plugin.
I'm looking for something like a spring boot starter web hello world example that doesn't use the gradle plugin.
I can't imagine that the plugin is a requirement, but a search for examples all seem to lean on the gradle plugin, which lets just say is not an option in my environment, and no I can't switch to maven either.
Ideally the gradle build would work by adding something like the following:
gradle.properties
springBootVersion=2.1.3.RELEASE
build.gradle
dependencies {
compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: springBootVersion
}
I used the spring dependency management plugin, and it works
buildscript {
ext {
springDepManagementVersion = '1.0.10.RELEASE'
springBootVersion = '2.6.6'
springCloudVersion = "2021.0.1"
}
dependencies {
classpath "io.spring.gradle:dependency-management-plugin:${springDepManagementVersion}"
}
}
apply plugin: 'io.spring.dependency-management'
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
mavenBom "org.springframework.boot:spring-boot-dependencies:${springBootVersion}"
}
}
dependencies {
implementation "org.springframework.cloud:spring-cloud-starter-sleuth"
implementation 'org.springframework.boot:spring-boot-starter-json'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-mail'
implementation 'org.springframework.boot:spring-boot-starter-security'
...
}
I can't use spring boot gradle plugin, since I can only use gradle 6.7.1, while spring boot gradle plugin requires gradle version at least 6.8 to support spring boot 2.6. I was inspired by the spring cloud bom solution.

Building a Spring-boot project without eclipse gradle

I'm fairly new to gradle and writing a project that I have working in eclipse and was posed with the challenge to write it without eclipse using gradle. I'm finding that even once I add the spring framework configurations to my build file it still can not see what I am importing. I am also using maven so I think it my understanding of gradle changing from a maven project and with SQL. Any thoughts?
Here is my build.gradle:
plugins {
id "org.springframework.boot" version "1.5.9.RELEASE"
id "io.spring.dependency-management" version "1.0.4.RELEASE"
}
apply plugin: 'java'
repositories {
jcenter()
mavenCentral()
}
// spring dependency management plugin configuration
dependencyManagement {
imports {
// select versions based on this BOM
mavenBom 'io.spring.platform:platform-bom:1.1.1.RELEASE'
}
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-web')
compile("org.springframework:spring-jdbc")
compile('mysql:mysql-connector-java:5.1.37')
}
You need to add spring boot dependencies.
like:
dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
}
See the Spring documentation:
https://spring.io/guides/gs/spring-boot/#scratch

Resources