enum mapping, invalid enum value names

20. July 2024

In a previous article custom enum mapping I described how we can create a custom enum mapping if we would like to use different or better names for the enum values in the code than the ones used in the OpenAPI description.

It is a simple solution, it just has the drawback that we manually have to keep our enum in sync with the OpenAPI description. But I fear there is no better alternative.

Another issue with enum values is that the generated enum has to use valid Java identifiers. The processor can’t just uppercase the enum value (the Java convention for enums values) because it may not be a valid Java identifier.

In versions before 2025.3.1 openapi-processor would simply strip invalid characters at the beginning to create a valid enum identifier.

Unfortunately this was not the best solution because it may still create invalid code.

For example having an enum in the OpenAPI description that has enum values starting with numbers (which is not allowed for a java identifier)

openapi.yaml
# ...

components:
  schemas:
    AnEnum:
      type: string
      enum:
        - "1A"
        - "2A"

would create a Java enum with duplicate enum values:

BrokenEnum.java
public enum AnEnum {
    A("1A"),
    A("2A");

    // ...
}

Because of that, starting with openapi-processor 2025.3.1, it now simply prefixes all OpenAPI enum values with V (for value) that start with an invalid character:

ValidEnum.java
public enum AnEnum {
    A("V1_A"),
    A("V2_A");

    // ...
}

You may wonder why there is an underscore. The processor splits an OpenAPI name into words , the switch from number to letter is considered a word break, and then joins the words with an underscore to create the enum name…​

enum-type: string

If you want to avoid all that, an alternative would be to use enum-type option string:

mapping.yaml
openapi-processor-mapping: v13

options:
  enum-type: string

With this openapi-processor will not create Java enum classes but simply use String. Having the following OpenAPI endpoint and eum description

openapi.yaml
  # ...

  /string-enum:
    post:
      summary: api with enum in body and parameter.
      parameters:
        - name: type
          description: enum parameter
          in: query
          schema:
            $ref: '#/components/schemas/Type'
      responses:
        '204':
          description: no result

components:
  schemas:
    Type:
      type: string
      description: Type
      enum:
        - foo
        - bar

 # ...

the generated code looks like this:

Api.java
// ...

@ResponseStatus(HttpStatus.NO_CONTENT)
@PostMapping(path = "/string-enum")
void postStringEnum(@RequestParam(name = "type", required = false) String type);

// ...

Now the enum has exactly the same value as described in the OpenAPI. There is no issue anymore with translating the enum names to valid java identifiers.

No win without loss, this is a global setting, i.e. now all enums will use String, and we have lost type-safety.

validating string enum

We can reduce the pain of the lost type-safety by enabling bean validation.

openapi.yaml
openapi-processor-mapping: v13

options:
  # ...

  # use bean validations with jakarta package name
  bean-validation: jakarta

In case bean-validation and enum-type: string are configured the processor will generate an annotation and a validator to check that the enum String parameter matches any of the allowed values (as described in the OpenAPI).

The generated interface endpoint will now look like this:

Api.java
// ...

@ResponseStatus(HttpStatus.NO_CONTENT)
@PostMapping(path = "/string-enum")
void postStringEnum(@RequestParam(name = "type", required = false) @Values(values = { "foo", "bar" }) String type);

// ...

making it possible to validate type parameter.

make sure you annotate the controller with @Validated to run the @Values check.

api interface with validation
@Validated
@RestController
public class ApiController implements Api {
    // ...
}

summary

This article describes how to handle OpenAPI enum values that are no valid Java identifiers. Either by accepting the default generated enum, which may have non-perfect enum names or by using enum-type: string which will reduce type-safety.

My favorite is to use the manual enum described in custom enum mapping.

If you have an idea how to make this easier start a discussion on GitHub.