Hot swapping in Spring Boot - java

I've been doing a P.O.C with Spring Boot.
So far it's been going really good and promising, but there's one major drawback: I'm using an embedded server (i.e., packaging the web app in a .jar), so when developing I have to rebuild the jar and restart the server every time I change the CSS, HTML or JS files. There's not hot-swap. This really slows down the UI development.
I can think of several quick fixes, such as loading static resources off a different domain and serving it from a local nginx, and some more variations like this, but isn't there a built-in option of some sort when working with IntelliJ/Eclipse?

There are several options. Running in an IDE (especially with debugging on) is a good way to do development (all modern IDEs allow reloading of static resources and usually also hotswapping of Java class changes). Spring Boot devtools is a cheap way to get quite a big boost (just add it to your classpath). It works by restarting your application in a hot JVM when changes are detected. It also switches off things like thymeleaf caches while it is running, so you don't have to remember to do that yourself. You can use it with an external css/js compiler process if you are writing that code with higher level tools.
Spring Loaded is no longer recommended, but probably still in use. More sophisticated agent-based tools work much better if you need hot swapping with zero delay (e.g. JRebel).
See the docs for some up to date content

but isn't there a built-in option of some sort when working with IntelliJ/Eclipse?
What helped me in IntelliJ 15.0, windows 10, was the following sequence:
STEP 1: Added the following dependency in pom (This is mentioned everywhere but this alone dint solve it), as mentioned by #jonashackt
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
STEP 2: Then from File->Settings-> Build-Execution-Deployment -> Compiler (make sure main compiler option is selected and not any of its sub-options)
enable Make Project Automatically. Click ok and close the dialog
Note : In latest version it will be Build project automatically
STEP 3: Hold Shift+Ctrl+A (on windows) you will see a search dialog with title "Enter Action or option name", type registry. Double click the first option that says "Registry..." it will open another window. Look for the following option:
compiler.automake.allow.when.app.running
and enable it, click close
STEP 4: Restart IDE
Elaborated from this source

You can get hot swapping:
for java code: using spring-loaded
for Thymeleaf templates: disabling the cache
Check this post to see more details: http://blog.netgloo.com/2014/05/21/hot-swapping-in-spring-boot-with-eclipse-sts/

I do not know how far this kind of support goes, but in case you use Eclipse IDE (or anyone reading this): starting up your Spring-Boot application via m2e in debug-mode (press the "Debug"-dropdown button and pick your maven run configuration item).
It works for me like a charm.
My maven run configuration item is configured as follows:
goal is set to "spring-boot:run"
base directory is the project directory
I am not using any further libraries (not even spring-boot-devtools).
That's it.

You can also use JRebel - it will reload all changes (better hotswap) including spring beans. It is easily integratred with both Intellij and Eclipse.

Assuming you are using gradle; use the following config in your build.gradle
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'spring-boot'
apply plugin: 'application'
applicationDefaultJvmArgs = ["-agentlib:jdwp=transport=dt_socket,address=localhost:7000,server=y,suspend=n"]
mainClassName = "package.ApplicationRunner"
Run the application from the IDE or command line using the command gradle build run
Now the IDE can connect to the remote JVM (on port 7000) where the spring boot application runs. It also supports hot deployment of static files.
or even you can run the main class from intelliJ if the dependencies are properly managed in the IDE. The main class is the class that contains the main method which will call SpringApplication.run("classpath:/applicationContext.xml", args);

In Intellij, I can get this behavior. When the program is running in debug mode, select Run > Reload Changed Classes
Note: After Intellij completes the action, it might say Loaded classes are up to date. Nothing to reload. This is misleading, because it actually DID reload your classpath resources.
My environment/setup includes:
Intellij 13
Embedded Tomcat
Run/Debug configuration of type 'Application' (which just uses a main class)
Serving static html, css and js (no jsp)

try using this spring-boot-devtools tag in pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
http://mytechnologythought.blogspot.com/2017/07/how-to-run-server-of-spring-boot-auto.html

From 1.3.0. (now in Milestone 2) on, you can use the spring-boot-devtools for that as a lightweigt approach - see the docs or this blogpost.
Simply upgrade to >= 1.3.0. and add the following to your pom.xml:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
Than start your SpringBootApplication with Run As... and you´re fine.

I recommend Thymeleaf (template engine), jRebel for personal developer.
Thymeleaf template files are just HTML resources. So, they`re changed immediately after you edit template files.

If you're using maven, the spring-boot-maven-plugin in your pom.xml needs to be like this to get the hot swap:
<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>
and if you're using thymeleaf, add this to your application properties:
spring.thymeleaf.cache=false
But remember something: Don't use this in your production environment..

How to perform Hot Swap in Springboot Application
When using gradle include following in the dependency:
compile group: 'org.springframework.boot', name: 'spring-boot-devtools', version: '2.0.1.RELEASE' & providedRuntime('org.springframework.boot:spring-boot-starter-tomcat')
In application.properties add the property spring.devtools.restart.additional-paths=.
Build Gradle and then run application as bootRun
The application is ready to perform hot swap on modification of classes

Related

Java Library's Parameter Name differs between projects

I am developing Web Services with the following stacks:
Spring Boot with Spring Security
Maven -> add dependency from Maven Repo on pom.xml
Vs Code
Two Project (Two VS Code Windows): Production Development & Testing
List item
Desc:
In using 'SessionRegistry', when I try to see what is inside the 'SessionRegistry.class', the name of the parameters are as the image below:
Problem
Image_1.1) shows no indication on the purpose of the parameter as encircled on the image on the production project.
Stats on Testing Project, and this is my actual Expectation:
Expectation Image_1.2) has appropriate name of the parameter and it shows sense what is the purpose of the parameter.
++ Both of the Project is referring the same dependency thru pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
What I have already tried:
I have even tried to remove and download all of the dependencies at the Users/../.m2/repository
Wondered if the outdated version was the cause... so even tried to indicate the latest version enumerated on official maven repository website with the follwoing version:
--
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>2.6.3</version>
</dependency>
Awaiting for your advise with an advance grafulness.
You have not provided the source code for the library. Without the source, the IDE will still show the prototype (since that can be determined from the .class file) but it will make up names for the arguments, as you see.
Refer to the VSCode documentation to learn how to attach source jars.

JavaFX Maven project in IntelliJ. JavaFX runtime components are missing only in IntelliJ. JAR through mvn package executes without issues

I have a Java Project with Spring Boot and JavaFX added through maven. The code compiles and even i can execute the fat jar without the JavaFX SDK in the computer. But when I try to execute it in IntelliJ it results in
Error: JavaFX runtime components are missing, and are required to run this application
I have seen this output in many questions and in most of those cases the jar wasn't built at all or code compilation failed.
But in this scenario the mvn package works with no errors and I can execute the JAR with java -jar <jar_name> to cross out the fact that I might have the javafx sdk installed somewhere I tried it in a VM with only the JRE installed.
pom.xml
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>11.0.2</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>11.0.2</version>
</dependency>
As for plugins spring-boot-maven-plugin and maven-compiler-plugin.
Attempted Solutions
--1--
I tried the solution which said to add the
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.6</version>
<executions>
<execution>
<id>default-cli</id>
<configuration>
<mainClass>com.example.demofx.Starter</mainClass>
</configuration>
</execution>
</executions>
</plugin>
But what it does is add the ability to run with: mvn clean javafx:run
The need to execute with IntelliJ is to debug the code because Debugging with souts isn't efficient.
--2--
Trying to module build with a module-info.jar with following
module com.example.demofx {
requires javafx.controls;
requires javafx.fxml;
// all other required modules including spring
opens com.example.demofx to javafx.fxml;
exports com.example.demofx;
}
This might have worked but due to some of old dependencies not working properly with modularized build this results in lots of breaking changes to the codebase.
Edit:
Missed to mention the environment
JDK - 11.0.8
IntelliJ IDEA - 2021.2.2
Added second solution tried.
This is more a troubleshooting and research guide than an actual fix. Fixes for environmental issues are difficult to provide in a StackOverflow context. However, if you study the information here, it might help you fix your project.
Recommended troubleshooting approach
Use the Intellij new JavaFX project wizard. Ensure that it works in your environment, then gradually add components from your current project into the working project, checking that everything still works after each small addition.
Debugging when executing via the JavaFX maven plugin
I think the above recommendation is the preferred approach, however, you can alternately get the following to work:
run with: mvn clean javafx:run
The need to execute with IntelliJ is to debug the code"
See:
intellij idea : how to debug a java:fx maven project?
I also think you can just right-click on the maven target for javafx:run and select Debug. I am not sure, I don't make use of the JavaFX maven plugin.
Creating fat jars for JavaFX applications
the fat jar
This is not a recommended configuration, but if you really must do it, you can review:
Maven Shade JavaFX runtime components are missing
That answer doesn't discuss getting such a configuration to work in conjunction with an Idea run/debug configuration, so it may not assist you.
If you do continue with a fat jar, I would not advise using a module-info, as you will be running code off the classpath anyway.
Modular versus non-modular JavaFX applications
If you don't use a fat jar, getting all the module dependencies correct for Spring is tricky anyway because Spring is not currently architected to directly support modules well. Spring 6 will be designed to work well with modules, though I think you should be able to get Spring 5 to work if you try hard enough (I have got it to work in the past for some applications).
Alternately you can just have the JavaFX components as modules and run the rest off the classpath. For example, the "Non-modular with Maven" approach at openjfx.io. Note that in that approach, the JDK and JavaFX modules are still loaded as modules off of the module path, it is only Spring your application that is not providing a module-info.java file and running off the classpath.
Creating runtime images for JavaFX applications
I also advise studying:
these resources for the creation of an appropriate runtime image.

IntelliJ Idea not update remote Tomcat, only redeploy works

In IntelliJ Idea I've very basic Spring Boot Starter project configured with Tomcat in scope "Provided".
I've configuration for "Tomcat remote" in IDE and everything seems properly set.
My Tomcat version 8 is not modified except this file with JMX configuration:
I can start tomcat with "catalina run". When I click on the button "Run" in IDE to deploy project then
project is successfully deployed to remote Tomcat and is working.
Problem is that Hot Swap by pressins "Build project" button doesn't work at all even for basic html classes. Therefore when I make some changes I have to Redeploy entire project which is very time consuming.
How to resolve it?
what is your spring version ? - hope 1.3 and above
In the spring you have a tool named dev-tools add the entry in your pom file to support hot swap and reduce development time.youtube link
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
In eclipse we have a option build automatically ,make sure corresponding option is checked in the used ide(IntelliJ).

Using (Scala) library from Java Web App, getting NoClassDefFoundError

I've been working on a rather "standard" Java web application for a long time now. I develop in Eclipse using Eclipse's server plugin to run the app in Tomcat. The app's setup is straight forward: Spring for bootstrapping, Wicket for web, Hibernate for ORM, Maven for dependency management.
Today I have added Akka 2.0 to the project. I added it to my POM as per the manual:
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-actor</artifactId>
<version>2.0.2</version>
</dependency>
Maven finds the dependency and I can see it showing up in the Maven dependencies in Eclipse's package explorer. The referenced Scala Library also shows up (version 2.9.2 as it seems).
I can use the library just as one would expect: Eclipse finds the classes, I can jump to source files etc. Everything works perfectly. But once I start the app and it comes across any part of the program with references to Akka it throws a NoClassDefFoundError.
Since all other libraries still work as expected, my best guess is that is has something to do with the fact that Akka is a library developed in Scala. Since I've hardly used Scala myself though, I could not find any solution to the issue myself and Google isn't really that helpful when it comes to such generic exceptions.
Do you have any advice?
Verify that the required library (AKKA) is in your deployment assembly under Eclipse: open the project's properties and look for "Deployment Assembly" on the left.
[I'm using Eclipse Indigo]
You could verify the presence (or lack) of the expected jar file by examining the deployment under tomcat.

Cannot load classes from Guava r08 running in Tomcat. Cannot compile from source. Missing javax.annotations

I'm trying to use RichFaces in my learning JSF application. I have set up Maven using
https://repository.jboss.org/nexus/content/groups/public-jboss/
I have included the dependencies
<dependency>
<groupId>org.richfaces.ui</groupId>
<artifactId>richfaces-components-ui</artifactId>
<version>4.0.0.Final</version>
</dependency>
<dependency>
<groupId>org.richfaces.core</groupId>
<artifactId>richfaces-core-impl</artifactId>
<version>4.0.0.Final</version>
</dependency>
<dependency>
<groupId>org.richfaces.ui</groupId>
<artifactId>richfaces-components-api</artifactId>
<version>4.0.0.Final</version>
<type>pom</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.richfaces.core</groupId>
<artifactId>richfaces-core-api</artifactId>
<version>4.0.0.Final</version>
<type>pom</type>
<scope>compile</scope>
</dependency>
This has fetched guava-r08.jar.
When I try to run the project in Tomcat7 I see a lot of class load exceptions - failing to load classes that I can see exist within guava-r08.jar along with sac-1.3 and cssparser-0.9.5.
If I try to use the source instead - taking source from guava-r09 - Eclipse tells me that it cannot find classes such as javax.annotation.Nullable. Problem is neither can I!
Where can I find these classes, or am I taking the wrong approach from the start?
Thanks
Richard
Maven configuration for RichFaces dependencies
Tomcat fails to load these classes, because RichFaces' dependency on Guava has a runtime scope. Contrary to the compile scope, these dependencies are not added to the classpath when compiling. You must include them yourself.
To achieve this, you should include richfaces-bom in the dependency management section of your POM, as explained in this JBoss wiki article. This will include Guava and all other required dependencies RichFaces might need.
This is the "Bill of Materials" (BOM) pattern. The JBoss wiki explains this pattern far better than I would, and links to other articles on the subject.
javax.annotation.Nullable warnings in the Guava source
These occur because Guava uses JSR 305 annotations. It is not required to depend on the JSR 305 jar when using Guava, because annotations do not require to be present on the classpath once compiled. Of course, if you want to use #Nullable and other such annotations in your code (you definitely should), you'll need to add a dependency on the JSR 305 jar.
I have started from scratch using instructions at jboss.org
I installed Maven 3.0.3
I copied the supplied settings.xml to my .m2 directory and added the JBOSS section from 1
I used the command line to create the project:
mvn archetype:generate -DarchetypeGroupId=org.richfaces.archetypes \
-DarchetypeArtifactId=richfaces-archetype-simpleapp \
-DarchetypeVersion=4.0.0-SNAPSHOT \
-DgroupId=uk.m0rjc \
-DartifactId=jsfplay
I then built the project. I had to remove the previously downloaded guava jars from my m2 repository because they were corrupt - perhaps my initial problem.
mvn clean package
I copied the WAR file it produced to Tomcat and navigated to the sample page at localhost:8080/jsfplay-1.0-SNAPSHOT/
I had some issues making the project work in Eclipse. These may be due to my setup from previous experiments.
I used the "Import -> Maven -> Existing Maven Project" to import it
I had to switch the project to JDK 1.6 and 1.6 compatibility mode.
I was unable to use the JavaServer Faces facet. This does not seem to matter.
I had to set my Server Profile to use the right JDK
I had to map *.xhtml to the Faces Servlet in web.xml. It may have been corrupted when I pressed a wrong button to accept a JSF addin.
Then it worked!!
Now to try porting my existing code to the new project.

Categories