@@ -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