Gradle implementation project throws exception - gradle

I have this hierarchy to my project:
- project
- project-server
- build.gradle
- gradle.properties
- settings.gradle
- project-client
- build.gradle
- gradle.properties
- settings.gradle
- build.gradle
- gradle.properties
- settings.gradle
In the parent build.gradle file I added these lines:
project(':project-client') {
dependencies {
implementation project(':project-server')
}
}
and I am getting:
What went wrong: A problem occurred evaluating root project 'project'.
Could not find method implementation() for arguments [project ':project-client'] on object of type
org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.
This is my entire build.gradle:
apply plugin: 'java'
println(subprojects.each {it -> it.name})
project(':project-client') {
dependencies {
implementation project(':project-server')
}
}
allprojects {
group = 'com.test'
repositories {
mavenLocal()
maven {
//local nexus config
}
mavenCentral()
jcenter()
}
}
subprojects {
version = {version}
}
This is the setting.gradle:
rootProject.name = 'project'
include 'project-server', 'project-client'
Please help, thanks in advance.

implementation configuration is added by the java plugin.
You've applied java plugin only for the root project, in the provided build.gradle. Your :project-client subproject does not inherit plugins from it's parent (root), so the java plugin was not applied to :project-client project.
That's why it "could not find method implementation() for arguments...". Make sure to apply java plugin to subprojects.

Related

Gradle plugin that loads org.springframework.boot into projects

