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:
Marshalimports a Go structure or map into an FTL message.Unmarshalexports 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.
| Go Type | Marshals to FTL Message Field Type |
|---|---|
IT
|
TIB_FIELD_TYPE_LONG
|
FT
|
TIB_FIELD_TYPE_DOUBLE
|
[]IT
|
TIB_FIELD_TYPE_LONG_ARRAY
|
[]FT
|
TIB_FIELD_TYPE_DOUBLE_ARRAY
|
string
|
TIB_FIELD_TYPE_STRING
|
[]string
|
TIB_FIELD_TYPE_STRING_ARRAY
|
byte
Note:
[]*byte and
*[]*byte are not allowed.
|
TIB_FIELD_TYPE_OPAQUE
|
time.Time
|
TIB_FIELD_TYPE_DATETIME
|
[]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
|
TIB_FIELD_TYPE_MESSAGE
|
[]ftl.Message
|
TIB_FIELD_TYPE_MESSAGE_ARRAY
|
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.
|
| FTL Message Field Type | Unmarshals to Go Type |
|---|---|
TIB_FIELD_TYPE_LONG
Supports strict conversion. |
IT
|
TIB_FIELD_TYPE_DOUBLE
Supports strict conversion. |
FT
|
TIB_FIELD_TYPE_LONG_ARRAY
|
[]IT
The target struct must be a slice, not an array. |
TIB_FIELD_TYPE_DOUBLE_ARRAY
|
[]FT
The target struct must be a slice, not an array. |
TIB_FIELD_TYPE_STRING
|
string
|
TIB_FIELD_TYPE_STRING_ARRAY
|
[]string
The target struct must be a slice, not an array. |
TIB_FIELD_TYPE_OPAQUE
|
byte
|
TIB_FIELD_TYPE_DATETIME
|
time.Time
|
TIB_FIELD_TYPE_DATETIME_ARRAY
|
[]time.Time
The target struct must be a slice, not an array. |
TIB_FIELD_TYPE_MESSAGE
|
structure
embedded structure
|
TIB_FIELD_TYPE_MESSAGE_ARRAY
|
Array of structures
The target struct must be a slice, not an array. |
TIB_FIELD_TYPE_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
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
Zero values include
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.