Gradle Spring Boot Devtools: developmentOnly and runtimeClasspath - java

I am puzzled by this block of code to be used in a gradle file, suggested by Spring Boot Documentation on Developer Tools
configurations {
developmentOnly
runtimeClasspath {
extendsFrom developmentOnly
}
}
dependencies {
developmentOnly("org.springframework.boot:spring-boot-devtools")
}
I think I must declare the developmentOnly configuration because it is to be used in the dependencies {} block, but why do I need the lines for runtimeClasspath? I actually tried removing the lines in my project and the project built prefectly fine.
configurations {
developmentOnly
}
dependencies {
developmentOnly("org.springframework.boot:spring-boot-devtools")
}
Is runtimeClasspath used by the Java Plugin? (As suggested by this doc) Will there be any bad side-effect if I do not include those lines for runtimeClasspath?
Update (2019-12-10)
I can also confirm that the built executable jar built without the runtimeClasspath directive ran prefectly okay. So I really don't know what that directive is doing.

You need spring-boot-devtools only at runtime, that's why we're using runtimeClasspath config.
more details: https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_configurations_graph

The developmentOnly is a new configuration that you add.
The runtimeClasspath configuration is added by the Java Library Plugin.
You specify that the runtimeClasspath configuration extend from your developmentOnly configuration.
You set spring-boot-devtools as a dependency for your developmentOnly configuration, which will make the runtimeClasspath depend on spring-boot-devtools too.
I actually tried removing the lines in my project and the project built prefectly fine.
I think this is because the dependency is for run time, not for build time.
I can also confirm that the built executable jar built without the runtimeClasspath directive ran prefectly okay.
I think this is because spring-boot-devtools only works on development mode, e.g. when you execute the bootRun task with ./gradlew bootRun.

Related

How to add Lombok to a Gradle Java Library project?

