Migration from v2 to v3

February 1, 2024 ยท View on GitHub

This document contains all the breaking changes and migrations guidelines for adapting your code to the new version.

allowInheritance set to true will enable inheritance

This feature introduces a new option called allowInheritance in the interpreter options, which controls whether the generated models should inherit when the schema includes an allOf. By default, this option is set to false, which means that you'll not be affected if this property is not set. In the MetaModel and the ConstrainedMetaModel options, there is now an extend property (a list of models) and an isExtended property (boolean).

Here is an example of how to use the new feature and the allowInheritance option in your code:

const generator = new JavaFileGenerator({
  processorOptions: {
    interpreter: {
      allowInheritance: true
    }
  }
});

TypeScript

JS reserved keywords are no longer applied by default

By default up until now, JS reserved keywords have been checked for TS as well. Which means that something like:

{
  $schema: 'http://json-schema.org/draft-07/schema#',
  type: 'object',
  additionalProperties: false,
  properties: {
    location: {
      type: 'string'
    }
  }
}

Would be default be rendered as:

class Root {
  private _reservedLocation?: string;

  constructor(input: {
    reservedLocation?: string,
  }) {
    this._reservedLocation = input.reservedLocation;
  }

  get reservedLocation(): string | undefined { return this._reservedLocation; }
  set reservedLocation(reservedLocation: string | undefined) { this._reservedLocation = reservedLocation; }
}

However, without setting useJavascriptReservedKeywords: true by default the following will be generated:

class Root {
  private _location?: string;

  constructor(input: {
    location?: string,
  }) {
    this._location = input.location;
  }

  get location(): string | undefined { return this._location; }
  set location(location: string | undefined) { this._location = location; }
}

JavaScript

Is not affected by this change.

C#

System.TimeSpan is used when format is time

This example used to generate a string, but is now instead using System.TimeSpan.

type: object
properties:
  duration:
    type: string
    format: time

will generate

public class TestClass {
  private System.TimeSpan duration;
  ...
}

System.DateTime is used when format is date-time

This example used to generate a string, but is now instead using System.DateTime.

type: object
properties:
  dob:
    type: string
    format: date-time

will generate

public class TestClass {
  private System.DateTime dob;
  ...
}

System.Guid is used when format is uuid

This example used to generate a string, but is now instead using System.Guid.

type: object
properties:
  uniqueId:
    type: string
    format: uuid

will generate

public class TestClass {
  private System.Guid uniqueId;
  ...
}

Java

java.time.Duration is used when format is duration

This example used to generate a String, but is now instead using java.time.Duration.

type: object
properties:
  duration:
    type: string
    format: duration

will generate

public class TestClass {
  private java.time.Duration duration;
  ...
}

inheritance will generate interfaces

Please read the section about allowInheritance first. When allowInheritance is enabled, interfaces will be generated for schemas that uses allOf:

components:
  messages:
    Vehicle:
      payload:
        oneOf:
          - $ref: '#/components/schemas/Car'
          - $ref: '#/components/schemas/Truck'
  schemas:
    Vehicle:
      title: Vehicle
      type: object
      discriminator: vehicleType
      properties:
        vehicleType:
          title: VehicleType
          type: string
        length:
          type: number
          format: float
      required:
        - vehicleType
    Car:
      allOf:
        - '#/components/schemas/Vehicle'
        - type: object
          properties:
            vehicleType:
              const: Car
    Truck:
      allOf:
        - '#/components/schemas/Vehicle'
        - type: object
          properties:
            vehicleType:
              const: Truck

will generate

public interface NewVehicle {
  VehicleType getVehicleType();
}

public class Car implements NewVehicle, Vehicle {
  private final VehicleType vehicleType = VehicleType.CAR;
  private Float length;
  private Map<String, Object> additionalProperties;

  public VehicleType getVehicleType() { return this.vehicleType; }

  @Override
  public Float getLength() { return this.length; }
  @Override
  public void setLength(Float length) { this.length = length; }
}

public enum VehicleType {
  CAR((String)\\"Car\\"), TRUCK((String)\\"Truck\\");

  private String value;

  VehicleType(String value) {
    this.value = value;
  }

  public String getValue() {
    return value;
  }

  public static VehicleType fromValue(String value) {
    for (VehicleType e : VehicleType.values()) {
      if (e.value.equals(value)) {
        return e;
      }
    }
    throw new IllegalArgumentException(\\"Unexpected value '\\" + value + \\"'\\");
  }

  @Override
  public String toString() {
    return String.valueOf(value);
  }
}

public interface Vehicle {
  public Float getLength();
  public void setLength(Float length);
}

public class Truck implements NewVehicle, Vehicle {
  private final VehicleType vehicleType = VehicleType.TRUCK;
  private Float length;
  private Map<String, Object> additionalProperties;

  public VehicleType getVehicleType() { return this.vehicleType; }

  @Override
  public Float getLength() { return this.length; }
  @Override
  public void setLength(Float length) { this.length = length; }
}

Kotlin

Is not affected by this change.

Rust

Is not affected by this change.

Python

Union type for the Pydantic preset supports Python pre 3.10

Modelina used to use the newer way of representing unions in Python by using the | operator. In the Pydantic preset, this is now adjusted to support Python pre 3.10 by using Union[Model1, Model2] instead:

title: UnionTest
type: object
  properties:
    unionTest:
      oneOf:
        - title: Union1
          type: object
          properties:
            testProp1:
              type: string
        - title: Union2
          type: object
          properties:
            testProp2:
              type: string

will generate

class UnionTest(BaseModel):
  unionTest: Optional[Union[Union1, Union2]] = Field()
  additionalProperties: Optional[dict[Any, Any]] = Field()

class Union1(BaseModel):
  testProp1: Optional[str] = Field()
  additionalProperties: Optional[dict[Any, Any]] = Field()

class Union2(BaseModel):
  testProp2: Optional[str] = Field()
  additionalProperties: Optional[dict[Any, Any]] = Field()

Go

Is not affected by this change.

Dart

Is not affected by this change.

C++

Is not affected by this change.

Options in constraints

As part of https://github.com/asyncapi/modelina/issues/1475 we had the need to access options in the constraint logic, therefore all constraints now have direct access to the provided options.

To make it easier we now expose types for each of the constraints in each language to make it easier to re-use in TS integrations. They can be accessed as following:

import { <language>ConstantConstraint, <language>EnumKeyConstraint, <language>EnumValueConstraint, <language>ModelNameConstraint, <language>PropertyKeyConstraint } from @asyncapi/modelina