modelina icon indicating copy to clipboard operation
modelina copied to clipboard

Java & Kotlin - type mapping support in the asyncapi cli

Open ahmetcetin39 opened this issue 2 months ago • 2 comments

Why do we need this improvement?

As Kotlin user, would appreciate to have the data mapping support so that I could map type such as Double -> BigDecimal to avoid possible side-effects. Double -> BigDecimal is the only issue with type mapping we had, but considering other users might have different use cases, I am creating the ticket for general type mapping.

How will this change help?

It will help Java & Kotlin users to have type mapping so they don't need to use default mapping of types.

Screenshots

No response

How could it be implemented/designed?

Having another flag in the asyncapi generate model to support type mapping, something like --kotlinTypeMapping

🚧 Breaking changes

No

👀 Have you checked for similar open issues?

  • [x] I checked and didn't find a similar issue

🏢 Have you read the Contributing Guidelines?

Are you willing to work on this issue?

None

ahmetcetin39 avatar Nov 12 '25 13:11 ahmetcetin39

Candidate to be moved to modelina.

Shurtu-gal avatar Dec 17 '25 14:12 Shurtu-gal

Welcome to AsyncAPI. Thanks a lot for reporting your first issue. Please check out our contributors guide and the instructions about a basic recommended setup useful for opening a pull request.
Keep in mind there are also other channels you can use to interact with AsyncAPI community. For more details check out this issue.

github-actions[bot] avatar Dec 17 '25 15:12 github-actions[bot]

hi @Shurtu-gal @derberg

Thanks for opening this issue! We've been discussing the design for type mapping support in Java/Kotlin and wanted to share our proposal for feedback.

Proposed Implementation

We're thinking of a two-level approach with global and field-level type mappings:

1. Global Type Mappings

Define default type mappings at the document level that apply to all fields:

asyncapi: "2.2.0"
info:
  title: Account Service
  version: 1.0.0

# Global mappings - applies to ALL fields of these types
typeMappings:
  number: BigDecimal
  integer: Long
  string: String

2. Field-Level Overrides

Override the global mapping for specific fields using the x-type extension:

components:
  messages:
    UserSignedUp:
      payload:
        type: object
        properties:
          amount:
            type: number
            # Uses global mapping: BigDecimal ✓
            
          percentage:
            type: number
            x-type: Double
            # Override: This specific field uses Double instead
            description: Percentage where precision loss is acceptable
            
          accountId:
            type: integer
            # Uses global mapping: Long ✓

Design Rationale

Why two levels?

  • Global mappings: Cover the common case where you want all number types to be BigDecimal
  • Field-level overrides: Allow exceptions where specific fields need different types (e.g., percentages can use Double)

Why x-type for field-level?

  • Follows AsyncAPI extension conventions (x- prefix)
  • Clear and unambiguous - one type per field
  • Consistent with similar tools like OpenAPI Generator
  • Avoids confusing nested structures

Precedence Order:

Field-level (x-type) > Global (typeMappings) > Default generator mapping

CLI Support

We also propose supporting type mappings via CLI for quick overrides:

asyncapi generate models kotlin asyncapi.yaml \
  --type-mapping number=BigDecimal \
  --type-mapping integer=Long

CLI mappings would override the global typeMappings in the spec file.

Simple Type Names vs Fully Qualified

Support both simple and fully qualified names:

typeMappings:
  # Simple names (generator adds imports automatically)
  number: BigDecimal
  integer: Long
  
  # Fully qualified (when needed for custom/ambiguous types)
  timestamp: java.time.Instant
  customType: com.mycompany.Money

Complete Example

asyncapi: "2.2.0"
info:
  title: Account Service
  version: 1.0.0

typeMappings:
  number: BigDecimal  # All numbers → BigDecimal by default
  integer: Long

channels:
  user/signedup:
    subscribe:
      message:
        $ref: "#/components/messages/UserSignedUp"

components:
  messages:
    UserSignedUp:
      payload:
        type: object
        properties:
          displayName:
            type: string
            
          email:
            type: string
            format: email
            
          amount:
            type: number
            description: Uses BigDecimal (global mapping)
            
          taxRate:
            type: number
            x-type: Double
            description: Override to Double - precision loss acceptable
            
          accountId:
            type: integer
            description: Uses Long (global mapping)

Questions

  1. Does this approach align with AsyncAPI CLI's architecture and conventions?
  2. Is x-type an appropriate extension name, or would you prefer something like x-java-type / x-kotlin-type to be language-specific?
  3. Should the global typeMappings be at the root level, or nested under a generator-specific configuration?
  4. Are there any concerns about this design conflicting with existing or planned features?

We're happy to contribute a PR once we align on the design. Thanks for considering this!

Shyam-Raghuwanshi avatar Jan 01 '26 17:01 Shyam-Raghuwanshi