Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I did not change anything manually but for some reason, it is showing the wrong parameter name.

 return new Docket(DocumentationType.SWAGGER_2)
            .groupName("Rest API")
            .securitySchemes(Collections.singletonList(new BasicAuth(BASIC_AUTH)))
            .select()
            .apis(RequestHandlerSelectors.any())
            .paths(PathSelectors.any())
            .paths(s -> oneOf(
                "/some/**",
                "/search-controller/**").test(s))
            .build();

And the pom is

<dependency>
      <groupId>io.springfox</groupId>
      <artifactId>springfox-data-rest</artifactId>
      <version>2.9.0</version>
    </dependency>
    <dependency>
      <groupId>io.springfox</groupId>
      <artifactId>springfox-swagger-ui</artifactId>
      <version>2.9.0</version>
    </dependency>

And the controller is something like below

@RequestMapping(method = RequestMethod.GET)
    public HttpEntity<?> findAll(@RequestParam(value = "countryIsoAlpha2", required = false) final String countryKey,  final Pageable pageable){
                That is a different issue which had been fixed before but this is different. I get the parameters but with different names for some reason
– Abdullah Al Noman
                Jun 4, 2018 at 15:27

https://github.com/springfox/springfox/issues/755#issuecomment-393378205

Below is an example for creating a rule that automatically provides a convention for configuring Pageable type.

@Configuration
public class SwaggerConfig {
    @Bean
    public AlternateTypeRuleConvention pageableConvention(
            final TypeResolver resolver) {
        return new AlternateTypeRuleConvention() {
            @Override
            public int getOrder() {
                return Ordered.HIGHEST_PRECEDENCE;
            @Override
            public List<AlternateTypeRule> rules() {
                return Arrays.asList(
                        newRule(resolver.resolve(Pageable.class), resolver.resolve(pageableMixin()))
    private Type pageableMixin() {
        return new AlternateTypeBuilder()
                .fullyQualifiedClassName(
                        String.format("%s.generated.%s",
                                Pageable.class.getPackage().getName(),
                                Pageable.class.getSimpleName()))
                .withProperties(Arrays.asList(
                        property(Integer.class, "page"),
                        property(Integer.class, "size"),
                        property(String.class, "sort")
                .build();
    private AlternateTypePropertyBuilder property(Class<?> type, String name) {
        return new AlternateTypePropertyBuilder()
                .withName(name)
                .withType(type)
                .withCanRead(true)
                .withCanWrite(true);
                It worked, thank you! I just need to change "newRule" to "new AlternateTypeRule" (is a constructor) in rules() method.
– Crozeta
                May 7, 2019 at 15:15
                This worked for me, but in order for it to support multiple criteria sort, I had to replace String.class, "sort" with String[].class, "sort".
– Hassan
                Jun 19, 2020 at 14:42

Here's my expansion on the previous two examples. It also includes ApiParam annotation values and is configurable through SpringDataWebProperties settings.

Before Field Expansion:

After Field Expansion:

There are several ways to use Swagger AlternateTypeRules. They can be added directly to the Swagger Docket, added as a bean in several ways. Inspired by the above examples, here's how I did it, using an Annotation Proxy (show below) to include the additional ApiParam data:

@EnableSwagger2
@Configuration
public class SwaggerConfiguration {
    @Bean
    public AlternateTypeRuleConvention springDataWebPropertiesConvention(final SpringDataWebProperties webProperties) {
        return new AlternateTypeRuleConvention() {
            @Override
            public int getOrder() { return Ordered.HIGHEST_PRECEDENCE; }
            @Override
            public List<AlternateTypeRule> rules() {
                return singletonList(
                        newRule(Pageable.class, pageableDocumentedType(webProperties.getPageable(), webProperties.getSort()))
    private Type pageableDocumentedType(SpringDataWebProperties.Pageable pageable, SpringDataWebProperties.Sort sort) {
        final String firstPage = pageable.isOneIndexedParameters() ? "1" : "0";
        return new AlternateTypeBuilder()
                .fullyQualifiedClassName(fullyQualifiedName(Pageable.class))
                .property(property(pageable.getPageParameter(), Integer.class, ImmutableMap.of(
                        "value", "Page " + (pageable.isOneIndexedParameters() ? "Number" : "Index"),
                        "defaultValue", firstPage,
                        "allowableValues", String.format("range[%s, %s]", firstPage, Integer.MAX_VALUE),
                        "example", firstPage
                .property(property(pageable.getSizeParameter(), Integer.class, ImmutableMap.of(
                        "value", "Page Size",
                        "defaultValue", String.valueOf(pageable.getDefaultPageSize()),
                        "allowableValues", String.format("range[1, %s]", pageable.getMaxPageSize()),
                        "example", "5"
                .property(property(sort.getSortParameter(), String[].class, ImmutableMap.of(
                        "value", "Page Multi-Sort: fieldName,(asc|desc)"
                .build();
    private String fullyQualifiedName(Class<?> convertedClass) {
        return String.format("%s.generated.%s", convertedClass.getPackage().getName(), convertedClass.getSimpleName());
    private AlternateTypePropertyBuilder property(String name, Class<?> type, Map<String, Object> parameters) {
        return new AlternateTypePropertyBuilder()
                .withName(name)
                .withType(type)
                .withCanRead(true)
                .withCanWrite(true)
                .withAnnotations(Collections.singletonList(AnnotationProxy.of(ApiParam.class, parameters)));

In order to add the additional data like defaultValue and allowableValues, you have to use the .withAnnotations() method, which requires an Annotation Proxy. There are several available, here's mine (using lombok):

@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Accessors(fluent = true)
public class AnnotationProxy implements Annotation, InvocationHandler {
    @Getter
    private final Class<? extends Annotation> annotationType;
    private final Map<String, Object> values;
    public static <A extends Annotation> A of(Class<A> annotation, Map<String, Object> values) {
        return (A) Proxy.newProxyInstance(annotation.getClassLoader(),
                new Class[]{annotation},
                new AnnotationProxy(annotation, new HashMap<String, Object>(values) {{
                    put("annotationType", annotation); // Required because getDefaultValue() returns null for this call
                }}));
    public Object invoke(Object proxy, Method method, Object[] args) {
        return values.getOrDefault(method.getName(), method.getDefaultValue());
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.archisoft.mtx.controller"))
                .paths(regex("/api.*"))
                .build()
                .apiInfo(apiInfo());
    private ApiInfo apiInfo() {
        ApiInfo apiInfo = new ApiInfo(
                "Backend API Services",
                "Backend APIs for Business to Business",
                "V1.0",
                "Terms of service",
                "Sadun | Tharanga email",
                "Archisoft Global",
                "Archisoft URL");
        return apiInfo;
    @Bean
    public AlternateTypeRuleConvention pageableConvention(
            final TypeResolver resolver,
            final RepositoryRestConfiguration restConfiguration) {
        return new AlternateTypeRuleConvention() {
            @Override
            public int getOrder() {
                return Ordered.HIGHEST_PRECEDENCE;
            @Override
            public List<AlternateTypeRule> rules() {
                return singletonList(
                        newRule(resolver.resolve(Pageable.class), resolver.resolve(pageableMixin()))
    private Type pageableMixin() {
        return new AlternateTypeBuilder()
                .fullyQualifiedClassName(
                        String.format("%s.generated.%s",
                                Pageable.class.getPackage().getName(),
                                Pageable.class.getSimpleName()))
                .withProperties(Stream.of(
                        property(Integer.class, "page"),
                        property(Integer.class, "size"),
                        property(String.class, "sort")
                ).collect(toList()))
                .build();
    private AlternateTypePropertyBuilder property(Class<?> type, String name) {
        return new AlternateTypePropertyBuilder()
                .withName(name)
                .withType(type)
                .withCanRead(true)
                .withCanWrite(true);
        

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.