2

I am trying to decode an arbitrary JSON using Golang, so I unmarshal the incoming JSON in a map[string]interface{} as shown in the code below:

    func JsonHandler(jsonRequest []byte) {

      // Creating the maps for JSON
      var m interface{}

      // Parsing/Unmarshalling JSON encoding/json
      if err := json.Unmarshal([]byte(jsonRequest), &m); err != nil {
            panic(err)
       }

       //Creating an output file for writing
       f, err := os.OpenFile("/home/dorrahadrich/Desktop/output.txt", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
       if err != nil {
           panic(err)
       }

       defer f.Close()

       ParseJson(m, f, err)
   }

   func ParseJson(m interface{}, f *os.File, err error) {
       switch v := m.(interface{}).(type){
          case map[string]interface{}:
               ParseMap (m.(map[string]interface{}),f,err)
               fmt.Println(v)
          case []interface{}:
               ParseArray (m.([]interface{}),f,err)
               fmt.Println(v)
          default:
     }
 }

   func ParseMap(aMap map[string]interface{}, f *os.File, err error) {
    for key, val := range aMap {
        switch val.(type) {
        case map[string]interface{}:
            if _, err = f.WriteString(key + "={\n"); err != nil {
                panic(err)
            }

            ParseMap(val.(map[string]interface{}), f, err)

            //Close brackets
            if _, err = f.WriteString("};\n"); err != nil {
                panic(err)
            }

        case []interface{}:
            //Write to file
            if _, err = f.WriteString(key + "={\n"); err != nil {
                panic(err)
            }

            ParseArray(val.([]interface{}), f, err)

            //Close brackets
            if _, err = f.WriteString("};\n"); err != nil {
                panic(err)
            }
        default:
            otherValues(key, val.(interface{}), f , err)
        }
    }
}

func ParseArray(anArray []interface{}, f *os.File, err error) {
    for _, val := range anArray {
        switch val.(type) {
        case map[string]interface{}:
            ParseMap(val.(map[string]interface{}), f, err)
        case []interface{}:
            ParseArray(val.([]interface{}), f, err)
        default:
        }
    }

}
func otherValues(key string, other interface{}, f *os.File, err error) {
     if _, err = f.WriteString(key); err != nil {
           panic(err)
        }
    if _, err = f.WriteString("="); err != nil {
        panic(err)
        }

   switch other.(interface{}).(type) {
       case string:
           if _, err = f.WriteString(other.(string)); err != nil {
               panic(err)
            }
       case float64:
           if _, err = f.WriteString(strconv.FormatFloat(other.(float64), 'f', -1, 64)); err != nil {
                panic(err)
            }
       case bool:
    if _, err = f.WriteString(strconv.FormatBool(other.(bool))); err != nil {
                panic(err)
            }
       default:
     }  
   }

The problem is that whenever a JSON contains a bool/int/float or any not string value the program panics saying that it fails converting an interface to the given type! Please note that the JSON is arbitrary so I don't have any idea about the keys nor the values, I can't unmrashal into an interface nor access the values giving a path.

6
  • Unmarshal into a simple value of type interface{}. Does that work for you? Any valid JSON can be unmarshaled into that. Commented Mar 5, 2018 at 9:12
  • This is because When you are unmarshalling a json to interface{} it can also contain bool/float64/string. You have to add cases for the same too Commented Mar 5, 2018 at 9:12
  • I tried to switch the type of the "val" and convert it to string before passing it to the f.WriteString function, still the same error!! Commented Mar 5, 2018 at 9:12
  • any example failed json would help Commented Mar 5, 2018 at 9:13
  • You aren't handling strings, float and bools. Commented Mar 5, 2018 at 9:27

1 Answer 1

2

The error says it all:

interface conversion: interface{} is bool/float64

when you are unmarshalling json the values for int and bool which are not of interface type. In your switch add case for bool/float64/string too. Since json is arbitrary unmarshal them using interface{}.

func otherValues(other interface{}, f *os.File, err error) {
    switch bb := other.(interface{}).(type) {
    case string:
        fmt.Println("This is a string")
    case float64:
        fmt.Println("this is a float")
    case bool:
        fmt.Println("this is a boolean")
    default:
        fmt.Printf("Default value is of type %v", bb)
    }
}

Use file.Write in place of file.WriteString

func (f *File) Write(b []byte) (n int, err error)

Write writes len(b) bytes to the File. It returns the number of bytes written and an error, if any. Write returns a non-nil error when n != len(b).

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

10 Comments

I did unmarshal JSON into an interface{} and then did a switch of the real type of the interface{} and added the cases as you said but I am still getting the same error.
Show the json that you are unmarshalling and the code that you have tried after passing data. Are you getting same error
May be you are using file.WriteString that's why the string can be written. You can use file.Write
I have found a mistake in your code and edited it. We needs to convert other.(bool) to other.(interface{}).(bool)
But I am converting values to string before using the file.WriteString!
|

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.