Skip to content

[BUG][JAVA] Complex OpenAPI defaults generate uncompilable Java code #24993

Description

@jorgerod

Description

The Java spring and java generators can produce uncompilable Java code, or silently discard a value, when an OpenAPI property declares a complex default value or a scalar value that requires typed conversion.

The problem occurs in the common AbstractJavaCodegen.toDefaultValue() logic and in the handling of default values for arrays and composed schemas. It does not appear to be specific to a single generator.

The issue is reproducible with OpenAPI Generator 7.25.0 and affects, among others, the following cases:

  • Arrays of objects.
  • Nested arrays.
  • Arrays of integer values with format: int64.
  • Object defaults defined through allOf, oneOf, or anyOf.
  • byte and binary defaults.
  • Defaults for referenced enums inside composed schemas.
  • Explicit null defaults on objects.

Version

  • OpenAPI Generator: 7.25.0.
  • Generators: spring and java.
  • OpenAPI: 3.0.3.

Minimal Specification

openapi: 3.0.3
info:
  title: Complex defaults
  version: 1.0.0
paths: {}
components:
  schemas:
    DefaultObject:
      type: object
      required:
        - name
        - count
      properties:
        name:
          type: string
        count:
          type: integer
          format: int32
        status:
          $ref: '#/components/schemas/Status'

    Status:
      type: string
      enum:
        - ACTIVE
        - INACTIVE

    Payload:
      type: object
      properties:
        objectArray:
          type: array
          default:
            - name: first
              count: 1
              status: ACTIVE
            - name: second
              count: 2
              status: INACTIVE
          items:
            $ref: '#/components/schemas/DefaultObject'

        longArray:
          type: array
          default:
            - 10
            - 20
          items:
            type: integer
            format: int64

        objectAllOf:
          allOf:
            - $ref: '#/components/schemas/DefaultObject'
          default:
            name: all-of
            count: 3
            status: ACTIVE

        objectOneOf:
          oneOf:
            - $ref: '#/components/schemas/DefaultObject'
          default:
            name: one-of
            count: 4
            status: ACTIVE

        byteValue:
          type: string
          format: byte
          default: ZGVmYXVsdA==

        binaryValue:
          type: string
          format: binary
          default: ZGVmYXVsdA==

    NullableObject:
      type: object
      properties:
        value:
          type: object
          default: null
          properties:
            name:
              type: string

For example, generation can be configured with Maven as follows:

<plugin>
  <groupId>org.openapitools</groupId>
  <artifactId>openapi-generator-maven-plugin</artifactId>
  <version>7.25.0</version>
  <configuration>
    <generatorName>spring</generatorName>
    <inputSpec>${project.basedir}/src/main/resources/openapi.yaml</inputSpec>
    <output>${project.build.directory}/generated-sources/openapi</output>
    <generateApiTests>false</generateApiTests>
    <generateModelTests>false</generateModelTests>
  </configuration>
</plugin>

Current Result

The spring generator produces code such as:

private List<@Valid DefaultObject> objectArray =
    new ArrayList<>(Arrays.asList(, ));

private List<Long> longArray =
    new ArrayList<>(Arrays.asList(10, 20));

private PayloadObjectOneOf objectOneOf =
    {"name":"one-of","count":4,"status":"ACTIVE"};

private byte[] byteValue = "[B@...";

private org.springframework.core.io.Resource binaryValue = "[B@...";

The observed problems are:

  1. Arrays.asList(, ) is not a valid Java expression.
  2. 10 and 20 are Integer literals, not Long literals, and are incompatible with List<Long> type inference.
  3. The oneOf default is emitted as raw JSON instead of a Java expression.
  4. byte[] values are converted to the Object.toString() representation ([B@...) instead of being decoded from Base64.
  5. binary values are converted to a string ([B@...) even when the generated type is Resource or File.
  6. For some objects with default: null, the generator logs a ClassCastException from NullNode to ObjectNode and continues generation.

The java generator shows the same array, composition, and byte problems. For binary, it normally uses java.io.File, so a valid and deterministic behavior must be defined for a binary default that cannot be materialized directly as a File.

Expected Result

The generators should produce compilable Java code while preserving the meaning of the contract. For example:

private List<@Valid DefaultObject> objectArray =
    new ArrayList<>(Arrays.asList(
        new DefaultObject().name("first").count(1).status(Status.ACTIVE),
        new DefaultObject().name("second").count(2).status(Status.INACTIVE)));

private List<Long> longArray =
    new ArrayList<>(Arrays.asList(10L, 20L));

private byte[] byteValue =
    java.util.Base64.getDecoder().decode("ZGVmYXVsdA==");

For binary, if the Java type allows the content to be materialized, a valid equivalent expression should be generated. If the mapped type is File and there is no portable way to embed the content, the generator should omit the initializer or emit a clear diagnostic, but it must never generate a non-compiling [B@... string.

null defaults should be processed without internal exceptions or misleading stack traces.

Acceptance Criteria

  • Object-array defaults generate valid Java expressions.
  • Nested-array defaults are processed recursively.
  • int64 values retain the Long type in arrays and objects.
  • allOf, oneOf, and anyOf object defaults do not emit raw JSON or attempt to instantiate interfaces.
  • byte defaults are generated as valid Base64 conversions.
  • binary defaults generate valid code or an explicit behavior when the mapped type cannot materialize the content.
  • Enum defaults, including referenced enums inside compositions, generate enum constants rather than strings.
  • null defaults do not cause internal generator exceptions.
  • Generation and compilation tests are added for the cases above in the affected Java generators.
  • Existing behavior for simple defaults and composed object defaults is preserved.

Related Issues and PRs

This issue groups several default-generation problems that share the same code path. It is not intended to replace the existing reports; it provides a common place to coordinate a fix and a shared regression matrix.

Implementation Proposal

Centralize default rendering in AbstractJavaCodegen so the Java generators share the same typed conversion logic. The implementation should prefer CodegenProperty metadata and resolved schemas over calling toString() on raw values, and should add a compilation test for the generated code.

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