Skip to content

[BUG] [JAVA] Broken code generation when using format: enum #24950

Open

Description

@jglick

Bug Report Checklist

  • Have you provided a full/minimal spec to reproduce the issue?
  • Have you validated the input using an OpenAPI validator? N/A I guess?
  • Have you tested with the latest master to confirm the issue still exists?
  • Have you searched for related issues/PRs?
  • What's the actual output vs expected output?
  • [Optional] Sponsorship to speed up the bug fix or feature request (example)
Description

#24812 breaks code generation in my project (confirmed via git bisect). Noted tangentially in another issue #24942 (and was reproducible in that context) but filing here explicitly with a smaller test case as requested by @Mattias-Sehlstedt + @jpfinne.

openapi-generator version

7.26.0-SNAPSHOT as built from 993bfc9; a regression since 7.25.0

OpenAPI declaration file content or url
Reproduction sources

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>test</groupId>
  <artifactId>enum-format-repro</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <dependencies>
    <dependency>
      <groupId>org.openapitools</groupId>
      <artifactId>jackson-databind-nullable</artifactId>
      <version>0.2.6</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.17.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.datatype</groupId>
      <artifactId>jackson-datatype-jsr310</artifactId>
      <version>2.17.0</version>
    </dependency>
    <dependency>
      <groupId>com.google.code.findbugs</groupId>
      <artifactId>jsr305</artifactId>
      <version>3.0.2</version>
    </dependency>
    <dependency>
      <groupId>javax.annotation</groupId>
      <artifactId>javax.annotation-api</artifactId>
      <version>1.3.2</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.openapitools</groupId>
        <artifactId>openapi-generator-maven-plugin</artifactId>
        <!-- Switch between 7.25.0 (passes) and 7.26.0-SNAPSHOT (fails) -->
        <version>7.25.0</version>
        <!--
        <version>7.26.0-SNAPSHOT</version>
        -->
        <executions>
          <execution>
            <goals>
              <goal>generate</goal>
            </goals>
            <configuration>
              <inputSpec>${project.basedir}/src/main/openapi/test.yaml</inputSpec>
              <generatorName>java</generatorName>
              <library>native</library>
              <generateApiTests>false</generateApiTests>
              <generateModelTests>false</generateModelTests>
              <generateApiDocumentation>false</generateApiDocumentation>
              <generateModelDocumentation>false</generateModelDocumentation>
              <apiPackage>test.api</apiPackage>
              <modelPackage>test.model</modelPackage>
              <configOptions>
                <sourceFolder>src/main/java</sourceFolder>
              </configOptions>
            </configuration>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.13.0</version>
        <configuration>
          <source>11</source>
          <target>11</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

/tmp/enum-repro/src/main/openapi/test.yaml:

openapi: 3.0.3
info:
  title: Enum format test
  version: 1.0.0
paths: {}
components:
  schemas:
    Ruleset:
      type: object
      properties:
        bypassMode:
          type: string
          format: enum
          enum:
            - RULESET_BYPASS_MODE_UNSPECIFIED
            - RULESET_BYPASS_MODE_ALLOWED
            - RULESET_BYPASS_MODE_DISABLED
Generation Details

as above

Steps to reproduce

mvn clean compile with 7.25.0: no error

mvn clean install -Dmaven.test.skip=true -Dmaven.javadoc.skip=true -am -pl modules/openapi-generator-maven-plugin on trunk sources of the generator, then building test project with 7.26.0:

[ERROR] COMPILATION ERROR : 
[INFO] -------------------------------------------------------------
[ERROR] /tmp/enum-repro/target/generated-sources/openapi/src/main/java/test/model/Ruleset.java:[28,18] cannot find symbol
  symbol:   class Enum
  location: package test.model
[ERROR] /tmp/enum-repro/target/generated-sources/openapi/src/main/java/test/model/Ruleset.java:[45,41] method valueOf in class java.lang.Enum<E> cannot be applied to given types;
  required: java.lang.Class<T>,java.lang.String
  found:    java.lang.String
  reason: cannot infer type-variable(s) T
    (actual and formal argument lists differ in length)
