Swagger Models for Throwable and StackTraceElement - spring-boot

Swagger UI shows Models for StackTraceElement and Throwable objects.
I would like to configure it so that these models are not shown.
I have tried annotating the custom class for exceptions with #JsonIgnore:
/** Custom exception class to handle business validation exceptions. */
#JsonIgnoreProperties({"detailMessage", "cause", "stackTrace", "suppressed"})
public class PatientBundleException extends Exception {
#JsonIgnore
public PatientBundleException(String exceptionMessage) {
super(exceptionMessage);
}
}
Here is my Docket:
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("..."))
.paths(PathSelectors.any())
.build()
.apiInfo(apiInfo());
I am using springfox version 2.9.2
If anyone can help assist with configuring Swagger UI to not show models for Throwable and StackTraceElement, that would be much appreciated!

I fixed the issue, it turns out I was extending "Exception" on my model, when I didn't need to.

Related

SpringBoot Rest Controller Supporting both xml and json with JAXB Pojos + Custom Http Message Converters + Swagger-UI

Getting following Swagger error when I introduced custom message converters
Unable to render this definition
The provided definition does not specify a valid version field.
Please indicate a valid Swagger or OpenAPI version field. Supported version fields are swagger: "2.0" and those that match openapi: 3.0.n (for example, openapi: 3.0.0).
The error is misleading, I guess its getting confused with the converters. Any Ideas to get it fixed?
I followed - swagger-ui not working with custom XML ObjectMapper (no luck)
Background:
I have generated pojos from xsd(s) through xjc. And I have a rest endpoint which needs to support both xml and json for request/response
We got it working by following [spring documentation][1] section: 22.16.12 Message Converters
Here is what I added in MyConfig
#Configuration
#EnableWebMvc
public class MyConfig implements WebMvcConfigurer {
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new MappingJackson2HttpMessageConverter(objectMapper()));
converters.add(new MappingJackson2XmlHttpMessageConverter(xmlMapper()));
}
#Bean
#Primary
public ObjectMapper objectMapper() {
return new Jackson2ObjectMapperBuilder()
.modulesToInstall(new JaxbAnnotationModule())
.build();
}
#Bean
public XmlMapper xmlMapper() {
return new Jackson2ObjectMapperBuilder()
.indentOutput(true)
.defaultUseWrapper(false)
.serializationInclusion(JsonInclude.Include.NON_EMPTY)
.modulesToInstall(new JaxbAnnotationModule())
.createXmlMapper(true)
.build();
}
}
and my controller
// all the open api annotations //
#RequestMapping(value = "/run",
produces = {"application/json", "application/xml"},
consumes = {"application/json", "application/xml"},
method = RequestMethod.POST)
public ResponseEntity<MyResponse> run(#RequestBody MyRequest request) {
Ok its about which objectMapper. I had to clean up and remove '#primary' which made the trick in MyConfig
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
return new MappingJackson2HttpMessageConverter(new Jackson2ObjectMapperBuilder()
.modulesToInstall(new JaxbAnnotationModule())
.build());
}
#Bean
public MappingJackson2XmlHttpMessageConverter mappingJackson2XmlHttpMessageConverter() {
return new MappingJackson2XmlHttpMessageConverter(new Jackson2ObjectMapperBuilder()
.indentOutput(true)
.defaultUseWrapper(false)
.serializationInclusion(JsonInclude.Include.NON_EMPTY)
.modulesToInstall(new JaxbAnnotationModule())
.createXmlMapper(true)
.build());
}

How set SpringFox to show two (or more) versions of the Rest API using Spring Boot?

