Hot questions for Spring Boot Gradle Plugin
Question:
What does a correct Gradle configuration look like in a multi-module project that uses the Gradle plugins spring-boot-dependencies
and spring-boot
?
I have the following project setup:
parent | + build.gradle | + alpha | | | + build.gradle | + beta | | | + build.gradle
- The
parent
module contains common project configuration. - The
alpha
module is a module in which I would like to import dependencies using versions numbers specified in the spring-boot-dependencies bom, but the result of the is a standard jar. - The
beta
module is a module that depends onalpha
and the result is an executable Spring Boot jar file (including all dependencies). Consequently, this project needs both thespring-boot-dependencies
as well as thespring-boot
plugin.
In order to keep the Gradle files DRY, I have extracted common module scripts to the parent's build.gradle
file.
Attempts to execute $ gradle build
using the project configuration below results in:
> Plugin with id 'io.spring.dependency-management' not found.
parent gradle.build
allprojects { group = "com.example" version '0.0.1-SNAPSHOT' ext { dependencyManagementPluginVersion = '0.5.3.RELEASE' springBootVersion = '1.3.0.RC1' } apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'idea' } subprojects { sourceCompatibility = 1.8 targetCompatibility = 1.8 buildscript { repositories { jcenter() maven { url "https://repo.spring.io/snapshot" } maven { url "https://repo.spring.io/milestone" } } dependencies { classpath("io.spring.gradle:dependency-management-plugin:${dependencyManagementPluginVersion}") classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } } apply plugin: 'io.spring.dependency-management' dependencyManagement { imports { mavenBom("org.springframework.boot:spring-boot-dependencies:${springBootVersion}") // mavenBom("org.springframework.boot:spring-boot-starter-parent:${springBootVersion}") } } }
alpha build.gradle
dependencies { compile('org.springframework:spring-web') }
beta gradle.build
apply plugin: 'spring-boot' dependencies { compile project(':alpha') compile('org.springframework.boot:spring-boot-starter') compile('org.springframework.boot:spring-boot-starter-web') }
Comments:
- The behavior of the
spring-boot
plugin was changed in Spring Boot 1.3.0.M1 - Gradle version: 2.8
- Spring Boot version 1.3.0.RC1
Answer:
It turns out that parent/build.gradle
should be rearranged in the following way:
buildscript { ext { dependencyManagementPluginVersion = '0.5.3.RELEASE' springBootVersion = '1.3.0.RC1' } repositories { jcenter() maven { url "https://repo.spring.io/snapshot" } maven { url "https://repo.spring.io/milestone" } } dependencies { classpath("io.spring.gradle:dependency-management-plugin:${dependencyManagementPluginVersion}") classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } } allprojects { group = "com.example" version '0.0.1-SNAPSHOT' apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'idea' } subprojects { sourceCompatibility = 1.8 targetCompatibility = 1.8 apply plugin: 'io.spring.dependency-management' dependencyManagement { imports { mavenBom("org.springframework.boot:spring-boot-dependencies:${springBootVersion}") // mavenBom("org.springframework.boot:spring-boot-starter-parent:${springBootVersion}") } } }
The problem lies in the fact that buildscript
block for subprojects was indeed configured well but... in a wrong place. This subprojects
block relates to subprojects but it will be evaluated in the script it was declared, and there were no dependencies declared for the plugin it was trying to apply.
Question:
I'm trying to achieve a simple scenario in my spring boot project build: including / excluding dependencies and packaging war or jar depending on the environment.
So for example, for the environment dev
include devtools and package jar, for prod
package war etc.
I know it is not XML based configuration anymore and I can basically write if statements in my build.gradle but is there a recommended way of achieving this?
Can I declare some common dependencies and refer them in a single file instead of creating multiple build files?
Is there a best practice changing build configuration based on the build target environment?
Answer:
ext { devDependencies = ['org.foo:dep1:1.0', 'org.foo:dep2:1.0'] prodDependencies = ['org.foo:dep3:1.0', 'org.foo:dep4:1.0'] isProd = System.properties['env'] == 'prod' isDev = System.properties['env'] == 'dev' } apply plugin: 'java' dependencies { compile 'org.foo:common:1.0' if (isProd) { compile prodDependencies } if (isDev) { compile devDependencies } } if (isDev) tasks.withType(War).all { it.enabled = false }
Question:
I am using Spring Boot 2 in my Gradle project to do a build to jar in Jenkins, and I would like to change the name of that jar file.
By default, Spring Boot 2 used the Gradle property rootProject.name
, which can be set in the /settings.gradle
file.
However, I would like to change the jar file name, without changing the rootProject.name
.
Here are my bootJar
and springBoot
sections of the build.gradle
file:
bootJar { launchScript() }
.
springBoot { buildInfo { properties { artifact = "jarName" group = "groupName" name = "projectName" version = "1.0" } } }
Note: artifact
is not setting the jar name, as I expected it to, after reading: https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/html/#integrating-with-actuator
Answer:
archiveFileName
is the new hotness. Everything else is deprecated.
bootJar { archiveFileName = "${archiveBaseName.get()}.${archiveExtension.get()}" }
or the Kotlin DSL equivalent:
tasks.getByName<org.springframework.boot.gradle.tasks.bundling.BootJar>("bootJar") { this.archiveFileName.set("${archiveBaseName.get()}.${archiveExtension.get()}") }
See:
Question:
I'm using Gradle
with Spring Boot 2.0.0.M7
and have the following plugins applied:
buildscript { repositories { maven { url "https://plugins.gradle.org/m2/" } maven { url "https://repo.spring.io/milestone" } } dependencies { classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.0.M7" } } plugins { id "com.gorylenko.gradle-git-properties" version "1.4.17" }
spring-boot-starter-actuator
dependency is also there. git.properties
files is generated correctly to build/main/resoures
directory. I've also added property management.info.git.mode=full
. Due to official docs, git information should be added to /info
endpoint automatically with GitInfoContributor. However none of the above helps and /info
endpoint returns empty JSON instead - {}
. Any ideas on how this can be fixed?
UPDATE 1:
What I've found so far is that if I manually copy git.properties
to out/resources
, this way it would work, but they are not put there for some reason.
UPDATE 2:
When I run with gradle bootRun
it works, however when I start it from Intellij IDEA our run gradle clean build
which runs the test which checks if those properties are displayed on /info
endpoint - it doesn't work.
Answer:
The problem was running the app from IDE. As the properties are generated on the phase when JAR is assembled, they were not included. Running the application via java -jar artifact.jar
or gradle bootRun
works without any issues.
Thanks @fateddy for help on resolving the issue.
Question:
I have roughly the following setup:
test-utils/build.gradle:
buildscript { repositories { jcenter() } dependencies { classpath 'org.springframework.boot:spring-boot-gradle-plugin:1.3.1.RELEASE' } } apply plugin: 'java' apply plugin: 'spring-boot' dependencies { compile ('org.springframework.boot:spring-boot-starter-test') { exclude group: 'org.mockito' exclude group: 'org.hamcrest' } compile 'org.mockito:mockito-core:2.0.41-beta' compile 'org.assertj:assertj-core:3.3.0' }
main/build.gradle:
buildscript { repositories { jcenter() } dependencies { classpath 'org.springframework.boot:spring-boot-gradle-plugin:1.3.1.RELEASE' } } apply plugin: 'java' apply plugin: 'spring-boot' dependencies { testCompile project(':test-utils') }
But for some reason it seems that the spring boot plugin forces the mockito version back to 1.x:
# ./gradlew :main:dependencies --configuration=testCompile testCompile - Compile classpath for source set 'test'. +--- project :test-utils +--- org.springframework.boot:spring-boot-starter-test: -> 1.3.1.RELEASE | +--- junit:junit:4.12 | +--- org.springframework:spring-core:4.2.4.RELEASE | \--- org.springframework:spring-test:4.2.4.RELEASE | \--- org.springframework:spring-core:4.2.4.RELEASE +--- org.mockito:mockito-core:2.0.41-beta -> 1.10.19 | +--- org.hamcrest:hamcrest-core:1.1 -> 1.3 | \--- org.objenesis:objenesis:2.1 \--- org.assertj:assertj-core:3.3.0
If I take the spring boot plugin out of the equation, things work as expected:
# ./gradlew :main:dependencies --configuration=testCompile testCompile - Compile classpath for source set 'test'. +--- project :test-utils +--- org.springframework:spring-core:4.2.4.RELEASE (*) +--- org.springframework:spring-test:4.2.4.RELEASE | \--- org.springframework:spring-core:4.2.4.RELEASE (*) +--- junit:junit:4.12 +--- org.mockito:mockito-core:2.0.41-beta | +--- net.bytebuddy:byte-buddy:1.0.2 | \--- org.objenesis:objenesis:2.1 \--- org.assertj:assertj-core:3.3.0
What is the spring boot plugin doing exactly, and how can I tell it not to?
Answer:
Your main
project has Spring Boot's plugin applied to it, so it's using Spring Boot's dependency management. That means it will, by default, use Spring Boot's preferred version of Mockito, irrespective of the version specificied in test-utils
.
As described in the documentation, you can override the version of a dependency that Spring Boot manages by setting the relevant property. For Mockito that property is mockito.version
. Add the following to your main
project:
ext['mockito.version'] = '2.0.41-beta'
Question:
Recently I tried to update my Spring Boot application version from 1.5.10.RELEASE to 2.0.0.RELEASE
Project Environment
- JDK version 1.8
- jcenter() repository in Gradle
- IDE Spring tool Suite (STS) Version: 3.9.2
I have encountered two issues
I got the completion issue below.
Could not resolve all files for configuration ':compileClasspath'. Could not find org.springframework.boot:spring-boot-starter-mobile:
Then I checked the latest version of spring-boot-starter-mobile library and there’s no stable version of spring-boot-starter-mobile for Spring Boot 2.
So I had to declare milestone URL using maven to import version: '2.0.0.M5' and issue has resolved.
maven { url 'https://repo.spring.io/milestone' }
Originally I was using jcenter() and is it possible to import milestones using jcenter?
I’m getting the following runtime error when access the mobile device interface below.
org.springframework.mobile.device.Device
public ResponseEntity<?> TestM(@RequestBody MyRequest myRequest, Device device) throws AuthenticationException { return ResponseEntity.ok(); }
ERROR
2018-03-12 23:54:58.410 ERROR 13732 --- [nio-8080-exec-4] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalStateException: No primary or default constructor found for interface org.springframework.mobile.device.Device] with root cause java.lang.NoSuchMethodException: org.springframework.mobile.device.Device.<init>() at java.lang.Class.getConstructor0(Unknown Source) ~[na:1.8.0_121] at java.lang.Class.getDeclaredConstructor(Unknown Source) ~[na:1.8.0_121] at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.createAttribute(ModelAttributeMethodProcessor.java:209) ~[spring-web-5.0.4.RELEASE.jar!/:5.0.4.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.createAttribute(ServletModelAttributeMethodProcessor.java:84) ~[spring-webmvc-5.0.4.RELEASE.jar!/:5.0.4.RELEASE] at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:132) ~[spring-web-5.0.4.RELEASE.jar!/:5.0.4.RELEASE] at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:124) ~[spring-web-5.0.4.RELEASE.jar!/:5.0.4.RELEASE] at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:161) ~[spring-web-5.0.4.RELEASE.jar!/:5.0.4.RELEASE] at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:131) ~[spring-web-5.0.4.RELEASE.jar!/:5.0.4.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) ~[spring-webmvc-5.0.4.RELEASE.jar!/:5.0.4.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:870) ~[spring-webmvc-5.0.4.RELEASE.jar!/:5.0.4.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:776) ~[spring-webmvc-5.0.4.RELEASE.jar!/:5.0.4.RELEASE] at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.0.4.RELEASE.jar!/:5.0.4.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991) ~[spring-webmvc-5.0.4.RELEASE.jar!/:5.0.4.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925) ~[spring-webmvc-5.0.4.RELEASE.jar!/:5.0.4.RELEASE] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:978) ~[spring-webmvc-5.0.4.RELEASE.jar!/:5.0.4.RELEASE] at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:881) ~[spring-webmvc-5.0.4.RELEASE.jar!/:5.0.4.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:661) ~[tomcat-embed-core-8.5.28.jar!/:8.5.28] at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:855) ~[spring-webmvc-5.0.4.RELEASE.jar!/:5.0.4.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) ~[tomcat-embed-core-8.5.28.jar!/:8.5.28] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-8.5.28.jar!/:8.5.28] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.28.jar!/:8.5.28] at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.28.jar!/:8.5.28] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.28.jar!/:8.5.28] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.28.jar!/:8.5.28] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:101) ~[spring-web-5.0.4.RELEASE.jar!/:5.0.4.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.28.jar!/:8.5.28] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.28.jar!/:8.5.28] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320) ~[spring-security-web-5.0.3.RELEASE.jar!/:5.0.3.RELEASE] at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127) ~[spring-security-web-5.0.3.RELEASE.jar!/:5.0.3.RELEASE] at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91) ~[spring-security-web-5.0.3.RELEASE.jar!/:5.0.3.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.0.3.RELEASE.jar!/:5.0.3.RELEASE] at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:119) ~[spring-security-web-5.0.3.RELEASE.jar!/:5.0.3.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.0.3.RELEASE.jar!/:5.0.3.RELEASE] at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) ~[spring-security-web-5.0.3.RELEASE.jar!/:5.0.3.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.0.3.RELEASE.jar!/:5.0.3.RELEASE] at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) ~[spring-security-web-5.0.3.RELEASE.jar!/:5.0.3.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.0.3.RELEASE.jar!/:5.0.3.RELEASE] at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170) ~[spring-security-web-5.0.3.RELEASE.jar!/:5.0.3.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.0.3.RELEASE.jar!/:5.0.3.RELEASE] at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) ~[spring-security-web-5.0.3.RELEASE.jar!/:5.0.3.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.0.3.RELEASE.jar!/:5.0.3.RELEASE] at com.example.security.JwtAuthenticationTokenFilter.doFilterInternal(JwtAuthenticationTokenFilter.java:72) ~[classes!/:na] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.4.RELEASE.jar!/:5.0.4.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.0.3.RELEASE.jar!/:5.0.3.RELEASE] at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) ~[spring-security-web-5.0.3.RELEASE.jar!/:5.0.3.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.0.3.RELEASE.jar!/:5.0.3.RELEASE] at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66) ~[spring-security-web-5.0.3.RELEASE.jar!/:5.0.3.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.4.RELEASE.jar!/:5.0.4.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.0.3.RELEASE.jar!/:5.0.3.RELEASE] at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) ~[spring-security-web-5.0.3.RELEASE.jar!/:5.0.3.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.0.3.RELEASE.jar!/:5.0.3.RELEASE] at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) ~[spring-security-web-5.0.3.RELEASE.jar!/:5.0.3.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.4.RELEASE.jar!/:5.0.4.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.0.3.RELEASE.jar!/:5.0.3.RELEASE] at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215) ~[spring-security-web-5.0.3.RELEASE.jar!/:5.0.3.RELEASE] at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178) ~[spring-security-web-5.0.3.RELEASE.jar!/:5.0.3.RELEASE] at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357) ~[spring-web-5.0.4.RELEASE.jar!/:5.0.4.RELEASE] at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270) ~[spring-web-5.0.4.RELEASE.jar!/:5.0.4.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.28.jar!/:8.5.28] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.28.jar!/:8.5.28] at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-5.0.4.RELEASE.jar!/:5.0.4.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.4.RELEASE.jar!/:5.0.4.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.28.jar!/:8.5.28] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.28.jar!/:8.5.28] at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109) ~[spring-web-5.0.4.RELEASE.jar!/:5.0.4.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.4.RELEASE.jar!/:5.0.4.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.28.jar!/:8.5.28] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.28.jar!/:8.5.28] at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81) ~[spring-web-5.0.4.RELEASE.jar!/:5.0.4.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.4.RELEASE.jar!/:5.0.4.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.28.jar!/:8.5.28] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.28.jar!/:8.5.28] at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) ~[spring-web-5.0.4.RELEASE.jar!/:5.0.4.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.4.RELEASE.jar!/:5.0.4.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.28.jar!/:8.5.28] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.28.jar!/:8.5.28] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199) ~[tomcat-embed-core-8.5.28.jar!/:8.5.28] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.28.jar!/:8.5.28] at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:496) [tomcat-embed-core-8.5.28.jar!/:8.5.28] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.28.jar!/:8.5.28] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) [tomcat-embed-core-8.5.28.jar!/:8.5.28] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.28.jar!/:8.5.28] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.28.jar!/:8.5.28] at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803) [tomcat-embed-core-8.5.28.jar!/:8.5.28] at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.28.jar!/:8.5.28] at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790) [tomcat-embed-core-8.5.28.jar!/:8.5.28] at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459) [tomcat-embed-core-8.5.28.jar!/:8.5.28] at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.28.jar!/:8.5.28] at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [na:1.8.0_121] at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [na:1.8.0_121] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.28.jar!/:8.5.28] at java.lang.Thread.run(Unknown Source) [na:1.8.0_121]
Is there any major changes regarding the device access in Spring Boot 2? In that case please advise the correct method.
Answer:
I have configured manually and resolved this issue
Device detection
Add the following Java-based configuration to enable device detection in a Spring web application:
@Bean public DeviceResolverHandlerInterceptor deviceResolverHandlerInterceptor() { return new DeviceResolverHandlerInterceptor(); } @Bean public DeviceHandlerMethodArgumentResolver deviceHandlerMethodArgumentResolver() { return new DeviceHandlerMethodArgumentResolver(); } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(deviceResolverHandlerInterceptor()); } @Override public void addArgumentResolvers( List<HandlerMethodArgumentResolver> argumentResolvers) { argumentResolvers.add(deviceHandlerMethodArgumentResolver()); }
Inject the Device into your controller
@Controller public class HomeController { private static final Logger logger = LoggerFactory.getLogger(HomeController.class); @RequestMapping("/") public void home(Device device) { if (device.isMobile()) { logger.info("Hello mobile user!"); } else if (device.isTablet()) { logger.info("Hello tablet user!"); } else { logger.info("Hello desktop user!"); } } }
http://projects.spring.io/spring-mobile/
As @erhanasikoglu pointed out;
Since WebMvcConfigurerAdapter is deprecated, only need to implements WebMvcConfigurer interface inside that configuration class. (https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/config/annotation/WebMvcConfigurerAdapter.html)