Would using encoder.Encode within Go's customized json marshal function be causing goroutine stack overflow?
Please take a look at (enclosed below)
https://go.dev/play/p/KXLH0B20b1u
Using encoder.Encode outside (before line 135 the // os.Exit(0)) and within Go's customized json marshal function (before line 173 the os.Exit(0)) has totally different results.
What I'm trying to do is to customize the JSON marshalling output in Go so that each field entry in the fields array is on a single line while still producing a beautified JSON output for the entire MyForm struct.
Copy of https://go.dev/play/p/KXLH0B20b1u
package main
import (
"bytes"
"encoding/json"
"fmt"
"log"
"os"
)
type MyForm struct {
Fields []Field `json:"fields"`
Button struct {
Type string `json:"type,omitempty"`
Text string `json:"text,omitempty"`
ImageURL string `json:"imageUrl,omitempty"`
Width string `json:"width,omitempty"`
Location string `json:"location,omitempty"`
LayoutGridColumnSpan int `json:"layoutGridColumnSpan,omitempty"`
} `json:"button,omitempty"`
Title string `json:"title,omitempty"`
Description string `json:"description,omitempty"`
Version string `json:"version,omitempty"`
ID int `json:"id,omitempty"`
MarkupVersion int `json:"markupVersion,omitempty"`
NextFieldID int `json:"nextFieldId,omitempty"`
UseCurrentUserAsAuthor bool `json:"useCurrentUserAsAuthor,omitempty"`
PostContentTemplateEnabled bool `json:"postContentTemplateEnabled,omitempty"`
PostTitleTemplateEnabled bool `json:"postTitleTemplateEnabled,omitempty"`
PostTitleTemplate string `json:"postTitleTemplate,omitempty"`
PostContentTemplate string `json:"postContentTemplate,omitempty"`
LastPageButton any `json:"lastPageButton,omitempty"`
Pagination any `json:"pagination,omitempty"`
FirstPageCSSClass any `json:"firstPageCssClass,omitempty"`
GfpdfFormSettings []any `json:"gfpdf_form_settings,omitempty"`
LabelPlacement string `json:"labelPlacement,omitempty"`
DescriptionPlacement string `json:"descriptionPlacement,omitempty"`
ValidationPlacement string `json:"validationPlacement,omitempty"`
SubLabelPlacement string `json:"subLabelPlacement,omitempty"`
RequiredIndicator string `json:"requiredIndicator,omitempty"`
CustomRequiredIndicator string `json:"customRequiredIndicator,omitempty"`
CSSClass string `json:"cssClass,omitempty"`
SaveButtonText string `json:"saveButtonText,omitempty"`
LimitEntries bool `json:"limitEntries,omitempty"`
LimitEntriesCount string `json:"limitEntriesCount,omitempty"`
LimitEntriesPeriod string `json:"limitEntriesPeriod,omitempty"`
LimitEntriesMessage string `json:"limitEntriesMessage,omitempty"`
ScheduleForm bool `json:"scheduleForm,omitempty"`
ScheduleStart string `json:"scheduleStart,omitempty"`
ScheduleEnd string `json:"scheduleEnd,omitempty"`
SchedulePendingMessage string `json:"schedulePendingMessage,omitempty"`
ScheduleMessage string `json:"scheduleMessage,omitempty"`
RequireLogin bool `json:"requireLogin,omitempty"`
RequireLoginMessage string `json:"requireLoginMessage,omitempty"`
GravityviewEntryModeration string `json:"gravityview_entry_moderation,omitempty"`
HoneypotAction string `json:"honeypotAction,omitempty"`
ValidationSummary bool `json:"validationSummary,omitempty"`
Deprecated string `json:"deprecated,omitempty"`
SaveEnabled string `json:"saveEnabled,omitempty"`
EnableHoneypot bool `json:"enableHoneypot,omitempty"`
EnableAnimation bool `json:"enableAnimation,omitempty"`
GvInlineEditEnable string `json:"gv_inline_edit_enable,omitempty"`
FormRevisionsEnabled string `json:"formRevisionsEnabled,omitempty"`
Save struct {
Enabled bool `json:"enabled,omitempty"`
Button struct {
Type string `json:"type,omitempty"`
Text string `json:"text,omitempty"`
} `json:"button,omitempty"`
} `json:"save,omitempty"`
ScheduleStartHour string `json:"scheduleStartHour,omitempty"`
ScheduleStartMinute string `json:"scheduleStartMinute,omitempty"`
ScheduleStartAmpm string `json:"scheduleStartAmpm,omitempty"`
ScheduleEndHour string `json:"scheduleEndHour,omitempty"`
ScheduleEndMinute string `json:"scheduleEndMinute,omitempty"`
ScheduleEndAmpm string `json:"scheduleEndAmpm,omitempty"`
}
type Field struct {
Type string `json:"type,omitempty"`
ID int `json:"id,omitempty"`
Label string `json:"label,omitempty"`
AdminLabel string `json:"adminLabel,omitempty"`
IsRequired bool `json:"isRequired,omitempty"`
Size string `json:"size,omitempty"`
ErrorMessage string `json:"errorMessage,omitempty"`
Visibility string `json:"visibility,omitempty"`
Inputs any `json:"inputs,omitempty"`
Description string `json:"description,omitempty"`
AllowsPrepopulate bool `json:"allowsPrepopulate,omitempty"`
InputMask bool `json:"inputMask,omitempty"`
InputMaskValue string `json:"inputMaskValue,omitempty"`
InputMaskIsCustom bool `json:"inputMaskIsCustom,omitempty"`
MaxLength string `json:"maxLength,omitempty"`
InputType string `json:"inputType,omitempty"`
NumberFormat string `json:"numberFormat,omitempty,omitempty"`
RangeMin string `json:"rangeMin,omitempty,omitempty"`
RangeMax string `json:"rangeMax,omitempty,omitempty"`
}
func (f Field) MarshalJSON() ([]byte, error) {
// Marshal each Field into its JSON on a single line
buffer := &bytes.Buffer{}
encoder := json.NewEncoder(buffer)
encoder.SetEscapeHTML(false)
if err := encoder.Encode(f); err != nil {
return nil, err
}
// Remove the trailing newline added by `Encode`
result := buffer.Bytes()
return result[:len(result)-1], nil
}
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
Hobbies []string `json:"hobbies,omitempty"` // omitempty: omit if empty
}
func main() {
// Create some sample data
people := []Person{
{Name: "Alice", Age: 30, Hobbies: []string{"reading", "hiking"}},
{Name: "Bob", Age: 25}, // Hobbies will be omitted in JSON
{Name: "Charlie", Age: 40, Hobbies: []string{}}, // Hobbies will be omitted in JSON because it is an empty array
}
buffer := &bytes.Buffer{}
encoder := json.NewEncoder(buffer)
encoder.SetEscapeHTML(false)
if err := encoder.Encode(people); err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println(string(buffer.Bytes()))
// os.Exit(0)
// Example data
data1 := Field{
Type: "text",
ID: 1,
Label: "Name",
AdminLabel: "",
IsRequired: true,
Size: "large",
InputType: "text",
}
data := MyForm{
Fields: []Field{
{
Type: "text",
ID: 1,
Label: "Name",
AdminLabel: "",
IsRequired: true,
Size: "large",
InputType: "text",
},
{
Type: "email",
ID: 2,
Label: "Email",
IsRequired: true,
Size: "medium",
InputType: "email",
},
},
Title: "Example Form",
Description: "This is an example form",
Version: "1.0",
ID: 123,
}
json.MarshalIndent(data1, "", " ")
os.Exit(0)
// Marshal with beautification
output, err := json.MarshalIndent(data, "", " ")
if err != nil {
log.Fatalf("Error marshaling JSON: %v", err)
}
fmt.Println(string(output))
}
MarshalIndentdoes, the indentation is an entirely separate step from marshaling. Modifying the marshaled data does not affect howIndentformats the json