# JSON Serialization and Deserialization

This page documents the JSON serialization and deserialization system within the Mesh Connect Android SDK. The system handles conversion between JSON messages received from web content and strongly-typed Kotlin data classes used throughout the native Android code.

For information about the specific data models and payload structures, see [Data Models](/content/FrontFin/mesh-android-sdk/4-data-models/index.html). For details about the message broadcasting system that uses these converters, see [Message Broadcasting System](/content/FrontFin/mesh-android-sdk/3.2-message-broadcasting-system/index.html).

## Overview

The SDK uses a centralized JSON conversion system built around the `JsonConverter` class to handle bidirectional conversion between JSON strings and Kotlin objects. This system is primarily used for:

- Deserializing messages received from embedded web content via the JSBridge
- Converting typed Kotlin objects back to JSON for web communication
- Type-safe handling of different message types based on JSON structure

## Core Components

### JsonConverter Class

The `JsonConverter` serves as the central conversion utility, providing methods for both serialization and deserialization operations. Based on the usage patterns in the codebase, it provides the following key methods:

- `fromJson(json: String, classOfT: Class<T>): T` - Deserializes JSON to typed objects
- `toMap(json: String): Map<String, Any>` - Converts JSON to key-value pairs for flexible access

### Type-Based Message Processing

The system uses a type-based approach to determine how to deserialize incoming JSON messages. Each message contains a `type` field that maps to the `Type` enum:

| Type                           | Purpose                  | Target Class                 |
|--------------------------------|--------------------------|-------------------------------|
| `brokerageAccountAccessToken` | Account access tokens    | `AccessTokenPayload`         |
| `transferFinished`            | Transfer completion      | `TransferFinishedPayload`    |
| `delayedAuthentication`       | Delayed auth flow       | `DelayedAuthPayload`         |
| `error`                        | Error messages           | `JsError`                    |
| `close`                       | Close events             | Simple event                  |
| `done`                        | Done events              | Simple event                  |
| `showClose`                   | Show close button        | Simple event                  |
| `loaded`                      | Content loaded           | Simple event                  |
| `openTrueAuth`                | Open authentication      | Link extraction               |

## Deserialization Flow

### Message Type Detection and Routing

```
Raw JSON Message

JsType Deserialization

Extract type field

Type-based routing

Type.brokerageAccountAccessToken

Type.transferFinished

Type.delayedAuthentication

Type.error

Simple event types

Type.openTrueAuth

AccessTokenResponse

TransferFinishedResponse

DelayedAuthResponse

JsError

Link extraction via toMap()

AccessTokenPayload

TransferFinishedPayload

DelayedAuthPayload

LinkEvent.Payload

throw IllegalStateException

LinkEvent.TrueAuth

LinkEvent.Close/Done/etc
```

### Payload Deserialization Process

```
Kotlin Objects

Deserialization Steps

JSON Structure

JSON Message

type: 'brokerageAccountAccessToken'

payload: { ... }

Extract JsType

Deserialize to ResponseWrapper

Extract payload field

AccessTokenPayload

List

BrandInfo

Token expiration data

Account objects

access/refresh tokens
```

### Concrete Example: AccessTokenPayload

### JSON Structure

The following JSON structure represents an access token response:

```
{
    "type": "brokerageAccountAccessToken",
    "payload": {
        "accountTokens": [{
            "account": {
                "accountId": "2wwwc105-5xx-4390x",
                "accountName": "xx9xxx226",
                "fund": 5.36,
                "cash": 5.26,
                "isReconnected": false,
                "frontAccountId": "wow_id"
            },
            "accessToken": "8/luwjLWf/QxxfilS2r",
            "refreshToken": "#34381lmefl93"
        }],
        "brokerType": "alpaca",
        "brokerName": "Alpaca",
        "brokerBrandInfo": {
            "brokerLogo": "iVBORwxxxxxSUhEUgAAA",
            "brokerPrimaryColor": "#FFF",
            "logoLightUrl": "http://logoLightUrl",
            "logoDarkUrl": "http://logoDarkUrl",
            "iconLightUrl": "http://iconLightUrl",
            "iconDarkUrl": "http://iconDarkUrl"
        },
        "expiresInSeconds": 200,
        "refreshTokenExpiresInSeconds": 300
    }
}
```

### Resulting Kotlin Objects

The JSON deserializes to a hierarchy of Kotlin data classes:

```
AccessTokenPayload(
    accountTokens = listOf(
        AccountToken(
            account = Account(
                accountId = "2wwwc105-5xx-4390x",
                accountName = "xx9xxx226",
                fund = 5.36,
                cash = 5.26,
                isReconnected = false,
                frontAccountId = "wow_id"
            ),
            accessToken = "8/luwjLWf/QxxfilS2r",
            refreshToken = "#34381lmefl93"
        )
    ),
    brokerType = "alpaca",
    brokerName = "Alpaca",
    brokerBrandInfo = BrandInfo(
        brokerLogo = "iVBORwxxxxxSUhEUgAAA",
        brokerPrimaryColor = "#FFF",
        logoLightUrl = "http://logoLightUrl",
        logoDarkUrl = "http://logoDarkUrl",
        iconLightUrl = "http://iconLightUrl",
        iconDarkUrl = "http://iconDarkUrl"
    ),
    expiresInSeconds = 200,
    refreshTokenExpiresInSeconds = 300
)
```

## Response Wrapper Pattern

The system uses a wrapper pattern for complex payloads where the actual data is nested within a `payload` field:

### Message Structure Pattern

```
Actual Payload Classes

Response Wrapper Classes

JSON Message Format

Root JSON Object

type: string

payload: object

AccessTokenResponse

TransferFinishedResponse

DelayedAuthResponse

AccessTokenPayload

TransferFinishedPayload

DelayedAuthPayload
```

## Error Handling

The deserialization system includes error handling for malformed or error-type messages:

1. **Type Detection Errors** - Unknown or null types return `null` from the deserialization process
2. **Error Messages** - Messages with `type: "error"` are deserialized to `JsError` objects and throw `IllegalStateException`
3. **Deserialization Failures** - JSON parsing errors are handled by the underlying JSON converter implementation

### Error Message Processing

```
JSON with type: 'error'

Deserialize to JsError

Extract errorMessage field

Use default if null

throw IllegalStateException
```

### Special Cases

#### TrueAuth Link Extraction

For `openTrueAuth` messages, the system uses a different approach, converting the JSON to a `Map` and extracting the `link` field directly:

```
Type.openTrueAuth -> {
    val link = jsonConverter.toMap(json)["link"]
    LinkEvent.TrueAuth(link.toString())
}
```

### Simple Event Types

Some message types like `close`, `done`, `showClose`, and `loaded` don't require deserialization of complex payloads and map directly to sealed `LinkEvent` objects.

## Testing Framework

The system includes comprehensive testing for JSON deserialization:

- **Unit Tests** - Test individual payload deserialization with mock JSON data
- **Integration Tests** - Test the complete flow from JSON to `LinkEvent` objects
- **Sample Data** - Test resources contain realistic JSON examples for validation

The test framework uses a combination of actual JSON files and programmatically constructed expected objects to validate the deserialization accuracy.
