I am trying to configure spring session backed by hazelcast for spring security oauth2 client application.
I followed below link to configure hazelcast.
https://docs.spring.io/spring-session/docs/current/reference/html5/guides/java-hazelcast.html
However, classes annotated with #SpringBootTest started failing due to below error:
java.lang.IncompatibleClassChangeError: class org.springframework.session.hazelcast.PrincipalNameExtractor has interface com.hazelcast.query.extractor.ValueExtractor as super class
My pom.xml of spring boot 2.5 application contain below two new dependencies for hazelcast configuration
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast</artifactId>
<version>4.2</version>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-hazelcast</artifactId>
</dependency>
As per below stackoverflow post , issue seems to be that ValueExtractor is available for two different versions in maven dependencies
IncompatibleClassChangeError: class ClassMetadataReadingVisitor has interface ClassVisitor as super class
Hence, I checked maven dependencies and can see that PrincipalNameExtractor is available from 2.5 version of spring-session-hazelcast while ValueExtractor is available from 4.2 version on com.hazelcast. However,
spring-session-hazelcast is using 3.12.12 version of com.hazelcast for compilation.
So should I use 3.12.12 version of com.hazelcast to resolve this issue or am in misinterpreting the issue? I prefer to use latest version.
Starting from spring-sessions v2.4.0, you can use Hazelcast v4.x with configuring Hazelcast4PrincipalNameExtractor and Hazelcast4IndexedSessionRepository for the session repository. The only difference is the class names with 4 indicator. That is, HazelcastIndexedSessionRepository becomes 4.x compatible with Hazelcast4IndexedSessionRepository.
Here is a guide covering both versions: https://guides.hazelcast.org/spring-session-hazelcast/
I'm currently looking into testing jetty servlets. I found the org.eclipse.jetty.testing.ServletTester class in some old documentation (just by random searching on the web), but it seems to be removed in newer versions.
Is there a replacement for it, and if yes, where can i find it?
If there is no replacement, I would be happy to hear about different ways to accomplish the goal of testing servlets!
Thanks in advance
The class org.eclipse.jetty.testing.ServletTester is the old Jetty 7 and Jetty 8 ServletTester.
It can be found in the following maven artifacts ...
https://search.maven.org/search?q=fc:org.eclipse.jetty.testing.ServletTester
The newer org.eclipse.jetty.servlet.ServletTester (note the package change) is available for Jetty 9.x, Jetty 10.x, and Jetty 11.x in the following artifacts ...
https://search.maven.org/search?q=fc:org.eclipse.jetty.servlet.ServletTester
Standard maven repository behaviors here, as the class is not a runtime class, it sits in the tests jar (also on maven central).
Example:
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>9.4.35.v20201120</version>
<classifier>tests</classifier>
</dependency>
I upgraded my app from spring boot 1.5.9.RELEASE to 2.0.0.RELEASE, and I can no longer import org.springframework.boot.context.embedded.LocalServerPort. I was using this to inject the port the server is running on during a test:
public class Task1Test {
#LocalServerPort
private int port;
The Spring release notes do not mention this removal and #LocalServerPort was not deprecated.
Is there an equivalent in Spring Boot 2.0 that I can use?
Edit: I'm pretty sure that the class is gone. I'm getting these compilation errors:
[ERROR] ... Task1Test.java:[12,49]package org.springframework.boot.context.embedded does not exist
[ERROR] ... Task1Test.java:[46,6] cannot find symbol
symbol: class LocalServerPort
It looks like it was moved to org.springframework.boot.web.server.LocalServerPort without notice. Hope that helps.
It seems it's been moved to spring-boot-starter-web dependency as per this API documentation.
Try adding this maven dependency to see if that fixes it
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
#LocalServerPort is now in
org.springframework.boot.test.web.server.LocalServerPort
Update your imports in the test code.
Relevant link to the Spring boot docs here
https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/web/server/LocalServerPort.html
the change is notified here
https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/web/server/LocalServerPort.html
Note that if you are using the Spring Boot Getting Started guides, the guides are still using the old namespace and hence you will see a build error without an option to fix. You will need to update this manually.
I am in the process of creating a Java REST application, using Spring-boot. I have successfully loaded the example here and I have tried to convert the JAR file to the WAR file as presented on the Spring-boot site. I've modified my pom.xml file, adding:
<!-- other pom.xml conf -->
<packaging>war</packaging>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
Then I've modified the Application.java class to initialize the servlet (this is for what Spring-boot uses to replace the web.xml file):
public class Application extends SpringBootServletInitializer {
// public static void main(String[] args) {
// new SpringApplicationBuilder(Application.class).run(args);
// }
#Bean
public ServletRegistrationBean jerseyServlet() {
ServletRegistrationBean registration = new ServletRegistrationBean(new ServletContainer(), "/*");
registration.addInitParameter(ServletProperties.JAXRS_APPLICATION_CLASS, JerseyInitialization.class.getName());
return registration;
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}
I got my .WAR file generated, but when I deploy it on Tomcat the services are returning 404. The Tomcat logs aren't showing any errors either.
So I am not sure what it might be the problem. If you have any idea please, do share. Thanks!
Update:
Initially it wasn't working because beside the SpringBootApplication annotation to the Application class I was having other annotations too. Took those out and now Tomcat logs are showing this error.
SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
java.lang.IllegalStateException: Cannot initialize context because there is already a root application context present - check whether you have multiple ContextLoader* definitions in your web.xml!
I am not sure what other ContextLoader is there.
UpdateToUpdate:
Okay, after updating the jars to the latest version, using the annotation #SpringBootApplication for Application.java class, the application starts but when I am calling one of the services I receive:
java.lang.ClassNotFoundException: org.glassfish.jersey.process.internal.RequestExecutorFactory
A google search said that I should add the jersey-common and jersey-core jars, I did, but it didn't fix it. It looks like the RequestExecutorFactory.class is not packaged in the jersey-common-2.19.jar for some reason.
why do you have so many annotation in your Application class here ?
#SpringBootApplication should be sufficient to enable automatic configuration.
Try removing the others.
And put back the main method.
I think you mixed two configuration tw create a war : pre 3.0 and post 3.0 servlet container (as per the Spring Boot documentation)
EDIT :
I've found this question related to your problem.
Jersey is loading a Spring ApplicationContext. See this line of log : Spring WebApplicationInitializers detected on classpath: [com.jersey.Application#148ac084, org.glassfish.jersey.server.spring.SpringWebApplicationInitializer#7807c6d3]
Would it be possible for you to update your Spring Boot version ?
At least 1.20 so you will be able to use the spring-boot-starter-jersey. It will be a lot more easier to integrate Spring and Jersey.
You can find an example here (Spring Boot official examples).
Or you have to exclude the org.glassfish.jersey.server.spring.SpringWebApplicationInitializer of initializers
I have a simple Spring Boot application that gets messages from a JMS queue and saves some data to a log file, but does not need a web server. Is there any way of starting Spring Boot without the web server?
if you want to run Spring Boot 1.x without a servlet container, but with one on the classpath (e.g. for tests), use the following, as described in the spring boot documentation:
#Configuration
#EnableAutoConfiguration
public class MyClass {
public static void main(String[] args) throws JAXBException {
SpringApplication app = new SpringApplication(MyClass.class);
app.setWebEnvironment(false); //<<<<<<<<<
ConfigurableApplicationContext ctx = app.run(args);
}
}
also, I just stumbled across this property:
spring.main.web-environment=false
Spring Boot 2.x, 3.x
Application Properties
spring.main.web-application-type=NONE
# REACTIVE, SERVLET
or SpringApplicationBuilder
#SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(MyApplication.class)
.web(WebApplicationType.NONE) // .REACTIVE, .SERVLET
.run(args);
}
}
Where WebApplicationType:
NONE - The application should not run as a web application and should not start an embedded web server.
REACTIVE - The application should run as a reactive web application and should start an embedded reactive web server.
SERVLET - The application should run as a servlet-based web application and should start an embedded servlet web server.
You can create something like this:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(false).run(args);
}
}
And
#Component
public class CommandLiner implements CommandLineRunner {
#Override
public void run(String... args) throws Exception {
// Put your logic here
}
}
The dependency is still there though but not used.
Spring boot will not include embedded tomcat if you don't have Tomcat dependencies on the classpath.
You can view this fact yourself at the class EmbeddedServletContainerAutoConfiguration whose source you can find here.
The meat of the code is the use of the #ConditionalOnClass annotation on the class EmbeddedTomcat
Also, for more information check out this and this guide and this part of the documentation
The simplest solution. in your application.properties file. add the following property as mentioned by a previous answer:
spring.main.web-environment=false
For version 2.0.0 of Spring boot starter, use the following property :
spring.main.web-application-type=none
For documentation on all properties use this link : https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html
Use this code.
SpringApplication application = new SpringApplication(DemoApplication.class);
application.setWebApplicationType(WebApplicationType.NONE);
application.run(args);
For Spring boot v2.1.3.RELEASE, just add the follow properties into application.propertes:
spring.main.web-application-type=none
If you need web functionality in your application (like org.springframework.web.client.RestTemplate for REST calls) but you don't want to start a TOMCAT server, just exclude it in the POM:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
Through program :
ConfigurableApplicationContext ctx = new SpringApplicationBuilder(YourApplicationMain.class)
.web(WebApplicationType.NONE)
.run(args);
Through application.properties file :
spring.main.web-environment=false
Through application.yml file :
spring:
main:
web-environment:false
Spring boot has many starters, some starters have an embedded web server, some don't. The following have the embedded web server:
spring-boot-starter-web
spring-boot-starter-data-jpa
spring-boot-starter-jetty
spring-boot-starter-tomcat
spring-boot-starter-jdbc
spring-boot-starter-data-rest
...
Pick the one that meets your requirements and that does not have server support.
I only need to make restful json api request in my spring application, so the starter I need is
spring-boot-starter-json
which provide RestTemplate and jackson for me to use.
You can use the spring-boot-starter dependency. This will not have the web stuff.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
If you want to use one of the "Getting Started" templates from spring.io site, but you don't need any of the servlet-related stuff that comes with the "default" ("gs/spring-boot") template, you can try the scheduling-tasks template (whose pom* contains spring-boot-starter etc) instead:
https://spring.io/guides/gs/scheduling-tasks/
That gives you Spring Boot, and the app runs as a standalone (no servlets or spring-webmvc etc are included in the pom). Which is what you wanted (though you may need to add some JMS-specific stuff, as someone else points out already).
[* I'm using Maven, but assume that a Gradle build will work similarly].
Remove folowing dependancy on your pom file will work for me
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
For Kotling here is what I used lately:
// src/main/com.blabla/ShellApplication.kt
/**
* Main entry point for the shell application.
*/
#SpringBootApplication
public class ShellApplication : CommandLineRunner {
companion object {
#JvmStatic
fun main(args: Array<String>) {
val application = SpringApplication(ShellApplication::class.java)
application.webApplicationType = WebApplicationType.NONE
application.run(*args);
}
}
override fun run(vararg args: String?) {}
}
// src/main/com.blabla/command/CustomCommand.kt
#ShellComponent
public class CustomCommand {
private val logger = KotlinLogging.logger {}
#ShellMethod("Import, create and update data from CSV")
public fun importCsv(#ShellOption() file: String) {
logger.info("Hi")
}
}
And everything boot normally ending up with a shell with my custom command available.
In Spring boot, Spring Web dependency provides an embedded Apache Tomcat web server. If you remove spring-boot-starter-web dependency in the pom.xml then it doesn't provide an embedded web server.
remove the following dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
From my experience on spring boot > 2.5 ,
if you plan to build the application as a jar file, in my opinion the solution of spring.main.web-application-type=NONE should not be widely accepted and used, since it has only a limited scope of benefits.
For asking to have spring boot without the web server, it means that you have from Spring either the dependency spring-boot-starter-web to build a spring web application or the dependency spring-boot-starter-jersey to build a jax-rs web application. Those dependencies pack inside the spring-boot-starter-tomcat which will then bring the dependency of tomcat-embed-core which is the actual tomcat server. This library is packed automatically inside and is of size ~3.3 MB. Even if you disable the server with the aforementioned property, you will still deliver your application jar file, containing the tomcat server inside.
So the con of just using the aforementioned property is that the deliverable jar file will be some MB larger in size without any actual need.
So if you want to have spring boot without the web server just don't use the dependencies spring-boot-starter-jersey or spring-boot-starter-web since if you build your application as a jar file there is no reason to have those dependencies and not have an embedded server delivered.
if you plan to build the application as a war file, you should also not use the above property.
In this case you will just need in your .pom the following configurations
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web or (spring-boot-starter-jersey)</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>pick the version that the server that already runs in production supports</version>
<scope>provided</scope>
</dependency>
</dependencies>
Exceptional cases
The property spring.main.web-application-type=NONE should be in my opinion used for some exceptional cases like if we build some web library that needs the above dependencies but is not to be used like a web application, or we have some complex type of testing that needs those libraries although the application does not need any server to run. This type of usages are however rare.
Similar to #nayun oh answer above, but for older versions of Spring, use this code:
SpringApplication application = new SpringApplication(DemoApplication.class);
application.setApplicationContextClass(AnnotationConfigApplicationContext.class);
application.run(args);