I tried this:
plugins {
// Apply the java-library plugin to add support for Java Library
id 'java-library'
id 'io.freefair.lombok' version '3.8.4'
}
But I'm getting this error:
Unable to load class 'org.gradle.api.plugins.quality.FindBugsPlugin'.
This is an unexpected error. Please file a bug containing the idea.log file.
Lombok is available in maven central, so telling Gradle to download
lombok is easy.
The Lombok Gradle Plugin There is a plugin for gradle that we recommend you use; it makes deployment a breeze, and makes it easy to
do additional tasks, such as delomboking. The plugin is open source.
Read more about the gradle-lombok plugin.
Gradle without a plugin If you don't want to use the plugin, gradle has the built-in compileOnly scope, which can be used to tell
gradle to add lombok only during compilation. Your build.gradle will
look like:
repositories {
mavenCentral()
}
dependencies {
compileOnly 'org.projectlombok:lombok:1.18.16'
annotationProcessor 'org.projectlombok:lombok:1.18.16'
testCompileOnly 'org.projectlombok:lombok:1.18.16'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.16'
}
Remember that you still have to download lombok.jar (or find it in
gradle's caches) and run it as a jarfile, if you wish to program in
eclipse. The plugin makes that part easier.
Official site lombok -> https://projectlombok.org/setup/gradle

Spring development on Docker

I'm quite new to Java and Spring. I'm looking for a containerized solution that watches the src folder, rebuilds the project and takes advantage of Spring devtools hotswap to reload the changed classes.
I searched, but I just keep finding about production-ready containers, with separated steps for build and run. I tried to use 2 different containers, one with Gradle that keeps building (gradle build --continuous) and one that executes the built result:
version: '3.7'
services:
builder:
image: gradle:jdk11
working_dir: /home/gradle/project
volumes:
- ./:/home/gradle/project
command: gradle build --continuous
api:
image: openjdk:11-slim
volumes:
- ./build/classes:/app
command: java -classpath /app/java/main com.example.Application
It fails because Java doesn't find the dependencies (Spring, devtools, h2, etc.) inside the api container, and I don't know how to ask Gradle to include the external jars in the build folder. I want to do something like this, except that the example is outdated.
Still, I keep thinking that there might be a more elegant, simpler solution. It doesn't have to be with Gradle, it can be Maven if it works! :)
I know that many IDE have support for automatic builds and devtools, I just want to achieve it on Docker. This way, I would have a development workflow that is on repository, instead of on IDE's configuration, and virtually compatible with any dev environment. Is it a bad idea?
At last, I've found a solution that works quite well, with just one caveat.
This is of course a development environment, meant to quickly change files, automatically build and refresh the Spring application. It is not for production.
The build process is delegated to a Gradle container that watches for changes. Since Gradle has Incremental Compilation, it should scale well even for big projects.
The application itself is executed on a openjdk:11-slim. Since it runs the .class files, SpringBoot gets that it's dev-env and activates its devtools.
Here's my docker-compose.yml:
version: '3.7'
services:
builder:
image: gradle:jdk11
working_dir: /home/gradle/project
volumes:
- ./build:/home/gradle/project/build
- ./src:/home/gradle/project/src
- ./build.gradle:/home/gradle/project/build.gradle
command: gradle build --continuous -x test -x testClasses
api:
image: openjdk:13-alpine
volumes:
- ./build:/app
depends_on:
- builder
command: java -cp "/app/classes/java/main:/app/dependencies/*:/app/resources/main" com.example.Application
And here's my build.gradle:
plugins {
id 'org.springframework.boot' version '2.2.1.RELEASE'
id 'io.spring.dependency-management' version '1.0.8.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.1.0-SNAPSHOT'
sourceCompatibility = '11'
configurations {
developmentOnly
runtimeClasspath {
extendsFrom developmentOnly
}
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
task copyLibs(type: Copy) {
from configurations.runtimeClasspath
into "${buildDir}/dependencies"
}
build.dependsOn(copyLibs)
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'com.h2database:h2'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
annotationProcessor 'org.projectlombok:lombok'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
test {
useJUnitPlatform()
}
All in all, it takes 5s for the whole thing to rebuild and hot-swap a change in the source code. Not webpack-like quick, but still acceptable. And the biggest advantage of having it this way is that it resides on code, and everyone can get it working, regardless of their workstation.
The caveat? On the first run, the build folder is empty and the api container fails to start. You have to wait for builder to complete its work, and then restart api.
I'm still hoping for a better solution, and I encourage you to post everything that works smoother than this.

Is there a way for Gradle to resolve dependencies using curl command? [duplicate]

I have tried to add my local .jar file dependency to my build.gradle file:
apply plugin: 'java'
sourceSets {
main {
java {
srcDir 'src/model'
}
}
}
dependencies {
runtime files('libs/mnist-tools.jar', 'libs/gson-2.2.4.jar')
runtime fileTree(dir: 'libs', include: '*.jar')
}
And you can see that I added the .jar files into the referencedLibraries folder here: https://github.com/WalnutiQ/wAlnut/tree/version-2.3.1/referencedLibraries
But the problem is that when I run the command: gradle build on the command line I get the following error:
error: package com.google.gson does not exist
import com.google.gson.Gson;
Here is my entire repo: https://github.com/WalnutiQ/wAlnut/tree/version-2.3.1
According to the documentation, use a relative path for a local jar dependency as follows.
Groovy syntax:
dependencies {
implementation files('libs/something_local.jar')
}
Kotlin syntax:
dependencies {
implementation(files("libs/something_local.jar"))
}
If you really need to take that .jar from a local directory,
Add next to your module gradle (Not the app gradle file):
repositories {
flatDir {
dirs("libs")
}
}
dependencies {
implementation("gson-2.2.4")
}
However, being a standard .jar in an actual maven repository, why don't you try this?
repositories {
mavenCentral()
}
dependencies {
implementation("com.google.code.gson:gson:2.2.4")
}
You could also do this which would include all JARs in the local repository. This way you wouldn't have to specify it every time.
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}
The following works for me:
compile fileTree(dir: 'libs', include: '*.jar')
Refer to the Gradle Documentation.
You can try reusing your local Maven repository for Gradle:
Install the jar into your local Maven repository:
mvn install:install-file -Dfile=utility.jar -DgroupId=com.company -DartifactId=utility -Dversion=0.0.1 -Dpackaging=jar
Check that you have the jar installed into your ~/.m2/ local Maven repository
Enable your local Maven repository in your build.gradle file:
repositories {
mavenCentral()
mavenLocal()
}
dependencies {
implementation ("com.company:utility:0.0.1")
}
Now you should have the jar enabled for implementation in your project
A solution for those using Kotlin DSL
The solutions added so far are great for the OP, but can't be used with Kotlin DSL without first translating them. Here's an example of how I added a local .JAR to my build using Kotlin DSL:
dependencies {
compile(files("/path/to/file.jar"))
testCompile(files("/path/to/file.jar"))
testCompile("junit", "junit", "4.12")
}
Remember that if you're using Windows, your backslashes will have to be escaped:
...
compile(files("C:\\path\\to\\file.jar"))
...
And also remember that quotation marks have to be double quotes, not single quotes.
Edit for 2020:
Gradle updates have deprecated compile and testCompile in favor of implementation and testImplementation. So the above dependency block would look like this for current Gradle versions:
dependencies {
implementation(files("/path/to/file.jar"))
testImplementation(files("/path/to/file.jar"))
testImplementation("junit", "junit", "4.12")
}
The accepted answer is good, however, I would have needed various library configurations within my multi-project Gradle build to use the same 3rd-party Java library.
Adding '$rootProject.projectDir' to the 'dir' path element within my 'allprojects' closure meant each sub-project referenced the same 'libs' directory, and not a version local to that sub-project:
//gradle.build snippet
allprojects {
...
repositories {
//All sub-projects will now refer to the same 'libs' directory
flatDir {
dirs "$rootProject.projectDir/libs"
}
mavenCentral()
}
...
}
EDIT by Quizzie: changed "${rootProject.projectDir}" to "$rootProject.projectDir" (works in the newest Gradle version).
Shorter version:
dependencies {
implementation fileTree('lib')
}
The Question already has been answered in detail. I still want to add something that seems very surprising to me:
The "gradle dependencies" task does not list any file dependencies. Even though you might think so, as they have been specified in the "dependencies" block after all..
So don't rely on the output of this to check whether your referenced local lib files are working correctly.
A simple way to do this is
compile fileTree(include: ['*.jar'], dir: 'libs')
it will compile all the .jar files in your libs directory in App.
Some more ways to add local library files using Kotlin DSL (build.gradle.kts):
implementation(
files(
"libs/library-1.jar",
"libs/library-2.jar",
"$rootDir/foo/my-other-library.jar"
)
)
implementation(
fileTree("libs/") {
// You can add as many include or exclude calls as you want
include("*.jar")
include("another-library.aar") // Some Android libraries are in AAR format
exclude("bad-library.jar")
}
)
implementation(
fileTree(
"dir" to "libs/",
// Here, instead of repeating include or exclude, assign a list of paths
"include" to "*.jar",
"exclude" to listOf("bad-library-1.jar", "bad-library-2.jar")
)
)
The above code assumes that the library files are in libs/ directory of the module (by module I mean the directory where this build.gradle.kts is located).
You can use Ant patterns in includes and excludes as shown above.
See Gradle documentations for more information about file dependencies.
Thanks to this post for providing a helpful answer.
I couldn't get the suggestion above at https://stackoverflow.com/a/20956456/1019307 to work. This worked for me though. For a file secondstring-20030401.jar that I stored in a libs/ directory in the root of the project:
repositories {
mavenCentral()
// Not everything is available in a Maven/Gradle repository. Use a local 'libs/' directory for these.
flatDir {
dirs 'libs'
}
}
...
compile name: 'secondstring-20030401'
The best way to do it is to add this in your build.gradle file and hit the sync option
dependency{
compile files('path.jar')
}
The solution which worked for me is the usage of fileTree in build.gradle file.
Keep the .jar which need to add as dependency in libs folder. The give the below code in dependenices block in build.gradle:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}
You can add jar doing:
For gradle just put following code in build.gradle:
dependencies {
...
compile fileTree(dir: 'lib', includes: ['suitetalk-*0.jar'])
...
}
and for maven just follow steps:
For Intellij:
File->project structure->modules->dependency tab-> click on + sign-> jar and dependency->select jars you want to import-> ok-> apply(if visible)->ok
Remember that if you got any java.lang.NoClassDefFoundError: Could not initialize class exception at runtime this means that dependencies in jar not installed for that you have to add all dependecies in parent project.
For Gradle version 7.4 with Groovy build file
repositories {
flatDir {
dirs 'libs'
}
}
dependencies {
implementation ':gson-2.2.4'
}
If you are on gradle 4.10 or newer:
implementation fileTree(dir: 'libs', includes: ['*.jar'])
Goto File -> Project Structure -> Modules -> app -> Dependencies Tab -> Click on +(button) -> Select File Dependency - > Select jar file in the lib folder
This steps will automatically add your dependency to gralde
Very Simple
Be careful if you are using continuous integration, you must add your libraries in the same path on your build server.
For this reason, I'd rather add jar to the local repository and, of course, do the same on the build server.
An other way:
Add library in the tree view. Right click on this one. Select menu "Add As Library".
A dialog appear, let you select module. OK and it's done.

Java Spring workflow

I've been working with Rails, PHP and Node.js and used to auto reloading after code changes.
Now I'm trying Java and came to two commands:
gradle build --continuous
gradle bootRun
But I see changes only after I restart gradle bootRun
Is it possible to rebuild and rerun spring after each code change?
Spring developer tools will handle this for you. Just add following dependency in your Gradle build file.
configurations {
developmentOnly
runtimeClasspath {
extendsFrom developmentOnly
}
}
dependencies {
developmentOnly("org.springframework.boot:spring-boot-devtools")
}
For more details refer: https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-devtools.html

Gradle seems to ignore project dependencies

We have a multi-project build with a intra-project dependencies between the 'included' projects in the settings.gradle. There are a number of interdependencies between the various projects expressed as project dependencies included in the moderately sized list of the project's dependencies.
While this approach works fine in several other multi-project builds, in this particular project, the project dependencies are not being honored, therefore sub projects are being built in the wrong order and the build fails.
So, for starters, how do we diagnose what's going on here in order to determine if it is a bug?
We're running:
Gradle (Wrapper) Version: 3.1
Operating System: Windows 8.1 6.3 amd64
JDK: Oracle 1.8.0_65
So - we eventually determined that the problem was this - there was code in a configurations.all block that was setting the useVersion on various dependencies. If one of these dependencies happened to be a project dependency, the project dependency piece is broken.
It's hard to answer without seeing the relevant snippets of build.gradle and also an overview of how the offending projects include one another. Here's a couple of likely candidates
Sometimes the evaluation of one project is dependent upon the evaluation of another, in these cases you can use evaluationDependsOn
project(':projectA') {
evaluationDependsOn(':projectB')
}
project(':projectB') {
project(':projectA').tasks.create(...)
}
In cases where there's a circular reference between project dependencies you might be able to break the loop by adding extra configuration(s)
project(':projectA') {
configurations {
base
compile.extendsFrom base
}
dependencies {
base 'aaa:bbb:1.0'
compile project(path: ':projectB', configuration: 'base')
}
}
project(':projectB') {
configurations {
base
compile.extendsFrom base
}
dependencies {
base 'ccc:ddd:1.0'
compile project(path: ':projectA', configuration: 'base')
}
}

Categories

Resources