Skip to content

Conversation

@TAEWOOKK
Copy link

@TAEWOOKK TAEWOOKK commented Nov 1, 2025

Description

This PR implements automatic enum description injection into OpenAPI operation descriptions.
It addresses the issue described in #3116

What's Changed

  • Added @EnumDescription annotation to mark enum fields for automatic description generation
  • Automatically extracts enum constants and their descriptions from annotated fields
  • Formats enum information as Markdown and appends to operation descriptions

Usage Example

public enum UserStatus {
    ACTIVE("Represents an active user"),
    INACTIVE("Represents an inactive user"),
    PENDING("Represents a user pending activation");

    private final String description;

    UserStatus(String description) {
        this.description = description;
    }

    public String getDescription() {
        return description;
    }
}

public class UserRequest {
    @EnumDescription  // or @EnumDescription(fieldName = "label")
    private UserStatus status;
    
    private String name;
}
image image

Technical Details

  • Customizer: EnumDescriptionOperationCustomizer implements GlobalOperationCustomizer
  • Bean Registration: Automatically registered in SpringDocConfiguration
  • Field Scanning: Recursively scans DTO classes including parent classes
  • Reflection: Uses reflection to read enum field values safely

Future Improvements

As mentioned in the original issue, we considered adding support for schema-level descriptions as well.
This could be implemented using PropertyCustomizer to inject enum descriptions into schema property descriptions.
This enhancement could be added in a future PR if there's interest.

@Mattias-Sehlstedt
Copy link
Contributor

I would suggest adding a test case for when the annotation is used. This both as an illustrative case for how to use it, but also to show that the current implementation actually behaves as expected when utilized. Use the current tests as a suggestion for how they usually are structured.

@TAEWOOKK
Copy link
Author

TAEWOOKK commented Nov 2, 2025

Thanks for the feedback!
I'd like to clarify where to add the test case. I notice there are two different test patterns in the project:

  1. springdoc-openapi-starter-common/src/test/java/org/springdoc/core/

    • Unit tests using WebApplicationContextRunner (like SpringDocHateoasConfigurationTest)
  2. springdoc-openapi-starter-webmvc-api/src/test/java/test/org/springdoc/api/v30/appXXX/

    • Integration tests following the appXXX pattern

Note that the EnumDescription annotation and EnumDescriptionOperationCustomizer are both implemented in the common module, which is why I'm unsure which test pattern to follow.

Which directory structure should I use for the @EnumDescription test case?

@Mattias-Sehlstedt
Copy link
Contributor

I prefer the second approach with an integration test as per appXXX. So one can easily see exactly how the generated OpenAPI specification looks.

@TAEWOOKK
Copy link
Author

TAEWOOKK commented Nov 3, 2025

This PR adds test cases to verify the EnumDescription annotation functionality:

  • Test for default description field
  • Test for custom fieldName (e.g., label)

The tests verify that enum information is properly added to OpenAPI operation descriptions.

Please review when convenient. Thanks!

@Mattias-Sehlstedt
Copy link
Contributor

I see now that there exists two different ways of doing integration tests, either in the x-api or the x-ui folder. Could we replicate your test so that it is also present in as a x-api test?

The difference is that the assertion is made against the entire apixxx.json, so it is easy to see exactly how the exposed specification looks like.


A bit off topic, but what is the reason for deriving the name from a potential enum value, rather than explicitly having the values in a @Schema annotation on the class that carries the information? Or are we sending a domain object out directly with the api? I always try to segment the domain and the api with pure DTO objects, that are responsible for de(serialization) and carrying any meaningful information to the client through the specification (so @Schema annotation).

So the domain is:

public enum UserStatus {
    ACTIVE,
    INACTIVE,
    PENDING;
}

while the DTO is

@Schema(name = "UserStatus", description = "...", example = "...", ....)
public enum UserStatusDTO {
    ACTIVE,
    INACTIVE,
    PENDING;
}

The current approach seems like it could potentially cause minor "leakage", since it is not intuitive that anything that goes into an enum's value could reach the client. Sure it is semi-safe, since it is opt-in, but I would always argue for a more strict domain/api segmentation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants