gencomponents.go 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  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. propertiesString, err := c.buildProperties(defineStruct)
  105. if err != nil {
  106. return err
  107. }
  108. getSetString, err := c.buildGetterSetter(defineStruct)
  109. if err != nil {
  110. return err
  111. }
  112. superClassName := "HttpData"
  113. for _, item := range c.responseTypes {
  114. if item.Name() == defineStruct.Name() {
  115. superClassName = "HttpResponseData"
  116. if !stringx.Contains(c.imports, httpResponseData) {
  117. c.imports = append(c.imports, httpResponseData)
  118. }
  119. break
  120. }
  121. }
  122. if superClassName == "HttpData" && !stringx.Contains(c.imports, httpData) {
  123. c.imports = append(c.imports, httpData)
  124. }
  125. params, constructorSetter, err := c.buildConstructor()
  126. if err != nil {
  127. return err
  128. }
  129. fp, created, err := apiutil.MaybeCreateFile(dir, modelDir, modelFile)
  130. if err != nil {
  131. return err
  132. }
  133. if !created {
  134. return nil
  135. }
  136. defer fp.Close()
  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, 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, tp spec.Type, indent int) error {
  179. definedType, ok := tp.(spec.DefineStruct)
  180. if !ok {
  181. pointType, ok := tp.(spec.PointerType)
  182. if ok {
  183. return c.writeMembers(writer, pointType.Type, indent)
  184. }
  185. return fmt.Errorf("type %s not supported", tp.Name())
  186. }
  187. for _, member := range definedType.Members {
  188. if member.IsInline {
  189. err := c.writeMembers(writer, member.Type, indent)
  190. if err != nil {
  191. return err
  192. }
  193. continue
  194. }
  195. if member.IsBodyMember() || member.IsFormMember() {
  196. if err := writeProperty(writer, member, indent); err != nil {
  197. return err
  198. }
  199. c.members = append(c.members, member)
  200. }
  201. }
  202. return nil
  203. }
  204. func (c *componentsContext) buildConstructor() (string, string, error) {
  205. var params strings.Builder
  206. var constructorSetter strings.Builder
  207. for index, member := range c.members {
  208. tp, err := specTypeToJava(member.Type)
  209. if err != nil {
  210. return "", "", err
  211. }
  212. params.WriteString(fmt.Sprintf("%s %s", tp, util.Untitle(member.Name)))
  213. pn, err := member.GetPropertyName()
  214. if err != nil {
  215. return "", "", err
  216. }
  217. if index != len(c.members)-1 {
  218. params.WriteString(", ")
  219. }
  220. writeIndent(&constructorSetter, 2)
  221. constructorSetter.WriteString(fmt.Sprintf("this.%s = %s;", pn, util.Untitle(member.Name)))
  222. if index != len(c.members)-1 {
  223. constructorSetter.WriteString(util.NL)
  224. }
  225. }
  226. return params.String(), constructorSetter.String(), nil
  227. }
  228. func (c *componentsContext) genGetSet(writer io.Writer, indent int) error {
  229. var members = c.members
  230. for _, member := range members {
  231. javaType, err := specTypeToJava(member.Type)
  232. if err != nil {
  233. return nil
  234. }
  235. var property = util.Title(member.Name)
  236. var templateStr = getSetTemplate
  237. if javaType == "boolean" {
  238. templateStr = boolTemplate
  239. property = strings.TrimPrefix(property, "Is")
  240. property = strings.TrimPrefix(property, "is")
  241. }
  242. t := template.Must(template.New(templateStr).Parse(getSetTemplate))
  243. var tmplBytes bytes.Buffer
  244. tyString := javaType
  245. decorator := ""
  246. javaPrimitiveType := []string{"int", "long", "boolean", "float", "double", "short"}
  247. if !stringx.Contains(javaPrimitiveType, javaType) {
  248. if member.IsOptional() || member.IsOmitEmpty() {
  249. decorator = "@Nullable "
  250. } else {
  251. decorator = "@NotNull "
  252. }
  253. tyString = decorator + tyString
  254. }
  255. tagName, err := member.GetPropertyName()
  256. if err != nil {
  257. return err
  258. }
  259. err = t.Execute(&tmplBytes, map[string]string{
  260. "property": property,
  261. "propertyValue": util.Untitle(member.Name),
  262. "tagValue": tagName,
  263. "type": tyString,
  264. "decorator": decorator,
  265. "returnType": javaType,
  266. "indent": indentString(indent),
  267. })
  268. if err != nil {
  269. return err
  270. }
  271. r := tmplBytes.String()
  272. r = strings.Replace(r, " boolean get", " boolean is", 1)
  273. writer.Write([]byte(r))
  274. }
  275. return nil
  276. }
  277. func formatSource(source string) string {
  278. var builder strings.Builder
  279. scanner := bufio.NewScanner(strings.NewReader(source))
  280. preIsBreakLine := false
  281. for scanner.Scan() {
  282. text := strings.TrimSpace(scanner.Text())
  283. if text == "" && preIsBreakLine {
  284. continue
  285. }
  286. preIsBreakLine = text == ""
  287. builder.WriteString(scanner.Text() + "\n")
  288. }
  289. if err := scanner.Err(); err != nil {
  290. fmt.Println(err)
  291. }
  292. return builder.String()
  293. }