-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathmain.go
151 lines (143 loc) · 3.38 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// Copyright 2012 The jflect Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"bytes"
"encoding/json"
"errors"
"flag"
"fmt"
"go/format"
"io"
glog "log"
"os"
"sort"
)
// TODO: write proper Usage and README
var (
log = glog.New(os.Stderr, "", glog.Lshortfile)
fstruct = flag.String("s", "Foo", "struct name for json object")
debug = false
ErrNotValidSyntax = errors.New("Json reflection is not valid Go syntax")
)
func main() {
flag.Parse()
err := read(os.Stdin, os.Stdout)
if err != nil {
log.Fatal(err)
}
}
func read(r io.Reader, w io.Writer) error {
var v interface{}
err := json.NewDecoder(r).Decode(&v)
if err != nil {
log.Println(err)
return err
}
buf := new(bytes.Buffer)
// Open struct
b, err := xreflect(v)
if err != nil {
log.Println(err)
return err
}
field := NewField(*fstruct, "struct", b...)
fmt.Fprintf(buf, "type %s %s", field.name, field.gtype)
if debug {
os.Stdout.WriteString("*********DEBUG***********")
os.Stdout.Write(buf.Bytes())
os.Stdout.WriteString("*********DEBUG***********")
}
// Pass through gofmt for uniform formatting, and weak syntax check.
b, err = format.Source(buf.Bytes())
if err != nil {
log.Println(err)
fmt.Println("Final Go Code")
fmt.Println()
os.Stderr.Write(buf.Bytes())
fmt.Println()
return ErrNotValidSyntax
}
w.Write(b)
return nil
}
func xreflect(v interface{}) ([]byte, error) {
var (
buf = new(bytes.Buffer)
)
fields := []Field{}
switch root := v.(type) {
case map[string]interface{}:
for key, val := range root {
switch j := val.(type) {
case nil:
// FIXME: sometimes json service will return nil even though the type is string.
// go can not convert string to nil and vs versa. Can we assume its a string?
continue
case float64:
fields = append(fields, NewField(key, "int"))
case map[string]interface{}:
// If type is map[string]interface{} then we have nested object, Recurse
o, err := xreflect(j)
if err != nil {
log.Println(err)
return nil, err
}
fields = append(fields, NewField(key, "struct", o...))
case []interface{}:
gtype, err := sliceType(j)
if err != nil {
log.Println(err)
return nil, err
}
fields = append(fields, NewField(key, gtype))
default:
fields = append(fields, NewField(key, fmt.Sprintf("%T", val)))
}
}
default:
return nil, fmt.Errorf("%T: unexpected type", root)
}
// Sort and write field buffer last to keep order and formatting.
sort.Sort(FieldSort(fields))
for _, f := range fields {
fmt.Fprintf(buf, "%s %s %s\n", f.name, f.gtype, f.tag)
}
return buf.Bytes(), nil
}
// if all entries in j are the same type, return slice of that type
func sliceType(j []interface{}) (string, error) {
dft := "[]interface{}"
if len(j) == 0 {
return dft, nil
}
var t, t2 string
for _, v := range j {
switch v.(type) {
case string:
t2 = "[]string"
case float64:
t2 = "[]int"
case map[string]interface{}:
t2 = "[]struct"
default:
// something else, just return default
return dft, nil
}
if t != "" && t != t2 {
return dft, nil
}
t = t2
}
if t == "[]struct" {
o, err := xreflect(j[0])
if err != nil {
log.Println(err)
return "", err
}
f := NewField("", "struct", o...)
t = "[]" + f.gtype
}
return t, nil
}