-4

I have a struct with some fields as follows:

type Test struct {
    ID        int          `json:"id"`
    Active    bool         `json:"active"`
    Object    []obj.Object `json:"objects"`
}

Then some handler functions that encode Test objects to JSON as a response, but in one of the functions, I want to omit the last field "objects" from the response. I know json:"-" omits it but problem is I need that field for the others functions.

The way I encode the object to JSON is using this method:

 json.NewEncoder(w).Encode(t)

Is there a way I can achieve that? Thanks in advance!

jupcan
  • 436
  • 3
  • 7
  • 17
  • 3
    If your struct really has only two tiny objects you want to encode, why not create a new (temporary struct) with just those two? – Marc Aug 24 '20 at 10:10
  • 3
    What Marc says, or https://play.golang.org/p/h6ijXT_44Dr – mkopriva Aug 24 '20 at 10:13
  • Duplicate. There is no magic encoding/json flag for this. Use Marc's or mkopriva's solution. – Volker Aug 24 '20 at 10:25
  • @Marc Thank you very much! Have created the tmp struct while calling encode and filled those temporary fields with the ones from the object real strcut. – jupcan Aug 24 '20 at 10:42
  • 1
    @mkopriva thanks for your answer! Since I have not too many fields I have opted to pass the temporary struct on the encode function call instead of defining it as you suggest. – jupcan Aug 24 '20 at 10:43

3 Answers3

2

You can use omitempty tag with the struct of pointers. In this case, If the pointers are nil, the fields won't be Marshalled.(https://play.golang.org/p/7DihRGmW0jZ) For Example

package main

import (
    "encoding/json"
    "fmt"
)

type Test struct {
        ID          *int          `json:"id,omitempty"`
        Active      *bool         `json:"active,omitempty"`
        Object      *interface{}  `json:"objects,omitempty"`
}

func main() {
    var result Test
    id:= 1
    active := true

    result.ID = &id
    result.Active = &active
    
    b, err := json.Marshal(result)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%s\n", b)
}
Dharman
  • 30,962
  • 25
  • 85
  • 135
Ashish Sharma
  • 406
  • 3
  • 11
2

@alessiosavi's solution using omitempty is often the easiest, but here is an alternative solution that can be used for more complex scenarios. This leverages the fact that a value can be cast to another type as long as the structure is the same, even if the tags are not: https://play.golang.org/p/ZT6gbhsXxmD

type Test struct {
    ID     int      `json:"id"`
    Active bool     `json:"active"`
    Object []Object `json:"objects,omitempty"`
}

type Test2 struct {
    ID     int      `json:"id"`
    Active bool     `json:"active"`
    Object []Object `json:"-"`
}

func main() {
    var t Test
    t.ID = 1
    t.Active = true
    t.Object = make([]Object, 1)
    fmt.Println("Test:")
    json.NewEncoder(os.Stdout).Encode(t)
    fmt.Println("Test2:")
    t2 := Test2(t)
    json.NewEncoder(os.Stdout).Encode(&t2)
}

This can be useful in a lot of cases, e.g. where you don't want to remove the value from the field before sending to JSON, or you've got a more complex data structure.

Adrian
  • 42,911
  • 6
  • 107
  • 99
1

The simple way for omit a value is use the omitempty tag for the json and write a method that return the object as following:

package main

import (
    "encoding/json"
    "fmt"
    "os"
)

type Test struct {
    ID     int      `json:"id"`
    Active bool     `json:"active"`
    Object []Object `json:"objects,omitempty"`
}

type Object struct {
    TEMP string
}

func (t Test) getData() Test {
    return Test{ID: t.ID, Active: t.Active}
}

func main() {
    var t Test
    t.ID = 1
    t.Active = true
    t.Object = make([]Object, 1)
    fmt.Println(t)
    fmt.Println(t.getData())
    json.NewEncoder(os.Stdout).Encode(t)
    fmt.Println("--------")
    json.NewEncoder(os.Stdout).Encode(t.getData())
}

The result is the following one:

{1 true [{}]}
{1 true}
{"id":1,"active":true,"objects":[{"TEMP":""}]}
--------
{"id":1,"active":true}
alessiosavi
  • 2,753
  • 2
  • 19
  • 38