您好,登录后才能下订单哦!
这篇文章主要介绍“怎么使用golang编写基于注解的静态代码增强器/生成器”,在日常操作中,相信很多人在怎么使用golang编写基于注解的静态代码增强器/生成器问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么使用golang编写基于注解的静态代码增强器/生成器”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
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编写“基于注解的静态代码增强器/生成器”
struct解析清楚了,接着解析注解就比较容易了
scanner/IStructScanner.go:修复scanMethod()和scanAnnotation()的细节问题
scanner/IAnnotationScanner.go:注解扫描接口及默认实现。注解的属性支持双引号和重音号字符串。
scanner/IAnnotationScanner_test.go:针对注解信息的单元测试
注解扫描接口及默认实现。注解的属性支持双引号和重音号字符串。
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到此,关于“怎么使用golang编写基于注解的静态代码增强器/生成器”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。