Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,7 @@ func (p *hjsonParser) readObject(

var newDest reflect.Value
var newDestType reflect.Type
currentElemType := elemType
if stm != nil {
sfi, ok := stm.getField(key)
if ok {
Expand All @@ -713,7 +714,7 @@ func (p *hjsonParser) readObject(
return nil, p.errAt("Internal error")
}
newDestType = newDestType.Field(i).Type
elemType = newDestType
currentElemType = newDestType

if newDest.IsValid() {
if newDest.Kind() != reflect.Struct {
Expand All @@ -732,7 +733,7 @@ func (p *hjsonParser) readObject(

// duplicate keys overwrite the previous value
var val interface{}
if val, err = p.readValue(newDest, elemType); err != nil {
if val, err = p.readValue(newDest, currentElemType); err != nil {
return nil, err
}
if p.nodeDestination {
Expand Down
51 changes: 51 additions & 0 deletions hjson_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1793,3 +1793,54 @@ j: null, k: "another text", l: null
t.Error("Should have failed, should not be possible to call pointer method UnmarshalText() on the map elements because they are not addressable.")
}
}

type UnmarshalExtraFieldsConfig struct {
Type string `json:"type"`
Extra map[string]interface{}
}

// We implement UnmarshalJSON to capture the extra fields
func (c *UnmarshalExtraFieldsConfig) UnmarshalJSON(data []byte) error {
type Alias UnmarshalExtraFieldsConfig
aux := &struct {
*Alias
}{
Alias: (*Alias)(c),
}
// This will unmarshal the known fields
if err := json.Unmarshal(data, &aux); err != nil {
return err
}

// Now unmarshal everything into a map to get extra fields
var raw map[string]interface{}
if err := json.Unmarshal(data, &raw); err != nil {
return err
}

if val, ok := raw["allow_local"]; ok {
if _, isBool := val.(bool); !isBool {
return fmt.Errorf("allow_local is not bool, got %T", val)
}
} else {
return fmt.Errorf("allow_local missing")
}
return nil
}

func TestUnmarshalStructWithExtraFields(t *testing.T) {
txt := `
{
type: network_allow
allow_local: true
}
`
var cfg UnmarshalExtraFieldsConfig
err := Unmarshal([]byte(txt), &cfg)
if err != nil {
if strings.Contains(err.Error(), "allow_local is not bool") {
t.Fatalf("Bug reproduced: %v", err)
}
t.Fatalf("Unexpected error: %v", err)
}
}
Loading