MarshalJSON a String Declared Type - go

I have created a new declared type and added a method to marshal the value into JSON
type TextOutput string
func (t *TextOutput) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf(`{"data": "%s"}`, t)), nil
}
When I try to marshal an instance of the type I get the raw value returned. What am I missing?
var t TextOutput
t = `Test test`
output, err := json.Marshal(t)
if err != nil {
fmt.Println(err)
} else {
fmt.Println(string(output))
}
// prints Test Test. Expected {"data": "Test test"}

You have to define the MarshalJSON interface as a non-pointer.
func (t TextOutput) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf(`{"data": "%s"}`, t)), nil
}
Play Link: https://play.golang.org/p/lLK6zsAkOi
Output:
{"data":"Test test"}

The root of the problem stems from how interfaces in Go are implicitly satisfied.
In this particular case, the json.Marshal method uses type assertion at runtime to see if the given value implements json.Marshaler. Effective Go mentions this very case.
You could have satisfied the json.Marshaler for the *TextOutput type using a pointer-receiver like so:
func (t *TextOutput) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf(`{"data":"%s"}`, *t)), nil
}
And for this to work properly, pass the reference to the json.Marshal function:
var t TextOutput
t = `Test test`
output, err := json.Marshal(&t)
However, implementing it using a value-receiver ensures that both TextOutput and *TextOutput types implement json.Marshaler
func (t TextOutput) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf(`{"data": "%s"}`, t)), nil
}

Related

Mocking via stretchr/testify, different return args

Function below describes how to mock using testify. args.Bool(0), args.Error(1) are mocked positional return values.
func (m *MyMockedObject) DoSomething(number int) (bool, error) {
args := m.Called(number)
return args.Bool(0), args.Error(1)
}
Is it possible to return anything other than args.Int(), args.Bool(), args.String()? What if I need to return int64, or a custom struct. Is there a method or am I missing something?
For example:
func (m *someMock) doStuff(p *sql.DB, id int) (res int64, err error)
Yes, it is possible by using args.Get and type assertion.
From the docs:
// For objects of your own type, use the generic Arguments.Get(index) method and make a type assertion:
//
// return args.Get(0).(*MyObject), args.Get(1).(*AnotherObjectOfMine)
So, your example would be:
func (m *someMock) doStuff(p *sql.DB, id int) (res int64, err error) {
args := m.Called(p, id)
return args.Get(0).(int64), args.Error(1)
}
Additionaly, if your return value is a pointer (e.g. pointer to struct), you should check if it is nil before performing type assertion.

How do I Override UnmarshalJSON Correctly?

I am trying to write a simple custom marshaler and failing. Notice I have an interface that has three functions. Both Happy and Sad structs implement this interface by embedding the emotion struct which implements all the three required functions.
The problem is UnmarshalJSON does not get invoked when I call json.Unmarshal() on the pointer to either Happy or Sad and I can't understand why. You can reproduce the exact codebase in Go Playground or just look below. You will notice that while MarshalJSON is correctly called, UnmarshalJSON isn't.
type Emotion interface {
String() string
MarshalJSON() ([]byte, error)
UnmarshalJSON(data []byte) error
}
type emotion struct {
status string
}
func (s emotion) String() string {
return s.status
}
func (s emotion) MarshalJSON() ([]byte, error) {
fmt.Println("MarshalJSON is overriden: I am called fine")
x := struct {
Status string
}{
Status: s.String(),
}
return json.Marshal(x)
}
func (s *emotion) UnmarshalJSON(data []byte) error {
fmt.Println("MarshalJSON is overriden: I am never called")
y := struct {
Status string
}{
Status: "",
}
err := json.Unmarshal(data, &y)
if err != nil {
return err
}
s.status = y.Status
return nil
}
type Happy struct {
*emotion
}
// Job is not in any detention
type Sad struct {
*emotion
}
func main() {
x := Happy{&emotion{status: "happy"}}
jsonX, _ := json.Marshal(x)
var y Emotion
err := json.Unmarshal(jsonX, &y)
fmt.Printf("%v", err)
}
You cannot unmarshal into an abstract interface type.
An interface value is just a pointer to a type (associating that types methods) - it has no storage behind it - because an abstract type cannot know the exact size of any concrete value it may have in the future.
Using a concrete value type (that also implements that interface) will work:
y2 := emotion{}
err = json.Unmarshal(jsonX, &y2)
Playground: https://play.golang.org/p/8aCEjLgfKVQ
MarshalJSON is overriden: I am called fine
EXPECTED ERROR, Can't unmarshal into a non-concrete value: json: cannot unmarshal object into Go value of type main.Emotion
MarshalJSON is overriden: I am (fixed) and now called
SHOULD NOT ERROR: <nil>
VALUE: happy

How do you mock a type within a type in Golang?

The package 'gopkg.in/redis.v3' contains some code
type Client struct {
}
func (*client) Eval (string, []string, []string) *Cmd {
}
type Cmd struct {
}
func (*Cmd) Result () (interface{}, error) {
}
Which works successfully in the following way
func myFunc (cli *redis.Client) {
result, err := cli.Eval('my script').Result()
}
The problem is that sometimes the Redis cluster gets hammered, has a moment, and the interface returned as a result is nil.
This is reasonably easy to handle but I wish to put a test in place that will ensure that it is actually handled and no type assertion panic occurs.
Traditionally I would insert a mock Redis client into myFunc that can ultimately return nil.
type redisClient interface {
Eval(string, []string, []string) redisCmd
}
type redisCmd interface {
Result() (interface{}, error)
}
func myFunc (cli redisClient) {
result, err := cli.Eval('my script').Result()
}
The problem I am facing is the compiler doesn't recognise that redis.Client satisfies the interface redisClient because it doesn't recognise that the redis.Cmd returned from Eval satisfies redisCmd.
> cannot use client (type *redis.Client) as type redisClient in argument to myFunc:
> *redis.Client does not implement redisClient (wrong type for Eval method)
> have Eval(sting, []string, []string) *redis.Cmd
> want Eval(sting, []string, []string) redisCmd
The problem is that your interface does not match the redis client. If you change the interface to:
type redisClient interface {
Eval(string, []string, []string) *redis.Cmd
}
it will compile. That being said, it looks like you really want rediscmd, so you will need to make a wrapper around the redis client:
type wrapper struct{
c *redis.Client
}
func (w wrapper) Eval(x sting, y []string, z []string) redisCmd {
return w.c.Eval(x,y,z) // This assumes that *redis.Cmd implements rediscmd
}

Strange behaviour when Unmarshalling into struct in Go

I'm developing a tool that can be implemented to simplify the process of creating simple CRUD operations/endpoints. Since my endpoints don't know what kind of struct they'll be receiving, I've created an interface that users can implement, and return an empty object to be filled.
type ItemFactory interface {
GenerateEmptyItem() interface{}
}
And the users would implement something like:
type Test struct {
TestString string `json:"testString"`
TestInt int `json:"testInt"`
TestBool bool `json:"testBool"`
}
func (t Test) GenerateEmptyItem() interface{} {
return Test{}
}
When the Test object gets created, its type is "Test", even though the func returned an interface{}. However, as soon as I try to unmarshal some json of the same format into it, it strips it of its type, and becomes of type "map[string]interface {}".
item := h.ItemFactory.GenerateEmptyItem()
//Prints "Test"
fmt.Printf("%T\n", item)
fmt.Println(reflect.TypeOf(item))
err := ConvertRequestBodyIntoObject(r, &item)
if err != nil {...}
//Prints "map[string]interface {}"
fmt.Printf("%T\n", item)
Func that unmarshalls item:
func ConvertRequestBodyIntoObject(request *http.Request, object interface{}) error {
body, err := ioutil.ReadAll(request.Body)
if err != nil {
return err
}
// Unmarshal body into request object
err = json.Unmarshal(body, object)
if err != nil {
return err
}
return nil
}
Any suggestions as to why this happens, or how I can work around it?
Thanks
Your question lacks an example showing this behavior so I'm just guessing this is what is happening.
func Generate() interface{} {
return Test{}
}
func GeneratePointer() interface{} {
return &Test{}
}
func main() {
vi := Generate()
json.Unmarshal([]byte(`{}`), &vi)
fmt.Printf("Generate Type: %T\n", vi)
vp := GeneratePointer()
json.Unmarshal([]byte(`{}`), vp)
fmt.Printf("GenerateP Type: %T\n", vp)
}
Which outputs:
Generate Type: map[string]interface {}
GenerateP Type: *main.Test
I suggest you return a pointer in GenerateEmptyItem() instead of the actual struct value which is demonstrated in the GenerateP() example.
Playground Example

Function that accepts generic struct

Is it possible to have my function definition below accept any type of struct?
I've tried to refactor like so:
// This method should accept any type of struct
// Once I receive my response from the database,
// I scan the rows to create a slice of type struct.
func generateResponse(rows *sqlx.Rows, structSlice []struct{}, structBody struct{}) ([]struct{}, error) {
for rows.Next() {
err := rows.StructScan(&structBody)
if err != nil {
return nil, err
}
structSlice = append(structSlice, structBody)
}
err := rows.Err()
if err != nil {
return nil, err
}
return structSlice, nil
}
Assume my struct is of type OrderRevenue.
When I call the function above:
structSlice, err := generateResponse(rows, []OrderRevenue{}, OrderRevenue{})
The error I get is:
cannot use []OrderRevenue literal as type []struct{} in argument...
Am I going about this the wrong way?
This is considered the cornerstone (or more of a limitation) of Go's type system. struct{} is an unnamed type that is different from struct{ field1 int } and of course is not the same as OrderRevenue{}.
Go emphasizes abstraction through interfaces, and perhaps you should try that. Here is the first take:
type OrderRevenue interface {
MarshalMyself() ([]byte, error)
}
type Anonymous struct {}
func (a Anonymous) MarshalMyself() ([]byte, error) {
// implementation's up to you
return []byte{}, nil
}
// the function signature
generateResponse(rows *sqlx.Rows, structSlice []OrderRevenue, structBody Body) ([]Body, error) {
// ...
}
In this case you can also use empty interface interface{}, which all types implement, but you'll have to recursively go through the structure to do manual type assertion. The best approach in Go is to know the shape of your data in advance, at least partially.

Resources