jam.utils.json.decorators module

Decorators for adding JSON serialization capabilities to classes.

Core Decorators

@json_serializable

Adds JSON serialization to a class:

  • Adds to_json() and from_json() methods

  • Makes class inherit from JsonSerde

  • Preserves existing inheritance

  • Handles dataclass conversion

@json_field

Configures field serialization:

  • name: Custom JSON field name

  • skip_if_none: Skip None values

  • Integrates with dataclass fields

@with_json_metadata

Bulk configuration of field metadata:

  • Configure multiple fields at once

  • Supports all field options

  • Must be applied before @dataclass

Implementation Details

Class Transformation

The @json_serializable decorator:

  1. Makes class a dataclass if not already

  2. Adds JsonSerde to base classes

  3. Preserves class attributes and methods

  4. Caches type hints for validation

Field Configuration

Field metadata is stored in dataclass field.metadata:

@dataclass
class Point:
    x: int = json_field(name="xCoord")
    # field.metadata = {"json_name": "xCoord"}

Error Cases

Missing Type Annotations

@json_serializable  # Error: no type annotations
class Point:
    x = 1  # Missing annotation

Invalid Field Names

@with_json_metadata(
    missing="value"  # Error: field not found
)
class Document:
    id: str

Wrong Decorator Order

@dataclass  # Error: wrong order
@json_serializable
class Point:
    x: int

API Reference

Decorators

jam.utils.json.decorators.json_serializable(cls: Type[T]) Type[T][source]

Add JSON serialization to a class.

jam.utils.json.decorators.json_field(*, name: str | None = None, skip_if_none: bool = False) Any[source]

Field decorator for JSON customization.

jam.utils.json.decorators.with_json_metadata(**field_metadata: Dict[str, Any])[source]

Add JSON metadata to multiple fields.

jam.utils.json.decorators.json_field_metadata(field_name: str, *, json_name: str | None = None, skip_if_none: bool = False) Dict[str, Any][source]

Create metadata for a JSON field.

Examples

Basic Usage

from dataclasses import dataclass
from jam.utils.json import json_serializable, json_field

@json_serializable
@dataclass
class Point:
    x: int = json_field(name="xCoord")
    y: int = json_field(name="yCoord")

point = Point(1, 2)
data = point.to_json()  # -> {"xCoord": 1, "yCoord": 2}

Field Configuration

@json_serializable
@with_json_metadata(
    created={"name": "createdAt"},
    tags={"skip_if_none": True}
)
@dataclass
class Document:
    id: str
    created: datetime
    tags: Optional[list[str]] = None

doc = Document("123", datetime.now(), ["a", "b"])
# -> {
#     "id": "123",
#     "createdAt": "2024-02-11",
#     "tags": ["a", "b"]
# }