As we know org.springframework.boot support hot deploy to detect any changes
without restart application.
It works with maven when I run it with mvn spring-boot:run
but it does not work when I run it with gradle bootRun, it does not detect property file change automatically .
in my build.gradle i defined it already.
any hints will be more than welcome!
compile group: 'org.springframework.boot', name: 'spring-boot-devtools', version:'2.0.4.RELEASE'
You probably need to configure bootRun to load resources from src/main/resources rather than their built location beneath build. You can do so with the following configuration:
bootRun {
sourceResources sourceSets.main
}
Alternatively, you could use Gradle's continuous build support so that any changes in src/main/resources or src/main/java are automatically detected and then built. DevTools will then notice the changes in the build's output and reload.
Related
I'm creating a web project using Gradle (buildship) in Eclipse (WTP). I've put the libraries I need as "implementation" dependencies in my build.gradle, however they are not copied to Tomcat when I try to run the project from within Eclipse. When I build the WAR file (with gradle war), however, all the jar files are there.
I can't find anywhere the solution for this. It's beeing awful to manually (and redundantly) copying every jar and its dependency to WEB-INF/libs just to be able to run the app from Eclipse).
I've found a workaround here: https://github.com/eclipse/buildship/issues/496
It's adding this to build.gradle:
eclipse {
wtp {
component {
libConfigurations += [configurations.runtimeClasspath]
}
}
}
With this everything gets properly deployed.
UPDATE!
Gradle 5.3 has just been released and includes a fix for this issue and the hack above is not needed anymore.
The only thing that worked for me was changing
dependencies {
implementation group: 'org.projectlombok', name: 'lombok', version: '1.18.4'
}
too
dependencies {
compile group: 'org.projectlombok', name: 'lombok', version: '1.18.4'
}
Currently I have two projects with gradle build.gradle. The first is going to create a fat jar file, which I would like to include in a war file. I thought compiling it would be enough, but it doesn't seem to be ending up in the /lib directory of my war file. Anyone have thoughts I am quite new to gradle.
dependencies {
compile project(':JarProject')
providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
providedCompile 'org.apache.tomcat:tomcat-jsp-api:7.0.55'
}
war {
archiveName 'WarProject.war'
from 'JarProject/build/libs'
webXml = file('src/web.xml')
}
Does the second project war need to be in providedRuntime? Or should I publish the jar from the other project in the local maven repo and include it that way?
The War task essentially behaves like a CopyTask with regards to stuff it packs in the war, so the documentation on working with files is useful. In essence, I think you need something like (untested):
from fileTree('JarProject/build/libs') {
into("lib")
}
That being said, using mavenLocal() and publishing there also works, but it can lead to unexpected results when the war includes some old version from local, picking up the jar explicitly from the file system like above is better.
I think the elegant solution would be to use multi project builds and project level dependencies. You would have the two builds as separate projects of the same Gradle build and add the "jar project" as a regular compile dependency.
How have you declared the dependency? I assume you have a multi-project build with subprojects A and B, both using the War plugin. I made an experiment using Gradle 2.4 and if I declare B/build.gradle like this:
apply plugin: 'war'
dependencies {
compile project(':A')
}
then B.war contains WEB-INF/lib/A.jar. If you correctly follow conventions of Gradle War plugin (place web resources in A/src/main/webapp/ and code-related resources in A/src/main/resources/), then A.jar should contain what you want.
see this
It's configured the same here as it is everywhere else. In fact I use an import for configuring integration tests. I've done everything I can think of including a rename of local integration test tasks and configurations, including looking at the dependency tree, including running with --debug. Yet for some reason Gradle insists that the property integrationTest doesn't exist on the sourceSet for an inter-project dependency:
integrationTestCompile project(':components:things-components:abc-stuff').sourceSets.integrationTest.output
...now I'm not particularly fond of this syntax and I've already griped up a storm about inter-project test dependencies and how they should be in a test utility component. However, I'm doing it this way because this appears to be what IntelliJ will accept. Writing like this causes trouble:
integrationTestCompile project(path: ':components:things-components:abc-stuff', configuration: 'integrationTest')
How can I figure this out? I just don't get why only one project has this issue.
For the record, I've also tried:
integrationTestCompile project(path: ':components:things-components:abc-stuff', configuration: 'integrationTestCompile')
The issue is that Gradle hasn't been told to make a jar for you that you can consume in your other project.
integrationTestCompile project(':components:things-components:abc-stuff').sourceSets.integrationTest.output
Gets the classFiles and the dependencies, thats why its working using that notation. If you want to use the configuration notation you will need to tell gradle to publish a jar on the integrationTest. The jar doesn't have to be published to a repository, but will be used for the internal builds.
You can do this by doing:
configurations {
integrationTest
}
task integrationTestJar (type: Jar) {
baseName = "${project.name}-integ-test"
from sourceSets.integrationTest.output
}
artifacts {
integrationTest integrationTestJar
}
If you end up doing this in a log of projects, I would recommend writing a quick plugin that does this for you.
I'd like to use hot swap with my Spring Boot project. Somehow I am not able to make it working by running it in my IDE (IntelliJ), despite of having this topic covered by documentation. I simply run the class with my main method with VM attributes:
-javaagent:/path/to/jar/springloaded.jar -noverify
My question is, how do I make it work? :-)
Further question is how to use spring loaded with Gradle and IntelliJ. I find it quite inconvenient to force the developer to download the JAR manually, place it somewhere and point to it with a JVM parameter. Is there any better way (should I configure my own task which does the job and run it from my IDE as a Gradle task)?
You need to configure the project as stated in the documentation:
http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#howto-reload-springloaded-gradle-and-intellij-idea
After that, you must configure your IDE to output the compiled classes in build/classes/main (with Idea plugin, you can configure the outputDir as specified in the above link, and then invoke gradle idea to have it done).
Then, if you launch the task (run / bootRun) or run the main class from the IDE's using the debug mode, hot code reloading should work when a class is compiled.
The gotcha here is that IntelliJ, unlike Eclipse, doesn't automatically compile a class when it is saved (even if you configure the compiler to "Build on save", it won't do it when is Running/Debugging). This is apparently a design decission made by IntelliJ - as stated here Intellij IDEA Java classes not auto compiling on save (CrazyCoder answer) .
It would be ideal if spring boot provided a configuration option to monitor your source code files and recompile them when they change - that is what Grails does. But I think such a think does not exist yet, and maybe is not even possible to combine that with gradle, which is the responsible of managing the classpath and that kind of things.
So there are two options as far as I can tell:
You remember to compile everything you edit (adding an easier Compile shortcut as suggested in the previous StackOverflow link might help).
You put some filesystem monitor (inotify-tools for Linux, launchd for Mac OS X are examples) that invokes gradle compileJava/compileGroovy when a change is detected in any source code file.
First is tedious, second is slow :) . Actually there's another option: you change your IDE :-D (or install the EclipseMode IntelliJ plugin).
If one wants to be able to run the application solely from IntelliJ (using Right Click -> Debug on the main method) and not involve Spring Boot's Gradle tasks at all, you simply need to do the following:
Configure the run configuration in IntelliJ to use the SpringLoaded agent. This is easy to do and an example is shown in the following screenshot:
Notice how I have added a VM Option: -javaagent:/path/to/springloaded-${version}.jar -noverify (which you can download here)
Debug using Right Click -> Debug like the following screenshot:
Everytime you make a change and want to reload it, just compile the project. The default shortcut is Cntrl+F9, but you can also access it from the menu Build -> Make Project
I managed to do this with IDEA in a Maven project, it should work with the Gradle version as well I guess, my procedure was the following.
Settings -> Compiler -> Make project automatically (only works while not running/debugging !)
Start the project with the sprint-boot-plugin outside of the IDE (a trick because of the above sentence).
The Maven plugins setup looks like the following:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
<version>1.2.0.RELEASE</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
Now change some code and reload the page.
I'm running SpringBoot and Gradle in IntelliJ Idea. Auto-reloading is working 100%
Static Content is autoreloading (instantly)
Thymeleaf is autoreloading (instantly)
Controllers / Java Files require me to hit the "build" button (takes a few seconds), but does not require a restart - it's just to compile the files, so Spring Loaded can pick them up.
Step 1: Get SpringLoaded going
buildscript {
repositories {
mavenCentral()
jcenter()
}
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:1.2.1.RELEASE"
classpath 'org.springframework:springloaded:1.2.1.RELEASE'
}
}
apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'idea'
apply plugin: 'spring-boot'
repositories {
jcenter()
mavenLocal()
mavenCentral()
}
mainClassName = 'com.noxgroup.nitro.NitroApp'
idea {
module {
inheritOutputDirs = false
outputDir = file("$buildDir/classes/main/")
}
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-web:1.2.1.RELEASE")
compile("org.springframework.boot:spring-boot-starter-thymeleaf")
}
jar {
baseName = 'org.noxgroup-nitro'
version = '0.1.0'
}
task wrapper(type: Wrapper) {
gradleVersion = '1.11'
}
Step 2: Create an Application.properties
And add the following:
spring.thymeleaf.cache=false
Step 3: Run the bootRun task
(Not just the standard run task - this adds SpringLoaded functionality)
Step 4: Compile your Java
Make your Java files by hitting "Make Project" or pressing "Ctrl/Command + F9
In later versions of gradle you can start a command window and run
gradle -t classes
This will start a process that look for changes to source code and recompile them.
In another run.
gradle bootRun
Any changes to java or groovy src will automatically be recomplied. While not intellij specific, your good to go with intellij. You could even make do with you favorite text editor (e.g. submlime, atom ).
credits/link
I would like to use the arquillian plugin here to run jetty 8+:
https://github.com/aslakknutsen/arquillian-gradle-plugin
If I put "apply plugin: 'arquillian'" in my gradle script, it does not find it.
So I must have to install it somehow. I look for info on this, but did not find.
Would you have a pointer on how to do that?
I am using gradle 1.6 on windows.
Update after answer by #raeffs:
I updated the gradle script with it and the build is successfull, but I don't see my war started after an arquillianRunJetty (port 8080 is not even listening).
Then I tried to add what is indicated on the github page:
arquillian {
debug = true
deployable = file('my/path/arbitraryWebApp.war')
containers {
jetty {
version = '8'
type = 'embedded'
config = ['bindHttpPort': 8080, 'bindAddress': '127.0.0.1', 'jettyPlus': false]
dependencies {
adapter 'org.jboss.arquillian.container:arquillian-jetty-embedded-7:1.0.0.CR2'
container 'org.eclipse.jetty:jetty-webapp:8.1.11.v20130520'
container group: 'org.eclipse.jetty', name: 'jetty-plus', version: '8.1.11.v20130520'
}
}
I had to replace arquillian-jetty-embedded-7:1.0.0.CR2 with CR1 as it is not in maven central.
Then I put the path to my war. When starting again, there is more chatter but still no listening on port 8080.
So I still miss something.
I also find awkward to have to reference with an absolute path for the war I am building with the gradle script. I think there could be a kind of self reference.
Update
It is running fine now thanks to #raeffs. I don't really know what was wrong in my previous step.
The path to the web app takes the name, plus the version.
Thank you
The creator of the plugin has not published it to a maven repository, so you have to build it on your own.
Get a local copy of the plugin project and build it. You should get a the 'arquillian-gradle-plugin-0.1.jar' as output.
In the build script of yout own project you have to declare a dependency to that jar. Add the following to your build script:
buildscript {
dependencies {
classpath fileTree(dir: '/path/to/folder/that/contains/the/jar',
includes: ['arquillian-gradle-plugin-0.1.jar'])
}
}
Now you should be able to use the plugin.
Update
If you do not want to provide a hardcoded path to your deployable you could simply pass a variable. For example if you are using the war plugin:
arquillian {
deployable = war.archivePath
}
Here is an example of the usage: https://gist.github.com/raeffs/5920562#file-build-gradle
It starts the jetty container, deploys the war and waits until ctrl+c is pressed.