2. Type Mappings

This document explains how different types are mapped in each language.

Java

In Java, types are mapped as:

Type Name Java-class
32-bit integer java.lang.Integer, int
64-bit integer java.lang.Long, long
32-bit float java.lang.Float, float
64-bit float java.lang.Double, double
String java.lang.String
Boolean java.lang.Boolean
Big Integer java.math.BigInteger
Big Decimal java.math.BigDecimal
Zoned Date Time java.time.ZonedDateTime
Local Date Time java.time.LocalDateTime
Local Date java.time.LocalDate
Local Time java.time.LocalTime
Byte Array java.lang.byte[]
Array java.util.List / java.util.ArrayList
Set java.util.Set / java.util.HashSet
Map java.util.Map / java.util.HashMap

JavaScript

Because JavaScript is more restricted in its type system, some quirks and workarounds are needed to make everything work.

Basic Types

Most basic types are mapped as follows:

Type Name Actual Type
32-bit integer number
64-bit integer number
32-bit float number
64-bit float number
String string
Boolean boolean
Big Integer bigint
Big Decimal Custom Encoder needed
Zoned Date Time Temporal.ZonedDateTime
Local Date Time Temporal.PlainDateTime
Local Date Temporal.PlainDate
Local Time Temporal.PlainTime
Byte Array Uint8Array
Array array
Set Set
Map Map

Number Type Notes

Because JavaScript natively supports only 64-bit floats, other number types require conversions at runtime, which creates some special cases. For this, underflow and overflow strategies are needed. The possibilities are:

Throwing an error (the default)

In this strategy, an error is simply thrown during serialization or deserialization.

Number Capping

In this strategy, overflowing and underflowing numbers are capped to their minimum and maximum safe values. For instance, for 64-bit integers, the maximum safe size is actually 56 bits.

This strategy can be configured as:

const cbot = Cbot.getInstance({
  numberOverflowStrategy: {
    onDeserialize: OnDeserializeOverflow.CAP_TO_BOUNDS,
    onSerialize: OnSerializeOverflow.CAP_TO_BOUNDS
  }
});

Not A Number

For deserialization, there is also the option to simply use NaN to specify underflowing and overflowing situations. This can be configured as:

const cbot = Cbot.getInstance({
  numberOverflowStrategy: {
    onDeserialize: OnDeserializeOverflow.RETURN_NAN
  }
});

Temporal API Support

Because the JavaScript Temporal API is finally emerging, the implementation also uses it as the default option. However, because the support is still experimental and requires the use of polyfills, a few considerations are needed.

Configuration

In order to use the Temporal API, it needs to be enabled as:

const cbot = Cbot.getInstance({
  temporalApiEnabled: true
})

If the Temporal API is not available, an error will be thrown.

Using Polyfills

The Temporal API has been tested (at the time of writing) with package temporal-polyfill (0.3.2) and works as expected.

In this package, the library is imported as:

import 'temporal-polyfill/global';

Note that the import order matters. The Temporal polyfill must always be imported first, or you will get weird errors. For instance, if you get an error like this:

Inconsistent Meta-class declaration detected for type 'PlainDate'. Did you use 'A'-type without Meta-class declaration as value type?

then the import happened too late and must be done earlier.

Binary Arrays

In JavaScript, the Uint8Array type is considered the binary type. If binary support is needed, special consideration is required when creating a Cbot instance, as JavaScript does not have a universal Base64 converter. Instead, each environment has its own implementations.

Configuration

For instance, in a Node environment, the Cbot instance must be configured as:

const cbot = Cbot.getInstance({
  typedArrayCoders: {
    uint8ArrayCoder: {
      encode: (value:Uint8Array) => Buffer.from(value).toString('base64'),
      decode: (value:string) => Uint8Array.from(Buffer.from(value, 'base64'))
    }
   }
});

In a browser, it can be configured as:

const cbot = Cbot.getInstance({
  typedArrayCoders: {
    uint8ArrayCoder: {
      encode: (value: Uint8Array) => {
        let binaryStr = "";
        for (let i = 0; i < value.length; i++) {
          binaryStr += String.fromCharCode(value[i]);
        }
        return btoa(binaryStr);
      },
      decode: (value: string) => {
        const binary = atob(value);
        const len = binary.length;
        const bytes = new Uint8Array(len);
        for (let i = 0; i < len; i++) {
          bytes[i] = binary.charCodeAt(i);
        }
        return bytes;
      }
    }
  }
});

Python

Python has quite a complete set of different types, although numeric types require some extra attention.

Basic Types

Most basic types are mapped as follows:

Type Name Actual Type
32-bit integer int
64-bit integer int
32-bit float float
64-bit float float
String str
Boolean bool
Big Integer int
Big Decimal Decimal
Zoned Date Time datetime (with zone-info)
Local Date Time datetime (without zone-info)
Local Date date
Local Time time
Byte Array bytearray
Array list
Set set
Map Map (Custom dictionary)

Number Type Notes

Because Python has only a big integer type for all integers, the Cbot instance can be configured in three different ways regarding how it serializes integers in the untyped mode. The possibilities are:

This mode is configured via CbotOptions.

Map Notes

In Python, the default "map" is a dictionary. Unfortunately, it has a double role as an anonymous object, which is common when parsing JSON. For instance, in Java and JavaScript, both cases have well-defined counterparts. Thus, for Python, a Map class was created to specify that it is indeed a map and not an anonymous object.