编写golang编写注解的静态代码增强器/生成器的方法
发表于:2025-11-11 作者:千家信息网编辑
千家信息网最后更新 2025年11月11日,本篇内容介绍了"编写golang编写注解的静态代码增强器/生成器的方法"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读
千家信息网最后更新 2025年11月11日编写golang编写注解的静态代码增强器/生成器的方法
本篇内容介绍了"编写golang编写注解的静态代码增强器/生成器的方法"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
Spring
Spring的主要特性:1. 控制反转(Inversion of Control, IoC)2. 面向容器3. 面向切面(AspectOriented Programming, AOP)源码gitee地址:https://gitee.com/ioly/learning.gooop原文链接:https://my.oschina.net/ioly
目标
参考spring boot常用注解,使用golang编写"基于注解的静态代码增强器/生成器"
子目标(Day 7)
因为struct/field/method的扫描是关键,因此今天针对这块做了单元测试
common/Tokens.go:修复MatchBasicType方法的正则匹配bug。其实func类型的DataType也没考虑到,但现在暂时可以用type alias规避,先不追求完美吧。
scanner/IStructScanner.go: 修复若干细节, 并添加返回类型的扫描
scanner/IStructScanner_test.go:struct扫描器的单元测试
common/Tokens.go
修复MatchBasicType方法的正则匹配bug。其实func类型的DataType也没考虑到,但现在暂时可以用type alias规避,先不追求完美吧。
func (me *tTokens) MatchBasicType(s string) (bool, string) { list := []string{ "int", "string", "bool", "byte", "int32", "int64", "uint32", "uint64", "float32", "float64", "int8", "uint8", "int16", "uint16", `time\.Time`, } for _, it := range list { if ok, t := me.MatchRegexp(s, "^"+it+`(\s+|$)`); ok { return true, strings.TrimSpace(t) } } return false, ""}scanner/IStructScanner.go
修复若干细节, 并添加返回类型的扫描
package scannerimport ( "errors" "learning/gooop/spring/autogen/common" "learning/gooop/spring/autogen/domain" "regexp" "strings")type IStructScanner interface { ScanStruct(file *domain.CodeFileInfo)}type tStructScanner intfunc (me *tStructScanner) ScanStruct(file *domain.CodeFileInfo) { bInStruct := false vStructs := []*domain.StructInfo{nil} for lineNO, line := range file.CleanLines { if bInStruct { // end? if gStructEndRegexp.MatchString(line) { me.scanMethod(vStructs[0], lineNO+1) file.AppendStruct(vStructs[0]) bInStruct = false vStructs[0] = nil continue } // in struct block ok, fname, ftype := me.scanField(line) if ok { vStructs[0].AppendField(lineNO, fname, ftype) } } else { // not in struck block // matching start? if gStructStartRegexp.MatchString(line) { bInStruct = true ss := gStructStartRegexp.FindStringSubmatch(line) vStructs[0] = domain.NewStructInfo() vStructs[0].LineNO = lineNO vStructs[0].CodeFile = file vStructs[0].Name = ss[1] continue } } }}func (me *tStructScanner) scanField(line string) (ok bool, fldName string, fldType string) { if !gFieldStartRegexp.MatchString(line) { return false, "", "" } t := line s1 := gFieldStartRegexp.FindString(t) fldName = strings.TrimSpace(s1) t = t[len(s1):] b2, s2 := common.Tokens.MatchDataType(t) if !b2 { return false, "", "" } fldType = strings.TrimSpace(s2) return true, fldName, fldType}func (me *tStructScanner) scanMethod(stru *domain.StructInfo, fromLineNO int) { for i, limit := fromLineNO, len(stru.CodeFile.CleanLines); i < limit; i++ { line := stru.CodeFile.CleanLines[i] if !gMethodStartRegex.MatchString(line) { continue } ss := gMethodStartRegex.FindStringSubmatch(line) // declare declare := ss[0] offset := len(declare) // receiver receiver := ss[1] if receiver != stru.Name { continue } method := domain.NewMethodInfo() // name method.Name = ss[2] // method input args e, args := me.scanMethodArgs(method, strings.TrimSpace(line[offset:])) if e != nil { panic(e) } offset += len(args) // method return args e = me.scanReturnArgs(method, strings.TrimSpace(line[offset:])) if e != nil { panic(e) } // end scan method stru.AppendMethod(method) }}func (me *tStructScanner) scanMethodArgs(method *domain.MethodInfo, s string) (error, string) { t := s offset := 0 for { // name b1, s1 := common.Tokens.MatchRegexp(t, `^\w+(\s*,\s*\w+)?\s+`) if !b1 { break } argNames := strings.TrimSpace(s1) offset += len(s1) t = s[offset:] // data type b2, s2 := common.Tokens.MatchDataType(t) if !b2 { return gInvalidMethodArgs, "" } argDataType := s2 offset += len(s2) t = s[offset:] for _, it := range strings.Split(argNames, ",") { method.AppendArgument(it, argDataType) } // ,\s+ b3, s3 := common.Tokens.MatchRegexp(t, `\s*,\s*`) if !b3 { break } offset += len(s3) t = s[offset:] } b4, s4 := common.Tokens.MatchRegexp(t, `^\s*\)`) if !b4 { return errors.New("expecting right bracket"), "" } offset += len(s4) return nil, s[0:offset]}func (me *tStructScanner) scanReturnArgs(method *domain.MethodInfo, s string) error { // no args? if gMethodEndRegexp.MatchString(s) { return nil } // args start t := s b1, s1 := common.Tokens.MatchRegexp(t, `\s*\(\s*`) if !b1 { return errors.New("expecting left bracket") } t = t[len(s1):] // unnamed args? b2, s2 := common.Tokens.MatchDataType(t) if b2 { t = t[len(s2):] method.AppendUnnamedReturn(s2) // more unnamed args? for { b3, s3 := common.Tokens.MatchRegexp(t, `^\s*,\s*`) if !b3 { break } t = t[len(s3):] b4, s4 := common.Tokens.MatchDataType(t) if !b4 { return errors.New("expecting data type") } t = t[len(s4):] method.AppendUnnamedReturn(s4) } } else { // named args? for { // name b3, s3 := common.Tokens.MatchIdentifier(t) if !b3 { return errors.New("expecting identifier") } t = t[len(s3):] // \s+ b4, s4 := common.Tokens.MatchSpaces(t) if !b4 { return errors.New("expecting spaces") } t = t[len(s4):] // type b5, s5 := common.Tokens.MatchDataType(t) if !b5 { return errors.New("expecting data type") } t = t[len(s5):] // more? b6, s6 := common.Tokens.MatchRegexp(t, `^\s*,\s*`) if b6 { // yes more t = t[len(s6):] } else { // no more break } } } // arguments end b7, _ := common.Tokens.MatchRegexp(t, `^\s*\)\s*`) if !b7 { return errors.New("expecting end of arguments") } return nil}var gStructStartRegexp = regexp.MustCompile(`^\s*type\s+(\w+)\s+struct\s+\{`)var gStructEndRegexp = regexp.MustCompile(`^\s*}`)var gFieldStartRegexp = regexp.MustCompile(`^\s*\w+\s+`)var gMethodStartRegex = regexp.MustCompile(`^\s*func\s+\(\s*\w+\s+\*?(\w+)\s*\)\s+(\w+)\s*\(`)var gInvalidMethodArgs = errors.New("invalid method arguments")var gMethodEndRegexp = regexp.MustCompile(`^\s*\{`)var DefaultStructScanner IStructScanner = new(tStructScanner)scanner/IStructScanner_test.go
struct扫描器的单元测试
package scannerimport ( "encoding/json" "learning/gooop/spring/autogen/domain" "strings" "testing")func Test_StructScan(t *testing.T) { s := `type _mystruct struct {` t.Log(gStructStartRegexp.MatchString(s)) code := `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}func (me *StructInfo) AppendField(lineNO int, name string, dataType string) { fld := NewFieldInfo() fld.Struct = me fld.LineNO = lineNO fld.Name = name fld.DataType = dataType me.Fields = append(me.Fields, fld)}func (me *StructInfo) AppendMethod(method *MethodInfo) { me.Methods = append(me.Methods, method)}func (me *StructInfo) AppendAnnotation(ant *AnnotationInfo) { me.Annotations = append(me.Annotations, ant)}` file := domain.NewCodeFileInfo() file.CleanLines = strings.Split(code, "\n") DefaultStructScanner.ScanStruct(file) file.CleanLines = nil j, e := json.MarshalIndent(file.Structs, "", " ") if e != nil { panic(e) } t.Log(string(j))}测试输出
API server listening at: [::]:36077=== RUN Test_StructScan IStructScanner_test.go:12: true IStructScanner_test.go:58: [ { "LineNO": 1, "Name": "StructInfo", "Fields": [ { "LineNO": 2, "Name": "LineNO", "DataType": "int", "Annotations": [] }, { "LineNO": 3, "Name": "Name", "DataType": "string", "Annotations": [] }, { "LineNO": 4, "Name": "CodeFile", "DataType": "*CodeFileInfo", "Annotations": [] }, { "LineNO": 5, "Name": "Fields", "DataType": "[]*FieldInfo", "Annotations": [] }, { "LineNO": 6, "Name": "Methods", "DataType": "[]*MethodInfo", "Annotations": [] }, { "LineNO": 7, "Name": "Annotations", "DataType": "[]*AnnotationInfo", "Annotations": [] } ], "Methods": [ { "LineNO": 0, "Name": "AppendField", "Arguments": [ { "Name": "lineNO", "DataType": "int" }, { "Name": "name", "DataType": "string" }, { "Name": "dataType", "DataType": "string" } ], "Annotations": [], "Returns": [] }, { "LineNO": 0, "Name": "AppendMethod", "Arguments": [ { "Name": "method", "DataType": "*MethodInfo" } ], "Annotations": [], "Returns": [] }, { "LineNO": 0, "Name": "AppendAnnotation", "Arguments": [ { "Name": "ant", "DataType": "*AnnotationInfo" } ], "Annotations": [], "Returns": [] } ], "Annotations": [] } ]--- PASS: Test_StructScan (0.01s)PASSDebugger finished with exit code 0"编写golang编写注解的静态代码增强器/生成器的方法"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!
方法
注解
类型
测试
代码
生成器
静态
增强器
生成
单元
内容
扫描器
更多
正则
目标
知识
细节
输出
实用
学有所成
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
恒实科技 工业互联网
电子身份证数据库龙头
联合国贸易数据库双边贸易数据
软件开发工期
安徽计算机网络技术统招专升本
以下哪些数据库是关系型数据库
云南农村信用社服务器
伟文怎么数据库打印
今日头条因服务器故障
网络安全咨询顾问招聘
安卓软件开发个人总结
星际方块服务器客户端异常
数据库 建库和表
丽水物流软件开发亿连信
河北信息化软件开发有哪些
思迅医药之星 数据库
网络安全简介和环境
海南亿成网络技术有限公司客服电话
幼儿网络安全情景剧
网络安全防电信网络诈骗手抄报
做一个游戏内部服务器
服务器延迟高一般是因为什么原因
网络安全的效益
华为软件开发累吗
徐汇区管理网络技术咨询技术指导
幻塔服务器列表只有两个
昆明软件开发推荐
aix数据库快速启动
服务器远程密码修改
数据库安全主要包括