Spring Boot 2 cannot read properties as strings
When migrating a Spring Boot application from Spring Boot 1.4.0 to Spring Boot 2, I started getting errors when trying to read properties from my .properties file.
In the properties file, the property is defined as:
environment=dev
In one of my classes, I import the properties via @Value
annotations, as follows:
@Getter
@Setter
public class CustomUserFilter extends SwitchUserFilter {
...
@Value("${environment}")
private String environment;
...
The above class overrides org.springframework.security.web.authentication.switchuser.SwitchUserFilter
, enabling users to switch roles.
Prior to Spring Boot 1.4.0, I was able to import this property as a string into my class. However, since migrating to Spring Boot 2, I get the following compile-time error:
Error:(43, 20) java: getEnvironment() in demo.config.CustomUserFilter
cannot implement getEnvironment() in
org.springframework.core.env.EnvironmentCapable return type
java.lang.String is not compatible with
org.springframework.core.env.Environment
I’m not sure why this is the case. I also tried changing the type of this variable to Environment (org.springframework.core.env.Environment) (
shown below):
...
@Value("${environment}")
private Environment environment;
...
, but then I started getting the following error:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'switchUserFilter': Unsatisfied dependency expressed through field 'environment'; nested exception is org.springframework.beans.ConversionNotSupportedException: Failed to convert value of type 'java.lang.String' to required type ' org.springframework.core.env.Environment'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'org.springframework.core.env.Environment': no matching editors or conversion strategy found
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:584)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:370)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1336)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:572)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204)
at org.springframework.boot.web.servlet.ServletContextInitializerBeans.getOrderedBeansOfType(ServletContextInitializerBeans.java:226)
at org.springframework.boot.web.servlet.ServletContextInitializerBeans.addAsRegistrationBean(ServletContextInitializerBeans.java:182)
at org.springframework.boot.web.servlet.ServletContextInitializerBeans.addAsRegistrationBean(ServletContextInitializerBeans.java:177)
at org.springframework.boot.web.servlet.ServletContextInitializerBeans.addAdaptableBeans(ServletContextInitializerBeans.java:159)
at org.springframework.boot.web.servlet.ServletContextInitializerBeans.<init>(ServletContextInitializerBeans.java:81)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.getServletContextInitializerBeans(ServletWebServerApplicationContext.java:261)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.selfInitialize(ServletWebServerApplicationContext.java:234)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:185)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:154)
... 52 more
Caused by: org.springframework.beans.ConversionNotSupportedException: Failed to convert value of type 'java.lang.String' to required type 'org.springframework.core.env.Environment '; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'org.springframework.core.env.Environment': no matching editors or conversion strategy found
at org.springframework.beans.TypeConverterSupport.doConvert(TypeConverterSupport.java:77)
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:60)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1089)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1062)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:581)
... 70 more
Caused by: java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'org.springframework.core.env.Environment': no matching editors or conversion strategy found
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:299)
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:117)
at org.springframework.beans.TypeConverterSupport.doConvert(TypeConverterSupport.java:70)
... 74 more
Any clues about what might go wrong? I’m using Spring Boot 2.0, Spring 5, Java 11, and Tomcat 8.5.35. Thanks!
Solution
The problem has nothing to do with Spring Boot. My class above extends org.springframework.security.web.authentication.switchuser.SwitchUserFilter
, which further extends org.springframework.web.filter.GenericFilterBean.
This GenericFilterBean
class also has a property, private Environment environment;
。 In addition, this class was modified in the Spring 5 release to include getter methods for this property. Spring 5 introduced getEnvironment() with a return type of Environment
in the GenericFilterBean
class, which is different from my getEnvironment()
return type of String
.
To avoid this conflict, I just changed my property name from environment
to env
and everything worked fine.