[ERROR] /tmp/enum-repro/target/generated-sources/openapi/src/main/java/test/model/Ruleset.java:[47,37] method valueOf in class java.lang.Enum<E> cannot be applied to given types;
  required: java.lang.Class<T>,java.lang.String
  found:    java.lang.String
  reason: cannot infer type-variable(s) T
    (actual and formal argument lists differ in length)
[ERROR] /tmp/enum-repro/target/generated-sources/openapi/src/main/java/test/model/Ruleset.java:[49,38] method valueOf in class java.lang.Enum<E> cannot be applied to given types;
  required: java.lang.Class<T>,java.lang.String
  found:    java.lang.String
  reason: cannot infer type-variable(s) T
    (actual and formal argument lists differ in length)
[INFO] 4 errors 
[INFO] -------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE

The diff to the generated source file:

27a28
> import test.model.Enum;
44c45
<     RULESET_BYPASS_MODE_UNSPECIFIED(String.valueOf("RULESET_BYPASS_MODE_UNSPECIFIED")),
---
>     RULESET_BYPASS_MODE_UNSPECIFIED(Enum.valueOf("RULESET_BYPASS_MODE_UNSPECIFIED")),
46c47
<     RULESET_BYPASS_MODE_ALLOWED(String.valueOf("RULESET_BYPASS_MODE_ALLOWED")),
---
>     RULESET_BYPASS_MODE_ALLOWED(Enum.valueOf("RULESET_BYPASS_MODE_ALLOWED")),
48c49
<     RULESET_BYPASS_MODE_DISABLED(String.valueOf("RULESET_BYPASS_MODE_DISABLED"));
---
>     RULESET_BYPASS_MODE_DISABLED(Enum.valueOf("RULESET_BYPASS_MODE_DISABLED"));
50c51
<     private String value;
---
>     private Enum value;
52c53
<     BypassModeEnum(String value) {
---
>     BypassModeEnum(Enum value) {
57c58
<     public String getValue() {
---
>     public Enum getValue() {
67c68
<     public static BypassModeEnum fromValue(String value) {
---
>     public static BypassModeEnum fromValue(Enum value) {
Related issues/PRs

not that I could see

Suggest a fix

FWIW Claude claims

The intent of typeMapping.put("enum", "Enum") was to support the new getCommonSchemaType discriminator-resolution path. The fix should not pollute the global typeMapping; instead, handle it inline inside getCommonSchemaType / getCommonTypeMapping without registering "enum" as a general-purpose format mapping — or, at minimum, add importMapping.put("Enum", "java.lang.Enum") and fix the Mustache template so the generated code uses the correct BypassModeEnum.valueOf(String) call rather than Enum.valueOf(String) (the two-argument java.lang.Enum.valueOf(Class<T>, String) is unrelated to what the template emits).

Activity

  1. jpfinne commented on Sep 16, 2026

    @jpfinne
    Contributor

    @jglick we could use typeMapping.put("__discriminatorEnum__", "Enum") instead of "enum"

  2. jglick commented on Sep 16, 2026

    @jglick
    Author

    What an enum is in an API seems intuitive enough. I have no idea what a “discriminator” would be. Some sort of advanced usage I guess. All I know is that the change generated uncompilable code for the basic cases, so it would better be reverted until the problem is studied more closely. Otherwise 7.26.0 could be released with a critical regression.

    (Does this repo not have tests that assert that generated code compiles? Would be logistically hard to set up for all languages, but given that the generator is written in Java, it would seem like a good first step to at least verify that generated Java code is compilable.)

  3. jpfinne commented on Sep 16, 2026

    @jpfinne
    Contributor

    @jglick using format: enum is really an edge case. Not at all a "basic case". So I think the large majority of user won't be affected by this bug.

    properties:
            bypassMode:
              type: string
              format: enum
              enum:
                - RULESET_BYPASS_MODE_UNSPECIFIED
                - RULESET_BYPASS_MODE_ALLOWED
                - RULESET_BYPASS_MODE_DISABLED
    

    To the question in openapi, is it common to use format: enum AI tells me

    No, format: enum is not part of the OpenAPI specification.
    
    
    Some organizations add custom formats for internal tooling:
    but this is a vendor convention, not a standard OpenAPI feature.
    If you're using OpenAPI Generator, 
    I would recommend relying solely on enum: and avoiding format: enum unless a specific internal tool requires it.
    

    The OpenAPI Generator uses format for type mappings (using a config like --type-mappings string+enum=MyCustomEnum), so that probably produces the side effect.

    The repo has hundred of generated samples that are compiled (172 java, 70 spring). Unit tests also use JavaFileAssert that detects basic syntax errors.

    OneOf and Discriminators are REALLY complex with zillion of combination.

    Sorry if my PR gives you regression.

  4. changed the title [-][BUG] [JAVA] Broken code generation related to `Enum`[/-] [+][BUG] [JAVA] Broken code generation when using `format: enum`[/+] on Sep 16, 2026
  5. jglick commented on Sep 16, 2026

    @jglick
    Author

    Ah, it breaks only when

    format: enum

    is included. Is this syntax illegal, or legitimate but just weird? (No warnings are printed during code generation that I could see.)

    With that line removed, a compilable nested type is generated

    public enum BypassModeEnum {
      RULESET_BYPASS_MODE_UNSPECIFIED(String.valueOf("RULESET_BYPASS_MODE_UNSPECIFIED")),
    
      RULESET_BYPASS_MODE_ALLOWED(String.valueOf("RULESET_BYPASS_MODE_ALLOWED")),
    
      RULESET_BYPASS_MODE_DISABLED(String.valueOf("RULESET_BYPASS_MODE_DISABLED"));
    
      private String value;
    
      BypassModeEnum(String value) {
        this.value = value;
      }
    
      @JsonValue
      public String getValue() {
        return value;
      }
    
      @Override
      public String toString() {
        return String.valueOf(value);
      }
    
      @JsonCreator
      public static BypassModeEnum fromValue(String value) {
        for (BypassModeEnum b : BypassModeEnum.values()) {
          if (b.value.equals(value)) {
            return b;
          }
        }
        throw new IllegalArgumentException("Unexpected value '" + value + "'");
      }
    }

    (Note that this is not idiomatic Java. String.valueOf on a not-null constant is redundant; private String value just duplicates Enum.name; the toString override is redundant, and fromValue duplicates the standard valueOf. The whole thing would normally be expressed simply as enum BypassModeEnum {RULESET_BYPASS_MODE_UNSPECIFIED, RULESET_BYPASS_MODE_ALLOWED, RULESET_BYPASS_MODE_DISABLED}. I imagine all of this boilerplate is just the degenerate case of a potentially more complex type declaration? Or perhaps just to deal with enum values which do not happen to be Java identifiers?)

    Thank you for your quick attention. I can suggest the publisher of the schema simplify their usage.

  6. jpfinne commented on Sep 16, 2026

    @jpfinne
    Contributor

    @jglick modules/openapi-generator/src/main/resources/Java/libraries/native/modelEnum.mustache needs to deal with values being

    • numbers
    • camel case strings
    • string with uncompilable characters
    • ...

    The String.valueOf exists since 2016.
    Of course the mustache templates could be improved with a lot of optimization... but they come with the trade-off of increased complexity.

    If you want to customize the generation, you can override the default templates, see the customization page. Personally I don't think it is worth the trouble for such a trivial issue.

    Thanks for your understanding

  7. jglick commented on Sep 17, 2026

    @jglick
    Author

    jenkinsci/cursor-origin-branch-source-plugin#40 seems to work now with trunk (dda8e0e). Thanks for your help!

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions