di/annotation/annotation.go
crusader 700f188618 ing
2017-12-06 15:07:44 +09:00

160 lines
3.0 KiB
Go

package annotation
import (
"fmt"
"reflect"
"strings"
"git.loafle.net/commons_go/di"
)
const (
AnnotationChar = "@"
AnnotationStartChar = "("
AnnotationEndChar = ")"
AnnotationSpliter = ";"
AnnotationAttributeSpliter = ","
AnnotationKeyValueSpliter = "="
)
var annotationRegistry map[string]reflect.Type
func init() {
annotationRegistry = make(map[string]reflect.Type, 0)
}
func registerAnnotation(name string, t reflect.Type) {
annotationRegistry[name] = t
}
type Annotation interface {
parseAttribute(attributes map[string]string) error
}
// @Inject(name? string)
// @Resource(name? string)
func ParseAnnotation(tag reflect.StructTag) ([]Annotation, error) {
s := strings.Trim(tag.Get(di.AnnotationTag), " ")
if "" == s {
return nil, nil
}
annotations := strings.Split(s, AnnotationSpliter)
if nil == annotations || 0 == len(annotations) {
return nil, nil
}
rKVs := make([]Annotation, 0)
for _, a := range annotations {
a = strings.Trim(a, " ")
if "" == a {
continue
}
aName, attributes, err := ParseAnnotationItem(a)
if nil != err {
return nil, err
}
if "" == aName {
continue
}
annotation, err := NewAnnotation(aName, attributes)
if nil != err {
return nil, err
}
rKVs = append(rKVs, annotation)
}
return rKVs, nil
}
func NewAnnotation(name string, attributes map[string]string) (Annotation, error) {
t, ok := annotationRegistry[name]
if !ok {
return nil, fmt.Errorf("There is no annotation[%s]", name)
}
v := reflect.New(t.Elem())
i := v.Interface().(Annotation)
if nil != attributes {
i.parseAttribute(attributes)
}
return i, nil
}
func ParseAnnotationItem(a string) (name string, attributes map[string]string, err error) {
s := strings.Trim(a, " ")
if "" == s {
return
}
i := strings.Index(s, AnnotationChar)
if -1 == i {
err = fmt.Errorf("Syntax error: annotation must be started %s", AnnotationChar)
return
}
aStart := strings.Index(s, AnnotationStartChar)
if -1 == aStart {
// This is pure annotation ex)@Resource
name = s
return
}
name = s[:aStart]
aEnd := strings.Index(s, AnnotationEndChar)
if -1 == aEnd {
// This is syntax error ex)@Resource(
err = fmt.Errorf("Syntax error: annotation must be ended %s", AnnotationEndChar)
return
}
if 1 >= aEnd-aStart {
return
}
attr := s[aStart+1 : aEnd]
attr = strings.Trim(attr, " ")
if "" == attr {
return
}
attrs, pErr := ParseAttribute(s[aStart+1 : aEnd])
if nil != pErr {
err = pErr
return
}
attributes = attrs
return
}
func ParseAttribute(s string) (map[string]string, error) {
attr := strings.Trim(s, " ")
if "" == attr {
return nil, nil
}
kvs := strings.Split(attr, AnnotationAttributeSpliter)
if nil == kvs || 0 == len(kvs) {
return nil, nil
}
rKVs := make(map[string]string)
for i := 0; i < len(kvs); i++ {
s := strings.Trim(kvs[i], " ")
if "" == s {
continue
}
kv := strings.Split(s, AnnotationKeyValueSpliter)
k := strings.Trim(kv[0], " ")
v := strings.Trim(kv[1], " ")
rKVs[k] = v
}
return rKVs, nil
}