這篇文章主要介紹“怎么使用golang編寫基于注解的靜態(tài)代碼增強(qiáng)器/生成器”,在日常操作中,相信很多人在怎么使用golang編寫基于注解的靜態(tài)代碼增強(qiáng)器/生成器問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”怎么使用golang編寫基于注解的靜態(tài)代碼增強(qiáng)器/生成器”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!
作為一家“創(chuàng)意+整合+營銷”的成都網(wǎng)站建設(shè)機(jī)構(gòu),我們在業(yè)內(nèi)良好的客戶口碑。創(chuàng)新互聯(lián)公司提供從前期的網(wǎng)站品牌分析策劃、網(wǎng)站設(shè)計(jì)、成都網(wǎng)站制作、網(wǎng)站設(shè)計(jì)、創(chuàng)意表現(xiàn)、網(wǎng)頁制作、系統(tǒng)開發(fā)以及后續(xù)網(wǎng)站營銷運(yùn)營等一系列服務(wù),幫助企業(yè)打造創(chuàng)新的互聯(lián)網(wǎng)品牌經(jīng)營模式與有效的網(wǎng)絡(luò)營銷方法,創(chuàng)造更大的價(jià)值。
Spring的主要特性: 1. 控制反轉(zhuǎn)(Inversion of Control, IoC) 2. 面向容器 3. 面向切面(AspectOriented Programming, AOP) 源碼gitee地址: https://gitee.com/ioly/learning.gooop 原文鏈接: https://my.oschina.net/ioly
參考spring boot常用注解,使用golang編寫“基于注解的靜態(tài)代碼增強(qiáng)器/生成器”
struct解析清楚了,接著解析注解就比較容易了
scanner/IStructScanner.go:修復(fù)scanMethod()和scanAnnotation()的細(xì)節(jié)問題
scanner/IAnnotationScanner.go:注解掃描接口及默認(rèn)實(shí)現(xiàn)。注解的屬性支持雙引號(hào)和重音號(hào)字符串。
scanner/IAnnotationScanner_test.go:針對注解信息的單元測試
注解掃描接口及默認(rèn)實(shí)現(xiàn)。注解的屬性支持雙引號(hào)和重音號(hào)字符串。
package scanner import ( "errors" "learning/gooop/spring/autogen/common" "learning/gooop/spring/autogen/domain" "regexp" "strings" ) type IAnnotationScanner interface { ScanAnnotations(s *domain.StructInfo) } type tAnnotationScanner int func (me *tAnnotationScanner) ScanAnnotations(s *domain.StructInfo) { me.scanStructAnnotation(s) me.scanFieldAnnotation(s) me.scanMethodAnnotation(s) } func (me *tAnnotationScanner) scanStructAnnotation(s *domain.StructInfo) { for i := s.LineNO - 1; i >= 0; i-- { if !me.matchAnnotation(s, i) { break } code := s.CodeFile.RawLines[i] e, a := me.parseAnnotation(code) if e != nil { panic(e) } s.AppendAnnotation(a) } } func (me *tAnnotationScanner) scanFieldAnnotation(s *domain.StructInfo) { for _, fld := range s.Fields { for i := fld.LineNO - 1; i >= 0; i-- { if !me.matchAnnotation(s, i) { break } code := s.CodeFile.RawLines[i] e, a := me.parseAnnotation(code) if e != nil { panic(e) } fld.AppendAnnotation(a) } } } func (me *tAnnotationScanner) scanMethodAnnotation(s *domain.StructInfo) { for _, method := range s.Methods { for i := method.LineNO - 1; i >= 0; i-- { if !me.matchAnnotation(s, i) { break } code := s.CodeFile.RawLines[i] e, a := me.parseAnnotation(code) if e != nil { panic(e) } method.AppendAnnotation(a) } } } func (me *tAnnotationScanner) matchAnnotation(s *domain.StructInfo, lineNO int) bool { line := s.CodeFile.RawLines[lineNO] return gAnnotationStartRegexp.MatchString(line) } func (me *tAnnotationScanner) parseAnnotation(line string) (error, *domain.AnnotationInfo) { ss := gAnnotationStartRegexp.FindStringSubmatch(line) if len(ss) <= 0 { return nil, nil } a := domain.NewAnnotationInfo() // name declare := ss[0] a.Name = ss[1] // properties t := line[len(declare):] for { // space* b1, s1 := common.Tokens.MatchSpaces(t) if b1 { t = t[len(s1):] } // key b2, s2 := common.Tokens.MatchIdentifier(t) if !b2 { break } t = t[len(s2):] // = b31, s31 := common.Tokens.MatchSpaces(t) if b31 { t = t[len(s31):] } b32 := common.Tokens.MatchString(t, "=") if !b32 { return errors.New("expecting ="), nil } else { t = t[1:] } b33, s33 := common.Tokens.MatchSpaces(t) if b33 { t = t[len(s33):] } // value b4, s4, i4 := me.parsePropertyValue(t) if !b4 { return errors.New("expecting attribute value"), nil } else { t = t[i4:] a.AppendAttribute(s2, s4) } } return nil, a } func (me *tAnnotationScanner) parsePropertyValue(s string) (bool, string, int) { // quoted string by "" b2, s2 := common.Tokens.MatchRegexp(s, `^"((\\")|[^"])*"`) if b2 { return true, me.removeDoubleQuote(s2), len(s2) } // quoted string by `` b3, s3 := common.Tokens.MatchRegexp(s, "^`[^`]+`") if b3 { return true, s3[1 : len(s3)-1], len(s3) } // simple string b4, s4 := common.Tokens.MatchRegexp(s, `^\S+`) if b4 { return true, s4, len(s4) } return false, "", 0 } func (me *tAnnotationScanner) removeDoubleQuote(s string) string { s = s[1 : len(s)-1] arrSpecialChars := [][]string{ {`\r`, "\r"}, {`\n`, "\n"}, {`\t`, "\t"}, {`\"`, "\""}, {`\\`, "\\"}, {`\v`, "\v"}, } for _, it := range arrSpecialChars { s = strings.ReplaceAll(s, it[0], it[1]) } return s } var gAnnotationStartRegexp = regexp.MustCompile(`^//\s*@(\w+)\s*`) var DefaultAnnotationScanner = new(tAnnotationScanner)
針對注解信息的單元測試
package scanner import ( "encoding/json" "learning/gooop/spring/autogen/domain" "strings" "testing" ) func Test_AnnotationScanner(t *testing.T) { code := ` // @RestController path=/order scope=singleton type StructInfo struct { LineNO int Name string CodeFile *CodeFileInfo Fields []*FieldInfo Methods []*MethodInfo Annotations []*AnnotationInfo } func NewStructInfo() *StructInfo { it := new(StructInfo) it.Fields = []*FieldInfo{} it.Methods = []*MethodInfo{} it.Annotations = []*AnnotationInfo{} return it } // @GetMapping path=/AppendField func (me *StructInfo) AppendField(lineNO int, name string, dataType string) error { fld := NewFieldInfo() fld.Struct = me fld.LineNO = lineNO fld.Name = name fld.DataType = dataType me.Fields = append(me.Fields, fld) return nil } // @GetMapping path="/AppendMethod" func (me *StructInfo) AppendMethod(method *MethodInfo) (error, string) { me.Methods = append(me.Methods, method) return nil, "" } // @PostMapping path=/AppendAnnotation func (me *StructInfo) AppendAnnotation(ant *AnnotationInfo) (e error, s string) { me.Annotations = append(me.Annotations, ant) return nil, "" }` file := domain.NewCodeFileInfo() file.CleanLines = strings.Split(code, "\n") file.RawLines = file.CleanLines DefaultStructScanner.ScanStruct(file) for _, it := range file.Structs { DefaultAnnotationScanner.ScanAnnotations(it) j, e := json.MarshalIndent(it, "", " ") if e != nil { t.Fatal(e) } t.Log(string(j)) } }
API server listening at: [::]:41281 === RUN Test_AnnotationScanner IAnnotationScanner_test.go:63: { "LineNO": 2, "Name": "StructInfo", "Fields": [ { "LineNO": 3, "Name": "LineNO", "DataType": "int", "Annotations": [] }, { "LineNO": 4, "Name": "Name", "DataType": "string", "Annotations": [] }, { "LineNO": 5, "Name": "CodeFile", "DataType": "*CodeFileInfo", "Annotations": [] }, { "LineNO": 6, "Name": "Fields", "DataType": "[]*FieldInfo", "Annotations": [] }, { "LineNO": 7, "Name": "Methods", "DataType": "[]*MethodInfo", "Annotations": [] }, { "LineNO": 8, "Name": "Annotations", "DataType": "[]*AnnotationInfo", "Annotations": [] } ], "Methods": [ { "LineNO": 20, "Name": "AppendField", "Arguments": [ { "Name": "lineNO", "DataType": "int" }, { "Name": "name", "DataType": "string" }, { "Name": "dataType", "DataType": "string" } ], "Annotations": [ { "Name": "GetMapping", "Attributes": [ { "Key": "path", "Value": "/AppendField" } ] } ], "Returns": [ { "Name": "", "DataType": "error" } ] }, { "LineNO": 31, "Name": "AppendMethod", "Arguments": [ { "Name": "method", "DataType": "*MethodInfo" } ], "Annotations": [ { "Name": "GetMapping", "Attributes": [ { "Key": "path", "Value": "/AppendMethod" } ] } ], "Returns": [ { "Name": "", "DataType": "error" }, { "Name": "", "DataType": "string" } ] }, { "LineNO": 37, "Name": "AppendAnnotation", "Arguments": [ { "Name": "ant", "DataType": "*AnnotationInfo" } ], "Annotations": [ { "Name": "PostMapping", "Attributes": [ { "Key": "path", "Value": "/AppendAnnotation" } ] } ], "Returns": [ { "Name": "e", "DataType": "error" } ] } ], "Annotations": [ { "Name": "RestController", "Attributes": [ { "Key": "path", "Value": "/order" }, { "Key": "scope", "Value": "singleton" } ] } ] } --- PASS: Test_AnnotationScanner (0.01s) PASS Debugger finished with exit code 0
到此,關(guān)于“怎么使用golang編寫基于注解的靜態(tài)代碼增強(qiáng)器/生成器”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!