I'm writing a custom gradle plugin Foo and I want to load the org.springframework.boot plugin
into projects that apply the Foo plugin. I can load various other plugins this way, but this
particular plugin doesn't want to behave the same way.
Foo build.gradle
buildscript {
ext {
springBootVersion = "2.1.3.RELEASE"
}
}
apply plugin: "groovy"
repositories {
maven { url "http://custom.repo/blah" }
}
dependencies {
implementation gradleApi()
implementation localGroovy()
implementation("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
Foo plugin
class BuildPlugin implements Plugin<Project> {
#Override
void apply(Project project) {
project.repositories {
maven { url "http://custom.repo/blah" }
}
project.plugins.apply("org.springframework.boot")
}
}
Project build.gradle
buildscript {
dependencies {
classpath files("/some/cool/path/foo-plugin.jar")
}
}
apply plugin: "com.whatever.foo-id"
Project build output
$ ./gradlew --stacktrace clean build
FAILURE: Build failed with an exception.
* Where:
Build file '/cool/project/location/bar/build.gradle' line: 40
* What went wrong:
A problem occurred evaluating root project 'bar'.
> Failed to apply plugin [id 'com.whatever.foo-id']
> Plugin with id 'org.springframework.boot' not found.
Is it possible to apply a plugin 1 from plugin 2 where plugin 1 is a classpath dependency?
This isn't possible. The classpath is what pulls in the plugins, so it is impossible for them to modify the thing before they are pulled in.

How to avoid repeating dependency versions in a multi-module Gradle project?

There's a sample Spring Boot project here that contains two modules.
The build.gradle for one of the modules looks like this:
buildscript {
ext { springBootVersion = '2.1.4.RELEASE' }
repositories { mavenCentral() }
dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") }
}
plugins {
id "io.spring.dependency-management" version "1.0.5.RELEASE"
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
bootJar {
baseName = 'gs-multi-module-application'
version = '0.0.1-SNAPSHOT'
}
sourceCompatibility = 1.8
repositories { mavenCentral() }
dependencies {
compile('org.springframework.boot:spring-boot-starter-actuator')
compile('org.springframework.boot:spring-boot-starter-web')
compile project(':library')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
The other module's build.gradle looks like this:
buildscript {
repositories { mavenCentral() }
}
plugins { id "io.spring.dependency-management" version "1.0.5.RELEASE" }
ext { springBootVersion = '2.1.4.RELEASE' }
apply plugin: 'java'
apply plugin: 'eclipse'
jar {
baseName = 'gs-multi-module-library'
version = '0.0.1-SNAPSHOT'
}
sourceCompatibility = 1.8
repositories { mavenCentral() }
dependencies {
compile('org.springframework.boot:spring-boot-starter')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
dependencyManagement {
imports { mavenBom("org.springframework.boot:spring-boot-dependencies:${springBootVersion}") }
}
The springBootVersion = '2.1.4.RELEASE' is declared in both modules. For a 2 module project that might not be a problem, but if my project had 10 modules and I wanted to make sure that all modules always depend on the same version of Spring Boot, it would be inconvenient and error-prone to repeat this version in every module.
Similarly, I might want to add a dependency on commons-io to both of these modules, and ensure they both always depend on the same version of commons-io.
How can I avoid repeating the version numbers in each and every build.gradle file?
See this Gradle documentation : a good practice in Gradle is to configure subprojects which share common traits in a single place, for example in the root project's build script (or using custom plugins)
EDIT the solution proposed here is no longer considered as good practice from Gradle team (the link above does not even mention subproject bloc in latests Gradle version doc); thank you #buggy for the warning .
In your example taken from Spring boot documentation, this pattern could be applied to centralize Spring boot and other common dependencies versions in a single place, but you could go further and also configure other common traits (Java plugin configuration, repositoties, etc..)
Here is how I would re-write the Spring example to make it cleaner and DRY:
Root project
/**
* Add Springboot plugin into build script classpath (without applying it)
* This is this only place where you need to define the Springboot version.
*
* See https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/html/#managing-dependencies-using-in-isolation
*/
plugins {
id "org.springframework.boot" version "2.1.4.RELEASE" apply false
}
// Set version for dependencies share between subprojects
ext {
commonsIoVersion = "2.6"
}
subprojects {
// common config for all Java subprojects
apply plugin: "java"
apply plugin: "eclipse"
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
// apply Spring Boot's dependency management plugin
apply plugin: "io.spring.dependency-management"
}
Library sub-project
// no need for additional plugins
jar {
baseName = 'gs-multi-module-library'
version = '0.0.1-SNAPSHOT'
}
dependencies {
implementation('org.springframework.boot:spring-boot-starter')
implementation "commons-io:commons-io:${commonsIoVersion}"
testCompile('org.springframework.boot:spring-boot-starter-test')
}
dependencyManagement {
imports {
mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES
}
}
Application sub-project
plugins {
id "org.springframework.boot"
}
bootJar {
baseName = 'gs-multi-module-application'
version = '0.0.1-SNAPSHOT'
}
dependencies {
implementation project(':library')
implementation ('org.springframework.boot:spring-boot-starter-actuator')
implementation ('org.springframework.boot:spring-boot-starter-web')
implementation "commons-io:commons-io:${commonsIoVersion}"
// could also be configured in root project.
testCompile('org.springframework.boot:spring-boot-starter-test')
}
Notes
this solution uses the new plugins {} DSL only (no need for old buildscript block)
version of the io.spring.dependency-management should not be configured explicitly, it will be inherit from Spring boot plugin
You can move the ext{} block to a new file and reference it in your project's build.gradle file via the apply from: statement.
// project/versions.gradle
ext {
springBootVersion = '2.1.4.RELEASE'
}
// project/build.gradle
buildscript {
apply from: 'versions.gradle'
}
// module/build.gradle
dependencies {
implementation "some.dependency:dependency:$springBootVersion"
}
Now you only have to define your dependency versions in one place.
Typically, a project will have a project-level build.gradle file in addition to module-specific build.gradle files. However, the repo you shared is missing the project-level build script. This is why the ext{} block is defined in each module's build script. This is likely not optimal, and I recommend looking at other repos to see how different developers tackled this issue.
There's a Gradle consistent versions plugin that will handle this:
https://github.com/palantir/gradle-consistent-versions
After you set this plugin up in the root build.gradle file, you will create a versions.props file like this, to use the example from the documentation.
com.fasterxml.jackson.*:jackson-* = 2.9.6
com.google.guava:guava = 21.0
com.squareup.okhttp3:okhttp = 3.12.0
junit:junit = 4.12
org.assertj:* = 3.10.0
There's also a versions.locks file, which is auto-generated by ./gradlew --write-locks. You can then specify version-less dependencies in your build.gradle files.

How to avoid duplication of children repositories in a parent project

I have a multi-project build with the following structure:
Root project 'just-another-root-project'
+--- Project ':producer'
\--- Project ':consumer'
The root settings.gradle file:
rootProject.name = 'just-another-root-project'
include 'consumer', 'producer'
...connects created modules.
The producer.gradle file:
plugins {
id 'java-library'
}
group 'com.github.yarbshk.jarp'
version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
maven {
url 'http://maven.nuiton.org/release/'
}
}
dependencies {
implementation 'com.sun:tools:1.7.0.13'
}
...has an external dependency (com.sun.tools) that is not published in Maven Central therefore I've added a link to the Nuiton repository.
The consumer.gradle file:
plugins {
id 'java'
}
group 'com.github.yarbshk.jarp'
version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
annotationProcessor project(':producer')
}
The build described above is not working! To make it so I was enforced to duplicate all repositories from producer.gradle into consumer.gradle. So the question is how to build the root project without the excessive dependency duplication? How to do it in the right way? Thanks for any answer or hint :)
UPDATE 1:
I get the following error when try to build the project with files shown above:
FAILURE: Build failed with an exception.
* What went wrong:
Could not resolve all files for configuration ':consumer:compile'.
> Could not find com.sun:tools:1.7.0.13.
Searched in the following locations:
https://repo.maven.apache.org/maven2/com/sun/tools/1.7.0.13/tools-1.7.0.13.pom
https://repo.maven.apache.org/maven2/com/sun/tools/1.7.0.13/tools-1.7.0.13.jar
Required by:
project :consumer > project :producer
You can configure repositories directly in the root project like that:
root project build.gradle:
// configure repositories for all projects
allprojects {
repositories {
mavenCentral()
maven {
url 'http://maven.nuiton.org/release/'
}
}
}
EDIT (from you comment on other response)
You can also define only mavenCentral() repository on root project level (it will be added to repositories for all projects) and configure http://maven.nuiton.org/release repository only for producer subproject :
root project
repositories {
// will apply to all project
mavenCentral()
}
producer project
repositories {
maven {
url 'http://maven.nuiton.org/release/'
}
// mavenCentral inherited from root project
}
consumer project
// no need to re-define repositories here.
There is a section in an official gradle tutorial dedicated to this:
https://guides.gradle.org/creating-multi-project-builds/#configure_from_above
The root project can configure all projects:
allprojects {
repositories {
jcenter()
}
}

Unexprected behaviour making EAR for multiple spring boot war's returns a 1k EAR

I need to pack all microservices made with Spring Boot into one big EAR.
The project is organized like this:
/root
build.gradle
settings.gradle
/project1
build.gradle
...
/project3
build.gradle
...
/project3
build.gradle
...
The root settings.gradle contains:
rootProject.name = "mysystem"
include("project1")
include("project2")
include("project3")
The build.gradle in root contains
apply plugin: 'ear'
allprojects {
group = 'de.example'
}
dependencies {
deploy project(path:':project1', configuration:'archives')
deploy project(path:':project2', configuration:'archives')
deploy project(path:':project3', configuration:'archives')
}
ear {
deploymentDescriptor {
applicationName = "myproject"
initializeInOrder = true
displayName = "My Project"
description = "My Project EAR"
}
}
The project build.gradle looks like
buildscript {
ext {
springBootVersion = '2.0.2.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
defaultTasks 'bootWar'
repositories {
mavenCentral()
// Maven Spring Repository for Milestone Releases (optional for development but don't use it in Production)
maven { url 'https://repo.spring.io/libs-milestone-local' }
// Maven Spring Repository for Stable Releases
maven { url 'https://repo.spring.io/libs-release-local' }
}
dependencyManagement {
imports {
mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Finchley.RELEASE'
}
}
dependencies {
compile("org.springframework.boot:spring-boot-starter") {
}
compile('org.springframework.boot:spring-boot-starter-json')
compile("org.springframework.boot:spring-boot-starter-web") {
}
providedCompile('org.springframework.boot:spring-boot-starter-tomcat')
}
When I run gradle bootWar per project it generates the WAR in build/lib per project.
But when I run gradle ear in the root project, the output is like this:
Working Directory: D:\Workspace\root
Gradle User Home: D:\Workspace\.gradle
Gradle Distribution: Gradle wrapper from target build
Gradle Version: 4.3
Java Home: C:\Programme\Java\jdk8
JVM Arguments: None
Program Arguments: None
Build Scans Enabled: false
Offline Mode Enabled: false
Gradle Tasks: ear
Parallel execution with configuration on demand is an incubating feature.
:project1:compileJava
:project2:compileJava
:project3:compileJava
:project1:processResources
:project1:classes
:project1:war SKIPPED
:project2:processResources
:project2:classes
:project2:war SKIPPED
:project3:processResources
:project3:classes
:project3:war SKIPPED
:ear
BUILD SUCCESSFUL in 2s
7 actionable tasks: 7 executed
The result is an EAR with 1k size. There is no WAR generated per project. When I run gradle bootWar on every project and then run gradle ear, it works and the resulting EAR has 130Mb and includes all WARs.
Is there a way, that I only need to run gradle ear and it generates the WARs from bootWar?
In a gradle Spring Boot project the "war" task is disabled in lieu of the "bootWar" task.
Setup the "ear" task in the parent build.gradle to depend on the "bootWar" task(s).
ear {
dependsOn ':project1:bootWar'
}

Create external dependencies and add it to other project with gradle

I have two spring boot projet
A and B
would like to create a new projet to put common thing there
A
B
commons
how to add commons to A and B like a external dependencies?
Assume your project layout as below:
project
|- common
|- proja
|- projb
you need settings.gradle
rootProject.name = 'project'
include 'common'
include 'proja'
include 'projb'
then you need to update your build.gradle under project like this:
plugins {
id 'org.springframework.boot' version '1.5.4.RELEASE'
}
subprojects { // common configurations for all subprojects
apply plugin: 'groovy'
apply plugin: 'org.springframework.boot'
repositories {
jcenter()
}
dependencies { // common dependencies for all subprojects
compile 'org.codehaus.groovy:groovy-all:2.4.10'
testCompile 'org.springframework.boot:spring-boot-starter-test'
testCompile 'org.spockframework:spock-spring:1.0-groovy-2.4'
}
}
project ("proja") {
dependencies { // proja-specific dependencies
compile 'com.google.guava:guava:21.0'
compile project(":common")
}
}
project ("projb") {
dependencies { // projb-specific dependencies
compile project(":common")
}
}
Let me know if this works.
external solution seem the way to go
my commons build.gradle file
apply plugin: 'java-library-distribution'
repositories {
mavenCentral()
maven { url "https://repo.spring.io/snapshot" }
maven { url "https://repo.spring.io/milestone" }
}
dependencies {
compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa', version: '2.0.0.M2'
}
distributions {
main{
baseName = 'commons-code'
}
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
tasks.withType(JavaCompile) {
options.compilerArgs = ["-Xlint:unchecked", "-Xlint:deprecation", "-parameters"]
}
In my main project
i have an build.gradle
in the dependencies section i have
compile project (':commons-code')
and in the settings.gradle file i have
include ":commons-code"
project(":commons-code").projectDir = file("/home/bob/dev/project/commons/")

Resources