ing
This commit is contained in:
commit
e44b732fea
14
const.go
Normal file
14
const.go
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
package annotation
|
||||||
|
|
||||||
|
const (
|
||||||
|
// AnnotationTag is value
|
||||||
|
AnnotationTag = "annotation"
|
||||||
|
// AnnotationMetaTag is value
|
||||||
|
AnnotationMetaTag = "@annotation"
|
||||||
|
// AnnotationChar is value
|
||||||
|
AnnotationChar = "@"
|
||||||
|
// AnnotationStartChar is value
|
||||||
|
AnnotationStartChar = "("
|
||||||
|
// AnnotationEndChar is value
|
||||||
|
AnnotationEndChar = ")"
|
||||||
|
)
|
5
go.mod
Normal file
5
go.mod
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
module git.loafle.net/loafer/annotation-go
|
||||||
|
|
||||||
|
go 1.13
|
||||||
|
|
||||||
|
require git.loafle.net/loafer/util-go v0.0.0-20191112142134-9a567d18b779
|
2
go.sum
Normal file
2
go.sum
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
git.loafle.net/loafer/util-go v0.0.0-20191112142134-9a567d18b779 h1:TcBAz07pghDjiwGLgWrPVbovK4i8gnROGqFIwzxzarA=
|
||||||
|
git.loafle.net/loafer/util-go v0.0.0-20191112142134-9a567d18b779/go.mod h1:HGVw9FNJIc/UFDIzxmoIj5K2+D9Eadal5jjHOq0NFOU=
|
172
registry.go
Normal file
172
registry.go
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
package annotation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
luReflect "git.loafle.net/loafer/util-go/reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registry = newRegistry()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Definition is struct
|
||||||
|
type Definition struct {
|
||||||
|
t reflect.Type
|
||||||
|
rt reflect.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regist is interface
|
||||||
|
type Regist interface {
|
||||||
|
// Register is method
|
||||||
|
Register(t reflect.Type)
|
||||||
|
// Parse is method
|
||||||
|
Parse(tag reflect.StructTag) (map[reflect.Type]Annotation, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Registry is struct
|
||||||
|
type Registry struct {
|
||||||
|
definitions map[string]*Definition
|
||||||
|
}
|
||||||
|
|
||||||
|
var registry Regist
|
||||||
|
|
||||||
|
func newRegistry() Regist {
|
||||||
|
r := &Registry{}
|
||||||
|
r.definitions = make(map[string]*Definition, 0)
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register is method
|
||||||
|
func Register(t reflect.Type) {
|
||||||
|
registry.Register(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register is method
|
||||||
|
func (r *Registry) Register(t reflect.Type) {
|
||||||
|
rt, _, _ := luReflect.GetTypeInfo(t)
|
||||||
|
f := r.getTypeAnnotationField(t)
|
||||||
|
if nil == f {
|
||||||
|
panic(fmt.Sprintf("Annotation: This type[%s] is not Annotation. use TypeAnnotation", rt.Name()))
|
||||||
|
}
|
||||||
|
|
||||||
|
name := r.parseAnnotationMeta(f.Tag)
|
||||||
|
|
||||||
|
if _, ok := r.definitions[name]; ok {
|
||||||
|
panic(fmt.Sprintf("Annotation: name[%s] of annotation exist already", name))
|
||||||
|
}
|
||||||
|
|
||||||
|
def := &Definition{
|
||||||
|
t: t,
|
||||||
|
rt: rt,
|
||||||
|
}
|
||||||
|
|
||||||
|
r.definitions[name] = def
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse is method
|
||||||
|
func Parse(tag reflect.StructTag) (map[reflect.Type]Annotation, error) {
|
||||||
|
return registry.Parse(tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse is method
|
||||||
|
func (r *Registry) Parse(tag reflect.StructTag) (map[reflect.Type]Annotation, error) {
|
||||||
|
s := strings.Trim(tag.Get(AnnotationTag), " ")
|
||||||
|
if "" == s {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
annotations, err := r.splitAnnotation(s)
|
||||||
|
if nil != err {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if nil == annotations || 0 == len(annotations) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
rKVs := make(map[reflect.Type]Annotation, 0)
|
||||||
|
for name, attributes := range annotations {
|
||||||
|
t, annotation, err := r.buildAnnotation(name, attributes)
|
||||||
|
if nil != err {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rKVs[t] = annotation
|
||||||
|
}
|
||||||
|
|
||||||
|
return rKVs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Registry) getTypeAnnotationField(t reflect.Type) *reflect.StructField {
|
||||||
|
rt, _, _ := luReflect.GetTypeInfo(t)
|
||||||
|
if reflect.Struct != rt.Kind() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < rt.NumField(); i++ {
|
||||||
|
f := rt.Field(i)
|
||||||
|
|
||||||
|
if f.Anonymous {
|
||||||
|
if f.Type == TypeAnnotationType {
|
||||||
|
return &f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Registry) parseAnnotationMeta(tag reflect.StructTag) string {
|
||||||
|
return strings.Trim(tag.Get(AnnotationMetaTag), " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Registry) splitAnnotation(s string) (map[string]string, error) {
|
||||||
|
ss := make(map[string]string, 0)
|
||||||
|
ts := s
|
||||||
|
for {
|
||||||
|
as := strings.Index(ts, AnnotationChar)
|
||||||
|
if -1 == as {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
aas := strings.Index(ts, AnnotationStartChar)
|
||||||
|
aae := strings.Index(ts, AnnotationEndChar)
|
||||||
|
|
||||||
|
aName := ts[as:aas]
|
||||||
|
aAttributes := ts[aas+1 : aae]
|
||||||
|
|
||||||
|
if 0 < len(aAttributes) {
|
||||||
|
ss[aName] = aAttributes
|
||||||
|
} else {
|
||||||
|
ss[aName] = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ts) <= (aae + 1) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
ts = ts[aae+1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return ss, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Registry) buildAnnotation(name string, attributes string) (reflect.Type, Annotation, error) {
|
||||||
|
def, ok := r.definitions[name]
|
||||||
|
if !ok {
|
||||||
|
return nil, nil, fmt.Errorf("There is no annotation[%s]", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
v := reflect.New(def.rt)
|
||||||
|
i := v.Interface().(Annotation)
|
||||||
|
|
||||||
|
if "" != attributes {
|
||||||
|
_json := fmt.Sprintf("{%s}", attributes)
|
||||||
|
if err := json.Unmarshal([]byte(_json), i); nil != err {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return def.t, i, nil
|
||||||
|
}
|
247
registry_test.go
Normal file
247
registry_test.go
Normal file
|
@ -0,0 +1,247 @@
|
||||||
|
package annotation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_newRegistry(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
want Regist
|
||||||
|
}{
|
||||||
|
// TODO: Add test cases.
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := newRegistry(); !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("newRegistry() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRegister(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
t reflect.Type
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
}{
|
||||||
|
// TODO: Add test cases.
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
Register(tt.args.t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRegistry_Register(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
definitions map[string]*Definition
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
t reflect.Type
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
}{
|
||||||
|
// TODO: Add test cases.
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
r := &Registry{
|
||||||
|
definitions: tt.fields.definitions,
|
||||||
|
}
|
||||||
|
r.Register(tt.args.t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParse(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
tag reflect.StructTag
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want map[reflect.Type]Annotation
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
// TODO: Add test cases.
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := Parse(tt.args.tag)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("Parse() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("Parse() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRegistry_Parse(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
definitions map[string]*Definition
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
tag reflect.StructTag
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
want map[reflect.Type]Annotation
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
// TODO: Add test cases.
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
r := &Registry{
|
||||||
|
definitions: tt.fields.definitions,
|
||||||
|
}
|
||||||
|
got, err := r.Parse(tt.args.tag)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("Registry.Parse() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("Registry.Parse() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRegistry_getTypeAnnotationField(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
definitions map[string]*Definition
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
t reflect.Type
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
want *reflect.StructField
|
||||||
|
}{
|
||||||
|
// TODO: Add test cases.
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
r := &Registry{
|
||||||
|
definitions: tt.fields.definitions,
|
||||||
|
}
|
||||||
|
if got := r.getTypeAnnotationField(tt.args.t); !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("Registry.getTypeAnnotationField() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRegistry_parseAnnotationMeta(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
definitions map[string]*Definition
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
tag reflect.StructTag
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
// TODO: Add test cases.
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
r := &Registry{
|
||||||
|
definitions: tt.fields.definitions,
|
||||||
|
}
|
||||||
|
if got := r.parseAnnotationMeta(tt.args.tag); got != tt.want {
|
||||||
|
t.Errorf("Registry.parseAnnotationMeta() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRegistry_splitAnnotation(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
definitions map[string]*Definition
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
s string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
want map[string]string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
// TODO: Add test cases.
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
r := &Registry{
|
||||||
|
definitions: tt.fields.definitions,
|
||||||
|
}
|
||||||
|
got, err := r.splitAnnotation(tt.args.s)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("Registry.splitAnnotation() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("Registry.splitAnnotation() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRegistry_buildAnnotation(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
definitions map[string]*Definition
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
name string
|
||||||
|
attributes string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
want reflect.Type
|
||||||
|
want1 Annotation
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
// TODO: Add test cases.
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
r := &Registry{
|
||||||
|
definitions: tt.fields.definitions,
|
||||||
|
}
|
||||||
|
got, got1, err := r.buildAnnotation(tt.args.name, tt.args.attributes)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("Registry.buildAnnotation() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("Registry.buildAnnotation() got = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got1, tt.want1) {
|
||||||
|
t.Errorf("Registry.buildAnnotation() got1 = %v, want %v", got1, tt.want1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
26
types.go
Normal file
26
types.go
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
package annotation
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
|
// Annotation is interface
|
||||||
|
type Annotation interface {
|
||||||
|
}
|
||||||
|
|
||||||
|
// AnnotationType is type of Annotation
|
||||||
|
var AnnotationType = reflect.TypeOf((*Annotation)(nil))
|
||||||
|
|
||||||
|
// TypeAnnotation is interface
|
||||||
|
type TypeAnnotation interface {
|
||||||
|
Annotation
|
||||||
|
}
|
||||||
|
|
||||||
|
// TypeAnnotationType is type of TypeAnnotation
|
||||||
|
var TypeAnnotationType = reflect.TypeOf((*TypeAnnotation)(nil))
|
||||||
|
|
||||||
|
// MethodAnnotation is interface
|
||||||
|
type MethodAnnotation interface {
|
||||||
|
Annotation
|
||||||
|
}
|
||||||
|
|
||||||
|
// MethodAnnotationType is type of MethodAnnotation
|
||||||
|
var MethodAnnotationType = reflect.TypeOf((*MethodAnnotation)(nil))
|
Loading…
Reference in New Issue
Block a user