Skip to content

Sealed classes don't preserve field name mappings for Dart keyword fields #409

@Gj1337

Description

@Gj1337

Description

When generating sealed classes from OpenAPI schemas with oneOf, swagger_parser correctly renames fields that are Dart keywords (e.g., requiredrequiredValue) in the base interface classes and adds the proper field mapping annotation (@MappableField(key: 'required') for dart_mappable or @JsonKey(name: 'required') for json_serializable). However, swagger_parser fails to add these field mapping annotations in the sealed class implementations.

This causes the serializer to use the Dart field name (requiredValue) instead of the original JSON field name (required) that the server expects, resulting in API requests being rejected or fields being ignored by the server.

Environment

  • swagger_parser version: swagger_parser: ^1.37.0
  • Dart SDK version: Dart 3.11.0 (build 3.11.0-12.0.dev) • DevTools 2.51.0
  • Serializer: dart_mappable and json_serializable (tested and confirmed on both)
  • OpenAPI version: 3.0

Setup

OpenAPI Schema

components:
  schemas:
    OfferPutRequest:
      type: object
      properties:
        subsections:
          type: array
          items:
            oneOf:
            - $ref: "#/components/schemas/OfferCheckboxPostRequest"
            - $ref: "#/components/schemas/OfferTextFieldPostRequest"
    
    OfferCheckboxPostRequest:
      type: object
      description: Represents a request to create a new checkbox field in an offer
      properties:
        type:
          type: string
        title:
          type: string
        customerChecked:
          type: boolean
        required:
          type: boolean
      required:
      - customerChecked
      - required
      - title
      - type
    
    OfferTextFieldPostRequest:
      type: object
      properties:
        type:
          type: string
        title:
          type: string
        customerResponse:
          type: string
        required:
          type: boolean
      required:
      - required
      - title
      - type

Configuration (build.yaml)

targets:
  $default:
    builders:
      swagger_parser:
        options:
          schema_url: path/to/api-docs.yaml
          output_directory: lib/api
          json_serializer: dart_mappable
          enums_to_json: true
          unknown_enum_value: false

Current Behavior

Generated base class (CORRECT ✓)

offer_checkbox_post_request.dart:

@MappableClass()
class OfferCheckboxPostRequest {
  const OfferCheckboxPostRequest({
    required this.type,
    required this.title,
    required this.customerChecked,
    required this.requiredValue,
  });
  
  final String type;
  final String title;
  final bool customerChecked;

  @MappableField(key: 'required')  // ✓ Correct mapping
  final bool requiredValue;
}

When this class serializes to JSON, it correctly produces:

{
  "type": "checkbox",
  "title": "Accept terms",
  "customerChecked": false,
  "required": true  // ✓ Correct field name
}

Generated sealed class (INCORRECT ✗)

offer_post_request_subsections_sealed.dart:

@MappableClass()
class OfferPostRequestSubsectionsSealedOfferCheckboxPostRequest 
    extends OfferPostRequestSubsectionsSealed 
    implements OfferCheckboxPostRequest {
  @override
  final String type;
  @override
  final String title;
  @override
  final bool customerChecked;
  @override
  final bool requiredValue;  // ✗ Missing @MappableField(key: 'required')

  const OfferPostRequestSubsectionsSealedOfferCheckboxPostRequest({
    required this.type,
    required this.title,
    required this.customerChecked,
    required this.requiredValue,
  });
  
  // ... rest of implementation
}

When the sealed class serializes to JSON, it produces:

{
  "type": "checkbox",
  "title": "Accept terms",
  "customerChecked": false,
  "requiredValue": true  // ✗ Wrong field name!
}

Expected Behavior

The sealed class should preserve the field name mapping:

@MappableClass()
class OfferPostRequestSubsectionsSealedOfferCheckboxPostRequest 
    extends OfferPostRequestSubsectionsSealed 
    implements OfferCheckboxPostRequest {
  @override
  final String type;
  @override
  final String title;
  @override
  final bool customerChecked;
  @override
  @MappableField(key: 'required')  // ✓ Should be present
  final bool requiredValue;

  // ... rest of implementation
}

And the correct JSON:

{
  "type": "checkbox",
  "title": "Accept terms",
  "customerChecked": false,
  "required": true  // ✓ Correct field name 
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions