Migration from v3 to v4
This document contain all the breaking changes and migrations guidelines for adapting your code to the new version.
Deprecation of processor.interpreter
Since the early days we had the option to set processorOptions.interpreter
options to change how JSON Schema is interpreted to Meta models. However, these options are more accurately part of the processorOptions.jsonSchema
options.
Use this instead going forward.
Fixed edge cases for camel case names
Naming such as object properties using camel case formatting had an edge case where if they contained a number followed by an underscore and a letter it would be incorrectly formatted. This has been fixed in this version, which might mean properties, model names, etc that use camel case might be renamed.
This example contains such a string:
1type: object 2properties: 3 aa_00_testAttribute: 4 type: string
This used to generate:
1interface AnonymousSchema_1 { 2 aa_00TestAttribute?: string; 3}
but will now generate:
1interface AnonymousSchema_1 { 2 aa_00_testAttribute?: string; 3}
C#
Constant values are now properly rendered as const properties
This example used to generate a string
with a getter and setter, but will now generate a const string that is initialized to the const value provided.
1type: object 2properties: 3 property: 4 type: string 5 const: 'abc'
will generate
1public class TestClass { 2 private const string property = "test"; 3 4 public string Property 5 { 6 get { return property; } 7 } 8 ... 9}
Notice that Property
no longer has a set
method. This might break existing models.
DateTime and DateTimeOffset are now properly rendered based on specification format
In the previous version, date-time
and date
formats were rendered as DateTime
and DateTimeOffset
respectively.
This has been changed to render DateTimeOffset
for date-time
and DateTime
for date
formats.
This might break existing implementation and require manual changes.
The best thing to do is to fix your specification and use what you really need. If you don't care about the time and time zone, use date
instead of date-time
.
Otherwise, keep the date-time
format and update your code to use DateTimeOffset
instead of DateTime
.
That usually means doing this:
1var dateTime = new DateTime(2008, 6, 19, 7, 0, 0); 2 3// Set the DateTime property of the ModelinaModel 4var modelinaModel = new ModelinaModel(); 5modelinaModel.DateTime = dateTime; 6Console.WriteLine(modelinaModel.DateTime); 7 8// Get the DateTime property from the ModelinaModel 9DateTime dateTime2 = modelinaModel.DateTime.LocalDateTime; 10Console.WriteLine(dateTime2);
Python
Models are aiming to be >= v3.7 compliant.
Unique types in unions
In v4, unions types are rendered unique, meaning you will never see str | str
but just str
.
Pydantic now follows v2 instead of v1
Reference: https://docs.pydantic.dev/2.6/migration/
The schema description is now a description and not an alias:
1class Message(BaseModel): 2 identifier: str = Field(description='''The Identifier for the Message''')
In Modelina v3 this used is rendered as:
1class Message(BaseModel): 2 identifier: str = Field(alias='''The Identifier for the Message''')
Following standardized styling guide
Before names of properties and model names did not follow any specific styling standard.
In v4, we switched to using the following:
- Variables and functions: https://peps.python.org/pep-0008/#function-and-variable-names
- Model names: https://peps.python.org/pep-0008/#class-names
This means that properties and their accessor methods (getter and setters) have been renamed from:
1- self._someWeirdValueExclamationQuotationHash_2 = input.someWeirdValueExclamationQuotationHash_2 2+ self._some_weird_value_exclamation_quotation_hash_2 = input.some_weird_value_exclamation_quotation_hash_2
And model names have been renamed to:
1- class AsyncApi_3Dot_0Dot_0SchemaDot: 2+ class AsyncApi3Dot0Dot0SchemaDot:
If you are using the Python preset PYTHON_JSON_SERIALIZER_PRESET
, the functions have also been renamed:
1- serializeToJson 2+ serialize_to_json 3 4- deserializeFromJson 5+ deserialize_from_json
Type hints
Classes now have type hints on all properties and accessor functions.
Before:
1from typing import Any, Dict 2class ObjProperty: 3 def __init__(self, input): 4 if hasattr(input, 'number'): 5 self._number = input['number'] 6 if hasattr(input, 'additional_properties'): 7 self._additional_properties = input['additional_properties'] 8 9 @property 10 def number(self): 11 return self._number 12 @number.setter 13 def number(self, number): 14 self._number = number 15 16 @property 17 def additional_properties(self): 18 return self._additional_properties 19 @additional_properties.setter 20 def additional_properties(self, additional_properties): 21 self._additional_properties = additional_properties
After:
1from typing import Any, Dict 2class ObjProperty: 3 def __init__(self, input: Dict): 4 if hasattr(input, 'number'): 5 self._number: float = input['number'] 6 if hasattr(input, 'additional_properties'): 7 self._additional_properties: dict[str, Any] = input['additional_properties'] 8 9 @property 10 def number(self) -> float: 11 return self._number 12 @number.setter 13 def number(self, number: float): 14 self._number = number 15 16 @property 17 def additional_properties(self) -> dict[str, Any]: 18 return self._additional_properties 19 @additional_properties.setter 20 def additional_properties(self, additional_properties: dict[str, Any]): 21 self._additional_properties = additional_properties
Initialization of correct models
Before in the constructor, if a property was another class, they would not correctly be initialized. Now a new instance of the object is created.
Constants are now rendered
Before, constants where completely ignored, now they are respected and also means you don't have the possibility to change it through setters for example.
1class Address: 2 def __init__(self, input: Dict): 3 self._street_name: str = 'someAddress' 4 5 @property 6 def street_name(self) -> str: 7 return self._street_name
Import style deprecation
All models are from this point onwards imported using explicit styles from . import ${model.name}
to allow for circular model dependencies to work. This means that the option importsStyle
is deprecated and is no longer in use. It will be removed at some point in the future.
Go
File names
In v4, file names for go will be formatted as snake_case.go
. This is the "standard" in go: https://github.com/golang/go/issues/36060
Union types will be generated correctly with struct embeddings
Modelina now supports union types for Go
. Since Go
does not have native union types support modelina uses struct embeddings
to mock union types.
1type Union struct { 2 CustomStruct 3 int 4 string 5 ModelinaArrType []string 6 ModelinaDictType map[string] interface{} 7 ModelinaAnyType interface {} 8}
ModelinaArrType
, ModelinaDictType
, ModelinaAnyType
are generated by default by modelina, users can change the names by passing different names to the GoGenerator Options
, for example:
1const generator = new GoGenerator({ 2 unionAnyModelName: 'ModelinaAnyType', 3 unionArrModelName: 'ModelinaArrType', 4 unionDictModelName: 'ModelinaDictType' 5});
Union type with discriminator will render an interface and the children will implement that interface
While the above changes work for primitives, it's problematic for objects with a discriminator. This is solved by creating an interface for the parent with the discriminator and each child implements the interface:
1type Vehicle interface { 2 IsVehicleVehicleType() 3} 4 5type Car struct { 6 VehicleType *VehicleType 7 RegistrationPlate string 8 AdditionalProperties map[string]interface{} 9} 10 11func (r Car) IsVehicleVehicleType() {} 12 13type Truck struct { 14 VehicleType *VehicleType 15 RegistrationPlate string 16 AdditionalProperties map[string]interface{} 17} 18 19func (r Truck) IsVehicleVehicleType() {} 20 21type VehicleType uint 22 23const ( 24 VehicleTypeCar VehicleType = iota 25 VehicleTypeTruck 26) 27 28// Value returns the value of the enum. 29func (op VehicleType) Value() any { 30 if op >= VehicleType(len(VehicleTypeValues)) { 31 return nil 32 } 33 return VehicleTypeValues[op] 34} 35 36var VehicleTypeValues = []any{\\"Car\\",\\"Truck\\"} 37var ValuesToVehicleType = map[any]VehicleType{ 38 VehicleTypeValues[VehicleTypeCar]: VehicleTypeCar, 39 VehicleTypeValues[VehicleTypeTruck]: VehicleTypeTruck, 40}
Nullable and required properties
Modelina now has support for nullable and required properties in go structs. This support exists for generic types like int
, string
, bool
, float64
.
1type info struct { 2 name string // required 3 description *string // nullable 4 version *float64 5 isDevelopment *bool 6}
Java
When allowInheritance
is true, Modelina no longer renders the setter for enums in interfaces if the property exist in the implemented by class with a constant value
In Java, when a class implements an interface, it must implement all the methods of that interface. Therefore, if allowInheritance
is set to true, Modelina will no longer render the setter for enums in interfaces if the property exists in the implemented by class with a constant value.