Java Spring workflow - java

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

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

Gradle Spring Boot Devtools: developmentOnly and runtimeClasspath

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.

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.

The best way to use conditionally dependencies in Gradle for Jenkins

Info: Using Gradle 2.14 on Windows 7 to build JAVA multi-projects.
When I'm building on my machine i want to use the libraries/subprojects on my machine.
When Jenkins is building the project, he shall use the libraries/subprojects from my repo.
So I made a "JenkinsTask" that just exist for my IF statement. This is already almost working the way I want it. Here the code from my root project gradle script:
task JenkinsTask() {
//doing nothing
}
def ProjectB_Version //defined on command line
gradle.taskGraph.whenReady {taskGraph ->
if (taskGraph.hasTask(JenkinsTask)) {
println "Archiva dependency"
dependencies {
compile group: 'Lib_ProjectB', name: 'ProjectB', version: ProjectB_Version
}
}
else {
println "Filesystem dependency"
dependencies {
compile fileTree(dir: 'ProjectB\\build\\libs', includes: ['*.jar'])
}
}
}
compileJava.dependsOn ":ProjectB:build"
On my machine I just run gradle build -PProjectB_Version=0.5
On Jenkins I run gradle :build jenkinstask -x :ProjectB:build -PProjectB_Version=0.5
Now the question is if there is a "gradle" way to do this? So I wouldn't need the if/else statement and maybe even could relinquish the "-x" paramater Jenkins command line. Especially the "Jenkinstask" feels like a hack.
Thank you in advance.
I'm not sure if it's considered as a gradle way, but I think you should declare dependencies in the same way regardless of who builds the project and where.
Instead I think you should:
define artifacts repositories depending on the build environment,
base decision on a command line argument instead of checking for a task in the task execution graph.
This way you will be able to have automatic pom generation for your project locally as well because for that gradle needs to know artifact group and name. And the build script would look cleaner in my opinion.
Just place something like this somewhere before all your tasks:
if (project.hasProperty('jenkins')) {
repositories {
maven {
url "${jenkinsRepoUrl}"
}
}
} else {
repositories {
mavenLocal()
mavenCentral()
}
}
dependencies {
compile (
['commons-lang:commons-lang:2.4'],
["Lib_ProjectB:ProjectB:${ProjectB_Version}"],
}
}
And run the build as gradle clean build -PProjectB_Version=0.5 locally and as gradle clean build -Pjenkins -PProjectB_Version=0.5 -PjenkinsRepoUrl=https://nexuscn.my-company.com/content/repositories/main on Jenkins.
P.S.: I would declare the ProjectB_Version property in project gradle.properties instead since your code is likely to depend on the actual version API.

How to export a Spring Boot project to an executable standalone file?

I have created a project in Spring Tool Suite with Spring Boot and Gradle, and I really don't know how to export to make it work.
I don't know much about gradle, just the basics to add dependencies from the maven repository. So in some articles says to apply the application plugin to do the task, but I don't know how to set up the configuration file and how to create the executable.
If anyone could write or link a step by step detailed explanation on how to do it, it would be very much appreciated.
This is my build.gradle file:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.3.1.RELEASE")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'spring-boot'
springBoot {
mainClass = "com.rodamientosbulnes.objetivosventa.Application"
executable = true
}
jar {
baseName = 'objetivosventa'
version = '0.1.0'
}
repositories {
mavenCentral()
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
dependencies {
compile('org.springframework.boot:spring-boot-starter')
compile('org.springframework:spring-jdbc')
compile('net.sourceforge.jtds:jtds:1.3.1')
compile('org.apache.poi:poi-ooxml:3.13')
compile('com.miglayout:miglayout-swing:4.2')
}
task wrapper(type: Wrapper) {
gradleVersion = '2.3'
}
Build file looks fine, you only need to run gradle build (or Run As -> Gradle -> Gradle build in the STS) to create the runnable jar.
More details about configuration of the gradle plugin are available on spring boot documentation site.
Gradle's application plugin doesn't make a single execitable for you, but it can create a distribution, which includes all the dependencies, jar-artifact for your project and 2 scripts to run it (one batch-file and linex executable).
The main thing you need to know, is that spring-boot plugin already provide all the task from application plugin you may need. All the task you can find here. You need distZip or installDist to package your project to the distribution. This task will create a ready project distribution under your project-folder/build folder. One more task you may find usefull is buildRun which will run you spring-boot application without package it into distribution.

Categories

Resources