I'm trying to figure out how manage two (or more) version of my API endpoints using Spring Fox.
To version my APIs, I'm using the Versioning through content negotiation, also know as Versioning using Accept header. The versions of each endpoint are controlled individually using the header information. Per example, for the version one I use the attribute produces:
#Override
#PostMapping(
produces = "application/vnd.company.v1+json")
public ResponseEntity<User> createUser(
For version two, I use:
#Override
#PostMapping(
produces = "application/vnd.company.v2+json",
consumes = "application/vnd.company.v2+json")
public ResponseEntity<User> createUserVersion2(
I not use consumes for the first (v1) version, so if the client use only application/json on the call the first version will be called by default.
I would like to show the two version on the Swagger UI. How to do that?
It's very simple. Just create one Docket for each version.
Example, the first version:
#Bean
public Docket customImplementation(
#Value("${springfox.documentation.info.title}") String title,
#Value("${springfox.documentation.info.description}") String description) {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo(title, description, "1.0"))
.groupName("v1")
.useDefaultResponseMessages(false)
.securitySchemes(newArrayList(apiKey()))
.pathMapping("/api")
.securityContexts(newArrayList(securityContext())).select()
.apis(e -> Objects.requireNonNull(e).produces().parallelStream()
.anyMatch(p -> "application/vnd.company.v1+json".equals(p.toString())))
.paths(PathSelectors.any())
.build();
}
And for version two:
#Bean
public Docket customImplementationV2(
#Value("${springfox.documentation.info.title}") String title,
#Value("${springfox.documentation.info.description}") String description) {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo(title, description, "2.0"))
.groupName("v2")
.select()
.apis(e -> Objects.requireNonNull(e).produces()
.parallelStream()
.anyMatch(p -> "application/vnd.company.v2+json".equals(p.toString())))
.build();
}
The secret here is filter the available endpoints by the produces attribute.
The Swagger-UI will show the two versions on the combo:
This code needs to be on a class annotated with #Configuration. You also need to enable the Swagger with #EnableSwagger2.
As mentioned by Dherik you can create Docket for each version. But to filter here I have tried using Predicate and custom controller annotations.
Configuration class annotated with #Configuration and #EnableSwagger2
import com.google.common.base.Predicate;
#Bean
public Docket apiV30() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("v30")
.select()
.apis(selectorV30())
.paths(PathSelectors.any()).build().apiInfo(apiEndPointsInfo());
}
private Predicate<RequestHandler> selectorV30(){
return new Predicate<RequestHandler>() {
#Override
public boolean apply(RequestHandler input) {
return input.findControllerAnnotation(SwaggerDocV30.class).isPresent();
}
};
}
#Bean
public Docket apiV31() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("v31")
.select()
.apis(selectorV31())
.paths(PathSelectors.any()).build().apiInfo(apiEndPointsInfo());
}
private Predicate<RequestHandler> selectorV31(){
return new Predicate<RequestHandler>() {
#Override
public boolean apply(RequestHandler input) {
return input.findControllerAnnotation(SwaggerDocV31.class).isPresent();
}
};
}
Custom Annotation class : SwaggerDocV30
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
public #interface SwaggerDocV30 {
}
Custom Annotation class : SwaggerDocV31
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
public #interface SwaggerDocV31 {
}
Finally annotate your controllers with #SwaggerDocV30 or #SwaggerDocV31
#SwaggerDocV30
#Controller
public class MyController extends AbstractController {}
Or
#SwaggerDocV31
#Controller
public class MyController extends AbstractController {}]

Is it possible to implement AlternateTypeRules functionallity with annotation?

I've got following issue - https://github.com/springfox/springfox/issues/2373 and I fixed it with the following code:
#Bean
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2)
.alternateTypeRules(AlternateTypeRules.newRule(TestCarResource.Car.Id.class, String.class));
}
Can I mark my Car.Id class with any annotation to remove this boilerplate code?

Is there a way I can stop springfox swagger from scanning the model classes?

