When using Springfox to generate Swagger documentation for your Spring REST API, the default model definitions may not always match what you want to expose. Springfox provides ModelPropertyBuilderPlugin and ModelBuilderPlugin to let you customize how models and their properties appear in the Swagger UI.
Why Customize Models?
Common reasons to customize your Swagger models:
- Hide internal fields (passwords, audit columns) from the API docs
- Add example values to properties
- Change the displayed type (e.g., show a
Longasstringfor IDs) - Add custom descriptions or validation annotations
- Show different models for request vs. response
Using ModelPropertyBuilderPlugin
The ModelPropertyBuilderPlugin lets you modify individual properties of a model. Implement the supports and apply methods:
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.schema.ModelPropertyBuilderPlugin;
import springfox.documentation.schema.ModelPropertyBuilder;
import springfox.documentation.spi.schema.contexts.ModelPropertyContext;
@Component
@Order(Ordered.LAST)
public class CustomModelPropertyPlugin implements ModelPropertyBuilderPlugin {
@Override
public boolean supports(DocumentationType delimiter) {
return true;
}
@Override
public void apply(ModelPropertyContext context) {
// Add a description to specific fields
context.getBeanPropertyDefinition()
.ifPresent(property -> {
String name = property.getName();
if ("id".equals(name)) {
context.getBuilder()
.description("Unique identifier")
.example("550e8400-e29b-41d4-a716-446655440000")
.type(new TypeResolver().resolve(String.class));
}
});
// Hide fields annotated with @ApiHide
context.getBeanPropertyDefinition()
.ifPresent(property -> {
if (property.getField() != null
&& property.getField().getAnnotation(ApiHide.class) != null) {
context.getBuilder().hidden(true);
}
});
}
}Using ModelBuilderPlugin
The ModelBuilderPlugin lets you customize the model as a whole — for example, changing the description or ID of the model:
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.schema.ModelBuilderPlugin;
import springfox.documentation.spi.schema.contexts.ModelContext;
import springfox.documentation.schema.Model;
@Component
public class CustomModelPlugin implements ModelBuilderPlugin {
@Override
public boolean supports(DocumentationType delimiter) {
return true;
}
@Override
public void apply(ModelContext context) {
// Set a custom description for specific models
if (context.getType().getErasedType().equals(User.class)) {
context.getBuilder()
.description("User account information");
}
}
}Different Request vs. Response Models
One of the most common customizations is showing different fields in request and response. For example, you might want to exclude id from create requests but include it in responses.
Springfox uses ModelContext to determine whether the model is for a request or response:
@Override
public void apply(ModelPropertyContext context) {
ModelContext modelContext = (ModelContext) context.getParent();
// Check if this is a request (input) or response (output) model
boolean isResponse = modelContext.isReturnType();
context.getBeanPropertyDefinition().ifPresent(property -> {
String name = property.getName();
if ("id".equals(name) && !isResponse) {
context.getBuilder().hidden(true);
}
});
}Annotation-Based Hiding
Create a custom annotation to mark fields that should be hidden from Swagger:
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiHide {
}Then in your model:
public class User {
private String id;
private String name;
@ApiHide
private String internalNote; // Won't appear in Swagger docs
// getters and setters
}And in your ModelPropertyBuilderPlugin:
@Override
public void apply(ModelPropertyContext context) {
context.getBeanPropertyDefinition().ifPresent(property -> {
if (property.getField().getAnnotation(ApiHide.class) != null) {
context.getBuilder().hidden(true);
}
});
}Registering Plugins
Spring Boot will auto-detect your plugin if it’s annotated with @Component. Make sure your configuration class scans the package:
@Configuration
@ComponentScan("com.example.swagger")
public class SwaggerConfig {
// ...
}