Open topic with navigation

# Go: Marshal Method for FTL Messages

The FTL Go language API implements the marshal and unmarshal interfaces to convert message datatype.

## Methods

The `Message` type has two methods to conveniently import and export message fields:

- `Marshal` imports a Go structure or map into an FTL message.
- `Unmarshal` exports the fields of an FTL message to a Go structure or map.

FTL marshaling and unmarshaling support only those maps with key type string.

Marshaling ignores nil as the field value of a Go structure and as a slice element.

## FTL Numeric Field Types

FTL messages store all Go language integral types as `TIB_FIELD_TYPE_LONG` fields, corresponding to the Go language type `int64`.

FTL messages store all Go language floating-point types as `TIB_FIELD_TYPE_DOUBLE` fields, corresponding to the Go language type `float64`.

These designations apply within the following tables.

- IT refers to any of the following integral types: `int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr, bool`.
- FT refers to any of the following floating-point types: `float32, float64`.

Conversion of Go Types to FTL Fields
Go Type | Marshals to FTL Message Field Type
--- | ---
`IT` `*IT` | `TIB_FIELD_TYPE_LONG`
`FT` `*FT` | `TIB_FIELD_TYPE_DOUBLE`
`[]IT` `*[]IT` `[]*IT` `*[]*IT` | `TIB_FIELD_TYPE_LONG_ARRAY`
`[]FT` `*[]FT` `[]*FT` `*[]*FT` | `TIB_FIELD_TYPE_DOUBLE_ARRAY`
`string` `*string` | `TIB_FIELD_TYPE_STRING`
`[]string` `*[]string` `[]*string` `*[]*string` | `TIB_FIELD_TYPE_STRING_ARRAY`
`byte` `*byte` Note: `[]*byte` and `*[]*byte` are not allowed. | `TIB_FIELD_TYPE_OPAQUE`
`time.Time` `*time.Time` | `TIB_FIELD_TYPE_DATETIME`
`[]time.Time` `*[]time.Time` `[]*time.Time` `*[]*time.Time` | `TIB_FIELD_TYPE_DATETIME_ARRAY`
structure pointer to structure | `TIB_FIELD_TYPE_MESSAGE`
embedded structure pointer to embedded structure | individual fields within the message
`ftl.Message` `*ftl.Message` | `TIB_FIELD_TYPE_MESSAGE`
`[]ftl.Message` `*[]ftl.Message` `[]*ftl.Message` `*[]*ftl.Message` | `TIB_FIELD_TYPE_MESSAGE_ARRAY`
`ftl.Inbox` `*ftl.Inbox` | `TIB_FIELD_TYPE_INBOX`
`map[string]` | `TIB_FIELD_TYPE_MESSAGE` Note: Each element of the map marshals into a field within the message, with the element key becoming the field name. The key type must be `string`.

Conversion of FTL Fields to Go Types
FTL Message Field Type | Unmarshals to Go Type
--- | ---
`TIB_FIELD_TYPE_LONG` Supports strict conversion. | `IT` `*IT`
`TIB_FIELD_TYPE_DOUBLE` Supports strict conversion. | `FT` `*FT`
`TIB_FIELD_TYPE_LONG_ARRAY` | `[]IT` `*[]IT` `[]*IT` `*[]*IT` The target struct must be a slice, not an array.
`TIB_FIELD_TYPE_DOUBLE_ARRAY` | `[]FT` `*[]FT` `[]*FT` `*[]*FT` The target struct must be a slice, not an array.
`TIB_FIELD_TYPE_STRING` | `string` `*string`
`TIB_FIELD_TYPE_STRING_ARRAY` | `[]string` `*[]string` `[]*string` `*[]*string` The target struct must be a slice, not an array.
`TIB_FIELD_TYPE_OPAQUE` | `byte` `*byte`
`TIB_FIELD_TYPE_DATETIME` | `time.Time` `*time.Time`
`TIB_FIELD_TYPE_DATETIME_ARRAY` | `[]time.Time` `*[]time.Time` `[]*time.Time` `*[]*time.Time` The target struct must be a slice, not an array.
`TIB_FIELD_TYPE_MESSAGE` | structure embedded structure `ftl.Message` `*ftl.Message` `map[string]` `*map[string]`
`TIB_FIELD_TYPE_MESSAGE_ARRAY` | Array of structures `[]ftl.Message` `*[]ftl.Message` `[]*ftl.Message` `*[]*ftl.Message` `[]map[string]` `*[]map[string]` The target struct must be a slice, not an array.
`TIB_FIELD_TYPE_INBOX` | `ftl.Inbox` `*ftl.Inbox`

## Field Tags in struct Definitions