I'm currently using Springfox Swagger to document my spring boot application with a Java config. My API starts in about 75 seconds, (it was originally 20 secs without Springfox) with the whole scanning process. I currently just need the controller information without any model info. Is there a way I can exclude model scanning from the startup process in order to make my API start faster? And are there any other ways to make it faster? I'm using swagger 1.2
There is a way to prevent Sprinfox framework from generating a Swagger model or parameter information of specified ignored types. You have to use the method ignoredParameterTypes in SwaggerSpringMvcPlugin or Docket class to let it know the types to be ignored.
Swagger 1 Example
Here is an example of Swagger 1 Java configuration with ignored types. It definitely had an impact on my application startup time.
#Configuration
#EnableSwagger
public class SwaggerConfiguration {
#Autowired
private SpringSwaggerConfig springSwaggerConfig;
#Bean
public SwaggerSpringMvcPlugin api() {
Class[] clazz = {MyClassA.class, MyClassB.class};
return new SwaggerSpringMvcPlugin(this.springSwaggerConfig)
.apiInfo(apiInfo())
...
.ignoredParameterTypes(clazz);
}
private ApiInfo apiInfo() {
...
}
}
Swagger 2 Example
Here is an example of Swagger 2 Java configuration with ignored types,
#Configuration
#EnableSwagger2
public class SwaggerConfiguration {
#Bean
public Docket api() {
Class[] clazz = {MyClassA.class, MyClassB.class};
return new Docket(DocumentationType.SWAGGER_2)
.groupName("my-group")
.select()
.paths(PathSelectors.any())
.build()
.apiInfo(apiInfo())
.ignoredParameterTypes(clazz);
}
private ApiInfo apiInfo() {
...
}
}
With swagger 3.0 #Hidden annotation is available which is present at package io.swagger.v3.oas.annotations
It can be used on top of the class or method to exclude the resource in swagger documentation.
Springfox Swagger2 acquire UI data through GET /v2/api-docs, which will mapping to springfox.documentation.swagger2.web.Swagger2Controller.getDocumentation().So you can just create a bean to take place of 'ServiceModelToSwagger2Mapper' with your sanning logic:
#Primary
#Component
class CustomServiceModelToSwagger2Mapper : ServiceModelToSwagger2MapperImpl() {
override fun mapDocumentation(from: Documentation?): Swagger? {
// scanning logics...
}
}
refer to my another related answer : https://stackoverflow.com/a/64057512/14332259

Hide return value from a Spring MVC controller in SpringFox 2

I have an async Spring MVC controller that returns Future. SpringFox 2 renders it as this:
How do I remove it? Thank you in advance!
I resolved the issue by adding the following method call to SprinfFox's Docket:
.genericModelSubstitutes(ResponseEntity.class, CompletableFuture.class)
Hope it will help someone.
It does not work with types.
So, let's suppose that this is the controller method:
public CompletableFuture<ResponseEntity<ResponseDTO>> getDTO() {
return CompletableFuture.completedFuture(ResponseEntity.ok(new ResponseDTO());
}
Adding just the configuration:
.genericModelSubstitutes(ResponseEntity.class, CompletableFuture.class)
.directModelSubstitute(CompletableFuture.class, java.lang.Void.class)
it will not work. The method needs to be modified to:
public CompletableFuture getDTO() {
return CompletableFuture.completedFuture(ResponseEntity.ok(new ResponseDTO());
}
Then the CompletableFuture definition will disappear from OpenAPI specs.
Found a better approach. I'm using springfox version 2.8.0. If you have a look at their docs (RTFM) you can have type classes resolved to POJO using a type adapter. An example for this configuration is like this:
import com.fasterxml.classmate.TypeResolver;
#Configuration
#EnableSwagger2
public class SpringFoxConfig {
#Autowired
private TypeResolver typeResolver;
#Bean
public Docket apiDocket() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("base package"))
.paths(PathSelectors.any())
.build()
.genericModelSubstitutes(ResponseEntity.class)
.alternateTypeRules(
newRule(typeResolver.resolve(CompletableFuture.class,
typeResolver.resolve(ResponseEntity.class, WildcardType.class)),
typeResolver.resolve(WildcardType.class)))
.useDefaultResponseMessages(false)
.pathMapping("/");
}
And the controller method can be defined with types:
public CompletableFuture<ResponseEntity<ResponseDTO>> getDTO() {
return CompletableFuture.completedFuture(ResponseEntity.ok(new ResponseDTO());
}

Resources