Skip to content

Commit 9769b17

Browse files
authored
Fix: Boolean values incorrectly parsed as strings in struct unmarshaling (#76)
1 parent f321965 commit 9769b17

File tree

2 files changed

+54
-2
lines changed

2 files changed

+54
-2
lines changed

decode.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,7 @@ func (p *hjsonParser) readObject(
701701

702702
var newDest reflect.Value
703703
var newDestType reflect.Type
704+
currentElemType := elemType
704705
if stm != nil {
705706
sfi, ok := stm.getField(key)
706707
if ok {
@@ -713,7 +714,7 @@ func (p *hjsonParser) readObject(
713714
return nil, p.errAt("Internal error")
714715
}
715716
newDestType = newDestType.Field(i).Type
716-
elemType = newDestType
717+
currentElemType = newDestType
717718

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

733734
// duplicate keys overwrite the previous value
734735
var val interface{}
735-
if val, err = p.readValue(newDest, elemType); err != nil {
736+
if val, err = p.readValue(newDest, currentElemType); err != nil {
736737
return nil, err
737738
}
738739
if p.nodeDestination {

hjson_test.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1793,3 +1793,54 @@ j: null, k: "another text", l: null
17931793
t.Error("Should have failed, should not be possible to call pointer method UnmarshalText() on the map elements because they are not addressable.")
17941794
}
17951795
}
1796+
1797+
type UnmarshalExtraFieldsConfig struct {
1798+
Type string `json:"type"`
1799+
Extra map[string]interface{}
1800+
}
1801+
1802+
// We implement UnmarshalJSON to capture the extra fields
1803+
func (c *UnmarshalExtraFieldsConfig) UnmarshalJSON(data []byte) error {
1804+
type Alias UnmarshalExtraFieldsConfig
1805+
aux := &struct {
1806+
*Alias
1807+
}{
1808+
Alias: (*Alias)(c),
1809+
}
1810+
// This will unmarshal the known fields
1811+
if err := json.Unmarshal(data, &aux); err != nil {
1812+
return err
1813+
}
1814+
1815+
// Now unmarshal everything into a map to get extra fields
1816+
var raw map[string]interface{}
1817+
if err := json.Unmarshal(data, &raw); err != nil {
1818+
return err
1819+
}
1820+
1821+
if val, ok := raw["allow_local"]; ok {
1822+
if _, isBool := val.(bool); !isBool {
1823+
return fmt.Errorf("allow_local is not bool, got %T", val)
1824+
}
1825+
} else {
1826+
return fmt.Errorf("allow_local missing")
1827+
}
1828+
return nil
1829+
}
1830+
1831+
func TestUnmarshalStructWithExtraFields(t *testing.T) {
1832+
txt := `
1833+
{
1834+
type: network_allow
1835+
allow_local: true
1836+
}
1837+
`
1838+
var cfg UnmarshalExtraFieldsConfig
1839+
err := Unmarshal([]byte(txt), &cfg)
1840+
if err != nil {
1841+
if strings.Contains(err.Error(), "allow_local is not bool") {
1842+
t.Fatalf("Bug reproduced: %v", err)
1843+
}
1844+
t.Fatalf("Unexpected error: %v", err)
1845+
}
1846+
}

0 commit comments

Comments
 (0)