Issue
My application uses spring-boot 2.5.5.
I set a property for Tomcat at application startup to allow encoded slash in @PathVariable
:
@SpringBootApplication
public class App {
public static void main(String[] args) {
System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true");
SpringApplication.run(App.class, args);
}
}
Everything works fine when I start the app, except in my integration tests :
@ActiveProfiles("test-connected")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@ExtendWith(SpringExtension.class)
class GlobalFullTest {
When I debug the org.apache.tomcat.util.buf.UDecoder
class : I see that the property org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH
is null
when class is loaded, so a default value false
is set.
I tried the following :
- Adding
System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true");
in the@BeforeAll
method of my test - Adding
properties = { "org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true" }
in the@SpringBootTest
annotation. - Adding
org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH: true
in myapplication-test-connected.yaml
- Using
WebServerFactoryCustomizer
:
@Configuration
public class WebServerConfiguration {
@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> customizer() {
return factory -> factory.addConnectorCustomizers(connector -> connector.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true"));
}
}
But none of these worked : when the property is retrieved by org.apache.tomcat.util.buf.UDecoder
class, its value is always null
.
How could I set the property before the org.apache.tomcat.util.buf.UDecoder
class is loaded ?
Solution
Referring to How to set environment variable or system property in spring tests?
The simplest way
Follow add static initializer in the class
...
class GlobalFullTest {
static {
System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true");
}
...
}
down side is we need to copy that for every test.
Clean way
create ApplicationContextInitializer, which can be reused in the Spring application and any other test.
public class CustomApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>
{
@Override
public void initialize(ConfigurableApplicationContext applicationContext)
{
System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true");
}
}
...
@ContextConfiguration(initializers = CustomApplicationContextInitializer.class,...)
class GlobalFullTest {
...
Answered By - samabcde
Answer Checked By - Senaida (JavaFixing Volunteer)