github.com/ShaleApps/viper@v1.15.1-concurrent/internal/encoding/javaproperties/codec.go (about)

     1  package javaproperties
     2  
     3  import (
     4  	"bytes"
     5  	"sort"
     6  	"strings"
     7  
     8  	"github.com/magiconair/properties"
     9  	"github.com/spf13/cast"
    10  )
    11  
    12  // Codec implements the encoding.Encoder and encoding.Decoder interfaces for Java properties encoding.
    13  type Codec struct {
    14  	KeyDelimiter string
    15  
    16  	// Store read properties on the object so that we can write back in order with comments.
    17  	// This will only be used if the configuration read is a properties file.
    18  	// TODO: drop this feature in v2
    19  	// TODO: make use of the global properties object optional
    20  	Properties *properties.Properties
    21  }
    22  
    23  func (c *Codec) Encode(v map[string]interface{}) ([]byte, error) {
    24  	if c.Properties == nil {
    25  		c.Properties = properties.NewProperties()
    26  	}
    27  
    28  	flattened := map[string]interface{}{}
    29  
    30  	flattened = flattenAndMergeMap(flattened, v, "", c.keyDelimiter())
    31  
    32  	keys := make([]string, 0, len(flattened))
    33  
    34  	for key := range flattened {
    35  		keys = append(keys, key)
    36  	}
    37  
    38  	sort.Strings(keys)
    39  
    40  	for _, key := range keys {
    41  		_, _, err := c.Properties.Set(key, cast.ToString(flattened[key]))
    42  		if err != nil {
    43  			return nil, err
    44  		}
    45  	}
    46  
    47  	var buf bytes.Buffer
    48  
    49  	_, err := c.Properties.WriteComment(&buf, "#", properties.UTF8)
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  
    54  	return buf.Bytes(), nil
    55  }
    56  
    57  func (c *Codec) Decode(b []byte, v map[string]interface{}) error {
    58  	var err error
    59  	c.Properties, err = properties.Load(b, properties.UTF8)
    60  	if err != nil {
    61  		return err
    62  	}
    63  
    64  	for _, key := range c.Properties.Keys() {
    65  		// ignore existence check: we know it's there
    66  		value, _ := c.Properties.Get(key)
    67  
    68  		// recursively build nested maps
    69  		path := strings.Split(key, c.keyDelimiter())
    70  		lastKey := strings.ToLower(path[len(path)-1])
    71  		deepestMap := deepSearch(v, path[0:len(path)-1])
    72  
    73  		// set innermost value
    74  		deepestMap[lastKey] = value
    75  	}
    76  
    77  	return nil
    78  }
    79  
    80  func (c Codec) keyDelimiter() string {
    81  	if c.KeyDelimiter == "" {
    82  		return "."
    83  	}
    84  
    85  	return c.KeyDelimiter
    86  }