Skip to content

[BUG][Java][Spring] 7.26.0 regression: oneOf interface getter for the discriminator is typed with the name of a primitive-alias schema that has no model ("cannot find symbol") #25226

Open

Description

@cmuchinsky

Bug Report Checklist

  • Have you provided a full/minimal spec to reproduce the issue?
  • Have you validated the input using an OpenAPI validator? (openapi-generator-cli validate: "No validation issues detected.")
  • Have you tested with the latest master to confirm the issue still exists? (7.27.0-SNAPSHOT, commit 3faf172)
  • Have you searched for related issues/PRs? (see below)
  • What's the actual output vs expected output?
  • [Optional] Sponsorship to speed up the bug fix or feature request (example)
Description

When all the schemas mapped by a oneOf discriminator declare the discriminator property as a $ref to the same primitive alias schema (here ShapeKind: a plain type: string schema without enum), the generated oneOf interface declares the getter with the name of the alias schema (ShapeKind getKind()). No model is generated for a primitive alias, and the implementing classes correctly use String, so the generated code does not compile (cannot find symbol).

7.25.0 generates String getKind(). This looks like a side effect of #24812: when only one distinct property schema remains and it is a $ref, DefaultCodegen#getCommonSchemaType returns toModelName(<ref>) without checking that a model exists for it.

Affected generators (tested): spring (with default options), jaxrs-spec and java (--library restclient / resttemplate) with useOneOfInterfaces=true. Not affected (tested with default options): kotlin, kotlin-spring.

openapi-generator version

7.26.0. It is a regression: 7.25.0 is fine. Still reproducible with the latest snapshot (7.27.0-SNAPSHOT, commit 3faf172).

OpenAPI declaration file content or url
shapes.yaml
openapi: 3.0.3
info:
  title: Discriminator property typed by a primitive alias
  version: 1.0.0
paths:
  /shape:
    get:
      operationId: getShape
      responses:
        '200':
          description: A shape
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Shape'
components:
  schemas:
    Shape:
      oneOf:
        - $ref: '#/components/schemas/Circle'
        - $ref: '#/components/schemas/Square'
      discriminator:
        propertyName: kind
        mapping:
          circle: '#/components/schemas/Circle'
          square: '#/components/schemas/Square'
    ShapeKind:
      type: string
      description: The kind of shape.
    Circle:
      type: object
      required:
        - kind
      properties:
        kind:
          $ref: '#/components/schemas/ShapeKind'
        radius:
          type: number
    Square:
      type: object
      required:
        - kind
      properties:
        kind:
          $ref: '#/components/schemas/ShapeKind'
        side:
          type: number
Generation Details
java -jar openapi-generator-cli-7.26.0.jar generate -g spring -i shapes.yaml -o out --global-property models

No additional options are needed (JDK 21). The same happens with -g jaxrs-spec --additional-properties useOneOfInterfaces=true or -g java --library restclient --additional-properties useOneOfInterfaces=true.

Steps to reproduce
  1. Generate as above with 7.26.0 (and with 7.25.0 for comparison).

  2. Look at out/src/main/java/org/openapitools/model/Shape.java.

    7.25.0:

    public interface Shape {
        public String getKind();
    }

    7.26.0:

    public interface Shape {
        public ShapeKind getKind();
    }

    There is no ShapeKind.java (only Shape, Circle and Square are generated), and Circle / Square use String getKind().

  3. Compiling the generated sources fails:

    org/openapitools/model/Shape.java:37: error: cannot find symbol
        public ShapeKind getKind();
               ^
      symbol:   class ShapeKind
      location: interface Shape
    

Observations that narrow the cause:

  • It only happens when the discriminator property resolves to exactly one distinct schema across all the mapped subtypes. If each subtype references its own alias schema, the output is fine (String getKind()): that goes through the multi-schema branch of getCommonSchemaType, which dereferences the $refs first.
  • It also happens when the alias property is inherited through allOf from a shared base schema.
  • An integer alias (type: integer) or a format: uuid alias fails the same way.
Related issues/PRs

I could not find an existing issue or PR about discriminators typed by a primitive alias.

Suggest a fix

In DefaultCodegen#getCommonSchemaType (case 1), when the only distinct property schema is a $ref, resolve aliases of primitive types first before treating the $ref as a model name. This mirrors getSingleSchemaType, which computes the property type of the implementing classes: unaliasSchema, then the model name if a $ref remains, otherwise the primitive type:

                 Schema first = schemas.get(0);
                 try {
                     if (StringUtils.isNotEmpty(first.get$ref())) {
+                        // a $ref to an alias of a primitive type has no model: use the aliased type,
+                        // like the type of the property in the concrete models
+                        first = unaliasSchema(first);
+                    }
+                    if (StringUtils.isNotEmpty(first.get$ref())) {
                         return toModelName(ModelUtils.getSimpleRef(first.get$ref()));
                     }

unaliasSchema keeps the $ref for everything that gets a generated model (enums, objects, composed schemas, schemaMappings targets), so the existing behavior for those is unchanged. Primitive aliases (also alias of alias) are resolved to the underlying schema and handled like an inline property (String, Integer, UUID, ...), consistent with the implementing classes. It does not touch the lines changed by #25008.

Validation of the patch (patched DefaultCodegen, compiled against the 7.26.0 jar; the file is identical on master):

  • The reproduction above generates String getKind() for spring, jaxrs-spec and java (restclient, resttemplate); the generated spring and restclient model sources compile with javac.
  • A spec with six oneOf groups compiles with javac: integer alias -> Integer, format: uuid alias -> UUID, alias of an alias -> String, alias of an enum -> the enum model, direct $ref to an enum -> the enum model (unchanged from 7.26.0), inline string -> String. For comparison, the same spec gives 16 compile errors with 7.25.0 (non-String discriminators, the problem fixed by fix(core) handle mismatching discriminatorType in oneOf interfaces #24812) and 4 with 7.26.0 (the alias groups).
  • Generating the 150 test specs that mention discriminator (modules/openapi-generator/src/test/resources/3_0 and 3_1) with spring and with java --library restclient (both with useOneOfInterfaces=true) gives byte-identical output with and without the patch. None of them exercises a primitive-alias discriminator, so a regression test would be new coverage.

Happy to open a PR with the change and a regression test if this approach looks right.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions