'Spring Boot allow Square brackets for nested objects in Request Parameters
I'm using Spring Boot 2.6.7 and org.springdoc:springdoc-openapi-ui:1.6.7 to run swagger ui with OpenApi 3 definition along with my backend.
My Setup
@GetMapping(value = "/hello", produces = MediaType.APPLICATION_JSON_VALUE)
public String getHello(HelloInput input) {
return "";
}
public class HelloInput {
public NestedInput nested;
// getter setter omitted
}
public class NestedInput {
public boolean a = true;
// getter setter omitted
}
This produces the following request when trying it out in swagger ui:
curl -X 'GET' \
'http://localhost:8080/api/hello?nested[a]=true' \
-H 'accept: application/json'
The Problem
However, when I execute this call I get the following Exception:
org.springframework.beans.InvalidPropertyException: Invalid property 'nested[a]' of bean class [com.proj.App.rest.explore.HelloInput]: Property referenced in indexed property path 'nested[a]' is neither an array nor a List nor a Map; returned value was [com.proj.App.rest.explore.NestedInput@68d1c7c4]
What do I need
The square braces notation causes this issue. The same call with dot notation does not cause exceptions:
curl -X 'GET' \
'http://localhost:8080/api/hello?nested.a.=true' \
-H 'accept: application/json'
Is there a way to either:
A: Configure Spring Boot in a way that it accepts the square brackets notation also for object properties and not just maps, lists etc.
OR
B: Configure Swagger UI in a way that it uses the dot notation when constructing the calls?
What did I already try
I already did a lot of research, but could not find other people with this problem.
I found a feature request for Spring to support squared brackets, but it was rejected: https://github.com/spring-projects/spring-framework/issues/20052
I found basically the same question, but the answers seem to be outdated, since the RelaxedDataBinder does not seem to be a part of Spring Boot 2.6.7 anymore: Customize Spring @RequestParam Deserialization for Maps and/or Nested Objects
Other than that, no one else seems to have this problem. Am I completely misunderstanding how Spring Boot handles Request Parameters and this problem occurs because I'm breaking some convention on how to handle GET Requests with many parameters?
Solution 1:[1]
CAUTION: Hacky workaround for making swagger ui use dots instead of squared braces (probably breaks in a lot of scenarios)
Swagger Ui offers to define a requestInterceptor, that takes outbound requests and offers the user to change them.
When using Springdoc, swagger ui downloads a swagger-initializer.js
for configuration of swagger ui.
This file is generated by an instance of a SwaggerIndexPageTransformer
. The default instance already creates a requestInterceptor
for CORS requests. I took that code and adapted it to change all requests with the squared braces notation to the dot notation.
For reference see AbstractSwaggerIndexTransformer#addCRSF
Workaround
First define a Configuration that offers a SwaggerIndexTransformer
Bean:
@Configuration
public class OpenApiConfig {
@Bean
public SwaggerIndexTransformer swaggerIndexTransformer(
SwaggerUiConfigProperties a,
SwaggerUiOAuthProperties b,
SwaggerUiConfigParameters c,
SwaggerWelcomeCommon d) {
return new CustomSwaggerIndexTransformer(a, b, c, d);
}
}
Next implement the CustomSwaggerIndexTransformer
, that now edits the swagger-initializer.js
to add a requestInterceptor
function, that replaces every [
with a .
and removes all ]
.
public class CustomSwaggerIndexTransformer extends SwaggerIndexPageTransformer {
private static final String PRESETS = "presets: [";
...
@Override
protected String defaultTransformations(InputStream inputStream) throws IOException {
String html = super.defaultTransformations(inputStream);
html = addDottedRequests(html);
return html;
}
protected String addDottedRequests(String html) {
String interceptorFn = """
requestInterceptor: (request) => {
request.url = request.url.replaceAll("[", ".").replaceAll("]", "");
return request;
},
""" + PRESETS;
return html.replace(PRESETS, interceptorFn);
}
}
Limitations
- This probably breaks working behavior when swagger ui uses squared braces for Maps, Arrays and Lists
- This does not work when CORS is enabled for springdoc, since it also defines a requestInterceptor, in that case the javascript should somehow be incorporated into the CORS requestInterceptor function.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Jonathan |