I am using swagger on my springboot project.
The problem appears for endpoint which returns the entity with list of MonetaryAmount i.e. (List<MonetaryAmount> rates
)
Swagger-ui shows incorrect data for such endpoints as:
{
"rates": [
null
]
}
However I expect to see each MonetaryAmount value as pair of Double and String. Smth like this:
{
"rates": [
{"currency":"EUR", "rate": 12.23}
]
}
I tried to use directModelSubstitute but it seems it is not working for List.
Here is my model :
public class CurrencyRatesResponse implements Serializable {
private List<MonetaryAmount> rates;
public CurrencyRatesResponse() {
}
public CurrencyRatesResponse(List<MonetaryAmount> rates) {
this.rates = rates;
}
public List<MonetaryAmount> getRates() {
return rates;
}
public void setRates(List<MonetaryAmount> rates) {
this.rates = rates;
}
}
And here is an example of my endpoint
@RequestMapping(path = "/public/rates", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public CurrencyRatesResponse getRates() {...}
Generated swagger JSON:
"/public/rates":{
"get":{
"tags":[
"rate-endpoint"
],
"summary":"getRates",
"operationId":"getRatesUsingGET",
"produces":[
"application/json;charset=UTF-8"
],
"parameters":[
{
....
}
],
"responses":{
"200":{
"description":"OK",
"schema":{
"$ref":"#/definitions/CurrencyRatesResponse"
}
},
"401":{
"description":"Unauthorized"
},
"403":{
"description":"Forbidden"
},
"404":{
"description":"Not Found"
}
}
}
}
} ....
"CurrencyRatesResponse":{
"type":"object",
"properties":{
"rates":{
"type":"array",
"items":{
"$ref":"#/definitions/MonetaryAmount"
}
}
},
"title":"CurrencyRatesResponse"
},
There are several steps to achieve this.
First of all, we need proper objectMapper soMonetaryAmount
gets mapped to proper object with two fields currency
and rate
. To achieve this we need to add custom module for the springfox's objectMapper.
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import org.zalando.jackson.datatype.money.MoneyModule;
import springfox.documentation.schema.configuration.ObjectMapperConfigured;
@Component
public class SwaggerJacksonModule implements ApplicationListener<ObjectMapperConfigured> {
@Override
public void onApplicationEvent(ObjectMapperConfigured event) {
event.getObjectMapper().registerModule(new MoneyModule());
}
}
Explanation: We add a listener to the springfox's ObjectMapperConfigured
event and whenever the event is triggered we simply get the mapper and register our module. I use Zalando's Jackson Datatype Money library so that I don't write my own.
Next step would be to work on actual Swagger representation. Let's create our own representation object MonetaryWrapper
which we gonna use it to substitute MonetaryAmount
.
public class MonetaryWrapper {
private BigDecimal amount;
private String currency;
// getters and setters (getters are important)
}
In order to get Single object representations right it's enough to add .directModelSubstitute(MonetaryAmount.class, MonetaryWrapper.class)
to the Docket
object.
BUT It's not that simple for collections. e.g List in this case. We need add Special AlternateTypeRule
object into Docket
object in order for lists show properly.
More details on this topic in springfox's documentation
Something like this:
TypeResolver resolver = new TypeResolver();
AlternateTypeRule monetaryAmountListRule =
newRule(resolver.resolve(List.class, MonetaryAmount.class),
resolver.resolve(List.class, MonetaryWrapper.class))
And finally our Docket
bean would look something like this:
@Bean
public Docket productApi() {
TypeResolver resolver = new TypeResolver();
AlternateTypeRule monetaryAmountListRule =
newRule(resolver.resolve(List.class, MonetaryAmount.class),
resolver.resolve(List.class, MonetaryWrapper.class));
return new Docket(DocumentationType.SWAGGER_2)
.alternateTypeRules(monetaryAmountListRule)
.directModelSubstitute(MonetaryAmount.class, MonetaryWrapper.class)
.select().apis(RequestHandlerSelectors.basePackage("com.swagger.test"))
.paths(PathSelectors.regex("/public.*")).build();
}
And some demo screenshots here:
Demo when executing request:
Demo just for object description:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With