How to implement Annotation-based static Code Enhancer / Generator with golang
This article focuses on "how to use golang to implement an annotation-based static code enhancer / generator". Interested friends may wish to take a look. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn how to use golang to implement an annotation-based static code enhancer / generator.
The main features of SpringSpring: 1. Control inversion (Inversion of Control, IoC) 2. Facing Container 3. Aspect-oriented (AspectOriented Programming, AOP) source gitee address: https://gitee.com/ioly/learning.gooop original text link: https://my.oschina.net/ioly target
Refer to the common notes in spring boot and write "Annotation-based static Code Enhancer / Generator" in golang.
Configuration: ComponentScan,Configuration, Bean
Bean statement: Component, Service, Controller
Bean injection: Autowried
AOP comments: Before, After, Around, PointCut
Subgoal (Day 6)
I got my ideas straight yesterday, and I started to scan all kinds of lexical elements today.
Project.go: scan all code files for the entire project. The module name is taken from the go.mod file
Packages.go: recursively scans a code directory
Files.go: scan a go code file and parse elements such as import/struct/field/method
Imports: scans all import of the specified code file
Domain/*.go: lexical element model set, code strategy
Project.go
Scan all code files for the entire project. The module name is taken from the go.mod file
Package scannerimport ("errors"io/ioutil"learning/gooop/spring/autogen/common"learning/gooop/spring/autogen/domain"os"path"strings") func ScanProject (name, dir string) (error, * domain.ProjectInfo) {e, module: = parseModFileAndGetModuleName (dir) if e! = nil {return e Nil} files, e: = ioutil.ReadDir (dir) if e! = nil {return e, nil} project: = domain.NewProjectInfo () project.Name = name project.LocalDir = dir project.Module = module for _ File: = range files {if! file.IsDir () {continue} e, pkg: = ScanPackage (project, nil, dir+ "/" + file.Name ()) if e! = nil {return e Nil} else {project.AppendPackage (pkg)}} return nil, project} func parseModFileAndGetModuleName (dir string) (error, string) {modfile: = path.Join (dir, gModuleFile) _, e: = os.Stat (modfile) if e! = nil {return gErrorModuleFileNotFound, ""} data E: = ioutil.ReadFile (modfile) if e! = nil {return e, ""} text: = string (data) for _, line: = range strings.Split (text, "\ n") {line: = strings.TrimSpace (line) if! common.Tokens.MatchString (line GModulePrefix) {continue} if ok, s: = common.Tokens.MatchRegexp (line, gModulePattern) Ok {return nil, strings.TrimSpace (slen (gModulePrefix) + 1:])} return gErrorProjectModuleNotFound, "} var gModuleFile =" go.mod "var gModulePrefix =" module "var gModulePattern =" ^ module\\ s +\\ w + (/\\ w +) * "var gErrorModuleFileNotFound = errors.New (" module file not found: go.mod ") var gErrorProjectModuleNotFound = errors.New (" project module not found in go.mod ") packages.go
Recursively scan a code directory
Package scannerimport ("io/ioutil"learning/gooop/spring/autogen/domain"path/filepath"strings") func ScanPackage (project * domain.ProjectInfo, parent * domain.PackageInfo, dir string) (error, * domain.PackageInfo) {pkg: = domain.NewPackageInfo () pkg.Project = project pkg.Parent = parent pkg.LocalDir = dir _ F: = filepath.Split (dir) pkg.Name = f files, e: = ioutil.ReadDir (dir) if e! = nil {return e, nil} for _, file: = range files {if file.IsDir () {e, p: = ScanPackage (project, pkg) Dir+ "/" + file.Name () if e! = nil {return e, nil} else if p! = nil {pkg.AppendPackage (p)}} else if strings.HasSuffix (file.Name ()) ".go") {e, f: = ScanCodeFile (pkg, dir+ "/" + file.Name ()) if e! = nil {return e Nil} else if f! = nil {pkg.AppendFile (f)} return nil, pkg} files.go
Read into a go code file, clear comments, and then parse elements such as import/struct/field/method
Package scannerimport ("io/ioutil"learning/gooop/spring/autogen/common"learning/gooop/spring/autogen/domain"regexp"strings"unicode") func ScanCodeFile (pkg * domain.PackageInfo, file string) (error, * domain.CodeFileInfo) {fbytes, e: = ioutil.ReadFile (file) if e! = nil {return e Nil} ftext: = string (fbytes) lines: = strings.Split (ftext, "\ n") for I, it: = range lines {lines [I] = strings.TrimRightFunc (it Unicode.IsSpace)} codeFile: = domain.NewCodeFileInfo () codeFile.Package = pkg codeFile.RawLines = lines / / clean comments bInParaComment: = false cleanLines: = make ([] string, len (lines)) for I, it: = range lines {s: = it if bInParaComment {/ / para comment end? I: = strings.Index (it GParaCommentEnd) if I > = 0 {bInParaComment = false s = s [iTunes 1:]} else {cleanLines [I] = "" continue }} if common.Tokens.MatchString (it GLineCommentPrefix) {cleanLines [I] = "" continue} s = removeParaCommentInLine (it) i1: = strings.Index (s) GParaCommentStart) if i1 > = 0 {s = s [: i1] bInParaComment = true} cleanLines [I] = s} / / parse imports ScanImport (codeFile) / / todo: parse struct declares/fields/methods return nil Nil} func removeParaCommentInLine (s string) string {arr: = gParaCommentInLine.FindAllStringIndex (s,-1) if len (arr) > 0 {for I: = len (arr)-1 I > = 0 From-{from: = arr [I] [0] to: = arr [I] [1] s = s [: from] + s [to+1:]}} return s} var gLineCommentPrefix = "^\\ s regexp.MustCompile /" var gParaCommentInLine = regexp.MustCompile ("/\\ *. *\ * / ") var gParaCommentStart =" / * "var gParaCommentEnd =" * / "imports.go
Scan all import of the specified code file
Package scannerimport ("learning/gooop/spring/autogen/domain"regexp") func ScanImport (file * domain.CodeFileInfo) {parseSingleImport (file) parseMultiImports (file)} func parseSingleImport (file * domain.CodeFileInfo) {for _, it: = range file.CleanLines {if gSingleImportRegexp.MatchString (it) {ss: = gSingleImportRegexp.FindAllStringSubmatch (it -1) [0] imp: = domain.NewImportInfo () imp.File = file if len (ss) = = 3 {imp.Alias = "" imp.Package = ss [1] } else if len (ss) = = 5 {imp.Alias = ss [1] imp.Package = ss [3]} file.AppendImport (imp)}} func parseMultiImports (file * domain.CodeFileInfo) {bInBlock: = false for _ It: = range file.CleanLines {if bInBlock {if gMultiImportEnd.MatchString (it) {bInBlock = false continue} if gImportPackage.MatchString (it) { Ss: = gImportPackage.FindAllStringSubmatch (it -1) [0] imp: = domain.NewImportInfo () imp.File = file if len (ss) = = 3 {imp.Alias = "" Imp.Package = ss [1]} else if len (ss) = = 5 {imp.Alias = ss [2] imp.Package = ss [3]} }} if gMultiImportStart.MatchString (it) {bInBlock = true continue} var gSingleImportRegexp = regexp.MustCompile (`\ s*import\ s + ((\ w + |\.)\ s +)? ("\ w + (/\ w +) *")`) var gMultiImportStart = regexp.MustCompile (`^\ s*import \ s +\ (`) var gMultiImportEnd = regexp.MustCompile (`^\ s*\)`) var gImportPackage = regexp.MustCompile (`^\ s* ((\ w + |\.)\ s +)? ("\ w + (/\ w +) *") `) so far I believe you have a better understanding of "how to use golang to implement an annotation-based static code enhancer / generator". You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!