For convenience, you can use field tags to guide marshaling and unmarshaling (similar to JSON processing). For example:

    type myStructType struct {
        myFieldA   int `json:"my_field_A" ftl:"myFieldA"`
        myFieldB   int `json:"my_field_B" ftl:"myFieldB,strict"`
        myFieldC   int `json:"my_field_C" ftl:"myFieldC,zeromissing,omitzero"`
    }

FTL software recognizes tags with this general form:

    ftl:"<fieldname>[,<options>]"

- `<fieldname>` is the name of a field in an FTL message, corresponding to the tagged field of the Go struct definition.
- `<options>` is a comma-separated list of options to apply marshaling and unmarshaling the field (see the following table).
- Separate the individual tags with a space character. Each line of the example illustrates this with a space between the JSON tag and FTL tag.

Option | Description
--- | ---
`strict` | When unmarshaling, enforce strict conversion for numeric fields. In strict conversion, the sign of a numeric FTL field value must be compatible with the corresponding Go language field type. If it is not compatible, the unmarshal call returns an error. For example, consider the effect of unmarshaling an FTL message field with type `TIB_FIELD_TYPE_LONG`. The value 100 fits into any unsigned Go field, or into an `int8`. But the value -1000 does not fit, and strict conversion would reject it. Non-strict conversion could yield unpredictable values for values that do not fit.
`zeromissing` | When unmarshaling, supply zero values for missing fields. If the target Go struct definition specifies a field but a corresponding field does not exist in the source FTL message, then conversion sets the Go field to the zero value of its field type. When this option is absent, unmarshaling does not modify the target Go field unless the field is present in the FTL message.
`omitzero` | When marshaling, omit fields that contain the zero value. This option is analogous to `omitempty` in JSON marshaling. If the Go field contains the zero value for its type, then marshaling does not add a corresponding field to the FTL message. Zero values include `false`, `0`, `0.0`, `""`, a nil pointer or interface value, and any empty array, slice, map, structure, or string. When this option is absent, marshaling adds an FTL field corresponding to every Go field.
`format=<format_name>` | Marshal a Go field value that is itself a nested structure to an FTL message with format < format_name>. (Use this option when your FTL application definition manages all formats.) When this option is absent, marshal a nested structure to an FTL message of unnamed dynamic format (that is, null format name).

## Examples

The FTL go API provides a simple mechanism for marshaling structures into an FTL message, and for unmarshaing FTL messages into a structure. The use of field tags is similar to that found in the encoding/json package. Note that structure fields must be exportable in order to be marshaled or unmarshaled. In simple terms, this means the field name must begin with an upper-case letter.

Marshal/unmarshal also supports the use of maps, in the form `map[string]interface{}`. In this case, the FTL field name corresponds to the map entry key, and the FTL field value corresponds to the map entry value.

The following example unmarshals message data into a Go structure:

    type HelloMessage struct {
    	Type  string `ftl:"type"`
    	Message string `ftl:"message"`
    }
    func main() {
    	// Create an instance of the HelloMessage structure. Then unmarshal
    	// the message into the structure, based on the tags attached to
    	// each field in the structure.
    	//
    	// Note that a pointer to the structure (or map) must be passed to
    	// the Unmarshal() function.
    	helloMsg := HelloMessage{}
    	if err = msg.Unmarshal(&helloMsg); err != nil {
    	log.Fatal(ftl.ErrStack(err))
    	}
    	// Print the message contents, both as a formatted FTL message
    	// (via the message String() function) and the as the
    	// unmarshaled structure content (using go's %#v formatting directive).
    	//
    	log.Printf("message: %s\n", msg.String())
    	log.Printf("Unmarshalled message: %#v\n", helloMsg)
    }

The following example marshals Go structure data into a message:

    func main() {
    	msg, err := realm.NewMessage("helloworld")
    	if err != nil {
    	log.Fatal(ftl.ErrStack(err))
    	}
    	// Defer the destruction of the message.
    	defer msg.Destroy()
    	// Construct the message content into a map[string]interface{}.
    	content := make(map[string]interface{})
    	content["type"] = "hello"
    	content["message"] = "hello world earth"
    	// Marshal the message content into the FTL message. Note that a
    	// pointer to the map must be passed to msg.Marshal().
    	if err = msg.Marshal(&content); err != nil {
    	log.Fatal(ftl.ErrStack(err))
    	}
    }

For more information about FTL message marshaling/unmarshaling, see the samples in `.../samples/src/golang/src/tibco.com/ftl-sample`.

Did you find this helpful?

Yes No
Great!
Thanks for taking the time to give us some feedback.
Sorry about that

Why wasn't this helpful? (check all that apply)

Could not find what I was looking for
Instructions confusing or unclear
Instructions did not work

Want to tell us more?

Please select at least one option or provide details about the issue!!

Error occurred while submitting feedback.

Error2 occurred while submitting feedback.

TIBCO FTL® - Enterprise Edition

Copyright © 2009-2024. Cloud Software Group, Inc. All Rights Reserved.