8

I am trying to generate OpenAPI (version 3.0.1) specification for my Java code. In order to achieve this I use Swagger Annotations (version 2.0.8) and Swagger Maven Plugin.

I have a problem with Enums. Say, I have two methods returning the very same Enum. In OpenAPI specification, I would like to have the single schema definition for this Enum and $ref link in both API operations. But instead I have duplicated Enum definitions in each API operations. How do I avoid this duplication without editing specification file manually?

Here is Java code with two methods returning the same Enum:

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

@Path("/properties")
@Produces("application/json")
public class TestService {
    @GET
    @Path("/enum1")
    @Operation
    @ApiResponses({
        @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Color.class)))
    })
    public Color getColor1() {
        throw new UnsupportedOperationException();
    }

    @GET
    @Path("/enum2")
    @Operation
    @ApiResponses({
        @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Color.class)))
    })
    public Color getColor2() {
        throw new UnsupportedOperationException();
    }

    public enum Color {
        RED,

        GREEN,

        BLUE
    }
}

Here is specification I would like to get:

openapi: 3.0.1
components:
    schemas:
        Color:
            type: string
            enum:
                - RED
                - GREEN
                - BLUE
paths:
  /properties/enum2:
    get:
      operationId: getColor2
      responses:
        200:
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Color'
  /properties/enum1:
    get:
      operationId: getColor1
      responses:
        200:
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Color'

And here is specification I do get:

openapi: 3.0.1
paths:
  /properties/enum2:
    get:
      operationId: getColor2
      responses:
        200:
          content:
            application/json:
              schema:
                type: string
                enum:
                - RED
                - GREEN
                - BLUE
  /properties/enum1:
    get:
      operationId: getColor1
      responses:
        200:
          content:
            application/json:
              schema:
                type: string
                enum:
                - RED
                - GREEN
                - BLUE

5
  • Q: Have you considered using a ref? swagger.io/docs/specification/using-ref Commented Jul 17, 2019 at 15:52
  • 1
    The thing is I prefer not to write Swagger file manually. I would like to have it autogenerated from my code. Actually $ref is what I need but I would like to express it in via Swagger Java annotations. Commented Jul 17, 2019 at 15:58
  • If a $ref is what you need, then a $ref is what you should use :) Look here and here for annotations examples you should be able to adapt pretty easily. Please post back what you learn. Commented Jul 17, 2019 at 16:10
  • 1
    Sorry, I was not accurate enough. Yes, $ref is what I need. But there is one more thing I need — a schema definition this $ref will refer to. Thank you for your links, but there is a little different kind of issue. It is about how to refer (with $ref) to existing schema. As for me, I need this schema to be generated (not inside operation definition, but in reusable way). Commented Jul 17, 2019 at 16:33
  • Did you manage to do it? Commented Dec 19, 2019 at 23:31

3 Answers 3

6

I am in kotlin but I added the (relatively new) @Schema(enumAsRef = true) to the enum class with success.

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

@Path("/properties")
@Produces("application/json")
public class TestService {
    @GET
    @Path("/enum1")
    @Operation
    @ApiResponses({
        @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Color.class)))
    })
    public Color getColor1() {
        throw new UnsupportedOperationException();
    }

    @GET
    @Path("/enum2")
    @Operation
    @ApiResponses({
        @ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = Color.class)))
    })
    public Color getColor2() {
        throw new UnsupportedOperationException();
    }

    @Schema(enumAsRef = true) // THIS MAKES ENUM REF
    public enum Color {
        RED,

        GREEN,

        BLUE
    }
}
Sign up to request clarification or add additional context in comments.

Comments

1

I was facing the same issue with a Dropwizard application.

My model was something like this:

public class Model {

  @Schema(name = "fields")
  @Default
  @NotNull
  private Set<CustomEnum> fields = Collections.emptySet();

  @Schema(name = "patches")
  @Default
  @NotNull
  private Set<CustomEnum> patches = Collections.emptySet();
}

and my enum:

public enum CustomEnum {
  COMPANY,
  PERSON,
  EMAIL
}

My approach was the following:

First, add the @Schema annotation to the CustomEnum enum:

@Schema(ref = "#/components/schemas/CustomEnumItem")
public enum CustomEnum {}

Note that I change the reference name to CustomEnumItem.

Second, I registered the schema and swagger configuration programmatically:

OpenAPI oas =
    new OpenAPI()
        .info(getInfo())
        .addServersItem(new Server().url(baseUrl));

var customEnumItem = new Schema<CustomEnum>();
customEnumItem.setType("string");
customEnumItem.setEnum(List.of(CustomEnum.values()));
oas.getComponents().addSchemas("CustomEnumItem", customEnumItem);

return new SwaggerConfiguration()
    .openAPI(oas)
    .readAllResources(true)
    .prettyPrint(true);

So, my swagger.json file was generated like this:

  • Schema section:
  "components" : {
    "schemas" : {
      "CustomEnumItem" : {
        "type" : "string",
        "enum" : [ "COMPANY", "PERSON", "EMAIL"]
      },
  • Model section:
"Model" : {
        "required" : [ "fields", "patches"],
        "type" : "object",
        "properties" : {
          "fields" : {
            "uniqueItems" : true,
            "type" : "array",
            "items" : {
              "$ref" : "#/components/schemas/CustomEnumItem"
            }
          },
          "patches" : {
            "uniqueItems" : true,
            "type" : "array",
            "items" : {
              "$ref" : "#/components/schemas/CustomEnumItem"
            }
          },

And my generated client code like this:

public class Model  {

    @JsonProperty("fields")
    private Set<CustomEnumItem> fields;

    @JsonProperty("patches")
    private Set<CustomEnumItem> patches;

Before this change I got something like this (two enums instead of one):

public class Model  {

    @JsonProperty("fields")
    private Set<FieldsEnum> fields;

    @JsonProperty("patches")
    private Set<PatchesEnum> patches;
}

We can find the reference to reusable enums here.

Also as @david-karlsson mentioned enumAsRef also works, but you need swagger annotations 2.1.0.

2 Comments

In the Schema section you mention PatchKeyItem ... that would be CustomEnumItem, right? Because PatchKeyItem is nowhere else to be found. Also in the Java source are 2 patchKeysItem which should probably be the defined customEnumItem.
I think yes, let me fix it
0

Write a toString in the enum class (in my example ErrorClass). Swagger takes it automatically.

@ApiResponse(responseCode = "404",description = "Errors example",content = {
                    @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorClass.class)) }),

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.