Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Serialize a map using a specific order

I have a map that uses string for both key and value. I have an array of keys that specifies the order of the values of the map.

I want to serialize that map to a JSON, but keeping the order defined on the array.

There is a sample code here: http://play.golang.org/p/A52GTDY6Wx

I want to serialize it as:

{
  "name": "John",
  "age": "20"
}

But if I serialize the map directly, the keys are ordered alphabetically:

{      
  "age": "20",
  "name": "John"
}

I can serialize it as an array of maps, thus keeping the order, however that generates a lot of undesired characters:

[
  {
    "name": "John"
  },
  {
    "age": "20"
  }
]

In my real code I need to serialize the results of a database query which is specified in a text file, and I need to maintain the column order. I cannot use structs because the columns are not known at compile time.

EDIT: I don't need to read the JSON later in the specified order. The generated JSON is meant to be read by people, so I just want it to be as humanly readable as possible.

I could use a custom format but JSON suits me perfectly for this.

Thanks!

like image 434
Ricardo Smania Avatar asked Aug 07 '14 12:08

Ricardo Smania


People also ask

How to serialize a Java Map?

Java Maps are collections that map a key Object to a value Object, and are often the least intuitive objects to serialize. 3.1. Map<String, String> Serialization For a simple case, let's create a Map<String, String> and serialize it to JSON:

How to serialize a map<string> to JSON in Jackson?

For a simple case, let's create a Map<String, String> and serialize it to JSON: Map<String, String> map = new HashMap<> (); map.put ( "key", "value" ); ObjectMapper mapper = new ObjectMapper (); String jsonResult = mapper.writerWithDefaultPrettyPrinter () .writeValueAsString (map); ObjectMapper is Jackson's serialization mapper.

How to serialize a Java object to JSON?

Serialization converts a Java object into a stream of bytes, which can be persisted or shared as needed. Java Maps are collections which map a key Object to a value Object and are often the least intuitive objects to serialize. 3.1. Map<String, String> Serialization For the simple case, let's create a Map<String, String> and serialize it to JSON:

How to sort a map by key in Java 8?

Since Java 8, Map.Entry class has a static method comparingByKey () to help you in sorting by keys. This method returns a Comparator that compares Map.Entry in natural order on key. Alternatively, we can pass a custom Comparator to use in sorting. This can be used to sort the map in reverse order. 2.1. Ascending Order


1 Answers

You need to implement the json.Marshaler interface on a custom type. This has the advantage of playing well within other struct types.

Sorry, you're always going to have to write a little bit of JSON encoding code.

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "log"
)

type KeyVal struct {
    Key string
    Val interface{}
}

// Define an ordered map
type OrderedMap []KeyVal

// Implement the json.Marshaler interface
func (omap OrderedMap) MarshalJSON() ([]byte, error) {
    var buf bytes.Buffer

    buf.WriteString("{")
    for i, kv := range omap {
        if i != 0 {
            buf.WriteString(",")
        }
        // marshal key
        key, err := json.Marshal(kv.Key)
        if err != nil {
            return nil, err
        }
        buf.Write(key)
        buf.WriteString(":")
        // marshal value
        val, err := json.Marshal(kv.Val)
        if err != nil {
            return nil, err
        }
        buf.Write(val)
    }

    buf.WriteString("}")
    return buf.Bytes(), nil
}

func main() {
    dict := map[string]interface{}{
        "orderedMap": OrderedMap{
            {"name", "John"},
            {"age", 20},
        },
    }
    dump, err := json.Marshal(dict)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%s\n", dump)
}

Outputs

{"orderedMap":{"name":"John","age":20}}
like image 166
eric chiang Avatar answered Nov 03 '22 16:11

eric chiang