Skip to content

How to properly define inheritance for list items using discriminator and allOf/anyOf/oneOf? #1597

@ThomasVerhoeven1998

Description

@ThomasVerhoeven1998

We’re trying to model polymorphic objects in a list using AsyncAPI 3.0.0 and JSON Schema (Draft 7), with class generation via Modelina. However, it’s unclear what the recommended or correct way is to define inheritance in this context — especially for arrays of polymorphic types.

The Goal ✅

Will be using an example:

Define a schema where an array of items (workers) can contain different subtypes (Employer, Employee) inheriting from a base type (Worker), and ensure correct support in tools like Modelina for code generation.

What we've tried (simplified versions below) 🔍

Option 1 – use of allOf on subclasses

Subtypes extend Worker, workers just refers to Worker.

asyncapi: 3.0.0
.....
components:
  schemas:
    WorkersCreatedEvent:
      title: WorkersCreatedEvent
      type: object
      properties:
       id:
        type: string
        format: uuid
       workers:
        type: array
        items:
          $ref: '#/components/schemas/Worker'
      required:
        - id
    Worker:
      type: object
      properties:
        name:
          type: string
      discriminator: "@type"
    Employer:
      title: Employer
      type: object
      allOf:
        - $ref: '#/components/schemas/Worker'
        - type: object
          properties:
            hasFullAccess:
              type: boolean
      required:
        - hasFullAccess
    Employee:
      title: Employee
      type: object
      allOf:
        - $ref: '#/components/schemas/Worker'
        - type: object
          properties:
            registrationDate:
              type: string
      required:
        - registrationDate

Option 2 – allOf on subclasses + anyOf and allOf on array items

Array items use anyOf to allow multiple subtypes explicitly but also mark it they should be all of type worker

asyncapi: 3.0.0
....
components:
  schemas:
    WorkersCreatedEvent:
      title: WorkersCreatedEvent
      type: object
      properties:
        id:
          type: string
          format: uuid
        workers:
          type: array
          items:
            title: WorkerMixin
            allOf:
              - $ref: '#/components/schemas/Worker'
            anyOf:
              - $ref: '#/components/schemas/Employer'
              - $ref: '#/components/schemas/Employee'
    Worker:
      title: Worker
      type: object
      properties:
        name:
          type: string
      discriminator: "@type"
    Employer:
      title: Employer
      type: object
      allOf:
        - $ref: '#/components/schemas/Worker'
        - type: object
          properties:
            hasFullAccess:
              type: boolean
      required:
        - hasFullAccess
    Employee:
      title: Employee
      type: object
      allOf:
        - $ref: '#/components/schemas/Worker'
        - type: object
          properties:
            registrationDate:
              type: string
      required:
        - registrationDate

Option 3 – oneOf declared in base class

Worker uses oneOf to point to valid subtypes directly.

asyncapi: 3.0.0
....
components:
  schemas:
    WorkersCreatedEvent:
      title: WorkersCreatedEvent
      type: object
      properties:
        id:
          type: string
          format: uuid
        workers:
          type: array
          items:
            $ref: '#/components/schemas/Worker'
    Worker:
      type: object
      properties:
        name:
          type: string
      discriminator: "@type"
      oneOf:
        - $ref: '#/components/schemas/Employer'
        - $ref: '#/components/schemas/Employee'
    Employer:
      title: Employer
      type: object
      allOf:
        - type: object
          properties:
            hasFullAccess:
              type: boolean
      required:
        - hasFullAccess
    Employee:
      title: Employee
      type: object
      allOf:
        - type: object
          properties:
            registrationDate:
              type: string
      required:
        - registrationDate

Option 4 – allOf on subclasses + anyOf on array

No inheritance on base class, just union the subtypes directly in the array definition.

asyncapi: 3.0.0
....
components:
  schemas:
    WorkersCreatedEvent:
      title: WorkersCreatedEvent
      type: object
      properties:
        id:
          type: string
          format: uuid
        workers:
          type: array
          items:
            title: WorkerItems
            anyOf:
              - $ref: '#/components/schemas/Employer'
              - $ref: '#/components/schemas/Employee'
    Worker:
      type: object
      properties:
        name:
          type: string # No properties cause Worker not be generated
      discriminator: "@type"
    Employer:
      title: Employer
      type: object
      allOf:
        - $ref: '#/components/schemas/Worker'
        - type: object
          properties:
            hasFullAccess:
              type: boolean
      required:
        - hasFullAccess
    Employee:
      title: Employee
      type: object
      allOf:
        - $ref: '#/components/schemas/Worker'
        - type: object
          properties:
            registrationDate:
              type: string
      required:
        - registrationDate

Option 5 – allOf on subclasses + oneOf on array

asyncapi: 3.0.0
...
components:
  schemas:
    WorkersCreatedEvent:
      title: WorkersCreatedEvent
      type: object
      properties:
        id:
          type: string
          format: uuid
        workers:
          type: array
          items:
            title: WorkerMixin
            oneOf:
              - $ref: '#/components/schemas/Employer'
              - $ref: '#/components/schemas/Employee'
    Worker:
      title: Worker
      type: object
      properties:
        name:
          type: string
      discriminator: "@type"
      required:
        - name
    Employer:
      title: Employer
      type: object
      allOf:
        - $ref: '#/components/schemas/Worker'
        - type: object
          properties:
            hasFullAccess:
              type: boolean
      required:
        - hasFullAccess
    Employee:
      title: Employee
      type: object
      allOf:
        - $ref: '#/components/schemas/Worker'
        - type: object
          properties:
            registrationTimestamp:
              type: string
              description: Time of prioritization
              format: date-time
            registrationDate:
              type: string
      required:
        - registrationDate

Option 6 - ...

Anything other than specified.

What we need clarity on ❓

  • What is the recommended way to define inheritance for object arrays (in our case, workers) in AsyncAPI 3.0 with JSON Schema Draft 7?

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