1

I am a newbie at GO Programming. Here is scenario :-

There exists a JSON file that looks like this :-

{
        "template": "linuxbase1",
        "checkname": ["check_disk"],
        "checkmethod": ["check_disk"]
}

I am Unmarshalling this data into a structure :-

package func1

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

type pluginfunc func() string
type Plugindata struct {
        Template string `json:"template"`
        Checkname []string `json:"checkname"`
        Checkmethod []pluginfunc `json:"checkmethod"`
}

var (
        Templatepath = "json_sample1.json"
        Templateitems Plugindata
)

func Gettemplatedata() {
        tdata, err := ioutil.ReadFile(Templatepath)
        if err != nil {
                fmt.Printf("Unable to read file %s. Error - %v\n",Templatepath, err.Error())
                os.Exit(3)
        }
        json.Unmarshal(tdata, &Templateitems)
}

The "check_disk" function is here :-

package func1

func check_disk() string {
        return "Called check_disk"
}

This is the program with main() :-

package main

import (
        "fmt"
        "checksexpt/func1"
)

func main() {
        func1.Gettemplatedata()
        fmt.Printf("Templateitems in Main() => %v\n",func1.Templateitems)
        for index,funcname := range func1.Templateitems.Checkmethod {
                fmt.Printf("%d = %s\n",index,funcname())
        }

}

As expected, when I run main(); I see the error :-

Templateitems in Main() => {linuxbase1 [check_cpu check_disk] [<nil> <nil>]}
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x0 pc=0x40115e]

goroutine 1 [running]:
panic(0x50e980, 0xc82000a100)
        /opt/go/src/runtime/panic.go:481 +0x3e6

So, I am trying to grab a string from the JSON file and treat it as a function call. That obviously fails ! But, the primary constraint here is that the function names have to be picked from the JSON file. How can I do this ? I know that I can create a static map as follows :-

type checkfunc func() string
var (
        Templateitems = map[string]map[string]checkfunc {
                "linuxbase1": {
                        "check_disk": check_disk,
                },
        }
)

So, A call like - Templateitems["linuxbase1"]["check_disk"]() would work just fine. But, I dont want to create any such static map as the elements in that map needs to keep growing. Any ideas on this?

1 Answer 1

2

There is no direct way to parse a function directly from a JSON value. Also, you cannot use string values to refer to variables. So a string check_cpu would not be able to refer to the function with the same name directly.

What you can do instead is parse the json string as is and have a global map for functions. That way, you can call your functions like so:

var funcMap = map[string]pluginfunc{
    "check_disk": check_disk,
    "check_cpu": check_cpu
}

In your main loop:

for index, funcname := range func1.Templateitems.Checkmethod {
        fmt.Printf("%d = %s\n", index, funcMap[funcname]())
}

If however, you really need to put the value in your structure, you can try implementing UnmarshalJSON from the json.Unmarshaler interface. A simple example would be:

type pf map[string]pluginfunc

type Plugindata struct {
        Template string `json:"template"`
        Checkname []string `json:"checkname"`
        Checkmethod pf `json:"checkmethod"`
}

func (p *pf) UnmarshalJSON(data []byte) error {
    d := []string{}
    if err := json.Unmarshal(data, &d); err != nil {
        return err
    }
    *p = make(pf)
    for _, s := range d {
        (*p)[s] = funcMap[s]
    }
    return nil
}

var funcMap = pf{
    "check_disk": check_disk,
    "check_cpu": check_cpu
}

func main() {
    json.Unmarshal(tdata, &Templateitems)
    for k, f := range Templateitems.Checkmethod {
        fmt.Printf("%s -- %s\n", k, f())
    }
}

Working code

Note that this way is not as readable or simple as the first method and it still relies on a function map.

You can read more about json.Unmarshaler here.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.