gencomponents.go 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. package javagen
  2. import (
  3. "bufio"
  4. "bytes"
  5. "errors"
  6. "fmt"
  7. "io"
  8. "path"
  9. "strings"
  10. "text/template"
  11. "github.com/tal-tech/go-zero/core/stringx"
  12. "github.com/tal-tech/go-zero/tools/goctl/api/spec"
  13. apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util"
  14. "github.com/tal-tech/go-zero/tools/goctl/util"
  15. )
  16. const (
  17. componentTemplate = `// Code generated by goctl. DO NOT EDIT.
  18. package com.xhb.logic.http.packet.{{.packet}}.model;
  19. import org.jetbrains.annotations.NotNull;
  20. import org.jetbrains.annotations.Nullable;
  21. {{.imports}}
  22. public class {{.className}} extends {{.superClassName}} {
  23. {{.properties}}
  24. {{if .HasProperty}}
  25. public {{.className}}() {
  26. }
  27. public {{.className}}({{.params}}) {
  28. {{.constructorSetter}}
  29. }
  30. {{end}}
  31. {{.getSet}}
  32. }
  33. `
  34. getSetTemplate = `
  35. {{.indent}}{{.decorator}}
  36. {{.indent}}public {{.returnType}} get{{.property}}() {
  37. {{.indent}} return this.{{.tagValue}};
  38. {{.indent}}}
  39. {{.indent}}public void set{{.property}}({{.type}} {{.propertyValue}}) {
  40. {{.indent}} this.{{.tagValue}} = {{.propertyValue}};
  41. {{.indent}}}
  42. `
  43. boolTemplate = `
  44. {{.indent}}{{.decorator}}
  45. {{.indent}}public {{.returnType}} is{{.property}}() {
  46. {{.indent}} return this.{{.tagValue}};
  47. {{.indent}}}
  48. {{.indent}}public void set{{.property}}({{.type}} {{.propertyValue}}) {
  49. {{.indent}} this.{{.tagValue}} = {{.propertyValue}};
  50. {{.indent}}}
  51. `
  52. httpResponseData = "import com.xhb.core.response.HttpResponseData;"
  53. httpData = "import com.xhb.core.packet.HttpData;"
  54. )
  55. type componentsContext struct {
  56. api *spec.ApiSpec
  57. requestTypes []spec.Type
  58. responseTypes []spec.Type
  59. imports []string
  60. members []spec.Member
  61. }
  62. func genComponents(dir, packetName string, api *spec.ApiSpec) error {
  63. types := api.Types
  64. if len(types) == 0 {
  65. return nil
  66. }
  67. var requestTypes []spec.Type
  68. var responseTypes []spec.Type
  69. for _, group := range api.Service.Groups {
  70. for _, route := range group.Routes {
  71. if route.RequestType != nil {
  72. requestTypes = append(requestTypes, route.RequestType)
  73. }
  74. if route.ResponseType != nil {
  75. responseTypes = append(responseTypes, route.ResponseType)
  76. }
  77. }
  78. }
  79. context := componentsContext{api: api, requestTypes: requestTypes, responseTypes: responseTypes}
  80. for _, ty := range types {
  81. if err := context.createComponent(dir, packetName, ty); err != nil {
  82. return err
  83. }
  84. }
  85. return nil
  86. }
  87. func (c *componentsContext) createComponent(dir, packetName string, ty spec.Type) error {
  88. defineStruct, ok := ty.(spec.DefineStruct)
  89. if !ok {
  90. return errors.New("unsupported type %s" + ty.Name())
  91. }
  92. for _, item := range c.requestTypes {
  93. if item.Name() == defineStruct.Name() {
  94. if len(defineStruct.GetFormMembers())+len(defineStruct.GetBodyMembers()) == 0 {
  95. return nil
  96. }
  97. }
  98. }
  99. modelFile := util.Title(ty.Name()) + ".java"
  100. filename := path.Join(dir, modelDir, modelFile)
  101. if err := util.RemoveOrQuit(filename); err != nil {
  102. return err
  103. }
  104. fp, created, err := apiutil.MaybeCreateFile(dir, modelDir, modelFile)
  105. if err != nil {
  106. return err
  107. }
  108. if !created {
  109. return nil
  110. }
  111. defer fp.Close()
  112. propertiesString, err := c.buildProperties(defineStruct)
  113. if err != nil {
  114. return err
  115. }
  116. getSetString, err := c.buildGetterSetter(defineStruct)
  117. if err != nil {
  118. return err
  119. }
  120. superClassName := "HttpData"
  121. for _, item := range c.responseTypes {
  122. if item.Name() == defineStruct.Name() {
  123. superClassName = "HttpResponseData"
  124. if !stringx.Contains(c.imports, httpResponseData) {
  125. c.imports = append(c.imports, httpResponseData)
  126. }
  127. break
  128. }
  129. }
  130. if superClassName == "HttpData" && !stringx.Contains(c.imports, httpData) {
  131. c.imports = append(c.imports, httpData)
  132. }
  133. params, constructorSetter, err := c.buildConstructor()
  134. if err != nil {
  135. return err
  136. }
  137. buffer := new(bytes.Buffer)
  138. t := template.Must(template.New("componentType").Parse(componentTemplate))
  139. err = t.Execute(buffer, map[string]interface{}{
  140. "properties": propertiesString,
  141. "params": params,
  142. "constructorSetter": constructorSetter,
  143. "getSet": getSetString,
  144. "packet": packetName,
  145. "imports": strings.Join(c.imports, "\n"),
  146. "className": util.Title(defineStruct.Name()),
  147. "superClassName": superClassName,
  148. "HasProperty": len(strings.TrimSpace(propertiesString)) > 0,
  149. })
  150. if err != nil {
  151. return err
  152. }
  153. _, err = fp.WriteString(formatSource(buffer.String()))
  154. return err
  155. }
  156. func (c *componentsContext) buildProperties(defineStruct spec.DefineStruct) (string, error) {
  157. var builder strings.Builder
  158. if err := c.writeType(&builder, defineStruct); err != nil {
  159. return "", apiutil.WrapErr(err, "Type "+defineStruct.Name()+" generate error")
  160. }
  161. return builder.String(), nil
  162. }
  163. func (c *componentsContext) buildGetterSetter(defineStruct spec.DefineStruct) (string, error) {
  164. var builder strings.Builder
  165. if err := c.genGetSet(&builder, defineStruct, 1); err != nil {
  166. return "", apiutil.WrapErr(err, "Type "+defineStruct.Name()+" get or set generate error")
  167. }
  168. return builder.String(), nil
  169. }
  170. func (c *componentsContext) writeType(writer io.Writer, defineStruct spec.DefineStruct) error {
  171. c.members = make([]spec.Member, 0)
  172. err := c.writeMembers(writer, defineStruct, 1)
  173. if err != nil {
  174. return err
  175. }
  176. return nil
  177. }
  178. func (c *componentsContext) writeMembers(writer io.Writer, defineStruct spec.DefineStruct, indent int) error {
  179. for _, member := range defineStruct.Members {
  180. if member.IsInline {
  181. defineStruct, ok := member.Type.(spec.DefineStruct)
  182. if ok {
  183. err := c.writeMembers(writer, defineStruct, indent)
  184. if err != nil {
  185. return err
  186. }
  187. continue
  188. }
  189. return errors.New("unsupported inline type %s" + member.Type.Name())
  190. }
  191. if member.IsBodyMember() || member.IsFormMember() {
  192. if err := writeProperty(writer, member, indent); err != nil {
  193. return err
  194. }
  195. c.members = append(c.members, member)
  196. }
  197. }
  198. return nil
  199. }
  200. func (c *componentsContext) buildConstructor() (string, string, error) {
  201. var params strings.Builder
  202. var constructorSetter strings.Builder
  203. for index, member := range c.members {
  204. tp, err := specTypeToJava(member.Type)
  205. if err != nil {
  206. return "", "", err
  207. }
  208. params.WriteString(fmt.Sprintf("%s %s", tp, util.Untitle(member.Name)))
  209. pn, err := member.GetPropertyName()
  210. if err != nil {
  211. return "", "", err
  212. }
  213. if index != len(c.members)-1 {
  214. params.WriteString(", ")
  215. }
  216. writeIndent(&constructorSetter, 2)
  217. constructorSetter.WriteString(fmt.Sprintf("this.%s = %s;", pn, util.Untitle(member.Name)))
  218. if index != len(c.members)-1 {
  219. constructorSetter.WriteString(util.NL)
  220. }
  221. }
  222. return params.String(), constructorSetter.String(), nil
  223. }
  224. func (c *componentsContext) genGetSet(writer io.Writer, defineStruct spec.DefineStruct, indent int) error {
  225. var members = defineStruct.GetBodyMembers()
  226. members = append(members, defineStruct.GetFormMembers()...)
  227. for _, member := range members {
  228. javaType, err := specTypeToJava(member.Type)
  229. if err != nil {
  230. return nil
  231. }
  232. var property = util.Title(member.Name)
  233. var templateStr = getSetTemplate
  234. if javaType == "boolean" {
  235. templateStr = boolTemplate
  236. property = strings.TrimPrefix(property, "Is")
  237. property = strings.TrimPrefix(property, "is")
  238. }
  239. t := template.Must(template.New(templateStr).Parse(getSetTemplate))
  240. var tmplBytes bytes.Buffer
  241. tyString := javaType
  242. decorator := ""
  243. javaPrimitiveType := []string{"int", "long", "boolean", "float", "double", "short"}
  244. if !stringx.Contains(javaPrimitiveType, javaType) {
  245. if member.IsOptional() || member.IsOmitEmpty() {
  246. decorator = "@Nullable "
  247. } else {
  248. decorator = "@NotNull "
  249. }
  250. tyString = decorator + tyString
  251. }
  252. tagName, err := member.GetPropertyName()
  253. if err != nil {
  254. return err
  255. }
  256. err = t.Execute(&tmplBytes, map[string]string{
  257. "property": property,
  258. "propertyValue": util.Untitle(member.Name),
  259. "tagValue": tagName,
  260. "type": tyString,
  261. "decorator": decorator,
  262. "returnType": javaType,
  263. "indent": indentString(indent),
  264. })
  265. if err != nil {
  266. return err
  267. }
  268. r := tmplBytes.String()
  269. r = strings.Replace(r, " boolean get", " boolean is", 1)
  270. writer.Write([]byte(r))
  271. }
  272. return nil
  273. }
  274. func formatSource(source string) string {
  275. var builder strings.Builder
  276. scanner := bufio.NewScanner(strings.NewReader(source))
  277. preIsBreakLine := false
  278. for scanner.Scan() {
  279. text := strings.TrimSpace(scanner.Text())
  280. if text == "" && preIsBreakLine {
  281. continue
  282. }
  283. preIsBreakLine = text == ""
  284. builder.WriteString(scanner.Text() + "\n")
  285. }
  286. if err := scanner.Err(); err != nil {
  287. fmt.Println(err)
  288. }
  289. return builder.String()
  290. }