编写golang编写注解的静态代码增强器/生成器的方法
发表于:2025-01-20 作者:千家信息网编辑
千家信息网最后更新 2025年01月20日,本篇内容介绍了"编写golang编写注解的静态代码增强器/生成器的方法"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读
千家信息网最后更新 2025年01月20日编写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安全错误
数据库的锁怎样保障安全
连接zmc数据库
免费个人网站服务器
郑州安卓软件开发公司有哪些
反向解析服务器
radius服务器设置
微型网络技术检修
石景山区软件开发诚信合作
建筑网络技术的三要素是什么
网络技术三级题库电子版
滴滴威胁网络安全
光传输设备网络管理服务器
入侵网络安全方案
免费书目数据库
小学生网络安全图片 三年级
为数据库表重命名
强化网络安全 预防网络沉迷
手机打开软件提示未连接服务器
dns服务器山西省云空间
串口服务器管理协议有哪些
网络安全中的dos
惠普服务器功率
关于网络安全事件
小马镇官网服务器脱机
国际电信联盟网络安全
南京h5多媒体软件开发
服务器有ack延迟
wap转换app软件开发
现场网络安全攻防竞赛开赛
软件测试数据库测试题
实况足球怎样搭建服务器